omakase/main.jai
2025-11-20 23:05:04 +02:00

134 lines
3.4 KiB
Plaintext

#import "Basic";
#import "Hash_Table";
#import "Socket";
String :: #import "String";
#load "server.jai";
consoom :: (input: *string, delimiter: string) -> string {
if input.count < 1 then return "INVALID READ";
found, left, right := String.split_from_left(input.*, delimiter);
input.* = right;
return left;
}
Request :: struct {
route : string;
method : string;
protocol : string;
headers : Table(string, string);
body : string;
}
Response :: struct {
protocol : string = "HTTP/1.1";
status : int = 200;
headers : Table(string, string);
body : string;
}
parse_request :: (data: *string) -> Request {
req := New(Request);
req.method = consoom(data, " ");
req.route = consoom(data, " ");
req.protocol = consoom(data, "\n");
headers_string := consoom(data, "\r\n\r\n");
while headers_string.count > 0 {
key := consoom(*headers_string, ": ");
value := consoom(*headers_string, "\n");
table_add(*req.headers, key, value);
}
req.body = data.*;
return req;
}
set_header :: (res: *Response, key: string, value: string) {
table_add(*res.headers, key, value);
}
serialize_response :: (res: *Response) -> string {
builder : String_Builder;
print_to_builder(*builder, "% % OK", res.protocol, res.status);
for v, k : res.headers {
print("%: %\n", k,v);
print_to_builder(*builder, "\n%: %", k, v);
}
print_to_builder(*builder, "\r\n\r\n");
print_to_builder(*builder, "%", res.body);
return builder_to_string(*builder);
}
sigaction_t :: struct {
sa_sigaction: (sig: s32, info: *siginfo_t, p: *void) #c_call;
sa_mask: sigset_t; // Signal mask to apply.
sa_flags: s32; // See signal options below.
#if OS == .LINUX then sa_restorer: () #c_call;
}
libc :: #library,system "libc";
sigaction :: (signum: s32, act: *sigaction_t, oldact: *void) -> s32 #foreign libc;
main_socket : Socket;
sigset_t :: struct { __val: [16] u64; }
siginfo_t :: struct { // This is not the correct size, but we don't instantiate it, so it's fine.
si_signo: s32;
si_errno: s32;
si_code: s32;
__pad0: s32;
si_addr: *void;
}
handle_signal :: (sig: s32, info: *siginfo_t, secret: *void) #c_call {
c : #Context;
push_context(c) {
print("Graceful exit!!!\n");
close_and_reset(*main_socket);
}
}
main :: () {
socket_init();
main_socket = socket(AF_INET, .SOCK_STREAM, .TCP);
reuse : s32 = 1;
setsockopt(main_socket, SOL_SOCKET, SO_REUSEADDR, *reuse, size_of(s32));
err := bind(main_socket, "127.0.0.1", 8080);
if err != 0 {
print("Error in binding socket: %\n", err);
return;
}
err = listen(main_socket, 1);
if err != 0 {
print("Error in listening: %\n", err);
return;
}
sa: sigaction_t;
sa.sa_sigaction = handle_signal;
sigaction(2, *sa, null);
while true {
rbuf : [2048 * 1000]u8;
addr : sockaddr;
addr_len : socklen_t;
reqs := accept(main_socket, *addr, *addr_len);
bytesRead := recv(reqs, rbuf.data, rbuf.count, 0);
datastring : string;
datastring.count = bytesRead;
datastring.data = rbuf.data;
req := parse_request(*datastring);
res : Response;
handler(req, *res);
res_string := serialize_response(*res);
send(reqs, res_string.data, xx res_string.count, 0);
close_and_reset(*reqs);
}
}