UNPKG

fox-wamp

Version:

Web Application Message Router/Server WAMP/MQTT

176 lines (153 loc) 4.78 kB
'use strict' const { BaseRealm, BaseEngine, makeDataSerializable, unSerializeData } = require('../realm') const { PromiseEngine, PromiseBinder } = require('../binder') const { MemKeyValueStorage } = require('../mono/memkv') const INTRA_REALM_NAME = 'sys' class HistorySegment { constructor (advanceSegment) { this.content = new Map() this.advanceSegment = advanceSegment this.generator = 0 } addActor (actor) { this.generator++ this.content.set(this.generator, actor) return { segment: this.advanceSegment, id: this.generator } } fetchActor (advance) { if (advance.segment !== this.advanceSegment) { throw "advance is not identical "+advance.segment+" "+this.advanceSegment } let actor = this.content.get(advance.id) if (actor) { this.content.delete(advance.id) } return actor } getAdvanceSegment() { return this.advanceSegment } } class NetEngine extends PromiseEngine { doPush (actor) { this.saveInboundHistory(actor) } } class NetBinder extends PromiseBinder { constructor (router) { super() this.curSegment = null this.advanceSegmentGen = 0 this.segments = new Map() this.router = router this.sysRealm = new BaseRealm(router, new BaseEngine()) router.addRealm(INTRA_REALM_NAME, this.sysRealm) this.sysRealm.registerKeyValueEngine(['#'], new MemKeyValueStorage()) this.sysApi = this.sysRealm.api() this.sysApi.subscribe(['beginSegmentAccepted'], (data, opt) => { if (!data.advanceSegment) { console.error('ERROR: no advanceSegment in package') } if (this.curSegment) { if (data.advanceSegment == this.curSegment.getAdvanceSegment()) { // it is time to create new segment if it is necessary this.curSegment = null console.log('advance segment completed', data.advanceSegment) } else { console.warn('warn: new segment is not accepted, cur:', this.curSegment.getAdvanceSegment(), 'inbound:', data.advanceSegment) } } }) this.sysApi.subscribe(['ackSegment'], (data, opt) => { console.log('=> ackSegment', data, opt.headers) this.ackSegment(opt.headers) }) this.sysApi.subscribe(['dispatchEvent'], (data, opt) => { console.log('=> dispatchEvent', data, opt.headers) this.dispatchEvent(opt.headers) }) } getSegment () { if (this.curSegment) { return this.curSegment } this.advanceSegmentGen++ let curAdvanceSegment = '' + this.router.getId() + '-' + this.advanceSegmentGen this.curSegment = new HistorySegment(curAdvanceSegment) this.segments.set(curAdvanceSegment, this.curSegment) this.sysApi.publish('beginSegment', { advanceSegment: curAdvanceSegment }) return this.curSegment } findSegment (advanceSegment) { return this.segments.get(advanceSegment) } deleteSegment (advanceSegment) { return this.segments.delete(advanceSegment) } ackSegment (syncMessage) { let segment = this.findSegment(syncMessage.advanceSegment) if (!segment) { return } console.log('ackSegment', syncMessage.advanceSegment) for (let event of syncMessage.pkg) { let actor = segment.fetchActor(event.advanceId) if (actor) { actor.setEventId(event.qid) actor.confirm() } else { console.log("actor not found by advanceId", event.advanceId) } } if (syncMessage.final) { this.deleteSegment(syncMessage.advanceSegment) if (segment.size() > 0) { console.log("removing not empty segment") } } } saveHistory (engine, actor) { let segment = this.getSegment() let advanceId = segment.addActor(actor) return this.sysApi.publish('saveHistory', null, { headers:{ advanceId: advanceId, realm: engine.getRealmName(), data: makeDataSerializable(actor.getData()), uri: actor.getUri(), opt: actor.getOpt(), sid: actor.getSid() }}) } getHistoryAfter (engine, after, uri, cbRow) { return this.msg.getEventHistory( engine.getRealmName(), { fromId: after, uri }, (event) => { cbRow({ qid: event.id, uri: event.uri, data: unSerializeData(event.body) }) } ) } dispatchEvent (eventData) { const realm = this.router.findRealm(eventData.realm) if (realm) { realm.getEngine().disperseToSubs({ qid: eventData.qid, uri: eventData.uri, data: unSerializeData(eventData.data), opt: eventData.opt, sid: eventData.sid }) } } cleanupSession (engine, sessionId) { return Promise.resolve(true) } } exports.NetBinder = NetBinder exports.NetEngine = NetEngine