-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle
room.subscribed
in realtime-api package (#311)
* ask get_initial_state on room subscribe * applyEmitterTransforms before subscribe * update toExternalJSON to convert nested arrays * add toExternalJSON test case * change ConsumerContract to accept a return type for subscribe * handle room.subscribed for realtime-api * update rt example * update specs * export interface and update docstring for subscribe() * add changeset * Add `instanceProxyFactory` (#315) * update toExternalJSON to be no-op for no-snake-case strings * add EventTransformType on each EventTransform * welcome proxyFactory * update BaseComponent to process the event payload for nested fields * rename proxyFactory to eventTransformUtils and refactoring a bit * add instanceProxyFactory tests * add comment for EventTransformType * add comment on _instanceByTransformKey * use type instead of key for EventTransformType * add comment * add comments to explain why we override subscribe on RoomSession * fix convert to date including ms * update changeset * rename key to type in test comments
- Loading branch information
Edoardo Gallo
authored
Oct 4, 2021
1 parent
cc5fd62
commit febb842
Showing
19 changed files
with
466 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@signalwire/core': patch | ||
--- | ||
|
||
Update `ConsumerContract` interface and add array-keys to the toExternalJSON whitelist. | ||
Fix issue on converting timestamp values to `Date` objects. [realtime-api] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@signalwire/realtime-api': patch | ||
--- | ||
|
||
Allow users to listen the `room.subscribed` event and change the `roomSession.subscribe()` to return a `Promise<RoomSessionFullState>`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { EventTransform } from './interfaces' | ||
import { | ||
instanceProxyFactory, | ||
_instanceByTransformType, | ||
} from './eventTransformUtils' | ||
import { toExternalJSON } from './toExternalJSON' | ||
|
||
describe('instanceProxyFactory', () => { | ||
const mockInstance = jest.fn() | ||
|
||
const payload = { | ||
nested: { | ||
id: 'random', | ||
snake_case: 'foo', | ||
camelCase: 'baz', | ||
otherTest: true, | ||
counter: 0, | ||
}, | ||
} | ||
|
||
const transform: EventTransform = { | ||
// @ts-expect-error | ||
type: 'randomKey', | ||
instanceFactory: () => { | ||
return mockInstance | ||
}, | ||
payloadTransform: (payload: any) => { | ||
return toExternalJSON(payload.nested) | ||
}, | ||
getInstanceEventNamespace: (payload: any) => { | ||
return payload.nested.id | ||
}, | ||
getInstanceEventChannel: (payload: any) => { | ||
return payload.nested.snake_case | ||
}, | ||
} | ||
|
||
it('should return a cached Proxy object reading from the payload', () => { | ||
for (let i = 0; i < 4; i++) { | ||
const proxy = instanceProxyFactory({ | ||
transform, | ||
payload: { | ||
nested: { | ||
...payload.nested, | ||
counter: i, | ||
}, | ||
}, | ||
}) | ||
|
||
expect(proxy.snakeCase).toBe('foo') | ||
expect(proxy.snake_case).toBeUndefined() | ||
expect(proxy.camelCase).toBe('baz') | ||
expect(proxy.otherTest).toBe(true) | ||
expect(proxy.counter).toBe(i) | ||
expect(proxy.eventChannel).toBe('foo') | ||
expect(proxy._eventsNamespace).toBe('random') | ||
} | ||
|
||
expect(_instanceByTransformType.size).toBe(1) | ||
expect(_instanceByTransformType.get('randomKey')).toBe(mockInstance) | ||
}) | ||
|
||
it('should cache the instances by type', () => { | ||
const firstProxy = instanceProxyFactory({ transform, payload }) | ||
expect(firstProxy.snakeCase).toBe('foo') | ||
|
||
const secondProxy = instanceProxyFactory({ transform, payload }) | ||
expect(secondProxy.snakeCase).toBe('foo') | ||
|
||
expect(_instanceByTransformType.size).toBe(1) | ||
expect(_instanceByTransformType.get('randomKey')).toBe(mockInstance) | ||
|
||
const thirdProxy = instanceProxyFactory({ | ||
transform: { | ||
...transform, | ||
// @ts-expect-error | ||
type: 'otherKey', | ||
}, | ||
payload, | ||
}) | ||
expect(thirdProxy.snakeCase).toBe('foo') | ||
|
||
expect(_instanceByTransformType.size).toBe(2) | ||
expect(_instanceByTransformType.get('otherKey')).toBe(mockInstance) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { EventTransform, EventTransformType } from './interfaces' | ||
|
||
interface InstanceProxyFactoryParams { | ||
transform: EventTransform | ||
payload: Record<any, unknown> | ||
} | ||
|
||
interface NestedFieldToProcess { | ||
/** Nested field to transform through an EventTransform */ | ||
field: string | ||
/** | ||
* Allow us to update the nested `payload` to match the shape we already | ||
* treat consuming other events from the server. | ||
* For example: wrapping the `payload` within a specific key. | ||
* `payload` becomes `{ "member": payload }` | ||
*/ | ||
preProcessPayload: (payload: any) => any | ||
/** Type of the EventTransform to select from `instance._emitterTransforms` */ | ||
eventTransformType: EventTransformType | ||
} | ||
|
||
/** | ||
* Note: the cached instances within `_instanceByTransformType` will never be | ||
* cleaned since we're caching by `transform.type` so we will always have one | ||
* instance per type regardless of the Room/Member/Recording we're working on. | ||
* This is something we can improve in the future, but not an issue right now. | ||
* Exported for test purposes | ||
*/ | ||
export const _instanceByTransformType = new Map<string, EventTransform>() | ||
export const NESTED_FIELDS_TO_PROCESS: NestedFieldToProcess[] = [ | ||
{ | ||
field: 'members', | ||
preProcessPayload: (payload) => ({ member: payload }), | ||
eventTransformType: 'roomSessionMember', | ||
}, | ||
{ | ||
field: 'recordings', | ||
preProcessPayload: (payload) => ({ recording: payload }), | ||
eventTransformType: 'roomSessionRecording', | ||
}, | ||
] | ||
|
||
const _getOrCreateInstance = ({ | ||
transform, | ||
payload, | ||
}: InstanceProxyFactoryParams) => { | ||
if (!_instanceByTransformType.has(transform.type)) { | ||
const instance = transform.instanceFactory(payload) | ||
_instanceByTransformType.set(transform.type, instance) | ||
|
||
return instance | ||
} | ||
|
||
return _instanceByTransformType.get(transform.type) | ||
} | ||
|
||
export const instanceProxyFactory = ({ | ||
transform, | ||
payload, | ||
}: InstanceProxyFactoryParams) => { | ||
/** Create the instance or pick from cache */ | ||
const cachedInstance = _getOrCreateInstance({ | ||
transform, | ||
payload, | ||
}) | ||
|
||
const transformedPayload = transform.payloadTransform(payload) | ||
const proxiedObj = new Proxy(cachedInstance, { | ||
get(target: any, prop: any, receiver: any) { | ||
if (prop === '_eventsNamespace' && transform.getInstanceEventNamespace) { | ||
return transform.getInstanceEventNamespace(payload) | ||
} | ||
if (prop === 'eventChannel' && transform.getInstanceEventChannel) { | ||
return transform.getInstanceEventChannel(payload) | ||
} | ||
|
||
if (prop in transformedPayload) { | ||
return transformedPayload[prop] | ||
} | ||
|
||
return Reflect.get(target, prop, receiver) | ||
}, | ||
}) | ||
|
||
return proxiedObj | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.