Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asset class separate from Subscriber #114

Merged
merged 4 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 42 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,56 +42,68 @@ yarn add @ably/asset-tracking

## Usage

Here is an example of how the SDK can be used:
### Subscribing to location updates

```ts
import { Subscriber, Accuracy } from '@ably/asset-tracking';
import { Subscriber } from '@ably/asset-tracking';

// Client options passed to the underling ably-js instance.
// You must provide some way for the client to authenticate with Ably.
// In this example we're using basic authentication which means we must also provide a clientId.
// See: https://ably.com/docs/core-features/authentication
const ablyOptions = {
key: ABLY_API_KEY,
clientId: CLIENT_ID,
};

// Create a Subscriber instance.
const subscriber = new Subscriber({
ablyOptions,
});

// Get an asset.
const asset = subscriber.get('my_tracking_id');

// Define a callback to be notified when a location update is recieved.
const onLocationUpdate = (locationUpdate) => {
asset.addLocationListener((locationUpdate) => {
console.log(`Location update recieved. Coordinates: ${locationUpdate.location.geometry.coordinates}`);
};
});

// Start tracking the asset. This will attach to the Ably realtime channel and enter presence.
await asset.start(trackingId);

// Stop tracking the asset, at some point later on when you no longer need to receive location updates.
await asset.stop();
```

### Subscribing to driver status

// Define a callback to be notified when the asset online status is updated.
const onStatusUpdate = (isOnline) => {
```ts
// Register a callback to be notified when the asset online status is updated.
asset.addStatusListener((isOnline) => {
console.log(`Status update: Publisher is now ${isOnline ? 'online' : 'offline'}`);
};
});
```

// Request a specific resolution to be considered by the publisher.
### Requesting publisher resolution
```ts
import { Accuracy } from '@ably/asset-tracking';

// You can request a specific resolution to be considered by the publisher when you create an asset instance...
const resolution = {
accuracy: Accuracy.High,
desiredInterval: 1000,
minimumDisplacement: 1,
};

// Initialise the subscriber.
const subscriber = new Subscriber({
ablyOptions,
onLocationUpdate,
onStatusUpdate,
});

const trackingId = '<some application defined asset tracking identifier>';
const asset = subscriber.get('my_tracking_id', resolution);

(async () => {
// Start tracking an asset using its tracking identifier.
await subscriber.start(trackingId);

// Request a new resolution to be considered by the publisher.
await subscriber.sendChangeRequest({
accuracy: Accuracy.Low,
desiredInterval: 3000,
minimumDisplacement: 5,
});

// Stop tracking the asset.
await subscriber.stop();
})();
// ...And you can send a request to change the resolution when the asset is already started
await asset.sendChangeRequest({
accuracy: Accuracy.Low,
desiredInterval: 3000,
minimumDisplacement: 5,
});
```

## Example App
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export class GoogleMapsMarker {
this.current = markerCoordinate;
this.lastCompassDirection = "N";
this.marker = new google.maps.Marker({ icon: "/driverN.png", map: map });
this.rawMarker = new google.maps.Marker({ icon: "/driverN.png", map: map, opacity: 0.3, visible: false });
this.rawMarker = new google.maps.Marker({ icon: "/driverN.png", map: map, opacity: 0.3, visible: false });
this.accuracyCircle = new google.maps.Circle({
strokeColor: "#FF0000",
strokeOpacity: 0.8,
Expand Down
42 changes: 24 additions & 18 deletions examples/subscribing-example-app/public/RiderConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,40 +38,46 @@ export class RiderConnection {

this.subscriber = new Subscriber({
ablyOptions: { authUrl: '/api/createTokenRequest' },
onLocationUpdate: (message) => {
this.processMessage(message);
},
onRawLocationUpdate: (message) => {
this.processMessage(message, true);
},
onStatusUpdate: (status) => {
this.statusUpdateCallback(status);
},
resolution: this.hiRes ? lowResolution : highResolution,
onLocationUpdateIntervalUpdate: (desiredInterval) => {
this.locationUpdateInterval = desiredInterval
},
});

createMapSpecificZoomListener((zoom) => {
this.zoomLevel = zoom;
if (zoom > zoomThreshold && !this.hiRes) {
this.hiRes = true;
this.subscriber.sendChangeRequest(highResolution);
this.asset?.sendChangeRequest?.(highResolution);
this.rider?.showAccuracyCircle();
} else if (zoom <= zoomThreshold && this.hiRes) {
this.rider?.hideAccuracyCircle();
this.hiRes = false;
this.subscriber.sendChangeRequest(lowResolution);
this.asset?.sendChangeRequest?.(lowResolution);
}
});
}

async connect(channelId) {
if (this.subscriber.assetConnection) {
await this.subscriber.stop();
if (this.asset) {
await this.asset.stop();
}

this.subscriber.start(channelId || 'ivan');
this.asset = this.subscriber.get(channelId || 'ivan', this.hiRes ? lowResolution : highResolution);

this.asset.addLocationListener((message) => {
this.processMessage(message);
});

this.asset.addRawLocationListener((message) => {
this.processMessage(message, true);
});

this.asset.addStatusListener((status) => {
this.statusUpdateCallback(status);
});

this.asset.addLocationUpdateIntervalListener((desiredInterval) => {
this.locationUpdateInterval = desiredInterval
});

await this.asset.start(channelId || 'ivan');
}

setRenderSkippedLocations(state) {
Expand Down
92 changes: 92 additions & 0 deletions src/lib/Asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {
LocationListener,
LocationUpdateIntervalListener,
Resolution,
ResolutionListener,
StatusListener,
} from '../types';
import AssetConnection from './AssetConnection';
import Subscriber from './Subscriber';

type AssetState = 'initialized' | 'started' | 'stopped';

class Asset {
trackingId: string;
assetConnection: AssetConnection;
resolution?: Resolution;
state: AssetState;

constructor(subscriber: Subscriber, trackingId: string, resolution?: Resolution) {
this.trackingId = trackingId;
this.resolution = resolution;
this.assetConnection = new AssetConnection(subscriber, trackingId, resolution);
this.state = 'initialized';
}

async start(): Promise<void> {
if (this.state === 'started') {
return;
}
await this.assetConnection.start();
this.state = 'started';
}

async stop(): Promise<void> {
if (this.state !== 'started') {
return;
}
await this.assetConnection.close();
this.state = 'stopped';
}

addLocationListener(listener: LocationListener): void {
this.assetConnection.enhancedLocationListeners.add(listener);
}

addRawLocationListener(listener: LocationListener): void {
this.assetConnection.rawLocationListeners.add(listener);
}

addStatusListener(listener: StatusListener): void {
this.assetConnection.statusListeners.add(listener);
}

addResolutionListener(listener: ResolutionListener): void {
this.assetConnection.resolutionListeners.add(listener);
}

addLocationUpdateIntervalListener(listener: LocationUpdateIntervalListener): void {
this.assetConnection.locationUpdateIntervalListeners.add(listener);
}

removeLocationListener(listener: LocationListener): void {
this.assetConnection.enhancedLocationListeners.delete(listener);
}

removeRawLocationListener(listener: LocationListener): void {
this.assetConnection.rawLocationListeners.delete(listener);
}

removeStatusListener(listener: StatusListener): void {
this.assetConnection.statusListeners.delete(listener);
}

removeResolutionListener(listener: ResolutionListener): void {
this.assetConnection.resolutionListeners.delete(listener);
}

removeLocationUpdateIntervalListener(listener: LocationUpdateIntervalListener): void {
this.assetConnection.locationUpdateIntervalListeners.delete(listener);
}

async sendChangeRequest(resolution: Resolution): Promise<void> {
this.resolution = resolution;
if (this.state !== 'started') {
throw new Error('Cannot change resolution; asset is not currently being tracked.');
} else {
await this.assetConnection.performChangeResolution(resolution);
}
}
}

export default Asset;
Loading