2022-03-11 10:53:32 -08:00
import { Injectable } from '@angular/core'
import { Subject } from 'rxjs'
import { environment } from 'src/environments/environment'
2025-02-06 16:47:50 -08:00
import { WebsocketDocumentsDeletedMessage } from '../data/websocket-documents-deleted-message'
import { WebsocketProgressMessage } from '../data/websocket-progress-message'
2023-08-08 16:27:40 -07:00
import { SettingsService } from './settings.service'
2021-01-26 00:51:45 +01:00
2025-02-06 16:47:50 -08:00
export enum WebsocketStatusType {
STATUS_UPDATE = 'status_update' ,
DOCUMENTS_DELETED = 'documents_deleted' ,
}
2024-04-17 19:59:14 -07:00
// see ProgressStatusOptions in src/documents/plugins/helpers.py
2021-01-26 00:51:45 +01:00
export enum FileStatusPhase {
STARTED = 0 ,
UPLOADING = 1 ,
2023-07-25 10:21:34 -07:00
WORKING = 2 ,
2021-01-26 00:51:45 +01:00
SUCCESS = 3 ,
2022-03-11 10:53:32 -08:00
FAILED = 4 ,
2021-01-26 00:51:45 +01:00
}
2021-01-28 22:06:02 +01:00
export const FILE_STATUS_MESSAGES = {
2022-03-11 10:53:32 -08:00
document_already_exists : $localize ` Document already exists. ` ,
2024-08-05 17:01:01 -07:00
document_already_exists_in_trash : $localize ` Document already exists. Note: existing document is in the trash. ` ,
2023-01-16 14:26:41 +01:00
asn_already_exists : $localize ` Document with ASN already exists. ` ,
2024-08-05 17:01:01 -07:00
asn_already_exists_in_trash : $localize ` Document with ASN already exists. Note: existing document is in the trash. ` ,
2022-03-11 10:53:32 -08:00
file_not_found : $localize ` File not found. ` ,
pre_consume_script_not_found : $localize ` :Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist. ` ,
pre_consume_script_error : $localize ` :Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script. ` ,
post_consume_script_not_found : $localize ` :Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Post-consume script does not exist. ` ,
post_consume_script_error : $localize ` :Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing post-consume script. ` ,
new_file : $localize ` Received new file. ` ,
unsupported_type : $localize ` File type not supported. ` ,
parsing_document : $localize ` Processing document... ` ,
generating_thumbnail : $localize ` Generating thumbnail... ` ,
parse_date : $localize ` Retrieving date from document... ` ,
save_document : $localize ` Saving document... ` ,
finished : $localize ` Finished. ` ,
2021-01-28 22:06:02 +01:00
}
2021-01-26 00:51:45 +01:00
export class FileStatus {
filename : string
taskId : string
2021-01-26 02:32:45 -08:00
phase : FileStatusPhase = FileStatusPhase . STARTED
2021-01-26 00:51:45 +01:00
currentPhaseProgress : number
currentPhaseMaxProgress : number
message : string
documentId : number
2023-08-08 16:27:40 -07:00
ownerId : number
2021-01-26 00:51:45 +01:00
getProgress ( ) : number {
switch ( this . phase ) {
case FileStatusPhase . STARTED :
return 0.0
case FileStatusPhase . UPLOADING :
2022-03-11 10:53:32 -08:00
return ( this . currentPhaseProgress / this . currentPhaseMaxProgress ) * 0.2
2023-07-25 10:21:34 -07:00
case FileStatusPhase . WORKING :
2022-03-11 10:53:32 -08:00
return (
( this . currentPhaseProgress / this . currentPhaseMaxProgress ) * 0.8 + 0.2
)
2021-01-26 00:51:45 +01:00
case FileStatusPhase . SUCCESS :
case FileStatusPhase . FAILED :
return 1.0
}
}
2022-03-11 10:53:32 -08:00
updateProgress (
status : FileStatusPhase ,
currentProgress? : number ,
maxProgress? : number
) {
2021-01-26 00:51:45 +01:00
if ( status >= this . phase ) {
this . phase = status
2021-01-27 15:23:29 +01:00
if ( currentProgress != null ) {
2021-01-26 00:51:45 +01:00
this . currentPhaseProgress = currentProgress
}
2021-01-27 15:23:29 +01:00
if ( maxProgress != null ) {
2021-01-26 00:51:45 +01:00
this . currentPhaseMaxProgress = maxProgress
}
}
}
2020-11-07 12:05:15 +01:00
}
@Injectable ( {
2022-03-11 10:53:32 -08:00
providedIn : 'root' ,
2020-11-07 12:05:15 +01:00
} )
2025-02-06 16:47:50 -08:00
export class WebsocketStatusService {
2023-08-08 16:27:40 -07:00
constructor ( private settingsService : SettingsService ) { }
2020-11-07 12:05:15 +01:00
2021-02-02 16:22:36 +01:00
private statusWebSocket : WebSocket
2020-11-07 12:05:15 +01:00
2021-01-26 01:10:39 +01:00
private consumerStatus : FileStatus [ ] = [ ]
2021-01-27 17:28:11 +01:00
private documentDetectedSubject = new Subject < FileStatus > ( )
2020-11-07 12:05:15 +01:00
private documentConsumptionFinishedSubject = new Subject < FileStatus > ( )
private documentConsumptionFailedSubject = new Subject < FileStatus > ( )
2025-02-06 16:47:50 -08:00
private documentDeletedSubject = new Subject < boolean > ( )
2020-11-07 12:05:15 +01:00
2021-01-26 00:51:45 +01:00
private get ( taskId : string , filename? : string ) {
2022-03-11 10:53:32 -08:00
let status =
this . consumerStatus . find ( ( e ) = > e . taskId == taskId ) ||
this . consumerStatus . find (
( e ) = > e . filename == filename && e . taskId == null
)
2021-01-27 17:28:11 +01:00
let created = false
2021-01-26 00:51:45 +01:00
if ( ! status ) {
status = new FileStatus ( )
this . consumerStatus . push ( status )
2021-01-27 17:28:11 +01:00
created = true
2021-01-26 00:51:45 +01:00
}
status . taskId = taskId
status . filename = filename
2022-03-11 10:53:32 -08:00
return { status : status , created : created }
2021-01-26 00:51:45 +01:00
}
2021-01-26 01:10:39 +01:00
newFileUpload ( filename : string ) : FileStatus {
2021-01-26 00:51:45 +01:00
let status = new FileStatus ( )
2021-01-26 01:10:39 +01:00
status . filename = filename
2021-01-26 00:51:45 +01:00
this . consumerStatus . push ( status )
return status
}
2021-01-26 01:10:39 +01:00
getConsumerStatus ( phase? : FileStatusPhase ) {
2021-01-28 10:54:56 +01:00
if ( phase != null ) {
2022-03-11 10:53:32 -08:00
return this . consumerStatus . filter ( ( s ) = > s . phase == phase )
2021-01-26 01:10:39 +01:00
} else {
return this . consumerStatus
}
}
2021-01-28 10:54:56 +01:00
getConsumerStatusNotCompleted() {
2022-03-11 10:53:32 -08:00
return this . consumerStatus . filter ( ( s ) = > s . phase < FileStatusPhase . SUCCESS )
2021-01-28 10:54:56 +01:00
}
2021-01-27 18:34:59 +01:00
getConsumerStatusCompleted() {
2022-03-11 10:53:32 -08:00
return this . consumerStatus . filter (
( s ) = >
s . phase == FileStatusPhase . FAILED || s . phase == FileStatusPhase . SUCCESS
)
2021-01-27 18:34:59 +01:00
}
2020-11-07 12:05:15 +01:00
connect() {
this . disconnect ( )
2021-02-02 16:22:36 +01:00
2022-03-11 10:53:32 -08:00
this . statusWebSocket = new WebSocket (
` ${ environment . webSocketProtocol } // ${ environment . webSocketHost } ${ environment . webSocketBaseUrl } status/ `
)
2025-02-06 16:47:50 -08:00
this . statusWebSocket . onmessage = ( ev : MessageEvent ) = > {
const {
type ,
data : messageData ,
} : {
type : WebsocketStatusType
data : WebsocketProgressMessage | WebsocketDocumentsDeletedMessage
} = JSON . parse ( ev . data )
switch ( type ) {
case WebsocketStatusType . DOCUMENTS_DELETED :
this . documentDeletedSubject . next ( true )
break
case WebsocketStatusType . STATUS_UPDATE :
this . handleProgressUpdate ( messageData as WebsocketProgressMessage )
break
2023-08-08 16:27:40 -07:00
}
2025-02-06 16:47:50 -08:00
}
}
2023-08-08 16:27:40 -07:00
2025-02-06 16:47:50 -08:00
handleProgressUpdate ( messageData : WebsocketProgressMessage ) {
// fallback if backend didn't restrict message
if (
messageData . owner_id &&
messageData . owner_id !== this . settingsService . currentUser ? . id &&
! this . settingsService . currentUser ? . is_superuser
) {
return
}
2021-01-27 17:28:11 +01:00
2025-02-06 16:47:50 -08:00
let statusMessageGet = this . get ( messageData . task_id , messageData . filename )
let status = statusMessageGet . status
let created = statusMessageGet . created
2020-11-07 12:05:15 +01:00
2025-02-06 16:47:50 -08:00
status . updateProgress (
FileStatusPhase . WORKING ,
messageData . current_progress ,
messageData . max_progress
)
if ( messageData . message && messageData . message in FILE_STATUS_MESSAGES ) {
status . message = FILE_STATUS_MESSAGES [ messageData . message ]
} else if ( messageData . message ) {
status . message = messageData . message
}
status . documentId = messageData . document_id
2023-07-25 10:21:34 -07:00
2025-02-06 16:47:50 -08:00
if ( messageData . status in FileStatusPhase ) {
status . phase = FileStatusPhase [ messageData . status ]
}
2023-07-25 10:21:34 -07:00
2025-02-06 16:47:50 -08:00
switch ( status . phase ) {
case FileStatusPhase . STARTED :
if ( created ) this . documentDetectedSubject . next ( status )
break
2023-07-25 10:21:34 -07:00
2025-02-06 16:47:50 -08:00
case FileStatusPhase . SUCCESS :
this . documentConsumptionFinishedSubject . next ( status )
break
2023-07-25 10:21:34 -07:00
2025-02-06 16:47:50 -08:00
case FileStatusPhase . FAILED :
this . documentConsumptionFailedSubject . next ( status )
break
default :
break
2020-11-07 12:05:15 +01:00
}
}
2021-01-27 16:04:06 +01:00
fail ( status : FileStatus , message : string ) {
status . message = message
status . phase = FileStatusPhase . FAILED
this . documentConsumptionFailedSubject . next ( status )
}
2020-11-07 12:05:15 +01:00
disconnect() {
2021-02-02 16:22:36 +01:00
if ( this . statusWebSocket ) {
this . statusWebSocket . close ( )
this . statusWebSocket = null
2020-11-07 12:05:15 +01:00
}
}
dismiss ( status : FileStatus ) {
2021-02-15 14:52:47 +01:00
let index
if ( status . taskId != null ) {
2022-03-11 10:53:32 -08:00
index = this . consumerStatus . findIndex ( ( s ) = > s . taskId == status . taskId )
2021-02-15 14:52:47 +01:00
} else {
2022-03-11 10:53:32 -08:00
index = this . consumerStatus . findIndex (
( s ) = > s . filename == status . filename
)
2021-02-15 14:52:47 +01:00
}
2020-11-07 12:05:15 +01:00
if ( index > - 1 ) {
this . consumerStatus . splice ( index , 1 )
}
}
2021-02-04 16:55:48 +01:00
dismissCompleted() {
2022-03-11 10:53:32 -08:00
this . consumerStatus = this . consumerStatus . filter (
2023-09-28 10:18:12 -07:00
( status ) = >
! [ FileStatusPhase . SUCCESS , FileStatusPhase . FAILED ] . includes (
status . phase
)
2022-03-11 10:53:32 -08:00
)
2021-01-26 02:52:16 -08:00
}
2020-11-07 12:05:15 +01:00
onDocumentConsumptionFinished() {
return this . documentConsumptionFinishedSubject
}
onDocumentConsumptionFailed() {
return this . documentConsumptionFailedSubject
}
2021-01-27 17:28:11 +01:00
onDocumentDetected() {
return this . documentDetectedSubject
}
2025-02-06 16:47:50 -08:00
onDocumentDeleted() {
return this . documentDeletedSubject
}
2020-11-07 12:05:15 +01:00
}