├── .gitignore
├── .travis.yml
├── Cargo.toml
├── Makefile
├── Readme.md
├── src
├── bin
│ └── thrust.rs
├── binary_protocol.rs
├── dispatcher.rs
├── event_loop.rs
├── lib.rs
├── protocol.rs
├── reactor.rs
├── result.rs
├── runner.rs
├── service.rs
├── testing.rs
├── transport.rs
└── util.rs
├── tests
├── namespace.rs
└── struct.rs
├── thrust-codegen
├── Cargo.toml
└── src
│ └── lib.rs
├── thrust-examples
├── Cargo.toml
├── main.thrift
└── src
│ ├── foobar.rs
│ ├── foobar1.rs
│ └── lib.rs
├── thrust-macros-test
├── Cargo.toml
└── src
│ └── lib.rs
├── thrust-macros
├── Cargo.toml
└── src
│ └── lib.rs
└── thrust-parser
├── Cargo.toml
└── src
└── lib.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | Cargo.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | matrix:
3 | include:
4 | - rust: nightly
5 | env: TEST_SUITE=suite_nightly
6 | script:
7 | - cargo build --verbose
8 | - cargo test --verbose
9 | - cd thrust-parser && cargo test --verbose && cd ..
10 | - cd thrust-macros && cargo test --verbose && cd ..
11 | - cd thrust-macros-test && cargo test --verbose && cd ..
12 | - if [ "$TEST_SUITE" = "suite_nightly" ]; then cargo bench --verbose; fi
13 | after_success: |
14 | [ $TRAVIS_BRANCH = master ] &&
15 | [ $TRAVIS_PULL_REQUEST = false ] &&
16 | cargo doc &&
17 | echo "" > target/doc/index.html &&
18 | sudo pip install ghp-import &&
19 | ghp-import -n target/doc &&
20 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
21 | env:
22 | global:
23 | secure: R/VUiFqpQX5wA1aeK8GasWjBQQd4XvpmktacItZ885tNvjOZvj6sGs9OOnpj0fiMgbO8csUBlVcprPRUyl0B+QxuetWZAcNf09sPqR2eQrtU94p3f2Ce41SHqHGaz1tLdnIUHjjm+F8FM514tDMPY3GXeScqSyl68obtMpJf/pU=
24 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "thrust"
3 | version = "0.1.0"
4 | description = "Thrift for Rust"
5 | documentation = "https://thehydroimpulse.github.io/thrust/thrust/index.html"
6 | homepage = "https://github.com/thehydroimpulse/thrust"
7 | repository = "https://github.com/thehydroimpulse/thrust"
8 | readme = "Readme.md"
9 | keywords = ["thrift", "rpc", "async", "networking"]
10 | license = "MIT"
11 | authors = ["Daniel Fagnan "]
12 |
13 | [dependencies]
14 | byteorder = "0.4"
15 | docopt = "0.6"
16 | rustc-serialize = "0.3"
17 | lazy_static = "0.1.*"
18 | tangle = "0.4.0"
19 | rand = "0.3"
20 | slab = "0.1.3"
21 | num_cpus = "0.2"
22 | libc = "0.2"
23 |
24 | [dependencies.mio]
25 | git = "https://github.com/carllerche/mio"
26 |
27 | [dependencies.bytes]
28 | git = "https://github.com/carllerche/bytes"
29 |
30 | [dependencies.thrust_codegen]
31 | path = "thrust-codegen"
32 |
33 | [dependencies.thrust_parser]
34 | path = "thrust-parser"
35 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | echo Nothing to do...
3 |
4 | docs:
5 | cargo doc
6 | in-dir ./target/doc fix-perms
7 | rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/
8 |
9 | push:
10 | git push origin master
11 | git push github master
12 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Thrust [](https://travis-ci.org/thehydroimpulse/thrust)
2 |
3 | **Note:** A work in progress. It's not in a useful state right now.
4 |
5 | A Rust implementation of the [Apache Thrift](https://thrift.apache.org/) protocol that simplifies communicating between independent systems that may be implemented in various languages.
6 |
7 | ## Features
8 |
9 | - Scalable Thrift RPC
10 | - Rust code generator from a `.thrift` file.
11 | - Built on-top of Asynchronous I/O via Mio.
12 | - Heavily uses Futures to manage asynchronous code.
13 | - Multiplexing multiple RPC services on a single event-loop.
14 | - (Currently limited to one for now) Automatically spawn an `EventLoop` per CPU core.
15 |
16 | ## Installing
17 |
18 | ```toml
19 | [dependencies]
20 | thrust = "*"
21 | ```
22 |
23 | You may also want to install the code generator using Cargo:
24 |
25 | ```bash
26 | cargo install thrust
27 | ```
28 |
29 | ## Generating Rust Code
30 |
31 | Thrust comes with a `thrust` binary that compiles your `.thrift` files into Rust code.
32 |
33 | ```bash
34 | thrust hello.thrift .
35 | ```
36 |
37 | The first argument is the input thrift file and the second is the *path* where you want your
38 | Rust file to be written to. The filename will be based on the Rust namespace in your thrift file `namespace rust `.
39 |
40 | ## Spawning The Reactor
41 |
42 | All the I/O and networking is built using Mio. By default, a single Reactor is spun up globally. Support for multiple event loops/Reactors are supported but not working correctly right now.
43 |
44 | ```rust
45 | use thrust::Reactor;
46 |
47 | fn main() {
48 | // Run the reactor that multiplexes many clients and servers.
49 | Reactor::run();
50 | }
51 | ```
52 |
53 | ## Creating a Thrift Service
54 |
55 | Thrust supports creating Thrift services, backed by non-blocking TCP sockets with Mio.
56 |
57 | ```thrift
58 | namespace rust thrift;
59 | // Start by defining a service in your Thrift file.
60 | service Flock {
61 | bool isLoggedIn(1: string token);
62 | }
63 | ```
64 |
65 | After using Thrust to generate the service in Rust, we can start using it.
66 |
67 | ```rust
68 | extern crate thrust;
69 | // Tangle is a futures implementation
70 | extern crate tangle;
71 |
72 | // The generated Rust module.
73 | use thrift::Flock;
74 |
75 | use thrust::{Reactor, Server};
76 | use tangle::{Future, Async};
77 |
78 | pub struct FlockService;
79 |
80 | impl Flock for FlockService {
81 | fn isLoggedIn(&mut self, token: String) -> Future {
82 | if &*token == "123" {
83 | Async::Ok(true)
84 | } else {
85 | Async::Ok(false)
86 | }
87 | }
88 | }
89 |
90 | fn main() {
91 | let addr: SocketAddr = "127.0.0.1:7899".parse().unwrap();
92 |
93 | // Asynchronously bind the server to the specified port. This does
94 | // not block the current thread.
95 | Server::new(FlockService).bind(addr);
96 |
97 | // Run the Reactor with the server.
98 | Reactor::run();
99 | }
100 | ```
101 |
102 | ## Connecting to a Service
103 |
104 | A client is automatically generated for each service you define in your `.thrift` file. Let's keep using our previously defined service as an example.
105 |
106 | ```rust
107 | extern crate thrust;
108 | // Tangle is a futures implementation
109 | extern crate tangle;
110 |
111 | // The generated Rust module.
112 | use thrift::{Flock, Client};
113 |
114 | use thrust::Reactor;
115 | use tangle::{Future, Async};
116 |
117 | fn main() {
118 | let addr: SocketAddr = "127.0.0.1:7899".parse().unwrap();
119 |
120 | // Connect to the service
121 | let flock = Client::connect(addr);
122 |
123 | // Initiate an RPC call
124 | flock.isLoggedIn("123").and_then(move |is| {
125 | if is == true {
126 | println!("You're logged in!")
127 | } else {
128 | println!("Nada");
129 | }
130 |
131 | Async::Ok(())
132 | });
133 |
134 | // Just as before, running the Reactor is required.
135 | Reactor::run();
136 | }
137 | ```
138 |
139 | Remember, Thrust is built using asynchronous primitives and futures are currently the common language for asynchronous tasks. Futures prevent much of the problems in traditional callback-based systems.
140 |
141 | ```rust
142 | enum Error {
143 | AccessDenied
144 | }
145 |
146 | flock.isLoggedIn("123").and_then(move |is_logged_in| {
147 | if is_logged_in == true {
148 | Async::Ok(())
149 | } else {
150 | Async::Err(Error::AccessDenied)
151 | }
152 | }).and_then(move || {
153 | // This will only run if the user has been logged in. Errors
154 | // can be caught later on.
155 |
156 | // ... Do some other fun stuff here.
157 | Async::Ok(())
158 | }).error(move |err| {
159 | Async::Err(err)
160 | })
161 | ```
162 |
163 | ## Sharing Clients
164 |
165 | You might want to share clients across threads and that's perfectly supported! Clients are fully clone-able and are thread-safe.
166 |
167 | ```rust
168 | let shared = client.clone();
169 |
170 | thread::spawn(move || {
171 | shared...
172 | })
173 | ```
174 |
175 | This will re-use the same connection underneath. All TCP connections run in a single Mio event loop (baring multiple event loops). If you wish to use multiple connections, you may create a new client.
176 |
177 | ## License
178 |
179 | MIT — go ham!
180 |
--------------------------------------------------------------------------------
/src/bin/thrust.rs:
--------------------------------------------------------------------------------
1 | extern crate thrust_codegen;
2 | extern crate thrust_parser;
3 | extern crate rustc_serialize;
4 | extern crate docopt;
5 |
6 | use docopt::Docopt;
7 |
8 | use std::io::{Write, Read};
9 | use std::fs::File;
10 | use std::path::Path;
11 | use thrust_parser::Parser;
12 | use thrust_codegen::{compile, find_rust_namespace};
13 |
14 | const USAGE: &'static str = "
15 | Thrust: Thrift compiler for Rust
16 |
17 | Usage:
18 | thrust