teletype-client-modified
Version:
I have modified the library developed by Atom to make it compatible with non-browser facility. I am using it only for experimentation purposes. I will remove this package post my experiment and raise a PR at Atom to finally merge this package so that this
134 lines (110 loc) • 4.41 kB
JavaScript
const {CompositeDisposable, Emitter} = require('event-kit')
const {RouterMessage} = require('./teletype-client_pb')
const convertToProtobufCompatibleBuffer = require('./convert-to-protobuf-compatible-buffer')
module.exports =
class Router {
constructor (network) {
this.network = network
this.emitter = new Emitter()
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(network.onReceive(this.receive.bind(this)))
this.nextRequestId = 0
this.requestPromiseResolveCallbacks = new Map()
this.peerIdsByRequestId = new Map()
this.lastReceivePromise = Promise.resolve()
}
dispose () {
this.subscriptions.dispose()
}
notify ({recipientId, channelId, body}) {
body = convertToProtobufCompatibleBuffer(body)
const notification = new RouterMessage.Notification()
notification.setChannelId(channelId)
if (body != null) notification.setBody(body)
const routerMessage = new RouterMessage()
routerMessage.setNotification(notification)
if (recipientId) {
this.network.unicast(recipientId, routerMessage.serializeBinary())
} else {
this.network.broadcast(routerMessage.serializeBinary())
}
}
request ({recipientId, channelId, body}) {
if (body) body = convertToProtobufCompatibleBuffer(body)
const requestId = this.nextRequestId++
const request = new RouterMessage.Request()
request.setChannelId(channelId)
request.setRequestId(requestId)
if (body) request.setBody(body)
const routerMessage = new RouterMessage()
routerMessage.setRequest(request)
this.network.unicast(recipientId, routerMessage.serializeBinary())
return new Promise((resolve) => {
this.requestPromiseResolveCallbacks.set(requestId, resolve)
})
}
respond ({requestId, ok, body}) {
const recipientId = this.peerIdsByRequestId.get(requestId)
if (!recipientId) throw new Error('Multiple responses to the same request are not allowed')
if (ok == null) ok = true
if (body) body = convertToProtobufCompatibleBuffer(body)
const response = new RouterMessage.Response()
response.setRequestId(requestId)
response.setOk(ok)
response.setBody(body)
const routerMessage = new RouterMessage()
routerMessage.setResponse(response)
this.peerIdsByRequestId.delete(requestId)
this.network.unicast(recipientId, routerMessage.serializeBinary())
}
onNotification (channelId, callback) {
return this.emitter.on('notification:' + channelId, callback)
}
onRequest (channelId, callback) {
return this.emitter.on('request:' + channelId, callback)
}
receive ({senderId, message}) {
const routerMessage = RouterMessage.deserializeBinary(message)
if (routerMessage.hasNotification()) {
this.receiveNotification(senderId, routerMessage.getNotification())
} else if (routerMessage.hasRequest()) {
this.receiveRequest(senderId, routerMessage.getRequest())
} else if (routerMessage.hasResponse()) {
this.receiveResponse(routerMessage.getResponse())
} else {
throw new Error('Unsupported router message variant')
}
}
receiveNotification (senderId, notification) {
this.lastReceivePromise = this.lastReceivePromise.then(async () => {
const channelId = notification.getChannelId()
const body = convertToProtobufCompatibleBuffer(notification.getBody())
await this.emitter.emitAsync(
'notification:' + channelId,
{senderId, body}
)
})
}
receiveRequest (senderId, request) {
this.lastReceivePromise = this.lastReceivePromise.then(async () => {
const channelId = request.getChannelId()
const requestId = request.getRequestId()
const eventName = 'request:' + channelId
const body = convertToProtobufCompatibleBuffer(request.getBody())
this.peerIdsByRequestId.set(requestId, senderId)
if (this.emitter.listenerCountForEventName(eventName) === 0) {
this.respond({requestId, ok: false})
} else {
await this.emitter.emitAsync(eventName, {senderId, requestId, body})
}
})
}
receiveResponse (response) {
const requestId = response.getRequestId()
const requestResolveCallback = this.requestPromiseResolveCallbacks.get(requestId)
requestResolveCallback({
body: convertToProtobufCompatibleBuffer(response.getBody()),
ok: response.getOk()
})
}
}