import { o_assign, is_func, as_func } from '../../code/builtins.jsy' import { DiscoFirst } from './ops.jsy' export function discovery_plugin(opt={}) :: let disco_first = new DiscoFirst() let _lut_discover_fn = @{} 'function': (accept, fn) => q => accept(q) ? fn(q) : void 0 'string': (accept, fn) => q => q.key.startsWith(accept) ? fn(q) : void 0 'boolean': (k, arg) => k && bind_discover_path(arg) 'object'(accept, fn) :: if ! fn :: as_func(accept.discover) fn = q => accept.discover(q) return ! is_func(accept.test) ? fn : q => accept.test(q.key) ? fn(q) : void 0 let _disco_ = @{} _disco_cache() :: return this.timeouts.hashbelt(opt.ms_rotate || 15000) _disco_timeout(resolve) :: return this.timeouts(opt.ms_timeout || 2000, resolve) addDiscovery(accept, arg) :: if arg || !is_func(accept) :: accept = _lut_discover_fn[typeof accept](accept, arg) this.discovery = [... (this.discovery || []), as_func(accept)] return @{} subclass(Hub) :: o_assign @ Hub.FabricRouter.prototype, _disco_, @{} async discoverRoute(id_route, router_ctx) :: let fns = this.discovery if fns :: router_ctx ||= this.router_ctx let query = @{} __proto__: router_ctx key: id_route, id_route, kind: 'route', return await disco_first.cached(this, fns, query) o_assign @ Hub.TargetRouter.prototype, _disco_, @{} async discoverTarget(id_target, pktctx) :: let fns = this.discovery if fns :: let query = @{} __proto__: pktctx key: id_target, id_target, kind: 'target', return await disco_first.cached(this, fns, query) export function bind_discover_path(path_sep='.') :: return async query => :: let id_route = query.id_route let i = id_route.lastIndexOf(path_sep) if 0 < i :: let id_fwd = id_route.slice(0,i) let fn_route = await query.resolveRoute(id_fwd, true, true) if fn_route :: query.hub_router.addRoute(id_route, fn_route) return fn_route