diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/dispatch.ts | 35 | ||||
-rw-r--r-- | js/timers.ts | 56 |
2 files changed, 44 insertions, 47 deletions
diff --git a/js/dispatch.ts b/js/dispatch.ts index 537291877..9dcd2f420 100644 --- a/js/dispatch.ts +++ b/js/dispatch.ts @@ -8,31 +8,20 @@ import * as util from "./util"; let nextCmdId = 0; const promiseTable = new Map<number, util.Resolvable<msg.Base>>(); -let fireTimers: () => void; - -export function setFireTimersCallback(fn: () => void): void { - fireTimers = fn; -} - export function handleAsyncMsgFromRust(ui8: Uint8Array): void { - // If a the buffer is empty, recv() on the native side timed out and we - // did not receive a message. - if (ui8 && ui8.length) { - const bb = new flatbuffers.ByteBuffer(ui8); - const base = msg.Base.getRootAsBase(bb); - const cmdId = base.cmdId(); - const promise = promiseTable.get(cmdId); - util.assert(promise != null, `Expecting promise in table. ${cmdId}`); - promiseTable.delete(cmdId); - const err = errors.maybeError(base); - if (err != null) { - promise!.reject(err); - } else { - promise!.resolve(base); - } + util.assert(ui8 != null && ui8.length > 0); + const bb = new flatbuffers.ByteBuffer(ui8); + const base = msg.Base.getRootAsBase(bb); + const cmdId = base.cmdId(); + const promise = promiseTable.get(cmdId); + util.assert(promise != null, `Expecting promise in table. ${cmdId}`); + promiseTable.delete(cmdId); + const err = errors.maybeError(base); + if (err != null) { + promise!.reject(err); + } else { + promise!.resolve(base); } - // Fire timers that have become runnable. - fireTimers(); } function sendInternal( diff --git a/js/timers.ts b/js/timers.ts index d06056cf2..4089d5f8b 100644 --- a/js/timers.ts +++ b/js/timers.ts @@ -2,7 +2,7 @@ import { assert } from "./util"; import * as msg from "gen/msg_generated"; import * as flatbuffers from "./flatbuffers"; -import { sendSync, setFireTimersCallback } from "./dispatch"; +import { sendAsync, sendSync } from "./dispatch"; interface Timer { id: number; @@ -37,28 +37,39 @@ function getTime(): number { return now; } -function setGlobalTimeout(due: number | null, now: number): void { +function clearGlobalTimeout(): void { + const builder = flatbuffers.createBuilder(); + msg.GlobalTimerStop.startGlobalTimerStop(builder); + const inner = msg.GlobalTimerStop.endGlobalTimerStop(builder); + globalTimeoutDue = null; + let res = sendSync(builder, msg.Any.GlobalTimerStop, inner); + assert(res == null); +} + +async function setGlobalTimeout(due: number, now: number): Promise<void> { // Since JS and Rust don't use the same clock, pass the time to rust as a // relative time value. On the Rust side we'll turn that into an absolute // value again. - // Note that a negative time-out value stops the global timer. - let timeout; - if (due === null) { - timeout = -1; - } else { - timeout = due - now; - assert(timeout >= 0); - } + let timeout = due - now; + assert(timeout >= 0); // Send message to the backend. const builder = flatbuffers.createBuilder(); - msg.SetTimeout.startSetTimeout(builder); - msg.SetTimeout.addTimeout(builder, timeout); - const inner = msg.SetTimeout.endSetTimeout(builder); - const res = sendSync(builder, msg.Any.SetTimeout, inner); - assert(res == null); - // Remember when when the global timer will fire. + msg.GlobalTimer.startGlobalTimer(builder); + msg.GlobalTimer.addTimeout(builder, timeout); + const inner = msg.GlobalTimer.endGlobalTimer(builder); globalTimeoutDue = due; + await sendAsync(builder, msg.Any.GlobalTimer, inner); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + fireTimers(); +} + +function setOrClearGlobalTimeout(due: number | null, now: number): void { + if (due == null) { + clearGlobalTimeout(); + } else { + setGlobalTimeout(due, now); + } } function schedule(timer: Timer, now: number): void { @@ -75,7 +86,7 @@ function schedule(timer: Timer, now: number): void { // If the new timer is scheduled to fire before any timer that existed before, // update the global timeout to reflect this. if (globalTimeoutDue === null || globalTimeoutDue > timer.due) { - setGlobalTimeout(timer.due, now); + setOrClearGlobalTimeout(timer.due, now); } } @@ -97,7 +108,7 @@ function unschedule(timer: Timer): void { nextTimerDue = Number(key); break; } - setGlobalTimeout(nextTimerDue, getTime()); + setOrClearGlobalTimeout(nextTimerDue, getTime()); } } else { // Multiple timers that are due at the same point in time. @@ -162,9 +173,10 @@ function fireTimers(): void { Promise.resolve(timer).then(fire); } } + // Update the global alarm to go off when the first-up timer that hasn't fired // yet is due. - setGlobalTimeout(nextTimerDue, now); + setOrClearGlobalTimeout(nextTimerDue, now); } export type Args = unknown[]; @@ -226,7 +238,7 @@ export function setInterval( return setTimer(cb, delay, args, true); } -/** Clears a previously set timer by id. */ +/** Clears a previously set timer by id. AKA clearTimeout and clearInterval. */ export function clearTimer(id: number): void { const timer = idMap.get(id); if (timer === undefined) { @@ -237,7 +249,3 @@ export function clearTimer(id: number): void { unschedule(timer); idMap.delete(timer.id); } - -// Tell the dispatcher which function it should call to fire timers that are -// due. This is done using a callback because circular imports are disallowed. -setFireTimersCallback(fireTimers); |