@lsdsoftware/janus-client-node 1.0.3 → 1.0.5

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/dist/client.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ClientRequestArgs } from "http";
2
2
  import * as rxjs from "rxjs";
3
3
  import { ClientOptions } from "ws";
4
- import { JanusMessage, JanusRequest } from "./types.js";
4
+ import { JanusRequest } from "./types.js";
5
5
  export declare function createClient(websocketUrl: string, websocketOpts?: ClientOptions | ClientRequestArgs): rxjs.Observable<{
6
6
  requestSubject: rxjs.Subject<JanusRequest>;
7
7
  send$: rxjs.Observable<never>;
8
- receive$: rxjs.Observable<JanusMessage>;
8
+ receive$: rxjs.Observable<Record<string, unknown>>;
9
9
  close$: rxjs.Observable<import("ws").default.CloseEvent>;
10
10
  close: (code?: number, data?: string | Buffer) => void;
11
11
  }>;
package/dist/client.js CHANGED
@@ -8,16 +8,31 @@ export function createClient(websocketUrl, websocketOpts) {
8
8
  const pendingTxs = new Map();
9
9
  return {
10
10
  requestSubject,
11
- send$: requestSubject.pipe(rxjs.concatMap(request => {
11
+ send$: requestSubject.pipe(rxjs.mergeMap(request => {
12
12
  const txId = String(Math.random());
13
13
  request.message.transaction = txId;
14
- conn.send(JSON.stringify(request.message), err => {
14
+ return new rxjs.Observable(subscriber => conn.send(JSON.stringify(request.message), err => {
15
+ subscriber.next(err);
16
+ subscriber.complete();
17
+ })).pipe(rxjs.exhaustMap(err => {
15
18
  if (err) {
16
19
  request.reject(err);
20
+ return rxjs.EMPTY;
17
21
  }
18
22
  else {
19
- pendingTxs.set(txId, response => {
20
- pendingTxs.delete(txId);
23
+ function waitResponse(timeout) {
24
+ return new rxjs.Observable(subscriber => {
25
+ pendingTxs.set(txId, response => {
26
+ subscriber.next(response);
27
+ subscriber.complete();
28
+ });
29
+ return () => pendingTxs.delete(txId);
30
+ }).pipe(timeout == Infinity ? rxjs.identity : rxjs.timeout({
31
+ first: timeout,
32
+ with: () => rxjs.of({ janus: 'error', error: { code: 408, reason: 'Request timeout' } })
33
+ }));
34
+ }
35
+ return waitResponse(30_000).pipe(rxjs.exhaustMap(response => rxjs.iif(() => response.janus == 'ack', waitResponse(request.timeout ?? 300_000), rxjs.of(response))), rxjs.exhaustMap(response => {
21
36
  if (response.janus == 'error') {
22
37
  const { code, reason } = response.error;
23
38
  request.reject(makeJanusError(request, code, reason));
@@ -25,16 +40,16 @@ export function createClient(websocketUrl, websocketOpts) {
25
40
  else {
26
41
  request.fulfill(response);
27
42
  }
28
- });
43
+ return rxjs.EMPTY;
44
+ }));
29
45
  }
30
- });
31
- return rxjs.EMPTY;
46
+ }));
32
47
  }), rxjs.share()),
33
48
  receive$: conn.message$.pipe(rxjs.concatMap(event => {
34
49
  try {
35
50
  assert(typeof event.data == 'string');
36
51
  const message = JSON.parse(event.data);
37
- if (message.janus == 'event' && typeof message.transaction == 'undefined') {
52
+ if (typeof message.transaction == 'undefined') {
38
53
  return rxjs.of(message);
39
54
  }
40
55
  else {
@@ -53,7 +68,10 @@ export function createClient(websocketUrl, websocketOpts) {
53
68
  return rxjs.EMPTY;
54
69
  }
55
70
  }), rxjs.share()),
56
- close$: conn.close$,
71
+ close$: conn.close$.pipe(rxjs.tap(() => {
72
+ for (const pending of pendingTxs.values())
73
+ pending({ janus: 'error', error: { code: 503, reason: 'Connection closed before response was received' } });
74
+ })),
57
75
  close: conn.close.bind(conn)
58
76
  };
59
77
  }));
@@ -1,8 +1,8 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusMessage, JanusRequest } from "./types.js";
2
+ import { JanusRequest } from "./types.js";
3
3
  export declare function createPluginHandle(session: {
4
4
  requestSubject: rxjs.Subject<JanusRequest>;
5
- receive$: rxjs.Observable<JanusMessage>;
5
+ receive$: rxjs.Observable<Record<string, unknown>>;
6
6
  }, plugin: string): rxjs.Observable<{
7
7
  requestSubject: rxjs.Subject<JanusRequest>;
8
8
  send$: rxjs.Observable<never>;
@@ -35,7 +35,7 @@ export function createPluginHandle(session, plugin) {
35
35
  }), rxjs.share()),
36
36
  detach() {
37
37
  session.requestSubject.next({
38
- message: { janus: "detach" },
38
+ message: { janus: "detach", handle_id: handleId },
39
39
  stacktrace: new Error(),
40
40
  fulfill: rxjs.noop,
41
41
  reject: err => console.error('JanusPluginHandle detach fail', handleId, err)
package/dist/session.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusMessage, JanusRequest } from "./types.js";
2
+ import { JanusRequest } from "./types.js";
3
3
  export declare function createSession(client: {
4
4
  requestSubject: rxjs.Subject<JanusRequest>;
5
- receive$: rxjs.Observable<JanusMessage>;
5
+ receive$: rxjs.Observable<Record<string, unknown>>;
6
6
  }, { keepAliveInterval }?: {
7
7
  keepAliveInterval?: number;
8
8
  }): rxjs.Observable<{
9
9
  requestSubject: rxjs.Subject<JanusRequest>;
10
10
  send$: rxjs.Observable<never>;
11
- receive$: rxjs.Observable<JanusMessage>;
11
+ receive$: rxjs.Observable<Record<string, unknown>>;
12
12
  keepAlive$: rxjs.Observable<Error>;
13
13
  destroy(): void;
14
14
  }>;
package/dist/session.js CHANGED
@@ -11,7 +11,7 @@ export function createSession(client, { keepAliveInterval = 45_000 } = {}) {
11
11
  return rxjs.EMPTY;
12
12
  }), rxjs.share()),
13
13
  receive$: client.receive$.pipe(rxjs.filter(message => message.session_id == sessionId), rxjs.share()),
14
- keepAlive$: requestSubject.pipe(rxjs.switchMap(() => rxjs.interval(keepAliveInterval).pipe(rxjs.switchMap(() => new rxjs.Observable(subscriber => client.requestSubject.next({
14
+ keepAlive$: requestSubject.pipe(rxjs.startWith(null), rxjs.switchMap(() => rxjs.interval(keepAliveInterval).pipe(rxjs.switchMap(() => new rxjs.Observable(subscriber => client.requestSubject.next({
15
15
  message: { janus: "keepalive", session_id: sessionId },
16
16
  stacktrace: new Error(),
17
17
  fulfill() {
@@ -24,7 +24,7 @@ export function createSession(client, { keepAliveInterval = 45_000 } = {}) {
24
24
  }))))), rxjs.share()),
25
25
  destroy() {
26
26
  client.requestSubject.next({
27
- message: { janus: 'destroy' },
27
+ message: { janus: 'destroy', session_id: sessionId },
28
28
  stacktrace: new Error(),
29
29
  fulfill: rxjs.noop,
30
30
  reject: err => console.error('JanusSession destroy fail', sessionId, err)
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export type JanusMessage = Record<string, unknown>;
2
1
  export interface JanusRequest {
3
- readonly message: JanusMessage;
2
+ readonly message: Record<string, unknown>;
3
+ readonly timeout?: number;
4
4
  readonly stacktrace: Error;
5
- fulfill(response: JanusMessage): void;
5
+ fulfill(response: Record<string, unknown>): void;
6
6
  reject(err: Error): void;
7
7
  }
package/dist/util.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusMessage, JanusRequest } from "./types.js";
3
- export declare function request<T extends JanusMessage>(requestSubject: rxjs.Subject<JanusRequest>, message: JanusMessage): rxjs.Observable<T>;
2
+ import { JanusRequest } from "./types.js";
3
+ export declare function request<T>(requestSubject: rxjs.Subject<JanusRequest>, message: Record<string, unknown>, { timeout }?: {
4
+ timeout?: number;
5
+ }): rxjs.Observable<T>;
4
6
  export declare function makeJanusError({ stacktrace, message }: JanusRequest, code: number, reason: string): Error & {
5
7
  code: number;
6
8
  };
package/dist/util.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as rxjs from "rxjs";
2
- export function request(requestSubject, message) {
2
+ export function request(requestSubject, message, { timeout } = {}) {
3
3
  const stacktrace = new Error();
4
4
  return new rxjs.Observable(subscriber => requestSubject.next({
5
5
  message,
6
+ timeout,
6
7
  stacktrace,
7
8
  fulfill(response) {
8
9
  subscriber.next(response);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsdsoftware/janus-client-node",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Janus WebSocket client for Node, built on RxJS observables",
5
5
  "keywords": [
6
6
  "janus",
package/src/client.ts CHANGED
@@ -3,36 +3,66 @@ import assert from "assert"
3
3
  import { ClientRequestArgs } from "http"
4
4
  import * as rxjs from "rxjs"
5
5
  import { ClientOptions } from "ws"
6
- import { JanusMessage, JanusRequest } from "./types.js"
6
+ import { JanusRequest } from "./types.js"
7
7
  import { makeJanusError } from "./util.js"
8
8
 
9
9
  export function createClient(websocketUrl: string, websocketOpts?: ClientOptions | ClientRequestArgs) {
10
10
  return connect(websocketUrl, websocketOpts, 'janus-protocol').pipe(
11
11
  rxjs.map(conn => {
12
12
  const requestSubject = new rxjs.Subject<JanusRequest>()
13
- const pendingTxs = new Map<unknown, (response: JanusMessage) => void>()
13
+ const pendingTxs = new Map<unknown, (response: Record<string, unknown>) => void>()
14
14
  return {
15
15
  requestSubject,
16
16
  send$: requestSubject.pipe(
17
- rxjs.concatMap(request => {
17
+ rxjs.mergeMap(request => {
18
18
  const txId = String(Math.random())
19
19
  request.message.transaction = txId
20
- conn.send(JSON.stringify(request.message), err => {
21
- if (err) {
22
- request.reject(err)
23
- } else {
24
- pendingTxs.set(txId, response => {
25
- pendingTxs.delete(txId)
26
- if (response.janus == 'error') {
27
- const { code, reason } = response.error as { code: number, reason: string }
28
- request.reject(makeJanusError(request, code, reason))
29
- } else {
30
- request.fulfill(response)
20
+ return new rxjs.Observable<Error | undefined>(subscriber =>
21
+ conn.send(JSON.stringify(request.message), err => {
22
+ subscriber.next(err)
23
+ subscriber.complete()
24
+ })
25
+ ).pipe(
26
+ rxjs.exhaustMap(err => {
27
+ if (err) {
28
+ request.reject(err)
29
+ return rxjs.EMPTY
30
+ } else {
31
+ function waitResponse(timeout: number) {
32
+ return new rxjs.Observable<Record<string, unknown>>(subscriber => {
33
+ pendingTxs.set(txId, response => {
34
+ subscriber.next(response)
35
+ subscriber.complete()
36
+ })
37
+ return () => pendingTxs.delete(txId)
38
+ }).pipe(
39
+ timeout == Infinity ? rxjs.identity : rxjs.timeout({
40
+ first: timeout,
41
+ with: () => rxjs.of({ janus: 'error', error: { code: 408, reason: 'Request timeout' } })
42
+ })
43
+ )
31
44
  }
32
- })
33
- }
34
- })
35
- return rxjs.EMPTY
45
+ return waitResponse(30_000).pipe(
46
+ rxjs.exhaustMap(response =>
47
+ rxjs.iif(
48
+ () => response.janus == 'ack',
49
+ waitResponse(request.timeout ?? 300_000),
50
+ rxjs.of(response)
51
+ )
52
+ ),
53
+ rxjs.exhaustMap(response => {
54
+ if (response.janus == 'error') {
55
+ const { code, reason } = response.error as { code: number, reason: string }
56
+ request.reject(makeJanusError(request, code, reason))
57
+ } else {
58
+ request.fulfill(response)
59
+ }
60
+ return rxjs.EMPTY
61
+ })
62
+ )
63
+ }
64
+ })
65
+ )
36
66
  }),
37
67
  rxjs.share()
38
68
  ),
@@ -40,8 +70,8 @@ export function createClient(websocketUrl: string, websocketOpts?: ClientOptions
40
70
  rxjs.concatMap(event => {
41
71
  try {
42
72
  assert(typeof event.data == 'string')
43
- const message = JSON.parse(event.data) as JanusMessage
44
- if (message.janus == 'event' && typeof message.transaction == 'undefined') {
73
+ const message = JSON.parse(event.data) as Record<string, unknown>
74
+ if (typeof message.transaction == 'undefined') {
45
75
  return rxjs.of(message)
46
76
  } else {
47
77
  const pending = pendingTxs.get(message.transaction)
@@ -59,7 +89,12 @@ export function createClient(websocketUrl: string, websocketOpts?: ClientOptions
59
89
  }),
60
90
  rxjs.share()
61
91
  ),
62
- close$: conn.close$,
92
+ close$: conn.close$.pipe(
93
+ rxjs.tap(() => {
94
+ for (const pending of pendingTxs.values())
95
+ pending({ janus: 'error', error: { code: 503, reason: 'Connection closed before response was received' }})
96
+ })
97
+ ),
63
98
  close: conn.close.bind(conn)
64
99
  }
65
100
  })
@@ -1,11 +1,11 @@
1
1
  import * as rxjs from "rxjs"
2
- import { JanusMessage, JanusRequest } from "./types.js"
2
+ import { JanusRequest } from "./types.js"
3
3
  import { makeJanusError, request } from "./util.js"
4
4
 
5
5
  export function createPluginHandle(
6
6
  session: {
7
7
  requestSubject: rxjs.Subject<JanusRequest>
8
- receive$: rxjs.Observable<JanusMessage>
8
+ receive$: rxjs.Observable<Record<string, unknown>>
9
9
  },
10
10
  plugin: string
11
11
  ) {
@@ -50,7 +50,7 @@ export function createPluginHandle(
50
50
  ),
51
51
  detach() {
52
52
  session.requestSubject.next({
53
- message: { janus: "detach" },
53
+ message: { janus: "detach", handle_id: handleId },
54
54
  stacktrace: new Error(),
55
55
  fulfill: rxjs.noop,
56
56
  reject: err => console.error('JanusPluginHandle detach fail', handleId, err)
package/src/session.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as rxjs from "rxjs"
2
- import { JanusMessage, JanusRequest } from "./types.js"
2
+ import { JanusRequest } from "./types.js"
3
3
  import { request } from "./util.js"
4
4
 
5
5
  export function createSession(
6
6
  client: {
7
7
  requestSubject: rxjs.Subject<JanusRequest>
8
- receive$: rxjs.Observable<JanusMessage>
8
+ receive$: rxjs.Observable<Record<string, unknown>>
9
9
  },
10
10
  { keepAliveInterval = 45_000 }: {
11
11
  keepAliveInterval?: number
@@ -29,6 +29,7 @@ export function createSession(
29
29
  rxjs.share()
30
30
  ),
31
31
  keepAlive$: requestSubject.pipe(
32
+ rxjs.startWith(null),
32
33
  rxjs.switchMap(() =>
33
34
  rxjs.interval(keepAliveInterval).pipe(
34
35
  rxjs.switchMap(() =>
@@ -52,7 +53,7 @@ export function createSession(
52
53
  ),
53
54
  destroy() {
54
55
  client.requestSubject.next({
55
- message: { janus: 'destroy' },
56
+ message: { janus: 'destroy', session_id: sessionId },
56
57
  stacktrace: new Error(),
57
58
  fulfill: rxjs.noop,
58
59
  reject: err => console.error('JanusSession destroy fail', sessionId, err)
package/src/types.ts CHANGED
@@ -1,9 +1,8 @@
1
1
 
2
- export type JanusMessage = Record<string, unknown>
3
-
4
2
  export interface JanusRequest {
5
- readonly message: JanusMessage
3
+ readonly message: Record<string, unknown>
4
+ readonly timeout?: number
6
5
  readonly stacktrace: Error
7
- fulfill(response: JanusMessage): void
6
+ fulfill(response: Record<string, unknown>): void
8
7
  reject(err: Error): void
9
8
  }
package/src/util.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import * as rxjs from "rxjs"
2
- import { JanusMessage, JanusRequest } from "./types.js"
2
+ import { JanusRequest } from "./types.js"
3
3
 
4
- export function request<T extends JanusMessage>(
4
+ export function request<T>(
5
5
  requestSubject: rxjs.Subject<JanusRequest>,
6
- message: JanusMessage
6
+ message: Record<string, unknown>,
7
+ { timeout }: { timeout?: number } = {}
7
8
  ) {
8
9
  const stacktrace = new Error()
9
10
  return new rxjs.Observable<T>(subscriber =>
10
11
  requestSubject.next({
11
12
  message,
13
+ timeout,
12
14
  stacktrace,
13
15
  fulfill(response) {
14
16
  subscriber.next(response as T)