Skip to content
This repository was archived by the owner on Mar 14, 2023. It is now read-only.

Commit be9e96b

Browse files
author
clouless
committed
single ws connection per client and max 5 concurrent compress jobs
1 parent af4355c commit be9e96b

File tree

4 files changed

+69
-47
lines changed

4 files changed

+69
-47
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "kartoffelstampf-client",
3-
"version": "2.1.2",
3+
"version": "2.3.0",
44
"license": "MIT",
55
"scripts": {
66
"ng": "ng",

src/app/services/backend.service.ts

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from '../types/kartoffelstampf-server';
88
import { Observable, Subject, throwError } from 'rxjs';
99
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
10-
import { catchError } from 'rxjs/operators';
10+
import { catchError, filter, takeWhile } from 'rxjs/operators';
1111

1212
const httpOptions = {
1313
headers: new HttpHeaders({
@@ -22,8 +22,14 @@ export class BackendService {
2222
private restApiBaseUrl: string;
2323
private webSocketBaseUrl: string;
2424

25+
private ws: WebSocket;
26+
private subject = new Subject<KartoffelstampfTerminalOutputEntry>();
27+
2528
constructor(private http: HttpClient) {
29+
const self = this;
30+
//
2631
// Autodetect URLs
32+
//
2733
const hostname = window.location.hostname;
2834
const protocol = window.location.protocol;
2935
const port = window.location.port;
@@ -41,6 +47,22 @@ export class BackendService {
4147
this.restApiBaseUrl = `http://localhost:9999`;
4248
this.webSocketBaseUrl = `ws://localhost:9999`;
4349
}
50+
//
51+
// Connect
52+
//
53+
self.ws = new WebSocket(`${this.webSocketBaseUrl}/`);
54+
self.ws.onclose = function(event: CloseEvent) {
55+
console.log('websocket onclose', event);
56+
self.subject.complete();
57+
};
58+
self.ws.onmessage = function(event: MessageEvent) {
59+
const kartoffelstampfTerminalOutputEntry: KartoffelstampfTerminalOutputEntry = JSON.parse(event.data);
60+
self.subject.next(kartoffelstampfTerminalOutputEntry);
61+
};
62+
self.ws.onerror = function(event: ErrorEvent) {
63+
console.log('websocket onerror', event);
64+
self.subject.complete();
65+
};
4466
}
4567

4668
getDownloadUrl(temporaryFileName: string, originalFileName: string) {
@@ -55,22 +77,18 @@ export class BackendService {
5577
}
5678

5779
runCompressCommand(compressInstruction: KartoffelstampfCompressInstruction): Observable<KartoffelstampfTerminalOutputEntry> {
58-
const ws = new WebSocket(`${this.webSocketBaseUrl}/`);
59-
const subject = new Subject<KartoffelstampfTerminalOutputEntry>();
60-
ws.onopen = function (event) {
61-
ws.send(JSON.stringify(compressInstruction));
62-
};
63-
ws.onmessage = function(event: MessageEvent) {
64-
const kartoffelstampfTerminalOutputEntry: KartoffelstampfTerminalOutputEntry = JSON.parse(event.data);
65-
subject.next(kartoffelstampfTerminalOutputEntry);
66-
};
67-
ws.onerror = function (event) {
68-
console.log('websocket onerror', event);
69-
};
70-
ws.onclose = function (event) {
71-
subject.complete();
72-
};
73-
return subject.asObservable();
80+
this.ws.send(JSON.stringify(compressInstruction));
81+
// Use single websocket connection and distinguish messages by compressInstruction
82+
// The last message sent by the server per compressJob should be type=DONE. This is where we unsubscribe.
83+
return this.subject
84+
.asObservable()
85+
.pipe(
86+
filter(e =>
87+
e.compressInstruction.compressType === compressInstruction.compressType &&
88+
e.compressInstruction.temporaryFileName === compressInstruction.temporaryFileName
89+
),
90+
takeWhile(data => data.type !== 'DONE'),
91+
);
7492
}
7593

7694
}

src/app/types/kartoffelstampf-server.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
// Typings: https://github.com/codeclou/karteoffelstampf-server
33
//
44

5-
export interface KartoffelstampfTerminalOutputEntryPayload {
6-
text: string;
7-
}
8-
95
export interface KartoffelstampfTerminalOutputEntry {
10-
payload: KartoffelstampfTerminalOutputEntryPayload;
6+
payload: any;
117
type: string;
8+
compressInstruction: KartoffelstampfCompressInstruction;
129
}
1310

1411
export interface KartoffelstampfImageUploadRequest {

src/app/upload-page/upload-page.component.ts

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
22
import { BackendService } from '../services/backend.service';
33
import { KartoffelstampfTerminalOutputEntry, KartoffelstampfCompressInstruction } from '../types/kartoffelstampf-server';
44
import { TerminalLine, CompressImageJobItem } from '../types/kartoffelstampf-client';
5-
import { finalize, takeUntil } from 'rxjs/operators';
5+
import { finalize, takeUntil, takeWhile, endWith } from 'rxjs/operators';
66
import { Subject, throwError, of, EMPTY } from 'rxjs';
77
import { catchError } from 'rxjs/operators';
88
import { HttpErrorResponse } from '@angular/common/http';
@@ -57,6 +57,8 @@ export class UploadPageComponent implements OnInit, OnDestroy {
5757
uiStateDragLeave = true;
5858

5959
activeStep = 1;
60+
concurrentJobLimit = 5;
61+
concurrentJobCount = 0;
6062

6163
constructor(private backendService: BackendService) { }
6264

@@ -146,30 +148,35 @@ export class UploadPageComponent implements OnInit, OnDestroy {
146148

147149
runCompressCommand(job: CompressImageJobItem) {
148150
const self = this;
149-
self.backendService.runCompressCommand(<KartoffelstampfCompressInstruction>{
150-
compressType: KartoffelstampfCompressInstruction.COMPRESS_TYPE_LOSSLESS,
151-
temporaryFileName: job.temporaryFileName,
152-
})
153-
.pipe(
154-
finalize(() => {
155-
job.compressDone = true;
156-
}),
157-
takeUntil(self.preDestroy)
158-
)
159-
.subscribe(data => {
160-
if (data.type === 'compressResult') {
161-
job.compressedSize = data.payload['compressedSize'];
162-
} else {
163-
const terminalLine = new TerminalLine(data);
164-
const previousTerminalLine = job.terminalLines[job.terminalLines.length - 1];
165-
if (previousTerminalLine !== undefined &&
166-
previousTerminalLine.clearLine === true &&
167-
terminalLine.clearLine === true) {
168-
job.terminalLines.pop();
169-
}
170-
job.terminalLines.push(terminalLine);
151+
const intervallId = setInterval(function() {
152+
if (self.concurrentJobCount < self.concurrentJobLimit) {
153+
clearInterval(intervallId);
154+
self.concurrentJobCount = self.concurrentJobCount + 1;
155+
self.backendService.runCompressCommand(<KartoffelstampfCompressInstruction>{
156+
compressType: KartoffelstampfCompressInstruction.COMPRESS_TYPE_LOSSLESS,
157+
temporaryFileName: job.temporaryFileName,
158+
})
159+
.pipe(
160+
finalize(() => self.concurrentJobCount = self.concurrentJobCount - 1),
161+
takeUntil(self.preDestroy),
162+
)
163+
.subscribe(data => {
164+
if (data.type === 'compressResult') {
165+
job.compressedSize = data.payload['compressedSize'];
166+
job.compressDone = true;
167+
} else {
168+
const terminalLine = new TerminalLine(data);
169+
const previousTerminalLine = job.terminalLines[job.terminalLines.length - 1];
170+
if (previousTerminalLine !== undefined &&
171+
previousTerminalLine.clearLine === true &&
172+
terminalLine.clearLine === true) {
173+
job.terminalLines.pop();
174+
}
175+
job.terminalLines.push(terminalLine);
176+
}
177+
});
171178
}
172-
});
179+
}, 300);
173180
}
174181

175182
}

0 commit comments

Comments
 (0)