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) -> ! {
49 call::handle_panic("web-admin", info);
50}
51
52struct BufWriter<'a> {
53 buf: &'a mut [u8],
54 pos: usize,
55}
56
57impl<'a> BufWriter<'a> {
58 fn new(buf: &'a mut [u8]) -> Self {
60 Self { buf, pos: 0 }
61 }
62 fn len(&self) -> usize {
64 self.pos
65 }
66}
67
68impl core::fmt::Write for BufWriter<'_> {
69 fn write_str(&mut self, s: &str) -> core::fmt::Result {
71 let bytes = s.as_bytes();
72 let avail = self.buf.len().saturating_sub(self.pos);
73 let n = bytes.len().min(avail);
74 self.buf[self.pos..self.pos + n].copy_from_slice(&bytes[..n]);
75 self.pos += n;
76 Ok(())
77 }
78}
79
80pub fn log(msg: &str) {
82 let _ = call::debug_log(msg.as_bytes());
83}
84
85static CONFIG: picoserve::Config =
86 picoserve::Config::const_default().close_connection_after_response();
87
88#[unsafe(no_mangle)]
89pub extern "C" fn _start() -> ! {
91 log("[web-admin] Strat9 Web Admin starting on port 8080\n");
92
93 let app = routes::build_router();
94 let mut conn_count: u64 = 0;
95
96 loop {
97 let fd = net::open_listener(LISTEN_PORT);
98 conn_count += 1;
99
100 executor::block_on(async {
101 let socket = io::TcpSocket::new(fd);
102 let timer = io::Strat9Timer;
103 let mut http_buf = [0u8; HTTP_BUF_SIZE];
104
105 let server = picoserve::Server::custom(&app, timer, &CONFIG, &mut http_buf);
106
107 match server.serve(socket).await {
108 Ok(info) => {
109 let msg = alloc::format!(
110 "[web-admin] conn #{}: {} reqs\n",
111 conn_count,
112 info.handled_requests_count
113 );
114 log(&msg);
115 }
116 Err(_) => {
117 log("[web-admin] connection error\n");
118 }
119 }
120 });
121 }
122}