2017-03-11 17:52:41 -05:00
|
|
|
#!/usr/bin/env node
|
2017-05-15 23:56:35 +03:00
|
|
|
const cli = require("commander");
|
2017-03-11 17:52:41 -05:00
|
|
|
const watchman = require('fb-watchman');
|
|
|
|
const fs = require('fs');
|
|
|
|
const chalk = require('chalk');
|
2017-05-24 12:23:42 +03:00
|
|
|
const mdns = require('mdns');
|
2017-03-11 17:52:41 -05:00
|
|
|
|
|
|
|
const pkgJson = require(__dirname + '/package.json');
|
|
|
|
|
|
|
|
const client = new watchman.Client();
|
2017-06-04 18:36:33 +02:00
|
|
|
const defaultIp = process.env.STATUS_DEVICE_IP;
|
2017-05-24 12:23:42 +03:00
|
|
|
const statusDebugServerPort = 5561;
|
2017-03-11 17:52:41 -05:00
|
|
|
const StatusDev = require('./index.js');
|
|
|
|
|
2017-06-04 18:36:33 +02:00
|
|
|
function createStatusDev() {
|
|
|
|
const ip = cli.ip || defaultIp;
|
|
|
|
if (ip == null) {
|
|
|
|
console.error(chalk.red("You have provide your device IP using --ip."));
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
return new StatusDev({ip: ip});
|
|
|
|
}
|
|
|
|
|
2017-03-11 17:52:41 -05:00
|
|
|
function fromAscii(str) {
|
|
|
|
var hex = "";
|
|
|
|
for(var i = 0; i < str.length; i++) {
|
|
|
|
var code = str.charCodeAt(i);
|
|
|
|
var n = code.toString(16);
|
|
|
|
hex += n.length < 2 ? '0' + n : n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "0x" + hex;
|
|
|
|
};
|
|
|
|
|
2017-05-15 23:56:35 +03:00
|
|
|
function makeSubscription(client, watch, relativePath, contactData) {
|
2017-03-11 17:52:41 -05:00
|
|
|
sub = {
|
|
|
|
expression: ["allof", ["match", "*.*"]],
|
|
|
|
fields: ["name"]
|
|
|
|
};
|
|
|
|
if (relativePath) {
|
|
|
|
sub.relative_root = relativePath;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:56:35 +03:00
|
|
|
client.command(['subscribe', watch, 'contact-subscription', sub],
|
2017-03-11 17:52:41 -05:00
|
|
|
function (error, resp) {
|
|
|
|
if (error) {
|
|
|
|
console.error('Failed to subscribe: ', error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log('Subscription established');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
client.on('subscription', function (resp) {
|
2017-05-15 23:56:35 +03:00
|
|
|
if (resp.subscription !== 'contact-subscription') return;
|
2017-03-11 17:52:41 -05:00
|
|
|
|
|
|
|
resp.files.forEach(function (file) {
|
2017-05-31 19:25:49 +03:00
|
|
|
console.log('File changed: ' + file);
|
2017-03-11 17:52:41 -05:00
|
|
|
});
|
|
|
|
|
2017-05-31 19:25:49 +03:00
|
|
|
var statusDev = new StatusDev({ip: cli.ip || defaultIp});
|
|
|
|
statusDev.refreshContact(contactData, function(err, body) {
|
|
|
|
// nothing
|
2017-03-11 17:52:41 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCurrentPackageData() {
|
|
|
|
var obj = {};
|
|
|
|
if (fs.existsSync(process.cwd() + '/package.json')) {
|
|
|
|
var json = JSON.parse(fs.readFileSync(process.cwd() + '/package.json', 'utf8'));
|
|
|
|
obj["name"] = json.name;
|
|
|
|
obj["whisper-identity"] = "dapp-" + fromAscii(json.name);
|
2017-05-31 17:50:40 +03:00
|
|
|
obj["dapp-url"] = json["dapp-url"] || cli.dappUrl;
|
|
|
|
obj["bot-url"] = json["bot-url"] || cli.botUrl;
|
2017-03-11 17:52:41 -05:00
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:56:35 +03:00
|
|
|
function getPackageData(contact) {
|
2017-05-24 15:40:23 +03:00
|
|
|
var contactData = null;
|
2017-05-15 23:56:35 +03:00
|
|
|
if (!contact) {
|
2017-05-24 15:40:23 +03:00
|
|
|
var data = getCurrentPackageData();
|
|
|
|
if (data != null) {
|
|
|
|
contactData = JSON.stringify(data);
|
|
|
|
}
|
2017-05-16 22:08:16 +03:00
|
|
|
} else {
|
|
|
|
contactData = contact;
|
2017-03-11 17:52:41 -05:00
|
|
|
}
|
2017-05-15 23:56:35 +03:00
|
|
|
return contactData;
|
2017-03-11 17:52:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
function printMan() {
|
|
|
|
console.error(chalk.red("Cannot connect to Status."));
|
2017-05-31 13:01:42 +03:00
|
|
|
console.log("1. Please, ensure that your device is accessible from your computer;");
|
|
|
|
console.log("2. If it is, ensure that you're logged in and the debug mode is enabled;");
|
2017-03-11 17:52:41 -05:00
|
|
|
console.log();
|
2017-05-21 18:02:21 +03:00
|
|
|
console.log("Check our docs for more information:");
|
|
|
|
console.log("http://docs.status.im/");
|
|
|
|
}
|
|
|
|
|
|
|
|
function printServerProblem() {
|
|
|
|
console.log("Server doesn't respond properly.");
|
|
|
|
console.log("Please, re-run it or re-login to your account.");
|
|
|
|
console.log();
|
|
|
|
console.log("Check our docs for more information:");
|
|
|
|
console.log("http://docs.status.im/");
|
2017-03-11 17:52:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-15 23:56:35 +03:00
|
|
|
cli.command("add [contact]")
|
|
|
|
.description("Adds a contact")
|
|
|
|
.action(function (contact) {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-21 18:02:21 +03:00
|
|
|
var contactData = getPackageData(contact);
|
|
|
|
if (contactData) {
|
|
|
|
statusDev.addContact(contactData, function(err, body) {
|
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body.type == "error") {
|
|
|
|
console.log(chalk.red(body.text));
|
|
|
|
} else {
|
|
|
|
console.log(chalk.green(body.text));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-03-11 17:52:41 -05:00
|
|
|
});
|
|
|
|
|
2017-05-31 16:34:03 +03:00
|
|
|
cli.command("remove [contactIdentity]")
|
2017-05-15 23:56:35 +03:00
|
|
|
.description("Removes a contact")
|
2017-05-31 16:34:03 +03:00
|
|
|
.action(function (contactIdentity) {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-31 19:25:49 +03:00
|
|
|
|
|
|
|
var contact = null;
|
|
|
|
if (contactIdentity) {
|
|
|
|
contact = JSON.stringify({"whisper-identity": contactIdentity});
|
|
|
|
}
|
|
|
|
var contactData = getPackageData(contact);
|
2017-05-21 18:02:21 +03:00
|
|
|
if (contactData) {
|
|
|
|
statusDev.removeContact(contactData, function(err, body) {
|
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body.type == "error") {
|
|
|
|
console.log(chalk.red(body.text));
|
|
|
|
} else {
|
|
|
|
console.log(chalk.green(body.text));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-03-11 17:52:41 -05:00
|
|
|
});
|
|
|
|
|
2017-05-31 16:34:03 +03:00
|
|
|
cli.command("refresh [contactIdentity]")
|
2017-05-21 18:02:21 +03:00
|
|
|
.description("Refreshes a debuggable contact")
|
2017-05-31 16:34:03 +03:00
|
|
|
.action(function (contactIdentity) {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-31 19:25:49 +03:00
|
|
|
|
|
|
|
var contact = null;
|
|
|
|
if (contactIdentity) {
|
|
|
|
contact = JSON.stringify({"whisper-identity": contactIdentity});
|
|
|
|
}
|
|
|
|
var contactData = getPackageData(contact);
|
2017-05-21 18:02:21 +03:00
|
|
|
if (contactData) {
|
|
|
|
statusDev.refreshContact(contactData, function(err, body) {
|
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body.type == "error") {
|
|
|
|
console.log(chalk.red(body.text));
|
|
|
|
} else {
|
|
|
|
console.log(chalk.green(body.text));
|
|
|
|
}
|
|
|
|
});
|
2017-03-11 17:52:41 -05:00
|
|
|
}
|
2017-05-21 18:02:21 +03:00
|
|
|
});
|
2017-03-11 17:52:41 -05:00
|
|
|
|
|
|
|
cli.command("switch-node <url>")
|
2017-05-21 18:02:21 +03:00
|
|
|
.description("Switches the current RPC node")
|
|
|
|
.action(function (url) {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-21 18:02:21 +03:00
|
|
|
statusDev.switchNode(url, function(err, body) {
|
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body.type == "error") {
|
|
|
|
console.log(chalk.red(body.text));
|
|
|
|
} else {
|
|
|
|
console.log(chalk.green(body.text));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
cli.command("list")
|
|
|
|
.description("Displays all debuggable DApps and bots")
|
|
|
|
.action(function () {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-21 18:02:21 +03:00
|
|
|
statusDev.listDApps(function (err, body) {
|
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body === undefined) {
|
|
|
|
printServerProblem();
|
2017-05-22 14:27:34 +03:00
|
|
|
} else if (body.data === undefined) {
|
|
|
|
console.log(chalk.red("No DApps or bots."));
|
2017-05-21 18:02:21 +03:00
|
|
|
} else {
|
|
|
|
body.data.forEach(function(item, i, arr) {
|
|
|
|
if (item["dapp-url"]) {
|
|
|
|
console.log(chalk.green(chalk.bold(item["whisper-identity"]) +
|
|
|
|
" (Name: \"" + item.name + "\", DApp URL: \"" + item["dapp-url"] + "\")"));
|
|
|
|
} else if (item["bot-url"]) {
|
|
|
|
console.log(chalk.cyan(chalk.bold(item["whisper-identity"]) +
|
|
|
|
" (Name: \"" + item.name + "\", Bot URL: \"" + item["bot-url"] + "\")"));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-05-31 16:34:03 +03:00
|
|
|
cli.command("log <contactIdentity>")
|
2017-05-21 18:02:21 +03:00
|
|
|
.description("Returns log for a specified DApp or bot")
|
2017-05-31 16:34:03 +03:00
|
|
|
.action(function (contactIdentity) {
|
2017-06-04 18:36:33 +02:00
|
|
|
var statusDev = createStatusDev();
|
2017-05-31 16:34:03 +03:00
|
|
|
statusDev.getLog(contactIdentity, function (err, body) {
|
2017-05-21 18:02:21 +03:00
|
|
|
if (err) {
|
|
|
|
printMan();
|
|
|
|
} else if (body === undefined) {
|
|
|
|
printServerProblem();
|
|
|
|
} else if (body.type == "error") {
|
|
|
|
console.log(chalk.red(body.text));
|
|
|
|
} else {
|
|
|
|
body.data.forEach(function(item, i, arr) {
|
|
|
|
var time = new Date(item.timestamp).toLocaleString();
|
|
|
|
|
|
|
|
if (item.content.startsWith("error:")) {
|
|
|
|
console.log(chalk.red(time + " " + item.content));
|
|
|
|
} else if (item.content.startsWith("warn:")) {
|
|
|
|
console.log(chalk.cyan(time + " " + item.content));
|
|
|
|
} else {
|
|
|
|
console.log(time + " " + item.content);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2017-03-11 17:52:41 -05:00
|
|
|
});
|
|
|
|
|
2017-05-24 12:23:42 +03:00
|
|
|
cli.command("scan")
|
|
|
|
.description("Scans your network and searches for Status debug servers")
|
|
|
|
.action(function () {
|
|
|
|
console.log("Searching for connected devices...");
|
|
|
|
|
2017-05-30 00:23:32 +02:00
|
|
|
var sequence = [
|
|
|
|
mdns.rst.DNSServiceResolve(),
|
|
|
|
'DNSServiceGetAddrInfo' in mdns.dns_sd ? mdns.rst.DNSServiceGetAddrInfo({families:[0]}) : mdns.rst.getaddrinfo({families:[0]}),
|
|
|
|
mdns.rst.makeAddressesUnique()
|
|
|
|
];
|
|
|
|
var browser = mdns.createBrowser(mdns.tcp('http'), {resolverSequence: sequence});
|
2017-05-24 12:23:42 +03:00
|
|
|
browser.on('serviceUp', function(service) {
|
|
|
|
if (service.port == statusDebugServerPort) {
|
|
|
|
console.log(chalk.green(chalk.bold(service.name) + " (" + service.addresses.join(", ") + ")"));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
browser.start();
|
|
|
|
});
|
|
|
|
|
2017-05-31 16:34:03 +03:00
|
|
|
cli.command("watch [dir] [contactIdentity]")
|
2017-05-15 23:56:35 +03:00
|
|
|
.description("Starts watching for contact changes")
|
2017-05-31 16:34:03 +03:00
|
|
|
.action(function (dir, contactIdentity) {
|
2017-05-31 19:25:49 +03:00
|
|
|
var contact = null;
|
|
|
|
if (contactIdentity) {
|
|
|
|
contact = JSON.stringify({"whisper-identity": contactIdentity});
|
|
|
|
}
|
2017-05-15 23:56:35 +03:00
|
|
|
var contactData = getPackageData(contact);
|
|
|
|
if (!contactData) {
|
2017-03-11 17:52:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2017-05-15 23:56:35 +03:00
|
|
|
contactDir = dir || process.cwd();
|
|
|
|
console.log("Watching for changes in " + contactDir);
|
2017-03-11 17:52:41 -05:00
|
|
|
|
|
|
|
client.capabilityCheck(
|
|
|
|
{optional:[], required:['relative_root']},
|
|
|
|
function (error, resp) {
|
|
|
|
if (error) {
|
|
|
|
console.log(error);
|
|
|
|
client.end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
client.command(
|
2017-05-15 23:56:35 +03:00
|
|
|
['watch-project', contactDir],
|
2017-03-11 17:52:41 -05:00
|
|
|
function (error, resp) {
|
|
|
|
if (error) {
|
|
|
|
console.error('Error initiating watch:', error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('warning' in resp) {
|
|
|
|
console.log('Warning: ', resp.warning);
|
|
|
|
}
|
|
|
|
|
|
|
|
makeSubscription(
|
|
|
|
client,
|
|
|
|
resp.watch,
|
|
|
|
resp.relative_path,
|
2017-05-17 14:56:27 +03:00
|
|
|
contactData
|
2017-03-11 17:52:41 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
cli.on("*", function(command) {
|
|
|
|
console.error("Unknown command " + command[0] + ". See --help for valid commands.")
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
cli.version(pkgJson.version)
|
|
|
|
.option("--ip [ip]", "IP address of your device")
|
2017-05-29 18:03:23 +03:00
|
|
|
.option("--dappUrl [url]", "Custom DApp URL (overrides the one from the package.json)")
|
2017-05-31 17:50:40 +03:00
|
|
|
.option("--botUrl [url]", "Custom bot URL (overrides the one from the package.json)")
|
2017-03-11 17:52:41 -05:00
|
|
|
.parse(process.argv);
|