Skip to content

Commit

Permalink
Live location sharing - monitor liveness of beacons yet to start (PSF…
Browse files Browse the repository at this point in the history
…-1081) (#2437)

* monitor liveness of beacons yet to start

* make watch interval a timeout instead
  • Loading branch information
Kerry committed Jun 7, 2022
1 parent 96c35e2 commit 2982bd7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 10 deletions.
44 changes: 40 additions & 4 deletions spec/unit/models/beacon.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('Beacon', () => {

const advanceDateAndTime = (ms: number) => {
// bc liveness check uses Date.now we have to advance this mock
jest.spyOn(global.Date, 'now').mockReturnValue(now + ms);
jest.spyOn(global.Date, 'now').mockReturnValue(Date.now() + ms);
// then advance time for the interval by the same amount
jest.advanceTimersByTime(ms);
};
Expand Down Expand Up @@ -224,13 +224,49 @@ describe('Beacon', () => {
beacon.monitorLiveness();

// @ts-ignore
expect(beacon.livenessWatchInterval).toBeFalsy();
expect(beacon.livenessWatchTimeout).toBeFalsy();
advanceDateAndTime(HOUR_MS * 2 + 1);

// no emit
expect(emitSpy).not.toHaveBeenCalled();
});

it('checks liveness of beacon at expected start time', () => {
// go forward in time to make beacon with timestamp in future
jest.spyOn(global.Date, 'now').mockReturnValue(now + HOUR_MS);
const futureBeaconEvent = makeBeaconInfoEvent(
userId,
roomId,
{
timeout: HOUR_MS * 3,
isLive: true,
},
'$live123',
);
// go back to now
jest.spyOn(global.Date, 'now').mockReturnValue(now);

const beacon = new Beacon(futureBeaconEvent);
expect(beacon.isLive).toBeFalsy();
const emitSpy = jest.spyOn(beacon, 'emit');

beacon.monitorLiveness();

// advance to the start timestamp of the beacon
advanceDateAndTime(HOUR_MS + 1);

// beacon is in live period now
expect(emitSpy).toHaveBeenCalledTimes(1);
expect(emitSpy).toHaveBeenCalledWith(BeaconEvent.LivenessChange, true, beacon);

// check the expiry monitor is still setup ok
// advance to the expiry
advanceDateAndTime(HOUR_MS * 3 + 100);

expect(emitSpy).toHaveBeenCalledTimes(2);
expect(emitSpy).toHaveBeenCalledWith(BeaconEvent.LivenessChange, false, beacon);
});

it('checks liveness of beacon at expected expiry time', () => {
// live beacon was created an hour ago
// and has a 3hr duration
Expand All @@ -253,12 +289,12 @@ describe('Beacon', () => {

beacon.monitorLiveness();
// @ts-ignore
const oldMonitor = beacon.livenessWatchInterval;
const oldMonitor = beacon.livenessWatchTimeout;

beacon.monitorLiveness();

// @ts-ignore
expect(beacon.livenessWatchInterval).not.toEqual(oldMonitor);
expect(beacon.livenessWatchTimeout).not.toEqual(oldMonitor);
});

it('destroy kills liveness monitor and emits', () => {
Expand Down
19 changes: 13 additions & 6 deletions src/models/beacon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
public readonly roomId: string;
private _beaconInfo: BeaconInfoState;
private _isLive: boolean;
private livenessWatchInterval: ReturnType<typeof setInterval>;
private livenessWatchTimeout: ReturnType<typeof setTimeout>;
private _latestLocationState: BeaconLocationState | undefined;

constructor(
Expand Down Expand Up @@ -109,8 +109,8 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
}

public destroy(): void {
if (this.livenessWatchInterval) {
clearInterval(this.livenessWatchInterval);
if (this.livenessWatchTimeout) {
clearTimeout(this.livenessWatchTimeout);
}

this._isLive = false;
Expand All @@ -122,19 +122,26 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
* Emits BeaconEvent.LivenessChange when beacon expires
*/
public monitorLiveness(): void {
if (this.livenessWatchInterval) {
clearInterval(this.livenessWatchInterval);
if (this.livenessWatchTimeout) {
clearTimeout(this.livenessWatchTimeout);
}

this.checkLiveness();
if (this.isLive) {
const expiryInMs = (this._beaconInfo?.timestamp + this._beaconInfo?.timeout) - Date.now();
if (expiryInMs > 1) {
this.livenessWatchInterval = setInterval(
this.livenessWatchTimeout = setTimeout(
() => { this.monitorLiveness(); },
expiryInMs,
);
}
} else if (this._beaconInfo?.timestamp > Date.now()) {
// beacon start timestamp is in the future
// check liveness again then
this.livenessWatchTimeout = setTimeout(
() => { this.monitorLiveness(); },
this.beaconInfo?.timestamp - Date.now(),
);
}
}

Expand Down

0 comments on commit 2982bd7

Please sign in to comment.