Sync parity-ewf with parity
112
dapps/src/handlers/async.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Async Content Handler
|
||||||
|
//! Temporary solution until we switch to future-based server.
|
||||||
|
//! Wraps a future and converts it to hyper::server::Handler;
|
||||||
|
|
||||||
|
use std::{mem, time};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use futures::Future;
|
||||||
|
use hyper::{server, Decoder, Encoder, Next, Control};
|
||||||
|
use hyper::net::HttpStream;
|
||||||
|
|
||||||
|
use handlers::ContentHandler;
|
||||||
|
use parity_reactor::Remote;
|
||||||
|
|
||||||
|
const TIMEOUT_SECS: u64 = 15;
|
||||||
|
|
||||||
|
enum State<F, T, M> {
|
||||||
|
Initial(F, M, Remote, Control),
|
||||||
|
Waiting(mpsc::Receiver<Result<T, ()>>, M),
|
||||||
|
Done(ContentHandler),
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AsyncHandler<F, T, M> {
|
||||||
|
state: State<F, T, M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, M> AsyncHandler<F, T, M> {
|
||||||
|
pub fn new(future: F, map: M, remote: Remote, control: Control) -> Self {
|
||||||
|
AsyncHandler {
|
||||||
|
state: State::Initial(future, map, remote, control),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, E, M> server::Handler<HttpStream> for AsyncHandler<F, Result<T, E>, M> where
|
||||||
|
F: Future<Item=T, Error=E> + Send + 'static,
|
||||||
|
M: FnOnce(Result<Result<T, E>, ()>) -> ContentHandler,
|
||||||
|
T: Send + 'static,
|
||||||
|
E: Send + 'static,
|
||||||
|
{
|
||||||
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
|
if let State::Initial(future, map, remote, control) = mem::replace(&mut self.state, State::Invalid) {
|
||||||
|
let (tx, rx) = mpsc::sync_channel(1);
|
||||||
|
let control2 = control.clone();
|
||||||
|
let tx2 = tx.clone();
|
||||||
|
remote.spawn_with_timeout(move || future.then(move |result| {
|
||||||
|
// Send a result (ignore errors if the connection was dropped)
|
||||||
|
let _ = tx.send(Ok(result));
|
||||||
|
// Resume handler
|
||||||
|
let _ = control.ready(Next::read());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}), time::Duration::from_secs(TIMEOUT_SECS), move || {
|
||||||
|
// Notify about error
|
||||||
|
let _ = tx2.send(Err(()));
|
||||||
|
// Resume handler
|
||||||
|
let _ = control2.ready(Next::read());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.state = State::Waiting(rx, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
Next::wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
||||||
|
if let State::Waiting(rx, map) = mem::replace(&mut self.state, State::Invalid) {
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(result) => {
|
||||||
|
self.state = State::Done(map(result));
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
warn!("Resuming handler in incorrect state: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
if let State::Done(ref mut handler) = self.state {
|
||||||
|
handler.on_response(res)
|
||||||
|
} else {
|
||||||
|
Next::end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
||||||
|
if let State::Done(ref mut handler) = self.state {
|
||||||
|
handler.on_response_writable(encoder)
|
||||||
|
} else {
|
||||||
|
Next::end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
dapps/src/url.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! HTTP/HTTPS URL type. Based on URL type from Iron library.
|
||||||
|
|
||||||
|
use url_lib::{self};
|
||||||
|
pub use url_lib::Host;
|
||||||
|
|
||||||
|
/// HTTP/HTTPS URL type for Iron.
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct Url {
|
||||||
|
/// Raw url of url
|
||||||
|
pub raw: url_lib::Url,
|
||||||
|
|
||||||
|
/// The host field of the URL, probably a domain.
|
||||||
|
pub host: Host,
|
||||||
|
|
||||||
|
/// The connection port.
|
||||||
|
pub port: u16,
|
||||||
|
|
||||||
|
/// The URL path, the resource to be accessed.
|
||||||
|
///
|
||||||
|
/// A *non-empty* vector encoding the parts of the URL path.
|
||||||
|
/// Empty entries of `""` correspond to trailing slashes.
|
||||||
|
pub path: Vec<String>,
|
||||||
|
|
||||||
|
/// The URL query.
|
||||||
|
pub query: Option<String>,
|
||||||
|
|
||||||
|
/// The URL username field, from the userinfo section of the URL.
|
||||||
|
///
|
||||||
|
/// `None` if the `@` character was not part of the input OR
|
||||||
|
/// if a blank username was provided.
|
||||||
|
/// Otherwise, a non-empty string.
|
||||||
|
pub username: Option<String>,
|
||||||
|
|
||||||
|
/// The URL password field, from the userinfo section of the URL.
|
||||||
|
///
|
||||||
|
/// `None` if the `@` character was not part of the input OR
|
||||||
|
/// if a blank password was provided.
|
||||||
|
/// Otherwise, a non-empty string.
|
||||||
|
pub password: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Url {
|
||||||
|
/// Create a URL from a string.
|
||||||
|
///
|
||||||
|
/// The input must be a valid URL with a special scheme for this to succeed.
|
||||||
|
///
|
||||||
|
/// HTTP and HTTPS are special schemes.
|
||||||
|
///
|
||||||
|
/// See: http://url.spec.whatwg.org/#special-scheme
|
||||||
|
pub fn parse(input: &str) -> Result<Url, String> {
|
||||||
|
// Parse the string using rust-url, then convert.
|
||||||
|
match url_lib::Url::parse(input) {
|
||||||
|
Ok(raw_url) => Url::from_generic_url(raw_url),
|
||||||
|
Err(e) => Err(format!("{}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `Url` from a `rust-url` `Url`.
|
||||||
|
pub fn from_generic_url(raw_url: url_lib::Url) -> Result<Url, String> {
|
||||||
|
// Map empty usernames to None.
|
||||||
|
let username = match raw_url.username() {
|
||||||
|
"" => None,
|
||||||
|
username => Some(username.to_owned())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map empty passwords to None.
|
||||||
|
let password = match raw_url.password() {
|
||||||
|
Some(password) if !password.is_empty() => Some(password.to_owned()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let port = raw_url.port_or_known_default().ok_or_else(|| format!("Unknown port for scheme: `{}`", raw_url.scheme()))?;
|
||||||
|
let host = raw_url.host().ok_or_else(|| "Valid host, because only data:, mailto: protocols does not have host.".to_owned())?.to_owned();
|
||||||
|
let path = raw_url.path_segments().ok_or_else(|| "Valid path segments. In HTTP we won't get cannot-be-a-base URLs".to_owned())?
|
||||||
|
.map(|part| part.to_owned()).collect();
|
||||||
|
let query = raw_url.query().map(|x| x.to_owned());
|
||||||
|
|
||||||
|
Ok(Url {
|
||||||
|
port: port,
|
||||||
|
host: host,
|
||||||
|
path: path,
|
||||||
|
query: query,
|
||||||
|
raw: raw_url,
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::Url;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_port() {
|
||||||
|
assert_eq!(Url::parse("http://example.com/wow").unwrap().port, 80u16);
|
||||||
|
assert_eq!(Url::parse("https://example.com/wow").unwrap().port, 443u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_explicit_port() {
|
||||||
|
assert_eq!(Url::parse("http://localhost:3097").unwrap().port, 3097u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_username() {
|
||||||
|
assert!(Url::parse("http://@example.com").unwrap().username.is_none());
|
||||||
|
assert!(Url::parse("http://:password@example.com").unwrap().username.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_empty_username() {
|
||||||
|
let user = Url::parse("http://john:pass@example.com").unwrap().username;
|
||||||
|
assert_eq!(user.unwrap(), "john");
|
||||||
|
|
||||||
|
let user = Url::parse("http://john:@example.com").unwrap().username;
|
||||||
|
assert_eq!(user.unwrap(), "john");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_password() {
|
||||||
|
assert!(Url::parse("http://michael@example.com").unwrap().password.is_none());
|
||||||
|
assert!(Url::parse("http://:@example.com").unwrap().password.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_empty_password() {
|
||||||
|
let pass = Url::parse("http://michael:pass@example.com").unwrap().password;
|
||||||
|
assert_eq!(pass.unwrap(), "pass");
|
||||||
|
|
||||||
|
let pass = Url::parse("http://:pass@example.com").unwrap().password;
|
||||||
|
assert_eq!(pass.unwrap(), "pass");
|
||||||
|
}
|
||||||
|
}
|
23
ethcore/build.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate ethcore_ipc_codegen;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap();
|
||||||
|
ethcore_ipc_codegen::derive_ipc_cond("src/snapshot/snapshot_service_trait.rs", cfg!(feature="ipc")).unwrap();
|
||||||
|
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap();
|
||||||
|
}
|
27
ethcore/light/build.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
|
extern crate ethcore_ipc_codegen;
|
||||||
|
|
||||||
|
#[cfg(feature = "ipc")]
|
||||||
|
fn main() {
|
||||||
|
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
|
||||||
|
ethcore_ipc_codegen::derive_ipc_cond("src/provider.rs", true).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ipc"))]
|
||||||
|
fn main() { }
|
17
ethcore/light/src/types/mod.rs.in
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
pub mod request;
|
258
ethcore/light/src/types/request/builder.rs
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Request chain builder utility.
|
||||||
|
//! Push requests with `push`. Back-references and data required to verify responses must be
|
||||||
|
//! supplied as well.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use request::{
|
||||||
|
IncompleteRequest, OutputKind, Output, NoSuchOutput, ResponseError, ResponseLike,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Build chained requests. Push them onto the series with `push`,
|
||||||
|
/// and produce a `Requests` object with `build`. Outputs are checked for consistency.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct RequestBuilder<T> {
|
||||||
|
output_kinds: HashMap<(usize, usize), OutputKind>,
|
||||||
|
requests: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for RequestBuilder<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
RequestBuilder {
|
||||||
|
output_kinds: HashMap::new(),
|
||||||
|
requests: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IncompleteRequest> RequestBuilder<T> {
|
||||||
|
/// Attempt to push a request onto the request chain. Fails if the request
|
||||||
|
/// references a non-existent output of a prior request.
|
||||||
|
pub fn push(&mut self, request: T) -> Result<(), NoSuchOutput> {
|
||||||
|
request.check_outputs(|req, idx, kind| {
|
||||||
|
match self.output_kinds.get(&(req, idx)) {
|
||||||
|
Some(k) if k == &kind => Ok(()),
|
||||||
|
_ => Err(NoSuchOutput),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
let req_idx = self.requests.len();
|
||||||
|
request.note_outputs(|idx, kind| { self.output_kinds.insert((req_idx, idx), kind); });
|
||||||
|
self.requests.push(request);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the output kinds map.
|
||||||
|
pub fn output_kinds(&self) -> &HashMap<(usize, usize), OutputKind> {
|
||||||
|
&self.output_kinds
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this into a "requests" object.
|
||||||
|
pub fn build(self) -> Requests<T> {
|
||||||
|
Requests {
|
||||||
|
outputs: HashMap::new(),
|
||||||
|
requests: self.requests,
|
||||||
|
answered: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Requests pending responses.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Requests<T> {
|
||||||
|
outputs: HashMap<(usize, usize), Output>,
|
||||||
|
requests: Vec<T>,
|
||||||
|
answered: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Requests<T> {
|
||||||
|
/// Get access to the underlying slice of requests.
|
||||||
|
// TODO: unimplemented -> Vec<Request>, // do we _have to_ allocate?
|
||||||
|
pub fn requests(&self) -> &[T] { &self.requests }
|
||||||
|
|
||||||
|
/// Get the number of answered requests.
|
||||||
|
pub fn num_answered(&self) -> usize { self.answered }
|
||||||
|
|
||||||
|
/// Whether the batch is complete.
|
||||||
|
pub fn is_complete(&self) -> bool {
|
||||||
|
self.answered == self.requests.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map requests from one type into another.
|
||||||
|
pub fn map_requests<F, U>(self, f: F) -> Requests<U>
|
||||||
|
where F: FnMut(T) -> U, U: IncompleteRequest
|
||||||
|
{
|
||||||
|
Requests {
|
||||||
|
outputs: self.outputs,
|
||||||
|
requests: self.requests.into_iter().map(f).collect(),
|
||||||
|
answered: self.answered,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IncompleteRequest + Clone> Requests<T> {
|
||||||
|
/// Get the next request as a filled request. Returns `None` when all requests answered.
|
||||||
|
pub fn next_complete(&self) -> Option<T::Complete> {
|
||||||
|
if self.is_complete() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.requests[self.answered].clone()
|
||||||
|
.complete()
|
||||||
|
.expect("All outputs checked as invariant of `Requests` object; qed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sweep through all unanswered requests, filling them as necessary.
|
||||||
|
pub fn fill_unanswered(&mut self) {
|
||||||
|
let outputs = &mut self.outputs;
|
||||||
|
|
||||||
|
for req in self.requests.iter_mut().skip(self.answered) {
|
||||||
|
req.fill(|req_idx, out_idx| outputs.get(&(req_idx, out_idx)).cloned().ok_or(NoSuchOutput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supply a response, asserting its correctness.
|
||||||
|
/// Fill outputs based upon it.
|
||||||
|
pub fn supply_response_unchecked<R: ResponseLike>(&mut self, response: &R) {
|
||||||
|
if self.is_complete() { return }
|
||||||
|
|
||||||
|
let outputs = &mut self.outputs;
|
||||||
|
let idx = self.answered;
|
||||||
|
response.fill_outputs(|out_idx, output| {
|
||||||
|
// we don't need to check output kinds here because all back-references
|
||||||
|
// are validated in the builder.
|
||||||
|
// TODO: optimization for only storing outputs we "care about"?
|
||||||
|
outputs.insert((idx, out_idx), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.answered += 1;
|
||||||
|
|
||||||
|
// fill as much of the next request as we can.
|
||||||
|
if let Some(ref mut req) = self.requests.get_mut(self.answered) {
|
||||||
|
req.fill(|req_idx, out_idx| outputs.get(&(req_idx, out_idx)).cloned().ok_or(NoSuchOutput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: super::CheckedRequest + Clone> Requests<T> {
|
||||||
|
/// Supply a response for the next request.
|
||||||
|
/// Fails on: wrong request kind, all requests answered already.
|
||||||
|
pub fn supply_response(&mut self, env: &T::Environment, response: &T::Response)
|
||||||
|
-> Result<T::Extract, ResponseError<T::Error>>
|
||||||
|
{
|
||||||
|
let idx = self.answered;
|
||||||
|
|
||||||
|
// check validity.
|
||||||
|
if idx == self.requests.len() { return Err(ResponseError::Unexpected) }
|
||||||
|
let completed = self.next_complete()
|
||||||
|
.expect("only fails when all requests have been answered; this just checked against; qed");
|
||||||
|
|
||||||
|
let extracted = self.requests[idx]
|
||||||
|
.check_response(&completed, env, response).map_err(ResponseError::Validity)?;
|
||||||
|
|
||||||
|
self.supply_response_unchecked(response);
|
||||||
|
Ok(extracted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Requests<super::Request> {
|
||||||
|
/// For each request, produce a response.
|
||||||
|
/// The responses vector produced goes up to the point where the responder
|
||||||
|
/// first returns `None`, an invalid response, or until all requests have been responded to.
|
||||||
|
pub fn respond_to_all<F>(mut self, responder: F) -> Vec<super::Response>
|
||||||
|
where F: Fn(super::CompleteRequest) -> Option<super::Response>
|
||||||
|
{
|
||||||
|
let mut responses = Vec::new();
|
||||||
|
|
||||||
|
while let Some(response) = self.next_complete().and_then(&responder) {
|
||||||
|
match self.supply_response(&(), &response) {
|
||||||
|
Ok(()) => responses.push(response),
|
||||||
|
Err(e) => {
|
||||||
|
debug!(target: "pip", "produced bad response to request: {:?}", e);
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IncompleteRequest> Deref for Requests<T> {
|
||||||
|
type Target = [T];
|
||||||
|
|
||||||
|
fn deref(&self) -> &[T] {
|
||||||
|
&self.requests[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IncompleteRequest> DerefMut for Requests<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut [T] {
|
||||||
|
&mut self.requests[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use request::*;
|
||||||
|
use super::RequestBuilder;
|
||||||
|
use bigint::hash::H256;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_scalar() {
|
||||||
|
let mut builder = RequestBuilder::default();
|
||||||
|
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||||
|
num: 100.into(),
|
||||||
|
})).unwrap();
|
||||||
|
builder.push(Request::Receipts(IncompleteReceiptsRequest {
|
||||||
|
hash: H256::default().into(),
|
||||||
|
})).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn missing_backref() {
|
||||||
|
let mut builder = RequestBuilder::default();
|
||||||
|
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||||
|
num: Field::BackReference(100, 3),
|
||||||
|
})).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn wrong_kind() {
|
||||||
|
let mut builder = RequestBuilder::default();
|
||||||
|
assert!(builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||||
|
num: 100.into(),
|
||||||
|
})).is_ok());
|
||||||
|
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||||
|
num: Field::BackReference(0, 0),
|
||||||
|
})).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn good_backreference() {
|
||||||
|
let mut builder = RequestBuilder::default();
|
||||||
|
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||||
|
num: 100.into(), // header proof puts hash at output 0.
|
||||||
|
})).unwrap();
|
||||||
|
builder.push(Request::Receipts(IncompleteReceiptsRequest {
|
||||||
|
hash: Field::BackReference(0, 0),
|
||||||
|
})).unwrap();
|
||||||
|
}
|
||||||
|
}
|
53
ethcore/res/ethereum/metropolis_test.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "Metropolis (Test)",
|
||||||
|
"engine": {
|
||||||
|
"Ethash": {
|
||||||
|
"params": {
|
||||||
|
"minimumDifficulty": "0x020000",
|
||||||
|
"difficultyBoundDivisor": "0x0800",
|
||||||
|
"durationLimit": "0x0d",
|
||||||
|
|
||||||
|
"homesteadTransition": "0x0",
|
||||||
|
"eip150Transition": "0x0",
|
||||||
|
"eip160Transition": "0x0",
|
||||||
|
"eip161abcTransition": "0x0",
|
||||||
|
"eip161dTransition": "0x0",
|
||||||
|
"maxCodeSize": 24576
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
|
"blockReward": "0x4563918244F40000",
|
||||||
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
|
"accountStartNonce": "0x00",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x1",
|
||||||
|
"eip98Transition": "0x0",
|
||||||
|
"eip86Transition": "0x0",
|
||||||
|
"eip140Transition": "0x0",
|
||||||
|
"eip210Transition": "0x0",
|
||||||
|
"eip155Transition": "0x0"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"ethereum": {
|
||||||
|
"nonce": "0x0000000000000042",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x400000000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||||
|
"gasLimit": "0x1388"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||||
|
}
|
||||||
|
}
|
38
ethcore/res/ethereum/tobalaba.json
Normal file
39
ethcore/src/json_tests/homestead_chain.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use super::chain::json_chain_test;
|
||||||
|
use tests::helpers::*;
|
||||||
|
|
||||||
|
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||||
|
json_chain_test(json_data, ChainEra::Homestead)
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcBlockGasLimitTest, "BlockchainTests/Homestead/bcBlockGasLimitTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcForkStressTest, "BlockchainTests/Homestead/bcForkStressTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcGasPricerTest, "BlockchainTests/Homestead/bcGasPricerTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcInvalidHeaderTest, "BlockchainTests/Homestead/bcInvalidHeaderTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcInvalidRLPTest, "BlockchainTests/Homestead/bcInvalidRLPTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcMultiChainTest, "BlockchainTests/Homestead/bcMultiChainTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcRPC_API_Test, "BlockchainTests/Homestead/bcRPC_API_Test"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcStateTest, "BlockchainTests/Homestead/bcStateTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcTotalDifficultyTest, "BlockchainTests/Homestead/bcTotalDifficultyTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcUncleHeaderValiditiy, "BlockchainTests/Homestead/bcUncleHeaderValiditiy"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/bcUncleTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"}
|
||||||
|
declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"}
|
58
ethcore/src/snapshot/snapshot_service_trait.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use super::{ManifestData, RestorationStatus};
|
||||||
|
use bigint::hash::H256;
|
||||||
|
use util::Bytes;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
|
||||||
|
/// The interface for a snapshot network service.
|
||||||
|
/// This handles:
|
||||||
|
/// - restoration of snapshots to temporary databases.
|
||||||
|
/// - responding to queries for snapshot manifests and chunks
|
||||||
|
#[ipc(client_ident="RemoteSnapshotService")]
|
||||||
|
pub trait SnapshotService : Sync + Send {
|
||||||
|
/// Query the most recent manifest data.
|
||||||
|
fn manifest(&self) -> Option<ManifestData>;
|
||||||
|
|
||||||
|
/// Get the supported range of snapshot version numbers.
|
||||||
|
/// `None` indicates warp sync isn't supported by the consensus engine.
|
||||||
|
fn supported_versions(&self) -> Option<(u64, u64)>;
|
||||||
|
|
||||||
|
/// Get raw chunk for a given hash.
|
||||||
|
fn chunk(&self, hash: H256) -> Option<Bytes>;
|
||||||
|
|
||||||
|
/// Ask the snapshot service for the restoration status.
|
||||||
|
fn status(&self) -> RestorationStatus;
|
||||||
|
|
||||||
|
/// Begin snapshot restoration.
|
||||||
|
/// If restoration in-progress, this will reset it.
|
||||||
|
/// From this point on, any previous snapshot may become unavailable.
|
||||||
|
fn begin_restore(&self, manifest: ManifestData);
|
||||||
|
|
||||||
|
/// Abort an in-progress restoration if there is one.
|
||||||
|
fn abort_restore(&self);
|
||||||
|
|
||||||
|
/// Feed a raw state chunk to the service to be processed asynchronously.
|
||||||
|
/// no-op if not currently restoring.
|
||||||
|
fn restore_state_chunk(&self, hash: H256, chunk: Bytes);
|
||||||
|
|
||||||
|
/// Feed a raw block chunk to the service to be processed asynchronously.
|
||||||
|
/// no-op if currently restoring.
|
||||||
|
fn restore_block_chunk(&self, hash: H256, chunk: Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for SnapshotService { }
|
78
ethcore/src/tests/rpc.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Client RPC tests
|
||||||
|
|
||||||
|
use nanoipc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{Ordering, AtomicBool};
|
||||||
|
use client::{Client, BlockChainClient, ClientConfig, BlockId};
|
||||||
|
use client::remote::RemoteClient;
|
||||||
|
use tests::helpers::*;
|
||||||
|
use devtools::*;
|
||||||
|
use miner::Miner;
|
||||||
|
use crossbeam;
|
||||||
|
use io::IoChannel;
|
||||||
|
use util::kvdb::DatabaseConfig;
|
||||||
|
|
||||||
|
pub fn run_test_worker(scope: &crossbeam::Scope, stop: Arc<AtomicBool>, socket_path: &str) {
|
||||||
|
let socket_path = socket_path.to_owned();
|
||||||
|
scope.spawn(move || {
|
||||||
|
let temp = RandomTempPath::create_dir();
|
||||||
|
let spec = get_test_spec();
|
||||||
|
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||||
|
|
||||||
|
let client = Client::new(
|
||||||
|
ClientConfig::default(),
|
||||||
|
&spec,
|
||||||
|
temp.as_path(),
|
||||||
|
Arc::new(Miner::with_spec(&spec)),
|
||||||
|
IoChannel::disconnected(),
|
||||||
|
&db_config
|
||||||
|
).unwrap();
|
||||||
|
let mut worker = nanoipc::Worker::new(&(client as Arc<BlockChainClient>));
|
||||||
|
worker.add_reqrep(&socket_path).unwrap();
|
||||||
|
while !stop.load(Ordering::Relaxed) {
|
||||||
|
worker.poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_handshake() {
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
let stop_guard = StopGuard::new();
|
||||||
|
let socket_path = "ipc:///tmp/parity-client-rpc-10.ipc";
|
||||||
|
run_test_worker(scope, stop_guard.share(), socket_path);
|
||||||
|
let remote_client = nanoipc::generic_client::<RemoteClient<_>>(socket_path).unwrap();
|
||||||
|
|
||||||
|
assert!(remote_client.handshake().is_ok());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_query_block() {
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
let stop_guard = StopGuard::new();
|
||||||
|
let socket_path = "ipc:///tmp/parity-client-rpc-20.ipc";
|
||||||
|
run_test_worker(scope, stop_guard.share(), socket_path);
|
||||||
|
let remote_client = nanoipc::generic_client::<RemoteClient<_>>(socket_path).unwrap();
|
||||||
|
|
||||||
|
let non_existant_block = remote_client.block_header(BlockId::Number(999));
|
||||||
|
|
||||||
|
assert!(non_existant_block.is_none());
|
||||||
|
})
|
||||||
|
}
|
63
ethcore/wasm/src/call_args.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Wasm evm call arguments helper
|
||||||
|
|
||||||
|
use bigint::prelude::U256;
|
||||||
|
use bigint::hash::H160;
|
||||||
|
|
||||||
|
/// Input part of the wasm call descriptor
|
||||||
|
pub struct CallArgs {
|
||||||
|
/// Receiver of the transaction
|
||||||
|
pub address: [u8; 20],
|
||||||
|
|
||||||
|
/// Sender of the transaction
|
||||||
|
pub sender: [u8; 20],
|
||||||
|
|
||||||
|
/// Original transaction initiator
|
||||||
|
pub origin: [u8; 20],
|
||||||
|
|
||||||
|
/// Transfer value
|
||||||
|
pub value: [u8; 32],
|
||||||
|
|
||||||
|
/// call/create params
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallArgs {
|
||||||
|
/// New contract call payload with known parameters
|
||||||
|
pub fn new(address: H160, sender: H160, origin: H160, value: U256, data: Vec<u8>) -> Self {
|
||||||
|
let mut descriptor = CallArgs {
|
||||||
|
address: [0u8; 20],
|
||||||
|
sender: [0u8; 20],
|
||||||
|
origin: [0u8; 20],
|
||||||
|
value: [0u8; 32],
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.address.copy_from_slice(&*address);
|
||||||
|
descriptor.sender.copy_from_slice(&*sender);
|
||||||
|
descriptor.origin.copy_from_slice(&*origin);
|
||||||
|
value.to_big_endian(&mut descriptor.value);
|
||||||
|
|
||||||
|
descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Total call payload length in linear memory
|
||||||
|
pub fn len(&self) -> u32 {
|
||||||
|
self.data.len() as u32 + 92
|
||||||
|
}
|
||||||
|
}
|
16
ipc-common-types/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
description = "Types that implement IPC and are common to multiple modules."
|
||||||
|
name = "ipc-common-types"
|
||||||
|
version = "1.8.0"
|
||||||
|
license = "GPL-3.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
ethcore-ipc-codegen = { path = "../ipc/codegen" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
semver = "0.6"
|
||||||
|
ethcore-ipc = { path = "../ipc/rpc" }
|
||||||
|
ethcore-util = { path = "../util" }
|
||||||
|
ethcore-bigint = { path = "../util/bigint" }
|
21
ipc-common-types/build.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate ethcore_ipc_codegen;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
|
||||||
|
}
|
26
ipc-common-types/src/lib.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Updater for Parity executables
|
||||||
|
|
||||||
|
extern crate semver;
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
extern crate ethcore_bigint as bigint;
|
||||||
|
extern crate ethcore_ipc as ipc;
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
pub use types::*;
|
21
ipc-common-types/src/types/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Types used in the public api
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/mod.rs.in"));
|
||||||
|
|
21
ipc-common-types/src/types/mod.rs.in
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
pub mod release_track;
|
||||||
|
pub mod version_info;
|
||||||
|
|
||||||
|
pub use release_track::{ReleaseTrack};
|
||||||
|
pub use version_info::{VersionInfo};
|
83
ipc-common-types/src/types/release_track.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Types used in the public API
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A release's track.
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
|
#[binary]
|
||||||
|
pub enum ReleaseTrack {
|
||||||
|
/// Stable track.
|
||||||
|
Stable,
|
||||||
|
/// Beta track.
|
||||||
|
Beta,
|
||||||
|
/// Nightly track.
|
||||||
|
Nightly,
|
||||||
|
/// Testing track.
|
||||||
|
Testing,
|
||||||
|
/// No known track, also "current executable's track" when it's not yet known.
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ReleaseTrack {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}", match *self {
|
||||||
|
ReleaseTrack::Stable => "stable",
|
||||||
|
ReleaseTrack::Beta => "beta",
|
||||||
|
ReleaseTrack::Nightly => "nightly",
|
||||||
|
ReleaseTrack::Testing => "testing",
|
||||||
|
ReleaseTrack::Unknown => "unknown",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for ReleaseTrack {
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
match s {
|
||||||
|
"stable" => ReleaseTrack::Stable,
|
||||||
|
"beta" => ReleaseTrack::Beta,
|
||||||
|
"nightly" => ReleaseTrack::Nightly,
|
||||||
|
"testing" => ReleaseTrack::Testing,
|
||||||
|
_ => ReleaseTrack::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for ReleaseTrack {
|
||||||
|
fn from(i: u8) -> Self {
|
||||||
|
match i {
|
||||||
|
1 => ReleaseTrack::Stable,
|
||||||
|
2 => ReleaseTrack::Beta,
|
||||||
|
3 => ReleaseTrack::Nightly,
|
||||||
|
4 => ReleaseTrack::Testing,
|
||||||
|
_ => ReleaseTrack::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u8> for ReleaseTrack {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
ReleaseTrack::Stable => 1,
|
||||||
|
ReleaseTrack::Beta => 2,
|
||||||
|
ReleaseTrack::Nightly => 3,
|
||||||
|
ReleaseTrack::Testing => 4,
|
||||||
|
ReleaseTrack::Unknown => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
ipc-common-types/src/types/version_info.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Types used in the public API
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use semver::{Version};
|
||||||
|
use bigint::hash::H160;
|
||||||
|
use util::misc::raw_package_info;
|
||||||
|
use release_track::ReleaseTrack;
|
||||||
|
|
||||||
|
/// Version information of a particular release.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[binary]
|
||||||
|
pub struct VersionInfo {
|
||||||
|
/// The track on which it was released.
|
||||||
|
pub track: ReleaseTrack,
|
||||||
|
/// The version.
|
||||||
|
pub version: Version,
|
||||||
|
/// The (SHA1?) 160-bit hash of this build's code base.
|
||||||
|
pub hash: H160,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for VersionInfo {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}.{}.{}-{}-{}", self.version.major, self.version.minor, self.version.patch, self.track, self.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionInfo {
|
||||||
|
/// Get information for this (currently running) binary.
|
||||||
|
pub fn this() -> Self {
|
||||||
|
let raw = raw_package_info();
|
||||||
|
VersionInfo {
|
||||||
|
track: raw.0.into(),
|
||||||
|
version: { let mut v = Version::parse(raw.1).expect("Environment variables are known to be valid; qed"); v.build = vec![]; v.pre = vec![]; v },
|
||||||
|
hash: H160::from_str(raw.2).unwrap_or_else(|_| H160::zero()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compose the information from the provided raw fields.
|
||||||
|
pub fn from_raw(semver: u32, track: u8, hash: H160) -> Self {
|
||||||
|
let t = track.into();
|
||||||
|
VersionInfo {
|
||||||
|
version: Version {
|
||||||
|
major: (semver >> 16) as u64,
|
||||||
|
minor: ((semver >> 8) & 0xff) as u64,
|
||||||
|
patch: (semver & 0xff) as u64,
|
||||||
|
build: vec![],
|
||||||
|
pre: vec![],
|
||||||
|
},
|
||||||
|
track: t,
|
||||||
|
hash: hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
ipc/codegen/Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethcore-ipc-codegen"
|
||||||
|
version = "1.8.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
description = "Macros to auto-generate implementations for ipc call"
|
||||||
|
build = "build.rs"
|
||||||
|
keywords = ["ipc", "codegen"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["with-syntex"]
|
||||||
|
nightly = ["quasi_macros"]
|
||||||
|
nightly-testing = ["clippy"]
|
||||||
|
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
quasi_codegen = { version = "0.32", optional = true }
|
||||||
|
syntex = { version = "0.58", optional = true }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
aster = { version = "0.41", default-features = false }
|
||||||
|
clippy = { version = "^0.*", optional = true }
|
||||||
|
quasi = { version = "0.32", default-features = false }
|
||||||
|
quasi_macros = { version = "0.32", optional = true }
|
||||||
|
syntex = { version = "0.58", optional = true }
|
||||||
|
syntex_syntax = { version = "0.58", optional = true }
|
43
ipc/codegen/build.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
mod inner {
|
||||||
|
extern crate syntex;
|
||||||
|
extern crate quasi_codegen;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
let src = Path::new("src/lib.rs.in");
|
||||||
|
let dst = Path::new(&out_dir).join("lib.rs");
|
||||||
|
|
||||||
|
quasi_codegen::expand(&src, &dst).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
mod inner {
|
||||||
|
pub fn main() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
inner::main();
|
||||||
|
}
|
898
ipc/codegen/src/codegen.rs
Normal file
@ -0,0 +1,898 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
use aster;
|
||||||
|
|
||||||
|
use syntax::ast::{
|
||||||
|
MetaItem,
|
||||||
|
Item,
|
||||||
|
ImplItemKind,
|
||||||
|
MethodSig,
|
||||||
|
Arg,
|
||||||
|
PatKind,
|
||||||
|
FunctionRetTy,
|
||||||
|
Ty,
|
||||||
|
TraitRef,
|
||||||
|
Ident,
|
||||||
|
Generics,
|
||||||
|
TraitItemKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::codemap::Span;
|
||||||
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
|
use syntax::ptr::P;
|
||||||
|
|
||||||
|
pub struct Error;
|
||||||
|
|
||||||
|
const RESERVED_MESSAGE_IDS: u16 = 16;
|
||||||
|
|
||||||
|
pub fn expand_ipc_implementation(
|
||||||
|
cx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
meta_item: &MetaItem,
|
||||||
|
annotatable: &Annotatable,
|
||||||
|
push: &mut FnMut(Annotatable)
|
||||||
|
) {
|
||||||
|
let item = match *annotatable {
|
||||||
|
Annotatable::Item(ref item) => item,
|
||||||
|
_ => {
|
||||||
|
cx.span_err(meta_item.span, "`#[ipc]` may only be applied to implementations and traits");
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
|
let interface_map = match implement_interface(cx, &builder, &item, push, meta_item) {
|
||||||
|
Ok(interface_map) => interface_map,
|
||||||
|
Err(Error) => { return; },
|
||||||
|
};
|
||||||
|
|
||||||
|
push_client(cx, &builder, &interface_map, push);
|
||||||
|
|
||||||
|
push(Annotatable::Item(interface_map.item));
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! literal {
|
||||||
|
($builder:ident, $($arg:tt)*) => {
|
||||||
|
$builder.expr().lit().str::<&str>(&format!($($arg)*))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_name(builder: &aster::AstBuilder, arg: &Arg) -> ast::Ident {
|
||||||
|
match arg.pat.node {
|
||||||
|
PatKind::Ident(_, ref ident, _) => builder.id(ident.node),
|
||||||
|
_ => { panic!("unexpected param in interface: {:?}", arg.pat.node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_slice_u8(builder: &aster::AstBuilder, ty: &P<ast::Ty>) -> P<ast::Ty> {
|
||||||
|
if ::syntax::print::pprust::ty_to_string(&strip_ptr(ty)) == "[u8]" {
|
||||||
|
return builder.ty().id("Vec<u8>")
|
||||||
|
}
|
||||||
|
ty.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NamedSignature<'a> {
|
||||||
|
sig: &'a MethodSig,
|
||||||
|
ident: &'a Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_invoke_signature_aster(
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
named_signature: &NamedSignature,
|
||||||
|
push: &mut FnMut(Annotatable),
|
||||||
|
) -> Dispatch {
|
||||||
|
let inputs = &named_signature.sig.decl.inputs;
|
||||||
|
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
||||||
|
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
||||||
|
if &*first_field_name == "self" && inputs.len() == 1 { (None, vec![], vec![]) }
|
||||||
|
else {
|
||||||
|
let skip = if &*first_field_name == "self" { 2 } else { 1 };
|
||||||
|
let name_str = format!("{}_input", named_signature.ident.name.as_str());
|
||||||
|
|
||||||
|
let mut arg_names = Vec::new();
|
||||||
|
let mut arg_tys = Vec::new();
|
||||||
|
|
||||||
|
let arg_name = format!("{}", field_name(builder, &inputs[skip-1]).name);
|
||||||
|
let arg_ty = &inputs[skip-1].ty;
|
||||||
|
|
||||||
|
let mut tree = builder.item()
|
||||||
|
.attr().word("binary")
|
||||||
|
.attr().word("allow(non_camel_case_types)")
|
||||||
|
.struct_(name_str.as_str())
|
||||||
|
.field(arg_name.as_str())
|
||||||
|
.ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
|
||||||
|
|
||||||
|
arg_names.push(arg_name);
|
||||||
|
arg_tys.push(arg_ty.clone());
|
||||||
|
for arg in inputs.iter().skip(skip) {
|
||||||
|
let arg_name = format!("{}", field_name(builder, &arg));
|
||||||
|
let arg_ty = &arg.ty;
|
||||||
|
|
||||||
|
tree = tree.field(arg_name.as_str()).ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
|
||||||
|
arg_names.push(arg_name);
|
||||||
|
arg_tys.push(arg_ty.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
push(Annotatable::Item(tree.build()));
|
||||||
|
(Some(name_str.to_owned()), arg_names, arg_tys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(None, vec![], vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let return_type_ty = match named_signature.sig.decl.output {
|
||||||
|
FunctionRetTy::Ty(ref ty) => {
|
||||||
|
let name_str = format!("{}_output", named_signature.ident.name.as_str());
|
||||||
|
let tree = builder.item()
|
||||||
|
.attr().word("binary")
|
||||||
|
.attr().word("allow(non_camel_case_types)")
|
||||||
|
.struct_(name_str.as_str())
|
||||||
|
.field(format!("payload")).ty().build(ty.clone());
|
||||||
|
push(Annotatable::Item(tree.build()));
|
||||||
|
Some(ty.clone())
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
|
||||||
|
Dispatch {
|
||||||
|
function_name: format!("{}", named_signature.ident.name.as_str()),
|
||||||
|
input_type_name: input_type_name,
|
||||||
|
input_arg_names: input_arg_names,
|
||||||
|
input_arg_tys: input_arg_tys,
|
||||||
|
return_type_ty: return_type_ty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dispatch {
|
||||||
|
function_name: String,
|
||||||
|
input_type_name: Option<String>,
|
||||||
|
input_arg_names: Vec<String>,
|
||||||
|
input_arg_tys: Vec<P<Ty>>,
|
||||||
|
return_type_ty: Option<P<Ty>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the expanded version of this:
|
||||||
|
//
|
||||||
|
// let invoke_serialize_stmt = quote_stmt!(cx, {
|
||||||
|
// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap()
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// But the above does not allow comma-separated expressions for arbitrary number
|
||||||
|
// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n
|
||||||
|
fn implement_dispatch_arm_invoke_stmt(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
dispatch: &Dispatch,
|
||||||
|
) -> ast::Stmt
|
||||||
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
|
let function_name = builder.id(dispatch.function_name.as_str());
|
||||||
|
|
||||||
|
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
|
||||||
|
let arg_ident = builder.id(arg_name);
|
||||||
|
let expr = quote_expr!(cx, input. $arg_ident);
|
||||||
|
if has_ptr(&dispatch.input_arg_tys[arg_index]) { quote_expr!(cx, & $expr) }
|
||||||
|
else { expr }
|
||||||
|
}).collect::<Vec<P<ast::Expr>>>();
|
||||||
|
|
||||||
|
let ext_cx = &*cx;
|
||||||
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
|
ext_cx.parse_sess(),
|
||||||
|
{
|
||||||
|
let _sp = ext_cx.call_site();
|
||||||
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
|
if dispatch.return_type_ty.is_some() {
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Dot));
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
|
for arg_expr in input_args_exprs {
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
|
if dispatch.return_type_ty.is_some() {
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Dot));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Semi));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
|
}
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
|
tt
|
||||||
|
}
|
||||||
|
)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn implement_dispatch_arm_invoke(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
dispatch: &Dispatch,
|
||||||
|
buffer: bool,
|
||||||
|
) -> P<ast::Expr>
|
||||||
|
{
|
||||||
|
let deserialize_expr = if buffer {
|
||||||
|
quote_expr!(cx,
|
||||||
|
::ipc::binary::deserialize(buf)
|
||||||
|
.unwrap_or_else(|e| { panic!("ipc error while deserializing payload, aborting \n payload: {:?}, \n error: {:?}", buf, e); } )
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
quote_expr!(cx,
|
||||||
|
::ipc::binary::deserialize_from(r)
|
||||||
|
.unwrap_or_else(|e| { panic!("ipc error while deserializing payload, aborting \n error: {:?}", e); } )
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
|
||||||
|
dispatch.input_type_name.as_ref().map(|val| {
|
||||||
|
let input_type_id = builder.id(val.clone().as_str());
|
||||||
|
quote_expr!(cx, {
|
||||||
|
let input: $input_type_id = $deserialize_expr;
|
||||||
|
$invoke_serialize_stmt
|
||||||
|
})
|
||||||
|
}).unwrap_or(quote_expr!(cx, { $invoke_serialize_stmt }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generates dispatch match for method id
|
||||||
|
fn implement_dispatch_arm(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
index: u32,
|
||||||
|
dispatch: &Dispatch,
|
||||||
|
buffer: bool,
|
||||||
|
) -> ast::Arm
|
||||||
|
{
|
||||||
|
let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str());
|
||||||
|
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer);
|
||||||
|
let trace = literal!(builder, "Dispatching: {}", &dispatch.function_name);
|
||||||
|
quote_arm!(cx, $index_ident => {
|
||||||
|
trace!(target: "ipc", $trace);
|
||||||
|
$invoke_expr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn implement_dispatch_arms(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
dispatches: &[Dispatch],
|
||||||
|
buffer: bool,
|
||||||
|
) -> Vec<ast::Arm>
|
||||||
|
{
|
||||||
|
let mut index = -1;
|
||||||
|
dispatches.iter()
|
||||||
|
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn strip_ptr(ty: &P<ast::Ty>) -> P<ast::Ty> {
|
||||||
|
if let ast::TyKind::Rptr(_, ref ptr_mut) = ty.node {
|
||||||
|
ptr_mut.ty.clone()
|
||||||
|
}
|
||||||
|
else { ty.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_ptr(ty: &P<ast::Ty>) -> bool {
|
||||||
|
if let ast::TyKind::Rptr(_, ref _ptr_mut) = ty.node {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns an expression with the body for single operation that is being sent to server
|
||||||
|
/// operation itself serializes input, writes to socket and waits for socket to respond
|
||||||
|
/// (the latter only if original method signature returns anyting)
|
||||||
|
///
|
||||||
|
/// assuming expanded class contains method
|
||||||
|
/// fn commit(&self, f: u32) -> u32
|
||||||
|
///
|
||||||
|
/// the expanded implementation will generate method for the client like that
|
||||||
|
/// #[binary]
|
||||||
|
/// struct Request<'a> {
|
||||||
|
/// f: &'a u32,
|
||||||
|
/// }
|
||||||
|
/// let payload = Request{f: &f,};
|
||||||
|
/// let mut socket_ref = self.socket.borrow_mut();
|
||||||
|
/// let mut socket = socket_ref.deref_mut();
|
||||||
|
/// let serialized_payload = ::bincode::serde::serialize(&payload, ::bincode::SizeLimit::Infinite).unwrap();
|
||||||
|
/// ::ipc::invoke(0, &Some(serialized_payload), &mut socket);
|
||||||
|
/// while !socket.ready().load(::std::sync::atomic::Ordering::Relaxed) { }
|
||||||
|
/// ::bincode::serde::deserialize_from::<_, u32>(&mut socket, ::bincode::SizeLimit::Infinite).unwrap()
|
||||||
|
fn implement_client_method_body(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
index: u16,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
) -> P<ast::Expr>
|
||||||
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
|
let index_ident = builder.id(format!("{}", index + RESERVED_MESSAGE_IDS).as_str());
|
||||||
|
|
||||||
|
let request = if dispatch.input_arg_names.len() > 0 {
|
||||||
|
|
||||||
|
let arg_name = dispatch.input_arg_names[0].as_str();
|
||||||
|
let static_ty = strip_ptr(&dispatch.input_arg_tys[0]);
|
||||||
|
let arg_ty = builder
|
||||||
|
.ty().ref_()
|
||||||
|
.lifetime("'a")
|
||||||
|
.ty()
|
||||||
|
.build(static_ty.clone());
|
||||||
|
|
||||||
|
let mut tree = builder.item()
|
||||||
|
.attr().word("binary")
|
||||||
|
.struct_("Request")
|
||||||
|
.generics()
|
||||||
|
.lifetime_name("'a")
|
||||||
|
.build()
|
||||||
|
.field(arg_name).ty()
|
||||||
|
.build(arg_ty);
|
||||||
|
|
||||||
|
for arg_idx in 1..dispatch.input_arg_names.len() {
|
||||||
|
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
||||||
|
let static_ty = strip_ptr(&dispatch.input_arg_tys[arg_idx]);
|
||||||
|
|
||||||
|
let arg_ty = builder
|
||||||
|
.ty().ref_()
|
||||||
|
.lifetime("'a")
|
||||||
|
.ty()
|
||||||
|
.build(static_ty);
|
||||||
|
tree = tree.field(arg_name).ty().build(arg_ty);
|
||||||
|
|
||||||
|
}
|
||||||
|
let mut request_serialization_statements = Vec::new();
|
||||||
|
|
||||||
|
let struct_tree = tree.build();
|
||||||
|
let struct_stmt = quote_stmt!(cx, $struct_tree);
|
||||||
|
request_serialization_statements.push(struct_stmt);
|
||||||
|
|
||||||
|
// actually this is just expanded version of this:
|
||||||
|
// request_serialization_statements.push(quote_stmt!(cx, let payload = Request { p1: &p1, p2: &p2, ... pn: &pn, }));
|
||||||
|
// again, cannot dynamically create expression with arbitrary number of comma-separated members
|
||||||
|
request_serialization_statements.push({
|
||||||
|
let ext_cx = &*cx;
|
||||||
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
|
ext_cx.parse_sess(),
|
||||||
|
{
|
||||||
|
let _sp = ext_cx.call_site();
|
||||||
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("let"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Eq));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
|
for arg in dispatch.input_arg_names.iter() {
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Colon));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
|
tt
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
request_serialization_statements.push(
|
||||||
|
quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
|
||||||
|
|
||||||
|
request_serialization_statements.push(
|
||||||
|
quote_stmt!(cx, let serialized_payload = ::ipc::binary::serialize(&payload).unwrap()));
|
||||||
|
|
||||||
|
request_serialization_statements.push(
|
||||||
|
quote_stmt!(cx, ::ipc::invoke($index_ident, &Some(serialized_payload), &mut *socket)));
|
||||||
|
|
||||||
|
|
||||||
|
request_serialization_statements
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let mut request_serialization_statements = Vec::new();
|
||||||
|
request_serialization_statements.push(
|
||||||
|
quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
|
||||||
|
request_serialization_statements.push(
|
||||||
|
quote_stmt!(cx, ::ipc::invoke($index_ident, &None, &mut *socket)));
|
||||||
|
request_serialization_statements
|
||||||
|
};
|
||||||
|
|
||||||
|
let trace = literal!(builder, "Invoking: {}", &dispatch.function_name);
|
||||||
|
if let Some(ref return_ty) = dispatch.return_type_ty {
|
||||||
|
let return_expr = quote_expr!(cx,
|
||||||
|
::ipc::binary::deserialize_from::<$return_ty, _>(&mut *socket).unwrap()
|
||||||
|
);
|
||||||
|
quote_expr!(cx, {
|
||||||
|
trace!(target: "ipc", $trace);
|
||||||
|
$request;
|
||||||
|
$return_expr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
quote_expr!(cx, {
|
||||||
|
trace!(target: "ipc", $trace);
|
||||||
|
$request
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates signature and body (see `implement_client_method_body`)
|
||||||
|
/// for the client (signature is identical to the original method)
|
||||||
|
fn implement_client_method(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
index: u16,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
)
|
||||||
|
-> ast::ImplItem
|
||||||
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
|
let method_name = builder.id(dispatch.function_name.as_str());
|
||||||
|
let body = implement_client_method_body(cx, builder, index, interface_map);
|
||||||
|
|
||||||
|
let ext_cx = &*cx;
|
||||||
|
// expanded version of this
|
||||||
|
// pub fn $method_name(&self, p1: p1_ty, p2: p2_ty ... pn: pn_ty, ) [-> return_ty] { $body }
|
||||||
|
// looks like it's tricky to build function declaration with aster if body already generated
|
||||||
|
let signature = ::syntax::parse::parser::Parser::parse_impl_item(
|
||||||
|
&mut ::syntax::parse::new_parser_from_tts(
|
||||||
|
ext_cx.parse_sess(),
|
||||||
|
{
|
||||||
|
let _sp = ext_cx.call_site();
|
||||||
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("fn"))));
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(&method_name, ext_cx).into_iter());
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
|
|
||||||
|
for arg_idx in 0..dispatch.input_arg_names.len() {
|
||||||
|
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
||||||
|
let arg_ty = dispatch.input_arg_tys[arg_idx].clone();
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg_name))));
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Colon));
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(&arg_ty, ext_cx).into_iter());
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
|
}
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
|
if let Some(ref return_ty) = dispatch.return_type_ty {
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::RArrow));
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(return_ty, ext_cx).into_iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
|
tt.extend(::quasi::ToTokens::to_tokens(&body, ext_cx).into_iter());
|
||||||
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
|
tt
|
||||||
|
}));
|
||||||
|
|
||||||
|
signature.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> Generics {
|
||||||
|
let ty_param = aster::ty_param::TyParamBuilder::new(
|
||||||
|
builder.id("S")).trait_bound(
|
||||||
|
builder.path().global().ids(&["ipc", "IpcSocket"]).build()
|
||||||
|
).build().build();
|
||||||
|
|
||||||
|
builder.from_generics(interface_map.generics.clone())
|
||||||
|
.with_ty_param(ty_param)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder))
|
||||||
|
.with_generics(generics).build()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
aster::ty::TyBuilder::new().phantom_data()
|
||||||
|
.tuple().with_tys(generics.ty_params.iter().map(|x| aster::ty::TyBuilder::new().id(x.ident)))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generates client type for specified server type
|
||||||
|
/// for say `Service` it generates `ServiceClient`
|
||||||
|
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_short_ident = interface_map.ident_map.client_ident(cx, builder);
|
||||||
|
let phantom = client_phantom_ident(builder, interface_map);
|
||||||
|
|
||||||
|
let client_struct_item = quote_item!(cx,
|
||||||
|
pub struct $client_short_ident $generics {
|
||||||
|
socket: ::std::sync::RwLock<S>,
|
||||||
|
phantom: $phantom,
|
||||||
|
});
|
||||||
|
|
||||||
|
push(Annotatable::Item(client_struct_item.expect(&format!("could not generate client struct for {:?}", client_short_ident.name))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pushes generated code for the client class (type declaration and method invocation implementations)
|
||||||
|
fn push_client(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
push: &mut FnMut(Annotatable),
|
||||||
|
) {
|
||||||
|
push_client_struct(cx, builder, interface_map, push);
|
||||||
|
push_client_implementation(cx, builder, interface_map, push);
|
||||||
|
push_with_socket_client_implementation(cx, builder, interface_map, push);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_with_socket_client_implementation(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
push: &mut FnMut(Annotatable))
|
||||||
|
{
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_ident = client_qualified_ident(cx, builder, interface_map);
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
let client_short_ident = interface_map.ident_map.client_ident(cx, builder);
|
||||||
|
|
||||||
|
let implement = quote_item!(cx,
|
||||||
|
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
|
||||||
|
fn init(socket: S) -> $client_ident {
|
||||||
|
$client_short_ident {
|
||||||
|
socket: ::std::sync::RwLock::new(socket),
|
||||||
|
phantom: ::std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
push(Annotatable::Item(implement));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pushes full client side code for the original class exposed via ipc
|
||||||
|
fn push_client_implementation(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
push: &mut FnMut(Annotatable),
|
||||||
|
) {
|
||||||
|
let mut index = -1i32;
|
||||||
|
let items = interface_map.dispatches.iter()
|
||||||
|
.map(|_| { index = index + 1; P(implement_client_method(cx, builder, index as u16, interface_map)) })
|
||||||
|
.collect::<Vec<P<ast::ImplItem>>>();
|
||||||
|
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_ident = client_qualified_ident(cx, builder, interface_map);
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
let endpoint = interface_map.endpoint;
|
||||||
|
|
||||||
|
let handshake_item = quote_impl_item!(cx,
|
||||||
|
pub fn handshake(&self) -> Result<(), ::ipc::Error> {
|
||||||
|
let payload = ::ipc::Handshake {
|
||||||
|
protocol_version: $endpoint::protocol_version(),
|
||||||
|
api_version: $endpoint::api_version(),
|
||||||
|
};
|
||||||
|
|
||||||
|
::ipc::invoke(
|
||||||
|
0,
|
||||||
|
&Some(::ipc::binary::serialize(&::ipc::BinHandshake::from(payload)).unwrap()),
|
||||||
|
&mut *self.socket.write().unwrap());
|
||||||
|
|
||||||
|
let mut result = vec![0u8; 1];
|
||||||
|
if try!(self.socket.write().unwrap().read(&mut result).map_err(|_| ::ipc::Error::HandshakeFailed)) == 1 {
|
||||||
|
match result[0] {
|
||||||
|
1 => Ok(()),
|
||||||
|
_ => Err(::ipc::Error::RemoteServiceUnsupported),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { Err(::ipc::Error::HandshakeFailed) }
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
let socket_item = quote_impl_item!(cx,
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn socket(&self) -> &::std::sync::RwLock<S> {
|
||||||
|
&self.socket
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
let generic_items = vec![P(handshake_item), P(socket_item)];
|
||||||
|
|
||||||
|
if interface_map.impl_trait.is_some() {
|
||||||
|
let trait_ty = builder.id(
|
||||||
|
::syntax::print::pprust::path_to_string(
|
||||||
|
&interface_map.impl_trait.as_ref().unwrap().path));
|
||||||
|
|
||||||
|
let implement_trait =
|
||||||
|
quote_item!(cx,
|
||||||
|
impl $generics $trait_ty for $client_ident $where_clause {
|
||||||
|
$items
|
||||||
|
}
|
||||||
|
).unwrap();
|
||||||
|
push(Annotatable::Item(implement_trait));
|
||||||
|
|
||||||
|
let implement =
|
||||||
|
quote_item!(cx,
|
||||||
|
impl $generics $client_ident $where_clause {
|
||||||
|
$generic_items
|
||||||
|
}
|
||||||
|
).unwrap();
|
||||||
|
push(Annotatable::Item(implement));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let pub_items = items.iter().map(|item| {
|
||||||
|
let pub_item = item.clone();
|
||||||
|
pub_item.map(|mut val| { val.vis = ast::Visibility::Public; val })
|
||||||
|
}).collect::<Vec<P<ast::ImplItem>>>();
|
||||||
|
|
||||||
|
let implement = quote_item!(cx,
|
||||||
|
impl $generics $client_ident $where_clause {
|
||||||
|
$pub_items
|
||||||
|
$generic_items
|
||||||
|
}).unwrap();
|
||||||
|
push(Annotatable::Item(implement));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implements dispatching of system handshake invocation (method_num 0)
|
||||||
|
fn implement_handshake_arm(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
) -> (ast::Arm, ast::Arm)
|
||||||
|
{
|
||||||
|
let handshake_deserialize = quote_stmt!(&cx,
|
||||||
|
let handshake_payload = ::ipc::binary::deserialize_from::<::ipc::BinHandshake, _>(r).unwrap();
|
||||||
|
);
|
||||||
|
|
||||||
|
let handshake_deserialize_buf = quote_stmt!(&cx,
|
||||||
|
let handshake_payload = ::ipc::binary::deserialize::<::ipc::BinHandshake>(buf).unwrap();
|
||||||
|
);
|
||||||
|
|
||||||
|
let handshake_serialize = quote_expr!(&cx,
|
||||||
|
::ipc::binary::serialize::<bool>(&Self::handshake(&handshake_payload.to_semver())).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
quote_arm!(&cx, 0 => {
|
||||||
|
$handshake_deserialize
|
||||||
|
$handshake_serialize
|
||||||
|
}),
|
||||||
|
quote_arm!(&cx, 0 => {
|
||||||
|
$handshake_deserialize_buf
|
||||||
|
$handshake_serialize
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<String, ()> {
|
||||||
|
match lit.node {
|
||||||
|
ast::LitKind::Str(ref s, _) => Ok(format!("{}", s)),
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
lit.span,
|
||||||
|
&format!("ipc client_ident annotation `{}` must be a string, not `{}`",
|
||||||
|
name,
|
||||||
|
::syntax::print::pprust::lit_to_string(lit)));
|
||||||
|
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_ident_renamed(cx: &ExtCtxt, meta_item: &MetaItem) -> Option<String> {
|
||||||
|
if let ast::MetaItemKind::List(ref list) = meta_item.node {
|
||||||
|
for nested in list {
|
||||||
|
match nested.node {
|
||||||
|
ast::NestedMetaItemKind::MetaItem(ref meta_item) => {
|
||||||
|
let is_client_ident = &*meta_item.name.as_str() == "client_ident";
|
||||||
|
match meta_item.node {
|
||||||
|
ast::MetaItemKind::NameValue(ref lit) if is_client_ident => {
|
||||||
|
if let Ok(s) = get_str_from_lit(cx, "client_ident", lit) {
|
||||||
|
return Some(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
meta_item.span,
|
||||||
|
&format!("unknown client_ident container attribute `{}`",
|
||||||
|
::syntax::print::pprust::meta_item_to_string(&meta_item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InterfaceMap {
|
||||||
|
pub original_item: Item,
|
||||||
|
pub item: P<ast::Item>,
|
||||||
|
pub dispatches: Vec<Dispatch>,
|
||||||
|
pub generics: Generics,
|
||||||
|
pub impl_trait: Option<TraitRef>,
|
||||||
|
pub ident_map: IdentMap,
|
||||||
|
pub endpoint: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IdentMap {
|
||||||
|
original_path: ast::Path,
|
||||||
|
meta_item: MetaItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentMap {
|
||||||
|
fn ident(&self, builder: &aster::AstBuilder) -> Ident {
|
||||||
|
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder) -> Ident {
|
||||||
|
if let Some(new_name) = client_ident_renamed(cx, &self.meta_item) {
|
||||||
|
builder.id(new_name)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ty_ident_map(original_ty: &P<Ty>, meta_item: &MetaItem) -> IdentMap {
|
||||||
|
let original_path = match original_ty.node {
|
||||||
|
::syntax::ast::TyKind::Path(_, ref path) => path.clone(),
|
||||||
|
_ => { panic!("incompatible implementation"); }
|
||||||
|
};
|
||||||
|
let ident_map = IdentMap { original_path: original_path, meta_item: meta_item.clone() };
|
||||||
|
ident_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implements `IpcInterface` for the given class `C`
|
||||||
|
fn implement_interface(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
push: &mut FnMut(Annotatable),
|
||||||
|
meta_item: &MetaItem,
|
||||||
|
) -> Result<InterfaceMap, Error> {
|
||||||
|
let (generics, impl_trait, original_ty, dispatch_table) = match item.node {
|
||||||
|
ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => {
|
||||||
|
let mut method_signatures = Vec::new();
|
||||||
|
for impl_item in impl_items {
|
||||||
|
if let ImplItemKind::Method(ref signature, _) = impl_item.node {
|
||||||
|
method_signatures.push(NamedSignature { ident: &impl_item.ident, sig: signature });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dispatch_table = method_signatures.iter().map(|named_signature|
|
||||||
|
push_invoke_signature_aster(builder, named_signature, push))
|
||||||
|
.collect::<Vec<Dispatch>>();
|
||||||
|
|
||||||
|
(generics, impl_trait.clone(), ty.clone(), dispatch_table)
|
||||||
|
},
|
||||||
|
ast::ItemKind::Trait(_, ref generics, _, ref trait_items) => {
|
||||||
|
let mut method_signatures = Vec::new();
|
||||||
|
for trait_item in trait_items {
|
||||||
|
if let TraitItemKind::Method(ref signature, _) = trait_item.node {
|
||||||
|
method_signatures.push(NamedSignature { ident: &trait_item.ident, sig: signature });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dispatch_table = method_signatures.iter().map(|named_signature|
|
||||||
|
push_invoke_signature_aster(builder, named_signature, push))
|
||||||
|
.collect::<Vec<Dispatch>>();
|
||||||
|
|
||||||
|
(
|
||||||
|
generics,
|
||||||
|
Some(ast::TraitRef {
|
||||||
|
path: builder.path().ids(&[item.ident.name]).build(),
|
||||||
|
ref_id: item.id,
|
||||||
|
}),
|
||||||
|
builder.ty().id(item.ident),
|
||||||
|
dispatch_table
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
item.span,
|
||||||
|
"`#[ipc]` may only be applied to implementations and traits");
|
||||||
|
return Err(Error);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let impl_generics = builder.from_generics(generics.clone()).build();
|
||||||
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
|
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
|
||||||
|
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
|
||||||
|
|
||||||
|
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
||||||
|
|
||||||
|
let ty = ty_ident_map(&original_ty, meta_item).ident(builder);
|
||||||
|
let (interface_endpoint, host_generics) = match impl_trait {
|
||||||
|
Some(ref trait_) => (builder.id(::syntax::print::pprust::path_to_string(&trait_.path)), None),
|
||||||
|
None => (ty, Some(&impl_generics)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ipc_item = quote_item!(cx,
|
||||||
|
impl $host_generics ::ipc::IpcInterface for $interface_endpoint $where_clause {
|
||||||
|
fn dispatch<R>(&self, r: &mut R) -> Vec<u8>
|
||||||
|
where R: ::std::io::Read
|
||||||
|
{
|
||||||
|
let mut method_num = vec![0u8;2];
|
||||||
|
match r.read(&mut method_num) {
|
||||||
|
Ok(size) if size == 0 => { panic!("method id not supplied" ); }
|
||||||
|
Err(e) => { panic!("ipc read error: {:?}, aborting", e); }
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// method_num is a 16-bit little-endian unsigned number
|
||||||
|
match method_num[1] as u16 + (method_num[0] as u16)*256 {
|
||||||
|
// handshake
|
||||||
|
$handshake_arm
|
||||||
|
// user methods
|
||||||
|
$dispatch_arms
|
||||||
|
_ => vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8>
|
||||||
|
{
|
||||||
|
match method_num {
|
||||||
|
$handshake_arm_buf
|
||||||
|
$dispatch_arms_buffered
|
||||||
|
_ => vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
Ok(InterfaceMap {
|
||||||
|
ident_map: ty_ident_map(&original_ty, meta_item),
|
||||||
|
original_item: item.clone(),
|
||||||
|
item: ipc_item,
|
||||||
|
dispatches: dispatch_table,
|
||||||
|
generics: generics.clone(),
|
||||||
|
impl_trait: impl_trait.clone(),
|
||||||
|
endpoint: interface_endpoint,
|
||||||
|
})
|
||||||
|
}
|
237
ipc/codegen/src/lib.rs
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Codegen for IPC RPC
|
||||||
|
|
||||||
|
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
|
||||||
|
#![cfg_attr(feature = "nightly-testing", feature(plugin))]
|
||||||
|
#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
|
||||||
|
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
|
||||||
|
#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]
|
||||||
|
|
||||||
|
extern crate aster;
|
||||||
|
extern crate quasi;
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
extern crate syntex;
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
extern crate syntex_syntax as syntax;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
extern crate rustc_plugin;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
use syntax::feature_gate::AttributeType;
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
use syntax::{ast, fold};
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
include!("lib.rs.in");
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
pub fn expand(src: &std::path::Path, dst: &std::path::Path) {
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
register(&mut registry);
|
||||||
|
registry.expand("", src, dst).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
struct StripAttributeFolder<'a> {
|
||||||
|
attr_title: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
impl<'a> fold::Folder for StripAttributeFolder<'a> {
|
||||||
|
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
||||||
|
let is_self = &*attr.value.name.as_str() == self.attr_title;
|
||||||
|
|
||||||
|
match attr.value.node {
|
||||||
|
ast::MetaItemKind::List(_) if is_self => { return None; }
|
||||||
|
ast::MetaItemKind::Word if is_self => { return None; }
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||||
|
fold::noop_fold_mac(mac, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
pub fn register_cleaner_ipc(reg: &mut syntex::Registry) {
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
|
||||||
|
let mut folder = StripAttributeFolder { attr_title: "ipc" };
|
||||||
|
fold::Folder::fold_crate(&mut folder, krate)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.add_post_expansion_pass(strip_attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
pub fn register_cleaner_binary(reg: &mut syntex::Registry) {
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
|
||||||
|
let mut folder = StripAttributeFolder { attr_title: "binary" };
|
||||||
|
fold::Folder::fold_crate(&mut folder, krate)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.add_post_expansion_pass(strip_attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "with-syntex")]
|
||||||
|
pub fn register(reg: &mut syntex::Registry) {
|
||||||
|
reg.add_attr("feature(custom_derive)");
|
||||||
|
reg.add_attr("feature(custom_attribute)");
|
||||||
|
|
||||||
|
reg.add_decorator("ipc", codegen::expand_ipc_implementation);
|
||||||
|
reg.add_decorator("binary", serialization::expand_serialization_implementation);
|
||||||
|
|
||||||
|
register_cleaner_ipc(reg);
|
||||||
|
register_cleaner_binary(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "with-syntex"))]
|
||||||
|
pub fn register(reg: &mut rustc_plugin::Registry) {
|
||||||
|
reg.register_syntax_extension(
|
||||||
|
syntax::parse::token::intern("ipc"),
|
||||||
|
syntax::ext::base::MultiDecorator(
|
||||||
|
Box::new(codegen::expand_ipc_implementation)));
|
||||||
|
reg.register_syntax_extension(
|
||||||
|
syntax::parse::token::intern("binary"),
|
||||||
|
syntax::ext::base::MultiDecorator(
|
||||||
|
Box::new(serialization::expand_serialization_implementation)));
|
||||||
|
|
||||||
|
reg.register_attribute("ipc".to_owned(), AttributeType::Normal);
|
||||||
|
reg.register_attribute("binary".to_owned(), AttributeType::Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error { InvalidFileName, ExpandFailure, Io(std::io::Error) }
|
||||||
|
|
||||||
|
impl std::convert::From<std::io::Error> for Error {
|
||||||
|
fn from(err: std::io::Error) -> Self {
|
||||||
|
Error::Io(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_ipc_cond(src_path: &str, has_feature: bool) -> Result<(), Error> {
|
||||||
|
if has_feature { derive_ipc(src_path) }
|
||||||
|
else { cleanup_ipc(src_path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_ipc(src_path: &str) -> Result<(), Error> {
|
||||||
|
cleanup(src_path, AttributeKind::Ipc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_binary(src_path: &str) -> Result<(), Error> {
|
||||||
|
cleanup(src_path, AttributeKind::Binary)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AttributeKind {
|
||||||
|
Ipc,
|
||||||
|
Binary,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(src_path: &str, attr: AttributeKind) -> Result<(), Error> {
|
||||||
|
use std::env;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
|
||||||
|
match attr {
|
||||||
|
AttributeKind::Ipc => { register_cleaner_ipc(&mut registry); }
|
||||||
|
AttributeKind::Binary => { register_cleaner_binary(&mut registry); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_) = registry.expand("", &Path::new(src_path), &Path::new(&out_dir).join(&file_name))
|
||||||
|
{
|
||||||
|
// will be reported by compiler
|
||||||
|
return Err(Error::ExpandFailure)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_ipc(src_path: &str) -> Result<(), Error> {
|
||||||
|
use std::env;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
|
||||||
|
|
||||||
|
let final_path = Path::new(&out_dir).join(&file_name);
|
||||||
|
|
||||||
|
let mut intermediate_file_name = file_name.clone();
|
||||||
|
intermediate_file_name.push_str(".rpc.in");
|
||||||
|
let intermediate_path = Path::new(&out_dir).join(&intermediate_file_name);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
register(&mut registry);
|
||||||
|
if let Err(_) = registry.expand("", &Path::new(src_path), &intermediate_path) {
|
||||||
|
// will be reported by compiler
|
||||||
|
return Err(Error::ExpandFailure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
register(&mut registry);
|
||||||
|
if let Err(_) = registry.expand("", &intermediate_path, &final_path) {
|
||||||
|
// will be reported by compiler
|
||||||
|
return Err(Error::ExpandFailure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_binary(src_path: &str) -> Result<(), Error> {
|
||||||
|
use std::env;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
|
||||||
|
let final_path = Path::new(&out_dir).join(&file_name);
|
||||||
|
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
register(&mut registry);
|
||||||
|
if let Err(_) = registry.expand("", &Path::new(src_path), &final_path) {
|
||||||
|
// will be reported by compiler
|
||||||
|
return Err(Error::ExpandFailure)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_binary_cond(src_path: &str, has_feature: bool) -> Result<(), Error> {
|
||||||
|
if has_feature { derive_binary(src_path) }
|
||||||
|
else { cleanup_binary(src_path) }
|
||||||
|
}
|
18
ipc/codegen/src/lib.rs.in
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mod codegen;
|
||||||
|
mod serialization;
|
810
ipc/codegen/src/serialization.rs
Normal file
@ -0,0 +1,810 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
use aster;
|
||||||
|
|
||||||
|
use syntax::ast::{
|
||||||
|
MetaItem,
|
||||||
|
Item,
|
||||||
|
Ident,
|
||||||
|
};
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::codemap::Span;
|
||||||
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
|
use syntax::ptr::P;
|
||||||
|
|
||||||
|
pub struct Error;
|
||||||
|
|
||||||
|
use super::codegen;
|
||||||
|
|
||||||
|
pub fn expand_serialization_implementation(
|
||||||
|
cx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
meta_item: &MetaItem,
|
||||||
|
annotatable: &Annotatable,
|
||||||
|
push: &mut FnMut(Annotatable)
|
||||||
|
) {
|
||||||
|
let item = match *annotatable {
|
||||||
|
Annotatable::Item(ref item) => item,
|
||||||
|
_ => {
|
||||||
|
cx.span_err(meta_item.span, "`#[derive(Binary)]` may only be applied to structs and enums");
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
|
let impl_item = match serialize_item(cx, &builder, &item) {
|
||||||
|
Ok(item) => item,
|
||||||
|
Err(Error) => {
|
||||||
|
// An error occurred, but it should have been reported already.
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
push(Annotatable::Item(impl_item))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_item(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
) -> Result<P<ast::Item>, Error> {
|
||||||
|
let generics = match item.node {
|
||||||
|
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||||
|
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
item.span,
|
||||||
|
"`#[derive(Binary)]` may only be applied to structs and enums");
|
||||||
|
return Err(Error);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = builder.ty().path()
|
||||||
|
.segment(item.ident).with_generics(generics.clone()).build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
|
let binary_expressions = try!(binary_expr(cx,
|
||||||
|
&builder,
|
||||||
|
&item,
|
||||||
|
&generics,
|
||||||
|
ty.clone()));
|
||||||
|
|
||||||
|
let (size_expr, read_expr, write_expr) =
|
||||||
|
(binary_expressions.size, binary_expressions.read, binary_expressions.write);
|
||||||
|
|
||||||
|
match quote_item!(cx,
|
||||||
|
impl $generics ::ipc::BinaryConvertable for $ty $where_clause {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
$size_expr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut ::std::collections::VecDeque<usize>) -> Result<(), ::ipc::BinaryConvertError> {
|
||||||
|
$write_expr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes(buffer: &[u8], length_stack: &mut ::std::collections::VecDeque<usize>) -> Result<Self, ::ipc::BinaryConvertError> {
|
||||||
|
$read_expr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len_params() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Some(item) => Ok(item),
|
||||||
|
None => {
|
||||||
|
cx.span_err(
|
||||||
|
item.span,
|
||||||
|
"syntax error expanding serialization implementation");
|
||||||
|
Err(Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
fn binary_expr(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
impl_generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
|
) -> Result<BinaryExpressions, Error> {
|
||||||
|
match item.node {
|
||||||
|
ast::ItemKind::Struct(ref variant_data, _) => {
|
||||||
|
binary_expr_item_struct(
|
||||||
|
cx,
|
||||||
|
builder,
|
||||||
|
impl_generics,
|
||||||
|
ty,
|
||||||
|
item.span,
|
||||||
|
variant_data,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||||
|
binary_expr_enum(
|
||||||
|
cx,
|
||||||
|
builder,
|
||||||
|
item.ident,
|
||||||
|
impl_generics,
|
||||||
|
ty,
|
||||||
|
item.span,
|
||||||
|
enum_def,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
cx.span_bug(item.span,
|
||||||
|
"expected ItemStruct or ItemEnum in #[derive(Binary)]");
|
||||||
|
Err(Error) as Result<BinaryExpressions, Error>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BinaryExpressions {
|
||||||
|
pub size: P<ast::Expr>,
|
||||||
|
pub write: P<ast::Expr>,
|
||||||
|
pub read: P<ast::Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_qualified(s: &str) -> String {
|
||||||
|
if let Some(pos) = s.find("<") {
|
||||||
|
let mut source = s.to_owned();
|
||||||
|
source.insert(pos, ':');
|
||||||
|
source.insert(pos, ':');
|
||||||
|
source
|
||||||
|
}
|
||||||
|
else { s.to_owned() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binary_expr_struct(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
|
fields: &[ast::StructField],
|
||||||
|
value_ident: Option<ast::Ident>,
|
||||||
|
instance_ident: Option<ast::Ident>,
|
||||||
|
) -> Result<BinaryExpressions, Error> {
|
||||||
|
|
||||||
|
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
|
||||||
|
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
|
||||||
|
let index_ident = builder.id(format!("__field{}", index));
|
||||||
|
let field_id = match field.ident {
|
||||||
|
Some(ident) => builder.id(ident),
|
||||||
|
None => builder.id(format!("{}", index)),
|
||||||
|
};
|
||||||
|
|
||||||
|
match raw_ident.as_ref() {
|
||||||
|
"u8" => {
|
||||||
|
quote_expr!(cx, 1)
|
||||||
|
},
|
||||||
|
"[u8]" => {
|
||||||
|
value_ident.and_then(|x| {
|
||||||
|
Some(quote_expr!(cx, $x. $field_id .len()))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
quote_expr!(cx, $index_ident .len())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let field_type_ident = builder.id(
|
||||||
|
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
|
||||||
|
|
||||||
|
let field_type_ident_qualified = builder.id(
|
||||||
|
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
|
||||||
|
|
||||||
|
value_ident.and_then(|x|
|
||||||
|
{
|
||||||
|
Some(quote_expr!(cx,
|
||||||
|
match $field_type_ident_qualified::len_params() {
|
||||||
|
0 => ::std::mem::size_of::<$field_type_ident>(),
|
||||||
|
_ => $x. $field_id .size(),
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
quote_expr!(cx, match $field_type_ident_qualified::len_params() {
|
||||||
|
0 => ::std::mem::size_of::<$field_type_ident>(),
|
||||||
|
_ => $index_ident .size(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let first_size_expr = size_exprs[0].clone();
|
||||||
|
let mut total_size_expr = quote_expr!(cx, 0usize + $first_size_expr);
|
||||||
|
for index in 1..size_exprs.len() {
|
||||||
|
let next_expr = size_exprs[index].clone();
|
||||||
|
total_size_expr = quote_expr!(cx, $total_size_expr + $next_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut write_stmts = Vec::<ast::Stmt>::new();
|
||||||
|
write_stmts.push(quote_stmt!(cx, let mut offset = 0usize;).expect("stmt1"));
|
||||||
|
|
||||||
|
let mut map_stmts = Vec::<ast::Stmt>::new();
|
||||||
|
let field_amount = builder.id(&format!("{}",fields.len()));
|
||||||
|
map_stmts.push(quote_stmt!(cx, let mut map = vec![0usize; $field_amount];).expect("stmt2"));
|
||||||
|
map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).expect("stmt3"));
|
||||||
|
|
||||||
|
let mut post_write_stmts = Vec::<ast::Stmt>::new();
|
||||||
|
|
||||||
|
for (index, field) in fields.iter().enumerate() {
|
||||||
|
let field_type_ident = builder.id(
|
||||||
|
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
|
||||||
|
|
||||||
|
let field_type_ident_qualified = builder.id(
|
||||||
|
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
|
||||||
|
|
||||||
|
let field_id = match field.ident {
|
||||||
|
Some(ident) => builder.id(ident),
|
||||||
|
None => builder.id(format!("{}", index)),
|
||||||
|
};
|
||||||
|
let member_expr = match value_ident {
|
||||||
|
Some(x) => {
|
||||||
|
quote_expr!(cx, $x . $field_id)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let index_ident = builder.id(format!("__field{}", index));
|
||||||
|
quote_expr!(cx, $index_ident)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
|
||||||
|
let range_ident = builder.id(format!("r{}", index));
|
||||||
|
|
||||||
|
let error_message = "Error serializing member: ".to_owned() + &::syntax::print::pprust::expr_to_string(&member_expr);
|
||||||
|
let _error_message_literal = builder.expr().lit().str::<&str>(&error_message);
|
||||||
|
|
||||||
|
match raw_ident.as_ref() {
|
||||||
|
"u8" => {
|
||||||
|
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).expect("stmt4"));
|
||||||
|
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).expect("stm5"));
|
||||||
|
},
|
||||||
|
"[u8]" => {
|
||||||
|
write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
|
||||||
|
write_stmts.push(quote_stmt!(cx, let next_line = offset + size;).unwrap());
|
||||||
|
write_stmts.push(quote_stmt!(cx, length_stack.push_back(size);).unwrap());
|
||||||
|
write_stmts.push(quote_stmt!(cx, let $range_ident = offset..next_line; ).unwrap());
|
||||||
|
post_write_stmts.push(quote_stmt!(cx, buffer[$range_ident].clone_from_slice($member_expr); ).unwrap());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() {
|
||||||
|
0 => ::std::mem::size_of::<$field_type_ident>(),
|
||||||
|
_ => { let size = $member_expr .size(); length_stack.push_back(size); size },
|
||||||
|
}).unwrap());
|
||||||
|
write_stmts.push(quote_stmt!(cx, let $range_ident = offset..next_line; ).unwrap());
|
||||||
|
post_write_stmts.push(quote_stmt!(cx,
|
||||||
|
if $range_ident.end - $range_ident.start > 0 {
|
||||||
|
if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) {
|
||||||
|
return Err(e)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap());
|
||||||
|
|
||||||
|
let field_index = builder.id(&format!("{}", index));
|
||||||
|
map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap());
|
||||||
|
|
||||||
|
match raw_ident.as_ref() {
|
||||||
|
"u8" => {
|
||||||
|
map_stmts.push(quote_stmt!(cx, total += 1;).unwrap());
|
||||||
|
},
|
||||||
|
"[u8]" => {
|
||||||
|
map_stmts.push(quote_stmt!(cx, let size = length_stack.pop_front().unwrap();).unwrap());
|
||||||
|
map_stmts.push(quote_stmt!(cx, total += size;).unwrap());
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() {
|
||||||
|
0 => ::std::mem::size_of::<$field_type_ident>(),
|
||||||
|
_ => length_stack.pop_front().unwrap(),
|
||||||
|
}).unwrap());
|
||||||
|
map_stmts.push(quote_stmt!(cx, total += size;).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_expr = match fields.iter().any(|f| codegen::has_ptr(&f.ty)) {
|
||||||
|
true => {
|
||||||
|
// cannot create structs with pointers
|
||||||
|
quote_expr!(cx, Err(::ipc::binary::BinaryConvertError::not_supported()))
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
if value_ident.is_some() {
|
||||||
|
let instance_create = named_fields_sequence(cx, &ty, fields);
|
||||||
|
quote_expr!(cx, { $map_stmts; $instance_create; Ok(result) })
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let map_variant = P(fields_sequence(cx, &ty, fields, &instance_ident.unwrap_or(builder.id("Self"))));
|
||||||
|
quote_expr!(cx, { $map_stmts; Ok($map_variant) })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(BinaryExpressions {
|
||||||
|
size: total_size_expr,
|
||||||
|
write: quote_expr!(cx, { $write_stmts; $post_write_stmts; Ok(()) } ),
|
||||||
|
read: read_expr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
fn binary_expr_item_struct(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
_impl_generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
|
span: Span,
|
||||||
|
variant_data: &ast::VariantData,
|
||||||
|
) -> Result<BinaryExpressions, Error> {
|
||||||
|
match *variant_data {
|
||||||
|
ast::VariantData::Tuple(ref fields, _) => {
|
||||||
|
binary_expr_struct(
|
||||||
|
cx,
|
||||||
|
&builder,
|
||||||
|
ty,
|
||||||
|
fields,
|
||||||
|
Some(builder.id("self")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
ast::VariantData::Struct(ref fields, _) => {
|
||||||
|
binary_expr_struct(
|
||||||
|
cx,
|
||||||
|
&builder,
|
||||||
|
ty,
|
||||||
|
fields,
|
||||||
|
Some(builder.id("self")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
cx.span_bug(span,
|
||||||
|
&format!("#[derive(Binary)] Unsupported struct content, expected tuple/struct, found: {:?}",
|
||||||
|
variant_data));
|
||||||
|
Err(Error) as Result<BinaryExpressions, Error>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binary_expr_enum(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
|
impl_generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
|
span: Span,
|
||||||
|
enum_def: &ast::EnumDef,
|
||||||
|
) -> Result<BinaryExpressions, Error> {
|
||||||
|
let arms: Vec<_> = try!(enum_def.variants.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(variant_index, variant)| {
|
||||||
|
binary_expr_variant(
|
||||||
|
cx,
|
||||||
|
builder,
|
||||||
|
type_ident,
|
||||||
|
impl_generics,
|
||||||
|
ty.clone(),
|
||||||
|
span,
|
||||||
|
variant,
|
||||||
|
variant_index,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect());
|
||||||
|
|
||||||
|
let (size_arms, write_arms, mut read_arms) = (
|
||||||
|
arms.iter().map(|x| x.size.clone()).collect::<Vec<ast::Arm>>(),
|
||||||
|
arms.iter().map(|x| x.write.clone()).collect::<Vec<ast::Arm>>(),
|
||||||
|
arms.iter().map(|x| x.read.clone()).collect::<Vec<ast::Arm>>());
|
||||||
|
|
||||||
|
read_arms.push(quote_arm!(cx, _ => { Err(::ipc::BinaryConvertError::variant(buffer[0])) } ));
|
||||||
|
|
||||||
|
Ok(BinaryExpressions {
|
||||||
|
size: quote_expr!(cx, 1usize + match *self { $size_arms }),
|
||||||
|
write: quote_expr!(cx, match *self { $write_arms }; ),
|
||||||
|
read: quote_expr!(cx, match buffer[0] { $read_arms }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BinaryArm {
|
||||||
|
size: ast::Arm,
|
||||||
|
write: ast::Arm,
|
||||||
|
read: ast::Arm,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fields_sequence(
|
||||||
|
ext_cx: &ExtCtxt,
|
||||||
|
_ty: &P<ast::Ty>,
|
||||||
|
fields: &[ast::StructField],
|
||||||
|
variant_ident: &ast::Ident,
|
||||||
|
) -> ast::Expr {
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
|
let named_members = fields.iter().any(|f| f.ident.is_some());
|
||||||
|
|
||||||
|
::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
|
ext_cx.parse_sess(),
|
||||||
|
{
|
||||||
|
let _sp = ext_cx.call_site();
|
||||||
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
tt.push(Token(_sp, token::Ident(variant_ident.clone())));
|
||||||
|
if named_members {
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Brace)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, field) in fields.iter().enumerate() {
|
||||||
|
if field.ident.is_some() {
|
||||||
|
tt.push(Token(_sp, token::Ident(field.ident.clone().unwrap())));
|
||||||
|
tt.push(Token(_sp, token::Colon));
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case for u8, it just takes byte form sequence
|
||||||
|
if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case for [u8], it just takes a byte sequence
|
||||||
|
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::DotDot));
|
||||||
|
|
||||||
|
if idx+1 != fields.len() {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(
|
||||||
|
Token(
|
||||||
|
_sp,
|
||||||
|
token::Ident(ext_cx.ident_of(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty))))
|
||||||
|
));
|
||||||
|
tt.push(Token(_sp, token::ModSep));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::And)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::DotDot));
|
||||||
|
|
||||||
|
if idx+1 != fields.len() {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
|
||||||
|
// name member if it has resulted in the error
|
||||||
|
tt.push(Token(_sp, token::Dot));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map_err"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::Or)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::Or)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
|
||||||
|
tt.push(Token(_sp, token::Dot));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("named"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::Literal(token::Lit::Str_(
|
||||||
|
field.ident.unwrap_or(ext_cx.ident_of(&format!("f{}", idx))).name),
|
||||||
|
None))
|
||||||
|
);
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
}
|
||||||
|
if named_members {
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Brace)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
}
|
||||||
|
tt
|
||||||
|
})
|
||||||
|
).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn named_fields_sequence(
|
||||||
|
ext_cx: &ExtCtxt,
|
||||||
|
ty: &P<ast::Ty>,
|
||||||
|
fields: &[ast::StructField],
|
||||||
|
) -> ast::Stmt {
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
|
ext_cx.parse_sess(),
|
||||||
|
{
|
||||||
|
let _sp = ext_cx.call_site();
|
||||||
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("let"))));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("result"))));
|
||||||
|
tt.push(Token(_sp, token::Eq));
|
||||||
|
|
||||||
|
tt.push(Token(
|
||||||
|
_sp,
|
||||||
|
token::Ident(
|
||||||
|
ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(ty))
|
||||||
|
)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Brace)));
|
||||||
|
|
||||||
|
for (idx, field) in fields.iter().enumerate() {
|
||||||
|
tt.push(Token(_sp, match field.ident {
|
||||||
|
Some(ident) => token::Ident(ident),
|
||||||
|
None => token::Ident(ext_cx.ident_of(&format!("{}", idx))),
|
||||||
|
}));
|
||||||
|
tt.push(Token(_sp, token::Colon));
|
||||||
|
|
||||||
|
// special case for u8, it just takes byte form sequence
|
||||||
|
if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case for [u8], it just takes a byte sequence
|
||||||
|
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::DotDot));
|
||||||
|
|
||||||
|
if idx+1 != fields.len() {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(Token(
|
||||||
|
_sp,
|
||||||
|
token::Ident(
|
||||||
|
ext_cx.ident_of(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty)))
|
||||||
|
)));
|
||||||
|
tt.push(Token(_sp, token::ModSep));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::And)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::DotDot));
|
||||||
|
if idx + 1 != fields.len() {
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"))));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
|
||||||
|
// name member if it has resulted in the error
|
||||||
|
tt.push(Token(_sp, token::Dot));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map_err"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::Or)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
|
||||||
|
tt.push(Token(_sp, token::BinOp(token::Or)));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
|
||||||
|
tt.push(Token(_sp, token::Dot));
|
||||||
|
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("named"))));
|
||||||
|
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::Literal(token::Lit::Str_(
|
||||||
|
field.ident.unwrap_or(ext_cx.ident_of(&format!("f{}", idx))).name),
|
||||||
|
None))
|
||||||
|
);
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Paren)));
|
||||||
|
tt.push(Token(_sp, token::Comma));
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.push(Token(_sp, token::CloseDelim(token::Brace)));
|
||||||
|
tt
|
||||||
|
})
|
||||||
|
).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binary_expr_variant(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
type_ident: Ident,
|
||||||
|
_generics: &ast::Generics,
|
||||||
|
ty: P<ast::Ty>,
|
||||||
|
_span: Span,
|
||||||
|
variant: &ast::Variant,
|
||||||
|
variant_index: usize,
|
||||||
|
) -> Result<BinaryArm, Error> {
|
||||||
|
let variant_ident = variant.node.name;
|
||||||
|
let variant_index_ident = builder.id(format!("{}", variant_index));
|
||||||
|
|
||||||
|
match variant.node.data {
|
||||||
|
ast::VariantData::Unit(_) => {
|
||||||
|
let pat = builder.pat().path()
|
||||||
|
.id(type_ident).id(variant_ident)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let variant_val = builder.id(format!("{}::{}", type_ident, variant_ident));
|
||||||
|
|
||||||
|
Ok(BinaryArm {
|
||||||
|
size: quote_arm!(cx, $pat => { 0usize } ),
|
||||||
|
write: quote_arm!(cx, $pat => { buffer[0] = $variant_index_ident; Ok(()) } ),
|
||||||
|
read: quote_arm!(cx, $variant_index_ident => { Ok($variant_val) } ),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ast::VariantData::Tuple(ref fields, _) => {
|
||||||
|
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||||
|
.map(|i| builder.id(format!("__field{}", i)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let pat = builder.pat().enum_()
|
||||||
|
.id(type_ident).id(variant_ident).build()
|
||||||
|
.with_pats(
|
||||||
|
field_names.iter()
|
||||||
|
.map(|field| builder.pat().ref_id(field))
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let binary_expr = try!(binary_expr_struct(
|
||||||
|
cx,
|
||||||
|
&builder,
|
||||||
|
ty,
|
||||||
|
fields,
|
||||||
|
None,
|
||||||
|
Some(builder.id(format!("{}::{}", type_ident, variant_ident))),
|
||||||
|
));
|
||||||
|
|
||||||
|
let (size_expr, write_expr, read_expr) = (binary_expr.size, vec![binary_expr.write], binary_expr.read);
|
||||||
|
Ok(BinaryArm {
|
||||||
|
size: quote_arm!(cx, $pat => { $size_expr } ),
|
||||||
|
write: quote_arm!(cx,
|
||||||
|
$pat => {
|
||||||
|
buffer[0] = $variant_index_ident;
|
||||||
|
let buffer = &mut buffer[1..];
|
||||||
|
$write_expr
|
||||||
|
}),
|
||||||
|
read: quote_arm!(cx,
|
||||||
|
$variant_index_ident => {
|
||||||
|
let buffer = &buffer[1..];
|
||||||
|
$read_expr
|
||||||
|
}
|
||||||
|
),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ast::VariantData::Struct(ref fields, _) => {
|
||||||
|
let field_names: Vec<_> = (0 .. fields.len())
|
||||||
|
.map(|i| builder.id(format!("__field{}", i)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let pat = builder.pat().struct_()
|
||||||
|
.id(type_ident).id(variant_ident).build()
|
||||||
|
.with_pats(
|
||||||
|
field_names.iter()
|
||||||
|
.zip(fields.iter())
|
||||||
|
.map(|(id, field)|(field.ident.unwrap(), builder.pat().ref_id(id))))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let binary_expr = try!(binary_expr_struct(
|
||||||
|
cx,
|
||||||
|
&builder,
|
||||||
|
ty,
|
||||||
|
fields,
|
||||||
|
None,
|
||||||
|
Some(builder.id(format!("{}::{}", type_ident, variant_ident))),
|
||||||
|
));
|
||||||
|
|
||||||
|
let (size_expr, write_expr, read_expr) = (binary_expr.size, vec![binary_expr.write], binary_expr.read);
|
||||||
|
|
||||||
|
Ok(BinaryArm {
|
||||||
|
size: quote_arm!(cx, $pat => { $size_expr } ),
|
||||||
|
write: quote_arm!(cx,
|
||||||
|
$pat => {
|
||||||
|
buffer[0] = $variant_index_ident;
|
||||||
|
let buffer = &mut buffer[1..];
|
||||||
|
$write_expr
|
||||||
|
}),
|
||||||
|
read: quote_arm!(cx,
|
||||||
|
$variant_index_ident => {
|
||||||
|
let buffer = &buffer[1..];
|
||||||
|
$read_expr
|
||||||
|
}
|
||||||
|
),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
19
ipc/hypervisor/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethcore-ipc-hypervisor"
|
||||||
|
version = "1.2.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethcore-ipc = { path = "../rpc" }
|
||||||
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
|
ethcore-ipc-nano = { path = "../nano" }
|
||||||
|
semver = "0.6"
|
||||||
|
log = "0.3"
|
||||||
|
time = "0.1"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
ethcore-ipc-codegen = { path = "../codegen" }
|
21
ipc/hypervisor/build.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate ethcore_ipc_codegen;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
ethcore_ipc_codegen::derive_ipc("src/service.rs.in").unwrap();
|
||||||
|
}
|
273
ipc/hypervisor/src/lib.rs
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Parity interprocess hypervisor module
|
||||||
|
|
||||||
|
#![cfg_attr(feature="dev", allow(used_underscore_binding))]
|
||||||
|
|
||||||
|
extern crate ethcore_ipc as ipc;
|
||||||
|
extern crate ethcore_ipc_nano as nanoipc;
|
||||||
|
extern crate semver;
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
extern crate time;
|
||||||
|
|
||||||
|
pub mod service;
|
||||||
|
|
||||||
|
/// Default value for hypervisor ipc listener
|
||||||
|
pub const HYPERVISOR_IPC_URL: &'static str = "parity-internal-hyper-status.ipc";
|
||||||
|
|
||||||
|
use std::sync::{Arc,RwLock};
|
||||||
|
use service::{HypervisorService, IpcModuleId};
|
||||||
|
use std::process::{Command,Child};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub use service::{HypervisorServiceClient, ControlService, CLIENT_MODULE_ID, SYNC_MODULE_ID};
|
||||||
|
|
||||||
|
pub type BinaryId = &'static str;
|
||||||
|
|
||||||
|
pub struct Hypervisor {
|
||||||
|
ipc_addr: String,
|
||||||
|
service: Arc<HypervisorService>,
|
||||||
|
ipc_worker: RwLock<nanoipc::Worker<HypervisorService>>,
|
||||||
|
processes: RwLock<HashMap<IpcModuleId, Child>>,
|
||||||
|
modules: HashMap<IpcModuleId, BootArgs>,
|
||||||
|
pub io_path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boot arguments for binary
|
||||||
|
pub struct BootArgs {
|
||||||
|
cli: Option<Vec<String>>,
|
||||||
|
stdin: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BootArgs {
|
||||||
|
/// New empty boot arguments
|
||||||
|
pub fn new() -> BootArgs {
|
||||||
|
BootArgs {
|
||||||
|
cli: None,
|
||||||
|
stdin: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set command-line arguments for boot
|
||||||
|
pub fn cli(mut self, cli: Vec<String>) -> BootArgs {
|
||||||
|
self.cli = Some(cli);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set std-in stream for boot
|
||||||
|
pub fn stdin(mut self, stdin: Vec<u8>) -> BootArgs {
|
||||||
|
self.stdin = Some(stdin);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hypervisor {
|
||||||
|
/// initializes the Hypervisor service with the open ipc socket for incoming clients
|
||||||
|
pub fn new() -> Hypervisor {
|
||||||
|
Hypervisor::with_url(HYPERVISOR_IPC_URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module(mut self, module_id: IpcModuleId, args: BootArgs) -> Hypervisor {
|
||||||
|
self.modules.insert(module_id, args);
|
||||||
|
self.service.add_module(module_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local_module(self, module_id: IpcModuleId) -> Hypervisor {
|
||||||
|
self.service.add_module(module_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn io_path(mut self, directory: &str) -> Hypervisor {
|
||||||
|
self.io_path = directory.to_owned();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts with the specified address for the ipc listener and
|
||||||
|
/// the specified list of modules in form of created service
|
||||||
|
pub fn with_url(addr: &str) -> Hypervisor {
|
||||||
|
let service = HypervisorService::new();
|
||||||
|
let worker = nanoipc::Worker::new(&service);
|
||||||
|
Hypervisor{
|
||||||
|
ipc_addr: addr.to_owned(),
|
||||||
|
service: service,
|
||||||
|
ipc_worker: RwLock::new(worker),
|
||||||
|
processes: RwLock::new(HashMap::new()),
|
||||||
|
modules: HashMap::new(),
|
||||||
|
io_path: "/tmp".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Since one binary can host multiple modules
|
||||||
|
/// we match binaries
|
||||||
|
fn match_module(&self, module_id: &IpcModuleId) -> Option<&BootArgs> {
|
||||||
|
self.modules.get(module_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates IPC listener and starts all binaries
|
||||||
|
pub fn start(&self) {
|
||||||
|
let mut worker = self.ipc_worker.write().unwrap();
|
||||||
|
worker.add_reqrep(&self.ipc_addr).unwrap_or_else(|e| panic!("Hypervisor ipc worker can not start - critical! ({:?})", e));
|
||||||
|
|
||||||
|
for module_id in self.service.module_ids() {
|
||||||
|
self.start_module(module_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start binary for the specified module
|
||||||
|
/// Does nothing when it is already started on module is inside the
|
||||||
|
/// main binary
|
||||||
|
fn start_module(&self, module_id: IpcModuleId) {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
self.match_module(&module_id).map(|boot_args| {
|
||||||
|
let mut processes = self.processes.write().unwrap();
|
||||||
|
{
|
||||||
|
if processes.get(&module_id).is_some() {
|
||||||
|
// already started for another module
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut command = Command::new(&std::env::current_exe().unwrap());
|
||||||
|
command.stderr(std::process::Stdio::inherit());
|
||||||
|
|
||||||
|
if let Some(ref cli_args) = boot_args.cli {
|
||||||
|
for arg in cli_args { command.arg(arg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
command.stdin(std::process::Stdio::piped());
|
||||||
|
|
||||||
|
trace!(target: "hypervisor", "Spawn executable: {:?}", command);
|
||||||
|
|
||||||
|
let mut child = command.spawn().unwrap_or_else(
|
||||||
|
|e| panic!("Hypervisor cannot execute command ({:?}): {}", command, e));
|
||||||
|
|
||||||
|
if let Some(ref std_in) = boot_args.stdin {
|
||||||
|
trace!(target: "hypervisor", "Pushing std-in payload...");
|
||||||
|
child.stdin.as_mut()
|
||||||
|
.expect("std-in should be piped above")
|
||||||
|
.write(std_in)
|
||||||
|
.unwrap_or_else(|e| panic!(format!("Error trying to pipe stdin for {:?}: {:?}", &command, e)));
|
||||||
|
drop(child.stdin.take());
|
||||||
|
}
|
||||||
|
|
||||||
|
processes.insert(module_id, child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports if all modules are checked in
|
||||||
|
pub fn modules_ready(&self) -> bool {
|
||||||
|
self.service.unchecked_count() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modules_shutdown(&self) -> bool {
|
||||||
|
self.service.running_count() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for every required module to check in
|
||||||
|
pub fn wait_for_startup(&self) {
|
||||||
|
let mut worker = self.ipc_worker.write().unwrap();
|
||||||
|
while !self.modules_ready() {
|
||||||
|
worker.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for every required module to check in
|
||||||
|
pub fn wait_for_shutdown(&self) -> bool {
|
||||||
|
use time::{PreciseTime, Duration};
|
||||||
|
|
||||||
|
let mut worker = self.ipc_worker.write().unwrap();
|
||||||
|
let start = PreciseTime::now();
|
||||||
|
while !self.modules_shutdown() {
|
||||||
|
worker.poll();
|
||||||
|
if start.to(PreciseTime::now()) > Duration::seconds(30) {
|
||||||
|
warn!("Some modules failed to shutdown gracefully, they will be terminated.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.modules_shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shutdown the ipc and all managed child processes
|
||||||
|
pub fn shutdown(&self) {
|
||||||
|
let mut childs = self.processes.write().unwrap();
|
||||||
|
for (ref module, _) in childs.iter() {
|
||||||
|
trace!(target: "hypervisor", "Stopping process module: {}", module);
|
||||||
|
self.service.send_shutdown(**module);
|
||||||
|
}
|
||||||
|
trace!(target: "hypervisor", "Waiting for shutdown...");
|
||||||
|
if self.wait_for_shutdown() {
|
||||||
|
trace!(target: "hypervisor", "All modules reported shutdown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ref module, ref mut process) in childs.iter_mut() {
|
||||||
|
if self.service.is_running(**module) {
|
||||||
|
process.kill().unwrap();
|
||||||
|
trace!("Terminated {}", module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Hypervisor {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::sync::atomic::{AtomicBool,Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use nanoipc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_init() {
|
||||||
|
let url = "ipc:///tmp/test-parity-hypervisor-10.ipc";
|
||||||
|
let test_module_id = 8080u64;
|
||||||
|
|
||||||
|
let hypervisor = Hypervisor::with_url(url).local_module(test_module_id);
|
||||||
|
assert_eq!(false, hypervisor.modules_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_wait_for_startup() {
|
||||||
|
let url = "ipc:///tmp/test-parity-hypervisor-20.ipc";
|
||||||
|
let test_module_id = 8080u64;
|
||||||
|
|
||||||
|
let hypervisor_ready = Arc::new(AtomicBool::new(false));
|
||||||
|
let hypervisor_ready_local = hypervisor_ready.clone();
|
||||||
|
|
||||||
|
::std::thread::spawn(move || {
|
||||||
|
while !hypervisor_ready.load(Ordering::Relaxed) { }
|
||||||
|
|
||||||
|
let client = nanoipc::fast_client::<HypervisorServiceClient<_>>(url).unwrap();
|
||||||
|
client.handshake().unwrap();
|
||||||
|
client.module_ready(test_module_id, url.to_owned());
|
||||||
|
});
|
||||||
|
|
||||||
|
let hypervisor = Hypervisor::with_url(url).local_module(test_module_id);
|
||||||
|
hypervisor.start();
|
||||||
|
hypervisor_ready_local.store(true, Ordering::Relaxed);
|
||||||
|
hypervisor.wait_for_startup();
|
||||||
|
|
||||||
|
assert_eq!(true, hypervisor.modules_ready());
|
||||||
|
}
|
||||||
|
}
|
20
ipc/hypervisor/src/service.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Parity interprocess hypervisor IPC service
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/service.rs.in"));
|
125
ipc/hypervisor/src/service.rs.in
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::{RwLock,Arc};
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use nanoipc;
|
||||||
|
|
||||||
|
pub type IpcModuleId = u64;
|
||||||
|
|
||||||
|
/// Blockhain database module id
|
||||||
|
pub const CLIENT_MODULE_ID: IpcModuleId = 2000;
|
||||||
|
|
||||||
|
/// Sync module id
|
||||||
|
pub const SYNC_MODULE_ID: IpcModuleId = 2100;
|
||||||
|
|
||||||
|
/// IPC service that handles module management
|
||||||
|
pub struct HypervisorService {
|
||||||
|
modules: RwLock<HashMap<IpcModuleId, ModuleState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ModuleState {
|
||||||
|
started: bool,
|
||||||
|
control_url: String,
|
||||||
|
shutdown: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ipc]
|
||||||
|
pub trait ControlService {
|
||||||
|
fn shutdown(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ipc]
|
||||||
|
impl HypervisorService {
|
||||||
|
// return type for making method synchronous
|
||||||
|
fn module_ready(&self, module_id: u64, control_url: String) -> bool {
|
||||||
|
let mut modules = self.modules.write().unwrap();
|
||||||
|
modules.get_mut(&module_id).map(|mut module| {
|
||||||
|
module.started = true;
|
||||||
|
module.control_url = control_url;
|
||||||
|
});
|
||||||
|
trace!(target: "hypervisor", "Module ready: {}", module_id);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// return type for making method synchronous
|
||||||
|
fn module_shutdown(&self, module_id: u64) -> bool {
|
||||||
|
let mut modules = self.modules.write().unwrap();
|
||||||
|
modules.get_mut(&module_id).map(|mut module| {
|
||||||
|
module.shutdown = true;
|
||||||
|
});
|
||||||
|
trace!(target: "hypervisor", "Module shutdown: {}", module_id);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HypervisorService {
|
||||||
|
/// New service with the default list of modules
|
||||||
|
pub fn new() -> Arc<HypervisorService> {
|
||||||
|
HypervisorService::with_modules(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New service with list of modules that will report for being ready
|
||||||
|
pub fn with_modules(module_ids: Vec<IpcModuleId>) -> Arc<HypervisorService> {
|
||||||
|
let mut modules = HashMap::new();
|
||||||
|
for module_id in module_ids {
|
||||||
|
modules.insert(module_id, ModuleState::default());
|
||||||
|
}
|
||||||
|
Arc::new(HypervisorService {
|
||||||
|
modules: RwLock::new(modules),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add the module to the check-list
|
||||||
|
pub fn add_module(&self, module_id: IpcModuleId) {
|
||||||
|
self.modules.write().unwrap().insert(module_id, ModuleState::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of modules still being waited for check-in
|
||||||
|
pub fn unchecked_count(&self) -> usize {
|
||||||
|
self.modules.read().unwrap().iter().filter(|&(_, module)| !module.started).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of all modules within this service
|
||||||
|
pub fn module_ids(&self) -> Vec<IpcModuleId> {
|
||||||
|
self.modules.read().unwrap().iter().map(|(module_id, _)| module_id).cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of modules started and running
|
||||||
|
pub fn running_count(&self) -> usize {
|
||||||
|
self.modules.read().unwrap().iter().filter(|&(_, module)| module.started && !module.shutdown).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_running(&self, id: IpcModuleId) -> bool {
|
||||||
|
self.modules.read().unwrap().get(&id).map(|module| module.started && !module.shutdown).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_shutdown(&self, module_id: IpcModuleId) {
|
||||||
|
let modules = self.modules.read().unwrap();
|
||||||
|
modules.get(&module_id).map(|module| {
|
||||||
|
trace!(target: "hypervisor", "Sending shutdown to {}({})", module_id, &module.control_url);
|
||||||
|
let client = nanoipc::fast_client::<ControlServiceClient<_>>(&module.control_url).unwrap();
|
||||||
|
client.shutdown();
|
||||||
|
trace!(target: "hypervisor", "Sent shutdown to {}", module_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::ipc::IpcConfig for HypervisorService {}
|
||||||
|
|
||||||
|
impl ::ipc::IpcConfig for ControlService {}
|
13
ipc/nano/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethcore-ipc-nano"
|
||||||
|
version = "1.8.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethcore-ipc = { path = "../rpc" }
|
||||||
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
|
log = "0.3"
|
||||||
|
lazy_static = "0.2"
|
355
ipc/nano/src/lib.rs
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! IPC over nanomsg transport
|
||||||
|
|
||||||
|
extern crate ethcore_ipc as ipc;
|
||||||
|
extern crate nanomsg;
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate lazy_static;
|
||||||
|
|
||||||
|
pub use ipc::{WithSocket, IpcInterface, IpcConfig};
|
||||||
|
pub use nanomsg::Socket as NanoSocket;
|
||||||
|
|
||||||
|
use std::sync::*;
|
||||||
|
use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
const POLL_TIMEOUT: isize = 200;
|
||||||
|
const DEFAULT_CONNECTION_TIMEOUT: isize = 30000;
|
||||||
|
const DEBUG_CONNECTION_TIMEOUT: isize = 5000;
|
||||||
|
|
||||||
|
/// Generic worker to handle service (binded) sockets
|
||||||
|
pub struct Worker<S: ?Sized> where S: IpcInterface {
|
||||||
|
service: Arc<S>,
|
||||||
|
sockets: Vec<(Socket, Endpoint)>,
|
||||||
|
polls: Vec<PollFd>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// struct for guarding `_endpoint` (so that it wont drop)
|
||||||
|
/// derefs to client `S`
|
||||||
|
pub struct GuardedSocket<S> where S: WithSocket<Socket> {
|
||||||
|
client: Arc<S>,
|
||||||
|
_endpoint: Endpoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> GuardedSocket<S> where S: WithSocket<Socket> {
|
||||||
|
pub fn service(&self) -> Arc<S> {
|
||||||
|
self.client.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Deref for GuardedSocket<S> where S: WithSocket<Socket> {
|
||||||
|
type Target = Arc<S>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Arc<S> {
|
||||||
|
&self.client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawns client <`S`> over specified address
|
||||||
|
/// creates socket and connects endpoint to it
|
||||||
|
/// for duplex (paired) connections with the service
|
||||||
|
pub fn init_duplex_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
|
let mut socket = Socket::new(Protocol::Pair).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
socket.set_receive_timeout(DEFAULT_CONNECTION_TIMEOUT).unwrap();
|
||||||
|
|
||||||
|
let endpoint = socket.connect(socket_addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", socket_addr, e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(GuardedSocket {
|
||||||
|
client: Arc::new(S::init(socket)),
|
||||||
|
_endpoint: endpoint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawns client <`S`> over specified address
|
||||||
|
/// creates socket and connects endpoint to it
|
||||||
|
/// for request-reply connections to the service
|
||||||
|
pub fn client<S>(socket_addr: &str, receive_timeout: Option<isize>) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
|
let mut socket = Socket::new(Protocol::Req).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::RequestLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let Some(timeout) = receive_timeout {
|
||||||
|
socket.set_receive_timeout(timeout).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let endpoint = socket.connect(socket_addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", socket_addr, e);
|
||||||
|
SocketError::RequestLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
trace!(target: "ipc", "Created client for {}", socket_addr);
|
||||||
|
Ok(GuardedSocket {
|
||||||
|
client: Arc::new(S::init(socket)),
|
||||||
|
_endpoint: endpoint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// Set PARITY_IPC_DEBUG=1 for fail-fast connectivity problems diagnostic
|
||||||
|
pub static ref DEBUG_FLAG: bool = {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
if let Ok(debug) = env::var("PARITY_IPC_DEBUG") {
|
||||||
|
debug == "1" || debug.to_uppercase() == "TRUE"
|
||||||
|
}
|
||||||
|
else { false }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client with no default timeout on operations
|
||||||
|
pub fn generic_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
|
if *DEBUG_FLAG {
|
||||||
|
client(socket_addr, Some(DEBUG_CONNECTION_TIMEOUT))
|
||||||
|
} else {
|
||||||
|
client(socket_addr, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client over interface that is supposed to give quick almost non-blocking responses
|
||||||
|
pub fn fast_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
|
if *DEBUG_FLAG {
|
||||||
|
client(socket_addr, Some(DEBUG_CONNECTION_TIMEOUT))
|
||||||
|
} else {
|
||||||
|
client(socket_addr, Some(DEFAULT_CONNECTION_TIMEOUT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error occurred while establising socket or endpoint
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SocketError {
|
||||||
|
/// Error establising duplex (paired) socket and/or endpoint
|
||||||
|
DuplexLink,
|
||||||
|
/// Error establising duplex (paired) socket and/or endpoint
|
||||||
|
RequestLink,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: ?Sized> Worker<S> where S: IpcInterface {
|
||||||
|
/// New worker over specified `service`
|
||||||
|
pub fn new(service: &Arc<S>) -> Worker<S> {
|
||||||
|
Worker::<S> {
|
||||||
|
service: service.clone(),
|
||||||
|
sockets: Vec::new(),
|
||||||
|
polls: Vec::new(),
|
||||||
|
buf: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Polls all sockets, reads and dispatches method invocations
|
||||||
|
pub fn poll(&mut self) {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
let mut request = PollRequest::new(&mut self.polls[..]);
|
||||||
|
let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT);
|
||||||
|
|
||||||
|
for (fd_index, fd) in request.get_fds().iter().enumerate() {
|
||||||
|
if fd.can_read() {
|
||||||
|
let (ref mut socket, _) = self.sockets[fd_index];
|
||||||
|
unsafe { self.buf.set_len(0); }
|
||||||
|
match socket.nb_read_to_end(&mut self.buf) {
|
||||||
|
Ok(method_sign_len) => {
|
||||||
|
if method_sign_len >= 2 {
|
||||||
|
|
||||||
|
// method_num
|
||||||
|
let method_num = self.buf[0] as u16 * 256 + self.buf[1] as u16;
|
||||||
|
// payload
|
||||||
|
let payload = &self.buf[2..];
|
||||||
|
|
||||||
|
// dispatching for ipc interface
|
||||||
|
let result = self.service.dispatch_buf(method_num, payload);
|
||||||
|
|
||||||
|
if let Err(e) = socket.write(&result) {
|
||||||
|
warn!(target: "ipc", "Failed to write response: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(Error::TryAgain) => {
|
||||||
|
},
|
||||||
|
Err(x) => {
|
||||||
|
warn!(target: "ipc", "Error polling connections {:?}", x);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores nanomsg poll request for reuse
|
||||||
|
fn rebuild_poll_request(&mut self) {
|
||||||
|
self.polls = self.sockets.iter()
|
||||||
|
.map(|&(ref socket, _)| socket.new_pollfd(PollInOut::In))
|
||||||
|
.collect::<Vec<PollFd>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add exclusive socket for paired client
|
||||||
|
/// Only one connection over this address is allowed
|
||||||
|
pub fn add_duplex(&mut self, addr: &str) -> Result<(), SocketError> {
|
||||||
|
let mut socket = Socket::new(Protocol::Pair).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let endpoint = socket.bind(addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.sockets.push((socket, endpoint));
|
||||||
|
|
||||||
|
self.rebuild_poll_request();
|
||||||
|
|
||||||
|
trace!(target: "ipc", "Started duplex worker at {}", addr);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add generic socket for request-reply style communications
|
||||||
|
/// with multiple clients
|
||||||
|
pub fn add_reqrep(&mut self, addr: &str) -> Result<(), SocketError> {
|
||||||
|
let mut socket = Socket::new(Protocol::Rep).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
|
||||||
|
let endpoint = socket.bind(addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.sockets.push((socket, endpoint));
|
||||||
|
|
||||||
|
self.rebuild_poll_request();
|
||||||
|
|
||||||
|
trace!(target: "ipc", "Started request-reply worker at {}", addr);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod service_tests {
|
||||||
|
|
||||||
|
use super::Worker;
|
||||||
|
use ipc::*;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use nanomsg::{Socket, Protocol, Endpoint};
|
||||||
|
|
||||||
|
struct TestInvoke {
|
||||||
|
method_num: u16,
|
||||||
|
params: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DummyService {
|
||||||
|
methods_stack: RwLock<Vec<TestInvoke>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DummyService {
|
||||||
|
fn new() -> DummyService {
|
||||||
|
DummyService { methods_stack: RwLock::new(Vec::new()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcInterface for DummyService {
|
||||||
|
fn dispatch<R>(&self, _r: &mut R) -> Vec<u8> where R: Read {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8> {
|
||||||
|
self.methods_stack.write().unwrap().push(
|
||||||
|
TestInvoke {
|
||||||
|
method_num: method_num,
|
||||||
|
params: buf.to_vec(),
|
||||||
|
});
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for DummyService {}
|
||||||
|
|
||||||
|
fn dummy_write(addr: &str, buf: &[u8]) -> (Socket, Endpoint) {
|
||||||
|
let mut socket = Socket::new(Protocol::Pair).unwrap();
|
||||||
|
let endpoint = socket.connect(addr).unwrap();
|
||||||
|
socket.write(buf).unwrap();
|
||||||
|
(socket, endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_create_worker() {
|
||||||
|
let worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
|
assert_eq!(0, worker.sockets.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_add_duplex_socket_to_worker() {
|
||||||
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
|
worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap();
|
||||||
|
assert_eq!(1, worker.sockets.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn worker_can_poll_empty() {
|
||||||
|
let service = Arc::new(DummyService::new());
|
||||||
|
let mut worker = Worker::<DummyService>::new(&service);
|
||||||
|
worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap();
|
||||||
|
worker.poll();
|
||||||
|
assert_eq!(0, service.methods_stack.read().unwrap().len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn worker_can_poll() {
|
||||||
|
let url = "ipc:///tmp/parity-test30.ipc";
|
||||||
|
|
||||||
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
|
worker.add_duplex(url).unwrap();
|
||||||
|
|
||||||
|
let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]);
|
||||||
|
worker.poll();
|
||||||
|
|
||||||
|
assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
|
||||||
|
assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
|
||||||
|
assert_eq!([7, 7, 6, 6], worker.service.methods_stack.read().unwrap()[0].params[..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn worker_can_poll_long() {
|
||||||
|
let url = "ipc:///tmp/parity-test40.ipc";
|
||||||
|
|
||||||
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
|
worker.add_duplex(url).unwrap();
|
||||||
|
|
||||||
|
let message = [0u8; 1024*1024];
|
||||||
|
|
||||||
|
let (_socket, _endpoint) = dummy_write(url, &message);
|
||||||
|
worker.poll();
|
||||||
|
|
||||||
|
assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
|
||||||
|
assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
|
||||||
|
assert_eq!(vec![0u8; 1024*1024-2], worker.service.methods_stack.read().unwrap()[0].params);
|
||||||
|
}
|
||||||
|
}
|
14
ipc/rpc/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethcore-ipc"
|
||||||
|
version = "1.8.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethcore-devtools = { path = "../../devtools" }
|
||||||
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
|
ethcore-bigint = { path = "../../util/bigint"}
|
||||||
|
ethcore-util = { path = "../../util" }
|
||||||
|
semver = "0.6"
|
1196
ipc/rpc/src/binary.rs
Normal file
106
ipc/rpc/src/interface.rs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! IPC RPC interface
|
||||||
|
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::marker::Sync;
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
/// Handshake for client and server to negotiate api/protocol version
|
||||||
|
pub struct Handshake {
|
||||||
|
pub protocol_version: Version,
|
||||||
|
pub api_version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows to configure custom version and custom handshake response for
|
||||||
|
/// ipc host
|
||||||
|
pub trait IpcConfig {
|
||||||
|
/// Current service api version
|
||||||
|
/// Should be increased if any of the methods changes signature
|
||||||
|
fn api_version() -> Version {
|
||||||
|
Version::parse("1.0.0").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current ipc protocol version
|
||||||
|
/// Should be increased only if signature of system methods changes
|
||||||
|
fn protocol_version() -> Version {
|
||||||
|
Version::parse("1.0.0").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default handshake requires exact versions match
|
||||||
|
fn handshake(handshake: &Handshake) -> bool {
|
||||||
|
handshake.protocol_version == Self::protocol_version() &&
|
||||||
|
handshake.api_version == Self::api_version()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error in dispatching or invoking methods via IPC
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
UnkownSystemCall,
|
||||||
|
ClientUnsupported,
|
||||||
|
RemoteServiceUnsupported,
|
||||||
|
HandshakeFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows implementor to be attached to generic worker and dispatch rpc requests
|
||||||
|
/// over IPC
|
||||||
|
pub trait IpcInterface : IpcConfig {
|
||||||
|
/// reads the message from io, dispatches the call and returns serialized result
|
||||||
|
fn dispatch<R>(&self, r: &mut R) -> Vec<u8> where R: Read;
|
||||||
|
|
||||||
|
/// deserializes the payload from buffer, dispatches invoke and returns serialized result
|
||||||
|
/// (for non-blocking io)
|
||||||
|
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// serializes method invocation (method_num and parameters) to the stream specified by `w`
|
||||||
|
pub fn invoke<W>(method_num: u16, params: &Option<Vec<u8>>, w: &mut W) where W: Write {
|
||||||
|
// creating buffer to contain all message
|
||||||
|
let buf_len = match *params { None => 2, Some(ref val) => val.len() + 2 };
|
||||||
|
let mut buf = vec![0u8; buf_len];
|
||||||
|
|
||||||
|
// writing method_num as u16
|
||||||
|
buf[1] = (method_num & 255) as u8;
|
||||||
|
buf[0] = (method_num >> 8) as u8;
|
||||||
|
|
||||||
|
// serializing parameters only if provided with any
|
||||||
|
if params.is_some() {
|
||||||
|
buf[2..buf_len].clone_from_slice(params.as_ref().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.write(&buf).unwrap() != buf_len
|
||||||
|
{
|
||||||
|
// if write was inconsistent
|
||||||
|
panic!("failed to write to socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IpcSocket, read/write generalization
|
||||||
|
pub trait IpcSocket: Read + Write + Sync + Send {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Basically something that needs only socket to be spawned
|
||||||
|
pub trait WithSocket<S: IpcSocket> {
|
||||||
|
fn init(socket: S) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl IpcSocket for ::devtools::TestSocket {}
|
||||||
|
|
||||||
|
impl IpcSocket for ::nanomsg::Socket {}
|
28
ipc/rpc/src/lib.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! IPC RPC interface
|
||||||
|
|
||||||
|
extern crate ethcore_devtools as devtools;
|
||||||
|
extern crate semver;
|
||||||
|
extern crate nanomsg;
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
extern crate ethcore_bigint as bigint;
|
||||||
|
|
||||||
|
pub mod interface;
|
||||||
|
pub mod binary;
|
||||||
|
pub use interface::{IpcInterface, IpcSocket, invoke, IpcConfig, Handshake, Error, WithSocket};
|
||||||
|
pub use binary::{BinaryConvertable, BinaryConvertError, BinVersion, BinHandshake};
|
20
ipc/tests/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "ethcore-ipc-tests"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "run.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethcore-ipc = { path = "../rpc" }
|
||||||
|
ethcore-devtools = { path = "../../devtools" }
|
||||||
|
semver = "0.6"
|
||||||
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
|
ethcore-ipc-nano = { path = "../nano" }
|
||||||
|
ethcore-util = { path = "../../util" }
|
||||||
|
log = "0.3"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
ethcore-ipc-codegen = { path = "../codegen" }
|
19
ipc/tests/binary.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/binary.rs.in"));
|
169
ipc/tests/binary.rs.in
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
use util::Bytes;
|
||||||
|
|
||||||
|
#[binary]
|
||||||
|
pub enum Root {
|
||||||
|
Top,
|
||||||
|
Middle(u32, u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
#[binary]
|
||||||
|
pub struct DoubleRoot {
|
||||||
|
pub x1: u32,
|
||||||
|
pub x2: u64,
|
||||||
|
pub x3: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
#[binary]
|
||||||
|
pub struct ReferenceStruct<'a> {
|
||||||
|
pub ref_data: &'a u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
#[binary]
|
||||||
|
pub enum EnumWithStruct {
|
||||||
|
Left,
|
||||||
|
Right { how_much: u64 },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binary]
|
||||||
|
pub struct TwoVec {
|
||||||
|
v1: Vec<u8>,
|
||||||
|
v2: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binary]
|
||||||
|
struct ChunkSet {
|
||||||
|
items: Vec<Bytes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opt_two_vec() {
|
||||||
|
let example: Option<TwoVec> = None;
|
||||||
|
|
||||||
|
let serialized = ::ipc::binary::serialize(&example).unwrap();
|
||||||
|
assert_eq!(serialized, vec![0u8; 16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_with_struct() {
|
||||||
|
let example = EnumWithStruct::Right { how_much: 15 };
|
||||||
|
let serialized = ::ipc::binary::serialize(&example).unwrap();
|
||||||
|
let deserialized = ::ipc::binary::deserialize::<EnumWithStruct>(&serialized).unwrap();
|
||||||
|
assert_eq!(example, deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chunks() {
|
||||||
|
let sample: Vec<u8> = vec! [
|
||||||
|
15, 0, 0, 0, 0, 0, 0, 0, 81, 6, 0, 0, 0, 0, 0, 0,
|
||||||
|
110, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
112, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
173, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
112, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
107, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
114, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
114, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
81, 6, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
||||||
|
248, 108, 58, 133, 4, 168, 23, 200, 0, 130, 82, 8, 148, 182, 54,
|
||||||
|
177, 224, 198, 163, 123, 250, 122, 157, 158, 75, 138, 30, 7, 83, 91, 141, 56, 46, 136, 2,
|
||||||
|
197, 12, 243, 220, 69, 192, 0, 128, 28, 160, 32, 232, 123, 221, 90, 116, 93, 94, 136, 78,
|
||||||
|
235, 200, 167, 154, 3, 175, 74, 53, 133, 32, 239, 199, 169, 46, 95, 111, 114, 204, 19, 138,
|
||||||
|
15, 167, 160, 103, 72, 60, 241, 165, 248, 130, 213, 45, 166, 249, 102, 83, 87, 98, 153,
|
||||||
|
68, 58, 13, 83, 193, 182, 217, 182, 9, 241, 217, 28, 162, 152, 114, 136, 248, 110, 130, 6,
|
||||||
|
96, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 100, 131, 212, 219, 190, 174, 5, 47,
|
||||||
|
105, 201, 11, 11, 210, 108, 207, 242, 164, 74, 218, 19, 135, 6, 10, 36, 24, 30, 64, 0,
|
||||||
|
128, 27, 160, 206, 145, 163, 186, 24, 122, 126, 115, 80, 203, 152, 219, 160, 243, 1, 139,
|
||||||
|
109, 199, 115, 50, 159, 197, 95, 184, 174, 53, 150, 3, 200, 82, 138, 22, 160, 119, 226,
|
||||||
|
202, 208, 136, 165, 174, 240, 216, 222, 27, 214, 12, 213, 250, 68, 214, 144, 120, 53, 158,
|
||||||
|
46, 124, 105, 87, 220, 213, 192, 28, 81, 118, 6, 248, 110, 130, 6, 95, 133, 4, 168, 23,
|
||||||
|
200, 0, 131, 1, 95, 144, 148, 100, 131, 212, 219, 190, 174, 5, 47, 105, 201, 11, 11, 210,
|
||||||
|
108, 207, 242, 164, 74, 218, 19, 135, 6, 10, 36, 24, 30, 64, 0, 128, 27, 160, 19, 172, 66,
|
||||||
|
208, 28, 189, 213, 239, 125, 170, 127, 147, 190, 97, 171, 194, 229, 241, 178, 176, 111,
|
||||||
|
3, 201, 217, 9, 179, 23, 159, 159, 64, 55, 225, 160, 7, 123, 227, 76, 149, 80, 48, 130,
|
||||||
|
122, 23, 165, 175, 24, 89, 228, 128, 25, 106, 160, 195, 82, 204, 206, 150, 83, 70, 127,
|
||||||
|
34, 221, 169, 80, 43, 248, 110, 130, 6, 102, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148,
|
||||||
|
100, 131, 212, 219, 190, 174, 5, 47, 105, 201, 11, 11, 210, 108, 207, 242, 164, 74, 218,
|
||||||
|
19, 135, 6, 10, 36, 24, 30, 64, 0, 128, 27, 160, 29, 6, 237, 5, 67, 42, 51, 65, 172, 133,
|
||||||
|
9, 222, 160, 39, 202, 88, 230, 123, 232, 135, 234, 5, 244, 215, 99, 129, 242, 59, 63, 36,
|
||||||
|
26, 253, 160, 104, 178, 37, 227, 142, 255, 186, 41, 91, 108, 206, 13, 108, 24, 73, 229,
|
||||||
|
96, 224, 142, 230, 93, 214, 27, 60, 119, 149, 119, 56, 62, 5, 204, 179, 248, 171, 129, 136,
|
||||||
|
133, 4, 168, 23, 200, 0, 131, 2, 77, 248, 148, 137, 32, 90, 58, 59, 42, 105, 222, 109, 191,
|
||||||
|
127, 1, 237, 19, 178, 16, 139, 44, 67, 231, 128, 184, 68, 169, 5, 156, 187, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 105, 4, 134, 47, 167, 212, 79, 177, 44, 91, 97, 85, 184, 182, 222, 59, 231, 242,
|
||||||
|
110, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 2, 28, 160, 98, 5, 133, 180, 19, 27, 159, 186, 76, 27, 159, 143, 186, 97, 124, 253, 123, 40,
|
||||||
|
87, 35, 184, 115, 99, 176, 68, 85, 191, 210, 218, 132, 220, 52, 160, 48, 160, 79, 26, 47, 127, 253,
|
||||||
|
55, 252, 196, 196, 129, 87, 131, 132, 84, 74, 166, 33, 85, 134, 25, 34, 244, 14, 1, 16, 1, 205, 34,
|
||||||
|
30, 3, 248, 101, 3, 133, 13, 43, 184, 47, 225, 131, 1, 95, 144, 148, 202, 110, 19, 32, 65, 111, 158,
|
||||||
|
204, 235, 91, 252, 213, 35, 215, 54, 91, 165, 67, 183, 171, 1, 128, 28, 160, 182, 194, 27, 223, 136,
|
||||||
|
182, 189, 146, 57, 61, 173, 62, 58, 241, 42, 80, 125, 174, 84, 191, 82, 124, 228, 62, 216, 233, 116,
|
||||||
|
117, 227, 207, 138, 56, 160, 31, 210, 242, 212, 31, 156, 129, 155, 166, 64, 102, 140, 134, 35, 176,
|
||||||
|
137, 201, 206, 213, 199, 238, 132, 185, 145, 220, 217, 151, 80, 243, 93, 71, 211, 248, 110, 130,
|
||||||
|
6, 101, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 100, 131, 212, 219, 190, 174, 5, 47, 105,
|
||||||
|
201, 11, 11, 210, 108, 207, 242, 164, 74, 218, 19, 135, 6, 10, 36, 24, 30, 64, 0, 128, 27, 160,
|
||||||
|
86, 37, 61, 45, 13, 251, 9, 19, 188, 242, 233, 83, 77, 137, 28, 185, 141, 105, 217, 54, 182, 156,
|
||||||
|
119, 223, 213, 112, 240, 20, 119, 167, 4, 7, 160, 95, 53, 122, 159, 6, 209, 70, 155, 122, 153, 165,
|
||||||
|
192, 249, 223, 219, 83, 159, 40, 242, 39, 44, 132, 182, 208, 232, 77, 64, 178, 241, 233, 230, 253,
|
||||||
|
248, 110, 130, 6, 99, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 100, 131, 212, 219, 190, 174,
|
||||||
|
5, 47, 105, 201, 11, 11, 210, 108, 207, 242, 164, 74, 218, 19, 135, 6, 10, 36, 24, 30, 64, 0, 128,
|
||||||
|
27, 160, 114, 33, 104, 64, 195, 12, 156, 235, 56, 59, 210, 102, 183, 210, 216, 137, 223, 207, 134,
|
||||||
|
63, 65, 36, 204, 121, 38, 175, 214, 106, 184, 197, 26, 173, 160, 39, 94, 238, 34, 106, 190, 22,
|
||||||
|
225, 95, 211, 192, 249, 95, 231, 1, 111, 8, 204, 133, 35, 84, 242, 134, 75, 61, 50, 26, 150, 46,
|
||||||
|
209, 129, 155, 248, 105, 106, 133, 5, 103, 130, 1, 225, 131, 2, 130, 119, 148, 191, 78, 215, 178,
|
||||||
|
127, 29, 102, 101, 70, 227, 13, 116, 213, 13, 23, 61, 32, 188, 167, 84, 128, 132, 60, 207, 214,
|
||||||
|
11, 28, 160, 3, 83, 228, 182, 32, 30, 183, 26, 157, 247, 32, 142, 60, 192, 100, 175, 106, 216,
|
||||||
|
144, 16, 100, 165, 95, 91, 135, 138, 14, 41, 82, 251, 207, 159, 160, 74, 160, 161, 187, 63, 216,
|
||||||
|
18, 23, 64, 172, 216, 238, 192, 134, 191, 204, 206, 236, 197, 134, 116, 130, 15, 85, 113, 173,
|
||||||
|
130, 39, 50, 160, 49, 222, 248, 110, 130, 6, 98, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148,
|
||||||
|
100, 131, 212, 219, 190, 174, 5, 47, 105, 201, 11, 11, 210, 108, 207, 242, 164, 74, 218, 19, 135,
|
||||||
|
6, 10, 36, 24, 30, 64, 0, 128, 28, 160, 138, 12, 20, 188, 112, 66, 91, 30, 216, 44, 24, 124, 242,
|
||||||
|
200, 111, 179, 32, 26, 37, 221, 239, 110, 1, 84, 48, 89, 86, 61, 169, 129, 90, 21, 160, 44, 172,
|
||||||
|
112, 11, 130, 45, 247, 188, 207, 91, 247, 195, 58, 188, 110, 127, 59, 227, 41, 151, 244, 41, 120,
|
||||||
|
68, 185, 238, 41, 236, 195, 141, 38, 16, 248, 112, 131, 5, 238, 44, 133, 4, 168, 23, 200, 0, 131,
|
||||||
|
1, 95, 144, 148, 5, 113, 9, 145, 204, 89, 103, 32, 126, 46, 182, 84, 47, 76, 28, 159, 77, 184,
|
||||||
|
154, 59, 136, 1, 100, 240, 147, 154, 69, 101, 18, 128, 27, 160, 130, 0, 124, 82, 177, 112, 241,
|
||||||
|
14, 47, 186, 67, 117, 176, 187, 147, 94, 4, 177, 218, 198, 55, 59, 245, 9, 142, 95, 88, 220, 63,
|
||||||
|
98, 175, 49, 160, 17, 204, 228, 24, 242, 38, 166, 219, 17, 56, 103, 244, 33, 125, 223, 45, 43,
|
||||||
|
252, 215, 163, 40, 1, 187, 152, 34, 229, 82, 180, 213, 148, 129, 32, 248, 110, 130, 6, 100, 133,
|
||||||
|
4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 100, 131, 212, 219, 190, 174, 5, 47, 105, 201, 11, 11,
|
||||||
|
210, 108, 207, 242, 164, 74, 218, 19, 135, 6, 10, 36, 24, 30, 64, 0, 128, 27, 160, 149, 149, 154,
|
||||||
|
6, 198, 127, 14, 11, 164, 0, 244, 4, 74, 83, 9, 108, 164, 66, 186, 26, 109, 69, 98, 41, 149, 33,
|
||||||
|
238, 137, 23, 175, 124, 226, 160, 39, 249, 210, 237, 52, 83, 110, 229, 138, 84, 199, 64, 19, 209,
|
||||||
|
156, 195, 9, 50, 184, 64, 78, 67, 158, 167, 121, 220, 80, 137, 104, 240, 50, 60, 248, 112, 131, 5,
|
||||||
|
238, 45, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 247, 0, 201, 156, 113, 12, 158, 3, 208, 61,
|
||||||
|
221, 91, 236, 235, 235, 195, 40, 46, 100, 73, 136, 13, 230, 68, 67, 114, 161, 197, 100, 128, 27,
|
||||||
|
160, 123, 206, 0, 221, 2, 87, 197, 156, 109, 157, 133, 31, 26, 145, 223, 150, 235, 160, 54, 144,
|
||||||
|
210, 146, 31, 173, 221, 128, 233, 148, 73, 82, 191, 220, 160, 57, 62, 114, 94, 77, 8, 116, 150,
|
||||||
|
51, 112, 241, 70, 149, 157, 209, 193, 213, 109, 248, 102, 177, 27, 132, 226, 77, 141, 128, 122,
|
||||||
|
185, 238, 188, 114, 248, 110, 130, 6, 97, 133, 4, 168, 23, 200, 0, 131, 1, 95, 144, 148, 100,
|
||||||
|
131, 212, 219, 190, 174, 5, 47, 105, 201, 11, 11, 210, 108, 207, 242, 164, 74, 218, 19, 135, 6,
|
||||||
|
10, 36, 24, 30, 64, 0, 128, 28, 160, 53, 222, 41, 101, 73, 44, 103, 26, 39, 165, 120, 194, 128,
|
||||||
|
67, 109, 151, 96, 42, 193, 47, 255, 23, 27, 247, 8, 125, 200, 53, 129, 69, 103, 64, 160, 49, 12,
|
||||||
|
64, 143, 74, 149, 161, 245, 68, 83, 89, 101, 212, 254, 81, 16, 170, 176, 33, 87, 6, 112, 34, 153,
|
||||||
|
6, 192, 98, 126, 188, 17, 199, 155];
|
||||||
|
|
||||||
|
let chunks = ::ipc::binary::deserialize::<ChunkSet>(&sample).unwrap();
|
||||||
|
let total_length = chunks.items.iter().fold(0usize, |total, item| total + item.len());
|
||||||
|
|
||||||
|
assert_eq!(1617, total_length);
|
||||||
|
}
|
24
ipc/tests/build.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extern crate ethcore_ipc_codegen as codegen;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
codegen::derive_ipc("nested.rs.in").unwrap();
|
||||||
|
codegen::derive_ipc("service.rs.in").unwrap();
|
||||||
|
codegen::derive_ipc("with_attrs.rs.in").unwrap();
|
||||||
|
codegen::derive_binary("binary.rs.in").unwrap();
|
||||||
|
}
|
173
ipc/tests/examples.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::super::service::*;
|
||||||
|
use super::super::binary::*;
|
||||||
|
use super::super::nested::{DBClient, DBWriter};
|
||||||
|
use ipc::*;
|
||||||
|
use devtools::*;
|
||||||
|
use semver::Version;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_service() {
|
||||||
|
// method_num = 0, f = 10 (method Service::commit)
|
||||||
|
let mut socket = TestSocket::new_ready(vec![
|
||||||
|
0, 16,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
4, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
10, 0, 0, 0]);
|
||||||
|
|
||||||
|
let service = Arc::new(Service::new());
|
||||||
|
assert_eq!(0, *service.commits.read().unwrap());
|
||||||
|
|
||||||
|
service.dispatch(&mut socket);
|
||||||
|
|
||||||
|
assert_eq!(10, *service.commits.read().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_service_client() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![10, 0, 0, 0];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
let result = service_client.commit(5);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec![0, 16,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
4, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
5, 0, 0, 0],
|
||||||
|
service_client.socket().write().unwrap().write_buffer.clone());
|
||||||
|
assert_eq!(10, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_service_client_optional() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![10, 0, 0, 0];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
let result = service_client.rollback(Some(5), 10);
|
||||||
|
|
||||||
|
assert_eq!(vec![
|
||||||
|
0, 17,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
4, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
8, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().write().unwrap().write_buffer.clone());
|
||||||
|
assert_eq!(10, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn query_default_version() {
|
||||||
|
let ver = Service::protocol_version();
|
||||||
|
assert_eq!(ver, Version::parse("1.0.0").unwrap());
|
||||||
|
let ver = Service::api_version();
|
||||||
|
assert_eq!(ver, Version::parse("1.0.0").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_service_client_handshake() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
let result = service_client.handshake();
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_use_custom_params() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
let result = service_client.push_custom(CustomData { a: 3, b: 11});
|
||||||
|
|
||||||
|
assert_eq!(vec![
|
||||||
|
// message num..
|
||||||
|
0, 18,
|
||||||
|
// variable size length-s
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
16, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
// total length
|
||||||
|
16, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
// items
|
||||||
|
3, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
11, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
service_client.socket().write().unwrap().write_buffer.clone());
|
||||||
|
assert_eq!(true, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_invoke_generic_service() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
let db_client = DBClient::<u64, _>::init(socket);
|
||||||
|
let result = db_client.write(vec![1u8; 1]);
|
||||||
|
assert_eq!(vec![0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||||
|
db_client.socket().write().unwrap().write_buffer.clone());
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_handshake_generic_service() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let db_client = DBClient::<u64, _>::init(socket);
|
||||||
|
|
||||||
|
let result = db_client.handshake();
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_serialize_dummy_structs() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
|
||||||
|
let struct_ = DoubleRoot { x1: 0, x2: 100, x3: 100000};
|
||||||
|
let res = ::ipc::binary::serialize_into(&struct_, &mut socket);
|
||||||
|
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
let mut read_socket = TestSocket::new_ready(socket.write_buffer.clone());
|
||||||
|
let new_struct: DoubleRoot = ::ipc::binary::deserialize_from(&mut read_socket).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(struct_, new_struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_call_void_method() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
service_client.void(99);
|
||||||
|
|
||||||
|
assert_eq!(vec![
|
||||||
|
0, 19,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
8, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
99, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
service_client.socket().write().unwrap().write_buffer.clone());
|
||||||
|
}
|
||||||
|
}
|
18
ipc/tests/nested.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/nested.rs.in"));
|
56
ipc/tests/nested.rs.in
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
|
||||||
|
pub struct DB<L: Sized> {
|
||||||
|
pub writes: RwLock<u64>,
|
||||||
|
pub reads: RwLock<u64>,
|
||||||
|
pub holdings: L,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DBWriter {
|
||||||
|
fn write(&self, data: Vec<u8>) -> Result<(), DBError>;
|
||||||
|
fn write_slice(&self, data: &[u8]) -> Result<(), DBError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for DBWriter {}
|
||||||
|
|
||||||
|
#[binary]
|
||||||
|
pub enum DBError { Write, Read }
|
||||||
|
|
||||||
|
#[ipc]
|
||||||
|
impl<L: Sized> DBWriter for DB<L> {
|
||||||
|
fn write(&self, data: Vec<u8>) -> Result<(), DBError> {
|
||||||
|
let mut writes = self.writes.write().unwrap();
|
||||||
|
*writes = *writes + data.len() as u64;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_slice(&self, data: &[u8]) -> Result<(), DBError> {
|
||||||
|
let mut writes = self.writes.write().unwrap();
|
||||||
|
*writes = *writes + data.len() as u64;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ipc]
|
||||||
|
trait DBNotify {
|
||||||
|
fn notify(&self, a: u64, b: u64) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for DBNotify { }
|
77
ipc/tests/over_nano.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::super::service::*;
|
||||||
|
use super::super::with_attrs::PrettyNamedClient;
|
||||||
|
use nanoipc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::atomic::{Ordering, AtomicBool};
|
||||||
|
|
||||||
|
fn dummy_write(addr: &str, buf: &[u8]) -> (::nanomsg::Socket, ::nanomsg::Endpoint) {
|
||||||
|
let mut socket = ::nanomsg::Socket::new(::nanomsg::Protocol::Pair).unwrap();
|
||||||
|
let endpoint = socket.connect(addr).unwrap();
|
||||||
|
socket.write(buf).unwrap();
|
||||||
|
(socket, endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn init_worker(addr: &str) -> nanoipc::Worker<Service> {
|
||||||
|
let mut worker = nanoipc::Worker::<Service>::new(&Arc::new(Service::new()));
|
||||||
|
worker.add_duplex(addr).unwrap();
|
||||||
|
worker
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_create_client() {
|
||||||
|
let client = nanoipc::init_duplex_client::<ServiceClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
|
||||||
|
assert!(client.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_create_renamed_client() {
|
||||||
|
let client = nanoipc::init_duplex_client::<PrettyNamedClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
|
||||||
|
assert!(client.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_call_handshake() {
|
||||||
|
let url = "ipc:///tmp/parity-test-nano-20.ipc";
|
||||||
|
let worker_should_exit = Arc::new(AtomicBool::new(false));
|
||||||
|
let worker_is_ready = Arc::new(AtomicBool::new(false));
|
||||||
|
let c_worker_should_exit = worker_should_exit.clone();
|
||||||
|
let c_worker_is_ready = worker_is_ready.clone();
|
||||||
|
|
||||||
|
::std::thread::spawn(move || {
|
||||||
|
let mut worker = init_worker(url);
|
||||||
|
while !c_worker_should_exit.load(Ordering::Relaxed) {
|
||||||
|
worker.poll();
|
||||||
|
c_worker_is_ready.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
while !worker_is_ready.load(Ordering::Relaxed) { }
|
||||||
|
let client = nanoipc::init_duplex_client::<ServiceClient<_>>(url).unwrap();
|
||||||
|
|
||||||
|
let hs = client.handshake();
|
||||||
|
|
||||||
|
worker_should_exit.store(true, Ordering::Relaxed);
|
||||||
|
assert!(hs.is_ok());
|
||||||
|
}
|
||||||
|
}
|
32
ipc/tests/run.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern crate ethcore_ipc as ipc;
|
||||||
|
extern crate ethcore_devtools as devtools;
|
||||||
|
extern crate semver;
|
||||||
|
extern crate nanomsg;
|
||||||
|
extern crate ethcore_ipc_nano as nanoipc;
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
|
||||||
|
pub mod service;
|
||||||
|
mod examples;
|
||||||
|
mod over_nano;
|
||||||
|
mod nested;
|
||||||
|
mod binary;
|
||||||
|
mod with_attrs;
|
18
ipc/tests/service.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/service.rs.in"));
|
69
ipc/tests/service.rs.in
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
|
||||||
|
pub struct Service {
|
||||||
|
pub commits: RwLock<usize>,
|
||||||
|
pub rollbacks: RwLock<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binary]
|
||||||
|
pub struct CustomData {
|
||||||
|
pub a: u64,
|
||||||
|
pub b: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ipc]
|
||||||
|
impl Service {
|
||||||
|
fn commit(&self, f: u32) -> u32 {
|
||||||
|
let mut lock = self.commits.write().unwrap();
|
||||||
|
*lock = *lock + f as usize;
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rollback(&self, a: Option<u32>, b: u32) -> i32 {
|
||||||
|
let a_0 = a.unwrap_or_else(|| 0);
|
||||||
|
let mut lock = self.rollbacks.write().unwrap();
|
||||||
|
*lock = *lock + a_0 as usize - b as usize;
|
||||||
|
(a_0 - b) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_custom(&self, data: CustomData) -> bool {
|
||||||
|
let mut clock = self.commits.write().unwrap();
|
||||||
|
let mut rlock = self.commits.write().unwrap();
|
||||||
|
|
||||||
|
*clock = data.a as usize;
|
||||||
|
*rlock = data.b as usize;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn void(&self, a: u64) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Service {
|
||||||
|
pub fn new() -> Service {
|
||||||
|
Service {
|
||||||
|
commits: RwLock::new(0usize),
|
||||||
|
rollbacks: RwLock::new(0usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::ipc::IpcConfig for Service {}
|
18
ipc/tests/with_attrs.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/with_attrs.rs.in"));
|
28
ipc/tests/with_attrs.rs.in
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
|
||||||
|
pub struct BadlyNamedService;
|
||||||
|
|
||||||
|
#[ipc(client_ident="PrettyNamedClient")]
|
||||||
|
impl BadlyNamedService {
|
||||||
|
fn is_zero(&self, x: u64) -> bool {
|
||||||
|
x == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcConfig for BadlyNamedService {}
|
202
js/assets/fonts/Roboto/LICENSE.txt
Executable file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
56
js/assets/fonts/Roboto/font.css
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/0eC6fl06luXEYWpBSJvXCIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Fl4y0QdOxyyTHEGMXX8kcYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/-L14Jk06m6pUHB-5mXQQnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/I3S1wsgSg9YCurV6PUkTOYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/NYDWBdD4gIq26G5XYbHsFIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Pru33qjShpZSmG3z6VYwnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Hgo13k-tfSpn0qi1SFdUfZBw1xU1rKptJj_0jans920.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
|
}
|
BIN
js/assets/fonts/Roboto/ttf/Roboto-Black.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-BlackItalic.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Bold.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-BoldItalic.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Italic.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Light.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-LightItalic.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Medium.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-MediumItalic.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Regular.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-Thin.ttf
Executable file
BIN
js/assets/fonts/Roboto/ttf/Roboto-ThinItalic.ttf
Executable file
202
js/assets/fonts/RobotoMono/LICENSE.txt
Executable file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
56
js/assets/fonts/RobotoMono/font.css
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz0ExlR2MysFCBK8OirNw2kM.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz2dsm03krrxlabhmVQFB99s.woff2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59FzyJ0caWjaSBdV-xZbEgst_k.woff2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz2MSHb9EAJwuSzGfuRChQzQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz-pRBTtN4E2_qSPBnw6AgMc.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz9Dnm4qiMZlH5rhYv_7LI2Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto Mono';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz9TIkQYohD4BpHvJ3NvbHoA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
|
}
|
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Bold.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-BoldItalic.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Italic.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Light.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-LightItalic.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Medium.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-MediumItalic.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Regular.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-Thin.ttf
Executable file
BIN
js/assets/fonts/RobotoMono/ttf/RobotoMono-ThinItalic.ttf
Executable file
4
js/assets/images/certifications/unknown.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle fill="#4A90E2" cx="50" cy="50" r="50"/>
|
||||||
|
<path d="M20 45 L10 55 L35 85 L90 35 L80 25 L36 65 z" fill="#FFF"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 213 B |
BIN
js/assets/images/contracts/ethereum-black-64x64.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
js/assets/images/contracts/ethereum-black.png
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
js/assets/images/contracts/ethereum-white.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
js/assets/images/contracts/unknown-64x64.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
js/assets/images/contracts/unknown.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
js/assets/images/dapps/blocks-350.jpg
Normal file
After Width: | Height: | Size: 230 KiB |
12
js/assets/images/dapps/close.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" viewBox="0 0 512 512">
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<path d="M295.516 216.494h154v78.992h-154v-78.992z" fill="#FFFFFF" />
|
||||||
|
<path d="M62.474 216.514h154.050v78.971h-154.050v-78.971z" fill="#FFFFFF" />
|
||||||
|
<path d="M216.525 295.465h79.001v154.050h-79.001v-154.050z" fill="#FFFFFF" />
|
||||||
|
<path d="M216.525 62.474h79.001v154.041h-79.001v-154.041z" fill="#FFFFFF" />
|
||||||
|
<path d="M216.525 216.514h79.001v78.971h-79.001v-78.971z" fill="#FFFFFF" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 720 B |
12
js/assets/images/dapps/plus.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" viewBox="0 0 512 512">
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<path d="M295.516 216.494h154v78.992h-154v-78.992z" fill="#000000" />
|
||||||
|
<path d="M62.474 216.514h154.050v78.971h-154.050v-78.971z" fill="#000000" />
|
||||||
|
<path d="M216.525 295.465h79.001v154.050h-79.001v-154.050z" fill="#000000" />
|
||||||
|
<path d="M216.525 62.474h79.001v154.041h-79.001v-154.041z" fill="#000000" />
|
||||||
|
<path d="M216.525 216.514h79.001v78.971h-79.001v-78.971z" fill="#000000" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 715 B |
BIN
js/assets/images/dapps/signature.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
js/assets/images/parity-logo-black-no-text.ico
Normal file
After Width: | Height: | Size: 674 B |