Skip to content

Commit 36d56e1

Browse files
Validate messages instead (check deleted)
1 parent c2a4185 commit 36d56e1

File tree

2 files changed

+63
-45
lines changed

2 files changed

+63
-45
lines changed

src/client.ts

+18
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,24 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
25522552
return messageId;
25532553
}
25542554

2555+
public updateLiveLocation(
2556+
message: MessageResponse<StreamChatGenerics>,
2557+
{ latitude, longitude }: { latitude: number; longitude: number },
2558+
) {
2559+
const [attachment] = message.attachments ?? [];
2560+
2561+
if (!attachment || attachment.type !== 'live_location') {
2562+
throw new Error(
2563+
'Supplied message either has no attachments to update or attachment is not of type "live_location"',
2564+
);
2565+
}
2566+
2567+
return this.partialUpdateMessage(message.id, {
2568+
// @ts-expect-error valid update
2569+
set: { attachments: [{ ...attachment, latitude, longitude }] },
2570+
});
2571+
}
2572+
25552573
/**
25562574
* pinMessage - pins the message
25572575
* @param {string | { id: string }} messageOrMessageId message object or message id

src/live_location_manager.ts

+45-45
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99

1010
import { withCancellation } from './concurrency';
1111
import { StateStore } from './store';
12-
import type { MessageResponse, Attachment, EventTypes, ExtendableGenerics } from './types';
12+
import type { MessageResponse, Attachment, EventTypes, ExtendableGenerics, UpdateMessageAPIResponse } from './types';
1313
import type { StreamChat } from './client';
1414
import type { Unsubscribe } from './store';
1515

1616
// type Unsubscribe = () => void;
1717
type WatchLocation = (handler: (value: { latitude: number; longitude: number }) => void) => Unsubscribe;
18-
type SerializeAndStore = (state: MessageResponse[], userId: string) => void;
19-
type RetrieveAndDeserialize = (userId: string) => MessageResponse[];
18+
type SerializeAndStore<SCG extends ExtendableGenerics> = (state: MessageResponse<SCG>[], userId: string) => void;
19+
type RetrieveAndDeserialize<SCG extends ExtendableGenerics> = (userId: string) => MessageResponse<SCG>[];
2020

21-
export type LiveLocationManagerState = {
21+
export type LiveLocationManagerState<SCG extends ExtendableGenerics> = {
2222
ready: boolean;
23-
targetMessages: MessageResponse[];
23+
targetMessages: MessageResponse<SCG>[];
2424
};
2525

2626
// if (message.cid && this.messagesByChannelConfId[message.cid]) {
@@ -87,39 +87,55 @@ export type LiveLocationManagerState = {
8787
// }
8888

8989
function isValidLiveLocationAttachment(attachment?: Attachment) {
90-
if (!attachment || typeof attachment.end_time !== 'string' || attachment.stopped_sharing) return false;
90+
if (!attachment || attachment.type !== 'live_location' || attachment.stopped_sharing) {
91+
return false;
92+
}
93+
94+
// If end_time has been defined, consider it
95+
if (typeof attachment.end_time === 'string') {
96+
const endTimeTimestamp = new Date(attachment.end_time).getTime();
9197

92-
const endTimeTimestamp = new Date(attachment.end_time).getTime();
98+
if (Number.isNaN(endTimeTimestamp)) return false;
9399

94-
if (Number.isNaN(endTimeTimestamp)) return false;
100+
const nowTimestamp = Date.now();
95101

96-
const nowTimestamp = Date.now();
102+
return nowTimestamp < endTimeTimestamp;
103+
}
97104

98-
return attachment && attachment.type === 'live_location' && endTimeTimestamp > nowTimestamp;
105+
return true;
106+
}
107+
108+
function isValidLiveLocationMessage(message?: MessageResponse) {
109+
if (!message || message.type === 'deleted') return false;
110+
111+
const [attachment] = message.attachments ?? [];
112+
113+
return isValidLiveLocationAttachment(attachment);
99114
}
100115

101116
export type LiveLocationManagerConstructorParameters<SCG extends ExtendableGenerics> = {
102117
client: StreamChat<SCG>;
103118
watchLocation: WatchLocation;
104-
retrieveAndDeserialize?: RetrieveAndDeserialize;
105-
serializeAndStore?: SerializeAndStore;
119+
retrieveAndDeserialize?: RetrieveAndDeserialize<SCG>;
120+
serializeAndStore?: SerializeAndStore<SCG>;
106121
};
107122

108-
const MIN_THROTTLE_TIMEOUT = 1000;
123+
// Hard-coded minimal throttle timeout
124+
const MIN_THROTTLE_TIMEOUT = 3000;
109125

110126
export class LiveLocationManager<SCG extends ExtendableGenerics> {
111-
public state: StateStore<LiveLocationManagerState>;
127+
public state: StateStore<LiveLocationManagerState<SCG>>;
112128
private client: StreamChat<SCG>;
113129
private unsubscribeFunctions: Set<() => void> = new Set();
114-
private serializeAndStore: SerializeAndStore;
130+
private serializeAndStore: SerializeAndStore<SCG>;
115131
private watchLocation: WatchLocation;
116132
private messagesByChannelConfIdGetterCache: {
117133
calculated: { [key: string]: [MessageResponse, number] };
118-
targetMessages: LiveLocationManagerState['targetMessages'];
134+
targetMessages: LiveLocationManagerState<SCG>['targetMessages'];
119135
};
120136
private messagesByIdGetterCache: {
121137
calculated: { [key: string]: [MessageResponse, number] };
122-
targetMessages: LiveLocationManagerState['targetMessages'];
138+
targetMessages: LiveLocationManagerState<SCG>['targetMessages'];
123139
};
124140

125141
static symbol = Symbol(LiveLocationManager.name);
@@ -144,7 +160,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
144160

145161
const retreivedTargetMessages = retrieveAndDeserialize(client.userID!);
146162

147-
this.state = new StateStore<LiveLocationManagerState>({
163+
this.state = new StateStore<LiveLocationManagerState<SCG>>({
148164
targetMessages: retreivedTargetMessages,
149165
// If there are no messages to validate, the manager is considered "ready"
150166
ready: retreivedTargetMessages.length === 0,
@@ -204,7 +220,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
204220
let unsubscribeWatchLocation: null | (() => void) = null;
205221

206222
// Subscribe to location updates only if there are relevant messages to
207-
// update, no need for the location watcher to active/instantiated otherwise
223+
// update, no need for the location watcher to be active/instantiated otherwise
208224
const unsubscribe = this.state.subscribeWithSelector(
209225
({ targetMessages }) => ({ targetMessages }),
210226
({ targetMessages }) => {
@@ -239,39 +255,29 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
239255
nextWatcherCallTimestamp = Date.now() + MIN_THROTTLE_TIMEOUT;
240256

241257
withCancellation(LiveLocationManager.symbol, async () => {
242-
const promises: Promise<void>[] = [];
258+
const promises: Promise<UpdateMessageAPIResponse<SCG>>[] = [];
243259
const { ready } = this.state.getLatestValue();
244260

245261
if (!ready) {
246262
await this.recoverAndValidateMessages();
247263
}
248264

249265
const { targetMessages } = this.state.getLatestValue();
250-
// if validator removes messages, we need to check
266+
// If validator removes messages, we need to check
251267
if (!targetMessages.length) return;
252268

253269
for (const message of targetMessages) {
254-
const [attachment] = message.attachments ?? [];
255-
256-
if (!isValidLiveLocationAttachment(attachment)) {
270+
if (!isValidLiveLocationMessage(message)) {
257271
this.unregisterMessage(message);
258272
continue;
259273
}
260274

261-
// TODO: client.updateLiveLocation instead
262-
const promise = this.client
263-
.partialUpdateMessage(message.id, {
264-
// @ts-expect-error valid update
265-
set: { attachments: [{ ...attachment, latitude, longitude }] },
266-
})
267-
// TODO: change this this
268-
.then((v) => console.log(v));
275+
const promise = this.client.updateLiveLocation(message, { latitude, longitude });
269276

270277
promises.push(promise);
271278
}
272279

273-
const values = await Promise.allSettled(promises);
274-
console.log(values);
280+
await Promise.allSettled(promises);
275281
// TODO: handle values (remove failed - based on specific error code), keep re-trying others
276282
});
277283
});
@@ -298,29 +304,25 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
298304
for (const result of response.results) {
299305
const { message } = result;
300306

301-
const [attachment] = message.attachments ?? [];
302-
303-
if (isValidLiveLocationAttachment(attachment)) {
307+
if (isValidLiveLocationMessage(message)) {
304308
newTargetMessages.push(message);
305309
}
306310
}
307311

308312
this.state.partialNext({ ready: true, targetMessages: newTargetMessages });
309313
}
310314

311-
private registerMessage(message: MessageResponse) {
315+
private registerMessage(message: MessageResponse<SCG>) {
312316
if (!this.client.userID || message?.user?.id !== this.client.userID) return;
313317

314-
const [attachment] = message.attachments ?? [];
315-
316-
if (!isValidLiveLocationAttachment(attachment)) {
318+
if (!isValidLiveLocationMessage(message)) {
317319
return;
318320
}
319321

320322
this.state.next((currentValue) => ({ ...currentValue, targetMessages: [...currentValue.targetMessages, message] }));
321323
}
322324

323-
private updateRegisteredMessage(message: MessageResponse) {
325+
private updateRegisteredMessage(message: MessageResponse<SCG>) {
324326
if (!this.client.userID || message?.user?.id !== this.client.userID) return;
325327

326328
const [, targetMessageIndex] = this.messagesById[message.id];
@@ -381,9 +383,7 @@ export class LiveLocationManager<SCG extends ExtendableGenerics> {
381383

382384
if (!localMessage) return;
383385

384-
const [attachment] = event.message.attachments ?? [];
385-
386-
if (!isValidLiveLocationAttachment(attachment)) {
386+
if (!isValidLiveLocationMessage(event.message)) {
387387
this.unregisterMessage(event.message);
388388
} else {
389389
this.updateRegisteredMessage(event.message);

0 commit comments

Comments
 (0)