1#![no_std]
2#![no_main]
3#![feature(alloc_error_handler)]
4#![recursion_limit = "512"]
5
6extern crate alloc;
7
8mod executor;
9mod io;
10mod net;
11mod routes;
12mod sysinfo;
13
14use core::{alloc::Layout, fmt::Write, panic::PanicInfo};
15use strat9_syscall::call;
16
17const LISTEN_PORT: u16 = 8080;
18const HTTP_BUF_SIZE: usize = 8192;
19
20alloc_freelist::define_freelist_brk_allocator!(
21 pub struct WebAdminAllocator;
22 brk = strat9_syscall::call::brk;
23 heap_max = 4 * 1024 * 1024;
24);
25
26#[global_allocator]
27static ALLOCATOR: WebAdminAllocator = WebAdminAllocator;
28
29#[alloc_error_handler]
30fn alloc_error(layout: Layout) -> ! {
32 let mut buf = [0u8; 80];
33 let n = {
34 let mut w = BufWriter::new(&mut buf);
35 let _ = write!(
36 w,
37 "[web-admin] OOM: {} bytes align {}\n",
38 layout.size(),
39 layout.align()
40 );
41 w.len()
42 };
43 let _ = call::debug_log(&buf[..n]);
44 call::exit(12)
45}
46
47#[panic_handler]
48fn panic(info: &PanicInfo) -> ! {
50 let mut buf = [0u8; 256];
51 let n = {
52 let mut w = BufWriter::new(&mut buf);
53 let _ = write!(w, "[web-admin] PANIC: {}\n", info.message());
54 w.len()
55 };
56 let _ = call::debug_log(&buf[..n]);
57 call::exit(255)
58}
59
60struct BufWriter<'a> {
61 buf: &'a mut [u8],
62 pos: usize,
63}
64
65impl<'a> BufWriter<'a> {
66 fn new(buf: &'a mut [u8]) -> Self {
68 Self { buf, pos: 0 }
69 }
70 fn len(&self) -> usize {
72 self.pos
73 }
74}
75
76impl core::fmt::Write for BufWriter<'_> {
77 fn write_str(&mut self, s: &str) -> core::fmt::Result {
79 let bytes = s.as_bytes();
80 let avail = self.buf.len().saturating_sub(self.pos);
81 let n = bytes.len().min(avail);
82 self.buf[self.pos..self.pos + n].copy_from_slice(&bytes[..n]);
83 self.pos += n;
84 Ok(())
85 }
86}
87
88pub fn log(msg: &str) {
90 let _ = call::debug_log(msg.as_bytes());
91}
92
93static CONFIG: picoserve::Config =
94 picoserve::Config::const_default().close_connection_after_response();
95
96#[unsafe(no_mangle)]
97pub extern "C" fn _start() -> ! {
99 log("[web-admin] Strat9 Web Admin starting on port 8080\n");
100
101 let app = routes::build_router();
102 let mut conn_count: u64 = 0;
103
104 loop {
105 let fd = net::open_listener(LISTEN_PORT);
106 conn_count += 1;
107
108 executor::block_on(async {
109 let socket = io::TcpSocket::new(fd);
110 let timer = io::Strat9Timer;
111 let mut http_buf = [0u8; HTTP_BUF_SIZE];
112
113 let server = picoserve::Server::custom(&app, timer, &CONFIG, &mut http_buf);
114
115 match server.serve(socket).await {
116 Ok(info) => {
117 let msg = alloc::format!(
118 "[web-admin] conn #{}: {} reqs\n",
119 conn_count,
120 info.handled_requests_count
121 );
122 log(&msg);
123 }
124 Err(_) => {
125 log("[web-admin] connection error\n");
126 }
127 }
128 });
129 }
130}