Files
archived-raspberry-wifi-conf/app/wifi_manager.js

288 lines
10 KiB
JavaScript

var _ = require("underscore")._,
async = require("async"),
fs = require("fs"),
exec = require("child_process").exec,
config = require("../config.json");
// Better template format
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
evaluate : /\{\[([\s\S]+?)\]\}/g
};
// Helper function to write a given template to a file based on a given
// context
function write_template_to_file(template_path, file_name, context, callback) {
async.waterfall([
function read_template_file(next_step) {
fs.readFile(template_path, {encoding: "utf8"}, next_step);
},
function update_file(file_txt, next_step) {
var template = _.template(file_txt);
fs.writeFile(file_name, template(context), next_step);
}
], callback);
}
/*****************************************************************************\
Return a set of functions which we can use to manage and check our wifi
connection information
\*****************************************************************************/
module.exports = function() {
// Hack: this just assumes that the outbound interface will be "wlan0"
// Define some globals
var ifconfig_fields = {
"hw_addr": /HWaddr\s([^\s]+)/,
"inet_addr": /inet addr:([^\s]+)/,
}, iwconfig_fields = {
"ap_addr": /Access Point:\s([^\s]+)/,
"ap_ssid": /ESSID:\"([^\"]+)\"/,
"unassociated": /(unassociated)\s+Nick/,
}, last_wifi_info = null;
// TODO: rpi-config-ap hardcoded, should derive from a constant
// Get generic info on an interface
var _get_wifi_info = function(callback) {
var output = {
hw_addr: "<unknown>",
inet_addr: "<unknown>",
unassociated: "<unknown>",
};
// Inner function which runs a given command and sets a bunch
// of fields
function run_command_and_set_fields(cmd, fields, callback) {
exec(cmd, function(error, stdout, stderr) {
if (error) return callback(error);
for (var key in fields) {
re = stdout.match(fields[key]);
if (re && re.length > 1) {
output[key] = re[1];
}
}
callback(null);
});
}
// Run a bunch of commands and aggregate info
async.series([
function run_ifconfig(next_step) {
run_command_and_set_fields("ifconfig wlan0", ifconfig_fields, next_step);
},
function run_iwconfig(next_step) {
run_command_and_set_fields("iwconfig wlan0", iwconfig_fields, next_step);
},
], function(error) {
last_wifi_info = output;
return callback(error, output);
});
},
_reboot_wireless_network = function(wlan_iface, callback) {
async.series([
function down(next_step) {
exec("sudo ifdown " + wlan_iface, function(error, stdout, stderr) {
if (!error) console.log("ifdown " + wlan_iface + " successful...");
next_step();
});
},
function up(next_step) {
exec("sudo ifup " + wlan_iface, function(error, stdout, stderr) {
if (!error) console.log("ifup " + wlan_iface + " successful...");
next_step();
});
},
], callback);
},
// Wifi related functions
_is_wifi_enabled_sync = function(info) {
// If we are not an AP, and we have a valid
// inet_addr - wifi is enabled!
if (null == _is_ap_enabled_sync(info) &&
"<unknown>" != info["inet_addr"] &&
"<unknown>" == info["unassociated"] ) {
return info["inet_addr"];
}
return null;
},
_is_wifi_enabled = function(callback) {
_get_wifi_info(function(error, info) {
if (error) return callback(error, null);
return callback(null, _is_wifi_enabled_sync(info));
});
},
// Access Point related functions
_is_ap_enabled_sync = function(info) {
// If the hw_addr matches the ap_addr
// and the ap_ssid matches "rpi-config-ap"
// then we are in AP mode
var is_ap =
info["hw_addr"].toLowerCase() == info["ap_addr"].toLowerCase() &&
info["ap_ssid"] == config.access_point.ssid;
return (is_ap) ? info["hw_addr"].toLowerCase() : null;
},
_is_ap_enabled = function(callback) {
_get_wifi_info(function(error, info) {
if (error) return callback(error, null);
return callback(null, _is_ap_enabled_sync(info));
});
},
// Enables the accesspoint w/ bcast_ssid. This assumes that both
// isc-dhcp-server and hostapd are installed using:
// $sudo npm run-script provision
_enable_ap_mode = function(bcast_ssid, callback) {
_is_ap_enabled(function(error, result_addr) {
if (error) {
console.log("ERROR: " + error);
return callback(error);
}
if (result_addr && !config.access_point.force_reconfigure) {
console.log("\nAccess point is enabled with ADDR: " + result_addr);
return callback(null);
} else if (config.access_point.force_reconfigure) {
console.log("\nForce reconfigure enabled - reset AP");
} else {
console.log("\nAP is not enabled yet... enabling...");
}
var context = config.access_point;
context["enable_ap"] = true;
// Here we need to actually follow the steps to enable the ap
async.series([
// Enable the access point ip and netmask + static
// DHCP for the wlan0 interface
function update_interfaces(next_step) {
write_template_to_file(
"./assets/etc/network/interfaces.ap.template",
"/etc/network/interfaces",
context, next_step);
},
// Enable DHCP conf, set authoritative mode and subnet
function update_dhcpd(next_step) {
var context = config.access_point;
// We must enable this to turn on the access point
write_template_to_file(
"./assets/etc/dhcp/dhcpd.conf.template",
"/etc/dhcp/dhcpd.conf",
context, next_step);
},
// Enable the interface in the dhcp server
function update_dhcp_interface(next_step) {
write_template_to_file(
"./assets/etc/default/isc-dhcp-server.template",
"/etc/default/isc-dhcp-server",
context, next_step);
},
// Enable hostapd.conf file
function update_hostapd_conf(next_step) {
write_template_to_file(
"./assets/etc/hostapd/hostapd.conf.template",
"/etc/hostapd/hostapd.conf",
context, next_step);
},
function update_hostapd_default(next_step) {
write_template_to_file(
"./assets/etc/default/hostapd.template",
"/etc/default/hostapd",
context, next_step);
},
function reboot_network_interfaces(next_step) {
_reboot_wireless_network(context.wifi_interface, next_step);
},
function restart_dhcp_service(next_step) {
exec("service isc-dhcp-server restart", function(error, stdout, stderr) {
//console.log(stdout);
if (!error) console.log("... dhcp server restarted!");
next_step();
});
},
function restart_hostapd_service(next_step) {
exec("service hostapd restart", function(error, stdout, stderr) {
//console.log(stdout);
if (!error) console.log("... hostapd restarted!");
next_step();
});
},
// TODO: Do we need to issue a reboot here?
], callback);
});
},
// Disables AP mode and reverts to wifi connection
_enable_wifi_mode = function(connection_info, callback) {
console.log("Entered: _enable_wifi_mode");
_is_wifi_enabled(function(error, result_ip) {
if (error) return callback(error);
if (result_ip) {
console.log("\nWifi connection is enabled with IP: " + result_ip);
return callback(null);
}
async.series([
// Update /etc/network/interface with correct info...
function update_interfaces(next_step) {
write_template_to_file(
"./assets/etc/network/interfaces.wifi.template",
"/etc/network/interfaces",
connection_info, next_step);
},
// Stop the DHCP server...
function restart_dhcp_service(next_step) {
exec("service isc-dhcp-server stop", function(error, stdout, stderr) {
//console.log(stdout);
if (!error) console.log("... dhcp server stopped!");
next_step();
});
},
function reboot_network_interfaces(next_step) {
_reboot_wireless_network(config.wifi_interface, next_step);
},
], callback);
});
};
return {
get_wifi_info: _get_wifi_info,
reboot_wireless_network: _reboot_wireless_network,
is_wifi_enabled: _is_wifi_enabled,
is_wifi_enabled_sync: _is_wifi_enabled_sync,
is_ap_enabled: _is_ap_enabled,
is_ap_enabled_sync: _is_ap_enabled_sync,
enable_ap_mode: _enable_ap_mode,
enable_wifi_mode: _enable_wifi_mode,
};
}