From 6fabdacb19f0a3e60845f8000e44550891432064 Mon Sep 17 00:00:00 2001 From: Stefan Zerkalica Date: Sun, 3 Nov 2024 12:36:48 +0300 Subject: [PATCH] $mol_offline refactoring --- fetch/fetch.ts | 4 + notify/notify.web.ts | 2 +- service/ensure/ensure.ts | 5 ++ service/plugin/plugin.ts | 2 +- service/registration/registration.web.ts | 43 +++++++++ service/worker/worker.ts | 5 +- service/worker/worker.web.ts | 108 +++++++---------------- wire/sync/sync.ts | 17 +++- 8 files changed, 104 insertions(+), 82 deletions(-) create mode 100644 service/ensure/ensure.ts create mode 100644 service/registration/registration.web.ts diff --git a/fetch/fetch.ts b/fetch/fetch.ts index 76cdcc7c4cb..89734037ddc 100644 --- a/fetch/fetch.ts +++ b/fetch/fetch.ts @@ -80,6 +80,10 @@ namespace $ { } } + export function $mol_fetch_request_clone(this: typeof $, original: Request, options?: RequestInit) { + return new Request(original, options) + } + $.$mol_fetch_request_clone = $mol_wire_sync($).$mol_fetch_request_clone export class $mol_fetch extends $mol_object2 { diff --git a/notify/notify.web.ts b/notify/notify.web.ts index 7c45ea3ec26..5e9eff39c33 100644 --- a/notify/notify.web.ts +++ b/notify/notify.web.ts @@ -31,7 +31,7 @@ namespace $ { export class $mol_notify_service_web extends $mol_notify_service { static override show({ context: title, message: body, uri: data }: $mol_notify_info) { - const registration = this.$.$mol_service_worker_web.registration() + const registration = this.$.$mol_service_worker_web.registration().native() const tag = data const existen = registration.getNotifications({ tag }) diff --git a/service/ensure/ensure.ts b/service/ensure/ensure.ts new file mode 100644 index 00000000000..78b46e0a8b4 --- /dev/null +++ b/service/ensure/ensure.ts @@ -0,0 +1,5 @@ +namespace $ { + export function $mol_service_ensure() { + return typeof window === 'undefined' + } +} diff --git a/service/plugin/plugin.ts b/service/plugin/plugin.ts index 70bb4a9a0fc..4c665e00f3b 100644 --- a/service/plugin/plugin.ts +++ b/service/plugin/plugin.ts @@ -24,7 +24,7 @@ namespace $ { static need_modify(request: Request) { return false } static modify(request: Request) { return new Response } @ $mol_action - static request_clone(original: Request, options?: RequestInit) { + protected static request_clone(original: Request, options?: RequestInit) { return new Request(original, options) } } diff --git a/service/registration/registration.web.ts b/service/registration/registration.web.ts new file mode 100644 index 00000000000..c6e56dc00f0 --- /dev/null +++ b/service/registration/registration.web.ts @@ -0,0 +1,43 @@ +namespace $ { + export class $mol_service_registration_web extends $mol_object { + constructor ( protected raw: ServiceWorkerRegistration ) { super() } + + @ $mol_mem + native() { + const reg = this.raw + // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/updatefound_event + const worker_reset = () => this.worker(null) + reg.addEventListener( 'updatefound', worker_reset) + + return $mol_wire_sync(Object.assign(reg, { + destructor: () => { + reg.removeEventListener( 'updatefound', worker_reset) + } + })) + } + + preload() { return $mol_wire_sync(this.native().navigationPreload) } + pushes() { return $mol_wire_sync(this.native().pushManager) } + + @ $mol_mem + worker(reset?: null) { + const reg = this.native() + const worker = reg.installing ?? reg.waiting ?? reg.active ?? $mol_fail(new Error('No worker in registration')) + + const state_reset = () => this.state(null) + worker.addEventListener( 'statechange', state_reset) + + return $mol_wire_sync(Object.assign(worker, { + destructor: () => worker.removeEventListener('statechange', state_reset) + })) + } + + protected container() { + return this.$.$mol_dom_context.navigator?.serviceWorker ?? $mol_fail(new Error('Service worker not found')) + } + + @ $mol_mem + state(reset?: null) { return this.worker().state ?? null } + + } +} diff --git a/service/worker/worker.ts b/service/worker/worker.ts index 7b40fde4d9b..2bd7cb2f52f 100644 --- a/service/worker/worker.ts +++ b/service/worker/worker.ts @@ -3,15 +3,14 @@ namespace $ { static path() { return 'web.js' } static send_timeout() { return 20000 } - - @ $mol_action static send(data: {}) { return null as unknown } static init() {} @ $mol_mem static prepare(next?: $mol_service_prepare_event) { - return next ? next : null + next?.prompt() + return next ?? null } static claim() {} diff --git a/service/worker/worker.web.ts b/service/worker/worker.web.ts index 90f54b513f7..658ab50ee5d 100644 --- a/service/worker/worker.web.ts +++ b/service/worker/worker.web.ts @@ -3,14 +3,17 @@ namespace $ { export class $mol_service_worker_web extends $mol_service_worker { - protected static in_worker() { return typeof window === 'undefined' } + static plugins_add_wait() { return Promise.resolve() } @ $mol_mem static init() { $mol_wire_solid() try { - if ( this.in_worker() ) this.scope_ready() - else this.registration_ready() + if ( this.$.$mol_service_ensure() ) { + $mol_wire_sync(this).plugins_add_wait() + this.plugins() + } + this.registration().worker() } catch (error) { this.$.$mol_fail_log(error) } @@ -18,7 +21,7 @@ namespace $ { } @ $mol_mem - static container() { + protected static container() { const win = this.$.$mol_dom_context if( ! win.navigator.serviceWorker ) { @@ -35,63 +38,32 @@ namespace $ { @ $mol_mem static registration() { - const reg = this.in_worker() ? this.scope().registration : this.container().register( this.path() ) - return $mol_wire_sync(reg) - } - - @ $mol_mem_key - protected static registration_direct(key: 'active' | 'installing' | 'waiting') { - this.state() - return this.registration()[key] ?? null - } - - @ $mol_mem - protected static registration_event_installing() { - const reg = this.registration_direct('installing') - reg?.addEventListener( 'statechange', e => this.state(null)) - return null - } - - @ $mol_mem - protected static registration_event_active() { - const reg = this.registration_direct('active') - reg?.addEventListener( 'updatefound', e => { - this.worker()!.addEventListener( 'statechange', e => this.state(null)) - }) + const raw = this.$.$mol_service_ensure() + ? this.scope().registration + : this.container().register( this.path() ) - return null + return new this.$.$mol_service_registration_web(raw) } - static registration_ready_async() { return this.container().ready } + static ready_async() { return this.container().ready } + static ready() { return $mol_wire_sync( this ).ready_async() } - @ $mol_mem - static registration_ready() { - this.state() - if (this.registration_direct('waiting')) this.state(null) - this.registration_event_installing() - this.registration_event_active() - return $mol_wire_sync(this).registration_ready_async() - } + @ $mol_action + protected static post_message(data: unknown) { + if (this.$.$mol_service_ensure()) { + throw new Error('Worker can\'t send messages, use clients api') + } - protected static worker() { - const reg = this.registration() - return reg.installing ?? reg.waiting ?? reg.active - } + const channel = this.$.$mol_service_channel.make({ + timeout: () => this.send_timeout() + }) - @ $mol_mem - static state(reset?: null) { return this.worker()?.state ?? null } + this.ready().active?.postMessage(data, [ channel.out() ]) - @ $mol_mem - static scope_ready() { - const scope = this.scope() - $mol_wire_sync(this).plugins_add_wait() - this.plugins() - return scope + return channel } - static async plugins_add_wait() { - await Promise.resolve() - } + static send(data: {}) { return this.post_message(data).result() } @ $mol_mem protected static scope() { @@ -153,25 +125,6 @@ namespace $ { return this.clients().openWindow(url) } - @ $mol_action - protected static post_message(data: unknown) { - const channel = this.$.$mol_service_channel.make({ - timeout: () => this.send_timeout() - }) - - this.registration_ready().active!.postMessage(data, [ channel.out() ]) - - return channel - } - - static override send(data: {}) { - if (this.in_worker()) { - throw new Error('Worker can\'t send messages, use clients api') - } - - return this.post_message(data).result() - } - static message(event: $mol_service_message_event) { const data = event.data() if (! data) return @@ -300,13 +253,16 @@ namespace $ { return $mol_wire_async(plugin).modify(event.request) } } catch (error) { - if ($mol_fail_catch(error)) { - this.$.$mol_log3_fail({ + this.$.$mol_log3_fail($mol_promise_like(error) ? { + place: `${plugin}.need_modify()`, + message: 'Promise not allowed, FetchEvent.respondWith count not be called async', + promise: error, + } : { place: `${plugin}.modify()`, - message: error.message, + message: (error as Error).message, error, - }) - } + } + ) } } diff --git a/wire/sync/sync.ts b/wire/sync/sync.ts index 90a5a328eb2..0666ecf00ad 100644 --- a/wire/sync/sync.ts +++ b/wire/sync/sync.ts @@ -19,6 +19,13 @@ namespace $ { } }, + + construct(constr, args) { + const obj = (...args: unknown[]) => new (constr as new(...args: unknown[]) => any)(...args) + const temp = $mol_wire_task.getter( obj ) + const fiber = temp( constr, args ) + return fiber.sync() + }, apply( obj, self, args ) { const temp = $mol_wire_task.getter( obj as ( ... args: any[] )=> any ) @@ -37,8 +44,16 @@ namespace $ { [K in keyof Host]: FunctionResultAwaited } + type ConstructorResultAwaited = Some extends (new (...args: infer Args) => infer Res) + ? new (...args: Args) => Awaited + : Some + type ObjectOrFunctionResultAwaited = ( - Some extends (...args: any) => unknown ? FunctionResultAwaited : {} + Some extends new (...args: unknown[]) => unknown + ? ConstructorResultAwaited + : Some extends (...args: unknown[]) => unknown + ? FunctionResultAwaited + : {} ) & ( Some extends Object ? MethodsResultAwaited : Some ) }