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

Handle serviceDown events. #55

Merged
merged 2 commits into from
Aug 27, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "thing-url-adapter",
"display_name": "Web Thing",
"version": "0.2.1",
"version": "0.2.2",
"description": "Native web thing support",
"author": "Mozilla IoT",
"main": "index.js",
Expand Down
69 changes: 56 additions & 13 deletions thing-url-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,23 @@ class ThingURLProperty extends Property {
this.setCachedValue(updatedValue);
this.device.notifyPropertyChanged(this);
return updatedValue;
}).catch((e) => {
console.log(`Failed to set ${this.name}:`, e);
return this.value;
});
}
}

class ThingURLDevice extends Device {
constructor(adapter, id, url, description) {
constructor(adapter, id, url, description, mdnsUrl) {
super(adapter, id);
this.name = description.name;
this.type = description.type;
this['@context'] =
description['@context'] || 'https://iot.mozilla.org/schemas';
this['@type'] = description['@type'] || [];
this.url = url;
this.mdnsUrl = mdnsUrl;
this.actionsUrl = null;
this.eventsUrl = null;
this.wsUrl = null;
Expand All @@ -85,6 +89,7 @@ class ThingURLDevice extends Device {
this.notifiedEvents = new Set();
this.scheduledUpdate = null;
this.updateInterval = 5000;
this.closingWs = false;

for (const actionName in description.actions) {
this.addAction(actionName, description.actions[actionName]);
Expand All @@ -110,7 +115,7 @@ class ThingURLDevice extends Device {
this, propertyName, propertyUrl, propertyDescription);
this.properties.set(propertyName, property);
}).catch((e) => {
console.log('Failed to connect to', propertyUrl, ':', e);
console.log(`Failed to connect to ${propertyUrl}:`, e);
}));
}

Expand Down Expand Up @@ -145,21 +150,24 @@ class ThingURLDevice extends Device {
}

closeWebsocket() {
if (this.ws) {
this.ws.removeAllListeners('close');
this.ws.removeAllListeners('error');
if (this.ws !== null) {
this.closingWs = true;

if (this.ws.readyState === WebSocket.OPEN) {
this.ws.close();
}

this.ws = null;
// Allow the cleanup code in createWebsocket to handle shutdown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanupAndReopen code should be updated to null this.ws then for paranoia's sake.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. Done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

} else if (this.scheduledUpdate) {
clearTimeout(this.scheduledUpdate);
}
}

createWebsocket() {
if (this.closingWs) {
return;
}

this.ws = new WebSocket(this.wsUrl);

this.ws.on('open', () => {
Expand Down Expand Up @@ -228,7 +236,7 @@ class ThingURLDevice extends Device {
}
}
} catch (e) {
console.log(e);
console.log('Error receiving websocket message:', e);
}
});

Expand Down Expand Up @@ -261,7 +269,7 @@ class ThingURLDevice extends Device {
}
});
}).catch((e) => {
console.log('Failed to connect to', prop.url, ':', e);
console.log(`Failed to connect to ${prop.url}:`, e);
});
});

Expand Down Expand Up @@ -339,6 +347,10 @@ class ThingURLDevice extends Device {
return res.json();
}).then((res) => {
this.requestedActions.set(res[action.name].href, action);
}).catch((e) => {
console.log('Failed to perform action:', e);
action.status = 'error';
this.actionNotify(action);
});
}

Expand All @@ -352,6 +364,8 @@ class ThingURLDevice extends Device {
headers: {
Accept: 'application/json',
},
}).catch((e) => {
console.log('Failed to cancel action:', e);
});

this.requestedActions.delete(actionHref);
Expand Down Expand Up @@ -397,7 +411,7 @@ class ThingURLAdapter extends Adapter {
} catch (e) {
// Retry the connection at a 2 second interval up to 5 times.
if (retryCounter >= 5) {
console.log('Failed to connect to', url, ':', e);
console.log(`Failed to connect to ${url}:`, e);
} else {
setTimeout(() => this.loadThing(url, retryCounter + 1), 2000);
}
Expand All @@ -424,7 +438,7 @@ class ThingURLAdapter extends Adapter {
try {
data = JSON.parse(text);
} catch (e) {
console.log('Failed to parse description at', url, ':', e);
console.log(`Failed to parse description at ${url}:`, e);
return;
}

Expand All @@ -449,7 +463,23 @@ class ThingURLAdapter extends Adapter {
}
await this.removeThing(this.devices[id]);
}
await this.addDevice(id, thingUrl, thingDescription);
await this.addDevice(id, thingUrl, thingDescription, url);
}
}

unloadThing(url) {
url = url.replace(/\/$/, '');

for (const id in this.devices) {
const device = this.devices[id];
if (device.mdnsUrl === url) {
device.closeWebsocket();
this.removeThing(device);
}
}

if (this.knownUrls[url]) {
delete this.knownUrls[url];
}
}

Expand All @@ -459,13 +489,13 @@ class ThingURLAdapter extends Adapter {
* @param {String} deviceId ID of the device to add.
* @return {Promise} which resolves to the device added.
*/
addDevice(deviceId, deviceURL, description) {
addDevice(deviceId, deviceURL, description, mdnsUrl) {
return new Promise((resolve, reject) => {
if (deviceId in this.devices) {
reject(`Device: ${deviceId} already exists.`);
} else {
const device =
new ThingURLDevice(this, deviceId, deviceURL, description);
new ThingURLDevice(this, deviceId, deviceURL, description, mdnsUrl);
Promise.all(device.propertyPromises).then(() => {
this.handleDeviceAdded(device);
resolve(device);
Expand Down Expand Up @@ -570,6 +600,10 @@ function startDNSDiscovery(adapter) {
const host = service.host.replace(/\.$/, '');
adapter.loadThing(`http://${host}:${service.port}${service.txt.path}`);
});
webthingBrowser.on('serviceDown', (service) => {
const host = service.host.replace(/\.$/, '');
adapter.unloadThing(`http://${host}:${service.port}${service.txt.path}`);
});
webthingBrowser.start();

// Support legacy devices
Expand All @@ -578,6 +612,9 @@ function startDNSDiscovery(adapter) {
subtypeBrowser.on('serviceUp', (service) => {
adapter.loadThing(service.txt.url);
});
subtypeBrowser.on('serviceDown', (service) => {
adapter.unloadThing(service.txt.url);
});
subtypeBrowser.start();

httpBrowser = new dnssd.Browser(new dnssd.ServiceType('_http._tcp'));
Expand All @@ -587,6 +624,12 @@ function startDNSDiscovery(adapter) {
adapter.loadThing(service.txt.url);
}
});
httpBrowser.on('serviceDown', (service) => {
if (typeof service.txt === 'object' &&
service.txt.hasOwnProperty('webthing')) {
adapter.unloadThing(service.txt.url);
}
});
httpBrowser.start();
}

Expand Down