import { o_assign, o_defprop, is_func, as_func, _unref, _ref } from './builtins.jsy' import { ao_defer_v, ao_fence_v, ao_when, ao_track_when, ao_fence_when, ao_push_stream } from 'roap' export { ao_defer_v, ao_fence_v, ao_when, ao_track_when, ao_fence_when, ao_push_stream } from 'roap' const timeout_ttl = @{} extend: false reset() :: this.extend = true; return this with_reset(fn) :: return (...args) => @ this.reset(), fn(...args) create_ttl(query_ttl) :: let self = @{} __proto__: this, async _query_ttl(cancel) :: try :: if query_ttl :: await query_ttl(self) finally :: if ! self.extend :: cancel() self.extend = false return self export function bindTimeouts(ms_interval, on_fn_error) :: ms_interval = (0 | ms_interval) || 67 // 15 ticks per second const qz = [[], []] _unref @ setInterval(tick, ms_interval, Promise.resolve(add)) let [f_tick, resolve_tick] = ao_fence_v() let [f_empty, resolve_empty] = ao_fence_v() return o_assign @ add, @{} add, f_tick, f_empty ao_defer_v, ao_fence_v, ao_when, ao_track_when, ao_fence_when, ao_push_stream, async absent(absent, ...args) :: let res = await this.race(...args) return this !== res ? res : absent race(ms_min_timeout, ...promises) :: let dp = ao_defer_v() promises.push(dp[0]) add(ms_min_timeout, dp[1]) return Promise.race(promises) interval(ms_opt, callback) :: ms_opt = _as_ms_opt(ms_opt, {z: 1}) as_func(callback) let x = @{} cancel() :: x = null interval() :: if x :: callback(x.cancel) if x :: x.schedule() schedule() :: if x :: add @ ms_opt, x.interval return x.cancel if ms_opt.initial :: callback(x.cancel) return x.schedule() hashbelt(ms_opt, max_length=4, create=Object) :: let belt = [create()] add.interval @ ms_opt, rotate_belt return belt function rotate_belt() :: while max_length <= belt.length :: belt.pop() belt.unshift @ create() ttl(ms_opt, query_ttl) :: let ttl = timeout_ttl.create_ttl(query_ttl) ttl.cancel = add.interval @ _as_ms_opt(ms_opt, {ms: 60000, z:1}) ttl._query_ttl return ttl function add(ms_opt, callback) :: let res if ! callback :: // default to a promise [res, callback] = ao_defer_v() ms_opt = _as_ms_opt(ms_opt) let idx = Math.max @ 1, Math.ceil @ ms_opt.ms / ms_interval let z = 0|ms_opt.z let _q = qz[z] if ! _q :: _q = qz[z] = [] let _qi = _q[idx] if ! _qi :: _q[idx] = _qi = [] _qi.push @ as_func(callback) return res function tick(p_self) :: let _q, tip for _q of qz :: if tip = _q.shift() :: for let fn of tip :: p_self.then(fn).catch(on_fn_error) if 0 === qz[0].length :: resolve_empty(add) resolve_tick(add) function _as_ms_opt(opt, def) :: return 'number' === typeof opt ? {... def, ms: opt} : {... def, ... opt}