sw-stream
2024-10-05 22:59:20
https://github.com/kumavis/sw-stream
ServiceWorkerStream and ServiceWorkerGlobalListener
This a utility for creating streams between the page and a servive worker.
在页面也服务器中创建流
usage
in page
pass the registered service worker to create a duplex stream.
传递一个登录的service worker去创建一个双工流
const duplex = SwStream({ serviceWorker: this.serviceWorker.controller })
There is an optional context
property that will be passed along on the initial handshake and retreivable from the messageEvent.data.context
received from the SwGlobalListener.
context参数是可选的,它将会在第一次握手时传递并且会被从SwGlobalListener检索得到的messageEvent.data.context检索到
const duplex = SwStream({ serviceWorker, context })
in ServiceWorker
listen for client connections
const connectionListener = new SwGlobalListener(self) connectionListener.on('remote', (portStream, messageEvent) => {
// ...
})
看测试了解使用:
sw-stream/test/service-worker.js (即background.js)
const SwGlobalListener = require('../lib/sw-global-listener')
const swGlobal = self // setup ServiceWorkerGlobal and capture clients swGlobal.addEventListener('activate', function(event) {
event.waitUntil(swGlobal.clients.claim())
}) swGlobal.oninstall = function (event) {
event.waitUntil(swGlobal.skipWaiting())
} // listen for clients const connectionListener = new SwGlobalListener(swGlobal) connectionListener.on('remote', (portStream, messageEvent) => {
console.log('got a remote connection!')
remoteStream.on('data', (message) => {
console.log('message:', message)
// example: double value and then send back
let newValue = message.value *
remoteStream.write({ value: newValue })
})
})
sw-stream/lib/sw-global-listener.js
const EventEmitter = require('events')
const PortStream = require('./message-channel-port-stream') class SwGlobalListener extends EventEmitter { constructor (swGlobal) {
super()
swGlobal.addEventListener('message', (messageEvent) => {
// validate port
if (!messageEvent.data) return
if (messageEvent.data.action !== 'handshake') return
// process message
const port = messageEvent.ports[]
if (!port) throw new Error('Handshake missing port...')
// create new portStream
const portStream = new PortStream(port)
// announce new connection
this.emit('remote', portStream, messageEvent)
})
} } module.exports = SwGlobalListener
sw-stream/lib/message-channel-port-stream.js
const Duplex = require('readable-stream').Duplex
const inherits = require('util').inherits module.exports = MessageChannelPortDuplexStream inherits(MessageChannelPortDuplexStream, Duplex) function MessageChannelPortDuplexStream (port) {
Duplex.call(this, {
objectMode: true,
})
this._port = port
port.onmessage = this._onMessage.bind(this)
} // private MessageChannelPortDuplexStream.prototype._onMessage = function (event) {
const msg = event.data
if (Buffer.isBuffer(msg)) {
delete msg._isBuffer
var data = new Buffer(msg)
this.push(data)
} else {
this.push(msg)
}
} // stream plumbing MessageChannelPortDuplexStream.prototype._read = noop MessageChannelPortDuplexStream.prototype._write = function (msg, encoding, cb) {
try {
if (Buffer.isBuffer(msg)) {
var data = msg.toJSON()
data._isBuffer = true
this._port.postMessage(data)
} else {
this._port.postMessage(msg)
}
} catch (err) {
return cb(new Error('MessageChannelPortDuplexStream - disconnected'))
}
cb()
} // util function noop () {}
const EventEmitter = require('events')
const SwStream = require('../lib/sw-stream') module.exports = class ServiceWorkerLauncher extends EventEmitter {
constructor (opts) {
super()
this.serviceWorker = navigator.serviceWorker
this.startWorker()
.then(registeredWorker => {
console.log('setting up stream...')
const duplex = SwStream(registeredWorker)
duplex.on('data', (chunk) => {console.log('controller saw:', chunk) })
duplex.on('error', (chunk) => {console.log('controller saw:', chunk) })
duplex.write({ value: })
})
.catch(err => {
this.handleError(err)
})
} startWorker () {
// check to see if their is a preregistered service worker
if (!this.serviceWorker.controller) {
console.log('registering...')
return Promise.resolve(this.registerWorker())
} else {
console.log('ready')
return Promise.resolve(this.serviceWorker.ready)
}
} registerWorker () {
return this.serviceWorker.register('sw-bundle.js')
.then(sw => {
return sw
})
} handleError (err, contextMessage) {
if (!err) {
console.error(contextMessage)
this.emit('error', contextMessage)
} else {
console.error(err)
this.emit('error', err)
}
}
}
const PortStream = require('./message-channel-port-stream') module.exports = SericeWorkerStream function SericeWorkerStream({ serviceWorker, context }) {
// create message channel for communication
const messageChannel = new MessageChannel()
// send handshake including port to respond on
serviceWorker.postMessage({ action: 'handshake', context }, [messageChannel.port2])
// construct stream around local message channel port
const portStream = new PortStream(messageChannel.port1)
return portStream
}
最新文章
- kail linux 虚拟机安装实录(一) 新建虚拟机
- devexpress xaf 开发中遇到的问题.
- 武汉科技大学ACM :1007: A+B for Input-Output Practice (VII)
- cf B. Sereja and Suffixes
- Python闭包及装饰器
- 对象和XML文件的转换
- golang slice 经典例题
- hibernate 调用存储过程返回参数
- Android 开发 RecyclerView设置间距
- Spring_AOP 实现原理与 CGLIB 应用
- Protobuf3 语法指南
- 调试WebApi的一些方法
- 物联网架构成长之路(30)-Spring Boot Admin微服务WebUI监控
- IDEA上传码云报错Push rejected: Push to origin/master was rejected
- Junit + String/Integer/ArrayList/HashMap/TreeMap 基本使用Demo
- 《HTTP 权威指南》笔记:第三章 HTTP 报文
- 如何对xilinx FPGA进行bit文件加密
- 怎样在js中使用EL表达式
- 云端办公是 Office系统的未来方向么 ?
- Windows环境下JDK的配置及多版本JDK切换的方法记录