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]
48/// Implements panic.
49fn 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    /// Creates a new instance.
67    fn new(buf: &'a mut [u8]) -> Self {
68        Self { buf, pos: 0 }
69    }
70    /// Implements len.
71    fn len(&self) -> usize {
72        self.pos
73    }
74}
75
76impl core::fmt::Write for BufWriter<'_> {
77    /// Writes str.
78    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
88/// Implements log.
89pub 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)]
97/// Implements start.
98pub 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}