export class DiscoFirst :: constructor() :: this._cache = new WeakMap() async _disco_all(discovery_fns) :: let q=[] for let fn of discovery_fns :: q.push @ this._disco_one(fn) for let p of q :: await p this.query.abort() async _disco_one(fn_disco) :: try :: let res = await fn_disco(this.query) this.query.answer(res) catch err :: this.host._on_error('discovery', err) async cached(host, discovery_fns, query) :: let belt = this._cache.get(discovery_fns) if ! belt :: belt = host._disco_cache() this._cache.set(discovery_fns, belt) let ans, cache, key = query.key for cache of belt :: if ans = cache[key] :: return ans cache = belt[0] cache[key] = ans = this.search @ host, discovery_fns, query ans.finally @:: delete cache[key] return ans async search(host, discovery_fns, query) :: let [p_search, _resolve] = host.timeouts.ao_defer_v() let self = @{} __proto__: this, host, query Object.assign @ query, @{} host, p_search, done: false abort() :: _resolve(false) async answer(res) :: if null != res :: if res.then :: res = await res if true === res || ! res :: res = null // falsy and true is "already exists" _resolve(res) return res try :: host._disco_timeout(query.abort) self._disco_all(discovery_fns) return await p_search finally :: query.done = true