Tauri: Is there some way to access AppHandler or Window in regular struct or state managed one? - events

I'm tring to use hotwatch to monitor folders for backups.
If any changes happen, expect to emit an event to frontend to update pages.
Then i found that it's not able to access AppHandle or Window in regular struct.
I have tried using lifetime, but as Tauri: accessing-an-apphandle-in-commands mention, it seems there's no way to mantain a long enough life time.
pub struct MonitorHandler<'a> {
pub watcher: Hotwatch;
pub app_handler: Option<&'a AppHandle>
}
impl MonitorHandler<'_> {
pub fn initialize_app_handler(&mut self, handler: AppHandle) {
self.app_handler = Some(&handler);
}
pub fn append_target(path: &str) {
self.watcher.watch(path, |event| {
self.app_handler.emit_all("update");
})
}
}
// whitch shows error
89 | pub fn initialize_app_handler(&mut self, handler: AppHandle) {
| --------- has type `&mut MonitorHandler<'1>`
90 | self.app_handler = Some(&handler);
| ------------------------^^^^^^^^-
| | |
| | borrowed value does not live long enough
| assignment requires that `handler` is borrowed for `'1`
...
93 | }
| - `handler` dropped here while still borrowed
I have tried add app handle when setup, but it still not work, and with the same life time problem.
// main.rs
...
fn main() {
let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
let context = tauri::generate_context!();
tauri::Builder::default()
.manage(store)
.setup(|app| {
store.0.lock().unwrap().initialize_app_handler(app.app_handle());
})
.invoke_handler(tauri::generate_handler![
initialize_app_handler
])
.run(context)
.expect("error while running tauri application");
}
// which will occurs
|
40 | let store = MonitorHandler(Mutex::new(MonitorHandler {
| ----- move occurs because `store` has type `MonitorHandler<'_>`, which does not implement the `Copy` trait
...
51 | .manage(store)
| ----- value moved here
52 | .setup(|app| {
| ^^^^^^^^^^ value used here after move
53 | store.0.lock().unwrap().initialize_app_handler(app.app_handle());
| ------- use occurs due to use in closure
I'm not familiar with rust and tauri, so is there some way to access the AppHandle or Window in my situation? or i have to do this in another way?
Here's my origin code
// handler.rs
// in this case, whether it's AppHandle or Window, the program will just stuck and not able to anything
pub struct MonitorHandler {
pub watcher: Hotwatch;
pub app_handler: Option<AppHandle>
}
impl MonitorHandler {
pub fn initialize_app_handler(&mut self, handler: AppHandle) {
self.app_handler = Some(handler.clone());
}
}
pub struct MonitorHandler(pub Mutex<MonitorHandler>);
// main.rs
use hotwatch::Hotwatch;
use tauri::{ Manager, AppHandle };
use crate::handler::MonitorHandler;
#[tauri::command]
pub fn initialize_app_handler(monitor: State<MonitorHandler>, app_handler: AppHandle) -> bool {
monitor.0.lock().unwrap().initialize_app_handler(app_handler);
true
}
fn main() {
let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
let context = tauri::generate_context!();
tauri::Builder::default()
.manage(store)
.setup()
.invoke_handler(tauri::generate_handler![
initialize_app_handler
])
.run(context)
.expect("error while running tauri application");
}

The reason it get stuck is that the lock action cause a dead lock in the AppHandle since the stored sturct is assigned to the instance of the AppHandle.
How to solve the problem is simple, greet thanks for #FabianLars, here's the discussion Is there some way for backend to emit event actively?
To be brief, just initialize the struct and manage it in setup, like this
// handler.rs
pub struct MonitorHandler {
pub watcher: Hotwatch;
pub app_handler: AppHandle
}
impl MonitorHandler {
pub fn do_something(&self) {
// do something
self.app_handler.emit_all("events", some_payload { ... });
}
}
pub struct MonitorHandler(pub Mutex<MonitorHandler>);
// main.rs
use hotwatch::Hotwatch;
use tauri::{ Manager, AppHandle };
use crate::handler::MonitorHandler;
fn main() {
// let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
// let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
let context = tauri::generate_context!();
tauri::Builder::default()
.setup(move |app| {
let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
let struct_app_handle = app.handle().clone();
let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor, app_handler: struct_app_handle }));
app.manage(store);
})
.invoke_handler(tauri::generate_handler![
initialize_app_handler
])
.run(context)
.expect("error while running tauri application");
}

Related

Hi I am new to rust And I tried to setup a matrix rust server... and it always throws me a issue in error.rs

error[E0599]: no method named `map_err` found for type parameter `Self` in the current scope
--> src\server\error.rs:40:24
|
34 | pub trait ResultExt<T>: Sized {
| ----------------------------- method `map_err` not found for this type parameter
...
40 | let res = self.map_err(|_| MatrixError::internal_err());
| ^^^^^^^ method not found in `Self`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `map_err`, perhaps you need to add another supertrait for one of them:
|
34 | pub trait ResultExt<T>: Sized + ServiceFactory {
| ++++++++++++++++
34 | pub trait ResultExt<T>: Sized + TryFutureExt {
| ++++++++++++++
34 | pub trait ResultExt<T>: Sized + TryStreamExt {
| ++++++++++++++
34 | pub trait ResultExt<T>: Sized + actix_service::Service {
| ++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0599`.
warning: `maelstrom` (bin "maelstrom") generated 12 warnings
error: could not compile `maelstrom` due to previous error; 12 warnings emitted
It runs into an error where it says that self.map_err is not defined
I tried to completely delete the error.rs out of the code (it didn't work)
here is the code to mess around with
(oh and yes the matrix server uses actix web)
use actix_web::{http::StatusCode, Error, HttpResponse};
#[derive(Clone, Debug, serde::Serialize)]
pub struct MatrixError {
#[serde(skip)]
pub status: StatusCode,
pub errcode: ErrorCode,
pub error: String,
}
impl MatrixError {
pub fn new(status: StatusCode, errcode: ErrorCode, error: &str) -> Self {
MatrixError {
status,
errcode,
error: error.to_string(),
}
}
pub fn internal_err() -> Self {
Self::new(
StatusCode::INTERNAL_SERVER_ERROR,
ErrorCode::UNKNOWN,
"Internal server error.",
)
}
}
impl From<MatrixError> for Error {
fn from(e: MatrixError) -> Self {
HttpResponse::build(e.status).json(e).into()
}
}
pub trait ResultExt<T>: Sized {
fn with_codes(self, status: StatusCode, code: ErrorCode) -> Result<T, MatrixError>;
fn unknown(self) -> Result<T, MatrixError> {
#[cfg(debug_assertions)] // don't leak ISE info in release mode
let res = self.with_codes(StatusCode::INTERNAL_SERVER_ERROR, ErrorCode::UNKNOWN);
#[cfg(not(debug_assertions))]
let res = self.map_err(|_| MatrixError::internal_err());
res
}
}
impl<T, E> ResultExt<T> for Result<T, E>
where
E: std::fmt::Display,
{
fn with_codes(self, status: StatusCode, code: ErrorCode) -> Result<T, MatrixError> {
self.map_err(|e| MatrixError {
status,
errcode: code,
error: format!("{}", e),
})
}
}

Should I try to access self in a PointerPressed event handler for a CoreApp in the Rust Crate for Windows?

E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement.
#![windows_subsystem = "windows"]
use windows::{
core::*,
Foundation::*,
ApplicationModel::Core::*,
Foundation::Numerics::*,
Foundation::TypedEventHandler,
Win32::System::Com::*,
UI::{
Core::*,
Composition::*,
},
};
use windows as Windows;
#[implement(Windows::ApplicationModel::Core::IFrameworkViewSource)]
struct App();
#[allow(non_snake_case)]
impl App {
fn CreateView(&self) -> Result<IFrameworkView> {
// TODO: need self query `self.into()` to support implementing both IFrameworkViewSource and IFrameworkView on the same object.
Ok(AppView::new().into())
}
}
#[implement(Windows::ApplicationModel::Core::IFrameworkView)]
struct AppView {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
#[allow(non_snake_case)]
impl AppView {
fn new() -> Self {
Self {
m_target: None,
m_visuals: None,
m_selected: None,
m_offset: None,
}
}
fn Initialize(&self, _: &Option<CoreApplicationView>) -> Result<()> {
Ok(())
}
fn Load(&self, _: &HSTRING) -> Result<()> {
Ok(())
}
fn Uninitialize(&self) -> Result<()> {
Ok(())
}
fn Run(&self) -> Result<()> {
let window = CoreWindow::GetForCurrentThread()?;
window.Activate()?;
let dispatcher = window.Dispatcher()?;
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit)?;
Ok(())
}
fn SetWindow(&mut self, window: &Option<CoreWindow>) -> Result<()> {
let compositor = Compositor::new()?;
let root = compositor.CreateContainerVisual()?;
self.m_target = Some(compositor.CreateTargetForCurrentView()?);
let target = self.m_target.as_ref().unwrap();
target.SetRoot(&root)?;
self.m_visuals = Some(root.Children()?);
let visuals = self.m_visuals.as_ref().unwrap(); // extra line for test is ok
window.as_ref().unwrap().PointerPressed(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args|
{
let args = args.as_ref().unwrap();
let currentpoint = args.CurrentPoint().unwrap();
let point = currentpoint.Position().unwrap(); // Point not Vector2
//let visuals: &VisualCollection = self.m_visuals.as_ref().unwrap();
let visuals = self.m_visuals.as_ref().unwrap(); // E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement
Ok(())
}
))?;
window.as_ref().unwrap().PointerMoved(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
window.as_ref().unwrap().PointerReleased(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
Ok(())
}
fn AddVisual(_point: Point) {
//...
}
}
fn main() -> Result<()> {
unsafe {
CoInitializeEx(std::ptr::null_mut(), COINIT_MULTITHREADED)?;
}
let app: IFrameworkViewSource = App().into();
CoreApplication::Run(app)?;
Ok(())
}
Capturing AppView's instance self reference in v0.30 doesn't seem to be possible, because TypedEventHandler::new has a + 'static requirement for the callback (see), so any reference it captures must be 'static (a global variable basically).
Please raise an issue here if you want this. Your code looks like a reasonable way to use this API.
Until then, as a workaround you could make a level of indirection, where instead of storing the state directly in AppView, you store it in a shared helper object, for example:
struct AppView {
m_state: Rc<RefCell<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
You can clone it move into the callback for modification:
let pointer_pressed_state = Rc::clone(self.m_state);
let pointer_pressed_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_pressed_state.borrow(); // or .borrow_mut()
...
});
let pointer_moved_state = Rc::clone(self.m_state);
let pointer_moved_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_moved_state.borrow(); // or .borrow_mut()
...
});
This should work, because now the closure doesn't capture any references (everything gets moved).
If you want, you can add methods to AppViewState, and call them from the closures like state_ref.OnPointerPressed(...).
Another option that I don't recommend is to use unsafe and cast self to 'static.
Rc<RefCell> gives a thread related compiler error but changing to Arc<Mutex> resolves this.
struct AppView {
m_state: Arc<Mutex<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}

Compile error in Substrate smart contract 'the trait bound ink_storage::Vec<...>: WrapperTypeEncode is not satisfied'

I'm a newbie on Substrate and blockchain development. Currently, I'm writing a smart contract using Substrate with ink!. I've defined a custom type (struct Person in the code) and created the vector of this type in the contract's storage.
I then create contract's functions for working with that vector data. But the code fails to compile. There are errors with get_person_list() function. The first one is 'the trait bound ink_storage::Vec<Person>: WrapperTypeEncode is not satisfied'.
However, if I remove this function, the code can be compiled successfully. How can I solve this compile error? thanks.
#![cfg_attr(not(feature = "std"), no_std)]
use ink_lang as ink;
#[ink::contract]
mod test {
use ink_prelude::string::String;
use ink_storage::collections::Vec;
use ink_storage::traits::{
SpreadLayout,
PackedLayout,
};
use scale::{Encode, Decode};
#[derive(Debug, Clone, Encode, Decode, SpreadLayout, PackedLayout)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub struct Person {
name: String,
age: u32,
}
#[ink(storage)]
pub struct Test {
person_list: Vec<Person>,
}
impl Test {
#[ink(constructor)]
pub fn new() -> Self {
Self { person_list: Vec::new() }
}
#[ink(message)]
pub fn add_person(&mut self, name: String, age: u32) {
self.person_list.push(Person { name, age });
}
#[ink(message)]
pub fn get_person(&self, index: u32) -> Option<Person> {
self.person_list.get(index).cloned()
}
#[ink(message)]
pub fn person_list_count(&self) -> u32 {
self.person_list.len() as u32
}
#[ink(message)]
pub fn get_person_list(&self) -> Vec<Person> {
self.person_list.clone()
}
}
}
I think it will work if you use use ink_prelude::vec::Vec; instead of use ink_storage::collections::Vec;.

I want to keep a reference inside an HashMap but I'm not able to specify correctly the lifetime

I'm using ws-rs to build a chat app. I need to keep associations between a Sender and a Username but I'm having issues in referencing the Sender in my HashMap.
I'm 99.99% sure that Handler keeps the ownership of Sender.
I had solved this problem cloning every time the sender passing it to another thread, together with the username, via a mspc::channel but I wanna try to use smart pointers and reference.
Here is a Minimal, Reproducible Example:
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
trait Factory {
fn connection_made(&mut self, _: Sender) -> MHandler;
}
trait Handler {
fn on_open(&mut self) -> ();
}
struct MFactory<'a> {
connections: Arc<HashMap<String, &'a Sender>>,
}
struct MHandler<'a> {
sender: Sender,
connections: Arc<HashMap<String, &'a Sender>>,
}
struct Sender{}
fn main() {
let mut connections: Arc<HashMap<String, &Sender>> = Arc::new(HashMap::new());
// Server thread
let server = thread::Builder::new()
.name(format!("server"))
.spawn(|| {
let mFactory = MFactory {
connections: connections.clone(),
};
let mHandler = mFactory.connection_made(Sender{});
mHandler.on_open();
})
.unwrap();
}
impl Factory for MFactory<'_> {
fn connection_made(&mut self, s: Sender) -> MHandler {
MHandler {
sender: s,
connections: self.connections.clone(),
}
}
}
impl Handler for MHandler<'_> {
fn on_open(&mut self) -> () {
self.connections.insert(format!("Alan"), &self.sender);
}
}
Playground.
Ps: I'm aware that Arc doesn't guarantee mutual exclusion so I have to wrap my HasMap in a Mutex. I've decided to ignore it for the moment.
What you're trying to do is unsafe. You're keeping in a map that lives for the duration of your program references to a structure that is owned by another object inside a thread. So the map outlives the the objects it stores references to, which Rust prevents.
Following on my comment, this code compiles (I've removed the factory for clarity):
use std::collections::HashMap;
use std::sync::{Arc,Mutex};
use std::thread;
use std::ptr::NonNull;
struct MHandler {
sender: Sender,
}
struct Sender{}
struct Wrapper(NonNull<Sender>);
unsafe impl std::marker::Send for Wrapper { }
fn main() {
let connections: Arc<Mutex<HashMap<String, Wrapper>>> = Arc::new(Mutex::new(HashMap::new()));
// Server thread
let server = thread::Builder::new()
.name(format!("server"))
.spawn(move || {
let mut handler = MHandler {
sender: Sender{},
};
let w = Wrapper(NonNull::new(&mut handler.sender as *mut Sender).unwrap());
Arc::clone(&connections).lock().unwrap().insert(format!("Alan"), w);
})
.unwrap();
}
This is using raw pointers (https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer) and NonNull to be able to implement Send (see https://github.com/rust-lang/rust/issues/21709 and https://play.rust-lang.org/?gist=1ce2532a0eefc60695663c26faddebe1&version=stable)
Not sure this helps you.

Replace a struct member with a new value that uses the previous value

I have a struct which owns a boxed value of some trait type. The struct itself also implements the same trait. I would like to replace the value with a new instance of the same struct, which wraps it.
The following code, which does not compile, should make it more clear what I am trying to do:
trait T {}
struct S {
t: Box<dyn T>,
}
impl T for S {}
impl S {
fn new(t: Box<dyn T>) -> Self {
Self { t }
}
fn wrap_t(&mut self) {
self.t = Box::new(Self::new(self.t))
}
}
This fails:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:14:37
|
14 | self.t = Box::new(Self::new(self.t))
| ^^^^ cannot move out of borrowed content
Implementing wrap_t like this does compile:
use std::mem;
fn wrap_t(&mut self) {
unsafe {
let old_t = mem::replace(&mut self.t, mem::uninitialized());
let new_t = Box::new(Self::new(old_t));
let uninit = mem::replace(&mut self.t, new_t);
mem::forget(uninit);
}
}
I wonder if there is a safe way to do this.
The only unsafe function you are using is mem::uninitialized. You need something to pass to mem::replace, but implementing Default won't work because default() returns Self, which prevents it from being object-safe. Similarly, you can't implement Clone to duplicate the old value, since clone() also returns Self.
You can just implement a dummy type for the purpose though:
struct Dummy;
impl T for Dummy {}
fn wrap_t(&mut self) {
let old_t = mem::replace(&mut self.t, Box::new(Dummy));
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
You also won't need the mem::forget here now either (I'm assuming that was there to prevent undefined behaviour when the uninitialised memory was dropped).
As an alternative to Clone, you can roll your own own, which clones to a Box<dyn T>, avoiding having a Self in the method signature, so the trait stays object safe:
trait T: Debug {
fn clone_in_box(&self) -> Box<dyn T>;
}
impl T for S {
fn clone_in_box(&self) -> Box<dyn T> {
Box::new(S {
t: self.t.clone_in_box(),
})
}
}
fn wrap_t(&mut self) {
let cloned = self.clone_in_box();
let old_t = mem::replace(&mut self.t, cloned);
let new_t = Box::new(Self::new(old_t));
mem::replace(&mut self.t, new_t);
}
There is also an alternative design, which is much simpler to understand when reading the code. That is just to consume self and return a new object:
fn wrap_t(self) -> Self {
Self::new(Box::new(Self::new(self.t)))
}
And instead of this:
s.wrap_t();
You would do:
s = s.wrap_t();

Resources