* Use try!/map_err instead of match
* Use jsonrpc_core for serializing/deserializing rpc messages * Factor out unwraps * Remove mem::replace * Add nicer formating of ConfirmationRequests
This commit is contained in:
parent
273d7c00c3
commit
7a176094d5
@ -43,6 +43,8 @@ use presale::ImportWallet;
|
|||||||
use account::{AccountCmd, NewAccount, ImportAccounts, ImportFromGethAccounts};
|
use account::{AccountCmd, NewAccount, ImportAccounts, ImportFromGethAccounts};
|
||||||
use snapshot::{self, SnapshotCommand};
|
use snapshot::{self, SnapshotCommand};
|
||||||
|
|
||||||
|
const AUTHCODE_FILENAME: &'static str = "authcodes";
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Cmd {
|
pub enum Cmd {
|
||||||
Run(RunCmd),
|
Run(RunCmd),
|
||||||
@ -62,7 +64,7 @@ pub enum Cmd {
|
|||||||
authfile: PathBuf
|
authfile: PathBuf
|
||||||
},
|
},
|
||||||
SignerReject {
|
SignerReject {
|
||||||
id: usize,
|
id: Option<usize>,
|
||||||
port: u16,
|
port: u16,
|
||||||
authfile: PathBuf
|
authfile: PathBuf
|
||||||
},
|
},
|
||||||
@ -124,15 +126,14 @@ impl Configuration {
|
|||||||
=======
|
=======
|
||||||
} else if self.args.cmd_signer {
|
} else if self.args.cmd_signer {
|
||||||
let mut authfile = PathBuf::from(signer_conf.signer_path);
|
let mut authfile = PathBuf::from(signer_conf.signer_path);
|
||||||
authfile.push("authcodes");
|
authfile.push(AUTHCODE_FILENAME);
|
||||||
|
|
||||||
if self.args.cmd_new_token {
|
if self.args.cmd_new_token {
|
||||||
Cmd::SignerToken(dirs.signer)
|
Cmd::SignerToken(dirs.signer)
|
||||||
} else if self.args.cmd_sign {
|
} else if self.args.cmd_sign {
|
||||||
let pwfile = match self.args.flag_password.get(0) {
|
let pwfile = self.args.flag_password.get(0).map(|pwfile| {
|
||||||
Some(pwfile) => Some(PathBuf::from(pwfile)),
|
PathBuf::from(pwfile)
|
||||||
None => None,
|
});
|
||||||
};
|
|
||||||
Cmd::SignerSign {
|
Cmd::SignerSign {
|
||||||
id: self.args.arg_id,
|
id: self.args.arg_id,
|
||||||
pwfile: pwfile,
|
pwfile: pwfile,
|
||||||
@ -141,8 +142,7 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
} else if self.args.cmd_reject {
|
} else if self.args.cmd_reject {
|
||||||
Cmd::SignerReject {
|
Cmd::SignerReject {
|
||||||
// id is a required field for this command
|
id: self.args.arg_id,
|
||||||
id: self.args.arg_id.unwrap(),
|
|
||||||
port: signer_conf.port,
|
port: signer_conf.port,
|
||||||
authfile: authfile,
|
authfile: authfile,
|
||||||
}
|
}
|
||||||
|
@ -41,16 +41,16 @@ impl From<helpers::ConfirmationRequest> for ConfirmationRequest {
|
|||||||
|
|
||||||
impl fmt::Display for ConfirmationRequest {
|
impl fmt::Display for ConfirmationRequest {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "id: {:?}, {}", self.id, self.payload)
|
write!(f, "#{}: {}", self.id, self.payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConfirmationPayload {
|
impl fmt::Display for ConfirmationPayload {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match *self {
|
||||||
&ConfirmationPayload::Transaction(ref transaction)
|
ConfirmationPayload::Transaction(ref transaction)
|
||||||
=> write!(f, "{}", transaction),
|
=> write!(f, "{}", transaction),
|
||||||
&ConfirmationPayload::Sign(_) => write!(f, "TODO: data"),
|
ConfirmationPayload::Sign(_) => write!(f, "TODO: data"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,16 @@ pub struct TransactionRequest {
|
|||||||
|
|
||||||
impl fmt::Display for TransactionRequest {
|
impl fmt::Display for TransactionRequest {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?} from {:?} to {:?}",
|
let eth = self.value.unwrap_or(U256::from(0));
|
||||||
self.value.unwrap_or(U256::from(0)),
|
match self.to {
|
||||||
|
Some(ref to) => write!(f, "{} Ether from {:?} to {:?}",
|
||||||
|
eth.format_ether(),
|
||||||
self.from,
|
self.from,
|
||||||
self.to)
|
to),
|
||||||
|
None => write!(f, "{} Ether from {:?}",
|
||||||
|
eth.format_ether(),
|
||||||
|
self.from),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,25 @@ macro_rules! impl_uint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
/// Human readable formatting
|
||||||
|
pub fn format_ether(&self) -> String {
|
||||||
|
let divisor = $other::from(10u64.pow(18));
|
||||||
|
let ether = self.0 / divisor;
|
||||||
|
let rest = self.0 - ether * divisor;
|
||||||
|
let string = format!("{}.{}", ether, rest);
|
||||||
|
string.trim_right_matches('0')
|
||||||
|
.trim_right_matches('.')
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for $name {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::LowerHex for $name {
|
impl fmt::LowerHex for $name {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:#x}", self.0)
|
write!(f, "{:#x}", self.0)
|
||||||
|
@ -15,7 +15,7 @@ use std::fs::File;
|
|||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
|
||||||
fn sign_interactive(signer: &mut SignerRpc, pwd: &String, request: ConfirmationRequest)
|
fn sign_interactive(signer: &mut SignerRpc, password: &str, request: ConfirmationRequest)
|
||||||
{
|
{
|
||||||
print!("\n{}\nSign this transaction? (y)es/(N)o/(r)eject: ", request);
|
print!("\n{}\nSign this transaction? (y)es/(N)o/(r)eject: ", request);
|
||||||
let _ = stdout().flush();
|
let _ = stdout().flush();
|
||||||
@ -23,7 +23,7 @@ fn sign_interactive(signer: &mut SignerRpc, pwd: &String, request: ConfirmationR
|
|||||||
Some(Ok(line)) => {
|
Some(Ok(line)) => {
|
||||||
match line.to_lowercase().chars().nth(0) {
|
match line.to_lowercase().chars().nth(0) {
|
||||||
Some('y') => {
|
Some('y') => {
|
||||||
match sign_transaction(signer, request.id, pwd) {
|
match sign_transaction(signer, request.id, password) {
|
||||||
Ok(s) | Err(s) => println!("{}", s),
|
Ok(s) | Err(s) => println!("{}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,128 +39,129 @@ fn sign_interactive(signer: &mut SignerRpc, pwd: &String, request: ConfirmationR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_transactions(signer: &mut SignerRpc, pwd: String) -> Result<String, String> {
|
fn sign_transactions(signer: &mut SignerRpc, password: String) -> Result<String, String> {
|
||||||
signer.requests_to_confirm().map(|reqs| {
|
try!(signer.requests_to_confirm().map(|reqs| {
|
||||||
match reqs {
|
match reqs {
|
||||||
|
Ok(ref reqs) if reqs.is_empty() => {
|
||||||
|
Ok("No transactions in signing queue".to_owned())
|
||||||
|
}
|
||||||
Ok(reqs) => {
|
Ok(reqs) => {
|
||||||
if reqs.len() == 0 {
|
|
||||||
Ok("No transactions in signing queue".to_string())
|
|
||||||
} else {
|
|
||||||
for r in reqs {
|
for r in reqs {
|
||||||
sign_interactive(signer, &pwd, r)
|
sign_interactive(signer, &password, r)
|
||||||
}
|
|
||||||
Ok("".to_string())
|
|
||||||
}
|
}
|
||||||
|
Ok("".to_owned())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Err(format!("error: {:?}", err))
|
Err(format!("error: {:?}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).wait().unwrap()
|
}).map_err(|err| {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}).wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_transactions(signer: &mut SignerRpc) -> Result<String, String> {
|
fn list_transactions(signer: &mut SignerRpc) -> Result<String, String> {
|
||||||
signer.requests_to_confirm().map(|reqs| {
|
try!(signer.requests_to_confirm().map(|reqs| {
|
||||||
match reqs {
|
match reqs {
|
||||||
Ok(reqs) => {
|
Ok(ref reqs) if reqs.is_empty() => {
|
||||||
let mut s = "Transaction queue:".to_string();
|
Ok("No transactions in signing queue".to_owned())
|
||||||
if reqs.len() == 0 {
|
|
||||||
s = s + &"No transactions in signing queue";
|
|
||||||
} else {
|
|
||||||
for r in reqs {
|
|
||||||
s = s + &format!("\n{}", r);
|
|
||||||
}
|
}
|
||||||
}
|
Ok(ref reqs) => {
|
||||||
Ok(s)
|
Ok(format!("Transaction queue:\n{}", reqs
|
||||||
|
.iter()
|
||||||
|
.map(|r| format!("{}", r))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n")))
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Err(format!("error: {:?}", err))
|
Err(format!("error: {:?}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).wait().unwrap()
|
}).map_err(|err| {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}).wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_transaction(signer: &mut SignerRpc,
|
fn sign_transaction(signer: &mut SignerRpc,
|
||||||
id: U256,
|
id: U256,
|
||||||
pwd: &String) -> Result<String, String> {
|
password: &str) -> Result<String, String> {
|
||||||
signer.confirm_request(id, None, &pwd).map(|res| {
|
try!(signer.confirm_request(id, None, password).map(|res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(u) => Ok(format!("Signed transaction id: {:#x}", u)),
|
Ok(u) => Ok(format!("Signed transaction id: {:#x}", u)),
|
||||||
Err(e) => Err(format!("{:?}", e)),
|
Err(e) => Err(format!("{:?}", e)),
|
||||||
}
|
}
|
||||||
}).wait().unwrap()
|
}).map_err(|err| {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}).wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reject_transaction(signer: &mut SignerRpc,
|
fn reject_transaction(signer: &mut SignerRpc,
|
||||||
id: U256) -> Result<String, String> {
|
id: U256) -> Result<String, String> {
|
||||||
signer.reject_request(id).map(|res| {
|
try!(signer.reject_request(id).map(|res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(true) => Ok(format!("Rejected transaction id {:#x}", id)),
|
Ok(true) => Ok(format!("Rejected transaction id {:#x}", id)),
|
||||||
Ok(false) => Err(format!("No such request")),
|
Ok(false) => Err(format!("No such request")),
|
||||||
Err(e) => Err(format!("{:?}", e)),
|
Err(e) => Err(format!("{:?}", e)),
|
||||||
}
|
}
|
||||||
}).wait().unwrap()
|
}).map_err(|err| {
|
||||||
|
format!("{:?}", err)
|
||||||
|
}).wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmds
|
// cmds
|
||||||
|
|
||||||
pub fn cmd_signer_list(signerport: u16,
|
pub fn cmd_signer_list(signerport: u16,
|
||||||
authfile: PathBuf) -> Result<String, String> {
|
authfile: PathBuf) -> Result<String, String> {
|
||||||
match SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport),
|
let mut signer = try!(SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport), &authfile).map_err(|err| {
|
||||||
&authfile) {
|
format!("{:?}", err)
|
||||||
Ok(mut signer) => {
|
}));
|
||||||
list_transactions(&mut signer)
|
list_transactions(&mut signer)
|
||||||
}
|
}
|
||||||
Err(e) => Err(format!("{:?}", e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmd_signer_reject(id: usize,
|
pub fn cmd_signer_reject(id: Option<usize>, signerport: u16,
|
||||||
signerport: u16,
|
|
||||||
authfile: PathBuf) -> Result<String, String> {
|
authfile: PathBuf) -> Result<String, String> {
|
||||||
match SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport),
|
let id = try!(id.ok_or(format!("id required for signer reject")));
|
||||||
&authfile) {
|
let mut signer = try!(SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport), &authfile).map_err(|err| {
|
||||||
Ok(mut signer) => {
|
format!("{:?}", err)
|
||||||
|
}));
|
||||||
reject_transaction(&mut signer, U256::from(id))
|
reject_transaction(&mut signer, U256::from(id))
|
||||||
},
|
|
||||||
Err(e) => Err(format!("{:?}", e))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmd_signer_sign(id: Option<usize>,
|
pub fn cmd_signer_sign(id: Option<usize>,
|
||||||
pwfile: Option<PathBuf>,
|
pwfile: Option<PathBuf>,
|
||||||
signerport: u16,
|
signerport: u16,
|
||||||
authfile: PathBuf) -> Result<String, String> {
|
authfile: PathBuf) -> Result<String, String> {
|
||||||
let pwd;
|
let password;
|
||||||
match pwfile {
|
match pwfile {
|
||||||
Some(pwfile) => {
|
Some(pwfile) => {
|
||||||
match File::open(pwfile) {
|
match File::open(pwfile) {
|
||||||
Ok(fd) => {
|
Ok(fd) => {
|
||||||
match BufReader::new(fd).lines().next() {
|
match BufReader::new(fd).lines().next() {
|
||||||
Some(Ok(line)) => pwd = line,
|
Some(Ok(line)) => password = line,
|
||||||
_ => return Err(format!("No password in file"))
|
_ => return Err(format!("No password in file"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => return Err(format!("Could not open pwfile: {}", e))
|
Err(e) => return Err(format!("Could not open password file: {}", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
pwd = rpassword::prompt_password_stdout("Password: ").unwrap();
|
password = match rpassword::prompt_password_stdout("Password: ") {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => return Err(format!("{}", e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport),
|
let mut signer = try!(SignerRpc::new(&format!("ws://127.0.0.1:{}", signerport), &authfile).map_err(|err| {
|
||||||
&authfile) {
|
format!("{:?}", err)
|
||||||
Ok(mut signer) => {
|
}));
|
||||||
|
|
||||||
match id {
|
match id {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
sign_transaction(&mut signer, U256::from(id), &pwd)
|
sign_transaction(&mut signer, U256::from(id), &password)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
sign_transactions(&mut signer, pwd)
|
sign_transactions(&mut signer, password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => return Err(format!("{:?}", e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,6 +8,7 @@ version = "1.4.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
|
jsonrpc-core = "3.0.2"
|
||||||
lazy_static = "0.2.1"
|
lazy_static = "0.2.1"
|
||||||
matches = "0.1.2"
|
matches = "0.1.2"
|
||||||
rand = "0.3.14"
|
rand = "0.3.14"
|
||||||
@ -16,12 +17,6 @@ serde_json = "0.8"
|
|||||||
tempdir = "0.3.5"
|
tempdir = "0.3.5"
|
||||||
url = "1.2.0"
|
url = "1.2.0"
|
||||||
ws = "0.5.3"
|
ws = "0.5.3"
|
||||||
|
ethcore-rpc = { path = "../rpc" }
|
||||||
[dependencies.ethcore-rpc]
|
ethcore-signer = { path = "../signer" }
|
||||||
path = "../rpc"
|
ethcore-util = { path = "../util" }
|
||||||
|
|
||||||
[dependencies.ethcore-signer]
|
|
||||||
path = "../signer"
|
|
||||||
|
|
||||||
[dependencies.ethcore-util]
|
|
||||||
path = "../util"
|
|
||||||
|
@ -4,7 +4,6 @@ use std::sync::{Arc, Mutex};
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::mem;
|
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -12,7 +11,7 @@ use util::Hashable;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use ws::{connect,
|
use ws::{self,
|
||||||
Request,
|
Request,
|
||||||
Handler,
|
Handler,
|
||||||
Sender,
|
Sender,
|
||||||
@ -25,12 +24,12 @@ use ws::{connect,
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::ser::Serializer;
|
use serde::ser::Serializer;
|
||||||
use serde_json::{from_str,
|
use serde_json::{self as json,
|
||||||
to_string,
|
|
||||||
from_value,
|
|
||||||
Value as JsonValue,
|
Value as JsonValue,
|
||||||
Error as JsonError};
|
Error as JsonError};
|
||||||
|
|
||||||
|
//use jsonrpc_core::
|
||||||
|
|
||||||
use futures::{BoxFuture, Canceled, Complete, Future, oneshot, done};
|
use futures::{BoxFuture, Canceled, Complete, Future, oneshot, done};
|
||||||
|
|
||||||
/// The actual websocket connection handler, passed into the
|
/// The actual websocket connection handler, passed into the
|
||||||
@ -65,9 +64,12 @@ impl Handler for RpcHandler {
|
|||||||
fn build_request(&mut self, url: &Url) -> WsResult<Request> {
|
fn build_request(&mut self, url: &Url) -> WsResult<Request> {
|
||||||
match Request::from_url(url) {
|
match Request::from_url(url) {
|
||||||
Ok(mut r) => {
|
Ok(mut r) => {
|
||||||
let timestamp = time::UNIX_EPOCH.elapsed().unwrap().as_secs();
|
let timestamp = try!(time::UNIX_EPOCH.elapsed().map_err(|err| {
|
||||||
let hashed = format!("{}:{}", self.auth_code, timestamp).sha3();
|
WsError::new(WsErrorKind::Internal, format!("{}", err))
|
||||||
let proto = format!("{:?}_{}", hashed, timestamp);
|
}));
|
||||||
|
let secs = timestamp.as_secs();
|
||||||
|
let hashed = format!("{}:{}", self.auth_code, secs).sha3();
|
||||||
|
let proto = format!("{:?}_{}", hashed, secs);
|
||||||
r.add_protocol(&proto);
|
r.add_protocol(&proto);
|
||||||
Ok(r)
|
Ok(r)
|
||||||
},
|
},
|
||||||
@ -75,22 +77,25 @@ impl Handler for RpcHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn on_error(&mut self, err: WsError) {
|
fn on_error(&mut self, err: WsError) {
|
||||||
match mem::replace(&mut self.complete, None) {
|
match self.complete.take() {
|
||||||
Some(c) => c.complete(Err(RpcError::WsError(err))),
|
Some(c) => c.complete(Err(RpcError::WsError(err))),
|
||||||
None => println!("warning: unexpected error"),
|
None => println!("unexpected error: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn on_open(&mut self, _: Handshake) -> WsResult<()> {
|
fn on_open(&mut self, _: Handshake) -> WsResult<()> {
|
||||||
match mem::replace(&mut self.complete, None) {
|
match (self.complete.take(), self.out.take()) {
|
||||||
Some(c) => c.complete(Ok(Rpc {
|
(Some(c), Some(out)) => {
|
||||||
out: mem::replace(&mut self.out, None).unwrap(),
|
c.complete(Ok(Rpc {
|
||||||
|
out: out,
|
||||||
counter: AtomicUsize::new(0),
|
counter: AtomicUsize::new(0),
|
||||||
pending: self.pending.clone(),
|
pending: self.pending.clone(),
|
||||||
})),
|
}));
|
||||||
// Should not be reachable
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(WsError::new(WsErrorKind::Internal, format!("on_open called twice")))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn on_message(&mut self, msg: Message) -> WsResult<()> {
|
fn on_message(&mut self, msg: Message) -> WsResult<()> {
|
||||||
match parse_response(&msg.to_string()) {
|
match parse_response(&msg.to_string()) {
|
||||||
@ -153,16 +158,25 @@ impl Rpc {
|
|||||||
Err(e) => return done(Ok(Err(e))).boxed(),
|
Err(e) => return done(Ok(Err(e))).boxed(),
|
||||||
Ok(code) => {
|
Ok(code) => {
|
||||||
let url = String::from(url);
|
let url = String::from(url);
|
||||||
|
// The ws::connect takes a FnMut closure,
|
||||||
|
// which means c cannot be moved into it,
|
||||||
|
// since it's consumed on complete.
|
||||||
|
// Therefore we wrap it in an option
|
||||||
|
// and pick it out once.
|
||||||
|
let mut once = Some(c);
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
// mem:replace Option hack to move `c` out
|
let conn = ws::connect(url, |out| {
|
||||||
// of the FnMut closure
|
// this will panic if the closure
|
||||||
let mut swap = Some(c);
|
// is called twice, which it should never
|
||||||
match connect(url, |out| {
|
// be.
|
||||||
let c = mem::replace(&mut swap, None).unwrap();
|
let c = once.take().expect("connection closure called only once");
|
||||||
RpcHandler::new(out, code.clone(), c)
|
RpcHandler::new(out, code.clone(), c)
|
||||||
}) {
|
});
|
||||||
|
match conn {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let c = mem::replace(&mut swap, None).unwrap();
|
// since ws::connect is only called once, it cannot
|
||||||
|
// both fail and succeed.
|
||||||
|
let c = once.take().expect("connection closure called only once");
|
||||||
c.complete(Err(RpcError::WsError(err)));
|
c.complete(Err(RpcError::WsError(err)));
|
||||||
},
|
},
|
||||||
// c will complete on the `on_open` event in the Handler
|
// c will complete on the `on_open` event in the Handler
|
||||||
@ -183,13 +197,13 @@ impl Rpc {
|
|||||||
let id = self.counter.fetch_add(1, Ordering::Relaxed);
|
let id = self.counter.fetch_add(1, Ordering::Relaxed);
|
||||||
self.pending.insert(id, c);
|
self.pending.insert(id, c);
|
||||||
|
|
||||||
let serialized = to_string(&RpcRequest::new(id, method, params)).unwrap();
|
let serialized = json::to_string(&RpcRequest::new(id, method, params)).unwrap();
|
||||||
let _ = self.out.send(serialized);
|
let _ = self.out.send(serialized);
|
||||||
|
|
||||||
p.map(|result| {
|
p.map(|result| {
|
||||||
match result {
|
match result {
|
||||||
Ok(json) => {
|
Ok(json) => {
|
||||||
let t: T = try!(from_value(json));
|
let t: T = try!(json::from_value(json));
|
||||||
Ok(t)
|
Ok(t)
|
||||||
},
|
},
|
||||||
Err(err) => Err(err)
|
Err(err) => Err(err)
|
||||||
@ -281,7 +295,7 @@ impl From<Canceled> for RpcError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_response(s: &str) -> (Option<usize>, Result<JsonValue, RpcError>) {
|
fn parse_response(s: &str) -> (Option<usize>, Result<JsonValue, RpcError>) {
|
||||||
let mut json: JsonValue = match from_str(s) {
|
let mut json: JsonValue = match json::from_str(s) {
|
||||||
Err(e) => return (None, Err(RpcError::ParseError(e))),
|
Err(e) => return (None, Err(RpcError::ParseError(e))),
|
||||||
Ok(json) => json,
|
Ok(json) => json,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ extern crate serde;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
|
extern crate jsonrpc_core;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
@ -19,7 +20,7 @@ extern crate lazy_static;
|
|||||||
extern crate matches;
|
extern crate matches;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod tests {
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -29,46 +30,40 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_connection_refused() {
|
fn test_connection_refused() {
|
||||||
let (srv, port, tmpdir, _) = serve();
|
let (_srv, port, tmpdir, _) = serve();
|
||||||
|
|
||||||
let mut path = PathBuf::from(tmpdir.path());
|
let mut path = PathBuf::from(tmpdir.path());
|
||||||
path.push("authcodes");
|
path.push("authcodes");
|
||||||
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port - 1), &path);
|
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port - 1), &path);
|
||||||
|
|
||||||
connect.map(|conn| {
|
let _ = connect.map(|conn| {
|
||||||
assert!(matches!(&conn, &Err(RpcError::WsError(_))));
|
assert!(matches!(&conn, &Err(RpcError::WsError(_))));
|
||||||
}).wait();
|
}).wait();
|
||||||
|
|
||||||
drop(srv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_authcode_fail() {
|
fn test_authcode_fail() {
|
||||||
let (srv, port, _, _) = serve();
|
let (_srv, port, _, _) = serve();
|
||||||
let path = PathBuf::from("nonexist");
|
let path = PathBuf::from("nonexist");
|
||||||
|
|
||||||
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &path);
|
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &path);
|
||||||
|
|
||||||
connect.map(|conn| {
|
let _ = connect.map(|conn| {
|
||||||
assert!(matches!(&conn, &Err(RpcError::NoAuthCode)));
|
assert!(matches!(&conn, &Err(RpcError::NoAuthCode)));
|
||||||
}).wait();
|
}).wait();
|
||||||
|
|
||||||
drop(srv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_authcode_correct() {
|
fn test_authcode_correct() {
|
||||||
let (srv, port, tmpdir, _) = serve();
|
let (_srv, port, tmpdir, _) = serve();
|
||||||
|
|
||||||
let mut path = PathBuf::from(tmpdir.path());
|
let mut path = PathBuf::from(tmpdir.path());
|
||||||
path.push("authcodes");
|
path.push("authcodes");
|
||||||
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &path);
|
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &path);
|
||||||
|
|
||||||
connect.map(|conn| {
|
let _ = connect.map(|conn| {
|
||||||
assert!(conn.is_ok())
|
assert!(conn.is_ok())
|
||||||
}).wait();
|
}).wait();
|
||||||
|
|
||||||
drop(srv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
use client::{Rpc, RpcError};
|
use client::{Rpc, RpcError};
|
||||||
use rpc::v1::types::{ConfirmationRequest,
|
use rpc::v1::types::{ConfirmationRequest,
|
||||||
TransactionModification,
|
TransactionModification,
|
||||||
@ -13,16 +12,12 @@ pub struct SignerRpc {
|
|||||||
|
|
||||||
impl SignerRpc {
|
impl SignerRpc {
|
||||||
pub fn new(url: &str, authfile: &PathBuf) -> Result<Self, RpcError> {
|
pub fn new(url: &str, authfile: &PathBuf) -> Result<Self, RpcError> {
|
||||||
match Rpc::new(&url, authfile) {
|
Ok(SignerRpc { rpc: try!(Rpc::new(&url, authfile)) })
|
||||||
Ok(rpc) => Ok(SignerRpc { rpc: rpc }),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn requests_to_confirm(&mut self) ->
|
pub fn requests_to_confirm(&mut self) ->
|
||||||
BoxFuture<Result<Vec<ConfirmationRequest>, RpcError>, Canceled>
|
BoxFuture<Result<Vec<ConfirmationRequest>, RpcError>, Canceled>
|
||||||
{
|
{
|
||||||
self.rpc.request::<Vec<ConfirmationRequest>>
|
self.rpc.request("personal_requestsToConfirm", vec![])
|
||||||
("personal_requestsToConfirm", vec![])
|
|
||||||
}
|
}
|
||||||
pub fn confirm_request(&mut self,
|
pub fn confirm_request(&mut self,
|
||||||
id: U256,
|
id: U256,
|
||||||
@ -30,7 +25,7 @@ impl SignerRpc {
|
|||||||
pwd: &str) ->
|
pwd: &str) ->
|
||||||
BoxFuture<Result<U256, RpcError>, Canceled>
|
BoxFuture<Result<U256, RpcError>, Canceled>
|
||||||
{
|
{
|
||||||
self.rpc.request::<U256>("personal_confirmRequest", vec![
|
self.rpc.request("personal_confirmRequest", vec![
|
||||||
to_value(&format!("{:#x}", id)),
|
to_value(&format!("{:#x}", id)),
|
||||||
to_value(&TransactionModification { gas_price: new_gas_price }),
|
to_value(&TransactionModification { gas_price: new_gas_price }),
|
||||||
to_value(&pwd),
|
to_value(&pwd),
|
||||||
@ -39,7 +34,7 @@ impl SignerRpc {
|
|||||||
pub fn reject_request(&mut self, id: U256) ->
|
pub fn reject_request(&mut self, id: U256) ->
|
||||||
BoxFuture<Result<bool, RpcError>, Canceled>
|
BoxFuture<Result<bool, RpcError>, Canceled>
|
||||||
{
|
{
|
||||||
self.rpc.request::<bool>("personal_rejectRequest", vec![
|
self.rpc.request("personal_rejectRequest", vec![
|
||||||
JsonValue::String(format!("{:#x}", id))
|
JsonValue::String(format!("{:#x}", id))
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user