-
Notifications
You must be signed in to change notification settings - Fork 35
feat: SDK update for version 0.29.0 #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
4d979a5
a5a8671
858e600
d0b39b0
f3d9a37
8b3dec0
afd5e64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,15 +57,32 @@ type RealtimeResponse = { | |
| } | ||
|
|
||
| type RealtimeRequest = { | ||
| type: 'authentication'; | ||
| data: RealtimeRequestAuthenticate; | ||
| type: 'authentication' | 'subscribe'; | ||
| data: RealtimeRequestAuthenticate | RealtimeRequestSubscribe[]; | ||
| } | ||
|
|
||
| type RealtimeRequestSubscribe = { | ||
| subscriptionId?: string; | ||
| channels: string[]; | ||
| queries: string[]; | ||
| } | ||
|
|
||
| type RealtimeResponseAction = { | ||
| to?: string; | ||
| success?: boolean; | ||
| subscriptions?: Array<{ | ||
| subscriptionId?: string; | ||
| channels?: string[]; | ||
| queries?: string[]; | ||
| }>; | ||
| } | ||
|
|
||
| export type RealtimeResponseEvent<T extends unknown> = { | ||
| events: string[]; | ||
| channels: string[]; | ||
| timestamp: number; | ||
| payload: T; | ||
| subscriptions?: string[]; | ||
| } | ||
|
|
||
| type RealtimeResponseError = { | ||
|
|
@@ -103,21 +120,22 @@ type Realtime = { | |
|
|
||
| url?: string; | ||
| lastMessage?: RealtimeResponse; | ||
| channels: Set<string>; | ||
| queries: Set<string>; | ||
| subscriptions: Map<number, { | ||
| channels: string[]; | ||
| queries: string[]; | ||
| callback: (payload: RealtimeResponseEvent<any>) => void | ||
| }>; | ||
| slotToSubscriptionId: Map<number, string>; | ||
| subscriptionIdToSlot: Map<string, number>; | ||
| pendingSubscribeSlots: number[]; | ||
| subscriptionsCounter: number; | ||
| reconnect: boolean; | ||
| reconnectAttempts: number; | ||
| getTimeout: () => number; | ||
| connect: () => void; | ||
| createSocket: () => void; | ||
| createHeartbeat: () => void; | ||
| cleanUp: (channels: string[], queries: string[]) => void; | ||
| sendSubscribeMessage: () => void; | ||
| onMessage: (event: MessageEvent) => void; | ||
| } | ||
|
|
||
|
|
@@ -161,8 +179,8 @@ class Client { | |
| 'x-sdk-name': 'React Native', | ||
| 'x-sdk-platform': 'client', | ||
| 'x-sdk-language': 'reactnative', | ||
| 'x-sdk-version': '0.28.0', | ||
| 'X-Appwrite-Response-Format': '1.9.1', | ||
| 'x-sdk-version': '0.29.0', | ||
| 'X-Appwrite-Response-Format': '1.9.2', | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -377,9 +395,10 @@ class Client { | |
| timeout: undefined, | ||
| heartbeat: undefined, | ||
| url: '', | ||
| channels: new Set(), | ||
| queries: new Set(), | ||
| subscriptions: new Map(), | ||
| slotToSubscriptionId: new Map(), | ||
| subscriptionIdToSlot: new Map(), | ||
| pendingSubscribeSlots: [], | ||
| subscriptionsCounter: 0, | ||
| reconnect: true, | ||
| reconnectAttempts: 0, | ||
|
|
@@ -414,20 +433,14 @@ class Client { | |
| }, 20_000); | ||
| }, | ||
| createSocket: () => { | ||
| if (this.realtime.channels.size < 1) { | ||
| if (this.realtime.subscriptions.size < 1) { | ||
| this.realtime.reconnect = false; | ||
| this.realtime.socket?.close(); | ||
| return; | ||
| } | ||
|
|
||
| const channels = new URLSearchParams(); | ||
| channels.set('project', this.config.project); | ||
| this.realtime.channels.forEach(channel => { | ||
| channels.append('channels[]', channel); | ||
| }); | ||
| this.realtime.queries.forEach(query => { | ||
| channels.append('queries[]', query); | ||
| }); | ||
|
|
||
| const url = this.config.endpointRealtime + '/realtime?' + channels.toString(); | ||
|
|
||
|
|
@@ -476,23 +489,107 @@ class Client { | |
| this.realtime.createSocket(); | ||
| }, timeout); | ||
| }) | ||
| } else if (this.realtime.socket?.readyState === WebSocket.OPEN) { | ||
| // URL is unchanged; re-send subscribe message to apply updated queries. | ||
| this.realtime.sendSubscribeMessage(); | ||
| } | ||
| }, | ||
| sendSubscribeMessage: () => { | ||
| if (!this.realtime.socket || this.realtime.socket.readyState !== WebSocket.OPEN) { | ||
| return; | ||
| } | ||
|
|
||
| const rows: RealtimeRequestSubscribe[] = []; | ||
| this.realtime.pendingSubscribeSlots = []; | ||
|
|
||
| this.realtime.subscriptions.forEach((sub, slot) => { | ||
| const queries = sub.queries ?? []; | ||
|
|
||
| const row: RealtimeRequestSubscribe = { | ||
| channels: sub.channels, | ||
| queries | ||
| }; | ||
| const knownSubscriptionId = this.realtime.slotToSubscriptionId.get(slot); | ||
| if (knownSubscriptionId) { | ||
| row.subscriptionId = knownSubscriptionId; | ||
| } | ||
|
|
||
| rows.push(row); | ||
| this.realtime.pendingSubscribeSlots.push(slot); | ||
| }); | ||
|
|
||
| if (rows.length < 1) { | ||
| return; | ||
| } | ||
|
|
||
| this.realtime.socket.send(JSONbig.stringify(<RealtimeRequest>{ | ||
| type: 'subscribe', | ||
| data: rows | ||
| })); | ||
| }, | ||
| onMessage: (event) => { | ||
| try { | ||
| const message: RealtimeResponse = JSONbig.parse(event.data); | ||
| this.realtime.lastMessage = message; | ||
| switch (message.type) { | ||
| case 'connected': { | ||
| const messageData = <RealtimeResponseConnected>message.data; | ||
|
|
||
| let session = this.config.session; | ||
| if (!session) { | ||
| const cookie = JSONbig.parse(window.localStorage.getItem('cookieFallback') ?? '{}'); | ||
| session = cookie?.[`a_session_${this.config.project}`]; | ||
| } | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
| if (session && !messageData?.user) { | ||
| this.realtime.socket?.send(JSONbig.stringify(<RealtimeRequest>{ | ||
| type: 'authentication', | ||
| data: { | ||
| session | ||
| } | ||
| })); | ||
| } | ||
|
|
||
| this.realtime.sendSubscribeMessage(); | ||
| break; | ||
|
Comment on lines
+535
to
+553
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
| case 'response': { | ||
| const action = message.data as RealtimeResponseAction; | ||
| if (action?.to !== 'subscribe' || !Array.isArray(action.subscriptions)) { | ||
| break; | ||
| } | ||
|
|
||
| action.subscriptions.forEach((subscription, index) => { | ||
| const subscriptionId = subscription?.subscriptionId; | ||
| const slot = this.realtime.pendingSubscribeSlots[index]; | ||
| if (!subscriptionId || slot === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| this.realtime.slotToSubscriptionId.set(slot, subscriptionId); | ||
| this.realtime.subscriptionIdToSlot.set(subscriptionId, slot); | ||
| }); | ||
| break; | ||
| } | ||
| case 'event': | ||
| let data = <RealtimeResponseEvent<unknown>>message.data; | ||
| const data = <RealtimeResponseEvent<unknown>>message.data; | ||
| if (data?.channels) { | ||
| const isSubscribed = data.channels.some(channel => this.realtime.channels.has(channel)); | ||
| if (!isSubscribed) return; | ||
| this.realtime.subscriptions.forEach(subscription => { | ||
| if (data.channels.some(channel => subscription.channels.includes(channel))) { | ||
| setTimeout(() => subscription.callback(data)); | ||
| } | ||
| }) | ||
| if (data.subscriptions && data.subscriptions.length > 0) { | ||
| data.subscriptions.forEach((subscriptionId) => { | ||
| const slot = this.realtime.subscriptionIdToSlot.get(subscriptionId); | ||
| if (slot !== undefined) { | ||
| const subscription = this.realtime.subscriptions.get(slot); | ||
| if (subscription) { | ||
| setTimeout(() => subscription.callback(data)); | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| this.realtime.subscriptions.forEach(subscription => { | ||
| if (data.channels.some(channel => subscription.channels.includes(channel))) { | ||
| setTimeout(() => subscription.callback(data)); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| break; | ||
| case 'pong': | ||
|
|
@@ -505,31 +602,6 @@ class Client { | |
| } catch (e) { | ||
| console.error(e); | ||
| } | ||
| }, | ||
| cleanUp: (channels, queries) => { | ||
| this.realtime.channels.forEach(channel => { | ||
| if (channels.includes(channel)) { | ||
| let found = Array.from(this.realtime.subscriptions).some(([_key, subscription] )=> { | ||
| return subscription.channels.includes(channel); | ||
| }) | ||
|
|
||
| if (!found) { | ||
| this.realtime.channels.delete(channel); | ||
| } | ||
| } | ||
| }) | ||
|
|
||
| this.realtime.queries.forEach(query => { | ||
| if (queries.includes(query)) { | ||
| let found = Array.from(this.realtime.subscriptions).some(([_key, subscription]) => { | ||
| return subscription.queries?.includes(query); | ||
| }) | ||
|
|
||
| if (!found) { | ||
| this.realtime.queries.delete(query); | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -564,10 +636,8 @@ class Client { | |
| queries: (string | Query)[] = [] | ||
| ): () => void { | ||
| let channelArray = typeof channels === 'string' ? [channels] : channels; | ||
| channelArray.forEach(channel => this.realtime.channels.add(channel)); | ||
|
|
||
| const queryStrings = (queries ?? []).map(q => typeof q === 'string' ? q : q.toString()); | ||
| queryStrings.forEach(query => this.realtime.queries.add(query)); | ||
|
|
||
| const counter = this.realtime.subscriptionsCounter++; | ||
| this.realtime.subscriptions.set(counter, { | ||
|
|
@@ -579,8 +649,12 @@ class Client { | |
| this.realtime.connect(); | ||
|
|
||
| return () => { | ||
| const subscriptionId = this.realtime.slotToSubscriptionId.get(counter); | ||
| this.realtime.subscriptions.delete(counter); | ||
| this.realtime.cleanUp(channelArray, queryStrings); | ||
| this.realtime.slotToSubscriptionId.delete(counter); | ||
| if (subscriptionId) { | ||
| this.realtime.subscriptionIdToSlot.delete(subscriptionId); | ||
| } | ||
| this.realtime.connect(); | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.