Mercurial > hg-stable
comparison rust/chg/src/uihandler.rs @ 44850:c794d0da5fb2
rust-chg: reimplement uihandler by using async-trait and tokio-0.2
We no longer have to consume self and arguments.
Differential Revision: https://phab.mercurial-scm.org/D8444
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Fri, 10 Apr 2020 22:23:10 +0900 |
parents | e9e44e61042b |
children | 4b0185841058 |
comparison
equal
deleted
inserted
replaced
44849:cb5822e6e545 | 44850:c794d0da5fb2 |
---|---|
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | 1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org> |
2 // | 2 // |
3 // This software may be used and distributed according to the terms of the | 3 // This software may be used and distributed according to the terms of the |
4 // GNU General Public License version 2 or any later version. | 4 // GNU General Public License version 2 or any later version. |
5 | 5 |
6 use futures::future::IntoFuture; | 6 use async_trait::async_trait; |
7 use futures::Future; | |
8 use std::io; | 7 use std::io; |
9 use std::os::unix::io::AsRawFd; | 8 use std::os::unix::io::AsRawFd; |
10 use std::os::unix::process::ExitStatusExt; | 9 use std::os::unix::process::ExitStatusExt; |
11 use std::process::Stdio; | 10 use std::process::Stdio; |
12 use tokio; | 11 use tokio; |
14 | 13 |
15 use crate::message::CommandSpec; | 14 use crate::message::CommandSpec; |
16 use crate::procutil; | 15 use crate::procutil; |
17 | 16 |
18 /// Callback to process shell command requests received from server. | 17 /// Callback to process shell command requests received from server. |
19 pub trait SystemHandler: Sized { | 18 #[async_trait] |
19 pub trait SystemHandler { | |
20 type PagerStdin: AsRawFd; | 20 type PagerStdin: AsRawFd; |
21 type SpawnPagerResult: IntoFuture<Item = (Self, Self::PagerStdin), Error = io::Error>; | |
22 type RunSystemResult: IntoFuture<Item = (Self, i32), Error = io::Error>; | |
23 | 21 |
24 /// Handles pager command request. | 22 /// Handles pager command request. |
25 /// | 23 /// |
26 /// Returns the pipe to be attached to the server if the pager is spawned. | 24 /// Returns the pipe to be attached to the server if the pager is spawned. |
27 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult; | 25 async fn spawn_pager(&mut self, spec: &CommandSpec) -> io::Result<Self::PagerStdin>; |
28 | 26 |
29 /// Handles system command request. | 27 /// Handles system command request. |
30 /// | 28 /// |
31 /// Returns command exit code (positive) or signal number (negative). | 29 /// Returns command exit code (positive) or signal number (negative). |
32 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult; | 30 async fn run_system(&mut self, spec: &CommandSpec) -> io::Result<i32>; |
33 } | 31 } |
34 | 32 |
35 /// Default cHg implementation to process requests received from server. | 33 /// Default cHg implementation to process requests received from server. |
36 pub struct ChgUiHandler {} | 34 pub struct ChgUiHandler {} |
37 | 35 |
39 pub fn new() -> ChgUiHandler { | 37 pub fn new() -> ChgUiHandler { |
40 ChgUiHandler {} | 38 ChgUiHandler {} |
41 } | 39 } |
42 } | 40 } |
43 | 41 |
42 #[async_trait] | |
44 impl SystemHandler for ChgUiHandler { | 43 impl SystemHandler for ChgUiHandler { |
45 type PagerStdin = ChildStdin; | 44 type PagerStdin = ChildStdin; |
46 type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>; | |
47 type RunSystemResult = Box<dyn Future<Item = (Self, i32), Error = io::Error> + Send>; | |
48 | 45 |
49 fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult { | 46 async fn spawn_pager(&mut self, spec: &CommandSpec) -> io::Result<Self::PagerStdin> { |
50 let mut pager = new_shell_command(&spec).stdin(Stdio::piped()).spawn()?; | 47 let mut pager = new_shell_command(&spec).stdin(Stdio::piped()).spawn()?; |
51 let pin = pager.stdin.take().unwrap(); | 48 let pin = pager.stdin.take().unwrap(); |
52 procutil::set_blocking_fd(pin.as_raw_fd())?; | 49 procutil::set_blocking_fd(pin.as_raw_fd())?; |
53 // TODO: if pager exits, notify the server with SIGPIPE immediately. | 50 // TODO: if pager exits, notify the server with SIGPIPE immediately. |
54 // otherwise the server won't get SIGPIPE if it does not write | 51 // otherwise the server won't get SIGPIPE if it does not write |
55 // anything. (issue5278) | 52 // anything. (issue5278) |
56 // kill(peerpid, SIGPIPE); | 53 // kill(peerpid, SIGPIPE); |
57 tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors | 54 tokio::spawn(async { pager.await }); // just ignore errors |
58 Ok((self, pin)) | 55 Ok(pin) |
59 } | 56 } |
60 | 57 |
61 fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult { | 58 async fn run_system(&mut self, spec: &CommandSpec) -> io::Result<i32> { |
62 let fut = new_shell_command(&spec) | 59 let status = new_shell_command(&spec).spawn()?.await?; |
63 .spawn() | 60 // TODO: unindent |
64 .into_future() | 61 { |
65 .flatten() | 62 { |
66 .map(|status| { | |
67 let code = status | 63 let code = status |
68 .code() | 64 .code() |
69 .or_else(|| status.signal().map(|n| -n)) | 65 .or_else(|| status.signal().map(|n| -n)) |
70 .expect("either exit code or signal should be set"); | 66 .expect("either exit code or signal should be set"); |
71 (self, code) | 67 Ok(code) |
72 }); | 68 } |
73 Box::new(fut) | 69 } |
74 } | 70 } |
75 } | 71 } |
76 | 72 |
77 fn new_shell_command(spec: &CommandSpec) -> Command { | 73 fn new_shell_command(spec: &CommandSpec) -> Command { |
78 let mut builder = Command::new("/bin/sh"); | 74 let mut builder = Command::new("/bin/sh"); |