@@ -46,7 +46,7 @@ const MAX_HTTP_REQUEST_SIZE = 4096;
4646// +140 for the max control packet that might be interleaved in a message
4747const MAX_MESSAGE_SIZE = 512 * 1024 + 14 ;
4848
49- const Server = struct {
49+ pub const Server = struct {
5050 app : * App ,
5151 loop : * Loop ,
5252 allocator : Allocator ,
@@ -62,8 +62,74 @@ const Server = struct {
6262 // The response to send on a GET /json/version request
6363 json_version_response : []const u8 ,
6464
65- fn deinit (self : * Server ) void {
66- _ = self ;
65+ pub fn init (
66+ app : * App ,
67+ address : net.Address ,
68+ timeout : u64 ,
69+ ) ! Server {
70+ // create socket
71+ const flags = posix .SOCK .STREAM | posix .SOCK .CLOEXEC | posix .SOCK .NONBLOCK ;
72+ const listener = try posix .socket (address .any .family , flags , posix .IPPROTO .TCP );
73+ errdefer posix .close (listener );
74+
75+ try posix .setsockopt (listener , posix .SOL .SOCKET , posix .SO .REUSEADDR , & std .mem .toBytes (@as (c_int , 1 )));
76+ // TODO: Broken on darwin
77+ // https://github.com/ziglang/zig/issues/17260 (fixed in Zig 0.14)
78+ // if (@hasDecl(os.TCP, "NODELAY")) {
79+ // try os.setsockopt(socket.sockfd.?, os.IPPROTO.TCP, os.TCP.NODELAY, &std.mem.toBytes(@as(c_int, 1)));
80+ // }
81+ try posix .setsockopt (listener , posix .IPPROTO .TCP , 1 , & std .mem .toBytes (@as (c_int , 1 )));
82+
83+ // bind & listen
84+ try posix .bind (listener , & address .any , address .getOsSockLen ());
85+ try posix .listen (listener , 1 );
86+
87+ const allocator = app .allocator ;
88+ const json_version_response = try buildJSONVersionResponse (allocator , address );
89+ errdefer allocator .free (json_version_response );
90+
91+ return .{
92+ .app = app ,
93+ .loop = app .loop ,
94+ .timeout = timeout ,
95+ .listener = listener ,
96+ .allocator = allocator ,
97+ .accept_completion = undefined ,
98+ .json_version_response = json_version_response ,
99+ };
100+ }
101+
102+ pub fn deinit (self : * Server ) void {
103+ posix .close (self .listener );
104+ self .allocator .free (self .json_version_response );
105+ }
106+
107+ pub fn run (self : * Server , address : net.Address ) ! void {
108+ // accept an connection
109+ self .queueAccept ();
110+ log .info (.app , "server running" , .{ .address = address });
111+
112+ // infinite loop on I/O events, either:
113+ // - cmd from incoming connection on server socket
114+ // - JS callbacks events from scripts
115+ while (true ) {
116+ // @newhttp. This is a hack. We used to just have 1 loop, so we could
117+ // sleep it it "forever" and any activity (message to this server,
118+ // JS callback, http data) would wake it up.
119+ // Now we have 2 loops. If we block on one, the other won't get woken
120+ // up. We don't block "forever" but even 10ms adds a bunch of latency
121+ // since this is called in a loop.
122+ // Hopefully this is temporary and we can remove the io loop and then
123+ // only have 1 loop. But, until then, we need to check both loops and
124+ // pay some blocking penalty.
125+ if (self .client ) | client | {
126+ if (client .cdp ) | * cdp | {
127+ cdp .pageWait ();
128+ }
129+ }
130+
131+ try self .loop .io .run_for_ns (10 * std .time .ns_per_ms );
132+ }
67133 }
68134
69135 fn queueAccept (self : * Server ) void {
@@ -1008,72 +1074,6 @@ fn websocketHeader(buf: []u8, op_code: OpCode, payload_len: usize) []const u8 {
10081074 return buf [0.. 10];
10091075}
10101076
1011- pub fn run (
1012- app : * App ,
1013- address : net.Address ,
1014- timeout : u64 ,
1015- ) ! void {
1016- // create socket
1017- const flags = posix .SOCK .STREAM | posix .SOCK .CLOEXEC | posix .SOCK .NONBLOCK ;
1018- const listener = try posix .socket (address .any .family , flags , posix .IPPROTO .TCP );
1019- defer posix .close (listener );
1020-
1021- try posix .setsockopt (listener , posix .SOL .SOCKET , posix .SO .REUSEADDR , & std .mem .toBytes (@as (c_int , 1 )));
1022- // TODO: Broken on darwin
1023- // https://github.com/ziglang/zig/issues/17260 (fixed in Zig 0.14)
1024- // if (@hasDecl(os.TCP, "NODELAY")) {
1025- // try os.setsockopt(socket.sockfd.?, os.IPPROTO.TCP, os.TCP.NODELAY, &std.mem.toBytes(@as(c_int, 1)));
1026- // }
1027- try posix .setsockopt (listener , posix .IPPROTO .TCP , 1 , & std .mem .toBytes (@as (c_int , 1 )));
1028-
1029- // bind & listen
1030- try posix .bind (listener , & address .any , address .getOsSockLen ());
1031- try posix .listen (listener , 1 );
1032-
1033- var loop = app .loop ;
1034- const allocator = app .allocator ;
1035- const json_version_response = try buildJSONVersionResponse (allocator , address );
1036- defer allocator .free (json_version_response );
1037-
1038- var server = Server {
1039- .app = app ,
1040- .loop = loop ,
1041- .timeout = timeout ,
1042- .listener = listener ,
1043- .allocator = allocator ,
1044- .accept_completion = undefined ,
1045- .json_version_response = json_version_response ,
1046- };
1047- defer server .deinit ();
1048-
1049- // accept an connection
1050- server .queueAccept ();
1051- log .info (.app , "server running" , .{ .address = address });
1052-
1053- // infinite loop on I/O events, either:
1054- // - cmd from incoming connection on server socket
1055- // - JS callbacks events from scripts
1056- // var http_client = app.http_client;
1057- while (true ) {
1058- // @newhttp. This is a hack. We used to just have 1 loop, so we could
1059- // sleep it it "forever" and any activity (message to this server,
1060- // JS callback, http data) would wake it up.
1061- // Now we have 2 loops. If we block on one, the other won't get woken
1062- // up. We don't block "forever" but even 10ms adds a bunch of latency
1063- // since this is called in a loop.
1064- // Hopefully this is temporary and we can remove the io loop and then
1065- // only have 1 loop. But, until then, we need to check both loops and
1066- // pay some blocking penalty.
1067- if (server .client ) | client | {
1068- if (client .cdp ) | * cdp | {
1069- cdp .pageWait ();
1070- }
1071- }
1072-
1073- try loop .io .run_for_ns (10 * std .time .ns_per_ms );
1074- }
1075- }
1076-
10771077// Utils
10781078// --------
10791079
0 commit comments