Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite with rust and create a cargo package #1

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
fc02e03
Implement hokaido as a cargo package
hibariya Oct 19, 2015
9cda54b
Update dependencies
hibariya Oct 19, 2015
44e5cd3
Unnecessary at this point
hibariya Oct 20, 2015
6b9238a
Update msgpack-rust
hibariya Oct 20, 2015
04fa310
Default port is 4423, not 4747 :beer:
hibariya Oct 21, 2015
154ac07
Remove duplicated line
hibariya Oct 21, 2015
4a96f2f
Broadcast winsize after join
hibariya Oct 21, 2015
aae4d11
Revert "Update msgpack-rust"
ursm Oct 22, 2015
313336d
Whitespace
hibariya Oct 22, 2015
ab0fa18
Listen 0.0.0.0:4423 by default
hibariya Oct 22, 2015
3fa8cf6
Add description
hibariya Oct 24, 2015
fa7e0ae
Initialize a buffer before out of the loop
hibariya Oct 25, 2015
ad5d391
Update msgpack-rust
hibariya Oct 25, 2015
8ae242e
Ignore SendError due to takeover
hibariya Oct 26, 2015
87072f0
Version 0.0.2
hibariya Oct 30, 2015
c07048b
Fix failing build on macos
hrysd Oct 31, 2015
83dd591
Merge pull request #2 from hrysd/build-macos
hibariya Oct 31, 2015
0265d29
Add about installation
hibariya Oct 31, 2015
d4a52ce
Make brevity by using `try!` instead of `match`
hibariya Nov 1, 2015
a6e4745
Apply rustfmt
hibariya Nov 3, 2015
edfdcd9
Enable more lint options
hibariya Nov 4, 2015
b95ee17
Build with rust-clippy and fix its warnings
hibariya Nov 5, 2015
425c38c
Add .editorconfig to keep code clean
hibariya Nov 5, 2015
509c9e9
Version 0.0.3
hibariya Nov 11, 2015
ace1bd8
Replace deprecated `sleep_ms` with `sleep`
hibariya Nov 11, 2015
35e0741
Broadcast each message
hibariya Nov 12, 2015
eb9b427
Update pty-rs
hibariya Nov 14, 2015
7b175fc
Impl custom error
hibariya Nov 15, 2015
68b5c03
Remove closed stream from channel
hibariya Nov 23, 2015
f6f9eb2
Restore original termios at exit
hibariya Nov 23, 2015
c62cc68
Fix clippy warnings
hibariya Nov 25, 2015
30365a6
Version 0.0.4
hibariya Nov 25, 2015
9a4220b
Increase output buffer size to avoid character corruption
hibariya Dec 11, 2015
ec0b6b5
Version 0.0.5
hibariya Dec 11, 2015
86a7c8a
Use `output.write` instead of `print!`
hibariya Dec 19, 2015
c14eac1
Use pty-shell
hibariya Dec 27, 2015
2e7c13e
Version 0.0.6
hibariya Dec 30, 2015
466563d
Update pty-shell dependencies
hanachin Feb 3, 2016
528bbda
Merge pull request #4 from hanachin/update_pty_shell_dependencies
hibariya Feb 4, 2016
6ad2038
Version 0.0.7
hibariya Feb 4, 2016
adafc75
bump libc version to fix warning in rustc v1.6
takkanm Feb 8, 2016
cff73c2
Merge pull request #5 from takkanm/bump_libc_version
hibariya Feb 9, 2016
0c2a6c8
Log connection information
hibariya Mar 13, 2016
01b5aef
Removing channel.broadcaster is unnecessary
hibariya Mar 22, 2016
1e3cd65
Version 0.0.8
hibariya Mar 23, 2016
9c01087
Update nix
hibariya Mar 23, 2016
58e5abd
Add .travis.yml
hibariya Mar 25, 2016
b4da846
Don't have to notify to the former broadcaster if it has already gone
hibariya Mar 26, 2016
c645fa8
Version 0.0.9
hibariya Mar 27, 2016
babaa2e
bump rmp-serialize version
takkanm Jan 24, 2017
c396216
Merge pull request #7 from idobata/update_rmp-serialize_to_compile_by…
hibariya Feb 2, 2017
817f65d
Version 0.0.10
hibariya Feb 2, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4

[*.md]
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
Gemfile.lock
Cargo.lock
target
pkg/*
**/*.o
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: rust
rust:
- stable
- beta
- nightly
26 changes: 26 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = 'hokaido'
version = '0.0.10'
authors = ['Hika Hibariya <[email protected]>']
repository = 'https://github.com/idobata/hokaido'
homepage = 'https://github.com/idobata/hokaido'
license='MIT'
description='Terminal sharing tool.'
keywords = ['terminal', 'tool']

[dependencies]
docopt='0.6'
env_logger = '0.3'
libc='0.2.6'
log = '0.3'
nix='0.5.0'
pty='0.1.6'
pty-shell='0.1.3'
rmp-serialize = '0.8'
rustc-serialize='0.3'
termios='0.2.0'
clippy = {version = '0.0', optional = true}

[features]
default = []
dev = ['clippy']
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
# Hokaido

## 1. Start server (Anywhere in internet)
Hokaido is a character based terminal sharing tool. It's speedy and clear.

## Installation

``` sh
$ cargo install hokaido
```

## How to use

### 1. Start server

Server is needed to relay communication between broadcaster and watchers.

``` sh
$ hokaido server # on 203.0.113.10:4423
```

## 2. Watch (Tokyo)
### 2. Watch

`watch` displays broadcaster's shell output.

``` sh
$ hokaido watch --host 203.0.113.10
```

## 3. Broadcast (Hokaido!)
### 3. Broadcast

`broadcast` invokes a new $SHELL and starts broadcasting its output.

``` sh
$ hokaido broadcast --host 203.0.113.10
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
158 changes: 158 additions & 0 deletions src/broadcast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use std::{env, error, fmt, io, process, result, thread};
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};

use pty;
use pty_shell::{self, winsize, PtyShell};
use libc;

use message;

#[derive(Debug)]
pub enum Error {
Message(message::Error),
Pty(pty::Error),
PtyShell(pty_shell::Error),
Io(io::Error),
}

impl error::Error for Error {
fn description(&self) -> &str {
"Broadcast error"
}

fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Message(ref err) => Some(err),
Error::Pty(ref err) => Some(err),
Error::PtyShell(ref err) => Some(err),
Error::Io(ref err) => Some(err),
}
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
error::Error::description(self).fmt(f)
}
}

impl From<message::Error> for Error {
fn from(err: message::Error) -> Error {
Error::Message(err)
}
}

impl From<pty::Error> for Error {
fn from(err: pty::Error) -> Error {
Error::Pty(err)
}
}

impl From<pty_shell::Error> for Error {
fn from(err: pty_shell::Error) -> Error {
Error::PtyShell(err)
}
}

impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::Io(err)
}
}

pub type Result<T> = result::Result<T, Error>;

struct NotificationHandler {
stream: TcpStream,
sender: Sender<Option<message::Notification>>,
}

struct ShellHandler {
channel: Sender<Option<message::Notification>>,
}

impl pty_shell::PtyHandler for ShellHandler {
fn output(&mut self, data: &[u8]) {
let string = String::from_utf8_lossy(&data[..]).into_owned();
let _ = self.channel.send(Some(message::Notification::Output(string)));
}

fn resize(&mut self, size: &winsize::Winsize) {
let _ = self.channel.send(Some(build_winsize_notification(size)));
}

fn shutdown(&mut self) {
let _ = self.channel.send(None);
}
}

pub fn execute(host: String, port: i32, channel_name: String) -> Result<()> {
let mut stream = try!(TcpStream::connect(&format!("{}:{}", host, port)[..]));
let (sender, receiver) = channel();

try!(message::JoinRequest::Broadcast(channel_name.clone()).send(&mut stream));
try!(message::JoinResponse::receive(&stream));

NotificationHandler::spawn(&stream, &sender);

let child = try!(pty::fork());
try!(child.exec(env::var("SHELL").unwrap_or("bash".to_owned())));
try!(child.proxy(ShellHandler { channel: sender.clone() }));

let winsize = try!(winsize::from_fd(libc::STDIN_FILENO));
let _ = sender.send(Some(build_winsize_notification(&winsize)));

for message in receiver {
match message {
Some(notification) => try!(notification.send(&mut stream)),
None => break,
}
}

try!(child.wait());

Ok(())
}

impl NotificationHandler {
fn spawn(stream: &TcpStream, sender: &Sender<Option<message::Notification>>) {
let mut handler = NotificationHandler {
stream: stream.try_clone().unwrap(),
sender: sender.clone(),
};

thread::spawn(move || {
handler.process().unwrap_or_else(|e| {
println!("{:?}", e);
process::exit(1);
});
});
}

fn process(&mut self) -> Result<()> {
loop {
let notification = try!(message::Notification::receive(&self.stream));

match notification {
message::Notification::Closed(reason) => {
println!("Broadcast has stopped: {}", reason);
break;
}
message::Notification::WatcherJoined(_) => {
let winsize = try!(winsize::from_fd(libc::STDIN_FILENO));
let _ = self.sender.send(Some(build_winsize_notification(&winsize)));
}
_ => (),
}
}

let _ = self.sender.send(None);

Ok(())
}
}

fn build_winsize_notification(size: &winsize::Winsize) -> message::Notification {
message::Notification::Output(format!("\x1b[8;{};{}t", size.ws_row, size.ws_col))
}
74 changes: 74 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#![deny(missing_debug_implementations, missing_copy_implementations,
trivial_casts, trivial_numeric_casts,
unstable_features,
unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate docopt;
extern crate libc;
extern crate nix;
extern crate pty;
extern crate pty_shell;
extern crate rmp_serialize as msgpack;
extern crate rustc_serialize;
extern crate termios;

#[macro_use]
extern crate log;
extern crate env_logger;

mod message;
mod broadcast;
mod server;
mod watch;

use docopt::Docopt;

static USAGE: &'static str = "
Usage:
hokaido <command> [--host=<host>] [--port=<port>] [--channel=<channel>]
hokaido (-h | --help)
hokaido (-v | --version)

Options:
-h --help Show this screen.
-v --version Show the version of hokaido.
--host=<host> Server name [default: 0.0.0.0].
--port=<port> Server port [default: 4423].
--channel=<channel> Channel Name [default: default].
";

#[derive(RustcDecodable, Debug)]
struct Args {
arg_command: Option<String>,
flag_host: String,
flag_port: i32,
flag_channel: String,
flag_version: bool,
}

fn main() {
let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

env_logger::init().unwrap();

match args.arg_command {
Some(command_name) => {
match command_name.as_ref() {
"broadcast" => broadcast::execute(args.flag_host, args.flag_port, args.flag_channel).unwrap_or_else(|e| panic!(e)),
"server" => server::execute(args.flag_host, args.flag_port).unwrap_or_else(|e| panic!(e)),
"watch" => watch::execute(args.flag_host, args.flag_port, args.flag_channel).unwrap_or_else(|e| panic!(e)),
_ => unreachable!(),
}
}
_ => {
if args.flag_version {
println!("{}", env!("CARGO_PKG_VERSION"));
} else {
unreachable!();
}
}
}
}
Loading