1
0
Fork 0

fix(src): Ensure that the new c api can actually be used

This commit is contained in:
Benedikt Peetz 2024-05-04 15:00:58 +02:00
parent a39a0875a3
commit c233b30a52
10 changed files with 117 additions and 39 deletions

View File

@ -1,2 +1,5 @@
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
# [target.x86_64-unknown-linux-gnu]
# rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[build]
rustflags = ["-C", "link-args=-rdynamic -fuse-ld=mold"]

12
Cargo.lock generated
View File

@ -211,9 +211,9 @@ checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
[[package]]
name = "autocfg"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backoff"
@ -1696,9 +1696,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
@ -2863,9 +2863,9 @@ dependencies = [
[[package]]
name = "trixy"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84becfd882a68c35ec1c2bc23aac6a0b0e10021d74b8675250c048621d633c1"
checksum = "73eef2c0a310a228e44c0d5aa8b264381407f221975bb909646edb08d3b722ab"
dependencies = [
"convert_case",
"libc",

View File

@ -24,7 +24,7 @@ keymaps = {version = "0.1.1", features = ["crossterm"] }
# c api
libloading = "0.8.3"
trixy = {version = "0.1.0"}
trixy = {version = "0.1.1"}
# lua stuff
mlua = { version = "0.9.7", features = ["lua54", "async", "send", "serialize"] }
@ -43,7 +43,7 @@ directories = "5.0.1"
pretty_assertions = "1.4.0"
[build-dependencies]
trixy = { version = "0.1.0" }
trixy = { version = "0.1.1" }
[profile.release]
lto = true

View File

@ -1,14 +1,58 @@
// Run the `api` bin to see the generated api
use std::{panic::catch_unwind, process, thread};
use cli_log::{debug, info};
use crate::app::{events::Event, COMMAND_TRANSMITTER};
include!(concat!(env!("OUT_DIR"), "/api.rs"));
pub fn handle_cmd(cmd: Commands) {
// Unwinding into the c code implicitly calling this function would be UB. Besides, rust would
// probably just abort the process, giving us a weird shutdown without an error message.
// Thus we catch the panic before the ffi boundary. This could also be moved to trixy.
let error = catch_unwind(|| {
let tx = COMMAND_TRANSMITTER
.get()
.expect("The cell should always be populated, at this point");
info!("Received command: {:#?}", cmd);
// NOTE: The extra future and tokio runtime here is necessary to have a sync api. Which is imho
// better than expecting c to work with a async one. <2024-05-04>
let future = async move {
debug!("Asyncly started to send cmd");
// FIXME: The None here is definitely wrong <2024-05-03>
tx.send(Event::CommandEvent(cmd, None));
tx.send(Event::CommandEvent(cmd, None))
.await
.expect("I hope that this does not fail");
debug!("Done with the async send");
};
debug!("Starting runtime");
let handle = thread::spawn(|| {
// run the task a separate thread to avoid tokio having problems with the currently
// running runtime.
// PERFORMANCE(@soispha): Stating a new thread for each command is very bad. <2024-05-04>
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(future);
});
handle.join().expect("Shall never error");
debug!("Handled command");
});
if let Err(err) = error {
eprintln!("Catched a panic just before the c ffi: {:#?}", err);
// This will leave the terminal in a horrendous shape (as no destructors are run), but what
// can we do at this point beside that?
process::abort();
}
}

View File

@ -1,4 +1,4 @@
use std::{mem, str::FromStr};
use std::str::FromStr;
use crate::{
app::{
@ -84,11 +84,12 @@ pub async fn handle(
Trinitrix::Api(api) => match api {
Api::exit => {
send_status_output!("Terminating the application..");
warn!("Terminating the application");
EventStatus::Terminate
}
Api::room_message_send { message } => {
if let Some(room) = app.status.room_mut() {
room.send(message.clone()).await?;
room.send(message.to_string()).await?;
send_status_output!("Sent message: `{}`", message);
} else {
// FIXME(@soispha): This should raise an error within lua, as it would
@ -99,8 +100,6 @@ pub async fn handle(
);
}
// NOTE(@soispha): This is temporary, until trixy can do it automatically <2024-05-03>
mem::forget(message);
EventStatus::Ok
}
Api::Ui(ui) => match ui {
@ -140,9 +139,11 @@ pub async fn handle(
key,
callback,
} => {
mode.chars().for_each(|char| {
info!("Will add a keymapping for '{}' in mode '{}'", key, mode);
mode.as_str().chars().for_each(|char| {
info!("Setting keymaping ('{}') for mode '{}'", key, char);
let parsed_keys = key
.as_str()
.parse::<Keys>()
.map_err(|err| {
send_error_output!(err.to_string());
@ -172,8 +173,6 @@ pub async fn handle(
};
});
mem::forget(key);
mem::forget(mode);
EventStatus::Ok
}
// FIXME(@soispha): It would be nice to have these functions, but well..
@ -183,22 +182,20 @@ pub async fn handle(
},
Api::Raw(raw) => match raw {
Raw::raise_error { error_message } => {
send_error_output!(error_message);
mem::forget(error_message);
send_error_output!(error_message.to_string());
EventStatus::Ok
}
Raw::display_output { output_message } => {
// TODO(@Soispha): This is only used to show the Lua command output to the user.
// Lua commands already receive the output. This should probably be communicated
// better, should it?
send_status_output!(output_message);
mem::forget(output_message);
send_status_output!(output_message.to_string());
EventStatus::Ok
}
Raw::send_input_unprocessed { input } => {
let output = match app.status.state() {
State::Insert => {
let key = Key::from_str(&input)?;
let key = Key::from_str(input.as_str())?;
let cross_input: Event = key.try_into()?;
app.ui
.message_compose
@ -206,7 +203,7 @@ pub async fn handle(
EventStatus::Ok
}
State::Command => {
let key = Key::from_str(&input)?;
let key = Key::from_str(input.as_str())?;
let cross_input: Event = key.try_into()?;
app.ui
.cli
@ -222,7 +219,6 @@ pub async fn handle(
pending_keys: _,
} => EventStatus::Ok,
};
mem::forget(input);
output
}
Raw::Private(private) => {

View File

@ -32,7 +32,7 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
.send(Event::CommandEvent(
Commands::Trinitrix(Trinitrix::Api(Api::Raw(
Raw::send_input_unprocessed {
input: key.to_string_repr(),
input: key.to_string_repr().into(),
},
))),
None,
@ -45,7 +45,7 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
app.tx
.send(Event::CommandEvent(
Commands::Trinitrix(Trinitrix::Api(Api::Raw(Raw::send_input_unprocessed {
input: converted_key.to_string_repr(),
input: converted_key.to_string_repr().into(),
}))),
None,
))

View File

@ -4,7 +4,7 @@ pub mod listeners;
use anyhow::{Context, Result};
use crate::app::{command_interface::Commands, status::State, App};
use cli_log::trace;
use cli_log::{trace, warn};
use crossterm::event::Event as CrosstermEvent;
use handlers::{command, input, lua_command, matrix, setup};
@ -29,7 +29,13 @@ impl Event {
.await
.with_context(|| format!("Failed to handle command event: `{:#?}`", event)),
Event::LuaCommand(lua_code) => Ok(EventStatus::Terminate),
Event::LuaCommand(lua_code) => {
warn!(
"Got lua code to execute, but no exectuter is available:\n{}",
lua_code
);
Ok(EventStatus::Ok)
}
// lua_command::handle(app, lua_code.to_owned())
// .await
// .with_context(|| format!("Failed to handle lua code: `{}`", lua_code)),

View File

@ -5,14 +5,21 @@ pub mod status;
use std::{
collections::HashMap,
ffi::c_int,
path::{Path, PathBuf},
sync::OnceLock,
};
use anyhow::{Context, Error, Result};
use cli_log::{info, warn};
use crossterm::{
event::DisableMouseCapture,
execute,
terminal::{disable_raw_mode, LeaveAlternateScreen},
};
use directories::ProjectDirs;
use keymaps::trie::Node;
use libloading::{Library, Symbol};
use matrix_sdk::Client;
use tokio::sync::mpsc::{self, Sender};
use tokio_util::sync::CancellationToken;
@ -86,7 +93,11 @@ impl App<'_> {
})
}
pub async fn run(&mut self, cli_lua_config_file: Option<PathBuf>) -> Result<()> {
pub async fn run(
&mut self,
cli_lua_config_file: Option<PathBuf>,
plugin_path: Option<PathBuf>,
) -> Result<()> {
// Spawn input event listener
tokio::task::spawn(events::listeners::input::poll(
self.tx.clone(),
@ -121,6 +132,21 @@ impl App<'_> {
}
}
if let Some(plugin) = plugin_path {
info!("Loading plugin_main() from {}", plugin.display());
unsafe {
let lib = Library::new(plugin).context("Failed to load plugin")?;
let func: Symbol<unsafe fn() -> c_int> = lib
.get(b"plugin_main")
.context("Plugin does not have a 'plugin_main' symbol")?;
info!("Starting plugin");
let out = func();
info!("Plugin finished with: {}", out);
}
}
if self.account().is_err() {
info!("No saved sessions found -> jumping into setup");
self.setup().await?;

View File

@ -12,9 +12,12 @@ pub struct Args {
/// The subcommand to execute, default is start
pub subcommand: Option<Command>,
// #[arg(long, short)]
// /// Path to the Lua config file, executed instead of the normal one
// pub lua_config_file: Option<PathBuf>,
#[arg(long, short)]
/// Path to the Lua config file, executed instead of the normal one
pub lua_config_file: Option<PathBuf>,
/// Path to a plugin to load. It must be a shared-object (.so)
pub plugin_path: Option<PathBuf>,
}
#[derive(Subcommand, Debug)]
pub enum Command {

View File

@ -16,7 +16,9 @@ async fn main() -> anyhow::Result<()> {
match command {
Command::Start {} => {
let mut app = app::App::new()?;
app.run(args.lua_config_file).await?;
// NOTE(@soispha): The `None` is temporary <2024-05-03>
app.run(None, args.plugin_path).await?;
}
};
@ -24,6 +26,4 @@ async fn main() -> anyhow::Result<()> {
}
// FIXME(@soispha): Re-exports for trixy, this should be configurable <2024-05-03>
pub use crate::app::command_interface::handle_cmd;
pub use crate::app::command_interface::Commands;
pub use crate::app::command_interface::*;