140 lines
4.2 KiB
Zig
140 lines
4.2 KiB
Zig
const std = @import("std");
|
|
const zigeru = @import("zigeru");
|
|
const zircon = @import("zircon");
|
|
|
|
const Bot = zigeru.bot.Bot;
|
|
const BotCommand = zigeru.bot.Command;
|
|
|
|
var debug_allocator = std.heap.DebugAllocator(.{}).init;
|
|
|
|
pub fn main() !void {
|
|
const allocator = debug_allocator.allocator();
|
|
defer _ = debug_allocator.deinit();
|
|
|
|
var channels: [0][]const u8 = .{};
|
|
|
|
// Create a zircon.Client with a given configuration.
|
|
var client = try zircon.Client.init(allocator, .{
|
|
.user = "eru",
|
|
.nick = "eru",
|
|
.real_name = "Eru (zigeru) bot",
|
|
.server = "irc.dtek.se",
|
|
.port = 6697,
|
|
.tls = true,
|
|
.channels = &channels,
|
|
});
|
|
defer client.deinit();
|
|
|
|
var bot_adapter = try BotAdapter.init(allocator);
|
|
const adapter = bot_adapter.adapter();
|
|
|
|
// Connect to the IRC server and perform registration.
|
|
try client.connect();
|
|
try client.register();
|
|
try client.join("#eru-tests");
|
|
|
|
// Enter the main loop that keeps reading incoming IRC messages forever.
|
|
// The client loop accepts a LoopConfig struct with two optional fields.
|
|
//
|
|
// These two fields, .msg_callback and .spawn_thread are callback pointers.
|
|
// You set them to custom functions you define to customize the main loop.
|
|
//
|
|
// .msg_callback lets you answer any received IRC messages with another one.
|
|
//
|
|
// .spawn_thread lets you tweak if you spawn a thread to run .msg_callback.
|
|
client.loop(.{ .msg_callback = adapter.callbackFn }) catch |err| {
|
|
std.debug.print("eru exited with error: {}", .{err});
|
|
};
|
|
}
|
|
|
|
pub const Adapter = struct {
|
|
ptr: ?*anyopaque,
|
|
callbackFn: *const fn (?*anyopaque, zircon.Message) ?zircon.Message,
|
|
};
|
|
|
|
pub const BotAdapter = struct {
|
|
bot: Bot,
|
|
allocator: std.mem.Allocator,
|
|
|
|
pub fn init(allocator: std.mem.Allocator) !BotAdapter {
|
|
return BotAdapter{
|
|
.bot = try Bot.init(allocator),
|
|
.allocator = allocator,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *BotAdapter) void {
|
|
self.bot.deinit();
|
|
}
|
|
|
|
pub fn callback(self: *BotAdapter, message: zircon.Message) ?zircon.Message {
|
|
switch (message) {
|
|
.PRIVMSG => |msg| {
|
|
if (Command.parse(msg.prefix, msg.targets, msg.text)) |command| {
|
|
return command.handle(&self.bot);
|
|
}
|
|
self.bot.hear(zigeru.bot.Message{
|
|
.author = msg.prefix.?.nick orelse "unknown",
|
|
.timestamp = std.time.timestamp(),
|
|
.content = msg.text,
|
|
});
|
|
},
|
|
else => {},
|
|
}
|
|
return null;
|
|
}
|
|
|
|
pub fn adapter(self: *BotAdapter) Adapter {
|
|
return .{
|
|
.ptr = self,
|
|
.callbackFn = self.callback,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const Command = struct {
|
|
command: BotCommand,
|
|
prefix: ?zircon.Prefix,
|
|
targets: []const u8,
|
|
|
|
pub fn parse(prefix: ?zircon.Prefix, targets: []const u8, text: []const u8) ?Command {
|
|
const nick = prefix.?.nick.?;
|
|
const command = BotCommand.parse(nick, text) orelse return null;
|
|
return .{
|
|
.command = command,
|
|
.prefix = prefix,
|
|
.targets = targets,
|
|
};
|
|
}
|
|
|
|
pub fn handle(self: Command, bot: *Bot) ?zircon.Message {
|
|
return bot.execute(&self.command, self.prefix, self.targets) catch |err| {
|
|
std.debug.print("Failed to handle {}: {}", .{ self, err });
|
|
return null;
|
|
};
|
|
}
|
|
};
|
|
|
|
test "substitute" {
|
|
var bot_adapter = try BotAdapter.init(std.testing.allocator);
|
|
defer bot_adapter.deinit();
|
|
const prefix = zircon.Prefix{ .nick = "jassob", .user = "jassob", .host = "localhost" };
|
|
const msg = zircon.Message{
|
|
.PRIVMSG = .{
|
|
.prefix = prefix,
|
|
.targets = "#test",
|
|
.text = "hello world",
|
|
},
|
|
};
|
|
_ = bot_adapter.callback(msg);
|
|
const cmd_msg = zircon.Message{
|
|
.PRIVMSG = .{
|
|
.prefix = prefix,
|
|
.targets = "#test",
|
|
.text = "s/world/zig/",
|
|
},
|
|
};
|
|
const response = bot_adapter.callback(cmd_msg);
|
|
try std.testing.expect(response != null);
|
|
try std.testing.expectEqualStrings("hello zig", response.?.PRIVMSG.text);
|
|
}
|