solverforge-fsr / static /app-route-state.js
blackopsrepl's picture
feat(fsr): add snapshot-scoped route geometry
ae32abe
/* app-route-state.js - snapshot-scoped route geometry loading */
(function () {
'use strict';
var FSR = window.FSR = window.FSR || {};
FSR.createRouteGeometryController = function (options) {
var currentPlanIdentity = null;
var currentRouteIdentity = null;
var routeInFlightIdentity = null;
var latestRouteIdentity = null;
var routeRequestToken = 0;
return {
identityFrom: identityFrom,
invalidate: invalidate,
load: load,
setPlanIdentity: setPlanIdentity,
};
function invalidate() {
routeRequestToken += 1;
currentPlanIdentity = null;
currentRouteIdentity = null;
routeInFlightIdentity = null;
latestRouteIdentity = null;
if (options.onClearFocus) options.onClearFocus();
options.onRoutesChange(null);
}
function setPlanIdentity(identity) {
currentPlanIdentity = identity;
if (!identityEquals(currentRouteIdentity, identity)) {
currentRouteIdentity = null;
options.onRoutesChange(null);
}
}
function load(identity) {
if (!identity) return Promise.resolve();
latestRouteIdentity = identity;
if (routeInFlightIdentity || identityEquals(currentRouteIdentity, identity)) {
return Promise.resolve();
}
return fetchLatest();
}
function fetchLatest() {
var identity = latestRouteIdentity;
if (!identity || routeInFlightIdentity || identityEquals(currentRouteIdentity, identity)) {
return Promise.resolve();
}
var token = routeRequestToken;
routeInFlightIdentity = identity;
return options.utils.fetchJobRoutes(identity.jobId, identity.snapshotRevision)
.then(function (routes) {
if (!responseStillCurrent(token, identity)) return;
currentRouteIdentity = identity;
options.onRoutesChange(routes);
})
.catch(function (err) {
if (!responseStillCurrent(token, identity)) return;
currentRouteIdentity = null;
options.onRoutesChange(null);
console.error('Route geometry failed:', err);
})
.then(function () {
if (identityEquals(routeInFlightIdentity, identity)) routeInFlightIdentity = null;
if (
latestRouteIdentity
&& !identityEquals(latestRouteIdentity, identity)
&& responseStillCurrent(token, latestRouteIdentity)
&& !identityEquals(currentRouteIdentity, latestRouteIdentity)
) {
return fetchLatest();
}
});
}
function identityFrom(meta) {
var jobId = meta && meta.jobId != null ? meta.jobId : options.solver.getJobId();
var snapshotRevision = meta && meta.snapshotRevision != null
? meta.snapshotRevision
: options.solver.getSnapshotRevision();
if (jobId == null || jobId === '' || snapshotRevision == null) return null;
return { jobId: String(jobId), snapshotRevision: String(snapshotRevision) };
}
function responseStillCurrent(token, identity) {
return token === routeRequestToken && identityEquals(currentPlanIdentity, identity);
}
function identityEquals(left, right) {
return !!left
&& !!right
&& left.jobId === right.jobId
&& left.snapshotRevision === right.snapshotRevision;
}
};
})();