streamer-node 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/public/client.png +0 -0
- package/dist/public/ds.png +0 -0
- package/dist/src/application/interfaces/Logger.d.ts +7 -0
- package/dist/src/application/interfaces/Logger.d.ts.map +1 -0
- package/dist/src/application/interfaces/Logger.js +3 -0
- package/dist/src/application/interfaces/Logger.js.map +1 -0
- package/dist/src/application/interfaces/StartStreamUseCase.types.d.ts +36 -0
- package/dist/src/application/interfaces/StartStreamUseCase.types.d.ts.map +1 -0
- package/dist/src/application/interfaces/StartStreamUseCase.types.js +12 -0
- package/dist/src/application/interfaces/StartStreamUseCase.types.js.map +1 -0
- package/dist/src/application/services/HttpClient.d.ts +5 -0
- package/dist/src/application/services/HttpClient.d.ts.map +1 -0
- package/dist/src/application/services/HttpClient.js +30 -0
- package/dist/src/application/services/HttpClient.js.map +1 -0
- package/dist/src/application/services/StreamManagerService.d.ts +38 -0
- package/dist/src/application/services/StreamManagerService.d.ts.map +1 -0
- package/dist/src/application/services/StreamManagerService.js +298 -0
- package/dist/src/application/services/StreamManagerService.js.map +1 -0
- package/dist/src/application/use-cases/StartStreamUseCase.d.ts +27 -0
- package/dist/src/application/use-cases/StartStreamUseCase.d.ts.map +1 -0
- package/dist/src/application/use-cases/StartStreamUseCase.js +195 -0
- package/dist/src/application/use-cases/StartStreamUseCase.js.map +1 -0
- package/dist/src/application/use-cases/StopStreamUseCase.d.ts +18 -0
- package/dist/src/application/use-cases/StopStreamUseCase.d.ts.map +1 -0
- package/dist/src/application/use-cases/StopStreamUseCase.js +96 -0
- package/dist/src/application/use-cases/StopStreamUseCase.js.map +1 -0
- package/dist/src/domain/entities/Stream.d.ts +40 -0
- package/dist/src/domain/entities/Stream.d.ts.map +1 -0
- package/dist/src/domain/entities/Stream.js +115 -0
- package/dist/src/domain/entities/Stream.js.map +1 -0
- package/dist/src/domain/events/StreamEvent.d.ts +48 -0
- package/dist/src/domain/events/StreamEvent.d.ts.map +1 -0
- package/dist/src/domain/events/StreamEvent.js +3 -0
- package/dist/src/domain/events/StreamEvent.js.map +1 -0
- package/dist/src/domain/repositories/StreamRepository.d.ts +41 -0
- package/dist/src/domain/repositories/StreamRepository.d.ts.map +1 -0
- package/dist/src/domain/repositories/StreamRepository.js +3 -0
- package/dist/src/domain/repositories/StreamRepository.js.map +1 -0
- package/dist/src/domain/services/FFmpegService.d.ts +42 -0
- package/dist/src/domain/services/FFmpegService.d.ts.map +1 -0
- package/dist/src/domain/services/FFmpegService.js +3 -0
- package/dist/src/domain/services/FFmpegService.js.map +1 -0
- package/dist/src/domain/services/SSEService.d.ts +42 -0
- package/dist/src/domain/services/SSEService.d.ts.map +1 -0
- package/dist/src/domain/services/SSEService.js +3 -0
- package/dist/src/domain/services/SSEService.js.map +1 -0
- package/dist/src/domain/value-objects/StreamId.d.ts +10 -0
- package/dist/src/domain/value-objects/StreamId.d.ts.map +1 -0
- package/dist/src/domain/value-objects/StreamId.js +31 -0
- package/dist/src/domain/value-objects/StreamId.js.map +1 -0
- package/dist/src/domain/value-objects/StreamState.d.ts +12 -0
- package/dist/src/domain/value-objects/StreamState.d.ts.map +1 -0
- package/dist/src/domain/value-objects/StreamState.js +35 -0
- package/dist/src/domain/value-objects/StreamState.js.map +1 -0
- package/dist/src/domain/value-objects/StreamUrl.d.ts +12 -0
- package/dist/src/domain/value-objects/StreamUrl.d.ts.map +1 -0
- package/dist/src/domain/value-objects/StreamUrl.js +48 -0
- package/dist/src/domain/value-objects/StreamUrl.js.map +1 -0
- package/dist/src/infrastructure/config/Config.d.ts +42 -0
- package/dist/src/infrastructure/config/Config.d.ts.map +1 -0
- package/dist/src/infrastructure/config/Config.js +113 -0
- package/dist/src/infrastructure/config/Config.js.map +1 -0
- package/dist/src/infrastructure/logging/ConsoleLogger.d.ts +12 -0
- package/dist/src/infrastructure/logging/ConsoleLogger.d.ts.map +1 -0
- package/dist/src/infrastructure/logging/ConsoleLogger.js +41 -0
- package/dist/src/infrastructure/logging/ConsoleLogger.js.map +1 -0
- package/dist/src/infrastructure/logging/LogBuffer.d.ts +20 -0
- package/dist/src/infrastructure/logging/LogBuffer.d.ts.map +1 -0
- package/dist/src/infrastructure/logging/LogBuffer.js +95 -0
- package/dist/src/infrastructure/logging/LogBuffer.js.map +1 -0
- package/dist/src/infrastructure/logging/LogShippingService.d.ts +23 -0
- package/dist/src/infrastructure/logging/LogShippingService.d.ts.map +1 -0
- package/dist/src/infrastructure/logging/LogShippingService.js +128 -0
- package/dist/src/infrastructure/logging/LogShippingService.js.map +1 -0
- package/dist/src/infrastructure/logging/RemoteLogger.d.ts +37 -0
- package/dist/src/infrastructure/logging/RemoteLogger.d.ts.map +1 -0
- package/dist/src/infrastructure/logging/RemoteLogger.js +120 -0
- package/dist/src/infrastructure/logging/RemoteLogger.js.map +1 -0
- package/dist/src/infrastructure/logging/types/LogTypes.d.ts +27 -0
- package/dist/src/infrastructure/logging/types/LogTypes.d.ts.map +1 -0
- package/dist/src/infrastructure/logging/types/LogTypes.js +3 -0
- package/dist/src/infrastructure/logging/types/LogTypes.js.map +1 -0
- package/dist/src/infrastructure/repositories/FileSystemStreamRepository.d.ts +22 -0
- package/dist/src/infrastructure/repositories/FileSystemStreamRepository.d.ts.map +1 -0
- package/dist/src/infrastructure/repositories/FileSystemStreamRepository.js +212 -0
- package/dist/src/infrastructure/repositories/FileSystemStreamRepository.js.map +1 -0
- package/dist/src/infrastructure/services/NodeFFmpegService.d.ts +17 -0
- package/dist/src/infrastructure/services/NodeFFmpegService.d.ts.map +1 -0
- package/dist/src/infrastructure/services/NodeFFmpegService.js +306 -0
- package/dist/src/infrastructure/services/NodeFFmpegService.js.map +1 -0
- package/dist/src/infrastructure/services/NodeSSEService.d.ts +30 -0
- package/dist/src/infrastructure/services/NodeSSEService.d.ts.map +1 -0
- package/dist/src/infrastructure/services/NodeSSEService.js +268 -0
- package/dist/src/infrastructure/services/NodeSSEService.js.map +1 -0
- package/dist/src/main.d.ts +3 -0
- package/dist/src/main.d.ts.map +1 -0
- package/dist/src/main.js +87 -0
- package/dist/src/main.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../../../src/application/interfaces/Logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IACzC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CAC1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.js","sourceRoot":"","sources":["../../../../src/application/interfaces/Logger.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Stream } from "../../domain/entities/Stream";
|
|
2
|
+
export interface StartStreamRequest {
|
|
3
|
+
cameraUrl: string;
|
|
4
|
+
streamKey: string;
|
|
5
|
+
courtId: string;
|
|
6
|
+
detectAudio?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface StartStreamResponse {
|
|
9
|
+
streamId: string;
|
|
10
|
+
processId: number;
|
|
11
|
+
hasAudio: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare enum StreamAction {
|
|
14
|
+
MULTIPLE_STREAMS_RUNNING = "multiple_streams_running",
|
|
15
|
+
STREAM_RUNNING_WITHOUT_PID = "stream_running_without_pid",
|
|
16
|
+
DUPLICATE_EVENT = "duplicate_event",
|
|
17
|
+
INVALID_YOUTUBE_STREAM_KEY = "invalid_youtube_stream_key",
|
|
18
|
+
DEAD_PROCESS_DETECTED = "dead_process_detected"
|
|
19
|
+
}
|
|
20
|
+
export type StartStreamEvent = {
|
|
21
|
+
action: StreamAction.MULTIPLE_STREAMS_RUNNING;
|
|
22
|
+
streamList: Stream[];
|
|
23
|
+
} | {
|
|
24
|
+
action: StreamAction.STREAM_RUNNING_WITHOUT_PID | StreamAction.DUPLICATE_EVENT | StreamAction.INVALID_YOUTUBE_STREAM_KEY | StreamAction.DEAD_PROCESS_DETECTED;
|
|
25
|
+
stream: Stream;
|
|
26
|
+
};
|
|
27
|
+
type TrueOrFalse<T> = {
|
|
28
|
+
isValid: true;
|
|
29
|
+
} | {
|
|
30
|
+
isValid: false;
|
|
31
|
+
data: T;
|
|
32
|
+
};
|
|
33
|
+
export type ValidationEvent = TrueOrFalse<StartStreamEvent>;
|
|
34
|
+
export type ShouldStartStream = TrueOrFalse<StartStreamResponse>;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=StartStreamUseCase.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StartStreamUseCase.types.d.ts","sourceRoot":"","sources":["../../../../src/application/interfaces/StartStreamUseCase.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,oBAAY,YAAY;IACtB,wBAAwB,6BAA6B;IACrD,0BAA0B,+BAA+B;IACzD,eAAe,oBAAoB;IACnC,0BAA0B,+BAA+B;IACzD,qBAAqB,0BAA0B;CAChD;AAED,MAAM,MAAM,gBAAgB,GACxB;IACE,MAAM,EAAE,YAAY,CAAC,wBAAwB,CAAC;IAC9C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GACD;IACE,MAAM,EACF,YAAY,CAAC,0BAA0B,GACvC,YAAY,CAAC,eAAe,GAC5B,YAAY,CAAC,0BAA0B,GACvC,YAAY,CAAC,qBAAqB,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,KAAK,WAAW,CAAC,CAAC,IAAI;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamAction = void 0;
|
|
4
|
+
var StreamAction;
|
|
5
|
+
(function (StreamAction) {
|
|
6
|
+
StreamAction["MULTIPLE_STREAMS_RUNNING"] = "multiple_streams_running";
|
|
7
|
+
StreamAction["STREAM_RUNNING_WITHOUT_PID"] = "stream_running_without_pid";
|
|
8
|
+
StreamAction["DUPLICATE_EVENT"] = "duplicate_event";
|
|
9
|
+
StreamAction["INVALID_YOUTUBE_STREAM_KEY"] = "invalid_youtube_stream_key";
|
|
10
|
+
StreamAction["DEAD_PROCESS_DETECTED"] = "dead_process_detected";
|
|
11
|
+
})(StreamAction || (exports.StreamAction = StreamAction = {}));
|
|
12
|
+
//# sourceMappingURL=StartStreamUseCase.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StartStreamUseCase.types.js","sourceRoot":"","sources":["../../../../src/application/interfaces/StartStreamUseCase.types.ts"],"names":[],"mappings":";;;AAeA,IAAY,YAMX;AAND,WAAY,YAAY;IACtB,qEAAqD,CAAA;IACrD,yEAAyD,CAAA;IACzD,mDAAmC,CAAA;IACnC,yEAAyD,CAAA;IACzD,+DAA+C,CAAA;AACjD,CAAC,EANW,YAAY,4BAAZ,YAAY,QAMvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.d.ts","sourceRoot":"","sources":["../../../../src/application/services/HttpClient.ts"],"names":[],"mappings":"AAEA,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IAC/C,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC;CAqBrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpClient = void 0;
|
|
4
|
+
const Config_1 = require("../../infrastructure/config/Config");
|
|
5
|
+
class HttpClient {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.config = Config_1.Config.getInstance().get();
|
|
8
|
+
}
|
|
9
|
+
async goLiveYouTube(groundId, courtId, streamKey) {
|
|
10
|
+
// GET request to notify YouTube to go live
|
|
11
|
+
const url = `${this.config.server.baseUrl}/api/v1/padel-grounds/${groundId}/courts/${courtId}/go-live/${streamKey}`;
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch(url, {
|
|
14
|
+
method: "GET",
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
21
|
+
}
|
|
22
|
+
return response;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.HttpClient = HttpClient;
|
|
30
|
+
//# sourceMappingURL=HttpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../../../src/application/services/HttpClient.ts"],"names":[],"mappings":";;;AAAA,+DAA4D;AAE5D,MAAa,UAAU;IAAvB;QACmB,WAAM,GAAG,eAAM,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC;IA0BvD,CAAC;IAzBC,KAAK,CAAC,aAAa,CACjB,QAAgB,EAChB,OAAe,EACf,SAAiB;QAEjB,2CAA2C;QAC3C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,yBAAyB,QAAQ,WAAW,OAAO,YAAY,SAAS,EAAE,CAAC;QAEpH,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACrE,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AA3BD,gCA2BC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StreamRepository } from "../../domain/repositories/StreamRepository";
|
|
2
|
+
import { FFmpegService } from "../../domain/services/FFmpegService";
|
|
3
|
+
import { SSEService } from "../../domain/services/SSEService";
|
|
4
|
+
import { StartStreamUseCase } from "../use-cases/StartStreamUseCase";
|
|
5
|
+
import { StopStreamUseCase } from "../use-cases/StopStreamUseCase";
|
|
6
|
+
import { Logger } from "../interfaces/Logger";
|
|
7
|
+
import { Config } from "../../infrastructure/config/Config";
|
|
8
|
+
export declare class StreamManagerService {
|
|
9
|
+
private readonly streamRepository;
|
|
10
|
+
private readonly ffmpegService;
|
|
11
|
+
private readonly sseService;
|
|
12
|
+
private readonly startStreamUseCase;
|
|
13
|
+
private readonly stopStreamUseCase;
|
|
14
|
+
private readonly logger;
|
|
15
|
+
private readonly config;
|
|
16
|
+
private healthCheckInterval?;
|
|
17
|
+
private isRunning;
|
|
18
|
+
constructor(streamRepository: StreamRepository, ffmpegService: FFmpegService, sseService: SSEService, startStreamUseCase: StartStreamUseCase, stopStreamUseCase: StopStreamUseCase, logger: Logger, config: Config);
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
stop(): Promise<void>;
|
|
21
|
+
private initializeSystem;
|
|
22
|
+
private recoverStreams;
|
|
23
|
+
private cleanupOrphanedProcesses;
|
|
24
|
+
private setupSSEEventHandlers;
|
|
25
|
+
private handleStreamEvent;
|
|
26
|
+
private handleStartEvent;
|
|
27
|
+
private handleStopEvent;
|
|
28
|
+
private startHealthCheck;
|
|
29
|
+
private performHealthCheck;
|
|
30
|
+
private stopAllStreams;
|
|
31
|
+
getStatus(): Promise<{
|
|
32
|
+
isRunning: boolean;
|
|
33
|
+
sseConnected: boolean;
|
|
34
|
+
runningStreams: number;
|
|
35
|
+
totalStreams: number;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=StreamManagerService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamManagerService.d.ts","sourceRoot":"","sources":["../../../../src/application/services/StreamManagerService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAG5D,qBAAa,oBAAoB;IAK7B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,mBAAmB,CAAC,CAAiB;IAC7C,OAAO,CAAC,SAAS,CAAS;gBAGP,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,EACtB,kBAAkB,EAAE,kBAAkB,EACtC,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAGpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA8BpB,gBAAgB;YAmBhB,cAAc;YAsDd,wBAAwB;IA8BtC,OAAO,CAAC,qBAAqB;YAQf,iBAAiB;YAsBjB,gBAAgB;YAahB,eAAe;IAsB7B,OAAO,CAAC,gBAAgB;YAsBV,kBAAkB;YAoClB,cAAc;IA4Bf,SAAS,IAAI,OAAO,CAAC;QAChC,SAAS,EAAE,OAAO,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CAWH"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamManagerService = void 0;
|
|
4
|
+
const StreamState_1 = require("../../domain/value-objects/StreamState");
|
|
5
|
+
class StreamManagerService {
|
|
6
|
+
constructor(streamRepository, ffmpegService, sseService, startStreamUseCase, stopStreamUseCase, logger, config) {
|
|
7
|
+
this.streamRepository = streamRepository;
|
|
8
|
+
this.ffmpegService = ffmpegService;
|
|
9
|
+
this.sseService = sseService;
|
|
10
|
+
this.startStreamUseCase = startStreamUseCase;
|
|
11
|
+
this.stopStreamUseCase = stopStreamUseCase;
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.isRunning = false;
|
|
15
|
+
}
|
|
16
|
+
async start() {
|
|
17
|
+
if (this.isRunning) {
|
|
18
|
+
this.logger.warn("Stream manager is already running");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.logger.info("Starting Stream Manager Service");
|
|
22
|
+
this.isRunning = true;
|
|
23
|
+
try {
|
|
24
|
+
// Initialize state directories and recovery
|
|
25
|
+
await this.initializeSystem();
|
|
26
|
+
// Set up SSE event handlers
|
|
27
|
+
this.setupSSEEventHandlers();
|
|
28
|
+
// Start SSE connection
|
|
29
|
+
const sseConfig = this.config.get().sse;
|
|
30
|
+
await this.sseService.start({
|
|
31
|
+
...sseConfig,
|
|
32
|
+
groundId: this.config.get().groundInfo.groundId,
|
|
33
|
+
baseUrl: this.config.get().server.baseUrl,
|
|
34
|
+
});
|
|
35
|
+
// Start health check monitoring
|
|
36
|
+
this.startHealthCheck();
|
|
37
|
+
this.logger.info("Stream Manager Service started successfully");
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
this.logger.error("Failed to start Stream Manager Service", {
|
|
41
|
+
error: error instanceof Error ? error.message : String(error),
|
|
42
|
+
});
|
|
43
|
+
this.isRunning = false;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async stop() {
|
|
48
|
+
if (!this.isRunning) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.logger.info("Stopping Stream Manager Service");
|
|
52
|
+
this.isRunning = false;
|
|
53
|
+
try {
|
|
54
|
+
// Stop health check
|
|
55
|
+
if (this.healthCheckInterval) {
|
|
56
|
+
clearInterval(this.healthCheckInterval);
|
|
57
|
+
this.healthCheckInterval = undefined;
|
|
58
|
+
}
|
|
59
|
+
// Stop SSE service
|
|
60
|
+
await this.sseService.stop();
|
|
61
|
+
// Stop all running streams
|
|
62
|
+
await this.stopAllStreams();
|
|
63
|
+
this.logger.info("Stream Manager Service stopped successfully");
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.logger.error("Error stopping Stream Manager Service", {
|
|
67
|
+
error: error instanceof Error ? error.message : String(error),
|
|
68
|
+
});
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async initializeSystem() {
|
|
73
|
+
this.logger.info("Initializing stream management system");
|
|
74
|
+
try {
|
|
75
|
+
// Recover running streams from persistent state
|
|
76
|
+
await this.recoverStreams();
|
|
77
|
+
// Clean up orphaned processes
|
|
78
|
+
await this.cleanupOrphanedProcesses();
|
|
79
|
+
this.logger.info("System initialization completed");
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
this.logger.error("System initialization failed", {
|
|
83
|
+
error: error instanceof Error ? error.message : String(error),
|
|
84
|
+
});
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async recoverStreams() {
|
|
89
|
+
this.logger.info("Recovering streams from persistent state");
|
|
90
|
+
try {
|
|
91
|
+
const runningStreams = await this.streamRepository.findRunning();
|
|
92
|
+
this.logger.info("Found running streams to recover", {
|
|
93
|
+
count: runningStreams.length,
|
|
94
|
+
});
|
|
95
|
+
for (const stream of runningStreams) {
|
|
96
|
+
try {
|
|
97
|
+
// Check if the process is actually running
|
|
98
|
+
if (stream.processId) {
|
|
99
|
+
const isRunning = await this.ffmpegService.isProcessRunning(stream.processId);
|
|
100
|
+
if (!isRunning) {
|
|
101
|
+
this.logger.warn("Stream process not running, marking as failed", {
|
|
102
|
+
streamId: stream.id.value,
|
|
103
|
+
processId: stream.processId,
|
|
104
|
+
});
|
|
105
|
+
stream.markAsFailed("Process not found during recovery");
|
|
106
|
+
await this.streamRepository.save(stream);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.logger.info("Stream process recovered successfully", {
|
|
110
|
+
streamId: stream.id.value,
|
|
111
|
+
processId: stream.processId,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.logger.error("Failed to recover stream", {
|
|
118
|
+
streamId: stream.id.value,
|
|
119
|
+
error: error instanceof Error ? error.message : String(error),
|
|
120
|
+
});
|
|
121
|
+
stream.markAsFailed("Recovery failed");
|
|
122
|
+
await this.streamRepository.save(stream);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
this.logger.error("Stream recovery failed", {
|
|
128
|
+
error: error instanceof Error ? error.message : String(error),
|
|
129
|
+
});
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async cleanupOrphanedProcesses() {
|
|
134
|
+
this.logger.info("Cleaning up orphaned FFmpeg processes");
|
|
135
|
+
try {
|
|
136
|
+
const runningProcesses = await this.ffmpegService.getRunningProcesses();
|
|
137
|
+
const managedStreams = await this.streamRepository.findRunning();
|
|
138
|
+
const managedPids = new Set(managedStreams
|
|
139
|
+
.map((stream) => stream.processId)
|
|
140
|
+
.filter((pid) => pid !== undefined));
|
|
141
|
+
for (const process of runningProcesses) {
|
|
142
|
+
if (!managedPids.has(process.pid)) {
|
|
143
|
+
this.logger.warn("Found orphaned FFmpeg process, terminating", {
|
|
144
|
+
pid: process.pid,
|
|
145
|
+
command: process.command.fullCommand,
|
|
146
|
+
});
|
|
147
|
+
await this.ffmpegService.stopStream(process.pid);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.logger.error("Cleanup of orphaned processes failed", {
|
|
153
|
+
error: error instanceof Error ? error.message : String(error),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
setupSSEEventHandlers() {
|
|
158
|
+
this.logger.info("Setting up SSE event handlers");
|
|
159
|
+
this.sseService.onStreamEvent(async (event) => {
|
|
160
|
+
await this.handleStreamEvent(event);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async handleStreamEvent(event) {
|
|
164
|
+
this.logger.info("Handling SSE stream event", {
|
|
165
|
+
action: event.action,
|
|
166
|
+
cameraUrl: event.cameraUrl,
|
|
167
|
+
streamKey: event.streamKey,
|
|
168
|
+
reconciliationMode: event.reconciliationMode,
|
|
169
|
+
});
|
|
170
|
+
try {
|
|
171
|
+
if (event.action === "start") {
|
|
172
|
+
await this.handleStartEvent(event);
|
|
173
|
+
}
|
|
174
|
+
else if (event.action === "stop") {
|
|
175
|
+
await this.handleStopEvent(event);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
this.logger.error("Failed to process stream event", {
|
|
180
|
+
event,
|
|
181
|
+
error: error instanceof Error ? error.message : String(error),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async handleStartEvent(event) {
|
|
186
|
+
this.logger.info("Handling new stream");
|
|
187
|
+
await this.startStreamUseCase.execute({
|
|
188
|
+
cameraUrl: event.cameraUrl,
|
|
189
|
+
streamKey: event.streamKey,
|
|
190
|
+
courtId: event.courtId,
|
|
191
|
+
detectAudio: true,
|
|
192
|
+
}, this.stopStreamUseCase.execute);
|
|
193
|
+
}
|
|
194
|
+
async handleStopEvent(event) {
|
|
195
|
+
// Find stream by camera URL and stream key
|
|
196
|
+
const streams = await this.streamRepository.findAll();
|
|
197
|
+
const targetStream = streams.find((stream) => stream.cameraUrl.value === event.cameraUrl &&
|
|
198
|
+
stream.streamKey === event.streamKey &&
|
|
199
|
+
stream.state === StreamState_1.StreamState.RUNNING);
|
|
200
|
+
if (targetStream) {
|
|
201
|
+
await this.stopStreamUseCase.execute({
|
|
202
|
+
streamId: targetStream.id.value,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this.logger.warn("Stream not found for stop event", {
|
|
207
|
+
cameraUrl: event.cameraUrl,
|
|
208
|
+
streamKey: event.streamKey,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
startHealthCheck() {
|
|
213
|
+
const interval = this.config.get().stream.healthCheckInterval;
|
|
214
|
+
this.logger.info("Starting health check monitoring", {
|
|
215
|
+
intervalMs: interval,
|
|
216
|
+
});
|
|
217
|
+
this.healthCheckInterval = setInterval(async () => {
|
|
218
|
+
if (!this.isRunning) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
await this.performHealthCheck();
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
this.logger.error("Health check failed", {
|
|
226
|
+
error: error instanceof Error ? error.message : String(error),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}, interval);
|
|
230
|
+
}
|
|
231
|
+
async performHealthCheck() {
|
|
232
|
+
this.logger.debug("Performing health check");
|
|
233
|
+
try {
|
|
234
|
+
const runningStreams = await this.streamRepository.findRunning();
|
|
235
|
+
for (const stream of runningStreams) {
|
|
236
|
+
if (stream.processId) {
|
|
237
|
+
const isRunning = await this.ffmpegService.isProcessRunning(stream.processId);
|
|
238
|
+
if (!isRunning) {
|
|
239
|
+
this.logger.warn("Stream process died, marking as failed", {
|
|
240
|
+
streamId: stream.id.value,
|
|
241
|
+
processId: stream.processId,
|
|
242
|
+
});
|
|
243
|
+
stream.markAsFailed("Process died");
|
|
244
|
+
await this.streamRepository.save(stream);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Check SSE connection health
|
|
249
|
+
if (!this.sseService.isConnected()) {
|
|
250
|
+
this.logger.warn("SSE connection is down, attempting reconnection");
|
|
251
|
+
await this.sseService.reconnect();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
this.logger.error("Health check error", {
|
|
256
|
+
error: error instanceof Error ? error.message : String(error),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async stopAllStreams() {
|
|
261
|
+
this.logger.info("Stopping all running streams");
|
|
262
|
+
try {
|
|
263
|
+
const runningStreams = await this.streamRepository.findRunning();
|
|
264
|
+
for (const stream of runningStreams) {
|
|
265
|
+
try {
|
|
266
|
+
await this.stopStreamUseCase.execute({
|
|
267
|
+
streamId: stream.id.value,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
this.logger.error("Failed to stop stream during shutdown", {
|
|
272
|
+
streamId: stream.id.value,
|
|
273
|
+
error: error instanceof Error ? error.message : String(error),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// Force kill any remaining FFmpeg processes
|
|
278
|
+
await this.ffmpegService.killAllProcesses();
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
this.logger.error("Failed to stop all streams", {
|
|
282
|
+
error: error instanceof Error ? error.message : String(error),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async getStatus() {
|
|
287
|
+
const runningStreams = await this.streamRepository.findRunning();
|
|
288
|
+
const allStreams = await this.streamRepository.findAll();
|
|
289
|
+
return {
|
|
290
|
+
isRunning: this.isRunning,
|
|
291
|
+
sseConnected: this.sseService.isConnected(),
|
|
292
|
+
runningStreams: runningStreams.length,
|
|
293
|
+
totalStreams: allStreams.length,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
exports.StreamManagerService = StreamManagerService;
|
|
298
|
+
//# sourceMappingURL=StreamManagerService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamManagerService.js","sourceRoot":"","sources":["../../../../src/application/services/StreamManagerService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { StreamRepository } from "../../domain/repositories/StreamRepository";
|
|
2
|
+
import { FFmpegService } from "../../domain/services/FFmpegService";
|
|
3
|
+
import { Logger } from "../interfaces/Logger";
|
|
4
|
+
import { HttpClient } from "../services/HttpClient";
|
|
5
|
+
import { StopStreamRequest, StopStreamResponse } from "./StopStreamUseCase";
|
|
6
|
+
import { StartStreamRequest, StartStreamResponse } from "../interfaces/StartStreamUseCase.types";
|
|
7
|
+
export declare class StartStreamUseCase {
|
|
8
|
+
private readonly streamRepository;
|
|
9
|
+
private readonly ffmpegService;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly httpClient;
|
|
12
|
+
private readonly config;
|
|
13
|
+
constructor(streamRepository: StreamRepository, ffmpegService: FFmpegService, logger: Logger, httpClient: HttpClient);
|
|
14
|
+
private shouldStartNewStream;
|
|
15
|
+
/**
|
|
16
|
+
* Validates if a new stream can be started by checking:
|
|
17
|
+
* 1. No existing streams (valid to start)
|
|
18
|
+
* 2. Multiple streams on same court (invalid)
|
|
19
|
+
* 3. Stream exists but missing process ID (invalid)
|
|
20
|
+
* 4. Different stream key than existing (invalid)
|
|
21
|
+
* 5. Process already running (duplicate event)
|
|
22
|
+
* 6. Process dead but stream marked as running (stale state)
|
|
23
|
+
*/
|
|
24
|
+
private validateStreamEvent;
|
|
25
|
+
execute(request: StartStreamRequest, stopProcess: (request: StopStreamRequest) => Promise<StopStreamResponse>): Promise<StartStreamResponse>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=StartStreamUseCase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StartStreamUseCase.d.ts","sourceRoot":"","sources":["../../../../src/application/use-cases/StartStreamUseCase.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAEL,kBAAkB,EAClB,mBAAmB,EAGpB,MAAM,wCAAwC,CAAC;AAEhD,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAN7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;gBAGlC,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU;YAG3B,oBAAoB;IAmDlC;;;;;;;;OAQG;YACW,mBAAmB;IAqEpB,OAAO,CAClB,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,GACvE,OAAO,CAAC,mBAAmB,CAAC;CAiGhC"}
|