From 85cc39f59ee6d5a12d639562bfe8d7b2b47a05a3 Mon Sep 17 00:00:00 2001 From: dfahlander Date: Wed, 27 Sep 2023 23:38:02 +0200 Subject: [PATCH] Let syncState be offline if license expired Don't connect websocket if license expired --- .../src/authentication/authenticate.ts | 2 +- addons/dexie-cloud/src/computeSyncState.ts | 12 +++++++++++- .../src/sync/InvalidLicenseError.ts | 8 ++++++++ .../dexie-cloud/src/sync/connectWebSocket.ts | 18 +++++++++++++----- addons/dexie-cloud/src/types/SyncState.ts | 1 + 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 addons/dexie-cloud/src/sync/InvalidLicenseError.ts diff --git a/addons/dexie-cloud/src/authentication/authenticate.ts b/addons/dexie-cloud/src/authentication/authenticate.ts index 4a5057a63..954e33aaf 100644 --- a/addons/dexie-cloud/src/authentication/authenticate.ts +++ b/addons/dexie-cloud/src/authentication/authenticate.ts @@ -51,7 +51,7 @@ export async function loadAccessToken( await db.table('$logins').update(claims.sub, { accessToken: refreshedLogin.accessToken, accessTokenExpiration: refreshedLogin.accessTokenExpiration, - license: refreshedLogin.license + license: refreshedLogin.license, }); return refreshedLogin; } diff --git a/addons/dexie-cloud/src/computeSyncState.ts b/addons/dexie-cloud/src/computeSyncState.ts index 6bbf077c2..82c1d5df6 100644 --- a/addons/dexie-cloud/src/computeSyncState.ts +++ b/addons/dexie-cloud/src/computeSyncState.ts @@ -1,5 +1,6 @@ import { combineLatest, Observable, of } from 'rxjs'; import { debounceTime, map, startWith, switchMap } from 'rxjs/operators'; +import { getCurrentUserEmitter } from './currentUserEmitter'; import { DexieCloudDB, SyncStateChangedEventData } from './db/DexieCloudDB'; import { isOnline } from './sync/isOnline'; import { SyncState } from './types/SyncState'; @@ -35,9 +36,17 @@ export function computeSyncState(db: DexieCloudDB): Observable { return combineLatest([ lazyWebSocketStatus, db.syncStateChangedEvent.pipe(startWith({ phase: 'initial' } as SyncStateChangedEventData)), + getCurrentUserEmitter(db.dx._novip), userIsReallyActive ]).pipe( - map(([status, syncState, userIsActive]) => { + map(([status, syncState, user, userIsActive]) => { + if (user.license?.status && user.license.status !== 'ok') { + return { + phase: 'offline', + status: 'offline', + license: user.license.status + } satisfies SyncState; + } let { phase, error, progress } = syncState; let adjustedStatus = status; if (phase === 'error') { @@ -72,6 +81,7 @@ export function computeSyncState(db: DexieCloudDB): Observable { error, progress, status: isOnline ? adjustedStatus : 'offline', + license: 'ok' }; return retState; diff --git a/addons/dexie-cloud/src/sync/InvalidLicenseError.ts b/addons/dexie-cloud/src/sync/InvalidLicenseError.ts new file mode 100644 index 000000000..61f89ff80 --- /dev/null +++ b/addons/dexie-cloud/src/sync/InvalidLicenseError.ts @@ -0,0 +1,8 @@ +import { UserLogin } from "../db/entities/UserLogin"; + +export class InvalidLicenseError extends Error { + name = "InvalidLicenseError"; + constructor() { + super(`Invalid license`); + } +} \ No newline at end of file diff --git a/addons/dexie-cloud/src/sync/connectWebSocket.ts b/addons/dexie-cloud/src/sync/connectWebSocket.ts index 9056deaa0..33b15561b 100644 --- a/addons/dexie-cloud/src/sync/connectWebSocket.ts +++ b/addons/dexie-cloud/src/sync/connectWebSocket.ts @@ -24,6 +24,7 @@ import { WSConnectionMsg, WSObservable, } from '../WSObservable'; +import { InvalidLicenseError } from './InvalidLicenseError'; function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -68,11 +69,14 @@ export function connectWebSocket(db: DexieCloudDB) { map((userLogin) => [userLogin, syncState] as const) ) ), - switchMap(([userLogin, syncState]) => - userIsReallyActive.pipe( + switchMap(([userLogin, syncState]) => { + if (userLogin.license?.status && userLogin.license.status !== 'ok') { + throw new InvalidLicenseError(); + } + return userIsReallyActive.pipe( map((isActive) => [isActive ? userLogin : null, syncState] as const) - ) - ), + ); + }), switchMap(([userLogin, syncState]) => { if (userLogin?.isLoggedIn && !syncState?.realms.includes(userLogin.userId!)) { // We're in an in-between state when user is logged in but the user's realms are not yet synced. @@ -131,11 +135,15 @@ export function connectWebSocket(db: DexieCloudDB) { switchMap(() => createObservable()) ); } else { - return throwError(error); + return throwError(()=>error); } }), catchError((error) => { db.cloud.webSocketStatus.next("error"); + if (error instanceof InvalidLicenseError) { + // Don't retry. Just throw and don't try connect again. + return throwError(() => error); + } return from(waitAndReconnectWhenUserDoesSomething(error)).pipe( switchMap(() => createObservable()) ); diff --git a/addons/dexie-cloud/src/types/SyncState.ts b/addons/dexie-cloud/src/types/SyncState.ts index 6e9791e46..1ae95137a 100644 --- a/addons/dexie-cloud/src/types/SyncState.ts +++ b/addons/dexie-cloud/src/types/SyncState.ts @@ -5,4 +5,5 @@ export interface SyncState { phase: SyncStatePhase; progress?: number; // 0..100 error?: Error; // If phase === "error" + license?: 'ok' | 'expired' | 'deactivated'; }