diff --git a/build/build.node.ts b/build/build.node.ts index 97059586fa3..ec44c093bb8 100644 --- a/build/build.node.ts +++ b/build/build.node.ts @@ -1194,8 +1194,11 @@ namespace $ { } } catch( error ) { - if( $mol_promise_like( error ) ) $mol_fail_hidden( error ) - $mol_fail_log( error ) + if ($mol_fail_catch(error)) { + if (! (error as Error).message.match(/code E404/)) { + console.error( error ) + } + } } ++ version[2] diff --git a/build/client/client.js b/build/client/client.js index 22d91b68efe..8067a450afd 100644 --- a/build/client/client.js +++ b/build/client/client.js @@ -1,19 +1,31 @@ -function $mol_build_client() { - - const origin = document.location.origin.replace( /^http/ , 'ws' ) - const path = document.location.pathname - const uri = origin + path +// @ts-check - const socket = new WebSocket( uri ) - - socket.onclose = ()=> setTimeout( ()=> $mol_build_client() , 1000 ) - - socket.onmessage = message => { - if( message.data !== '$mol_build_obsolete' ) return - location.reload() - } +class $mol_build_client { + static closed = false + static run() { + const origin = document.location.origin.replace( /^http/ , 'ws' ) + const path = document.location.pathname + const uri = origin + path + + const socket = new WebSocket( uri ) + + socket.onclose = ()=> { + this.closed = true + setTimeout( ()=> $mol_build_client.run() , 1000 ) + } + socket.onopen = () => { + if (this.closed) location.reload() + this.closed = false + } + + socket.onmessage = message => { + if( message.data !== '$mol_build_obsolete' ) return + location.reload() + } + + } } -$mol_build_client() +$mol_build_client.run() diff --git a/file/file.node.ts b/file/file.node.ts index 9ed41f767bb..ba433be21a6 100644 --- a/file/file.node.ts +++ b/file/file.node.ts @@ -23,7 +23,7 @@ namespace $ { function buffer_normalize(buf: Buffer): Uint8Array { return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength) } - + export class $mol_file_node extends $mol_file { static relative( path : string ) { @@ -97,7 +97,7 @@ namespace $ { protected override drop() { $node.fs.unlinkSync( this.path() ) } - + @ $mol_action protected override read() { const path = this.path() @@ -175,6 +175,7 @@ namespace $ { return Object.assign(Writable.toWeb(stream), { destructor }) as WritableStream } + } $.$mol_file = $mol_file_node diff --git a/file/file.ts b/file/file.ts index dd764319c07..dc7b9d1ddb6 100644 --- a/file/file.ts +++ b/file/file.ts @@ -36,7 +36,7 @@ namespace $ { } @ $mol_mem - protected stat(next? : $mol_file_stat | null, virt?: 'virt') { + stat(next? : $mol_file_stat | null, virt?: 'virt') { const path = this.path() const parent = this.parent() @@ -46,10 +46,17 @@ namespace $ { // Лучше ограничить mam-ом const root = this.$.$mol_file.watch_root ?? this if ( this !== root ) { - // Если родитель удалился, надо ресетнуть все дочерние на любой глубине - // Родитель может удалиться, потом создасться, а дочерняя папка только удалиться. - // Поэтому parent.exists() не запустит перевычисления - // parent.version() меняется не только при удалении, иногда будет ложное срабатывание stat + /* + Если родитель удалился, надо ресетнуть все дочерние на любой глубине + Родитель может удалиться, потом создасться, а дочерняя папка только удалиться. + Поэтому parent.exists() не запустит перевычисления + + parent.version() меняется не только при удалении, будет ложное срабатывание + события вотчера addDir сбрасывает только parent.sub(), а parent.version() может остаться та же + тогда дочерний не перзапустится + Если addDir будет сбрасывать parent.version(), то будет лишний раз перевычислен parent, хоть и он сам не поменялся + */ + parent.version() } @@ -78,9 +85,9 @@ namespace $ { if ( type === 'addDir' ) { // добавилась папка, у parent обновляем список директорий в sub - this.added.add(file) // дочерние ресетим - this.changed.add(file) + // версию папки не меняем, т.к. иначе выполнится логика, связанная + this.added.add(file) } if ( type === 'unlinkDir') { @@ -101,6 +108,7 @@ namespace $ { @ $mol_action static flush() { + // this.flush_counter() // Пока flush работает, вотчер сюда не заходит, но может добавлять новые изменения // на каждом перезапуске они применятся // Пока run выполняется, изменения накапливаются, в конце run вызывается flush @@ -108,10 +116,10 @@ namespace $ { for (const file of this.added) { const parent = file.parent() - if (! $mol_wire_probe(() => parent.sub())) continue try { - parent.sub(null) + if ( $mol_wire_probe(() => parent.sub())) parent.sub(null) + file.reset() } catch (error) { if ($mol_fail_catch(error)) $mol_fail_log(error) } @@ -133,6 +141,7 @@ namespace $ { } protected static watching = true + protected static lock = new $mol_lock @ $mol_action @@ -154,7 +163,7 @@ namespace $ { static watch_off(side_effect: () => Result, affected_dir: string) { // ждем, пока выполнится предыдущий watch_off - const unlock = this.lock.grab() + const unlock = () => {} // this.lock.grab() this.watching_off(affected_dir) try { @@ -189,6 +198,56 @@ namespace $ { protected copy(to: string) {} protected read() { return new Uint8Array } protected write(buffer: Uint8Array) { } + protected kids() { + return [] as readonly $mol_file[] + } + stream_read() { return new ReadableStream } + stream_write() { return new WritableStream } + + @ $mol_mem + buffer( next? : Uint8Array ) { + + if( next === undefined ) { + + if( !this.stat() ) return new Uint8Array + + const prev = $mol_mem_cached( ()=> this.buffer() ) + + next = this.read() + + if( prev !== undefined && !$mol_compare_array( prev, next ) ) { + this.$.$mol_log3_rise({ + place: `$mol_file_node.buffer()`, + message: 'Changed' , + path: this.relate() , + }) + } + + return next + + } + + this.parent().exists( true ) + + this.stat( this.stat_make(next.length), 'virt' ) + + this.write(next) + + return next + + } + + @ $mol_action + stat_make(size: number) { + const now = new Date() + return { + type: 'file', + size, + atime: now, + mtime: now, + ctime: now, + } as const + } @ $mol_mem_key clone(to: string) { @@ -262,46 +321,6 @@ namespace $ { return match ? match[ 1 ].substring( 1 ) : '' } - - @ $mol_mem - buffer( next? : Uint8Array ) { - if( next === undefined ) { - - if( !this.stat() ) return new Uint8Array - - const prev = $mol_mem_cached( ()=> this.buffer() ) - - next = this.read() - - if( prev !== undefined && ! $mol_compare_array( prev, next ) ) { - this.$.$mol_log3_rise({ - place: `$mol_file_node.buffer()`, - message: 'Changed' , - path: this.relate() , - }) - } - - return next - - } - - this.parent().exists( true ) - - const now = new Date - this.stat( { - type: 'file', - size: next.length, - atime: now, - mtime: now, - ctime: now, - }, 'virt' ) - - this.write(next) - - return next - - } - text(next?: string, virt?: 'virt') { // Если пушим в text, то при сбросе таргета надо перезапускать пуш // Например файл удалили, потом снова создали, версия поменялась - перезаписываем @@ -312,14 +331,7 @@ namespace $ { @ $mol_mem text_int(next?: string, virt?: 'virt') { if( virt ) { - const now = new Date - this.stat( { - type: 'file', - size: 0, - atime: now, - mtime: now, - ctime: now, - }, 'virt' ) + this.stat( this.stat_make(0), 'virt' ) return next! } @@ -337,16 +349,12 @@ namespace $ { if (! this.exists() ) return [] if ( this.type() !== 'dir') return [] - this.version() + this.stat() // Если дочерний file удалился, список надо обновить return this.kids().filter(file => file.exists()) } - protected kids() { - return [] as readonly $mol_file[] - } - resolve(path: string): $mol_file { throw new Error('implement') } @@ -386,14 +394,6 @@ namespace $ { } } - stream_read(): ReadableStream { - throw new Error('implement') - } - - stream_write(): WritableStream { - throw new Error('implement') - } - toJSON() { return this.path() } diff --git a/file/file.web.ts b/file/file.web.ts index 84fe273851e..ffad921b8f3 100644 --- a/file/file.web.ts +++ b/file/file.web.ts @@ -10,14 +10,13 @@ namespace $ { ? new URL( '.' , ($mol_dom_context.document.currentScript as any)['src'] ).toString() : '' - protected override write(next: Uint8Array) { - throw new Error(`Saving content not supported: ${this.path()}`) - } + @ $mol_mem + override buffer( next? : Uint8Array ) { + if (next !== undefined) throw new Error(`Saving content not supported: ${this.path}`) - @ $mol_action - protected override read( ) { const response = $mol_fetch.response(this.path()) if (response.native.status === 404) return new Uint8Array + // throw new $mol_file_not_found(`File not found: ${this.path()}`) return new Uint8Array(response.buffer()) } @@ -42,7 +41,6 @@ namespace $ { throw new Error('$mol_file_web.drop() not implemented') } - @ $mol_mem protected override kids() : readonly $mol_file[] { throw new Error('$mol_file_web.sub() not implemented') } @@ -50,6 +48,7 @@ namespace $ { override relate( base = ( this.constructor as typeof $mol_file ).relative( '.' )): string { throw new Error('$mol_file_web.relate() not implemented') } + } $.$mol_file = $mol_file_web diff --git a/run/run.node.test.ts b/run/run.node.test.ts index 0859800947a..850321d2d26 100644 --- a/run/run.node.test.ts +++ b/run/run.node.test.ts @@ -2,19 +2,43 @@ namespace $ { $mol_test( { async 'exec timeout auto kill child process'($) { let close_mock = () => {} + const error_message = 'Run error, timeout' - const context_mock = $.$mol_ambient({ - $mol_run_spawn: () => ({ + function mol_run_spawn_sync_mock() { + return { + output: [], + stdout: error_message, + stderr: '', + status: 0, + signal: null, + pid: 123, + } + } + + function mol_run_spawn_mock() { + return { on(name: string, cb: () => void) { if (name === 'exit') close_mock = cb }, kill() { close_mock() } - } as any) + } as any + } + + const context_mock = $.$mol_ambient({ + $mol_run_spawn_sync: mol_run_spawn_sync_mock, + $mol_run_spawn: mol_run_spawn_mock }) - + + class $mol_run_mock extends $mol_run { + static get $() { return context_mock } + static override async_enabled() { + return true + } + } + let message = '' try { - const res = await $mol_wire_async(context_mock.$mol_run).spawn({ + const res = await $mol_wire_async($mol_run_mock).spawn({ command: 'sleep 10', dir: '.', timeout: 10, @@ -23,7 +47,7 @@ namespace $ { } catch (e) { message= (e as Error).message } - $mol_assert_equal(message, 'Run error, timeout') + $mol_assert_equal(message, error_message) } } ) diff --git a/run/run.node.ts b/run/run.node.ts index f3e494709ee..ebfcc5abc22 100644 --- a/run/run.node.ts +++ b/run/run.node.ts @@ -32,8 +32,12 @@ namespace $ { export class $mol_run extends $mol_object { + static async_enabled() { + return Boolean(this.$.$mol_env()['MOL_RUN_ASYNC']) + } + static spawn(options: $mol_run_options) { - const sync = ! this.$.$mol_env()['MOL_RUN_ASYNC'] || ! Boolean($mol_wire_auto()) + const sync = ! this.async_enabled() || ! Boolean($mol_wire_auto()) const env = options.env ?? this.$.$mol_env() return $mol_wire_sync(this).spawn_async( { ...options, sync, env } )