~stacyharper/bonsai

d81687fad39316cff51eb86b84adbd4ba9a5dc6c — Stacy Harper 4 months ago ee267dd
Add logging to bonsaid
4 files changed, 49 insertions(+), 6 deletions(-)

M cmd/bonsaid/cmd.ha
A cmd/bonsaid/logging.ha
M cmd/bonsaid/main.ha
M cmd/bonsaid/socket.ha
M cmd/bonsaid/cmd.ha => cmd/bonsaid/cmd.ha +10 -3
@@ 26,9 26,10 @@ fn strerror(err: cmderror) const str = {
};

fn exec(serv: *server, client: *client, cmd: str) (void | servererror) = {
	// TODO: Better logging of client activity
	log::printfln("executing command: '{}'", cmd);
	const args = match (shlex::split(cmd)) {
	case shlex::syntaxerr =>
		log::println("error invalid command syntax", cmd);
		writefmt(client, "error Invalid command syntax");
		return;
	case let items: []str =>


@@ 36,6 37,7 @@ fn exec(serv: *server, client: *client, cmd: str) (void | servererror) = {
	};
	defer strings::freeall(args);
	if (len(args) == 0) {
		log::println("error invalid command syntax");
		writefmt(client, "error Invalid command syntax");
		return;
	};


@@ 48,19 50,22 @@ fn exec(serv: *server, client: *client, cmd: str) (void | servererror) = {
	case "quit" =>
		yield &exec_quit;
	case =>
		writefmt(client, "error Unknown command");
		log::println("error unknown command");
		writefmt(client, "error unknown command");
		return;
	};

	match (cmd(serv, client, args[1..])) {
	case let err: servererror =>
		writefmt(client, "error Internal error");
		log::println("error internal error:", strerror(err));
		writefmt(client, "error internal error");
		return err;
	case void => yield;
	};
};

fn exec_event(serv: *server, client: *client, args: []str) (void | cmderror) = {
	log::println("executing event command");
	bonsai::state_forward(
		&serv.state,
		bonsai::action_event_received {


@@ 75,6 80,7 @@ fn exec_event(serv: *server, client: *client, args: []str) (void | cmderror) = {
};

fn exec_context(serv: *server, client: *client, args: []str) (void | cmderror) = {
	log::println("executing context command");
	let context_elements: []bonsai::context_element = [];
	for (let i = 0z; i < len(args); i += 1) {
		append(


@@ 97,6 103,7 @@ fn exec_context(serv: *server, client: *client, args: []str) (void | cmderror) =
};

fn exec_quit(serv: *server, client: *client, args: []str) (void | cmderror) = {
	log::println("executing quit command");
	if (!serv.daemonized) {
		writefmt(client, "error Server is not damonized, use a service manager");
		return;

A cmd/bonsaid/logging.ha => cmd/bonsaid/logging.ha +18 -0
@@ 0,0 1,18 @@

use fmt;
use log;

fn null_logger_println(logger: *log::logger, fields: fmt::formattable...) void = {
	return;
};

fn null_logger_printfln(logger: *log::logger, fmt: str, fields: fmt::field...) void = {
	return;
};

fn null_logger() log::logger = {
	return log::logger {
		println = &null_logger_println,
		printfln = &null_logger_printfln,
	};
};

M cmd/bonsaid/main.ha => cmd/bonsaid/main.ha +13 -1
@@ 14,17 14,21 @@ use fs;
export fn main() void = {
	const cmd = getopt::parse(
		os::args,
		('v', "enable verbose logging"),
		('t', "file", "json transition file source"),
		('D', "daemonize (fork) after startup")
	);
	defer getopt::finish(&cmd);

	let daemonize = false;
	let verbose = false;
	let json_file_path: (void | str) = void;

	for (let i = 0z; i < len(cmd.opts); i += 1) {
		const opt = &cmd.opts[i];
		switch (opt.0) {
		case 'v' =>
			verbose = true;
		case 'D' =>
			daemonize = true;
		case 't' =>


@@ 33,6 37,10 @@ export fn main() void = {
		};
	};

	if (verbose == false) {
		log::setlogger(&null_logger());
	};

	if (json_file_path is void) {
		fmt::fatal("You have to provide a json tree");
	};


@@ 53,6 61,8 @@ export fn main() void = {
		fmt::fatal("Failed to parse the json:", bonsai::strerror(err));
	};

	log::println("json file loaded");

	signal::block(signal::SIGINT, signal::SIGTERM);
	const sigfd = signal::signalfd(signal::SIGINT, signal::SIGTERM)!;
	defer io::close(sigfd)!;


@@ 67,12 77,14 @@ export fn main() void = {

	const server = bind(sigfd, daemonize, state);

	log::println("server binded");

	if (daemonize) {
		match (exec::fork()) {
		case let err: exec::error =>
			fmt::fatal("exec failed:", exec::strerror(err));
		case int =>
			log::println("Continuing in child process");
			log::println("continuing in child process");
			os::exit(0);
		case void =>
			io::close(os::stdin)!;

M cmd/bonsaid/socket.ha => cmd/bonsaid/socket.ha +8 -2
@@ 110,13 110,16 @@ fn dispatch(serv: *server) bool = {
	match (poll::poll(serv.pollfd, poll::INDEF)) {
	case uint =>
		if (serv.pollfd[0].revents & event::POLLIN != 0) {
			log::println("socket client entrance");
			accept(serv);
		};
		if (serv.pollfd[1].revents & event::POLLIN != 0) {
			log::println("signal received");
			signal::read(serv.signalfd)!;
			return false;
		};
		if (serv.pollfd[2].revents & event::POLLIN != 0) {
			log::println("child waiter talks");
			const synced = bonsai::sync_back_wait_child(&serv.state, false);

			const wait_pipes = serv.state.wait_pipes as (io::file, io::file);


@@ 124,6 127,7 @@ fn dispatch(serv: *server) bool = {
			io::close(wait_pipes.1)!;

			if (synced) {
				log::println("child waiter updated the state. moving forward...");
				bonsai::state_forward_available_transitions(&serv.state);
			};



@@ 131,12 135,14 @@ fn dispatch(serv: *server) bool = {
			const wait_pipes = serv.state.wait_pipes as (io::file, io::file);

			if (synced) {
				log::println("start eventually new delay");
				bonsai::trigger_delay_transition(&serv.state);
			};

			serv.pollfd[2].fd = wait_pipes.0;
		};
		for (let i = POLLFD_RESERVED; i < len(serv.pollfd); i += 1) {
			log::println("socket client conversation...");
			dispatch_client(serv, &serv.clients[i - POLLFD_RESERVED]);
			if (serv.disconnected) {
				// Restart loop on client disconnect


@@ 162,7 168,7 @@ fn accept(serv: *server) void = {
		log::fatal(net::strerror(err));
	};
	if (len(serv.clients) >= MAX_CLIENTS) {
		log::println("Max clients exceeded; dropping client");
		log::println("max clients exceeded; dropping client");
		io::close(sock)!;
		return;
	};


@@ 235,7 241,7 @@ fn client_readable(serv: *server, client: *client) void = {
		defer delete(client.rbuf[..i+1]);
		match (exec(serv, client, line)) {
			case let err: servererror =>
				log::printfln("Error processing user command: {}",
				log::printfln("error processing user command: {}",
					strerror(err));
			case void =>
				yield;