You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Beacon event types from MSC3489 (#2230)
* ASSET_NODE_TYPE -> M_ASSET Signed-off-by: Kerry Archibald <kerrya@element.io> * export const M_TIMESTAMP = new UnstableValue("m.ts", "org.matrix.msc3488.ts"); Signed-off-by: Kerry Archibald <kerrya@element.io> * LOCATION_EVENT_TYPE -> M_LOCATION Signed-off-by: Kerry Archibald <kerrya@element.io> * extensible event types for location Signed-off-by: Kerry Archibald <kerrya@element.io> * add locationevent parsing helpers Signed-off-by: Kerry Archibald <kerrya@element.io> * rename Signed-off-by: Kerry Archibald <kerrya@element.io> * comment Signed-off-by: Kerry Archibald <kerrya@element.io> * revert makelocationcontent signature Signed-off-by: Kerry Archibald <kerrya@element.io> * add beacon event types Signed-off-by: Kerry Archibald <kerrya@element.io> * add variable* to type and comment Signed-off-by: Kerry Archibald <kerrya@element.io> * add content helper functions for beacon_info and beacon Signed-off-by: Kerry Archibald <kerrya@element.io> * copyright Signed-off-by: Kerry Archibald <kerrya@element.io> * add m.beacon_info.live from msc3672 Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
115
spec/unit/content-helpers.spec.ts
Normal file
115
spec/unit/content-helpers.spec.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { REFERENCE_RELATION } from "matrix-events-sdk";
|
||||
|
||||
import { M_BEACON_INFO } from "../../src/@types/beacon";
|
||||
import { LocationAssetType, M_ASSET, M_LOCATION, M_TIMESTAMP } from "../../src/@types/location";
|
||||
import { makeBeaconContent, makeBeaconInfoContent } from "../../src/content-helpers";
|
||||
|
||||
describe('Beacon content helpers', () => {
|
||||
describe('makeBeaconInfoContent()', () => {
|
||||
const mockDateNow = 123456789;
|
||||
beforeEach(() => {
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(mockDateNow);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Date, 'now').mockRestore();
|
||||
});
|
||||
it('create fully defined event content', () => {
|
||||
expect(makeBeaconInfoContent(
|
||||
1234,
|
||||
true,
|
||||
'nice beacon_info',
|
||||
LocationAssetType.Pin,
|
||||
)).toEqual({
|
||||
[M_BEACON_INFO.name]: {
|
||||
description: 'nice beacon_info',
|
||||
timeout: 1234,
|
||||
live: true,
|
||||
},
|
||||
[M_TIMESTAMP.name]: mockDateNow,
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Pin,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('defaults timestamp to current time', () => {
|
||||
expect(makeBeaconInfoContent(
|
||||
1234,
|
||||
true,
|
||||
'nice beacon_info',
|
||||
LocationAssetType.Pin,
|
||||
)).toEqual(expect.objectContaining({
|
||||
[M_TIMESTAMP.name]: mockDateNow,
|
||||
}));
|
||||
});
|
||||
|
||||
it('defaults asset type to self when not set', () => {
|
||||
expect(makeBeaconInfoContent(
|
||||
1234,
|
||||
true,
|
||||
'nice beacon_info',
|
||||
// no assetType passed
|
||||
)).toEqual(expect.objectContaining({
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Self,
|
||||
},
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeBeaconContent()', () => {
|
||||
it('creates event content without description', () => {
|
||||
expect(makeBeaconContent(
|
||||
'geo:foo',
|
||||
123,
|
||||
'$1234',
|
||||
// no description
|
||||
)).toEqual({
|
||||
[M_LOCATION.name]: {
|
||||
description: undefined,
|
||||
uri: 'geo:foo',
|
||||
},
|
||||
[M_TIMESTAMP.name]: 123,
|
||||
"m.relates_to": {
|
||||
rel_type: REFERENCE_RELATION.name,
|
||||
event_id: '$1234',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('creates event content with description', () => {
|
||||
expect(makeBeaconContent(
|
||||
'geo:foo',
|
||||
123,
|
||||
'$1234',
|
||||
'test description',
|
||||
)).toEqual({
|
||||
[M_LOCATION.name]: {
|
||||
description: 'test description',
|
||||
uri: 'geo:foo',
|
||||
},
|
||||
[M_TIMESTAMP.name]: 123,
|
||||
"m.relates_to": {
|
||||
rel_type: REFERENCE_RELATION.name,
|
||||
event_id: '$1234',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
144
src/@types/beacon.ts
Normal file
144
src/@types/beacon.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EitherAnd, RELATES_TO_RELATIONSHIP, REFERENCE_RELATION } from "matrix-events-sdk";
|
||||
|
||||
import { UnstableValue } from "../NamespacedValue";
|
||||
import { MAssetEvent, MLocationEvent, MTimestampEvent } from "./location";
|
||||
|
||||
/**
|
||||
* Beacon info and beacon event types as described in MSC3489
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3489
|
||||
*/
|
||||
|
||||
/**
|
||||
* Beacon info events are state events.
|
||||
* We have two requirements for these events:
|
||||
* 1. they can only be written by their owner
|
||||
* 2. a user can have an arbitrary number of beacon_info events
|
||||
*
|
||||
* 1. is achieved by setting the state_key to the owners mxid.
|
||||
* Event keys in room state are a combination of `type` + `state_key`.
|
||||
* To achieve an arbitrary number of only owner-writable state events
|
||||
* we introduce a variable suffix to the event type
|
||||
*
|
||||
* Eg
|
||||
* {
|
||||
* "type": "m.beacon_info.@matthew:matrix.org.1",
|
||||
* "state_key": "@matthew:matrix.org",
|
||||
* "content": {
|
||||
* "m.beacon_info": {
|
||||
* "description": "The Matthew Tracker",
|
||||
* "timeout": 86400000,
|
||||
* },
|
||||
* // more content as described below
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* "type": "m.beacon_info.@matthew:matrix.org.2",
|
||||
* "state_key": "@matthew:matrix.org",
|
||||
* "content": {
|
||||
* "m.beacon_info": {
|
||||
* "description": "Another different Matthew tracker",
|
||||
* "timeout": 400000,
|
||||
* },
|
||||
* // more content as described below
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Variable event type for m.beacon_info
|
||||
*/
|
||||
export const M_BEACON_INFO_VARIABLE = new UnstableValue("m.beacon_info.*", "org.matrix.msc3489.beacon_info.*");
|
||||
|
||||
/**
|
||||
* Non-variable type for m.beacon_info event content
|
||||
*/
|
||||
export const M_BEACON_INFO = new UnstableValue("m.beacon_info", "org.matrix.msc3489.beacon_info");
|
||||
export const M_BEACON = new UnstableValue("m.beacon", "org.matrix.msc3489.beacon");
|
||||
|
||||
export type MBeaconInfoContent = {
|
||||
description?: string;
|
||||
// how long from the last event until we consider the beacon inactive in milliseconds
|
||||
timeout: number;
|
||||
// true when this is a live location beacon
|
||||
// https://github.com/matrix-org/matrix-spec-proposals/pull/3672
|
||||
live?: boolean;
|
||||
};
|
||||
|
||||
export type MBeaconInfoEvent = EitherAnd<
|
||||
{ [M_BEACON_INFO.name]: MBeaconInfoContent },
|
||||
{ [M_BEACON_INFO.altName]: MBeaconInfoContent }
|
||||
>;
|
||||
|
||||
/**
|
||||
* m.beacon_info Event example from the spec
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3489
|
||||
* {
|
||||
"type": "m.beacon_info.@matthew:matrix.org.1",
|
||||
"state_key": "@matthew:matrix.org",
|
||||
"content": {
|
||||
"m.beacon_info": {
|
||||
"description": "The Matthew Tracker", // same as an `m.location` description
|
||||
"timeout": 86400000, // how long from the last event until we consider the beacon inactive in milliseconds
|
||||
},
|
||||
"m.ts": 1436829458432, // creation timestamp of the beacon on the client
|
||||
"m.asset": {
|
||||
"type": "m.self" // the type of asset being tracked as per MSC3488
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* m.beacon_info.* event content
|
||||
*/
|
||||
export type MBeaconInfoEventContent = &
|
||||
MBeaconInfoEvent &
|
||||
// creation timestamp of the beacon on the client
|
||||
MTimestampEvent &
|
||||
// the type of asset being tracked as per MSC3488
|
||||
MAssetEvent;
|
||||
|
||||
/**
|
||||
* m.beacon event example
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3489
|
||||
*
|
||||
* {
|
||||
"type": "m.beacon",
|
||||
"sender": "@matthew:matrix.org",
|
||||
"content": {
|
||||
"m.relates_to": { // from MSC2674: https://github.com/matrix-org/matrix-doc/pull/2674
|
||||
"rel_type": "m.reference", // from MSC3267: https://github.com/matrix-org/matrix-doc/pull/3267
|
||||
"event_id": "$beacon_info"
|
||||
},
|
||||
"m.location": {
|
||||
"uri": "geo:51.5008,0.1247;u=35",
|
||||
"description": "Arbitrary beacon information"
|
||||
},
|
||||
"m.ts": 1636829458432,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
export type MBeaconEventContent = &
|
||||
MLocationEvent &
|
||||
// timestamp when location was taken
|
||||
MTimestampEvent &
|
||||
// relates to a beacon_info event
|
||||
RELATES_TO_RELATIONSHIP<typeof REFERENCE_RELATION>;
|
||||
|
@@ -16,6 +16,9 @@ limitations under the License.
|
||||
|
||||
/** @module ContentHelpers */
|
||||
|
||||
import { REFERENCE_RELATION } from "matrix-events-sdk";
|
||||
|
||||
import { MBeaconEventContent, MBeaconInfoEventContent, M_BEACON_INFO } from "./@types/beacon";
|
||||
import { MsgType } from "./@types/event";
|
||||
import { TEXT_NODE_TYPE } from "./@types/extensible_events";
|
||||
import {
|
||||
@@ -186,3 +189,41 @@ export const parseLocationEvent = (wireEventContent: LocationEventWireContent):
|
||||
|
||||
return makeLocationContent(fallbackText, geoUri, timestamp, description, assetType);
|
||||
};
|
||||
|
||||
/**
|
||||
* Beacon event helpers
|
||||
*/
|
||||
|
||||
export const makeBeaconInfoContent = (
|
||||
timeout: number,
|
||||
isLive?: boolean,
|
||||
description?: string,
|
||||
assetType?: LocationAssetType,
|
||||
): MBeaconInfoEventContent => ({
|
||||
[M_BEACON_INFO.name]: {
|
||||
description,
|
||||
timeout,
|
||||
live: isLive,
|
||||
},
|
||||
[M_TIMESTAMP.name]: Date.now(),
|
||||
[M_ASSET.name]: {
|
||||
type: assetType ?? LocationAssetType.Self,
|
||||
},
|
||||
});
|
||||
|
||||
export const makeBeaconContent = (
|
||||
uri: string,
|
||||
timestamp: number,
|
||||
beaconInfoId: string,
|
||||
description?: string,
|
||||
): MBeaconEventContent => ({
|
||||
[M_LOCATION.name]: {
|
||||
description,
|
||||
uri,
|
||||
},
|
||||
[M_TIMESTAMP.name]: timestamp,
|
||||
"m.relates_to": {
|
||||
rel_type: REFERENCE_RELATION.name,
|
||||
event_id: beaconInfoId,
|
||||
},
|
||||
});
|
||||
|
Reference in New Issue
Block a user