Skip to main content

web_admin/
main.rs

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]
30/// Implements alloc error.
31fn 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    /// Creates a new instance.
59    fn new(buf: &'a mut [u8]) -> Self {
60        Self { buf, pos: 0 }
61    }
62    /// Implements len.
63    fn len(&self) -> usize {
64        self.pos
65    }
66}
67
68impl core::fmt::Write for BufWriter<'_> {
69    /// Writes str.
70    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
80/// Implements log.
81pub 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)]
89/// Implements start.
90pub 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}