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 */
|
/** @module ContentHelpers */
|
||||||
|
|
||||||
|
import { REFERENCE_RELATION } from "matrix-events-sdk";
|
||||||
|
|
||||||
|
import { MBeaconEventContent, MBeaconInfoEventContent, M_BEACON_INFO } from "./@types/beacon";
|
||||||
import { MsgType } from "./@types/event";
|
import { MsgType } from "./@types/event";
|
||||||
import { TEXT_NODE_TYPE } from "./@types/extensible_events";
|
import { TEXT_NODE_TYPE } from "./@types/extensible_events";
|
||||||
import {
|
import {
|
||||||
@@ -186,3 +189,41 @@ export const parseLocationEvent = (wireEventContent: LocationEventWireContent):
|
|||||||
|
|
||||||
return makeLocationContent(fallbackText, geoUri, timestamp, description, assetType);
|
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