import { Injectable } from '@angular/core' ; import { Observable , of , forkJoin } from 'rxjs' ; import { map , scan , switchMap } from 'rxjs/operators' ; import { snapshotToValue } from './rx/snapshotToValue' ; import { DbRefBuilder } from './firebase/db-ref-builder' ; import { AuthService } from './auth' ; import { Lab } from './models/lab' ; import { User } from './models/user' ; import { Execution } from './models/execution' ; import { parseLabDirectory } from '@machinelabs/core' ; import { ExecutionStatus } from '@machinelabs/models' ; const mapExecutionLabDirectory = ( source ) => source . pipe ( map ( execution => { if ( execution && execution . lab ) { execution . lab . directory = parseLabDirectory ( execution . lab . directory ) ; } return execution ; } ) ) ; @ Injectable ( ) export class LabExecutionService { constructor ( private db , private authService ) { } observeExecution ( id ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . executionRef ( id ) . value ( ) ) , snapshotToValue , mapExecutionLabDirectory ) ; } observeExecutionsForLab ( lab ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . labVisibleExecutionsRef ( lab . id ) . childAdded ( ) ) , map ( ( snapshot ) => ( { id : snapshot . key , execution : this . observeExecution ( snapshot . key ) } ) ) , scan ( ( acc , val ) => { if ( ! acc . find ( execution => execution . id === val . id ) ) { return [ val , ... acc ] ; } return acc ; } , [ ] ) , map ( val => [ ... val ] ) ) ; } observeRecentExecutionsForLab ( lab , limit = 3 ) { return this . observeExecutionsForLab ( lab ) . pipe ( map ( executions => executions . slice ( 0 , limit ) ) ) ; } observeExecutionsForUser ( user ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . userVisibleExecutionsRef ( user . id ) . childAdded ( ) ) , map ( ( snapshot ) => this . observeExecution ( snapshot . key ) ) , scan ( ( acc , val ) => { acc . unshift ( val ) ; return acc ; } , [ ] ) ) ; } getLatestExecutionIdForLab ( id ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . labExecutionsRef ( id ) . limitToLast ( 1 ) . onceValue ( ) ) , snapshotToValue , map ( value => ( value ? Object . keys ( value ) [ 0 ] : null ) ) ) ; } getExecution ( id ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . executionRef ( id ) . onceValue ( ) ) , snapshotToValue , mapExecutionLabDirectory ) ; } getLatestVisibleExecutionIdForLab ( id ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . labVisibleExecutionsRef ( id ) . limitToLast ( 1 ) . onceValue ( ) ) , snapshotToValue , map ( value => ( value ? Object . keys ( value ) [ 0 ] : null ) ) ) ; } executionExists ( id ) { return this . authService . requireAuth ( ) . pipe ( switchMap ( _ => this . db . executionRef ( id ) . onceValue ( ) ) , map ( ( snapshot ) => ! ! snapshot . val ( ) ) ) ; } executionExistsAndVisible ( id ) { return this . authService . requireAuth ( ) . pipe ( switchMap ( _ => this . db . executionRef ( id ) . onceValue ( ) ) , snapshotToValue , map ( execution => ! execution . hidden ) ) ; } getExecutionsFromLab ( id ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . labVisibleExecutionsRef ( id ) . onceValue ( ) ) , snapshotToValue , map ( executionIds => Object . keys ( executionIds || { } ) ) , map ( executionIds => executionIds . map ( executionId => this . getExecution ( executionId ) ) ) , switchMap ( executionRefs => ( executionRefs . length ? forkJoin ( executionRefs ) : of ( [ ] ) ) ) , map ( executions => executions . filter ( execution => execution ) ) ) ; } updateExecution ( execution ) { return this . authService . requireAuthOnce ( ) . pipe ( switchMap ( _ => this . db . executionRef ( execution . id ) . update ( { hidden : execution . hidden || false , name : execution . name || '' } ) ) ) ; } labHasRunningExecutions ( id ) { return this . getExecutionsFromLab ( id ) . pipe ( map ( executions => executions . filter ( execution => execution . status === ExecutionStatus . Executing ) ) , map ( executions => ! ! executions . length ) ) ; } }