diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/html/env.nim | 14 | ||||
-rw-r--r-- | src/js/timeout.nim | 123 | ||||
-rw-r--r-- | src/local/client.nim | 14 |
3 files changed, 61 insertions, 90 deletions
diff --git a/src/html/env.nim b/src/html/env.nim index 0751d12f..6b70c74f 100644 --- a/src/html/env.nim +++ b/src/html/env.nim @@ -109,19 +109,19 @@ proc fetch[T: JSRequest|string](window: Window; input: T; return ok(promise) return ok(window.loader.fetch(input.request)) -proc setTimeout[T: JSValue|string](window: Window; handler: T; - timeout = 0i32): int32 {.jsfunc.} = - return window.timeouts.setTimeout(handler, timeout) +proc setTimeout(window: Window; handler: JSValue; timeout = 0i32): int32 + {.jsfunc.} = + return window.timeouts.setTimeout(ttTimeout, handler, timeout) -proc setInterval[T: JSValue|string](window: Window; handler: T; - interval = 0i32): int32 {.jsfunc.} = - return window.timeouts.setInterval(handler, interval) +proc setInterval(window: Window; handler: JSValue; interval = 0i32): int32 + {.jsfunc.} = + return window.timeouts.setTimeout(ttInterval, handler, interval) proc clearTimeout(window: Window; id: int32) {.jsfunc.} = window.timeouts.clearTimeout(id) proc clearInterval(window: Window; id: int32) {.jsfunc.} = - window.timeouts.clearInterval(id) + window.clearTimeout(id) func console(window: Window): Console {.jsfget.} = return window.internalConsole diff --git a/src/js/timeout.nim b/src/js/timeout.nim index 519ab8a6..6c4b157f 100644 --- a/src/js/timeout.nim +++ b/src/js/timeout.nim @@ -2,20 +2,25 @@ import std/selectors import std/tables import io/dynstream +import js/console +import monoucha/fromjs import monoucha/javascript +import types/opt type - TimeoutEntry = tuple - handler: (proc()) - fdi: int - tofree: JSValue + TimeoutType* = enum + ttTimeout = "setTimeout handler" + ttInterval = "setInterval handler" + + TimeoutEntry = ref object + t: TimeoutType + fd: int + val: JSValue TimeoutState* = object timeoutid: int32 timeouts: Table[int32, TimeoutEntry] - intervals: Table[int32, TimeoutEntry] - timeout_fdis: Table[int, int32] - interval_fdis: Table[int, int32] + timeoutFds: Table[int, int32] selector: Selector[int] #TODO would be better with void... jsctx: JSContext err: DynStream #TODO shouldn't be needed @@ -31,88 +36,54 @@ func newTimeoutState*(selector: Selector[int]; jsctx: JSContext; err: DynStream; ) func empty*(state: TimeoutState): bool = - return state.timeouts.len == 0 and state.intervals.len == 0 - -#TODO varargs -proc setTimeout*[T: JSValue|string](state: var TimeoutState; handler: T; - timeout = 0i32): int32 = - let id = state.timeoutid - inc state.timeoutid - let fdi = state.selector.registerTimer(max(timeout, 1), true, 0) - state.timeout_fdis[fdi] = id - when T is string: - let evalJSFree = state.evalJSFree - state.timeouts[id] = ((proc() = - evalJSFree(handler, "setTimeout handler") - ), fdi, JS_NULL) - else: - let fun = JS_DupValue(state.jsctx, handler) - let jsctx = state.jsctx - let err = state.err - state.timeouts[id] = ((proc() = - let ret = JS_Call(jsctx, fun, JS_UNDEFINED, 0, nil) - if JS_IsException(ret): - jsctx.writeException(err) - JS_FreeValue(jsctx, ret) - ), fdi, fun) - return id + return state.timeouts.len == 0 proc clearTimeout*(state: var TimeoutState; id: int32) = if id in state.timeouts: - let timeout = state.timeouts[id] - state.selector.unregister(timeout.fdi) - JS_FreeValue(state.jsctx, timeout.tofree) - state.timeout_fdis.del(timeout.fdi) + let entry = state.timeouts[id] + state.selector.unregister(entry.fd) + JS_FreeValue(state.jsctx, entry.val) + state.timeoutFds.del(entry.fd) state.timeouts.del(id) -proc clearInterval*(state: var TimeoutState; id: int32) = - if id in state.intervals: - let interval = state.intervals[id] - state.selector.unregister(interval.fdi) - JS_FreeValue(state.jsctx, interval.tofree) - state.interval_fdis.del(interval.fdi) - state.intervals.del(id) - #TODO varargs -proc setInterval*[T: JSValue|string](state: var TimeoutState; handler: T; - interval = 0i32): int32 = +proc setTimeout*(state: var TimeoutState; t: TimeoutType; handler: JSValue; + timeout = 0i32): int32 = let id = state.timeoutid inc state.timeoutid - let fdi = state.selector.registerTimer(max(interval, 1), false, 0) - state.interval_fdis[fdi] = id - when T is string: - let evalJSFree = state.evalJSFree - state.intervals[id] = ((proc() = - evalJSFree(handler, "setInterval handler") - ), fdi, JS_NULL) - else: - let fun = JS_DupValue(state.jsctx, handler) - let jsctx = state.jsctx - let err = state.err - state.intervals[id] = ((proc() = - let ret = JS_Call(jsctx, handler, JS_UNDEFINED, 0, nil) - if JS_IsException(ret): - jsctx.writeException(err) - JS_FreeValue(jsctx, ret) - ), fdi, fun) + let fd = state.selector.registerTimer(max(timeout, 1), t == ttTimeout, 0) + state.timeoutFds[fd] = id + state.timeouts[id] = TimeoutEntry( + t: t, + fd: fd, + val: JS_DupValue(state.jsctx, handler) + ) return id +proc runEntry(state: var TimeoutState; entry: TimeoutEntry; name: string) = + if JS_IsFunction(state.jsctx, entry.val): + let ret = JS_Call(state.jsctx, entry.val, JS_UNDEFINED, 0, nil) + if JS_IsException(ret): + state.jsctx.writeException(state.err) + JS_FreeValue(state.jsctx, ret) + else: + let s = fromJS[string](state.jsctx, entry.val) + if s.isSome: + state.evalJSFree(s.get, "setInterval handler") + proc runTimeoutFd*(state: var TimeoutState; fd: int): bool = - if fd in state.interval_fdis: - state.intervals[state.interval_fdis[fd]].handler() - return true - elif fd in state.timeout_fdis: - let id = state.timeout_fdis[fd] - let timeout = state.timeouts[id] - timeout.handler() + if fd notin state.timeoutFds: + return false + let id = state.timeoutFds[fd] + let entry = state.timeouts[id] + state.runEntry(entry, $entry.t) + if entry.t == ttTimeout: state.clearTimeout(id) - return true - return false + return true proc clearAll*(state: var TimeoutState) = for entry in state.timeouts.values: - JS_FreeValue(state.jsctx, entry.tofree) - for entry in state.intervals.values: - JS_FreeValue(state.jsctx, entry.tofree) + state.selector.unregister(entry.fd) + JS_FreeValue(state.jsctx, entry.val) state.timeouts.clear() - state.intervals.clear() + state.timeoutFds.clear() diff --git a/src/local/client.nim b/src/local/client.nim index a852d8cd..bdb796a7 100644 --- a/src/local/client.nim +++ b/src/local/client.nim @@ -360,19 +360,19 @@ proc input(client: Client): EmptyPromise = p.resolve() return p -proc setTimeout[T: JSValue|string](client: Client; handler: T; - timeout = 0i32): int32 {.jsfunc.} = - return client.timeouts.setTimeout(handler, timeout) +proc setTimeout(client: Client; handler: JSValue; timeout = 0i32): int32 + {.jsfunc.} = + return client.timeouts.setTimeout(ttTimeout, handler, timeout) -proc setInterval[T: JSValue|string](client: Client; handler: T; - interval = 0i32): int32 {.jsfunc.} = - return client.timeouts.setInterval(handler, interval) +proc setInterval(client: Client; handler: JSValue; interval = 0i32): int32 + {.jsfunc.} = + return client.timeouts.setTimeout(ttInterval, handler, interval) proc clearTimeout(client: Client; id: int32) {.jsfunc.} = client.timeouts.clearTimeout(id) proc clearInterval(client: Client; id: int32) {.jsfunc.} = - client.timeouts.clearInterval(id) + client.clearTimeout(id) let SIGWINCH {.importc, header: "<signal.h>", nodecl.}: cint |