rust/chg/src/attachio.rs
author Yuya Nishihara <yuya@tcha.org>
Fri, 10 Apr 2020 21:35:16 +0900
changeset 44688 1f5ab1a9363d
parent 43818 ce088b38f92b
child 44689 6bef9d43cc55
permissions -rw-r--r--
rust-chg: upgrade to 2018 edition and remove useless extern crates Differential Revision: https://phab.mercurial-scm.org/D8399
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     1
// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     2
//
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     3
// This software may be used and distributed according to the terms of the
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     4
// GNU General Public License version 2 or any later version.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     5
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     6
//! Functions to send client-side fds over the command server channel.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     7
44688
1f5ab1a9363d rust-chg: upgrade to 2018 edition and remove useless extern crates
Yuya Nishihara <yuya@tcha.org>
parents: 43818
diff changeset
     8
use futures::{try_ready, Async, Future, Poll};
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     9
use std::io;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    10
use std::os::unix::io::AsRawFd;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    11
use tokio_hglib::codec::ChannelMessage;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    12
use tokio_hglib::protocol::MessageLoop;
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    13
use tokio_hglib::{Client, Connection};
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    14
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    15
use super::message;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    16
use super::procutil;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    17
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    18
/// Future to send client-side fds over the command server channel.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    19
///
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    20
/// This works as follows:
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    21
/// 1. Client sends "attachio" request.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    22
/// 2. Server sends back 1-byte input request.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    23
/// 3. Client sends fds with 1-byte dummy payload in response.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    24
/// 4. Server returns the number of the fds received.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    25
///
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    26
/// If the stderr is omitted, it will be redirected to the stdout. This
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    27
/// allows us to attach the pager stdin to both stdout and stderr, and
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    28
/// dispose of the client-side handle once attached.
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    29
#[must_use = "futures do nothing unless polled"]
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    30
pub struct AttachIo<C, I, O, E>
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    31
where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    32
    C: Connection,
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    33
{
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    34
    msg_loop: MessageLoop<C>,
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    35
    stdin: I,
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    36
    stdout: O,
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    37
    stderr: Option<E>,
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    38
}
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    39
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    40
impl<C, I, O, E> AttachIo<C, I, O, E>
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    41
where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    42
    C: Connection + AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    43
    I: AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    44
    O: AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    45
    E: AsRawFd,
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    46
{
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    47
    pub fn with_client(
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    48
        client: Client<C>,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    49
        stdin: I,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    50
        stdout: O,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    51
        stderr: Option<E>,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    52
    ) -> AttachIo<C, I, O, E> {
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    53
        let msg_loop = MessageLoop::start(client, b"attachio");
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    54
        AttachIo {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    55
            msg_loop,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    56
            stdin,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    57
            stdout,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    58
            stderr,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    59
        }
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    60
    }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    61
}
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    62
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    63
impl<C, I, O, E> Future for AttachIo<C, I, O, E>
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    64
where
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    65
    C: Connection + AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    66
    I: AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    67
    O: AsRawFd,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    68
    E: AsRawFd,
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    69
{
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    70
    type Item = Client<C>;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    71
    type Error = io::Error;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    72
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    73
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    74
        loop {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    75
            let (client, msg) = try_ready!(self.msg_loop.poll());
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    76
            match msg {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    77
                ChannelMessage::Data(b'r', data) => {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    78
                    let fd_cnt = message::parse_result_code(data)?;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    79
                    if fd_cnt == 3 {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    80
                        return Ok(Async::Ready(client));
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    81
                    } else {
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    82
                        return Err(io::Error::new(
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    83
                            io::ErrorKind::InvalidData,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    84
                            "unexpected attachio result",
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
    85
                        ));
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    86
                    }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    87
                }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    88
                ChannelMessage::Data(..) => {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    89
                    // just ignore data sent to uninteresting (optional) channel
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    90
                    self.msg_loop = MessageLoop::resume(client);
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    91
                }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    92
                ChannelMessage::InputRequest(1) => {
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    93
                    // this may fail with EWOULDBLOCK in theory, but the
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    94
                    // payload is quite small, and the send buffer should
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    95
                    // be empty so the operation will complete immediately
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    96
                    let sock_fd = client.as_raw_fd();
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    97
                    let ifd = self.stdin.as_raw_fd();
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    98
                    let ofd = self.stdout.as_raw_fd();
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    99
                    let efd = self.stderr.as_ref().map_or(ofd, |f| f.as_raw_fd());
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   100
                    procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?;
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   101
                    self.msg_loop = MessageLoop::resume(client);
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   102
                }
43818
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   103
                ChannelMessage::InputRequest(..)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   104
                | ChannelMessage::LineRequest(..)
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   105
                | ChannelMessage::SystemRequest(..) => {
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   106
                    return Err(io::Error::new(
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   107
                        io::ErrorKind::InvalidData,
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   108
                        "unsupported request while attaching io",
ce088b38f92b rust: run rustfmt
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39972
diff changeset
   109
                    ));
39972
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   110
                }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   111
            }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   112
        }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   113
    }
7a0ffdd4af78 rust-chg: add future that handles "attachio" request
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   114
}