Implement basic net module

This commit is contained in:
2025-06-24 22:49:02 +10:00
parent 122ef04b16
commit 8c47987a45
4 changed files with 408 additions and 54 deletions

1
src/lib.rs Normal file
View File

@@ -0,0 +1 @@
pub use lb::net;

View File

@@ -1,9 +1,7 @@
use clap::Parser;
use lb_core::{GlobalState, PrettyError};
use mimalloc::MiMalloc;
use owo_colors::OwoColorize;
use std::{backtrace::Backtrace, net::SocketAddr, num::NonZero, panic, thread};
use tokio::{runtime, task::LocalSet};
use std::{backtrace::Backtrace, net::SocketAddr, num::NonZero, panic, process::ExitCode, thread};
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
@@ -20,14 +18,19 @@ fn panic_cb(panic: &panic::PanicHookInfo) {
"unknown error"
};
eprint!(
eprintln!(
"{}:\n{trace}",
format_args!(
"thread '{}' panicked at {location}: {msg}",
thread::current().name().unwrap_or("<unnamed>")
)
.red()
);
eprintln!(
"{}",
PrettyError::new(msg)
.with_trace(trace)
.prepend(format_args!(
"thread '{}' panicked at {location}",
thread::current().name().unwrap_or("<unnamed>")
))
"This is a bug in luby! Please kindly report this at https://git.lua.re/luaneko/luby."
.red()
);
}
@@ -76,24 +79,27 @@ impl Args {
}
}
fn main() {
fn main() -> ExitCode {
panic::set_hook(Box::new(panic_cb));
let args = Args::parse();
init_logger(&args);
let runtime = init_runtime(&args);
GlobalState::set(init_vm(&args));
let main = LocalSet::new();
main.spawn_local(run(args));
runtime.block_on(main);
let tokio = init_tokio(&args);
let lua = init_lua(&args);
let main = lua.spawn(async |s| main_async(args, s).await);
tokio.block_on(async {
lua.await;
main.await.unwrap_or_else(|err| panic!("{err}"))
})
}
fn init_logger(args: &Args) {
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{Layer, util::*};
let console = tracing_subscriber::fmt()
let log = tracing_subscriber::fmt()
.compact()
.with_env_filter(
tracing_subscriber::EnvFilter::builder()
@@ -110,59 +116,59 @@ fn init_logger(args: &Args) {
.with_default_env()
.server_addr(args.console_addr)
.spawn()
.with_subscriber(console)
.with_subscriber(log)
.init()
} else {
console.init()
log.init()
}
}
fn init_runtime(args: &Args) -> runtime::Runtime {
if args.threads.get() == 1 {
runtime::Builder::new_current_thread()
} else {
runtime::Builder::new_multi_thread()
}
.enable_all()
.thread_name("lb")
.worker_threads(args.threads.get() - 1)
.max_blocking_threads(args.blocking_threads.get())
.build()
.unwrap_or_else(|err| panic!("failed to initialise runtime: {err}"))
fn init_tokio(args: &Args) -> tokio::runtime::Runtime {
let mut rt = match args.threads.get() {
1 => tokio::runtime::Builder::new_current_thread(),
n => {
let mut rt = tokio::runtime::Builder::new_multi_thread();
rt.worker_threads(n - 1);
rt
}
};
rt.enable_all()
.thread_name("luby")
.max_blocking_threads(args.blocking_threads.get())
.build()
.expect("failed to initialise runtime")
}
fn init_vm(_args: &Args) -> luajit::State {
let mut state =
luajit::State::new().unwrap_or_else(|err| panic!("failed to initialise runtime: {err}"));
let mut registry = luaffi::Registry::new();
registry.preload::<lb_core::lb_core>("lb:core");
println!("{registry}");
state
.load(&luajit::Chunk::new(registry.done()).name("@[luby]"))
.and_then(|()| state.call(0, 0))
.unwrap_or_else(|err| panic!("failed to load modules: {err}"));
state
fn init_lua(_args: &Args) -> lb::runtime::Runtime {
let rt = lb::runtime::Builder::new();
rt.build().expect("failed to initialise runtime")
}
async fn run(args: Args) {
let mut state = GlobalState::new_thread();
async fn main_async(args: Args, state: &mut luajit::State) -> ExitCode {
for ref path in args.paths {
let chunk = match std::fs::read(path) {
Ok(chunk) => chunk,
Err(err) => return eprintln!("{}", format!("{path}: {err}").red()),
Err(err) => {
eprintln!("{}", format_args!("{path}: {err}").red()); // read file error
return ExitCode::FAILURE;
}
};
if let Err(err) = state.load(&luajit::Chunk::new(chunk).path(path)) {
return eprintln!("{}", err.red());
eprintln!("{}", err.red()); // syntax error
return ExitCode::FAILURE;
}
match state.call_async(0, 0).await {
Ok(_) => {}
Err(err) => GlobalState::uncaught_error(err),
if let Err(err) = state.call_async(0, 0).await {
match err.trace() {
Some(trace) => eprintln!("{}\n{trace}", err.red()), // runtime error
None => eprintln!("{}", err.red()),
}
return ExitCode::FAILURE;
}
}
ExitCode::SUCCESS
}