Skip to content

Commit

Permalink
Hotfixes for realtime-api and js (#615)
Browse files Browse the repository at this point in the history
* always connect the realtime-api video client

* changeset

* delay a bit the whole destroy

* changeset

* update specs

* always connect the realtime-api clients

* expose disconnect methods for Video, Chat and PubSub clients

* add disconnect to ts interfaces

* changeset for disconnect method
  • Loading branch information
edolix authored Aug 12, 2022
1 parent 7bdd7ab commit 7b19610
Show file tree
Hide file tree
Showing 16 changed files with 100 additions and 76 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-eyes-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@signalwire/realtime-api': patch
---

hotfix: always connect the lower level client.
5 changes: 5 additions & 0 deletions .changeset/honest-ways-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@signalwire/realtime-api': minor
---

Expose `.disconnect()` method on all the client objects: Video, Chat, PubSub, Task, Voice and Messaging.
5 changes: 5 additions & 0 deletions .changeset/slimy-toes-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@signalwire/core': patch
---

hotfix: wait for other sagas to complete before destroy
3 changes: 2 additions & 1 deletion packages/core/src/redux/rootSaga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,9 @@ describe('initSessionSaga', () => {
})
const sessionStatusTask = createMockTask()
sessionStatusTask.cancel = jest.fn()
// saga.next(sessionStatusTask).fork(componentCleanupSaga)
// saga.next().fork(componentCleanupSaga)
saga.next(sessionStatusTask).take(destroyAction.type)
saga.next().delay(300)
saga.next().isDone()
expect(sessionStatusTask.cancel).toHaveBeenCalledTimes(1)
expect(pubSubChannel.close).toHaveBeenCalledTimes(1)
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/redux/rootSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export function* initSessionSaga({
session.connect()

yield take(destroyAction.type)

// leave a bit of space to other sagas to finish
yield delay(300)
/**
* We have to manually cancel the fork because it is not
* being automatically cleaned up when the session is
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ export interface ConsumerContract<
SubscribeType = void
> extends EmitterContract<EventTypes> {
subscribe(): Promise<SubscribeType>
/**
* Disconnects this client. The client will stop receiving events and you will
* need to create a new instance if you want to use it again.
*
* @example
*
* ```js
* client.disconnect()
* ```
*/
disconnect(): void
}

export interface ClientContract<
Expand Down
16 changes: 4 additions & 12 deletions packages/realtime-api/src/chat/ChatClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,6 @@ const ChatClient = function (options?: ChatClientOptions) {
store,
emitter,
})
const chatOn: ChatClient['on'] = (...args) => {
clientConnect(client)

return chat.on(...args)
}
const chatOnce: ChatClient['once'] = (...args) => {
clientConnect(client)

return chat.once(...args)
}

const createInterceptor = <K extends ClientMethods>(prop: K) => {
return async (...params: Parameters<ChatClient[K]>) => {
Expand All @@ -93,9 +83,8 @@ const ChatClient = function (options?: ChatClientOptions) {
}

const interceptors = {
on: chatOn,
once: chatOnce,
_session: client,
disconnect: () => client.disconnect(),
} as const

return new Proxy<ChatClient>(chat, {
Expand All @@ -112,6 +101,9 @@ const ChatClient = function (options?: ChatClientOptions) {
return undefined
}

// Always connect the underlying client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down
11 changes: 11 additions & 0 deletions packages/realtime-api/src/messaging/Messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ export interface Messaging
ClientContextContract {
/** @internal */
_session: RealtimeClient
/**
* Disconnects this client. The client will stop receiving events and you will
* need to create a new instance if you want to use it again.
*
* @example
*
* ```js
* client.disconnect()
* ```
*/
disconnect(): void

/**
* Send an outbound SMS or MMS message.
Expand Down
17 changes: 4 additions & 13 deletions packages/realtime-api/src/messaging/MessagingClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,6 @@ const MessagingClient = function (options?: MessagingClientOptions) {
messaging.applyEmitterTransforms()
})

const messagingOn: Messaging['on'] = (...args) => {
clientConnect(client)

return messaging.on(...args)
}
const messagingOnce: Messaging['once'] = (...args) => {
clientConnect(client)

return messaging.once(...args)
}
const send: Messaging['send'] = async (...args) => {
await clientConnect(client)

Expand All @@ -79,9 +69,7 @@ const MessagingClient = function (options?: MessagingClientOptions) {

const interceptors = {
...clientContextInterceptorsFactory(client),
on: messagingOn,
once: messagingOnce,
send: send,
send,
_session: client,
disconnect,
} as const
Expand All @@ -93,6 +81,9 @@ const MessagingClient = function (options?: MessagingClientOptions) {
return interceptors[prop]
}

// Always connect the underlying client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down
16 changes: 4 additions & 12 deletions packages/realtime-api/src/pubSub/PubSubClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,6 @@ const PubSubClient = function (options?: PubSubClientOptions) {
store,
emitter,
})
const pubSubOn: PubSubClient['on'] = (...args) => {
clientConnect(client)

return pubSub.on(...args)
}
const pubSubOnce: PubSubClient['once'] = (...args) => {
clientConnect(client)

return pubSub.once(...args)
}

const createInterceptor = <K extends ClientMethods>(prop: K) => {
return async (...params: Parameters<PubSubClient[K]>) => {
Expand All @@ -75,9 +65,8 @@ const PubSubClient = function (options?: PubSubClientOptions) {
}

const interceptors = {
on: pubSubOn,
once: pubSubOnce,
_session: client,
disconnect: () => client.disconnect(),
} as const

return new Proxy<PubSubClient>(pubSub, {
Expand All @@ -94,6 +83,9 @@ const PubSubClient = function (options?: PubSubClientOptions) {
return undefined
}

// Always connect the underlying client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down
11 changes: 11 additions & 0 deletions packages/realtime-api/src/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ export interface Task
ClientContextContract {
/** @internal */
_session: RealtimeClient
/**
* Disconnects this client. The client will stop receiving events and you will
* need to create a new instance if you want to use it again.
*
* @example
*
* ```js
* client.disconnect()
* ```
*/
disconnect(): void
}

/** @internal */
Expand Down
15 changes: 3 additions & 12 deletions packages/realtime-api/src/task/TaskClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,10 @@ const TaskClient = function (options?: TaskClientOptions) {
emitter,
})

const taskOn: TaskClient['on'] = (...args) => {
clientConnect(client)

return task.on(...args)
}
const taskOnce: TaskClient['once'] = (...args) => {
clientConnect(client)

return task.once(...args)
}
const disconnect = () => client.disconnect()

const interceptors = {
...clientContextInterceptorsFactory(client),
on: taskOn,
once: taskOnce,
_session: client,
disconnect,
} as const
Expand All @@ -65,6 +53,9 @@ const TaskClient = function (options?: TaskClientOptions) {
return interceptors[prop]
}

// Always connect the underline client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down
11 changes: 11 additions & 0 deletions packages/realtime-api/src/video/Video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ export interface Video extends ConsumerContract<RealTimeVideoApiEvents> {
subscribe(): Promise<void>
/** @internal */
_session: RealtimeClient
/**
* Disconnects this client. The client will stop receiving events and you will
* need to create a new instance if you want to use it again.
*
* @example
*
* ```js
* client.disconnect()
* ```
*/
disconnect(): void

getRoomSessions(): Promise<{ roomSessions: RoomSession[] }>
getRoomSessionById(id: string): Promise<{ roomSession: RoomSession }>
Expand Down
18 changes: 5 additions & 13 deletions packages/realtime-api/src/video/VideoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,17 @@ const VideoClient = function (options?: VideoClientOptions) {
emitter,
})

// Video interceptors:
const videoOn: Video['on'] = (...args) => {
clientConnect(client)

return video.on(...args)
}
const videoOnce: Video['once'] = (...args) => {
clientConnect(client)

return video.once(...args)
}
const videoSubscribe: Video['subscribe'] = async () => {
await clientConnect(client)

return video.subscribe()
}

const interceptors = {
on: videoOn,
once: videoOnce,
// keep subscribe in here to await clientConnect
subscribe: videoSubscribe,
_session: client,
disconnect: () => client.disconnect(),
} as const

return new Proxy<Omit<VideoClient, 'new'>>(video, {
Expand All @@ -82,6 +71,9 @@ const VideoClient = function (options?: VideoClientOptions) {
return interceptors[prop]
}

// Always connect the underlying client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down
13 changes: 13 additions & 0 deletions packages/realtime-api/src/voice/Voice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ export interface Voice
ClientContextContract {
/** @internal */
_session: RealtimeClient

/**
* Disconnects this client. The client will stop receiving events and you will
* need to create a new instance if you want to use it again.
*
* @example
*
* ```js
* client.disconnect()
* ```
*/
disconnect(): void

/**
* Makes an outbound Call and waits until it has been answered or hung up.
* This is an advanced method that lets you call multiple devices in parallel
Expand Down
16 changes: 3 additions & 13 deletions packages/realtime-api/src/voice/VoiceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,6 @@ const VoiceClient = function (options?: VoiceClientOptions) {
...options,
})

const clientOn: Voice['on'] = (...args) => {
clientConnect(client)

return voice.on(...args)
}
const clientOnce: Voice['once'] = (...args) => {
clientConnect(client)

return voice.once(...args)
}

const callDial: Call['dial'] = async (dialer) => {
await clientConnect(client)

Expand All @@ -100,8 +89,6 @@ const VoiceClient = function (options?: VoiceClientOptions) {

const interceptors = {
...clientContextInterceptorsFactory(client),
on: clientOn,
once: clientOnce,
dial: callDial,
_session: client,
disconnect,
Expand All @@ -114,6 +101,9 @@ const VoiceClient = function (options?: VoiceClientOptions) {
return interceptors[prop]
}

// Always connect the underlying client
clientConnect(client)

return Reflect.get(target, prop, receiver)
},
})
Expand Down

0 comments on commit 7b19610

Please sign in to comment.