I develop an update system in rust. It create patches between 2 binaries. You can download binaries or patches and install it. Patches and binaries are compressed. The client download compressed files and decompress it
I do
#[async_trait]
impl<'a> Stream for UpdatePackageStream<'a> {
type Item = Result<SharedUpdateProgress, UpdateError>;
async fn poll_next(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
let download_poll = this.download_stream.poll_next_unpin(cx);
let apply_poll = this.apply_stream.poll_next_unpin(cx);
match (download_poll, apply_poll) {
(Poll::Ready(None), Poll::Ready(None)) => Poll::Ready(None),
(Poll::Pending, Poll::Pending) => Poll::Pending,
(Poll::Pending, Poll::Ready(None)) => Poll::Pending,
(Poll::Ready(None), Poll::Pending) => Poll::Pending,
(Poll::Ready(Some(Err(err))), _) => {
// Download errors cause the apply thread to be cancelled
this.apply_stream.cancel();
Poll::Ready(Some(Err(err)))
}
(download_poll, apply_poll) => {
let mut delta = Progression::default();
if let Poll::Ready(Some(Ok(download_progress))) = download_poll {
this.state.borrow_mut().available = download_progress.available;
let mut state = this.shared_state.lock().await;
state.downloading_operation_idx = download_progress.available.operation_idx;
delta.downloaded_files = download_progress.delta_downloaded_files;
delta.downloaded_bytes = download_progress.delta_downloaded_bytes;
this.apply_stream.notify(download_progress.available);
}
if let Poll::Ready(Some(apply_progress)) = apply_poll {
match apply_progress {
Ok(apply_progress) => {
this.state.borrow_mut().applied.operation_idx =
apply_progress.operation_idx;
let mut state = this.shared_state.lock().await; // note the await here, so the closure must be async
state.applying_operation_idx = apply_progress.operation_idx;
delta.applied_files = apply_progress.delta_applied_files;
delta.applied_input_bytes = apply_progress.delta_input_bytes;
delta.applied_output_bytes = apply_progress.delta_output_bytes;
}
Err(ApplyError::OperationFailed { path, slice, cause }) => {
warn!("{} failed: {}", path, cause);
let mut state = this.state.borrow_mut();
state.failures.push(match slice {
Some(slice) => metadata::v1::Failure::Slice { path, slice },
None => metadata::v1::Failure::Path { path },
});
delta.failed_files = 1;
}
Err(ApplyError::Cancelled) => {}
Err(ApplyError::PoisonError) => {
return Poll::Ready(Some(Err(UpdateError::PoisonError)))
}
}
}
`` {
let mut state = this.shared_state.lock().await;
state.inc_progress(delta);
}
Poll::Ready(Some(Ok(this.shared_state.clone())))
}
}
}
}
But get
error[E0195]: lifetime parameters or bounds on method `poll_next` do not match the trait declaration
--> lib/src/workspace/updater.rs:143:14
|
143 | async fn poll_next(
| ______________^
144 | | self: Pin<&mut Self>,
145 | | cx: &mut std::task::Context<'_>,
146 | | ) -> Poll<Option<Self::Item>> {
| |_____^ lifetimes do not match method in trait
Stream is from future::stream::Stream
Without async_trait and the 2 async fn, the fn and my app build without issue.
If I use std::sync::Mutex
instead of tokio::sync::Mutex
, I get
let state = update_state.lock();
| ----- has type `std::sync::MutexGuard<'_, UpdateProgress>` which is not `Send`
...
273 | let res = update_stream.try_for_each(|_state| future::ready(Ok(()))).await;
| ^^^^^^ await occurs here, with `state` maybe used later
...
305 | }
| - `state` is later dropped here
= note: required for the cast from `impl futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>>` to the object type `dyn futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>> + std::marker::Send`
UpdateProgress is a simple struct.
I don't inderstand why I get these issues and don't know how to fix them