/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2025 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
// Use these to incrementally fix warnings with cargo fix
#![allow(warnings, unused)]
//#![deny(unused_imports)]
use async_lock::{Mutex as AsyncMutex, RwLock as AsyncRwLock};
use darkfi::system::CondVar;
use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate};
use std::sync::{mpsc, Arc};
#[macro_use]
extern crate log;
#[allow(unused_imports)]
use log::LevelFilter;
#[derive(Debug)]
pub enum AndroidSuggestEvent {
Init,
CreateInputConnect,
Compose { text: String, cursor_pos: i32, is_commit: bool },
ComposeRegion { start: usize, end: usize },
FinishCompose,
DeleteSurroundingText { left: usize, right: usize },
}
#[cfg(target_os = "android")]
mod android;
mod app;
mod build_info;
mod error;
mod expr;
mod gfx;
mod logger;
mod mesh;
mod net;
mod plugin;
mod prop;
mod pubsub;
//mod py;
mod ringbuf;
mod scene;
mod shape;
use scene::SceneNode as SceneNode3;
mod text;
mod text2;
mod ui;
mod util;
use crate::{net::ZeroMQAdapter, text::TextShaper};
// Hides the cmd.exe terminal on Windows.
// Enable this when making release builds.
//#![windows_subsystem = "windows"]
pub type ExecutorPtr = Arc>;
fn panic_hook(panic_info: &std::panic::PanicHookInfo) {
error!("panic occurred: {panic_info}");
error!("{}", std::backtrace::Backtrace::force_capture().to_string());
std::process::abort()
}
fn main() {
// Abort the application on panic right away
std::panic::set_hook(Box::new(panic_hook));
text2::init_txt_ctx();
logger::setup_logging();
#[cfg(target_os = "android")]
{
use crate::android::{get_appdata_path, get_external_storage_path};
info!("App internal data path: {:?}", get_appdata_path());
info!("App external storage path: {:?}", get_external_storage_path());
// Workaround for this bug
// https://gitlab.torproject.org/tpo/core/arti/-/issues/999
unsafe {
std::env::set_var("HOME", get_appdata_path().as_os_str());
}
//let paths = std::fs::read_dir("/data/data/darkfi.darkfi/").unwrap();
//for path in paths {
// debug!("{}", path.unwrap().path().display())
//}
}
let exe_path = std::env::current_exe().unwrap();
let basename = exe_path.parent().unwrap();
std::env::set_current_dir(basename);
info!("Target OS: {}", build_info::TARGET_OS);
info!("Target arch: {}", build_info::TARGET_ARCH);
let cwd = std::env::current_dir().unwrap();
info!("Current dir: {}", cwd.display());
let ex = Arc::new(smol::Executor::new());
let sg_root = SceneNode3::root();
let async_runtime = app::AsyncRuntime::new(ex.clone());
async_runtime.start();
#[cfg(feature = "enable-netdebug")]
{
let sg_root2 = sg_root.clone();
let ex2 = ex.clone();
let zmq_task = ex.spawn(async {
let zmq_rpc = ZeroMQAdapter::new(sg_root2, ex2).await;
zmq_rpc.run().await;
});
async_runtime.push_task(zmq_task);
}
let (method_req, method_rep) = mpsc::channel();
// The UI actually needs to be running for this to reply back.
// Otherwise calls will just hang.
let render_api = gfx::RenderApi::new(method_req);
let event_pub = gfx::GraphicsEventPublisher::new();
let text_shaper = TextShaper::new();
let cv_gfxwin_started = Arc::new(CondVar::new());
let cv_gfxwin_started2 = cv_gfxwin_started.clone();
let cv_app_started = Arc::new(CondVar::new());
let cv_app_started2 = cv_app_started.clone();
let app = app::App::new(sg_root, render_api, event_pub.clone(), text_shaper, ex.clone());
let app2 = app.clone();
let app_task = ex.spawn(async move {
app2.setup().await;
// Needed because accessing screen_size() is not allowed until window init
cv_gfxwin_started2.wait().await;
app2.start().await;
cv_app_started2.notify();
});
async_runtime.push_task(app_task);
/*
// Nice to see which events exist
let ev_sub = event_pub.subscribe_key_down();
let ev_relay_task = ex.spawn(async move {
debug!(target: "main", "event relayer started");
loop {
let Ok((key, mods, repeat)) = ev_sub.receive().await else {
debug!(target: "main", "Event relayer closed");
break
};
// Ignore keys which get stuck repeating when switching windows
match key {
miniquad::KeyCode::LeftShift | miniquad::KeyCode::LeftSuper => continue,
_ => {}
}
if !repeat {
debug!(target: "main", "key_down event: {:?} {:?} {}", key, mods, repeat);
}
}
});
async_runtime.push_task(ev_relay_task);
let ev_sub = event_pub.subscribe_key_up();
let ev_relay_task = ex.spawn(async move {
debug!(target: "main", "event relayer started");
loop {
let Ok((key, mods)) = ev_sub.receive().await else {
debug!(target: "main", "Event relayer closed");
break
};
// Ignore keys which get stuck repeating when switching windows
match key {
miniquad::KeyCode::LeftShift | miniquad::KeyCode::LeftSuper => continue,
_ => {}
}
debug!(target: "main", "key_up event: {:?} {:?}", key, mods);
}
});
async_runtime.push_task(ev_relay_task);
let ev_sub = event_pub.subscribe_char();
let ev_relay_task = ex.spawn(async move {
debug!(target: "main", "event relayer started");
loop {
let Ok((key, mods, repeat)) = ev_sub.receive().await else {
debug!(target: "main", "Event relayer closed");
break
};
debug!(target: "main", "char event: {:?} {:?} {}", key, mods, repeat);
}
});
async_runtime.push_task(ev_relay_task);
*/
//let stage = gfx::Stage::new(method_rep, event_pub);
gfx::run_gui(app, async_runtime, method_rep, event_pub, cv_gfxwin_started);
debug!(target: "main", "Started GFX backend");
}
/*
use rustpython_vm::{self as pyvm, convert::ToPyObject};
fn main() {
let module = pyvm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
let source = r#"
def foo():
open("hihi", "w")
return 110
#max(1 + lw/3, 4*10) + foo(2, True)
"#;
//let code_obj = vm
// .compile(source, pyvm::compiler::Mode::Exec, "".to_owned())
// .map_err(|err| vm.new_syntax_error(&err, Some(source))).unwrap();
//code_obj
pyvm::import::import_source(vm, "lain", source).unwrap()
});
fn foo(x: u32, y: bool) -> u32 {
if y {
2 * x
} else {
x
}
}
let res = pyvm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
let globals = vm.ctx.new_dict();
globals.set_item("lw", vm.ctx.new_int(110).to_pyobject(vm), vm).unwrap();
globals.set_item("lh", vm.ctx.new_int(4).to_pyobject(vm), vm).unwrap();
globals.set_item("foo", vm.new_function("foo", foo).into(), vm).unwrap();
let scope = pyvm::scope::Scope::new(None, globals);
let foo_fn = module.get_attr("foo", vm).unwrap();
foo_fn.call((), vm).unwrap()
//vm.run_code_obj(code_obj, scope).unwrap()
});
println!("{:?}", res);
}
*/