import { action , observable , makeObservable } from 'mobx' ; import { injectable } from '@cloudbeaver/core-di' ; import { NotificationService } from '@cloudbeaver/core-events' ; import { PermissionsService , EPermission , PermissionsResource , SessionExpireService } from '@cloudbeaver/core-root' ; import { GraphQLService } from '@cloudbeaver/core-sdk' ; import { uuid } from '@cloudbeaver/core-utils' ; import { CoreSettingsService } from '../../../CoreSettingsService' ; import type { ILogEntry } from './ILogEntry' ; @ injectable ( ) export class LogViewerService { _isActive = false ; get isActive ( ) : boolean { return this . _isActive ; } private log : ILogEntry [ ] = [ ] ; private timeoutTaskId : NodeJS . Timeout | null = null ; private failedRequestsCount = 0 ; private maxFailedRequests = 0 ; constructor ( private graphQLService , private coreSettingsService , private notificationService , private permissionsService , private permissionsResource , private sessionExpireService ) { makeObservable < LogViewerService , 'log' | 'addNewEntries' > ( this , { _isActive : observable , log : observable , clearLog : action , addNewEntries : action , } ) ; this . permissionsResource . onDataUpdate . addHandler ( this . stopIfHasNoPermission . bind ( this ) ) ; } toggle ( ) { if ( this . _isActive ) { this . stopLog ( ) ; } else { this . startLog ( ) ; } } getLog ( ) { return this . log ; } async startLog ( ) { if ( this . _isActive ) { return ; } if ( ! this . isLogViewerAvailable ( ) ) { throw new Error ( 'Access denied' ) ; } this . failedRequestsCount = 0 ; this . _isActive = true ; const refreshInterval = this . coreSettingsService . settings . getValue ( 'app.logViewer.refreshTimeout' ) ; this . maxFailedRequests = this . coreSettingsService . settings . getValue ( 'app.logViewer.maxFailedRequests' ) ; await this . updateLog ( ) ; this . runInterval ( refreshInterval ) ; } stopLog ( ) { if ( this . timeoutTaskId ) { clearTimeout ( this . timeoutTaskId ) ; this . timeoutTaskId = null ; } this . _isActive = false ; } clearLog ( ) { this . log = [ ] ; } async loadLog ( ) { const maxLogEntries = this . coreSettingsService . settings . getValue ( 'app.logViewer.logBatchSize' ) ; const { log } = await this . graphQLService . sdk . readSessionLog ( { maxEntries : maxLogEntries , clearEntries : true , } ) ; const entries = log . map ( item => ( { ... item , id : uuid ( ) , } ) ) ; return entries ; } private addNewEntries ( entries ) { this . log . unshift ( ... entries . reverse ( ) ) ; const maxLogEntries = this . coreSettingsService . settings . getValue ( 'app.logViewer.maxLogRecords' ) ; if ( this . log . length > maxLogEntries ) { this . log . splice ( maxLogEntries , this . log . length - maxLogEntries ) ; } } private runInterval ( refreshInterval ) { this . timeoutTaskId = setTimeout ( async ( ) => { await this . updateLog ( ) ; if ( this . _isActive ) { this . runInterval ( refreshInterval ) ; } } , refreshInterval ) ; } private async updateLog ( ) { try { const newEntries = await this . loadLog ( ) ; this . addNewEntries ( newEntries ) ; } catch ( e ) { if ( this . failedRequestsCount === 0 && ! this . sessionExpireService . sessionExpired ) { this . notificationService . logException ( e , 'Failed to load log' ) ; } this . failedRequestsCount ++ ; if ( this . failedRequestsCount === this . maxFailedRequests ) { this . stopLog ( ) ; } } } private stopIfHasNoPermission ( ) { if ( this . _isActive && ! this . isLogViewerAvailable ( ) ) { this . stopLog ( ) ; } } private isLogViewerAvailable ( ) { return this . permissionsService . has ( EPermission . public ) ; } }