╭ changed ────╮ │src/serve.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────╮ │ 4 const hash = xit.hash; │ │ 5 const ui = @import("./ui.zig"); │ │ 6 const web = @import("./web.zig"); │ │ 7 +const serve_ssh_tui = @import("./serve_ssh_tui.zig");│ │ 8 │ │ 9 pub const Options = struct { │ │10 http_listen: []const u8 = "127.0.0.1:8080", │ ╰─────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │63 const ssh_address = try std.Io.net.IpAddress.parseIp4(ssh_listen_address.host, ssh_listen_address.port);│ │64 var ssh_server = try ssh_address.listen(io, .{ .reuse_address = true }); │ │65 defer ssh_server.deinit(io); │ │66 + │ │67 + // create tui listener │ │68 + │ │69 + const tui_listen_address = try parseListenAddress(options.tui_listen); │ │70 + const tui_address = try std.Io.net.IpAddress.parseIp4(tui_listen_address.host, tui_listen_address.port);│ │71 + var tui_server = try tui_address.listen(io, .{ .reuse_address = true }); │ │72 + defer tui_server.deinit(io); │ │73 │ │74 // create wui listener │ │75 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 95 │ │ 96 runSshListener(repo_kind, any_repo_opts, io, allocator, repo_root_path, &ssh_server, &tasks, err);│ │ 97 │ │ 98 + try err.print("serving TUI sessions on {s}\n", .{options.tui_listen}); │ │ 99 + try err.flush(); │ │100 + │ │101 + runTuiListener(io, allocator, admin_repo_path, &tui_server, &tasks, err); │ │102 + │ │103 try err.print("serving web UI on http://{s}/\n", .{options.wui_listen}); │ │104 try err.flush(); │ │105 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │369 }}); │ │370 } │ │371 │ │372 +fn runTuiListener( │ │373 + io: std.Io, │ │374 + allocator: std.mem.Allocator, │ │375 + admin_repo_path: []const u8, │ │376 + net_server: *std.Io.net.Server, │ │377 + tasks: *std.Io.Group, │ │378 + err: *std.Io.Writer, │ │379 +) void { │ │380 + const Listener = struct { │ │381 + io: std.Io, │ │382 + allocator: std.mem.Allocator, │ │383 + admin_repo_path: []const u8, │ │384 + net_server: *std.Io.net.Server, │ │385 + tasks: *std.Io.Group, │ │386 + err: *std.Io.Writer, │ │387 + │ │388 + fn run(ctx: @This()) void { │ │389 + while (true) { │ │390 + const stream = ctx.net_server.accept(ctx.io) catch |accept_err| { │ │391 + if (accept_err == error.Canceled) return; │ │392 + logError(ctx.err, "tui accept failed: {s}\n", .{@errorName(accept_err)}); │ │393 + continue; │ │394 + }; │ │395 + │ │396 + const Connection = struct { │ │397 + io: std.Io, │ │398 + allocator: std.mem.Allocator, │ │399 + admin_repo_path: []const u8, │ │400 + stream: std.Io.net.Stream, │ │401 + err: *std.Io.Writer, │ │402 + │ │403 + fn run(conn: @This()) void { │ │404 + defer conn.stream.close(conn.io); │ │405 + serve_ssh_tui.handleConnection(conn.io, conn.allocator, conn.stream, conn.admin_repo_path) catch |session_err| {│ │406 + logError(conn.err, "tui session failed: {s}\n", .{@errorName(session_err)}); │ │407 + }; │ │408 + } │ │409 + }; │ │410 + │ │411 + ctx.tasks.async(ctx.io, Connection.run, .{Connection{ │ │412 + .io = ctx.io, │ │413 + .allocator = ctx.allocator, │ │414 + .admin_repo_path = ctx.admin_repo_path, │ │415 + .stream = stream, │ │416 + .err = ctx.err, │ │417 + }}); │ │418 + } │ │419 + } │ │420 + }; │ │421 + │ │422 + tasks.async(io, Listener.run, .{Listener{ │ │423 + .io = io, │ │424 + .allocator = allocator, │ │425 + .admin_repo_path = admin_repo_path, │ │426 + .net_server = net_server, │ │427 + .tasks = tasks, │ │428 + .err = err, │ │429 + }}); │ │430 +} │ │431 + │ │432 fn handleSshGitConnection( │ │433 comptime repo_kind: rp.RepoKind, │ │434 comptime any_repo_opts: rp.AnyRepoOpts(repo_kind), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯