paperless-ngx/src-ui/src/app/services/consumer-status.service.ts
2021-02-15 14:52:47 +01:00

201 lines
6.4 KiB
TypeScript

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { environment } from 'src/environments/environment';
import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message';
export enum FileStatusPhase {
STARTED = 0,
UPLOADING = 1,
PROCESSING = 2,
SUCCESS = 3,
FAILED = 4
}
export const FILE_STATUS_MESSAGES = {
"document_already_exists": $localize`Document already exists.`,
"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.`
}
export class FileStatus {
filename: string
taskId: string
phase: FileStatusPhase = FileStatusPhase.STARTED
currentPhaseProgress: number
currentPhaseMaxProgress: number
message: string
documentId: number
getProgress(): number {
switch (this.phase) {
case FileStatusPhase.STARTED:
return 0.0
case FileStatusPhase.UPLOADING:
return this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.2
case FileStatusPhase.PROCESSING:
return (this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.8) + 0.2
case FileStatusPhase.SUCCESS:
case FileStatusPhase.FAILED:
return 1.0
}
}
updateProgress(status: FileStatusPhase, currentProgress?: number, maxProgress?: number) {
if (status >= this.phase) {
this.phase = status
if (currentProgress != null) {
this.currentPhaseProgress = currentProgress
}
if (maxProgress != null) {
this.currentPhaseMaxProgress = maxProgress
}
}
}
}
@Injectable({
providedIn: 'root'
})
export class ConsumerStatusService {
constructor() { }
private statusWebSocket: WebSocket
private consumerStatus: FileStatus[] = []
private documentDetectedSubject = new Subject<FileStatus>()
private documentConsumptionFinishedSubject = new Subject<FileStatus>()
private documentConsumptionFailedSubject = new Subject<FileStatus>()
private get(taskId: string, filename?: string) {
let status = this.consumerStatus.find(e => e.taskId == taskId) || this.consumerStatus.find(e => e.filename == filename && e.taskId == null)
let created = false
if (!status) {
status = new FileStatus()
this.consumerStatus.push(status)
created = true
}
status.taskId = taskId
status.filename = filename
return {'status': status, 'created': created}
}
newFileUpload(filename: string): FileStatus {
let status = new FileStatus()
status.filename = filename
this.consumerStatus.push(status)
return status
}
getConsumerStatus(phase?: FileStatusPhase) {
if (phase != null) {
return this.consumerStatus.filter(s => s.phase == phase)
} else {
return this.consumerStatus
}
}
getConsumerStatusNotCompleted() {
return this.consumerStatus.filter(s => s.phase < FileStatusPhase.SUCCESS)
}
getConsumerStatusCompleted() {
return this.consumerStatus.filter(s => s.phase == FileStatusPhase.FAILED || s.phase == FileStatusPhase.SUCCESS)
}
connect() {
this.disconnect()
this.statusWebSocket = new WebSocket(`${environment.webSocketProtocol}//${environment.webSocketHost}/ws/status/`);
this.statusWebSocket.onmessage = (ev) => {
let statusMessage: WebsocketConsumerStatusMessage = JSON.parse(ev['data'])
let statusMessageGet = this.get(statusMessage.task_id, statusMessage.filename)
let status = statusMessageGet.status
let created = statusMessageGet.created
status.updateProgress(FileStatusPhase.PROCESSING, statusMessage.current_progress, statusMessage.max_progress)
if (statusMessage.message && statusMessage.message in FILE_STATUS_MESSAGES) {
status.message = FILE_STATUS_MESSAGES[statusMessage.message]
} else if (statusMessage.message) {
status.message = statusMessage.message
}
status.documentId = statusMessage.document_id
if (created && statusMessage.status == 'STARTING') {
this.documentDetectedSubject.next(status)
}
if (statusMessage.status == "SUCCESS") {
status.phase = FileStatusPhase.SUCCESS
this.documentConsumptionFinishedSubject.next(status)
}
if (statusMessage.status == "FAILED") {
status.phase = FileStatusPhase.FAILED
this.documentConsumptionFailedSubject.next(status)
}
}
}
fail(status: FileStatus, message: string) {
status.message = message
status.phase = FileStatusPhase.FAILED
this.documentConsumptionFailedSubject.next(status)
}
disconnect() {
if (this.statusWebSocket) {
this.statusWebSocket.close()
this.statusWebSocket = null
}
}
dismiss(status: FileStatus) {
let index
if (status.taskId != null) {
index = this.consumerStatus.findIndex(s => s.taskId == status.taskId)
} else {
index = this.consumerStatus.findIndex(s => s.filename == status.filename)
}
if (index > -1) {
this.consumerStatus.splice(index, 1)
}
}
dismissCompleted() {
this.consumerStatus = this.consumerStatus.filter(status => status.phase != FileStatusPhase.SUCCESS)
}
onDocumentConsumptionFinished() {
return this.documentConsumptionFinishedSubject
}
onDocumentConsumptionFailed() {
return this.documentConsumptionFailedSubject
}
onDocumentDetected() {
return this.documentDetectedSubject
}
}