rpiConfigServer: Add NetworkSettings, other cleanups
This commit is contained in:
parent
7b78c412b0
commit
e33285763c
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,4 +15,5 @@ deps/tools/rpiConfigServer
|
||||||
deps/tools/setuidgids
|
deps/tools/setuidgids
|
||||||
*.o
|
*.o
|
||||||
*.sw?
|
*.sw?
|
||||||
|
*.debug
|
||||||
stage2/01-sys-tweaks/extfiles
|
stage2/01-sys-tweaks/extfiles
|
||||||
|
|
3
deps/tools/Makefile
vendored
3
deps/tools/Makefile
vendored
|
@ -33,6 +33,7 @@ _cscore.so: ../robotpy-cscore/src/_cscore.cpp ../robotpy-cscore/src/ndarray_conv
|
||||||
RPICONFIGSERVER_OBJS= \
|
RPICONFIGSERVER_OBJS= \
|
||||||
rpiConfigServer_src/main.o \
|
rpiConfigServer_src/main.o \
|
||||||
rpiConfigServer_src/MyHttpConnection.o \
|
rpiConfigServer_src/MyHttpConnection.o \
|
||||||
|
rpiConfigServer_src/NetworkSettings.o \
|
||||||
rpiConfigServer_src/SystemStatus.o \
|
rpiConfigServer_src/SystemStatus.o \
|
||||||
rpiConfigServer_src/VisionStatus.o \
|
rpiConfigServer_src/VisionStatus.o \
|
||||||
rpiConfigServer_src/WebSocketHandlers.o \
|
rpiConfigServer_src/WebSocketHandlers.o \
|
||||||
|
@ -45,6 +46,8 @@ rpiConfigServer: ${RPICONFIGSERVER_OBJS}
|
||||||
${RPICONFIGSERVER_OBJS} \
|
${RPICONFIGSERVER_OBJS} \
|
||||||
-L../allwpilib/wpiutil/build/libs/wpiutil/static/release \
|
-L../allwpilib/wpiutil/build/libs/wpiutil/static/release \
|
||||||
-lwpiutil
|
-lwpiutil
|
||||||
|
${COMPILER}objcopy --only-keep-debug $@ $@.debug
|
||||||
|
${COMPILER}strip -g $@
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
${COMPILER}g++ -O -Wall -c -o $@ \
|
${COMPILER}g++ -O -Wall -c -o $@ \
|
||||||
|
|
232
deps/tools/rpiConfigServer_src/NetworkSettings.cpp
vendored
Normal file
232
deps/tools/rpiConfigServer_src/NetworkSettings.cpp
vendored
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "NetworkSettings.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <wpi/FileSystem.h>
|
||||||
|
#include <wpi/MathExtras.h>
|
||||||
|
#include <wpi/SmallString.h>
|
||||||
|
#include <wpi/json.h>
|
||||||
|
#include <wpi/raw_istream.h>
|
||||||
|
#include <wpi/raw_ostream.h>
|
||||||
|
#include <wpi/uv/Process.h>
|
||||||
|
#include <wpi/uv/util.h>
|
||||||
|
|
||||||
|
namespace uv = wpi::uv;
|
||||||
|
|
||||||
|
#define DHCPCD_CONF "/boot/dhcpcd.conf"
|
||||||
|
|
||||||
|
#define GEN_MARKER "###### BELOW THIS LINE EDITED BY RPICONFIGSERVER ######"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Format of generated portion for static:
|
||||||
|
|
||||||
|
interface eth0
|
||||||
|
static ip_address=<networkAddress>/<networkMask as CIDR>
|
||||||
|
static routers=<networkGateway>
|
||||||
|
static domain_name_servers=<networkDNS>
|
||||||
|
|
||||||
|
For static fallback:
|
||||||
|
|
||||||
|
profile static_eth0
|
||||||
|
static ip_address=<networkAddress>/<networkMask as CIDR>
|
||||||
|
static routers=<networkGateway>
|
||||||
|
static domain_name_servers=<networkDNS>
|
||||||
|
interface eth0
|
||||||
|
fallback static_eth0
|
||||||
|
*/
|
||||||
|
|
||||||
|
wpi::StringRef CidrToNetmask(unsigned int cidr,
|
||||||
|
wpi::SmallVectorImpl<char>& buf) {
|
||||||
|
in_addr addr = { htonl(wpi::maskLeadingOnes<uint32_t>(cidr)) };
|
||||||
|
wpi::uv::AddrToName(addr, &buf);
|
||||||
|
return wpi::StringRef(buf.data(), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetmaskToCidr(wpi::StringRef netmask, unsigned int* cidr) {
|
||||||
|
in_addr addr;
|
||||||
|
if (wpi::uv::NameToAddr(netmask, &addr) != 0) return false;
|
||||||
|
uint32_t hostAddr = ntohl(addr.s_addr);
|
||||||
|
auto leadingOnes = wpi::countLeadingOnes(hostAddr);
|
||||||
|
auto trailingZeros = wpi::countTrailingZeros(hostAddr);
|
||||||
|
if (leadingOnes + trailingZeros != 32) return false;
|
||||||
|
*cidr = leadingOnes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkSettings> NetworkSettings::GetInstance() {
|
||||||
|
static auto inst = std::make_shared<NetworkSettings>(private_init{});
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::Set(Mode mode, wpi::StringRef address,
|
||||||
|
wpi::StringRef mask, wpi::StringRef gateway,
|
||||||
|
wpi::StringRef dns,
|
||||||
|
std::function<void(wpi::StringRef)> onFail) {
|
||||||
|
// validate and sanitize inputs
|
||||||
|
wpi::SmallString<32> addressOut;
|
||||||
|
unsigned int cidr;
|
||||||
|
wpi::SmallString<32> gatewayOut;
|
||||||
|
wpi::SmallString<128> dnsOut;
|
||||||
|
|
||||||
|
// address
|
||||||
|
in_addr addressAddr;
|
||||||
|
if (wpi::uv::NameToAddr(address, &addressAddr) != 0) {
|
||||||
|
wpi::SmallString<128> err;
|
||||||
|
err += "invalid address '";
|
||||||
|
err += address;
|
||||||
|
err += "'";
|
||||||
|
onFail(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wpi::uv::AddrToName(addressAddr, &addressOut);
|
||||||
|
|
||||||
|
// mask
|
||||||
|
if (!NetmaskToCidr(mask, &cidr)) {
|
||||||
|
wpi::SmallString<128> err;
|
||||||
|
err += "invalid netmask '";
|
||||||
|
err += mask;
|
||||||
|
err += "'";
|
||||||
|
onFail(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gateway (may be blank)
|
||||||
|
in_addr gatewayAddr;
|
||||||
|
if (wpi::uv::NameToAddr(gateway, &gatewayAddr) == 0)
|
||||||
|
wpi::uv::AddrToName(gatewayAddr, &gatewayOut);
|
||||||
|
|
||||||
|
// dns
|
||||||
|
wpi::SmallVector<wpi::StringRef, 4> dnsStrs;
|
||||||
|
wpi::SmallString<32> oneDnsOut;
|
||||||
|
bool first = true;
|
||||||
|
dns.split(dnsStrs, ' ', -1, false);
|
||||||
|
for (auto dnsStr : dnsStrs) {
|
||||||
|
in_addr dnsAddr;
|
||||||
|
if (wpi::uv::NameToAddr(dnsStr, &dnsAddr) != 0) {
|
||||||
|
wpi::SmallString<128> err;
|
||||||
|
err += "invalid DNS address '";
|
||||||
|
err += dnsStr;
|
||||||
|
err += "'";
|
||||||
|
onFail(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wpi::uv::AddrToName(dnsAddr, &oneDnsOut);
|
||||||
|
if (!first) dnsOut += ' ';
|
||||||
|
first = false;
|
||||||
|
dnsOut += oneDnsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read file (up to but not including the marker)
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
std::error_code ec;
|
||||||
|
{
|
||||||
|
wpi::raw_fd_istream is(DHCPCD_CONF, ec);
|
||||||
|
if (ec) {
|
||||||
|
onFail("could not read " DHCPCD_CONF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpi::SmallString<256> lineBuf;
|
||||||
|
while (!is.has_error()) {
|
||||||
|
wpi::StringRef line = is.getline(lineBuf, 256).trim();
|
||||||
|
if (line == GEN_MARKER) break;
|
||||||
|
lines.emplace_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write file
|
||||||
|
{
|
||||||
|
// write original lines
|
||||||
|
wpi::raw_fd_ostream os(DHCPCD_CONF, ec, wpi::sys::fs::F_Text);
|
||||||
|
if (ec) {
|
||||||
|
onFail("could not write " DHCPCD_CONF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto&& line : lines)
|
||||||
|
os << line << '\n';
|
||||||
|
|
||||||
|
// write marker
|
||||||
|
os << GEN_MARKER << '\n';
|
||||||
|
|
||||||
|
// write generated config
|
||||||
|
switch (mode) {
|
||||||
|
case kDhcp:
|
||||||
|
break; // nothing required
|
||||||
|
case kStatic:
|
||||||
|
os << "interface eth0\n";
|
||||||
|
os << "static ip_address=" << addressOut << '/' << cidr << '\n';
|
||||||
|
if (!gatewayOut.empty()) os << "static routers=" << gatewayOut << '\n';
|
||||||
|
if (!dnsOut.empty())
|
||||||
|
os << "static domain_name_servers=" << dnsOut << '\n';
|
||||||
|
break;
|
||||||
|
case kDhcpStatic:
|
||||||
|
os << "profile static_eth0\n";
|
||||||
|
os << "static ip_address=" << addressOut << '/' << cidr << '\n';
|
||||||
|
if (!gatewayOut.empty()) os << "static routers=" << gatewayOut << '\n';
|
||||||
|
if (!dnsOut.empty())
|
||||||
|
os << "static domain_name_servers=" << dnsOut << '\n';
|
||||||
|
os << "interface eth0\n";
|
||||||
|
os << "fallback static_eth0\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell dhcpcd to reload config
|
||||||
|
if (auto proc =
|
||||||
|
uv::Process::Spawn(m_loop, "/sbin/dhcpcd", "/sbin/dhcpcd", "-n")) {
|
||||||
|
proc->exited.connect([p = proc.get()](int64_t, int) { p->Close(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::UpdateStatus() { status(GetStatusJson()); }
|
||||||
|
|
||||||
|
wpi::json NetworkSettings::GetStatusJson() {
|
||||||
|
std::error_code ec;
|
||||||
|
wpi::raw_fd_istream is(DHCPCD_CONF, ec);
|
||||||
|
if (ec) {
|
||||||
|
wpi::errs() << "could not read " DHCPCD_CONF "\n";
|
||||||
|
return wpi::json();
|
||||||
|
}
|
||||||
|
|
||||||
|
wpi::json j = {{"type", "networkSettings"}, {"networkApproach", "dhcp"}};
|
||||||
|
|
||||||
|
wpi::SmallString<256> lineBuf;
|
||||||
|
bool foundMarker = false;
|
||||||
|
while (!is.has_error()) {
|
||||||
|
wpi::StringRef line = is.getline(lineBuf, 256).trim();
|
||||||
|
if (line == GEN_MARKER) foundMarker = true;
|
||||||
|
if (!foundMarker) continue;
|
||||||
|
if (line.empty()) continue;
|
||||||
|
if (line.startswith("static ip_address")) {
|
||||||
|
j["networkApproach"] = "static";
|
||||||
|
|
||||||
|
wpi::StringRef value = line.split('=').second.trim();
|
||||||
|
wpi::StringRef cidrStr;
|
||||||
|
std::tie(j["networkAddress"], cidrStr) = value.split('/');
|
||||||
|
|
||||||
|
unsigned int cidrInt;
|
||||||
|
if (!cidrStr.getAsInteger(10, cidrInt)) {
|
||||||
|
wpi::SmallString<64> netmaskBuf;
|
||||||
|
j["networkMask"] = CidrToNetmask(cidrInt, netmaskBuf);
|
||||||
|
}
|
||||||
|
} else if (line.startswith("static routers")) {
|
||||||
|
j["networkGateway"] = line.split('=').second.trim();
|
||||||
|
} else if (line.startswith("static domain_name_servers")) {
|
||||||
|
j["networkDNS"] = line.split('=').second.trim();
|
||||||
|
} else if (line.startswith("fallback")) {
|
||||||
|
j["networkApproach"] = "dhcp-fallback";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
52
deps/tools/rpiConfigServer_src/NetworkSettings.h
vendored
Normal file
52
deps/tools/rpiConfigServer_src/NetworkSettings.h
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef RPICONFIGSERVER_NETWORKSETTINGS_H_
|
||||||
|
#define RPICONFIGSERVER_NETWORKSETTINGS_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <wpi/Signal.h>
|
||||||
|
#include <wpi/StringRef.h>
|
||||||
|
#include <wpi/uv/Loop.h>
|
||||||
|
|
||||||
|
namespace wpi {
|
||||||
|
class json;
|
||||||
|
} // namespace wpi
|
||||||
|
|
||||||
|
class NetworkSettings {
|
||||||
|
struct private_init {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NetworkSettings(const private_init&) {}
|
||||||
|
NetworkSettings(const NetworkSettings&) = delete;
|
||||||
|
NetworkSettings& operator=(const NetworkSettings&) = delete;
|
||||||
|
|
||||||
|
void SetLoop(std::shared_ptr<wpi::uv::Loop> loop) {
|
||||||
|
m_loop = std::move(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Mode { kDhcp, kStatic, kDhcpStatic };
|
||||||
|
|
||||||
|
void Set(Mode mode, wpi::StringRef address, wpi::StringRef mask,
|
||||||
|
wpi::StringRef gateway, wpi::StringRef dns,
|
||||||
|
std::function<void(wpi::StringRef)> onFail);
|
||||||
|
|
||||||
|
void UpdateStatus();
|
||||||
|
|
||||||
|
wpi::json GetStatusJson();
|
||||||
|
|
||||||
|
wpi::sig::Signal<const wpi::json&> status;
|
||||||
|
|
||||||
|
static std::shared_ptr<NetworkSettings> GetInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<wpi::uv::Loop> m_loop;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RPICONFIGSERVER_NETWORKSETTINGS_H_
|
|
@ -105,7 +105,7 @@ bool SystemStatus::GetWritable() {
|
||||||
line.split(strs, ' ', -1, false);
|
line.split(strs, ' ', -1, false);
|
||||||
if (strs.size() < 4) continue;
|
if (strs.size() < 4) continue;
|
||||||
|
|
||||||
if (strs[1] == "/") return strs[2].contains("rw");
|
if (strs[1] == "/") return strs[3].contains("rw");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
|
|
||||||
#include <wpi/Signal.h>
|
#include <wpi/Signal.h>
|
||||||
#include <wpi/StringRef.h>
|
#include <wpi/StringRef.h>
|
||||||
|
#include <wpi/uv/Loop.h>
|
||||||
|
|
||||||
namespace wpi {
|
namespace wpi {
|
||||||
class json;
|
class json;
|
||||||
|
|
||||||
namespace uv {
|
namespace uv {
|
||||||
class Buffer;
|
class Buffer;
|
||||||
class Loop;
|
|
||||||
} // namespace uv
|
} // namespace uv
|
||||||
} // namespace wpi
|
} // namespace wpi
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <wpi/uv/Pipe.h>
|
#include <wpi/uv/Pipe.h>
|
||||||
#include <wpi/uv/Process.h>
|
#include <wpi/uv/Process.h>
|
||||||
|
|
||||||
|
#include "NetworkSettings.h"
|
||||||
#include "SystemStatus.h"
|
#include "SystemStatus.h"
|
||||||
#include "VisionStatus.h"
|
#include "VisionStatus.h"
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ struct WebSocketData {
|
||||||
wpi::sig::ScopedConnection sysWritableConn;
|
wpi::sig::ScopedConnection sysWritableConn;
|
||||||
wpi::sig::ScopedConnection visStatusConn;
|
wpi::sig::ScopedConnection visStatusConn;
|
||||||
wpi::sig::ScopedConnection visLogConn;
|
wpi::sig::ScopedConnection visLogConn;
|
||||||
|
wpi::sig::ScopedConnection netSettingsConn;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void SendWsText(wpi::WebSocket& ws, const wpi::json& j) {
|
static void SendWsText(wpi::WebSocket& ws, const wpi::json& j) {
|
||||||
|
@ -118,6 +120,13 @@ void InitWs(wpi::WebSocket& ws) {
|
||||||
if (d->visionLogEnabled) SendWsText(ws, j);
|
if (d->visionLogEnabled) SendWsText(ws, j);
|
||||||
});
|
});
|
||||||
visStatus->UpdateStatus();
|
visStatus->UpdateStatus();
|
||||||
|
|
||||||
|
// send initial network settings
|
||||||
|
auto netSettings = NetworkSettings::GetInstance();
|
||||||
|
auto netSettingsFunc = [&ws](const wpi::json& j) { SendWsText(ws, j); };
|
||||||
|
netSettingsFunc(netSettings->GetStatusJson());
|
||||||
|
data->netSettingsConn =
|
||||||
|
netSettings->status.connect_connection(netSettingsFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
||||||
|
@ -200,5 +209,31 @@ void ProcessWsText(wpi::WebSocket& ws, wpi::StringRef msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (t == "networkSave") {
|
} else if (t == "networkSave") {
|
||||||
|
auto statusFunc = [s = ws.shared_from_this()](wpi::StringRef msg) {
|
||||||
|
SendWsText(*s, {{"type", "status"}, {"message", msg}});
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
NetworkSettings::Mode mode;
|
||||||
|
auto& approach = j.at("networkApproach").get_ref<const std::string&>();
|
||||||
|
if (approach == "dhcp")
|
||||||
|
mode = NetworkSettings::kDhcp;
|
||||||
|
else if (approach == "static")
|
||||||
|
mode = NetworkSettings::kStatic;
|
||||||
|
else if (approach == "dhcp-fallback")
|
||||||
|
mode = NetworkSettings::kDhcpStatic;
|
||||||
|
else {
|
||||||
|
wpi::errs() << "could not understand networkApproach value: "
|
||||||
|
<< approach << '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NetworkSettings::GetInstance()->Set(
|
||||||
|
mode, j.at("networkAddress").get_ref<const std::string&>(),
|
||||||
|
j.at("networkMask").get_ref<const std::string&>(),
|
||||||
|
j.at("networkGateway").get_ref<const std::string&>(),
|
||||||
|
j.at("networkDNS").get_ref<const std::string&>(), statusFunc);
|
||||||
|
} catch (const wpi::json::exception& e) {
|
||||||
|
wpi::errs() << "could not read networkSave value: " << e.what() << '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
deps/tools/rpiConfigServer_src/main.cpp
vendored
2
deps/tools/rpiConfigServer_src/main.cpp
vendored
|
@ -20,6 +20,7 @@
|
||||||
#include <wpi/uv/Udp.h>
|
#include <wpi/uv/Udp.h>
|
||||||
|
|
||||||
#include "MyHttpConnection.h"
|
#include "MyHttpConnection.h"
|
||||||
|
#include "NetworkSettings.h"
|
||||||
#include "SystemStatus.h"
|
#include "SystemStatus.h"
|
||||||
#include "VisionStatus.h"
|
#include "VisionStatus.h"
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
auto loop = uv::Loop::Create();
|
auto loop = uv::Loop::Create();
|
||||||
|
|
||||||
|
NetworkSettings::GetInstance()->SetLoop(loop);
|
||||||
VisionStatus::GetInstance()->SetLoop(loop);
|
VisionStatus::GetInstance()->SetLoop(loop);
|
||||||
|
|
||||||
loop->error.connect(
|
loop->error.connect(
|
||||||
|
|
|
@ -153,11 +153,12 @@ function connect() {
|
||||||
visionLog(msg.data);
|
visionLog(msg.data);
|
||||||
break;
|
break;
|
||||||
case 'networkSettings':
|
case 'networkSettings':
|
||||||
$('#networkApproach').value = msg.networkApproach;
|
$('#networkApproach').val(msg.networkApproach);
|
||||||
$('#networkAddress').value = msg.networkAddress;
|
$('#networkAddress').val(msg.networkAddress);
|
||||||
$('#networkMask').value = msg.networkMask;
|
$('#networkMask').val(msg.networkMask);
|
||||||
$('#networkGateway').value = msg.networkGateway;
|
$('#networkGateway').val(msg.networkGateway);
|
||||||
$('#networkDNS').value = msg.networkDNS;
|
$('#networkDNS').val(msg.networkDNS);
|
||||||
|
updateNetworkSettingsView();
|
||||||
break;
|
break;
|
||||||
case 'systemReadOnly':
|
case 'systemReadOnly':
|
||||||
displayReadOnly();
|
displayReadOnly();
|
||||||
|
@ -268,25 +269,27 @@ function visionLog(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show details when appropriate for network approach
|
// Show details when appropriate for network approach
|
||||||
$('#networkApproach').change(function() {
|
function updateNetworkSettingsView() {
|
||||||
if (this.value == "dhcp") {
|
if ($('#networkApproach').val() === "dhcp") {
|
||||||
$('#networkIpDetails').collapse('hide');
|
$('#networkIpDetails').collapse('hide');
|
||||||
} else {
|
} else {
|
||||||
$('#networkIpDetails').collapse('show');
|
$('#networkIpDetails').collapse('show');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#networkApproach').change(function() {
|
||||||
|
updateNetworkSettingsView();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Network Save button handler
|
// Network Save button handler
|
||||||
$('#networkSave').click(function() {
|
$('#networkSave').click(function() {
|
||||||
var $this = $(this);
|
|
||||||
$this.button('loading');
|
|
||||||
var msg = {
|
var msg = {
|
||||||
type: 'networkSave',
|
type: 'networkSave',
|
||||||
networkApproach: $('#networkApproach').value,
|
networkApproach: $('#networkApproach').val(),
|
||||||
networkAddress: $('#networkAddress').value,
|
networkAddress: $('#networkAddress').val(),
|
||||||
networkMask: $('#networkMask').value,
|
networkMask: $('#networkMask').val(),
|
||||||
networkGateway: $('#networkGateway').value,
|
networkGateway: $('#networkGateway').val(),
|
||||||
networkDNS: $('#networkDNS').value
|
networkDNS: $('#networkDNS').val()
|
||||||
};
|
};
|
||||||
connection.send(JSON.stringify(msg));
|
connection.send(JSON.stringify(msg));
|
||||||
});
|
});
|
||||||
|
|
|
@ -197,7 +197,7 @@
|
||||||
<input type=text" class="form-control" id="networkDNS">
|
<input type=text" class="form-control" id="networkDNS">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button id="networkSave" type="submit" class="btn btn-primary" data-loading-text="<i class='spin' data-feather='loader'></i> Saving" disabled>
|
<button id="networkSave" type="button" class="btn btn-primary" data-loading-text="<i class='spin' data-feather='loader'></i> Saving" disabled>
|
||||||
<span data-feather="save"></span>
|
<span data-feather="save"></span>
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
@ -405,11 +405,11 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-auto mr-auto">
|
<div class="col-auto mr-auto">
|
||||||
<button type="submit" class="btn btn-primary" id="visionSave">
|
<button type="button" class="btn btn-primary" id="visionSave">
|
||||||
<span data-feather="save"></span>
|
<span data-feather="save"></span>
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" class="btn btn-secondary" id="visionDiscard">
|
<button type="button" class="btn btn-secondary" id="visionDiscard">
|
||||||
<span data-feather="x"></span>
|
<span data-feather="x"></span>
|
||||||
Discard Changes
|
Discard Changes
|
||||||
</button>
|
</button>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user