╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ serve.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯
181 const wui_listen_address = try parseListenAddress((Options{}).wui_listen); 182 var wui_server = try listen(io, wui_listen_address, .fallback); 183 defer wui_server.deinit(io); 184 185 var tasks: std.Io.Group = .init; 186 defer tasks.cancel(io); 187 188 runWebListener(io, allocator, &wui_server, &tasks, .{ .local = local }, err); 189 190 try runnable.run(wui_server.socket.address.getPort()); 191 } 192 193 fn runWebListener( 194 io: std.Io, 195 allocator: std.mem.Allocator, 196 net_server: *std.Io.net.Server, 197 tasks: *std.Io.Group, 198 host: web.Host, 199 err: *std.Io.Writer, 200 ) void { 201 const Context = struct { 202 io: std.Io, 203 allocator: std.mem.Allocator, 204 host: web.Host, 205 err: *std.Io.Writer, 206 }; 207 208 const handle = struct { 209 fn h(ctx: Context, stream: std.Io.net.Stream) void { 210 defer stream.close(ctx.io); 211 web.handleConnection(ctx.io, ctx.allocator, stream, ctx.host, ctx.err) catch |request_err| { 212 serve_common.logError(ctx.io, ctx.err, "web ui request failed: {s}\n", .{@errorName(request_err)}); 213 }; 214 } 215 }.h; 216 217 serve_common.runListener(io, net_server, tasks, err, "web ui", Context{ 218 .io = io, 219 .allocator = allocator, 220 .host = host, 221 .err = err, 222 }, handle); 223 } 224 225 // what a listener does with a port that is already taken 226 const PortPolicy = enum { 227 exact, 228 // leave it to whoever holds it and take an OS-assigned port instead 229 fallback, 230 }; 231 232 fn listen(io: std.Io, listen_address: ListenAddress, policy: PortPolicy) !std.Io.net.Server { 233 const address = try std.Io.net.IpAddress.parseIp4(listen_address.host, listen_address.port); 234 return switch (policy) { 235 .exact => try address.listen(io, .{}), 236 .fallback => address.listen(io, .{}) catch |listen_err| switch (listen_err) { 237 error.AddressInUse => blk: { 238 const any_port = try std.Io.net.IpAddress.parseIp4(listen_address.host, 0); 239 break :blk try any_port.listen(io, .{}); 240 }, 241 else => |e| return e, 242 }, 243 }; 244 } 245 246 fn parseListenAddress(value: []const u8) !ListenAddress { 247 const colon = std.mem.lastIndexOfScalar(u8, value, ':') orelse return error.InvalidListenAddress; 248 if (colon == 0 or colon + 1 >= value.len) return error.InvalidListenAddress; 249 const port = try std.fmt.parseInt(u16, value[colon + 1 ..], 10); 250 return .{ .host = value[0..colon], .port = port }; 251 } 252