UNPKG

fox-wamp

Version:

Web Application Message Router/Server WAMP/MQTT

191 lines (165 loc) 5.72 kB
import { Actor, BaseRealm, BaseEngine, makeDataSerializable, unSerializeData } from '../realm' import Router from '../router' import { HyperClient } from '../hyper/client' import { MemKeyValueStorage } from '../mono/memkv' import { AdvanceHistoryEvent, AdvanceOffsetId, INTRA_REALM_NAME } from './netengine.h' export class HistorySegment { private content: Map<number,Actor> = new Map() private advanceSegment: string private generator: number = 0 constructor (advanceSegment: string) { this.advanceSegment = advanceSegment } addActor (actor: Actor): AdvanceOffsetId { this.generator++ this.content.set(this.generator, actor) return { segment: this.advanceSegment, offset: this.generator } } fetchActor (advanceId: AdvanceOffsetId): Actor | undefined { if (advanceId.segment !== this.advanceSegment) { throw Error("advance is not identical "+advanceId.segment+" "+this.advanceSegment) } let actor = this.content.get(advanceId.offset) if (actor) { this.content.delete(advanceId.offset) } return actor } getAdvanceSegment(): string { return this.advanceSegment } } export class NetEngine extends BaseEngine { private netEngineMill: NetEngineMill constructor (netEngineMill: NetEngineMill) { super() this.netEngineMill = netEngineMill } // @return promise doPush (actor: any) { return this.netEngineMill.saveHistory(actor, this.getRealmName()) } getHistoryAfter (after: string, uri: string, cbEmitRow: any): Promise<any> { return Promise.resolve() // return History.getEventHistory( // getMainDb(), // engine.getRealmName(), // { fromId: after, uri }, // (event) => { // cbEmitRow({ // qid: event.id, // uri: event.uri, // data: unSerializeData(event.body) // }) // } // ) } } export class NetEngineMill { private curSegment: HistorySegment | null = null private advanceSegmentGen: number = 0 private segments = new Map() private router: Router private sysRealm: BaseRealm private sysApi: HyperClient constructor (router: any) { this.router = router this.sysRealm = new BaseRealm(router, new BaseEngine()) this.router.initRealm(INTRA_REALM_NAME, this.sysRealm) this.sysRealm.registerKeyValueEngine(['#'], new MemKeyValueStorage()) this.sysApi = this.sysRealm.buildApi() this.sysApi.subscribe('trim-advance-segment', (data: any, opt: any) => { // to do voute for complete if (!data.advanceSegment) { console.error('ERROR: no advanceSegment in package') } if (this.curSegment) { if (data.advanceSegment == this.curSegment.getAdvanceSegment()) { // it will be required to create new segment at the next inbound message this.curSegment = null console.log('advance-segment-over =>', data.advanceSegment) this.sysApi.publish('advance-segment-over', { advanceSegment: data.advanceSegment }) } else { console.warn('warn: new segment is not accepted, cur:', this.curSegment.getAdvanceSegment(), 'inbound:', data.advanceSegment) } } }) this.sysApi.subscribe('advance-segment-resolved', (data: any, opt: any) => { this.advanceSegmentResolved(opt.headers) }) this.sysApi.subscribe('dispatchEvent', (data: any, opt: any) => { console.log('=> dispatchEvent', opt.headers.qid) 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) // todo: sent all open advance segments, in case of sharding that keeps order this.sysApi.publish('begin-advance-segment', { advanceSegment: curAdvanceSegment }) return this.curSegment } findSegment (advanceSegment: string) { return this.segments.get(advanceSegment) } deleteSegment (advanceSegment: string) { return this.segments.delete(advanceSegment) } advanceSegmentResolved (syncMessage: any) { let segment = this.findSegment(syncMessage.advanceSegment) if (!segment) { return } console.log('advance-segment-resolved', syncMessage.advanceSegment, syncMessage.pkg) 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") } } } // @return promise saveHistory (actor: any, realmName: string) { let segment = this.getSegment() let advanceId = segment.addActor(actor) const event: AdvanceHistoryEvent = { advanceId: advanceId, realm: realmName, data: makeDataSerializable(actor.getData()), uri: actor.getUri(), opt: actor.getOpt(), sid: actor.getSid() } return this.sysApi.publish('keep-advance-history', null, { headers: event}) } dispatchEvent (eventData: any) { 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 }) } } }