rust jsonrpc-core decouple anounymous function from add_method - rust

I am writing rpc server with rust using jsonrpc-core and jsonrpc-http-server.
Here is my code:
let mut io = IoHandler::new();
io.add_method("validate_public_key", |params: Params| {
let map: HashMap<String, Value> = params.parse().unwrap();
println!("Params : {:?}", map);
let public_key = map.get("public_key").unwrap().as_str().unwrap();
println!("Public Key : {:?}", public_key);
Ok(Value::String(public_key.to_string()))
});
let server = ServerBuilder::new(io)
.start_http(&rpc_address.parse().unwrap())
.unwrap();
How do I remove the anonymous function from add_method? I want to write this method in sperate file and use it here as io.add_method("validate_public_key", |params: Params| validate);
Here is what I tried so far:
pub fn validate(params: Params) -> Result<Value> {
let map: Map<String, Value> = params.parse().unwrap();
println!("Params : {:?}", map);
let public_key = map.get("public_key").unwrap().as_str().unwrap();
println!("Public Key : {:?}", public_key);
Ok(Value::String(public_key.to_string()))
}
It give following error:
error[E0277]: the trait bound `fn(jsonrpc_core::types::params::Params)
-> std::result::Result<serde_json::Value, jsonrpc_core::types::error::Error> {app::rpc::validate_public_key}:
futures::future::Future` is not satisfied --> src/main.rs:37:12
|
37 | io.add_method("validate_public_key", |params: Params| validate_public_key);
| ^^^^^^^^^^ the trait `futures::future::Future` is not implemented for `fn(jsonrpc_core::types::params::Params) -> std::result::Result<serde_json::Value, jsonrpc_core::types::error::Error {app::rpc::validate_public_key}`
|
= note: required because of the requirements on the impl of `jsonrpc_core::calls::RpcMethodSimple` for `[closure#src/main.rs:37:46: 37:82]`
What am I doing wrong?

I just used io.add_method("validate_public_key", validate); instead of io.add_method("validate_public_key", |params: Params| validate);. It's working fine.
Saw the solution in the comment section but it's removed by user now.

Related

What signature can I use to download files using Axum and Tokio?

I'm using axum and this code (found here) to download files:
use axum::{
body::StreamBody,
http::{header, StatusCode},
response::{Headers, IntoResponse},
routing::get,
Router,
};
use std::net::SocketAddr;
use tokio_util::io::ReaderStream;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> impl IntoResponse {
// `File` implements `AsyncRead`
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
// convert the `AsyncRead` into a `Stream`
let stream = ReaderStream::new(file);
// convert the `Stream` into an `axum::body::HttpBody`
let body = StreamBody::new(stream);
let headers = Headers([
(header::CONTENT_TYPE, "text/toml; charset=utf-8"),
]);
Ok((headers, body))
}
Everything works. But I cannot find a way to move the below code in a separate function:
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
I would like to use both tokio::fs::File and https://crates.io/crates/rust-s3 methods in this function.
So I need a "common type" which appear to be AsyncRead, I think.
What should be the signature of the function?
I tried with:
use tokio::io::AsyncRead;
pub struct Player {
db: Arc<DB>
}
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<&(dyn AsyncRead)> {
//...use id here...
let file = &tokio::fs::File::open("player.pdf").await?;
Ok(file)
}
}
but I get the error:
error[E0308]: mismatched types
|
55 | Ok(file)
| -- ^^^^
| | |
| | expected reference, found struct `tokio::fs::File`
| | help: consider borrowing here: `&file`
| arguments to this enum variant are incorrect
|
= note: expected reference `&dyn tokio::io::AsyncRead`
found struct `tokio::fs::File`
I tried with: let file = &tokio::fs::File::open("player.pdf").await?; and I got:
error[E0515]: cannot return value referencing temporary value
|
43 | let file = &tokio::fs::File::open(...
| --------------------------- temporary value created here
...
55 | Ok(file)
| ^^^^^^^^ returns a value referencing data owned by the current function
What can I use?
Returning a generic "boxed" value might be the solution here:
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<Box<dyn AsyncRead>> {
//...use id here...
Ok(Box::new(tokio::fs::File::open("player.pdf").await?))
}
}
Where now there's no dangling reference, it's encapsulated and fully owned.

Blanket implementation for `der::asn1::SetOfVec` not recognized by compiler?

I want to DER encode a nested data structure using the der crate of the RustCrypto project. I have a Vec of SetOfVecs. There should be a blanket implementation of der::Encode for SetOfVec, but the compiler does not recognize it:
// Add this to Cargo.toml:
// ...
// [dependencies]
// der = { version = "0.6", features = ["alloc", "oid"]}
// main.rs:
use der::{DecodeValue, Encode, Header, Reader, Sequence};
use der::asn1::{ObjectIdentifier, SetOfVec};
struct NestedType(Vec<SetOfVec<ObjectIdentifier>>);
impl<'a> DecodeValue<'a> for NestedType {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
Ok(reader.decode()?)
}
}
impl<'a> Sequence<'a> for NestedType {
fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
where
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
{
// This works
// (the following 3 lines are just for comparison with the failing case)
let encoder1 = SetOfVec::<ObjectIdentifier>::new();
let encoder2 = SetOfVec::<ObjectIdentifier>::new();
field_encoder(&[&encoder1, &encoder2])?;
// This doesn't work
let mut refs: Vec<&SetOfVec<ObjectIdentifier>> = Vec::new();
for rdn in self.0.iter() {
refs.push(rdn);
}
field_encoder(refs.as_slice())
}
}
fn main() {}
The compiler error:
error[E0308]: mismatched types
--> src\main.rs:33:23
|
33 | field_encoder(refs.as_slice())
| ^^^^^^^^^^^^^^^ expected trait object `dyn Encode`, found struct `SetOfVec`
|
= note: expected reference `&[&dyn Encode]`
found reference `&[&SetOfVec<der::asn1::ObjectIdentifier>]`
As the Encode trait is implemented for SetOfVec, there should be no error. What's the problem here?
Looks like the compiler needs more info. The following code creates a Vec<&dyn Encode> with the references pointing to the SetOfVecs in the original Vec. This should also solve the memory allocation issue, that #Chayim Friedman mentioned (please correct me, if I'm wrong):
impl<'a> Sequence<'a> for NestedType {
fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
where
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
{
let mut refs: Vec<&dyn Encode> = Vec::new();
for rdn in self.0.iter() {
refs.push(rdn);
}
field_encoder(refs.as_slice())
}
}

Warp: single route works, multiple with .or() do not

Hoping someone can help me understand why running warp with a single route like this compiles fine:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// GET /stats
let stats = warp::get()
.and(warp::path("stats"))
.map(|| {
let mut sys = System::new_all();
sys.refresh_all();
let local = LocalSystem::from_sys(&sys);
warp::reply::json(&local);
});
// GET /
let index = warp::get()
.and(warp::path::end())
.map(|| warp::reply::json(&last_ten_logs()));
warp::serve(index).run(([127, 0, 0, 1], 4000)).await;
Ok(())
}
But changing the warp::serve() line to serve two routes like in the examples in the repo causes a compilation error:
error[E0277]: the trait bound `(): Reply` is not satisfied
--> src/main.rs:140:17
|
140 | warp::serve(stats.or(index)).run(([127, 0, 0, 1], 4000)).await;
| ----------- ^^^^^^^^^^^^^^^ the trait `Reply` is not implemented for `()`
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `Reply` for `((),)`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `Reply` for `(warp::generic::Either<((),), (Json,)>,)`
I don't understand what the compiler is asking me to change.
The error is explicit:
the trait Reply is not implemented for ()
The problem is that your stats endpoint do not return anything, just remove the last ; so it gets returned as the last expresion in the closure:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// GET /stats
let stats = warp::get()
.and(warp::path("stats"))
.map(|| {
let mut sys = System::new_all();
sys.refresh_all();
let local = LocalSystem::from_sys(&sys);
warp::reply::json(&local)
});
...
}

mismatched String type in Rust

I'm currently trying to learn Rust, and when I was trying to follow the official book tutorial I have encountered an error that was not described in the book.
use std::env;
use std::fs;
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args);
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
println!("{:?}", args);
let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file");
println!("With text:\n{}", contents);
}
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Config {
let query = &args[1].clone();
let filename = &args[2].clone();
Config { query, filename }
}
}
but I kept getting the following error from the compiler:
error[E0308]: mismatched types
--> src/main.rs:25:18
|
25 | Config { query, filename }
| ^^^^^
| |
| expected struct `std::string::String`, found `&str`
| help: try using a conversion method: `query: query.to_string()`
error[E0308]: mismatched types
--> src/main.rs:25:25
|
25 | Config { query, filename }
| ^^^^^^^^
| |
| expected struct `std::string::String`, found `&std::string::String`
| help: try using a conversion method: `filename: filename.to_string()`
error: aborting due to 2 previous errors
I have tried doing something like:
let query = &args[1].clone().to_string();
let filename = &args[2].clone().to_owned().to_string();
but it brought the same error. Finally, I have managed to solve this issue by applying the following changes:
struct Config<'a> {
query: &'a str,
filename: &'a str,
}
impl Config <'_> {
fn new(args: &[String]) -> Config {
let query = &*args[1];
let filename = &*args[2];
Config { query, filename }
}
}
My understanding is that new() could not return a struct of owned strings because values query and filename were assigned referenced values and for some reason, neither of the functions to_string(), to_owned() and clone() were not converting a referenced Sting into an owned one.
Does anyone know why I had to use referenced sices with lifetimes instead of strings?
Also, is there a way to use String type just like in the tutorial(https://doc.rust-lang.org/book/ch12-03-improving-error-handling-and-modularity.html)?
the query and file name type is &String, the clone method use &self, You should do like this
impl Config {
fn new(args: &[String]) -> Config {
let query = args[1].clone();
let filename = args[2].clone();
Config { query, filename }
}
}

How to use wirefilter over an infinite stream of data

I am writing a program to use wirefilter in order to filter data from an infinite stream.
But it seems that I cannot use a compiled ast in a loop because of lifetimes and when I try to compile, this is the output:
error: borrowed data cannot be stored outside of its closure
--> src/main.rs:34:33
|
31 | let filter = ast.compile();
| ------ ...so that variable is valid at time of its declaration
32 |
33 | for my_struct in data.filter(|my_struct| {
| ----------- borrowed data cannot outlive this closure
34 | let execution_context = my_struct.execution_context();
| ^^^^^^^^^ ----------------- cannot infer an appropriate lifetime...
| |
| cannot be stored outside of its closure
error: aborting due to previous error
error: Could not compile `wirefilter_playground`.
To learn more, run the command again with --verbose.
main.rs
use wirefilter::{ExecutionContext, Scheme};
lazy_static::lazy_static! {
static ref SCHEME: Scheme = Scheme! {
port: Int
};
}
#[derive(Debug)]
struct MyStruct {
port: i32,
}
impl MyStruct {
fn scheme() -> &'static Scheme {
&SCHEME
}
fn execution_context(&self) -> ExecutionContext {
let mut ctx = ExecutionContext::new(Self::scheme());
ctx.set_field_value("port", self.port).unwrap();
ctx
}
}
fn main() -> Result<(), failure::Error> {
let data = expensive_data_iterator();
let scheme = MyStruct::scheme();
let ast = scheme.parse("port in {2 5}")?;
let filter = ast.compile();
for my_struct in data.filter(|my_struct| {
let execution_context = my_struct.execution_context();
filter.execute(&execution_context).unwrap()
}).take(10) {
println!("{:?}", my_struct);
}
Ok(())
}
fn expensive_data_iterator() -> impl Iterator<Item=MyStruct> {
(0..).map(|port| MyStruct { port })
}
Cargo.toml
[package]
name = "wirefilter_playground"
version = "0.1.0"
edition = "2018"
[dependencies]
wirefilter-engine = "0.6.1"
failure = "0.1.5"
lazy_static = "1.3.0"
is it possible to make it work? I would like to yield only the filtered data for the final user otherwise the amount of data would be huge in memory.
Thank you in advance!
It looks like the problem is with the lifetime elision in return structs. In particular this code:
fn execution_context(&self) -> ExecutionContext {
//...
}
is equivalent to this one:
fn execution_context<'s>(&'s self) -> ExecutionContext<'s> {
//...
}
Which becomes obvious once you realize that ExecutionContext has an associated lifetime.
The lifetime of ExecutionContext does not have to match that of the MyStruct so you probably want to write:
fn execution_context<'e>(&self) -> ExecutionContext<'e> {
//...
}
or maybe:
fn execution_context<'s, 'e>(&'s self) -> ExecutionContext<'e>
where 'e: 's {
//...
}
depending on whether your context will eventually refer to any content of MyStruct.

Resources