mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 18:31:52 +00:00
feat: get rid of cyclic dep between patch-db and api service
Signed-off-by: waterplea <alexander@inkin.ru>
This commit is contained in:
@@ -28,7 +28,6 @@ import { PreloaderModule } from './app/preloader/preloader.module'
|
||||
import { FooterModule } from './app/footer/footer.module'
|
||||
import { MenuModule } from './app/menu/menu.module'
|
||||
import { APP_PROVIDERS } from './app.providers'
|
||||
import { PatchDbModule } from './services/patch-db/patch-db.module'
|
||||
import { ToastContainerModule } from './components/toast-container/toast-container.module'
|
||||
import { ConnectionBarComponentModule } from './components/connection-bar/connection-bar.component.module'
|
||||
import { WidgetsPageModule } from './pages/widgets/widgets.module'
|
||||
@@ -54,7 +53,6 @@ import { environment } from '../environments/environment'
|
||||
MonacoEditorModule,
|
||||
SharedPipesModule,
|
||||
MarketplaceModule,
|
||||
PatchDbModule,
|
||||
ToastContainerModule,
|
||||
ConnectionBarComponentModule,
|
||||
TuiRootModule,
|
||||
|
||||
@@ -3,6 +3,11 @@ import { UntypedFormBuilder } from '@angular/forms'
|
||||
import { Router, RouteReuseStrategy } from '@angular/router'
|
||||
import { IonicRouteStrategy, IonNav } from '@ionic/angular'
|
||||
import { RELATIVE_URL, THEME, WorkspaceConfig } from '@start9labs/shared'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import {
|
||||
PATCH_CACHE,
|
||||
PatchDbSource,
|
||||
} from 'src/app/services/patch-db/patch-db-source'
|
||||
import { ApiService } from './services/api/embassy-api.service'
|
||||
import { MockApiService } from './services/api/embassy-mock-api.service'
|
||||
import { LiveApiService } from './services/api/embassy-live-api.service'
|
||||
@@ -29,6 +34,11 @@ export const APP_PROVIDERS: Provider[] = [
|
||||
provide: ApiService,
|
||||
useClass: useMocks ? MockApiService : LiveApiService,
|
||||
},
|
||||
{
|
||||
provide: PatchDB,
|
||||
deps: [PatchDbSource, PATCH_CACHE],
|
||||
useClass: PatchDB,
|
||||
},
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
deps: [StorageService, AuthService, ClientStorageService, Router],
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
RpcError,
|
||||
RPCOptions,
|
||||
} from '@start9labs/shared'
|
||||
import { PATCH_CACHE } from 'src/app/services/patch-db/patch-db-source'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import { RR } from './api.types'
|
||||
import { parsePropertiesPermissive } from 'src/app/util/properties.util'
|
||||
@@ -16,7 +17,7 @@ import { Observable, filter, firstValueFrom } from 'rxjs'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { DOCUMENT } from '@angular/common'
|
||||
import { DataModel } from '../patch-db/data-model'
|
||||
import { PatchDB, pathFromArray } from 'patch-db-client'
|
||||
import { Dump, pathFromArray } from 'patch-db-client'
|
||||
|
||||
@Injectable()
|
||||
export class LiveApiService extends ApiService {
|
||||
@@ -25,7 +26,7 @@ export class LiveApiService extends ApiService {
|
||||
private readonly http: HttpService,
|
||||
private readonly config: ConfigService,
|
||||
private readonly auth: AuthService,
|
||||
private readonly patch: PatchDB<DataModel>,
|
||||
@Inject(PATCH_CACHE) private readonly cache$: Observable<Dump<DataModel>>,
|
||||
) {
|
||||
super()
|
||||
; (window as any).rpcClient = this
|
||||
@@ -482,7 +483,7 @@ export class LiveApiService extends ApiService {
|
||||
const patchSequence = res.headers.get('x-patch-sequence')
|
||||
if (patchSequence)
|
||||
await firstValueFrom(
|
||||
this.patch.cache$.pipe(filter(({ id }) => id >= Number(patchSequence))),
|
||||
this.cache$.pipe(filter(({ id }) => id >= Number(patchSequence))),
|
||||
)
|
||||
|
||||
return body.result
|
||||
|
||||
56
web/projects/ui/src/app/services/patch-db/patch-db-source.ts
Normal file
56
web/projects/ui/src/app/services/patch-db/patch-db-source.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { inject, Injectable, InjectionToken } from '@angular/core'
|
||||
import { Dump, Revision, Update } from 'patch-db-client'
|
||||
import { BehaviorSubject, EMPTY, Observable } from 'rxjs'
|
||||
import {
|
||||
bufferTime,
|
||||
catchError,
|
||||
filter,
|
||||
startWith,
|
||||
switchMap,
|
||||
take,
|
||||
} from 'rxjs/operators'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
import { ApiService } from '../api/embassy-api.service'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { DataModel } from './data-model'
|
||||
import { LocalStorageBootstrap } from './local-storage-bootstrap'
|
||||
|
||||
export const PATCH_CACHE = new InjectionToken('', {
|
||||
factory: () =>
|
||||
new BehaviorSubject<Dump<DataModel>>({
|
||||
id: 0,
|
||||
value: {} as DataModel,
|
||||
}),
|
||||
})
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PatchDbSource extends Observable<Update<DataModel>[]> {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly state = inject(StateService)
|
||||
private readonly stream$ = inject(AuthService).isVerified$.pipe(
|
||||
switchMap(verified => (verified ? this.api.subscribeToPatchDB({}) : EMPTY)),
|
||||
switchMap(({ dump, guid }) =>
|
||||
this.api.openWebsocket$<Revision>(guid, {}).pipe(
|
||||
bufferTime(250),
|
||||
filter(revisions => !!revisions.length),
|
||||
startWith([dump]),
|
||||
),
|
||||
),
|
||||
catchError((_, original$) => {
|
||||
this.state.retrigger()
|
||||
|
||||
return this.state.pipe(
|
||||
filter(current => current === 'running'),
|
||||
take(1),
|
||||
switchMap(() => original$),
|
||||
)
|
||||
}),
|
||||
startWith([inject(LocalStorageBootstrap).init()]),
|
||||
)
|
||||
|
||||
constructor() {
|
||||
super(subscriber => this.stream$.subscribe(subscriber))
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import { InjectionToken, Injector } from '@angular/core'
|
||||
import { Revision, Update } from 'patch-db-client'
|
||||
import { defer, EMPTY, from, Observable } from 'rxjs'
|
||||
import {
|
||||
bufferTime,
|
||||
catchError,
|
||||
filter,
|
||||
startWith,
|
||||
switchMap,
|
||||
take,
|
||||
} from 'rxjs/operators'
|
||||
import { StateService } from 'src/app/services/state.service'
|
||||
import { ApiService } from '../api/embassy-api.service'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { DataModel } from './data-model'
|
||||
import { LocalStorageBootstrap } from './local-storage-bootstrap'
|
||||
|
||||
export const PATCH_SOURCE = new InjectionToken<Observable<Update<DataModel>[]>>(
|
||||
'',
|
||||
)
|
||||
|
||||
export function sourceFactory(
|
||||
injector: Injector,
|
||||
): Observable<Update<DataModel>[]> {
|
||||
// defer() needed to avoid circular dependency with ApiService, since PatchDB is needed there
|
||||
return defer(() => {
|
||||
const api = injector.get(ApiService)
|
||||
const auth = injector.get(AuthService)
|
||||
const state = injector.get(StateService)
|
||||
const bootstrapper = injector.get(LocalStorageBootstrap)
|
||||
|
||||
return auth.isVerified$.pipe(
|
||||
switchMap(verified =>
|
||||
verified ? from(api.subscribeToPatchDB({})) : EMPTY,
|
||||
),
|
||||
switchMap(({ dump, guid }) =>
|
||||
api.openWebsocket$<Revision>(guid, {}).pipe(
|
||||
bufferTime(250),
|
||||
filter(revisions => !!revisions.length),
|
||||
startWith([dump]),
|
||||
),
|
||||
),
|
||||
catchError((_, original$) => {
|
||||
state.retrigger()
|
||||
|
||||
return state.pipe(
|
||||
filter(current => current === 'running'),
|
||||
take(1),
|
||||
switchMap(() => original$),
|
||||
)
|
||||
}),
|
||||
startWith([bootstrapper.init()]),
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { Injector, NgModule } from '@angular/core'
|
||||
import { PATCH_SOURCE, sourceFactory } from './patch-db.factory'
|
||||
|
||||
// This module is purely for providers organization purposes
|
||||
@NgModule({
|
||||
providers: [
|
||||
{
|
||||
provide: PATCH_SOURCE,
|
||||
deps: [Injector],
|
||||
useFactory: sourceFactory,
|
||||
},
|
||||
{
|
||||
provide: PatchDB,
|
||||
deps: [PATCH_SOURCE],
|
||||
useClass: PatchDB,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class PatchDbModule {}
|
||||
Reference in New Issue
Block a user