|
|
@ -32,9 +32,6 @@ uireader: std.fs.File.Reader, // ngui stdout
|
|
|
|
uiwriter: std.fs.File.Writer, // ngui stdin
|
|
|
|
uiwriter: std.fs.File.Writer, // ngui stdin
|
|
|
|
wpa_ctrl: types.WpaControl, // guarded by mu once start'ed
|
|
|
|
wpa_ctrl: types.WpaControl, // guarded by mu once start'ed
|
|
|
|
|
|
|
|
|
|
|
|
/// used only in comm thread; move under mu when no longer the case
|
|
|
|
|
|
|
|
screenstate: enum { locked, unlocked },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// guards all the fields below to sync between pub fns and main/poweroff threads.
|
|
|
|
/// guards all the fields below to sync between pub fns and main/poweroff threads.
|
|
|
|
mu: std.Thread.Mutex = .{},
|
|
|
|
mu: std.Thread.Mutex = .{},
|
|
|
|
|
|
|
|
|
|
|
@ -121,7 +118,7 @@ const Error = error{
|
|
|
|
|
|
|
|
|
|
|
|
const InitOpt = struct {
|
|
|
|
const InitOpt = struct {
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
conf: Config,
|
|
|
|
confpath: []const u8,
|
|
|
|
uir: std.fs.File.Reader,
|
|
|
|
uir: std.fs.File.Reader,
|
|
|
|
uiw: std.fs.File.Writer,
|
|
|
|
uiw: std.fs.File.Writer,
|
|
|
|
wpa: [:0]const u8,
|
|
|
|
wpa: [:0]const u8,
|
|
|
@ -141,14 +138,15 @@ pub fn init(opt: InitOpt) !Daemon {
|
|
|
|
try svlist.append(sys.Service.init(opt.allocator, sys.Service.LND, .{ .stop_wait_sec = 600 }));
|
|
|
|
try svlist.append(sys.Service.init(opt.allocator, sys.Service.LND, .{ .stop_wait_sec = 600 }));
|
|
|
|
try svlist.append(sys.Service.init(opt.allocator, sys.Service.BITCOIND, .{ .stop_wait_sec = 600 }));
|
|
|
|
try svlist.append(sys.Service.init(opt.allocator, sys.Service.BITCOIND, .{ .stop_wait_sec = 600 }));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const conf = try Config.init(opt.allocator, opt.confpath);
|
|
|
|
|
|
|
|
errdefer conf.deinit();
|
|
|
|
return .{
|
|
|
|
return .{
|
|
|
|
.allocator = opt.allocator,
|
|
|
|
.allocator = opt.allocator,
|
|
|
|
.conf = opt.conf,
|
|
|
|
.conf = conf,
|
|
|
|
.uireader = opt.uir,
|
|
|
|
.uireader = opt.uir,
|
|
|
|
.uiwriter = opt.uiw,
|
|
|
|
.uiwriter = opt.uiw,
|
|
|
|
.wpa_ctrl = try types.WpaControl.open(opt.wpa),
|
|
|
|
.wpa_ctrl = try types.WpaControl.open(opt.wpa),
|
|
|
|
.state = .stopped,
|
|
|
|
.state = .stopped,
|
|
|
|
.screenstate = if (opt.conf.data.slock != null) .locked else .unlocked,
|
|
|
|
|
|
|
|
.services = .{ .list = try svlist.toOwnedSlice() },
|
|
|
|
.services = .{ .list = try svlist.toOwnedSlice() },
|
|
|
|
// send persisted settings immediately on start
|
|
|
|
// send persisted settings immediately on start
|
|
|
|
.want_settings = true,
|
|
|
|
.want_settings = true,
|
|
|
@ -170,6 +168,7 @@ pub fn init(opt: InitOpt) !Daemon {
|
|
|
|
pub fn deinit(self: *Daemon) void {
|
|
|
|
pub fn deinit(self: *Daemon) void {
|
|
|
|
self.wpa_ctrl.close() catch |err| logger.err("deinit: wpa_ctrl.close: {any}", .{err});
|
|
|
|
self.wpa_ctrl.close() catch |err| logger.err("deinit: wpa_ctrl.close: {any}", .{err});
|
|
|
|
self.services.deinit(self.allocator);
|
|
|
|
self.services.deinit(self.allocator);
|
|
|
|
|
|
|
|
self.conf.deinit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// start launches daemon threads and returns immediately.
|
|
|
|
/// start launches daemon threads and returns immediately.
|
|
|
@ -185,7 +184,6 @@ pub fn start(self: *Daemon) !void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try self.wpa_ctrl.attach();
|
|
|
|
try self.wpa_ctrl.attach();
|
|
|
|
self.want_stop = false;
|
|
|
|
|
|
|
|
errdefer {
|
|
|
|
errdefer {
|
|
|
|
self.wpa_ctrl.detach() catch {};
|
|
|
|
self.wpa_ctrl.detach() catch {};
|
|
|
|
self.want_stop = true;
|
|
|
|
self.want_stop = true;
|
|
|
@ -226,6 +224,7 @@ pub fn wait(self: *Daemon) void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.wpa_ctrl.detach() catch |err| logger.err("wait: wpa_ctrl.detach: {any}", .{err});
|
|
|
|
self.wpa_ctrl.detach() catch |err| logger.err("wait: wpa_ctrl.detach: {any}", .{err});
|
|
|
|
|
|
|
|
self.want_stop = false;
|
|
|
|
self.state = .stopped;
|
|
|
|
self.state = .stopped;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -238,16 +237,8 @@ fn standby(self: *Daemon) !void {
|
|
|
|
.stopped, .poweroff => return Error.InvalidState,
|
|
|
|
.stopped, .poweroff => return Error.InvalidState,
|
|
|
|
.wallet_reset => return Error.WalletResetActive,
|
|
|
|
.wallet_reset => return Error.WalletResetActive,
|
|
|
|
.running => {
|
|
|
|
.running => {
|
|
|
|
const has_lock = self.conf.safeReadOnly(struct {
|
|
|
|
|
|
|
|
fn f(data: Config.Data, _: Config.StaticData) bool {
|
|
|
|
|
|
|
|
return data.slock != null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}.f);
|
|
|
|
|
|
|
|
if (has_lock) {
|
|
|
|
|
|
|
|
self.screenstate = .locked;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
self.state = .standby;
|
|
|
|
|
|
|
|
try screen.backlight(.off);
|
|
|
|
try screen.backlight(.off);
|
|
|
|
|
|
|
|
self.state = .standby;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -347,7 +338,6 @@ fn mainThreadLoopCycle(self: *Daemon) !void {
|
|
|
|
fn f(conf: Config.Data, static: Config.StaticData) bool {
|
|
|
|
fn f(conf: Config.Data, static: Config.StaticData) bool {
|
|
|
|
const msg: comm.Message.Settings = .{
|
|
|
|
const msg: comm.Message.Settings = .{
|
|
|
|
.hostname = static.hostname,
|
|
|
|
.hostname = static.hostname,
|
|
|
|
.slock_enabled = conf.slock != null,
|
|
|
|
|
|
|
|
.sysupdates = .{
|
|
|
|
.sysupdates = .{
|
|
|
|
.channel = switch (conf.syschannel) {
|
|
|
|
.channel = switch (conf.syschannel) {
|
|
|
|
.dev => .edge,
|
|
|
|
.dev => .edge,
|
|
|
@ -384,7 +374,6 @@ fn mainThreadLoopCycle(self: *Daemon) !void {
|
|
|
|
|
|
|
|
|
|
|
|
// onchain bitcoin stats
|
|
|
|
// onchain bitcoin stats
|
|
|
|
if (self.want_onchain_report or self.bitcoin_timer.read() > self.onchain_report_interval) {
|
|
|
|
if (self.want_onchain_report or self.bitcoin_timer.read() > self.onchain_report_interval) {
|
|
|
|
// TODO: this takes too long; run in a separate thread
|
|
|
|
|
|
|
|
if (self.sendOnchainReport()) {
|
|
|
|
if (self.sendOnchainReport()) {
|
|
|
|
self.bitcoin_timer.reset();
|
|
|
|
self.bitcoin_timer.reset();
|
|
|
|
self.want_onchain_report = false;
|
|
|
|
self.want_onchain_report = false;
|
|
|
@ -396,7 +385,6 @@ fn mainThreadLoopCycle(self: *Daemon) !void {
|
|
|
|
// lightning stats
|
|
|
|
// lightning stats
|
|
|
|
if (self.state != .wallet_reset) {
|
|
|
|
if (self.state != .wallet_reset) {
|
|
|
|
if (self.want_lnd_report or self.lnd_timer.read() > self.lnd_report_interval) {
|
|
|
|
if (self.want_lnd_report or self.lnd_timer.read() > self.lnd_report_interval) {
|
|
|
|
// TODO: this takes too long; run in a separate thread
|
|
|
|
|
|
|
|
if (self.sendLightningReport()) {
|
|
|
|
if (self.sendLightningReport()) {
|
|
|
|
self.lnd_timer.reset();
|
|
|
|
self.lnd_timer.reset();
|
|
|
|
self.want_lnd_report = false;
|
|
|
|
self.want_lnd_report = false;
|
|
|
@ -451,13 +439,9 @@ fn commThreadLoop(self: *Daemon) void {
|
|
|
|
self.reportNetworkStatus(.{ .scan = req.scan });
|
|
|
|
self.reportNetworkStatus(.{ .scan = req.scan });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.wifi_connect => |req| {
|
|
|
|
.wifi_connect => |req| {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
self.startConnectWifi(req.ssid, req.password) catch |err| {
|
|
|
|
self.startConnectWifi(req.ssid, req.password) catch |err| {
|
|
|
|
logger.err("startConnectWifi: {any}", .{err});
|
|
|
|
logger.err("startConnectWifi: {any}", .{err});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("refusing wifi connect: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.standby => {
|
|
|
|
.standby => {
|
|
|
|
logger.info("entering standby mode", .{});
|
|
|
|
logger.info("entering standby mode", .{});
|
|
|
@ -468,68 +452,38 @@ fn commThreadLoop(self: *Daemon) void {
|
|
|
|
self.wakeup() catch |err| logger.err("nd.wakeup: {any}", .{err});
|
|
|
|
self.wakeup() catch |err| logger.err("nd.wakeup: {any}", .{err});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.switch_sysupdates => |chan| {
|
|
|
|
.switch_sysupdates => |chan| {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
logger.info("switching sysupdates channel to {s}", .{@tagName(chan)});
|
|
|
|
logger.info("switching sysupdates channel to {s}", .{@tagName(chan)});
|
|
|
|
self.switchSysupdates(chan) catch |err| {
|
|
|
|
self.switchSysupdates(chan) catch |err| {
|
|
|
|
logger.err("switchSysupdates: {any}", .{err});
|
|
|
|
logger.err("switchSysupdates: {any}", .{err});
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("ignoring sysupdates switch: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.set_nodename => |newname| {
|
|
|
|
.set_nodename => |newname| {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
self.setNodename(newname) catch |err| {
|
|
|
|
self.setNodename(newname) catch |err| {
|
|
|
|
logger.err("setNodename: {!}", .{err});
|
|
|
|
logger.err("setNodename: {!}", .{err});
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("ignoring nodename change: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.lightning_genseed => {
|
|
|
|
.lightning_genseed => {
|
|
|
|
// non commital: ok even if the screen is locked
|
|
|
|
|
|
|
|
self.generateWalletSeed() catch |err| {
|
|
|
|
self.generateWalletSeed() catch |err| {
|
|
|
|
logger.err("generateWalletSeed: {!}", .{err});
|
|
|
|
logger.err("generateWalletSeed: {!}", .{err});
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
};
|
|
|
|
};
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.lightning_init_wallet => |req| {
|
|
|
|
.lightning_init_wallet => |req| {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
self.initWallet(req) catch |err| {
|
|
|
|
self.initWallet(req) catch |err| {
|
|
|
|
logger.err("initWallet: {!}", .{err});
|
|
|
|
logger.err("initWallet: {!}", .{err});
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("ignoring lnd wallet init: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.lightning_get_ctrlconn => {
|
|
|
|
.lightning_get_ctrlconn => {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
self.sendLightningPairingConn() catch |err| {
|
|
|
|
self.sendLightningPairingConn() catch |err| {
|
|
|
|
logger.err("sendLightningPairingConn: {!}", .{err});
|
|
|
|
logger.err("sendLightningPairingConn: {!}", .{err});
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
// TODO: send err back to ngui
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("refusing to give out lnd pairing: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.lightning_reset => {
|
|
|
|
.lightning_reset => {
|
|
|
|
if (self.screenstate != .locked) {
|
|
|
|
self.resetLndNode() catch |err| logger.err("resetLndNode: {!}", .{err});
|
|
|
|
self.resetLndNode() catch |err| logger.err("resetLndNode: {!}", .{err});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.warn("refusing lnd reset: screen is locked", .{});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.slock_set_pincode => |pincode_or_null| {
|
|
|
|
|
|
|
|
self.conf.setSlockPin(pincode_or_null) catch |err| logger.err("conf.setSlockPin: {!}", .{err});
|
|
|
|
|
|
|
|
self.mu.lock();
|
|
|
|
|
|
|
|
self.want_settings = true;
|
|
|
|
|
|
|
|
self.mu.unlock();
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.unlock_screen => |pincode| {
|
|
|
|
|
|
|
|
self.unlockScreen(pincode) catch |err| logger.err("unlockScreen: {!}", .{err});
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
else => |v| logger.warn("unhandled msg tag {s}", .{@tagName(v)}),
|
|
|
|
else => |v| logger.warn("unhandled msg tag {s}", .{@tagName(v)}),
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -542,29 +496,9 @@ fn commThreadLoop(self: *Daemon) void {
|
|
|
|
logger.info("exiting comm thread loop", .{});
|
|
|
|
logger.info("exiting comm thread loop", .{});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// all callers must belong to comm thread due to self.screenstate access.
|
|
|
|
|
|
|
|
fn unlockScreen(self: *Daemon, pincode: []const u8) !void {
|
|
|
|
|
|
|
|
const pindup = try self.allocator.dupe(u8, pincode);
|
|
|
|
|
|
|
|
defer self.allocator.free(pindup);
|
|
|
|
|
|
|
|
// TODO: slow down
|
|
|
|
|
|
|
|
self.conf.verifySlockPin(pindup) catch |err| {
|
|
|
|
|
|
|
|
if (!builtin.is_test) { // logging err makes some tests fail
|
|
|
|
|
|
|
|
logger.err("verifySlockPin: {!}", .{err});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const errmsg: comm.Message = .{ .screen_unlock_result = .{
|
|
|
|
|
|
|
|
.ok = false,
|
|
|
|
|
|
|
|
.err = if (err == error.IncorrectSlockPin) "incorrect pin code" else "unlock failed",
|
|
|
|
|
|
|
|
} };
|
|
|
|
|
|
|
|
return comm.write(self.allocator, self.uiwriter, errmsg);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const ok: comm.Message = .{ .screen_unlock_result = .{ .ok = true } };
|
|
|
|
|
|
|
|
comm.write(self.allocator, self.uiwriter, ok) catch |err| logger.err("{!}", .{err});
|
|
|
|
|
|
|
|
self.screenstate = .unlocked;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// sends poweroff progress to uiwriter in comm.Message.PoweroffProgress format.
|
|
|
|
/// sends poweroff progress to uiwriter in comm.Message.PoweroffProgress format.
|
|
|
|
fn sendPoweroffReport(self: *Daemon) !void {
|
|
|
|
fn sendPoweroffReport(self: *Daemon) !void {
|
|
|
|
const svstat = try self.allocator.alloc(comm.Message.PoweroffProgress.Service, self.services.list.len);
|
|
|
|
var svstat = try self.allocator.alloc(comm.Message.PoweroffProgress.Service, self.services.list.len);
|
|
|
|
defer self.allocator.free(svstat);
|
|
|
|
defer self.allocator.free(svstat);
|
|
|
|
for (self.services.list, svstat) |*sv, *stat| {
|
|
|
|
for (self.services.list, svstat) |*sv, *stat| {
|
|
|
|
stat.* = .{
|
|
|
|
stat.* = .{
|
|
|
@ -964,7 +898,7 @@ fn processLndReportError(self: *Daemon, err: anyerror) !void {
|
|
|
|
error.FileNotFound, // tls cert file missing, not re-generated by lnd yet
|
|
|
|
error.FileNotFound, // tls cert file missing, not re-generated by lnd yet
|
|
|
|
=> return comm.write(self.allocator, self.uiwriter, msg_starting),
|
|
|
|
=> return comm.write(self.allocator, self.uiwriter, msg_starting),
|
|
|
|
// old tls cert, refused by our http client
|
|
|
|
// old tls cert, refused by our http client
|
|
|
|
std.http.Client.ConnectTcpError.TlsInitializationFailed => {
|
|
|
|
std.http.Client.ConnectUnproxiedError.TlsInitializationFailed => {
|
|
|
|
try self.resetLndTlsUnguarded();
|
|
|
|
try self.resetLndTlsUnguarded();
|
|
|
|
return error.LndReportRetryLater;
|
|
|
|
return error.LndReportRetryLater;
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -1008,7 +942,7 @@ fn sendLightningPairingConn(self: *Daemon) !void {
|
|
|
|
defer self.allocator.free(tor_rpc);
|
|
|
|
defer self.allocator.free(tor_rpc);
|
|
|
|
const tor_http = try self.conf.lndConnectWaitMacaroonFile(self.allocator, .tor_http);
|
|
|
|
const tor_http = try self.conf.lndConnectWaitMacaroonFile(self.allocator, .tor_http);
|
|
|
|
defer self.allocator.free(tor_http);
|
|
|
|
defer self.allocator.free(tor_http);
|
|
|
|
const conn: comm.Message.LightningCtrlConn = &.{
|
|
|
|
var conn: comm.Message.LightningCtrlConn = &.{
|
|
|
|
.{ .url = tor_rpc, .typ = .lnd_rpc, .perm = .admin },
|
|
|
|
.{ .url = tor_rpc, .typ = .lnd_rpc, .perm = .admin },
|
|
|
|
.{ .url = tor_http, .typ = .lnd_http, .perm = .admin },
|
|
|
|
.{ .url = tor_http, .typ = .lnd_http, .perm = .admin },
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1259,7 +1193,7 @@ fn setNodenameInternal(self: *Daemon, newname: []const u8) !void {
|
|
|
|
/// replaces whitespace with space literal and ignores ascii control chars.
|
|
|
|
/// replaces whitespace with space literal and ignores ascii control chars.
|
|
|
|
/// caller owns returned value.
|
|
|
|
/// caller owns returned value.
|
|
|
|
fn allocSanitizeNodename(allocator: std.mem.Allocator, name: []const u8) ![]const u8 {
|
|
|
|
fn allocSanitizeNodename(allocator: std.mem.Allocator, name: []const u8) ![]const u8 {
|
|
|
|
if (name.len == 0 or try std.unicode.utf8CountCodepoints(name) > std.posix.HOST_NAME_MAX) {
|
|
|
|
if (name.len == 0 or try std.unicode.utf8CountCodepoints(name) > std.os.HOST_NAME_MAX) {
|
|
|
|
return error.InvalidNodenameLength;
|
|
|
|
return error.InvalidNodenameLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var sanitized = try std.ArrayList(u8).initCapacity(allocator, name.len);
|
|
|
|
var sanitized = try std.ArrayList(u8).initCapacity(allocator, name.len);
|
|
|
@ -1283,18 +1217,17 @@ fn allocSanitizeNodename(allocator: std.mem.Allocator, name: []const u8) ![]cons
|
|
|
|
return allocator.dupe(u8, trimmed);
|
|
|
|
return allocator.dupe(u8, trimmed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
test "daemon: start-stop" {
|
|
|
|
test "start-stop" {
|
|
|
|
const t = std.testing;
|
|
|
|
const t = std.testing;
|
|
|
|
|
|
|
|
|
|
|
|
const pipe = try types.IoPipe.create();
|
|
|
|
const pipe = try types.IoPipe.create();
|
|
|
|
var daemon = try Daemon.init(.{
|
|
|
|
var daemon = try Daemon.init(.{
|
|
|
|
.allocator = t.allocator,
|
|
|
|
.allocator = t.allocator,
|
|
|
|
.conf = try dummyTestConfig(),
|
|
|
|
.confpath = "/unused.json",
|
|
|
|
.uir = pipe.reader(),
|
|
|
|
.uir = pipe.reader(),
|
|
|
|
.uiw = pipe.writer(),
|
|
|
|
.uiw = pipe.writer(),
|
|
|
|
.wpa = "/dev/null",
|
|
|
|
.wpa = "/dev/null",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
defer daemon.conf.deinit();
|
|
|
|
|
|
|
|
daemon.want_settings = false;
|
|
|
|
daemon.want_settings = false;
|
|
|
|
daemon.want_network_report = false;
|
|
|
|
daemon.want_network_report = false;
|
|
|
|
daemon.want_onchain_report = false;
|
|
|
|
daemon.want_onchain_report = false;
|
|
|
@ -1329,7 +1262,7 @@ test "daemon: start-stop" {
|
|
|
|
try t.expect(!daemon.wpa_ctrl.opened);
|
|
|
|
try t.expect(!daemon.wpa_ctrl.opened);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
test "daemon: start-poweroff" {
|
|
|
|
test "start-poweroff" {
|
|
|
|
const t = std.testing;
|
|
|
|
const t = std.testing;
|
|
|
|
const tt = @import("../test.zig");
|
|
|
|
const tt = @import("../test.zig");
|
|
|
|
|
|
|
|
|
|
|
@ -1342,7 +1275,7 @@ test "daemon: start-poweroff" {
|
|
|
|
const gui_reader = gui_stdin.reader();
|
|
|
|
const gui_reader = gui_stdin.reader();
|
|
|
|
var daemon = try Daemon.init(.{
|
|
|
|
var daemon = try Daemon.init(.{
|
|
|
|
.allocator = arena,
|
|
|
|
.allocator = arena,
|
|
|
|
.conf = try dummyTestConfig(),
|
|
|
|
.confpath = "/unused.json",
|
|
|
|
.uir = gui_stdout.reader(),
|
|
|
|
.uir = gui_stdout.reader(),
|
|
|
|
.uiw = gui_stdin.writer(),
|
|
|
|
.uiw = gui_stdin.writer(),
|
|
|
|
.wpa = "/dev/null",
|
|
|
|
.wpa = "/dev/null",
|
|
|
@ -1353,7 +1286,6 @@ test "daemon: start-poweroff" {
|
|
|
|
daemon.want_lnd_report = false;
|
|
|
|
daemon.want_lnd_report = false;
|
|
|
|
defer {
|
|
|
|
defer {
|
|
|
|
daemon.deinit();
|
|
|
|
daemon.deinit();
|
|
|
|
daemon.conf.deinit();
|
|
|
|
|
|
|
|
gui_stdin.close();
|
|
|
|
gui_stdin.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1394,78 +1326,3 @@ test "daemon: start-poweroff" {
|
|
|
|
// need custom runner to set up a global registry for child processes.
|
|
|
|
// need custom runner to set up a global registry for child processes.
|
|
|
|
// https://github.com/ziglang/zig/pull/13411
|
|
|
|
// https://github.com/ziglang/zig/pull/13411
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
test "daemon: screen unlock" {
|
|
|
|
|
|
|
|
const t = std.testing;
|
|
|
|
|
|
|
|
const tt = @import("../test.zig");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var arena_alloc = std.heap.ArenaAllocator.init(t.allocator);
|
|
|
|
|
|
|
|
defer arena_alloc.deinit();
|
|
|
|
|
|
|
|
const arena = arena_alloc.allocator();
|
|
|
|
|
|
|
|
var tmp = try tt.TempDir.create();
|
|
|
|
|
|
|
|
defer tmp.cleanup();
|
|
|
|
|
|
|
|
const correct_pin = "12345";
|
|
|
|
|
|
|
|
var ndconf = try Config.init(t.allocator, try tmp.join(&.{"ndconf.json"}));
|
|
|
|
|
|
|
|
defer ndconf.deinit();
|
|
|
|
|
|
|
|
try ndconf.setSlockPin(correct_pin);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const gui_stdin = try types.IoPipe.create();
|
|
|
|
|
|
|
|
const gui_stdout = try types.IoPipe.create();
|
|
|
|
|
|
|
|
const gui_reader = gui_stdin.reader();
|
|
|
|
|
|
|
|
var daemon = try Daemon.init(.{
|
|
|
|
|
|
|
|
.allocator = arena,
|
|
|
|
|
|
|
|
.conf = ndconf,
|
|
|
|
|
|
|
|
.uir = gui_stdout.reader(),
|
|
|
|
|
|
|
|
.uiw = gui_stdin.writer(),
|
|
|
|
|
|
|
|
.wpa = "/dev/null",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
defer {
|
|
|
|
|
|
|
|
daemon.deinit();
|
|
|
|
|
|
|
|
gui_stdin.close();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
daemon.want_settings = false;
|
|
|
|
|
|
|
|
daemon.want_network_report = false;
|
|
|
|
|
|
|
|
daemon.want_onchain_report = false;
|
|
|
|
|
|
|
|
daemon.want_lnd_report = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try daemon.start();
|
|
|
|
|
|
|
|
try t.expect(daemon.screenstate == .locked);
|
|
|
|
|
|
|
|
try comm.write(arena, gui_stdout.writer(), .{ .unlock_screen = "000" });
|
|
|
|
|
|
|
|
try comm.write(arena, gui_stdout.writer(), .{ .unlock_screen = correct_pin });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const msg = try comm.read(arena, gui_reader);
|
|
|
|
|
|
|
|
try t.expect(!msg.value.screen_unlock_result.ok);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const msg = try comm.read(arena, gui_reader);
|
|
|
|
|
|
|
|
try t.expect(msg.value.screen_unlock_result.ok);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
daemon.stop();
|
|
|
|
|
|
|
|
gui_stdout.close();
|
|
|
|
|
|
|
|
daemon.wait();
|
|
|
|
|
|
|
|
try t.expect(daemon.screenstate == .unlocked);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn dummyTestConfig() !Config {
|
|
|
|
|
|
|
|
const talloc = std.testing.allocator;
|
|
|
|
|
|
|
|
const arena = try talloc.create(std.heap.ArenaAllocator);
|
|
|
|
|
|
|
|
arena.* = std.heap.ArenaAllocator.init(talloc);
|
|
|
|
|
|
|
|
return Config{
|
|
|
|
|
|
|
|
.arena = arena,
|
|
|
|
|
|
|
|
.confpath = "/dummy.conf",
|
|
|
|
|
|
|
|
.data = .{
|
|
|
|
|
|
|
|
.slock = null,
|
|
|
|
|
|
|
|
.syschannel = .master,
|
|
|
|
|
|
|
|
.syscronscript = "",
|
|
|
|
|
|
|
|
.sysrunscript = "",
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.static = .{
|
|
|
|
|
|
|
|
.hostname = "testhost",
|
|
|
|
|
|
|
|
.lnd_user = null,
|
|
|
|
|
|
|
|
.lnd_tor_hostname = null,
|
|
|
|
|
|
|
|
.bitcoind_rpc_pass = null,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|