11import { timeout } from 'thingies/lib/timeout' ;
2+ import { SESSION } from 'json-joy/lib/json-crdt-patch/constants' ;
3+ import { ts } from 'json-joy/lib/json-crdt-patch' ;
4+ import { once } from 'thingies' ;
25import type { RemoteBlockPatch } from '../../remote/types' ;
36import type { ServerCrudLocalHistoryCore } from './ServerCrudLocalHistoryCore' ;
47import type { BlockSyncMetadata } from './types' ;
5- import { SESSION } from 'json-joy/lib/json-crdt-patch/constants' ;
6- import { ts } from 'json-joy/lib/json-crdt-patch' ;
8+ import type { Subscription } from 'rxjs' ;
79
810const SYNC_FILE_NAME = 'sync.cbor' ;
911
@@ -25,29 +27,38 @@ export interface ServerCrudLocalHistorySyncOpts {
2527}
2628
2729export class ServerCrudLocalHistorySync {
28- private syncLoopTimer : any = 0 ;
30+ // private syncLoopTimer: any = 0;
31+ private _conSub : Subscription | undefined = undefined ;
2932
3033 constructor (
3134 protected readonly opts : ServerCrudLocalHistorySyncOpts ,
3235 protected readonly core : ServerCrudLocalHistoryCore ,
3336 ) { }
3437
38+ @once
3539 public start ( ) : void {
36-
40+ this . _conSub = this . core . connected$ . subscribe ( ( connected ) => {
41+ if ( connected ) {
42+ this . syncAll ( ) . catch ( ( ) => { } ) ;
43+ } else {
44+
45+ }
46+ } ) ;
3747 }
3848
49+ @once
3950 public stop ( ) : void {
40-
51+ this . _conSub ?. unsubscribe ( ) ;
4152 }
4253
4354 protected remoteTimeout ( ) : number {
4455 return this . opts . remoteTimeout ?? 5000 ;
4556 }
4657
47- public async push ( collection : string [ ] , id : string ) : Promise < boolean > {
48- return await this . lock < boolean > ( { collection, id} , async ( ) => {
49- // TODO: handle case when this times out, but actually succeeds, so on re-sync it handles the case when the block is already synced.
58+ public async sync ( collection : string [ ] , id : string ) : Promise < boolean > {
59+ return await this . lockItemSync < boolean > ( { collection, id} , async ( ) => {
5060 try {
61+ // TODO: handle case when this times out, but actually succeeds, so on re-sync it handles the case when the block is already synced.
5162 return timeout ( this . remoteTimeout ( ) , async ( ) => {
5263 const core = this . core ;
5364 if ( ! core . connected$ . getValue ( ) ) return false ;
@@ -86,7 +97,10 @@ export class ServerCrudLocalHistorySync {
8697 } ) ;
8798 }
8899
89- public async lock < T > (
100+ /**
101+ * Locks a specific item for synchronization.
102+ */
103+ private async lockItemSync < T > (
90104 {
91105 collection,
92106 id,
@@ -141,28 +155,42 @@ export class ServerCrudLocalHistorySync {
141155 }
142156 }
143157
144- protected async * listDirty ( collection : string [ ] = [ 'sync' , 'dirty' ] ) : AsyncIterableIterator < { collection : string [ ] ; id : string } > {
158+ protected async * listDirty ( collection : string [ ] = [ 'sync' , 'dirty' ] ) : AsyncIterableIterator < ItemId > {
145159 for await ( const entry of this . core . crud . scan ( collection ) ) {
146160 if ( entry . type === 'collection' ) yield * this . listDirty ( [ ...collection , entry . id ] ) ;
147161 else yield { collection, id : entry . id } ;
148162 }
149163 }
150164
151- protected async * syncDirty ( ) : AsyncIterableIterator < [ block : { collection : string [ ] ; id : string } , success : boolean ] > {
165+ protected async * syncDirty ( ) : AsyncIterableIterator < SyncResult > {
152166 for await ( const block of this . listDirty ( ) ) {
153- const { collection, id} = block ;
154- const success = await this . push ( collection , id ) ;
155- yield [ block , success ] ;
167+ const { collection : [ _sync , _dirty , ...collection ] , id} = block ;
168+ try {
169+ const success = await this . sync ( collection , id ) ;
170+ yield [ block , success ] ;
171+ } catch ( error ) {
172+ yield [ block , false , error ] ;
173+ }
156174 }
157175 }
158176
159- protected async syncAllDirty ( ) : Promise < SyncResultList > {
177+ public async syncAll ( ) : Promise < SyncResultList > {
178+ const locks = this . core . locks ;
179+ if ( locks . isLocked ( 'sync' ) ) return [ ] ;
160180 const list : SyncResultList = [ ] ;
161- for await ( const result of this . syncDirty ( ) ) list . push ( result ) ;
162- return list ;
181+ const duration = 30000 ;
182+ const start = Date . now ( ) ;
183+ return await locks . lock ( 'sync' , duration , 3000 ) ( async ( ) => {
184+ for await ( const result of this . syncDirty ( ) ) {
185+ list . push ( result ) ;
186+ const now = Date . now ( ) ;
187+ if ( now - start + 100 > duration ) break ;
188+ }
189+ return list ;
190+ } ) ;
163191 }
164192}
165193
166194export type ItemId = { collection : string [ ] , id : string } ;
167- export type SyncResult = [ block : ItemId , success : boolean ] ;
195+ export type SyncResult = [ block : ItemId , success : boolean , err ?: Error | unknown ] ;
168196export type SyncResultList = SyncResult [ ] ;
0 commit comments