@lsdsoftware/janus-client-node 1.0.1 → 1.0.3

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
@@ -4,8 +4,8 @@ import { ClientOptions } from "ws";
4
4
  import { JanusMessage, JanusRequest } from "./types.js";
5
5
  export declare function createClient(websocketUrl: string, websocketOpts?: ClientOptions | ClientRequestArgs): rxjs.Observable<{
6
6
  requestSubject: rxjs.Subject<JanusRequest>;
7
- send$: rxjs.Observable<Error>;
8
- receive$: rxjs.Observable<Error | JanusMessage>;
7
+ send$: rxjs.Observable<never>;
8
+ receive$: rxjs.Observable<JanusMessage>;
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
@@ -1,26 +1,34 @@
1
1
  import { connect } from "@service-broker/websocket";
2
2
  import assert from "assert";
3
3
  import * as rxjs from "rxjs";
4
- import { JanusError } from "./types.js";
4
+ import { makeJanusError } from "./util.js";
5
5
  export function createClient(websocketUrl, websocketOpts) {
6
6
  return connect(websocketUrl, websocketOpts, 'janus-protocol').pipe(rxjs.map(conn => {
7
7
  const requestSubject = new rxjs.Subject();
8
- const pendingRequests = new Map();
8
+ const pendingTxs = new Map();
9
9
  return {
10
10
  requestSubject,
11
11
  send$: requestSubject.pipe(rxjs.concatMap(request => {
12
12
  const txId = String(Math.random());
13
13
  request.message.transaction = txId;
14
- return new rxjs.Observable(subscriber => conn.send(JSON.stringify(request.message), err => {
14
+ conn.send(JSON.stringify(request.message), err => {
15
15
  if (err) {
16
- subscriber.next(new Error('JanusClient sendMessage fail', { cause: err }));
17
- subscriber.complete();
16
+ request.reject(err);
18
17
  }
19
18
  else {
20
- subscriber.complete();
21
- pendingRequests.set(txId, request);
19
+ pendingTxs.set(txId, response => {
20
+ pendingTxs.delete(txId);
21
+ if (response.janus == 'error') {
22
+ const { code, reason } = response.error;
23
+ request.reject(makeJanusError(request, code, reason));
24
+ }
25
+ else {
26
+ request.fulfill(response);
27
+ }
28
+ });
22
29
  }
23
- }));
30
+ });
31
+ return rxjs.EMPTY;
24
32
  }), rxjs.share()),
25
33
  receive$: conn.message$.pipe(rxjs.concatMap(event => {
26
34
  try {
@@ -30,16 +38,9 @@ export function createClient(websocketUrl, websocketOpts) {
30
38
  return rxjs.of(message);
31
39
  }
32
40
  else {
33
- const request = pendingRequests.get(message.transaction);
34
- if (request) {
35
- pendingRequests.delete(message.transaction);
36
- if (message.janus == 'error') {
37
- const { code, reason } = message.error;
38
- request.reject(new JanusError(code, reason));
39
- }
40
- else {
41
- request.fulfill(message);
42
- }
41
+ const pending = pendingTxs.get(message.transaction);
42
+ if (pending) {
43
+ pending(message);
43
44
  return rxjs.EMPTY;
44
45
  }
45
46
  else {
@@ -48,9 +49,8 @@ export function createClient(websocketUrl, websocketOpts) {
48
49
  }
49
50
  }
50
51
  catch (err) {
51
- if (err instanceof Error)
52
- err.cause = event.data;
53
- return rxjs.of(new Error('JanusClient processMessage fail', { cause: err }));
52
+ console.error('JanusClient receive fail', event.data, err);
53
+ return rxjs.EMPTY;
54
54
  }
55
55
  }), rxjs.share()),
56
56
  close$: conn.close$,
@@ -1,7 +1,7 @@
1
1
  import { afterEverything, describe, expect, Expectation } from "@service-broker/test-utils";
2
2
  import assert from "assert";
3
3
  import * as rxjs from "rxjs";
4
- import { createClient, createPluginHandle, createSession, JanusError, request } from "./index.js";
4
+ import { createClient, createPluginHandle, createSession, request } from "./index.js";
5
5
  const requestSubject = new rxjs.ReplaySubject();
6
6
  const shutdownSubject = new rxjs.Subject();
7
7
  assert(process.env.JANUS_URL, 'Missing env JANUS_URL');
@@ -15,8 +15,6 @@ rxjs.exhaustMap(client => rxjs.merge(client.send$, client.receive$, createSessio
15
15
  next(event) {
16
16
  if (event instanceof Error)
17
17
  console.error(event);
18
- else if (event instanceof JanusError)
19
- console.error('JanusError', event);
20
18
  else
21
19
  console.info('Unhandled', event);
22
20
  },
@@ -1,9 +1,11 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusRequest } from "./types.js";
2
+ import { JanusMessage, JanusRequest } from "./types.js";
3
3
  export declare function createPluginHandle(session: {
4
4
  requestSubject: rxjs.Subject<JanusRequest>;
5
+ receive$: rxjs.Observable<JanusMessage>;
5
6
  }, plugin: string): rxjs.Observable<{
6
7
  requestSubject: rxjs.Subject<JanusRequest>;
7
8
  send$: rxjs.Observable<never>;
9
+ receive$: rxjs.Observable<Record<string, unknown>>;
8
10
  detach(): void;
9
11
  }>;
@@ -1,6 +1,5 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusError } from "./types.js";
3
- import { request } from "./util.js";
2
+ import { makeJanusError, request } from "./util.js";
4
3
  export function createPluginHandle(session, plugin) {
5
4
  return request(session.requestSubject, { janus: "attach", plugin }).pipe(rxjs.map(({ data: { id: handleId } }) => {
6
5
  const requestSubject = new rxjs.Subject();
@@ -13,11 +12,12 @@ export function createPluginHandle(session, plugin) {
13
12
  handle_id: handleId,
14
13
  body: request.message
15
14
  },
15
+ stacktrace: request.stacktrace,
16
16
  fulfill(response) {
17
17
  const { data } = response.plugindata;
18
18
  if (data.error) {
19
19
  const { error, error_code } = data;
20
- request.reject(new JanusError(error_code, error));
20
+ request.reject(makeJanusError(this, error_code, error));
21
21
  }
22
22
  else {
23
23
  request.fulfill(data);
@@ -28,10 +28,15 @@ export function createPluginHandle(session, plugin) {
28
28
  }
29
29
  });
30
30
  return rxjs.EMPTY;
31
- })),
31
+ }), rxjs.share()),
32
+ receive$: session.receive$.pipe(rxjs.filter(message => message.handle_id == handleId), rxjs.map(message => {
33
+ const { data } = message.plugindata;
34
+ return data;
35
+ }), rxjs.share()),
32
36
  detach() {
33
37
  session.requestSubject.next({
34
38
  message: { janus: "detach" },
39
+ stacktrace: new Error(),
35
40
  fulfill: rxjs.noop,
36
41
  reject: err => console.error('JanusPluginHandle detach fail', handleId, err)
37
42
  });
package/dist/session.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import * as rxjs from "rxjs";
2
- import { JanusError, JanusRequest } from "./types.js";
2
+ import { JanusMessage, JanusRequest } from "./types.js";
3
3
  export declare function createSession(client: {
4
4
  requestSubject: rxjs.Subject<JanusRequest>;
5
+ receive$: rxjs.Observable<JanusMessage>;
5
6
  }, { keepAliveInterval }?: {
6
7
  keepAliveInterval?: number;
7
8
  }): rxjs.Observable<{
8
9
  requestSubject: rxjs.Subject<JanusRequest>;
9
10
  send$: rxjs.Observable<never>;
10
- keepAlive$: rxjs.Observable<JanusError>;
11
+ receive$: rxjs.Observable<JanusMessage>;
12
+ keepAlive$: rxjs.Observable<Error>;
11
13
  destroy(): void;
12
14
  }>;
package/dist/session.js CHANGED
@@ -9,9 +9,11 @@ export function createSession(client, { keepAliveInterval = 45_000 } = {}) {
9
9
  request.message.session_id = sessionId;
10
10
  client.requestSubject.next(request);
11
11
  return rxjs.EMPTY;
12
- })),
12
+ }), rxjs.share()),
13
+ receive$: client.receive$.pipe(rxjs.filter(message => message.session_id == sessionId), rxjs.share()),
13
14
  keepAlive$: requestSubject.pipe(rxjs.switchMap(() => rxjs.interval(keepAliveInterval).pipe(rxjs.switchMap(() => new rxjs.Observable(subscriber => client.requestSubject.next({
14
15
  message: { janus: "keepalive", session_id: sessionId },
16
+ stacktrace: new Error(),
15
17
  fulfill() {
16
18
  subscriber.complete();
17
19
  },
@@ -19,10 +21,11 @@ export function createSession(client, { keepAliveInterval = 45_000 } = {}) {
19
21
  subscriber.next(err);
20
22
  subscriber.complete();
21
23
  }
22
- })))))),
24
+ }))))), rxjs.share()),
23
25
  destroy() {
24
26
  client.requestSubject.next({
25
27
  message: { janus: 'destroy' },
28
+ stacktrace: new Error(),
26
29
  fulfill: rxjs.noop,
27
30
  reject: err => console.error('JanusSession destroy fail', sessionId, err)
28
31
  });
package/dist/types.d.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  export type JanusMessage = Record<string, unknown>;
2
- export declare class JanusError {
3
- readonly code: number;
4
- readonly reason: string;
5
- constructor(code: number, reason: string);
6
- }
7
2
  export interface JanusRequest {
8
3
  readonly message: JanusMessage;
4
+ readonly stacktrace: Error;
9
5
  fulfill(response: JanusMessage): void;
10
- reject(err: JanusError): void;
6
+ reject(err: Error): void;
11
7
  }
package/dist/types.js CHANGED
@@ -1,8 +1 @@
1
- export class JanusError {
2
- code;
3
- reason;
4
- constructor(code, reason) {
5
- this.code = code;
6
- this.reason = reason;
7
- }
8
- }
1
+ export {};
package/dist/util.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import * as rxjs from "rxjs";
2
2
  import { JanusMessage, JanusRequest } from "./types.js";
3
3
  export declare function request<T extends JanusMessage>(requestSubject: rxjs.Subject<JanusRequest>, message: JanusMessage): rxjs.Observable<T>;
4
+ export declare function makeJanusError({ stacktrace, message }: JanusRequest, code: number, reason: string): Error & {
5
+ code: number;
6
+ };
package/dist/util.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as rxjs from "rxjs";
2
2
  export function request(requestSubject, message) {
3
+ const stacktrace = new Error();
3
4
  return new rxjs.Observable(subscriber => requestSubject.next({
4
5
  message,
6
+ stacktrace,
5
7
  fulfill(response) {
6
8
  subscriber.next(response);
7
9
  subscriber.complete();
@@ -11,3 +13,9 @@ export function request(requestSubject, message) {
11
13
  }
12
14
  }));
13
15
  }
16
+ export function makeJanusError({ stacktrace, message }, code, reason) {
17
+ stacktrace.name = 'JanusError';
18
+ stacktrace.cause = message;
19
+ stacktrace.message = reason;
20
+ return Object.assign(stacktrace, { code });
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsdsoftware/janus-client-node",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Janus WebSocket client for Node, built on RxJS observables",
5
5
  "keywords": [
6
6
  "janus",
package/src/client.ts CHANGED
@@ -3,30 +3,36 @@ 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 { JanusError, JanusMessage, JanusRequest } from "./types.js"
6
+ import { JanusMessage, JanusRequest } from "./types.js"
7
+ import { makeJanusError } from "./util.js"
7
8
 
8
9
  export function createClient(websocketUrl: string, websocketOpts?: ClientOptions | ClientRequestArgs) {
9
10
  return connect(websocketUrl, websocketOpts, 'janus-protocol').pipe(
10
11
  rxjs.map(conn => {
11
12
  const requestSubject = new rxjs.Subject<JanusRequest>()
12
- const pendingRequests = new Map<unknown, JanusRequest>()
13
+ const pendingTxs = new Map<unknown, (response: JanusMessage) => void>()
13
14
  return {
14
15
  requestSubject,
15
16
  send$: requestSubject.pipe(
16
17
  rxjs.concatMap(request => {
17
18
  const txId = String(Math.random())
18
19
  request.message.transaction = txId
19
- return new rxjs.Observable<Error>(subscriber =>
20
- conn.send(JSON.stringify(request.message), err => {
21
- if (err) {
22
- subscriber.next(new Error('JanusClient sendMessage fail', { cause: err }))
23
- subscriber.complete()
24
- } else {
25
- subscriber.complete()
26
- pendingRequests.set(txId, request)
27
- }
28
- })
29
- )
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)
31
+ }
32
+ })
33
+ }
34
+ })
35
+ return rxjs.EMPTY
30
36
  }),
31
37
  rxjs.share()
32
38
  ),
@@ -38,23 +44,17 @@ export function createClient(websocketUrl: string, websocketOpts?: ClientOptions
38
44
  if (message.janus == 'event' && typeof message.transaction == 'undefined') {
39
45
  return rxjs.of(message)
40
46
  } else {
41
- const request = pendingRequests.get(message.transaction)
42
- if (request) {
43
- pendingRequests.delete(message.transaction)
44
- if (message.janus == 'error') {
45
- const { code, reason } = message.error as { code: number, reason: string }
46
- request.reject(new JanusError(code, reason))
47
- } else {
48
- request.fulfill(message)
49
- }
47
+ const pending = pendingTxs.get(message.transaction)
48
+ if (pending) {
49
+ pending(message)
50
50
  return rxjs.EMPTY
51
51
  } else {
52
52
  throw new Error('Stray')
53
53
  }
54
54
  }
55
55
  } catch (err) {
56
- if (err instanceof Error) err.cause = event.data
57
- return rxjs.of(new Error('JanusClient processMessage fail', { cause: err }))
56
+ console.error('JanusClient receive fail', event.data, err)
57
+ return rxjs.EMPTY
58
58
  }
59
59
  }),
60
60
  rxjs.share()
package/src/index.test.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { afterEverything, describe, expect, Expectation } from "@service-broker/test-utils"
2
2
  import assert from "assert"
3
3
  import * as rxjs from "rxjs"
4
- import { createClient, createPluginHandle, createSession, JanusError, JanusRequest, request } from "./index.js"
4
+ import { createClient, createPluginHandle, createSession, JanusRequest, request } from "./index.js"
5
5
 
6
6
  const requestSubject = new rxjs.ReplaySubject<JanusRequest>()
7
7
  const shutdownSubject = new rxjs.Subject<void>()
@@ -52,7 +52,6 @@ createClient(process.env.JANUS_URL).pipe(
52
52
  ).subscribe({
53
53
  next(event) {
54
54
  if (event instanceof Error) console.error(event)
55
- else if (event instanceof JanusError) console.error('JanusError', event)
56
55
  else console.info('Unhandled', event)
57
56
  },
58
57
  error(err) {
@@ -1,8 +1,14 @@
1
1
  import * as rxjs from "rxjs"
2
- import { JanusError, JanusRequest } from "./types.js"
3
- import { request } from "./util.js"
2
+ import { JanusMessage, JanusRequest } from "./types.js"
3
+ import { makeJanusError, request } from "./util.js"
4
4
 
5
- export function createPluginHandle(session: { requestSubject: rxjs.Subject<JanusRequest> }, plugin: string) {
5
+ export function createPluginHandle(
6
+ session: {
7
+ requestSubject: rxjs.Subject<JanusRequest>
8
+ receive$: rxjs.Observable<JanusMessage>
9
+ },
10
+ plugin: string
11
+ ) {
6
12
  return request<{ data: { id: number } }>(session.requestSubject, { janus: "attach", plugin }).pipe(
7
13
  rxjs.map(({ data: { id: handleId }}) => {
8
14
  const requestSubject = new rxjs.Subject<JanusRequest>()
@@ -16,11 +22,12 @@ export function createPluginHandle(session: { requestSubject: rxjs.Subject<Janus
16
22
  handle_id: handleId,
17
23
  body: request.message
18
24
  },
25
+ stacktrace: request.stacktrace,
19
26
  fulfill(response) {
20
27
  const { data } = response.plugindata as { data: Record<string, unknown> }
21
28
  if (data.error) {
22
29
  const { error, error_code } = data as { error: string, error_code: number }
23
- request.reject(new JanusError(error_code, error))
30
+ request.reject(makeJanusError(this, error_code, error))
24
31
  } else {
25
32
  request.fulfill(data)
26
33
  }
@@ -30,11 +37,21 @@ export function createPluginHandle(session: { requestSubject: rxjs.Subject<Janus
30
37
  }
31
38
  })
32
39
  return rxjs.EMPTY
33
- })
40
+ }),
41
+ rxjs.share()
42
+ ),
43
+ receive$: session.receive$.pipe(
44
+ rxjs.filter(message => message.handle_id == handleId),
45
+ rxjs.map(message => {
46
+ const { data } = message.plugindata as { data: Record<string, unknown> }
47
+ return data
48
+ }),
49
+ rxjs.share()
34
50
  ),
35
51
  detach() {
36
52
  session.requestSubject.next({
37
53
  message: { janus: "detach" },
54
+ stacktrace: new Error(),
38
55
  fulfill: rxjs.noop,
39
56
  reject: err => console.error('JanusPluginHandle detach fail', handleId, err)
40
57
  })
package/src/session.ts CHANGED
@@ -1,10 +1,16 @@
1
1
  import * as rxjs from "rxjs"
2
- import { JanusError, JanusRequest } from "./types.js"
2
+ import { JanusMessage, JanusRequest } from "./types.js"
3
3
  import { request } from "./util.js"
4
4
 
5
- export function createSession(client: { requestSubject: rxjs.Subject<JanusRequest> }, { keepAliveInterval = 45_000 }: {
6
- keepAliveInterval?: number
7
- } = {}) {
5
+ export function createSession(
6
+ client: {
7
+ requestSubject: rxjs.Subject<JanusRequest>
8
+ receive$: rxjs.Observable<JanusMessage>
9
+ },
10
+ { keepAliveInterval = 45_000 }: {
11
+ keepAliveInterval?: number
12
+ } = {}
13
+ ) {
8
14
  return request<{ data: { id: number } }>(client.requestSubject, { janus: 'create' }).pipe(
9
15
  rxjs.map(({ data: { id: sessionId } }) => {
10
16
  const requestSubject = new rxjs.Subject<JanusRequest>()
@@ -15,15 +21,21 @@ export function createSession(client: { requestSubject: rxjs.Subject<JanusReques
15
21
  request.message.session_id = sessionId
16
22
  client.requestSubject.next(request)
17
23
  return rxjs.EMPTY
18
- })
24
+ }),
25
+ rxjs.share()
26
+ ),
27
+ receive$: client.receive$.pipe(
28
+ rxjs.filter(message => message.session_id == sessionId),
29
+ rxjs.share()
19
30
  ),
20
31
  keepAlive$: requestSubject.pipe(
21
32
  rxjs.switchMap(() =>
22
33
  rxjs.interval(keepAliveInterval).pipe(
23
34
  rxjs.switchMap(() =>
24
- new rxjs.Observable<JanusError>(subscriber =>
35
+ new rxjs.Observable<Error>(subscriber =>
25
36
  client.requestSubject.next({
26
37
  message: { janus: "keepalive", session_id: sessionId },
38
+ stacktrace: new Error(),
27
39
  fulfill() {
28
40
  subscriber.complete()
29
41
  },
@@ -35,11 +47,13 @@ export function createSession(client: { requestSubject: rxjs.Subject<JanusReques
35
47
  )
36
48
  )
37
49
  )
38
- )
50
+ ),
51
+ rxjs.share()
39
52
  ),
40
53
  destroy() {
41
54
  client.requestSubject.next({
42
55
  message: { janus: 'destroy' },
56
+ stacktrace: new Error(),
43
57
  fulfill: rxjs.noop,
44
58
  reject: err => console.error('JanusSession destroy fail', sessionId, err)
45
59
  })
package/src/types.ts CHANGED
@@ -1,12 +1,9 @@
1
1
 
2
2
  export type JanusMessage = Record<string, unknown>
3
3
 
4
- export class JanusError {
5
- constructor(readonly code: number, readonly reason: string) {}
6
- }
7
-
8
4
  export interface JanusRequest {
9
5
  readonly message: JanusMessage
6
+ readonly stacktrace: Error
10
7
  fulfill(response: JanusMessage): void
11
- reject(err: JanusError): void
8
+ reject(err: Error): void
12
9
  }
package/src/util.ts CHANGED
@@ -5,9 +5,11 @@ export function request<T extends JanusMessage>(
5
5
  requestSubject: rxjs.Subject<JanusRequest>,
6
6
  message: JanusMessage
7
7
  ) {
8
+ const stacktrace = new Error()
8
9
  return new rxjs.Observable<T>(subscriber =>
9
10
  requestSubject.next({
10
11
  message,
12
+ stacktrace,
11
13
  fulfill(response) {
12
14
  subscriber.next(response as T)
13
15
  subscriber.complete()
@@ -18,3 +20,10 @@ export function request<T extends JanusMessage>(
18
20
  })
19
21
  )
20
22
  }
23
+
24
+ export function makeJanusError({ stacktrace, message }: JanusRequest, code: number, reason: string) {
25
+ stacktrace.name = 'JanusError'
26
+ stacktrace.cause = message
27
+ stacktrace.message = reason
28
+ return Object.assign(stacktrace, { code })
29
+ }