sw-stream

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 * 2
    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[0]
      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 () {}

sw-stream/test/sw-launcher.js

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: 42 })
    })
    .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)
    }
  }
}

sw-stream/lib/sw-stream.js

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
}





原文地址:https://www.cnblogs.com/wanghui-garcia/p/9915565.html