Files
standardnotes-app-web/packages/snjs/lib/Services/Sync/Account/Operation.ts

109 lines
3.1 KiB
TypeScript

import { ServerSyncPushContextualPayload } from '@standardnotes/models'
import { arrayByDifference, nonSecureRandomIdentifier, subtractFromArray } from '@standardnotes/utils'
import { ServerSyncResponse } from '@Lib/Services/Sync/Account/Response'
import { ResponseSignalReceiver, SyncSignal } from '@Lib/Services/Sync/Signals'
import { LegacyApiService } from '../../Api/ApiService'
export const SyncUpDownLimit = 150
/**
* A long running operation that handles multiple roundtrips from a server,
* emitting a stream of values that should be acted upon in real time.
*/
export class AccountSyncOperation {
public readonly id = nonSecureRandomIdentifier()
private pendingPayloads: ServerSyncPushContextualPayload[]
private responses: ServerSyncResponse[] = []
/**
* @param payloads An array of payloads to send to the server
* @param receiver A function that receives callback multiple times during the operation
*/
constructor(
public readonly payloads: ServerSyncPushContextualPayload[],
private receiver: ResponseSignalReceiver<ServerSyncResponse>,
private apiService: LegacyApiService,
public readonly options: {
syncToken?: string
paginationToken?: string
sharedVaultUuids?: string[]
},
) {
this.pendingPayloads = payloads.slice()
}
/**
* Read the payloads that have been saved, or are currently in flight.
*/
get payloadsSavedOrSaving(): ServerSyncPushContextualPayload[] {
return arrayByDifference(this.payloads, this.pendingPayloads)
}
popPayloads(count: number) {
const payloads = this.pendingPayloads.slice(0, count)
subtractFromArray(this.pendingPayloads, payloads)
return payloads
}
async run(): Promise<void> {
await this.receiver(SyncSignal.StatusChanged, undefined, {
completedUploadCount: this.totalUploadCount - this.pendingUploadCount,
totalUploadCount: this.totalUploadCount,
})
const payloads = this.popPayloads(this.upLimit)
const rawResponse = await this.apiService.sync(
payloads,
this.options.syncToken,
this.options.paginationToken,
this.downLimit,
this.options.sharedVaultUuids,
)
const response = new ServerSyncResponse(rawResponse)
this.responses.push(response)
this.options.syncToken = response.lastSyncToken as string
this.options.paginationToken = response.paginationToken as string
try {
await this.receiver(SyncSignal.Response, response)
} catch (error) {
console.error('Sync handle response error', error)
}
if (!this.done) {
return this.run()
}
}
get done() {
return this.pendingPayloads.length === 0 && !this.options.paginationToken
}
private get pendingUploadCount() {
return this.pendingPayloads.length
}
private get totalUploadCount() {
return this.payloads.length
}
private get upLimit() {
return SyncUpDownLimit
}
private get downLimit() {
return SyncUpDownLimit
}
get numberOfItemsInvolved() {
let total = 0
for (const response of this.responses) {
total += response.numberOfItemsInvolved
}
return total
}
}