~sircmpwn/harebot

ref: 319ea157cb027ca80ccfad4271b53c24bf69be23 harebot/main.ha -rw-r--r-- 1.9 KiB
319ea157Drew DeVault Update match..case syntax 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use fmt;
use hare::module;
use hare::parse;
use io;
use net::irc;
use os;
use shlex;
use strings;

type state = struct {
	conn: *irc::client,
	chan: *irc::channel,
};

type error = !(parse::error | module::error);

export fn main() void = {
	// TODO: Configurable, I guess
	let network = "irc.libera.chat";
	let channel = "#hare";
	const conf = irc::config {
		nick = "harebot",
		user = "harebot",
		realname = "Hare IRC bot",
		logfn = &logmsg,
		...
	};

	let conn = match (irc::dial(network, &conf)) {
	case let conn: *irc::client =>
		yield conn;
	case let err: irc::error =>
		fmt::fatal("Failed to dial IRC server: {}",
			irc::strerror(err));
	};
	defer irc::close(conn);

	const chan = irc::join(conn, channel)!;
	let state = state {
		conn = conn,
		chan = chan,
	};

	const support = irc::supports(conn);
	fmt::printfln("Connected to {}", support.network)!;
	irc::on(conn, "PRIVMSG", &handle_privmsg, &state);

	for (!(irc::dispatch(conn)! is io::EOF)) void;
};

fn logmsg(state: nullable *void, party: irc::party, msg: *irc::message) void = {
	switch (party) {
	case irc::party::SERVER =>
		fmt::print("<= ")!;
	case irc::party::CLIENT =>
		fmt::print("-> ")!;
	};
	if (msg.command == "PASS") {
		fmt::println("PASS <redacted>")!;
	} else {
		irc::serialize(os::stdout, msg)!;
	};
};

fn handle_privmsg(
	user: nullable *void,
	msg: const *irc::message,
) (void | irc::error) = {
	let state = user: *state;
	const cmd = match (shlex::split(msg.params[1])) {
	case let items: []str =>
		yield items;
	case shlex::syntaxerr =>
		return;
	};
	defer strings::freeall(cmd);
	if (len(cmd) == 0) {
		return;
	};

	let handler = switch (cmd[0]) {
	case "!haredoc" =>
		yield &handle_haredoc;
	case =>
		return;
	};

	match (handler(state, msg, cmd)) {
	case void => void;
	case let err: parse::error =>
		irc::privmsg(state.conn, parse::strerror(err), msg.params[0])!;
	case let err: module::error =>
		irc::privmsg(state.conn, module::strerror(err), msg.params[0])!;
	};
};