123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- import { Helpers } from '/core/helpers.js';
- import { Utility } from '/core/vwf/utility/utility.js';
- class VirtualTime {
- constructor() {
- console.log("Virtual Time constructor");
- this.helpers = new Helpers;
- this.utility = new Utility;
-
-
-
-
-
-
- this.now = 0;
-
-
-
-
-
-
-
-
-
-
-
- this.sequence_ = undefined
-
-
-
-
-
-
- this.client_ = undefined
-
-
-
-
-
- this.time = 0
-
-
-
- this.suspension = 0
-
-
-
-
- this.sequence = 0
-
-
-
- this.queue = new Heap({
- compar: this.queueSort
- })
-
- this.initReflectorStream();
- }
- initReflectorStream() {
- const self = this;
- this.streamDelay = 0;
- this.streamDefaultScheduler = M.scheduler.newDefaultScheduler();
-
-
- const [induce, events] = M.createAdapter();
- this.streamAdapter = {
- induce: induce,
- events: events,
- };
- const tapFunction = function (res) {
- let mostTime =
- M.scheduler.currentTime(self.streamDefaultScheduler) / 1000;
- if (_app.config.streamMsg) {
- console.log('STREAM: ', res, ' TIME: ', mostTime);
- self.insert(res, !res.action);
- }
- };
- this.reflectorStream = M.multicast(events);
- const resultStream = M.concatMap(el => {
- return M.delay(this.streamDelay, M.now(el))
- }, this.reflectorStream);
-
- this.eventsStream = M.tap((res) => {
- tapFunction(res);
- }, resultStream);
- M.runEffects(this.eventsStream, this.streamDefaultScheduler);
- }
-
-
-
-
-
-
-
-
-
-
-
-
- insert(fields, chronic) {
- var messages = fields instanceof Array ? fields : [fields];
- messages.forEach(function (fields) {
-
- fields.sequence = ++this.sequence;
- this.queue.insert(fields);
-
- if (chronic) {
- this.time = Math.max(this.time, fields.time);
- }
- }, this);
-
- if (chronic) {
- this.dispatch();
- }
- }
-
-
-
-
-
- pull() {
- if (this.suspension == 0 && this.queue.length > 0 && this.queue.peek().time <= this.time) {
- return this.queue.shift();
- }
- }
-
-
-
-
-
-
-
-
- filter(callback ) {
-
- let filtered = this.queue._list.slice().filter(callback);
-
- this.queue = new Heap({
- compar: this.queueSort
- });
- filtered.map(el => {
- this.queue.insert(el);
- });
- }
- filterQueue() {
- this.filter(function (fields) {
- if ((fields.origin === "reflector") && fields.sequence > vwf.virtualTime.sequence_) {
- return true;
- } else {
- vwf.logger.debugx("setState", function () {
- return ["removing", JSON.stringify(loggableFields(fields)), "from queue"];
- });
- }
- })
- }
-
-
-
-
-
- suspend(why) {
- if (this.suspension++ == 0) {
- vwf.logger.infox("-queue#suspend", "suspending queue at time", this.now, why ? why : "");
- return true;
- } else {
- vwf.logger.debugx("-queue#suspend", "further suspending queue at time", this.now, why ? why : "");
- return false;
- }
- }
-
-
-
-
-
-
-
-
-
- resume(why) {
- if (--this.suspension == 0) {
- vwf.logger.infox("-queue#resume", "resuming queue at time", this.now, why ? why : "");
- this.dispatch();
- return true;
- } else {
- vwf.logger.debugx("-queue#resume", "partially resuming queue at time", this.now, why ? why : "");
- return false;
- }
- }
-
-
-
-
-
- ready() {
- return this.suspension == 0;
- }
- queueSort(a, b) {
-
-
-
-
-
-
-
-
-
-
-
- if (a.time != b.time) {
- return a.time - b.time;
- } else if (a.origin != "reflector" && b.origin == "reflector") {
- return -1;
- } else if (a.origin == "reflector" && b.origin != "reflector") {
- return 1;
- } else {
- return a.sequence - b.sequence;
- }
- }
-
-
-
-
-
-
-
- queueTransitTransformation(object, names, depth) {
- let self = this
- if (depth == 0) {
-
-
-
- return object.filter(el => el !== 0).filter(function (fields) {
- return !(fields.origin === "reflector" && fields.sequence > vwf.virtualTime.sequence_) && fields.action;
- }).sort(function (fieldsA, fieldsB) {
- return fieldsA.sequence - fieldsB.sequence;
- });
- } else if (depth == 1) {
-
-
-
- var filtered = {};
- Object.keys(object).filter(function (key) {
- return key != "sequence";
- }).forEach(function (key) {
- filtered[key] = object[key];
- });
- return filtered;
- }
- return object;
- }
- get stateQueue() {
- return {
- time: this.time,
- queue: this.utility.transform(this.queue._list, this.queueTransitTransformation),
- }
- }
-
-
-
-
-
-
- dispatch() {
- var fields;
-
-
- while (fields = this.pull()) {
-
- if (this.now != fields.time) {
- this.sequence_ = undefined;
- this.client_ = undefined;
- this.now = fields.time;
- this.tock();
- }
-
- if (fields.action) {
- this.sequence_ = fields.sequence;
- this.client_ = fields.client;
- this.receive(fields.node, fields.action, fields.member, fields.parameters, fields.respond, fields.origin);
- } else {
- this.tick();
- }
- }
-
-
- if (this.ready() && this.now != this.time) {
- this.sequence_ = undefined;
- this.client_ = undefined;
- this.now = this.time;
- this.tock();
- }
- }
-
-
- plan(nodeID, actionName, memberName, parameters, when, callback_async ) {
- vwf.logger.debuggx("plan", nodeID, actionName, memberName,
- parameters && parameters.length, when, callback_async && "callback");
- var time = when > 0 ?
- Math.max(this.now, when) :
- this.now + (-when);
- var fields = {
- time: time,
- node: nodeID,
- action: actionName,
- member: memberName,
- parameters: parameters,
- client: this.client_,
- origin: "future",
-
- };
- this.insert(fields);
- vwf.logger.debugu();
- }
-
-
-
-
-
- send(nodeID, actionName, memberName, parameters, when, callback_async ) {
- vwf.logger.debuggx("send", nodeID, actionName, memberName,
- parameters && parameters.length, when, callback_async && "callback");
- var time = when > 0 ?
- Math.max(this.now, when) :
- this.now + (-when);
-
- var fields = {
- time: time,
- node: nodeID,
- action: actionName,
- member: memberName,
- parameters: this.utility.transform(parameters, this.utility.transforms.transit),
-
- };
- if (vwf.isLuminary) {
- vwf.luminary.stampExternalMessage(fields);
- } else if (vwf.reflectorClient.socket) {
-
- var message = JSON.stringify(fields);
- vwf.reflectorClient.socket.send(message);
- }
-
-
-
-
-
-
- vwf.logger.debugu();
- }
-
-
-
-
-
-
- respond(nodeID, actionName, memberName, parameters, result) {
- vwf.logger.debuggx("respond", nodeID, actionName, memberName,
- parameters && parameters.length, "...");
-
- var fields = {
-
- time: this.now,
- node: nodeID,
- action: actionName,
- member: memberName,
- parameters: this.utility.transform(parameters, this.utility.transforms.transit),
- result: this.utility.transform(result, this.utility.transforms.transit)
- };
- if (vwf.isLuminary) {
- vwf.luminary.stampExternalMessage(fields);
- } else if (vwf.reflectorClient.socket) {
-
- var message = JSON.stringify(fields);
- vwf.reflectorClient.socket.send(message);
- } else {
-
- }
- vwf.logger.debugu();
- }
-
-
-
-
- receive(nodeID, actionName, memberName, parameters, respond, origin) {
-
-
-
-
-
-
-
-
-
- var args = [],
- result;
- if (nodeID || nodeID === 0) args.push(nodeID);
- if (memberName) args.push(memberName);
- if (parameters) args = args.concat(parameters);
- if (actionName == 'createChild') {
- console.log("create child!");
-
-
-
-
-
-
-
-
-
-
- }
-
-
-
-
- if (origin !== "reflector" || !nodeID || vwf.private.nodes.existing[nodeID]) {
- result = vwf[actionName] && vwf[actionName].apply(vwf, args);
- } else {
- vwf.logger.debugx("receive", "ignoring reflector action on non-existent node", nodeID);
- result = undefined;
- }
-
- respond && this.respond(nodeID, actionName, memberName, parameters, result);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
-
-
-
-
- tick() {
-
- vwf.models.forEach(function (model) {
- model.ticking && model.ticking(this.now);
- }, vwf);
-
- vwf.views.forEach(function (view) {
- view.ticked && view.ticked(this.now);
- }, vwf);
-
- vwf.tickable.nodeIDs.forEach(function (nodeID) {
- vwf.callMethod(nodeID, "tick", [this.now]);
- }, vwf);
- };
-
-
-
-
-
-
- tock() {
-
- vwf.views.forEach(function (view) {
- view.tocked && view.tocked(this.now);
- }, vwf);
- }
- get getNow() {
- return this.now
- }
- }
- export {
- VirtualTime
- }
|