mod native;
use std::collections::BTreeMap;
use std::io::{self, Read};
use std::process::ExitCode;
use brazen::{
count_tokens, route, Args, CodeReceiver, CountIo, EnvSnapshot, Host, ListIo, LoginIo,
ProvidersIo, ReplayStash, Route, ServeIo,
};
use native::{
random_token, stash_root, HttpTransport, LoopbackReceiver, RealPacer, SystemBrowserLauncher,
SystemClock, TcpBind, XdgCredStore, XdgModelCache,
};
fn main() -> ExitCode {
restore_sigpipe();
let args = Args {
argv: std::env::args().skip(1).collect(),
env: EnvSnapshot(std::env::vars().collect::<BTreeMap<_, _>>()),
tty: stdin_is_tty(),
stdout_tty: stdout_is_tty(),
};
let code = match route(&args.argv) {
Route::Login => login(args),
Route::ListModels => list_models(args),
Route::ListProviders => list_providers(args),
Route::CountTokens => count(args),
Route::Serve => serve(args),
Route::Run => run(args),
};
ExitCode::from(code)
}
fn run(args: Args) -> u8 {
let stdin = io::stdin();
let stdout = io::stdout();
let stderr = io::stderr();
let mut empty = io::empty();
let mut locked = stdin.lock();
let reader: &mut dyn Read = if args.tty { &mut empty } else { &mut locked };
let (transport, store, cache, clock) = (
HttpTransport::new(),
XdgCredStore::new(),
XdgModelCache::new(),
SystemClock,
);
let stash = ReplayStash::new(stash_root());
let host = Host {
transport: &transport,
store: &store,
cache: &cache,
clock: &clock,
stash: &stash,
};
brazen::run(args, reader, &mut stdout.lock(), &mut stderr.lock(), &host)
}
fn serve(args: Args) -> u8 {
let stdout = io::stdout();
let stderr = io::stderr();
let (transport, store, cache, clock) = (
HttpTransport::new(),
XdgCredStore::new(),
XdgModelCache::new(),
SystemClock,
);
let bind = TcpBind;
let stash = ReplayStash::new(stash_root());
let mut io = ServeIo {
stdout: &mut stdout.lock(),
stderr: &mut stderr.lock(),
bind: &bind,
transport: &transport,
store: &store,
cache: &cache,
clock: &clock,
stash: &stash,
};
brazen::serve(&args, &mut io)
}
fn list_models(args: Args) -> u8 {
let stdout = io::stdout();
let stderr = io::stderr();
let mut io = ListIo {
stdout: &mut stdout.lock(),
stderr: &mut stderr.lock(),
transport: &HttpTransport::new(),
store: &XdgCredStore::new(),
cache: &XdgModelCache::new(),
clock: &SystemClock,
};
brazen::list_models(&args, &mut io)
}
fn list_providers(args: Args) -> u8 {
let stdout = io::stdout();
let stderr = io::stderr();
let mut io = ProvidersIo {
stdout: &mut stdout.lock(),
stderr: &mut stderr.lock(),
store: &XdgCredStore::new(),
};
brazen::list_providers(&args, &mut io)
}
fn count(args: Args) -> u8 {
let stdin = io::stdin();
let stdout = io::stdout();
let stderr = io::stderr();
let mut empty = io::empty();
let mut locked = stdin.lock();
let reader: &mut dyn Read = if args.tty { &mut empty } else { &mut locked };
let (transport, store, cache, clock) = (
HttpTransport::new(),
XdgCredStore::new(),
XdgModelCache::new(),
SystemClock,
);
let mut io = CountIo {
stdout: &mut stdout.lock(),
stderr: &mut stderr.lock(),
transport: &transport,
store: &store,
cache: &cache,
clock: &clock,
};
count_tokens(&args, reader, &mut io)
}
fn login(args: Args) -> u8 {
let receiver = LoopbackReceiver::new();
dispatch_login(args, &receiver)
}
fn dispatch_login(args: Args, receiver: &dyn CodeReceiver) -> u8 {
let stdout = io::stdout();
let stderr = io::stderr();
let (transport, store, clock) = (HttpTransport::new(), XdgCredStore::new(), SystemClock);
let (browser, pacer) = (SystemBrowserLauncher, RealPacer);
let (verifier, state) = (random_token(), random_token());
let mut stdout = stdout.lock();
let mut stderr = stderr.lock();
let mut io = LoginIo {
stdout: &mut stdout,
stderr: &mut stderr,
transport: &transport,
store: &store,
clock: &clock,
browser: &browser,
receiver,
pacer: &pacer,
verifier: &verifier,
state: &state,
};
brazen::login(&args, &mut io)
}
#[cfg(unix)]
fn restore_sigpipe() {
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
#[cfg(not(unix))]
fn restore_sigpipe() {}
#[cfg(unix)]
fn stdin_is_tty() -> bool {
unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}
#[cfg(not(unix))]
fn stdin_is_tty() -> bool {
false
}
#[cfg(unix)]
fn stdout_is_tty() -> bool {
unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}
#[cfg(not(unix))]
fn stdout_is_tty() -> bool {
false
}