Skip to content

Commit 5243222

Browse files
author
Kerry
authored
add upsert function for updating beacon events (#2247)
* add upsert function for updating beacon events Signed-off-by: Kerry Archibald <[email protected]> * expose event type on beacon model Signed-off-by: Kerry Archibald <[email protected]> * allow setting timestamp in beaconinfo content helper Signed-off-by: Kerry Archibald <[email protected]> * expose parsed beacon info Signed-off-by: Kerry Archibald <[email protected]>
1 parent 905a884 commit 5243222

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

spec/unit/content-helpers.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ describe('Beacon content helpers', () => {
5959
}));
6060
});
6161

62+
it('uses timestamp when provided', () => {
63+
expect(makeBeaconInfoContent(
64+
1234,
65+
true,
66+
'nice beacon_info',
67+
LocationAssetType.Pin,
68+
99999,
69+
)).toEqual(expect.objectContaining({
70+
[M_TIMESTAMP.name]: 99999,
71+
}));
72+
});
73+
6274
it('defaults asset type to self when not set', () => {
6375
expect(makeBeaconInfoContent(
6476
1234,

spec/unit/matrix-client.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { MEGOLM_ALGORITHM } from "../../src/crypto/olmlib";
1414
import { EventStatus, MatrixEvent } from "../../src/models/event";
1515
import { Preset } from "../../src/@types/partials";
1616
import * as testUtils from "../test-utils/test-utils";
17+
import { makeBeaconInfoContent } from "../../src/content-helpers";
18+
import { M_BEACON_INFO } from "../../src/@types/beacon";
1719

1820
jest.useFakeTimers();
1921

@@ -969,4 +971,43 @@ describe("MatrixClient", function() {
969971
client.supportsExperimentalThreads = supportsExperimentalThreads;
970972
});
971973
});
974+
975+
describe("beacons", () => {
976+
const roomId = '!room:server.org';
977+
const content = makeBeaconInfoContent(100, true);
978+
979+
beforeEach(() => {
980+
client.http.authedRequest.mockClear().mockResolvedValue({});
981+
});
982+
983+
it("creates new beacon info", async () => {
984+
await client.unstable_createLiveBeacon(roomId, content, '123');
985+
986+
// event type combined
987+
const expectedEventType = `${M_BEACON_INFO.name}.${userId}.123`;
988+
const [callback, method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0];
989+
expect(callback).toBeFalsy();
990+
expect(method).toBe('PUT');
991+
expect(path).toEqual(
992+
`/rooms/${encodeURIComponent(roomId)}/state/` +
993+
`${encodeURIComponent(expectedEventType)}/${encodeURIComponent(userId)}`,
994+
);
995+
expect(queryParams).toBeFalsy();
996+
expect(requestContent).toEqual(content);
997+
});
998+
999+
it("updates beacon info with specific event type", async () => {
1000+
const eventType = `${M_BEACON_INFO.name}.${userId}.456`;
1001+
1002+
await client.unstable_setLiveBeacon(roomId, eventType, content);
1003+
1004+
// event type combined
1005+
const [, , path, , requestContent] = client.http.authedRequest.mock.calls[0];
1006+
expect(path).toEqual(
1007+
`/rooms/${encodeURIComponent(roomId)}/state/` +
1008+
`${encodeURIComponent(eventType)}/${encodeURIComponent(userId)}`,
1009+
);
1010+
expect(requestContent).toEqual(content);
1011+
});
1012+
});
9721013
});

spec/unit/models/beacon.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ describe('Beacon', () => {
122122
expect(beacon.roomId).toEqual(roomId);
123123
expect(beacon.isLive).toEqual(true);
124124
expect(beacon.beaconInfoOwner).toEqual(userId);
125+
expect(beacon.beaconInfoEventType).toEqual(liveBeaconEvent.getType());
125126
});
126127

127128
describe('isLive()', () => {

src/client.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3686,14 +3686,32 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
36863686
* @returns {ISendEventResponse}
36873687
*/
36883688
// eslint-disable-next-line @typescript-eslint/naming-convention
3689-
unstable_createLiveBeacon(
3689+
public async unstable_createLiveBeacon(
36903690
roomId: Room["roomId"],
36913691
beaconInfoContent: MBeaconInfoEventContent,
36923692
eventTypeSuffix: string,
36933693
) {
36943694
const userId = this.getUserId();
36953695
const eventType = M_BEACON_INFO_VARIABLE.name.replace('*', `${userId}.${eventTypeSuffix}`);
3696-
return this.sendStateEvent(roomId, eventType, beaconInfoContent, userId);
3696+
return this.unstable_setLiveBeacon(roomId, eventType, beaconInfoContent);
3697+
}
3698+
3699+
/**
3700+
* Upsert a live beacon event
3701+
* using a specific m.beacon_info.* event variable type
3702+
* @param {string} roomId string
3703+
* @param {string} beaconInfoEventType event type including variable suffix
3704+
* @param {MBeaconInfoEventContent} beaconInfoContent
3705+
* @returns {ISendEventResponse}
3706+
*/
3707+
// eslint-disable-next-line @typescript-eslint/naming-convention
3708+
public async unstable_setLiveBeacon(
3709+
roomId: string,
3710+
beaconInfoEventType: string,
3711+
beaconInfoContent: MBeaconInfoEventContent,
3712+
) {
3713+
const userId = this.getUserId();
3714+
return this.sendStateEvent(roomId, beaconInfoEventType, beaconInfoContent, userId);
36973715
}
36983716

36993717
/**

src/content-helpers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,20 +198,22 @@ export type MakeBeaconInfoContent = (
198198
isLive?: boolean,
199199
description?: string,
200200
assetType?: LocationAssetType,
201+
timestamp?: number
201202
) => MBeaconInfoEventContent;
202203

203204
export const makeBeaconInfoContent: MakeBeaconInfoContent = (
204205
timeout,
205206
isLive,
206207
description,
207208
assetType,
209+
timestamp,
208210
) => ({
209211
[M_BEACON_INFO.name]: {
210212
description,
211213
timeout,
212214
live: isLive,
213215
},
214-
[M_TIMESTAMP.name]: Date.now(),
216+
[M_TIMESTAMP.name]: timestamp || Date.now(),
215217
[M_ASSET.name]: {
216218
type: assetType ?? LocationAssetType.Self,
217219
},

src/models/beacon.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const isBeaconInfoEventType = (type: string) =>
4444
// https://github.com/matrix-org/matrix-spec-proposals/pull/3489
4545
export class Beacon extends TypedEventEmitter<BeaconEvent, BeaconEventHandlerMap> {
4646
public readonly roomId: string;
47-
private beaconInfo: BeaconInfoState;
47+
private _beaconInfo: BeaconInfoState;
4848
private _isLive: boolean;
4949
private livenessWatchInterval: number;
5050

@@ -69,6 +69,14 @@ export class Beacon extends TypedEventEmitter<BeaconEvent, BeaconEventHandlerMap
6969
return this.rootEvent.getStateKey();
7070
}
7171

72+
public get beaconInfoEventType(): string {
73+
return this.rootEvent.getType();
74+
}
75+
76+
public get beaconInfo(): BeaconInfoState {
77+
return this._beaconInfo;
78+
}
79+
7280
public update(beaconInfoEvent: MatrixEvent): void {
7381
if (beaconInfoEvent.getId() !== this.beaconInfoId) {
7482
throw new Error('Invalid updating event');
@@ -95,22 +103,22 @@ export class Beacon extends TypedEventEmitter<BeaconEvent, BeaconEventHandlerMap
95103
}
96104

97105
if (this.isLive) {
98-
const expiryInMs = (this.beaconInfo?.timestamp + this.beaconInfo?.timeout + 1) - Date.now();
106+
const expiryInMs = (this._beaconInfo?.timestamp + this._beaconInfo?.timeout + 1) - Date.now();
99107
if (expiryInMs > 1) {
100108
this.livenessWatchInterval = setInterval(this.checkLiveness.bind(this), expiryInMs);
101109
}
102110
}
103111
}
104112

105113
private setBeaconInfo(event: MatrixEvent): void {
106-
this.beaconInfo = parseBeaconInfoContent(event.getContent());
114+
this._beaconInfo = parseBeaconInfoContent(event.getContent());
107115
this.checkLiveness();
108116
}
109117

110118
private checkLiveness(): void {
111119
const prevLiveness = this.isLive;
112-
this._isLive = this.beaconInfo?.live &&
113-
isTimestampInDuration(this.beaconInfo?.timestamp, this.beaconInfo?.timeout, Date.now());
120+
this._isLive = this._beaconInfo?.live &&
121+
isTimestampInDuration(this._beaconInfo?.timestamp, this._beaconInfo?.timeout, Date.now());
114122

115123
if (prevLiveness !== this.isLive) {
116124
this.emit(BeaconEvent.LivenessChange, this.isLive, this);

0 commit comments

Comments
 (0)