fune/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm
2018-11-02 10:38:14 +00:00

258 lines
6.3 KiB
JavaScript

// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["MulticastDNS"];
ChromeUtils.import("resource://gre/modules/Messaging.jsm");
const DEBUG = false;
var log = function(s) {};
if (DEBUG) {
log = ChromeUtils.import("resource://gre/modules/AndroidLog.jsm", {})
.AndroidLog.d.bind(null, "MulticastDNS");
}
const FAILURE_INTERNAL_ERROR = -65537;
// Helper function for sending commands to Java.
function send(type, data, callback) {
let msg = {
type,
};
for (let i in data) {
try {
msg[i] = data[i];
} catch (e) {
}
}
EventDispatcher.instance.sendRequestForResult(msg)
.then(result => callback(result, null),
err => callback(null, typeof err === "number" ? err : FAILURE_INTERNAL_ERROR));
}
// Receives service found/lost event from NsdManager
function ServiceManager() {
}
ServiceManager.prototype = {
listeners: {},
numListeners: 0,
onEvent(event, data, callback) {
if (event === "NsdManager:ServiceFound") {
this.onServiceFound();
} else if (event === "NsdManager:ServiceLost") {
this.onServiceLost();
}
},
registerEvent() {
log("registerEvent");
EventDispatcher.instance.registerListener(this, [
"NsdManager:ServiceFound",
"NsdManager:ServiceLost",
]);
},
unregisterEvent() {
log("unregisterEvent");
EventDispatcher.instance.unregisterListener(this, [
"NsdManager:ServiceFound",
"NsdManager:ServiceLost",
]);
},
addListener(aServiceType, aListener) {
log("addListener: " + aServiceType + ", " + aListener);
if (!this.listeners[aServiceType]) {
this.listeners[aServiceType] = [];
}
if (this.listeners[aServiceType].includes(aListener)) {
log("listener already exists");
return;
}
this.listeners[aServiceType].push(aListener);
++this.numListeners;
if (this.numListeners === 1) {
this.registerEvent();
}
log("listener added: " + this);
},
removeListener(aServiceType, aListener) {
log("removeListener: " + aServiceType + ", " + aListener);
if (!this.listeners[aServiceType]) {
log("listener doesn't exist");
return;
}
let index = this.listeners[aServiceType].indexOf(aListener);
if (index < 0) {
log("listener doesn't exist");
return;
}
this.listeners[aServiceType].splice(index, 1);
--this.numListeners;
if (this.numListeners === 0) {
this.unregisterEvent();
}
log("listener removed" + this);
},
onServiceFound(aServiceInfo) {
let listeners = this.listeners[aServiceInfo.serviceType];
if (listeners) {
for (let listener of listeners) {
listener.onServiceFound(aServiceInfo);
}
} else {
log("no listener");
}
return {};
},
onServiceLost(aServiceInfo) {
let listeners = this.listeners[aServiceInfo.serviceType];
if (listeners) {
for (let listener of listeners) {
listener.onServiceLost(aServiceInfo);
}
} else {
log("no listener");
}
return {};
},
};
// make an object from nsIPropertyBag2
function parsePropertyBag2(bag) {
if (!bag || !(bag instanceof Ci.nsIPropertyBag2)) {
throw new TypeError("Not a property bag");
}
let attributes = [];
for (let {name} of bag.enumerator) {
let value = bag.getPropertyAsACString(name);
attributes.push({
"name": name,
"value": value,
});
}
return attributes;
}
function MulticastDNS() {
this.serviceManager = new ServiceManager();
}
MulticastDNS.prototype = {
startDiscovery(aServiceType, aListener) {
this.serviceManager.addListener(aServiceType, aListener);
let serviceInfo = {
serviceType: aServiceType,
uniqueId: aListener.uuid,
};
send("NsdManager:DiscoverServices", serviceInfo, (result, err) => {
if (err) {
log("onStartDiscoveryFailed: " + aServiceType + " (" + err + ")");
this.serviceManager.removeListener(aServiceType, aListener);
aListener.onStartDiscoveryFailed(aServiceType, err);
} else {
aListener.onDiscoveryStarted(result);
}
});
},
stopDiscovery(aServiceType, aListener) {
this.serviceManager.removeListener(aServiceType, aListener);
let serviceInfo = {
uniqueId: aListener.uuid,
};
send("NsdManager:StopServiceDiscovery", serviceInfo, (result, err) => {
if (err) {
log("onStopDiscoveryFailed: " + aServiceType + " (" + err + ")");
aListener.onStopDiscoveryFailed(aServiceType, err);
} else {
aListener.onDiscoveryStopped(aServiceType);
}
});
},
registerService(aServiceInfo, aListener) {
let serviceInfo = {
port: aServiceInfo.port,
serviceType: aServiceInfo.serviceType,
uniqueId: aListener.uuid,
};
try {
serviceInfo.host = aServiceInfo.host;
} catch (e) {
// host unspecified
}
try {
serviceInfo.serviceName = aServiceInfo.serviceName;
} catch (e) {
// serviceName unspecified
}
try {
serviceInfo.attributes = parsePropertyBag2(aServiceInfo.attributes);
} catch (e) {
// attributes unspecified
}
send("NsdManager:RegisterService", serviceInfo, (result, err) => {
if (err) {
log("onRegistrationFailed: (" + err + ")");
aListener.onRegistrationFailed(aServiceInfo, err);
} else {
aListener.onServiceRegistered(result);
}
});
},
unregisterService(aServiceInfo, aListener) {
let serviceInfo = {
uniqueId: aListener.uuid,
};
send("NsdManager:UnregisterService", serviceInfo, (result, err) => {
if (err) {
log("onUnregistrationFailed: (" + err + ")");
aListener.onUnregistrationFailed(aServiceInfo, err);
} else {
aListener.onServiceUnregistered(aServiceInfo);
}
});
},
resolveService(aServiceInfo, aListener) {
send("NsdManager:ResolveService", aServiceInfo, (result, err) => {
if (err) {
log("onResolveFailed: (" + err + ")");
aListener.onResolveFailed(aServiceInfo, err);
} else {
aListener.onServiceResolved(result);
}
});
},
};