> {
self.session.clone()
}
}
/// Implementation of whisper RPC.
pub struct WhisperClient {
store: Arc>,
pool: P,
filter_manager: Arc,
_meta: ::std::marker::PhantomData,
}
impl WhisperClient
{
/// Create a new whisper client with basic metadata.
pub fn with_simple_meta(pool: P, filter_manager: Arc) -> Self {
WhisperClient::new(pool, filter_manager)
}
}
impl WhisperClient
{
/// Create a new whisper client.
pub fn new(pool: P, filter_manager: Arc) -> Self {
WhisperClient {
store: filter_manager.key_store(),
pool: pool,
filter_manager: filter_manager,
_meta: ::std::marker::PhantomData,
}
}
fn delete_filter_kind(&self, id: H256, kind: filter::Kind) -> bool {
match self.filter_manager.kind(&id) {
Some(k) if k == kind => {
self.filter_manager.remove(&id);
true
}
None | Some(_) => false,
}
}
}
impl Whisper for WhisperClient {
fn info(&self) -> Result {
let status = self.pool.pool_status();
Ok(types::NodeInfo {
required_pow: status.required_pow,
messages: status.message_count,
memory: status.cumulative_size,
target_memory: status.target_size,
})
}
fn new_key_pair(&self) -> Result {
let mut store = self.store.write();
let key_pair = Key::new_asymmetric(store.rng());
Ok(HexEncode(store.insert(key_pair)))
}
fn add_private_key(&self, private: types::Private) -> Result {
let key_pair = Key::from_secret(private.into_inner().into())
.ok_or_else(|| whisper_error("Invalid private key"))?;
Ok(HexEncode(self.store.write().insert(key_pair)))
}
fn new_sym_key(&self) -> Result {
let mut store = self.store.write();
let key = Key::new_symmetric(store.rng());
Ok(HexEncode(store.insert(key)))
}
fn add_sym_key(&self, raw_key: types::Symmetric) -> Result {
let raw_key = raw_key.into_inner().0;
let key = Key::from_raw_symmetric(raw_key);
Ok(HexEncode(self.store.write().insert(key)))
}
fn get_public(&self, id: types::Identity) -> Result {
self.store.read().public(&id.into_inner())
.cloned()
.map(HexEncode)
.ok_or_else(|| whisper_error("Unknown identity"))
}
fn get_private(&self, id: types::Identity) -> Result {
self.store.read().secret(&id.into_inner())
.map(|x| (&**x).clone())
.map(HexEncode)
.ok_or_else(|| whisper_error("Unknown identity"))
}
fn get_symmetric(&self, id: types::Identity) -> Result {
self.store.read().symmetric(&id.into_inner())
.cloned()
.map(H256)
.map(HexEncode)
.ok_or_else(|| whisper_error("Unknown identity"))
}
fn remove_key(&self, id: types::Identity) -> Result {
Ok(self.store.write().remove(&id.into_inner()))
}
fn post(&self, req: types::PostRequest) -> Result {
use self::crypto::EncryptionInstance;
let encryption = match req.to {
Some(types::Receiver::Public(public)) => EncryptionInstance::ecies(public.into_inner())
.map_err(whisper_error)?,
Some(types::Receiver::Identity(id)) => self.store.read().encryption_instance(&id.into_inner())
.map_err(whisper_error)?,
None => {
use rand::{Rng, OsRng};
// broadcast mode: use fixed nonce and fresh key each time.
let mut rng = OsRng::new()
.map_err(|_| whisper_error("unable to acquire secure randomness"))?;
let key = Memzero::from(rng.gen::<[u8; 32]>());
if req.topics.is_empty() {
return Err(whisper_error("must supply at least one topic for broadcast message"));
}
EncryptionInstance::broadcast(
key,
req.topics.iter().map(|x| topic_hash(&x)).collect()
)
}
};
let sign_with = match req.from {
Some(from) => {
Some(
self.store.read().secret(&from.into_inner())
.cloned()
.ok_or_else(|| whisper_error("Unknown identity `from`"))?
)
}
None => None,
};
let encrypted = {
let payload = payload::encode(payload::EncodeParams {
message: &req.payload.into_inner(),
padding: req.padding.map(|p| p.into_inner()).as_ref().map(|x| &x[..]),
sign_with: sign_with.as_ref(),
}).map_err(whisper_error)?;
encryption.encrypt(&payload).ok_or(whisper_error("encryption error"))?
};
// mining the packet is the heaviest item of work by far.
// there may be a benefit to dispatching this onto the CPU pool
// and returning a future. but then things get _less_ efficient
// if the server infrastructure has more threads than the CPU pool.
let message = Message::create(CreateParams {
ttl: req.ttl,
payload: encrypted,
topics: req.topics.into_iter().map(|x| abridge_topic(&x.into_inner())).collect(),
work: req.priority,
}).map_err(|_| whisper_error("Empty topics"))?;
if !self.pool.relay(message) {
Err(whisper_error("PoW too low to compete with other messages"))
} else {
Ok(true)
}
}
fn new_filter(&self, req: types::FilterRequest) -> Result {
let filter = Filter::new(req).map_err(whisper_error)?;
self.filter_manager.insert_polled(filter)
.map(HexEncode)
.map_err(whisper_error)
}
fn poll_changes(&self, id: types::Identity) -> Result, Error> {
match self.filter_manager.poll_changes(&id.into_inner()) {
None => Err(whisper_error("no such message filter")),
Some(items) => Ok(items),
}
}
fn delete_filter(&self, id: types::Identity) -> Result {
Ok(self.delete_filter_kind(id.into_inner(), filter::Kind::Poll))
}
}
impl WhisperPubSub for WhisperClient {
type Metadata = M;
fn subscribe(
&self,
_meta: Self::Metadata,
subscriber: Subscriber,
req: types::FilterRequest,
) {
match Filter::new(req) {
Ok(filter) => {
if let Err(e) = self.filter_manager.insert_subscription(filter, subscriber) {
debug!(target: "whisper", "Failed to add subscription: {}", e);
}
}
Err(reason) => { let _ = subscriber.reject(whisper_error(reason)); }
}
}
fn unsubscribe(&self, _: Option, id: SubscriptionId) -> Result {
use std::str::FromStr;
let res = match id {
SubscriptionId::String(s) => H256::from_str(&s)
.map_err(|_| "unrecognized ID")
.map(|id| self.delete_filter_kind(id, filter::Kind::Subscription)),
SubscriptionId::Number(_) => Err("unrecognized ID"),
};
res.map_err(whisper_error)
}
}