This commit is contained in:
2026-01-02 02:13:13 +00:00
parent 9ee8317cb0
commit 1e3c21f150
2 changed files with 102 additions and 56 deletions

View File

@@ -5,7 +5,9 @@ const Client = @This();
connect: ?Message.Connect, connect: ?Message.Connect,
// Messages for this client to receive. // Messages to send to this client.
send_queue: ?*std.Io.Queue(Message) = null,
// Messages received from this client.
recv_queue: ?*std.Io.Queue(Message) = null, recv_queue: ?*std.Io.Queue(Message) = null,
from_client: *std.Io.Reader, from_client: *std.Io.Reader,
@@ -23,9 +25,32 @@ pub fn init(
}; };
} }
pub fn start(self: *Client, io: std.Io, alloc: std.mem.Allocator, queue: *std.Io.Queue(Message)) !void { pub fn start(
self.recv_queue = queue; self: *Client,
io: std.Io,
alloc: std.mem.Allocator,
send_queue: *std.Io.Queue(Message),
recv_queue: *std.Io.Queue(Message),
) !void {
self.send_queue = send_queue;
self.recv_queue = recv_queue;
var recvL = try io.concurrent(startSendLoop, .{ self, io, alloc });
defer recvL.cancel(io) catch {};
var sendL = try io.concurrent(startRecvLoop, .{ self, io, alloc });
defer sendL.cancel(io) catch {};
// Wait for one of the tasks to cancel.
_ = try io.select(.{
.recv = &recvL,
.send = &sendL,
});
}
fn startSendLoop(self: *Client, io: std.Io, alloc: std.mem.Allocator) !void {
var msgs: [8]Message = undefined; var msgs: [8]Message = undefined;
if (self.send_queue) |queue| {
while (true) { while (true) {
const len = try queue.get(io, &msgs, 1); const len = try queue.get(io, &msgs, 1);
std.debug.assert(len <= msgs.len); std.debug.assert(len <= msgs.len);
@@ -77,16 +102,25 @@ pub fn start(self: *Client, io: std.Io, alloc: std.mem.Allocator, queue: *std.Io
} }
try self.to_client.flush(); try self.to_client.flush();
} }
} else unreachable;
}
fn startRecvLoop(self: *Client, io: std.Io, alloc: std.mem.Allocator) !void {
if (self.recv_queue) |queue| {
while (Message.next(alloc, self.from_client)) |msg| {
try queue.putOne(io, msg);
} else |_| {}
} else unreachable;
} }
pub fn send(self: *Client, io: std.Io, msg: Message) !void { pub fn send(self: *Client, io: std.Io, msg: Message) !void {
if (self.recv_queue) |queue| { if (self.send_queue) |queue| {
try queue.putOne(io, msg); try queue.putOne(io, msg);
} else @panic("Must start() the client before sending it messages."); } else @panic("Must start() the client before sending it messages.");
} }
pub fn next(self: *Client, allocator: std.mem.Allocator) !Message { pub fn next(self: *Client, allocator: std.mem.Allocator) !Message {
return Message.next(allocator, self.from_client); return;
} }
test { test {

View File

@@ -160,11 +160,11 @@ fn handleConnection(
try server.addClient(server_allocator, id, &client); try server.addClient(server_allocator, id, &client);
defer server.removeClient(io, server_allocator, id); defer server.removeClient(io, server_allocator, id);
var qbuf: [8]Message = undefined; var sdqbuf: [8]Message = undefined;
var queue: std.Io.Queue(Message) = .init(&qbuf); var send_queue: std.Io.Queue(Message) = .init(&sdqbuf);
defer { defer {
queue.close(io); send_queue.close(io);
while (queue.getOne(io)) |msg| { while (send_queue.getOne(io)) |msg| {
switch (msg) { switch (msg) {
.msg => |m| m.deinit(server_allocator), .msg => |m| m.deinit(server_allocator),
else => {}, else => {},
@@ -172,7 +172,19 @@ fn handleConnection(
} else |_| {} } else |_| {}
} }
var client_task = try io.concurrent(Client.start, .{ &client, io, server_allocator, &queue }); var rcqbuf: [8]Message = undefined;
var recv_queue: std.Io.Queue(Message) = .init(&rcqbuf);
defer {
recv_queue.close(io);
while (recv_queue.getOne(io)) |msg| {
switch (msg) {
.msg => |m| m.deinit(server_allocator),
else => {},
}
} else |_| {}
}
var client_task = try io.concurrent(Client.start, .{ &client, io, server_allocator, &send_queue, &recv_queue });
defer client_task.cancel(io) catch {}; defer client_task.cancel(io) catch {};
try io.sleep(std.Io.Duration.fromMilliseconds(5), .real); try io.sleep(std.Io.Duration.fromMilliseconds(5), .real);