UdpFramed with Actix Rust. Can't send messages using SinkWrite - sockets

I'm trying to write a Udp Client Actor using Actix. I've followed this example, UDP-Echo, but I can't seem to send a message to the server using the UdpFramed tokio struct.
Here's what I have so far, this is the Udp Client Actor implementation
use std::collections::HashMap;
use std::net::{SocketAddr};
use actix_rt::net::UdpSocket;
use actix::{Actor, Addr, AsyncContext, Context, Handler, StreamHandler, Message};
use actix::io::SinkWrite;
use actix_web::web::{Bytes, BytesMut};
use futures_util::stream::{SplitSink};
use futures_util::StreamExt;
use log::info;
use serde_json::Value;
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
use crate::rosclient::messages::Subscribe;
use std::io::Result;
mod messages;
type SinkItem = (Bytes, SocketAddr);
type UdpSink = SplitSink<UdpFramed<BytesCodec, UdpSocket>, SinkItem>;
pub struct UdpClientActor {
pub address: SocketAddr,
pub sink: SinkWrite<SinkItem, UdpSink>,
}
impl UdpClientActor {
pub fn start(udp: UdpSocket, address: SocketAddr) -> Addr<UdpClientActor> {
let framed = UdpFramed::new(udp, BytesCodec::new());
let (split_sink, split_stream) = framed.split();
UdpClientActor::create(|ctx| {
ctx.add_stream(split_stream.filter_map(
|item: Result<(BytesMut, SocketAddr)>| async {
item.map(|(data, sender)| UdpPacket(data, sender)).ok()
},
));
UdpClientActor {
address,
sink: SinkWrite::new(split_sink, ctx),
}
})
}
}
impl Actor for UdpClientActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
let mut hashmap = HashMap::new();
hashmap.insert(String::from("topic"), Value::String(String::from("/client_count")));
let subscription = Subscribe {
id: Default::default(),
op: "subscribe".to_string(),
extra: hashmap
};
ctx.notify(subscription);
}
}
#[derive(Message)]
#[rtype(result = "()")]
struct UdpPacket(BytesMut, SocketAddr);
impl StreamHandler<UdpPacket> for
UdpClientActor {
fn handle(&mut self, item: UdpPacket, _ctx: &mut Self::Context) {
println!("Received: ({:?}, {:?})", item.0, item.1);
self.sink.write((item.0.into(), item.1)).unwrap();
}
}
impl actix::io::WriteHandler<std::io::Error> for UdpClientActor {}
impl Handler<Subscribe> for UdpClientActor {
type Result = ();
fn handle(&mut self, msg: Subscribe, _ctx: &mut Self::Context) -> Self::Result {
let js = serde_json::json!(msg).to_string();
let _ = self.sink.write((Bytes::from(msg.to_string()), self.address));
info!("Subscribing to topic {}", js);
}
}
My main function creates the udp socket and spawns the actor.
fn main() {
////////////////////////////////////////////////////////////////////////////
let fut = async {
////////////////////////////////////////////////////////////////////////////
/////////// UDP_ACTOR
let sock = tokio::net::UdpSocket::bind("0.0.0.0:9091").await.unwrap();
let remote_addr = "172.30.89.169:9091".parse::<SocketAddr>().unwrap();
// let message = b"{ \"op\": \"subscribe\", \"topic\": \"/client_count\"}";
let _ = sock.connect(remote_addr).await;
// sock.send(message).await.unwrap();
let _udp_client = UdpClientActor::start(sock, remote_addr);
};
actix_rt::Arbiter::new().spawn(fut);
// system.block_on(fut);
system.run().unwrap();
}
If I remove the comments on
let message = b"{ \"op\": \"subscribe\", \"topic\": \"/client_count\"}";
and
sock.send(message).await.unwrap();
I can at least check that the server can actually receive messages. So I know that the problem must lie in my implementation of the actor. I do have another one which uses the LinesCodec instead of the BytesCodec, which follows the exact same implementation. Only difference is that SinkWrite becomes this:
SinkWrite<(String, SocketAddr), SplitSink<UdpFramed<codec::LinesCodec>,
(String, SocketAddr)>>
Here is my Cargo.toml for reference.
[package]
name = "local_websocket_client"
version = "0.1.0"
edition = "2018"
[dependencies]
actix="0.12"
actix-codec = "0.4"
actix-rt = "2.5"
bytestring = "1.0"
serde = {version="1.0", features=["serde_derive"]}
log = "0.4"
env_logger = "0.9.0"
chrono = "0.4"
dashmap = "4.0"
futures = "0.3"
openssl = "0.10"
tokio = { version = "1", features = ["full"] }
actix-web = "4.0.0-beta.15"
futures-util = "0.3"
tokio-util = { version="0.6", features=["net", "codec"] }
tokio-udp = "0.1.6"
bytes= { version="0.6", features=["serde"] }
[dependencies.awc]
features = ["openssl"]
version = "3.0.0-beta.9"
[dependencies.serde_json]
features = ["default"]
version = "1.0"
[dependencies.uuid]
features = ["v4", "serde", "v5"]
version = "0.8"
There are some extra crates there because I'm running 2 other websocket clients on the same application.
I would really appreciate some help on this matter.
Thank you

Solved it by wrapping the UdpSocket in an Arc and keeping the reference in the actor for later use. Using the socket to write messages works. The split stream used for the streamhandler needs no change, as it works as expected.

Related

How to access database connection from a Rocket's fairing?

I'm trying to use database connection from a Rocket's on_ignite fairing:
use sqlx::{ self, FromRow };
use rocket::fairing::{self, Fairing, Info, Kind};
use rocket::{Build, Rocket};
use crate::database::PostgresDb;
#[derive(FromRow)]
struct TableRow {
column_a: String,
column_b: String
}
#[rocket::async_trait]
impl Fairing for TableRow {
fn info(&self) -> Info {
Info {
name: "Cache table row",
kind: Kind::Ignite,
}
}
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
let mut db = rocket
.state::<Connection<PostgresDb>>()
.expect("Unable to find db connection.");
let row = sqlx::query_as::<_, TableRow>("SELECT * FROM table WHERE id = 1;")
.fetch_one(&mut db)
.await
.unwrap();
fairing::Result::Ok(rocket.manage(row))
}
}
The problem is I get following rust error during .fetch_one(&mut db):
the trait bound `&mut rocket_db_pools::Connection<PostgresDb>: Executor<'_>` is not satisfied
the following other types implement trait `Executor<'c>`:
<&'c mut PgConnection as Executor<'c>>
<&'c mut PgListener as Executor<'c>>
<&'c mut PoolConnection<Postgres> as Executor<'c>>
<&'t mut Transaction<'c, Postgres> as Executor<'t>>
<&sqlx::Pool<DB> as Executor<'p>>rustcClick for full compiler diagnostic
cache_rbac_on_ignite.rs(56, 14): required by a bound introduced by this call
query_as.rs(132, 17): required by a bound in `QueryAs::<'q, DB, O, A>::fetch_all`
I tried solution suggested here: How to get the database Connection in rocket.rs Fairing. but it did not work out.
Here is the code:
use sqlx::{ self, FromRow, Database };
use rocket::fairing::{self, Fairing, Info, Kind};
use rocket::{Build, Rocket};
use crate::database::PostgresDb;
#[derive(FromRow)]
struct TableRow {
column_a: String,
column_b: String
}
#[rocket::async_trait]
impl Fairing for TableRow {
fn info(&self) -> Info {
Info {
name: "Cache table row",
kind: Kind::Ignite,
}
}
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
let mut db = PostgresDb::get_one(rocket).await.unwrap();
let row = sqlx::query_as::<_, TableRow>("SELECT * FROM table WHERE id = 1;")
.fetch_one(&mut db)
.await
.unwrap();
fairing::Result::Ok(rocket.manage(row))
}
}
I get following rust error on line let mut db = PostgresDb::get_one(rocket).await.unwrap();:
no function or associated item named `get_one` found for struct `PostgresDb` in the current scope
function or associated item not found in `PostgresDb`rustcClick for full compiler diagnostic
mod.rs(8, 1): function or associated item `get_one` not found for this struct
What is the right way to use database connection inside of the fairing? Thank you!
Finally found an answer. Here is what worked for me:
use rocket::fairing::{self, Fairing, Info, Kind};
use rocket::{Build, Rocket};
use rocket_db_pools::{ sqlx::{ self, FromRow }, Database };
use crate::database::PostgresDb;
#[derive(FromRow)]
struct TableRow {
column_a: String,
column_b: String
}
#[rocket::async_trait]
impl Fairing for TableRow {
fn info(&self) -> Info {
Info {
name: "Cache table row",
kind: Kind::Ignite,
}
}
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
let db = PostgresDb::fetch(&rocket).unwrap();
let mut conn = db.aquire().await.unwrap();
let row = sqlx::query_as::<_, TableRow>("SELECT * FROM table WHERE id = 1;")
.fetch_one(&mut conn)
.await
.unwrap();
fairing::Result::Ok(rocket.manage(row))
}
}

the trait `LoadConnection` is not implemented for `&diesel::PgConnection`

I want to create a rest api with rust and can't make it work.
My relevant code so far:
In the main.rs:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Loading .env into environment variable.
dotenv::dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
// set up database connection pool
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL");
let manager = ConnectionManager::<PgConnection>::new(database_url);
let pool: DbPool = r2d2::Pool::builder()
.test_on_check_out(true)
.build(manager)
.expect("Could not build connection pool");
let port = std::env::var("PORT").expect("$PORT is not set.");
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(pool.clone()))
.wrap(middleware::Logger::default())
.route("/", web::get().to(|| async { "Actix REST API" }))
.service(handlers::common::houses::index)
})
.bind(("0.0.0.0", port.parse().unwrap()))?
.run()
.await
}
The schema:
diesel::table! {
houses (id) {
id -> Int4,
user_id -> Varchar,
street -> Varchar,
figure -> Varchar,
floor -> Varchar,
create_date -> Timestamp,
update_date -> Timestamp,
is_deleted -> Bool,
}
}
The model:
#[derive(Debug, Serialize, Deserialize, Queryable)]
pub struct House {
pub id: i32,
pub user_id: String,
pub street: String,
pub figure: String,
pub floor: String,
pub create_date: chrono::NaiveDateTime,
pub update_date: chrono::NaiveDateTime,
pub is_deleted: bool,
}
The handler:
#[get("/houses")]
async fn index(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
let houses = web::block(move || {
let conn = &pool.get()?;
find_all(&conn)
})
.await?
.map_err(actix_web::error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(houses))
}
fn find_all(conn: &PgConnection) -> Result<Vec<House>, DbError> {
use crate::schemas::common::houses::houses::dsl::*;
let items =houses.load::<House>(&mut conn)?;
Ok(items)
}
The dependencies are:
[dependencies]
actix-web = "4"
chrono = { version = "0.4.19", features = ["serde"] }
diesel = { version = "2.0.3", features = ["postgres", "r2d2", "chrono"] }
dotenv = "0.15.0"
env_logger = "0.10.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0"`
It keeps giving an error, and I don't understand why.
The error is:
`error[E0277]: the trait bound `&diesel::PgConnection: LoadConnection` is not satisfied src\handlers\common\houses.rs:25:37
| 25 | let items =houses.load::<House>(&mut conn)?;
| ---- -^^^^^^^^
| | | the trait `LoadConnection` is not implemented for `&diesel::PgConnection` help: consider removing the leading `&`-reference required by a bound introduced by this call
| note: required for `table` to implement `LoadQuery<'_, &diesel::PgConnection, House>` note: required by a bound in `diesel::RunQueryDsl::load`
I've seen a similar error with the diesel version 1.4, but I think that this version is different.
Plus I'm starting with rust and I'm a little lost in general at the moment.
I was hopping someone knows what the problem is and how to fix it.
PgConnection implements LoadConnection but &PgConnection does not (note the extra &).
Make conn mutable and pass as a mutable reference:
#[get("/houses")]
async fn index(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
let houses = web::block(move || {
let mut conn = pool.get()?; // <------------
find_all(&mut conn) // <------------
})
.await?
.map_err(actix_web::error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(houses))
}
fn find_all(conn: &mut PgConnection) -> Result<Vec<House>, DbError> {
// ^^^ <------------
use crate::schemas::common::houses::houses::dsl::*;
let items = houses.load::<House>(conn)?; // <------------
Ok(items)
}

kube-rs: Store.state() returns nothing

I'm having some trouble with pulling the state of my custom resources through a reflector.
let ns = env::var("NAMESPACE").expect("Need NAMESPACE evar");
let fancy_cr: Api<FancyStruct> = Api::namespaced(client.clone(), &ns);
let (fancy_store, writer) = reflector::store::<FancyStruct>();
let lp = ListParams::default().timeout(20);
// I do see resources' name properly printed
for r in fancy_cr.list(&ListParams::default().timeout(20)).await? {
println!("Found resource: {}", r.name());
}
let rf = reflector(writer, watcher(manifests_cr, lp));
# Will print: "State: []" -> This is empty
println!("State: {:?}", fancy_store.state());
With the snippet above, I can list my custom resources (I can print their name). However calling state() doesn't return anything, so I can't continuously watch the state of my resources.
These are the versions of the dependencies I use (the latest versions as of today):
kube = { version = "0.76.0", features=["rustls-tls", "runtime"], default-features = false}
k8s-openapi = { version = "0.16.0", features = ["v1_25"] }
Would you mind helping me figuring that out please?

How to include a json-rpc in the pow consensus building on Substrate?

In the pow consensus module of substrate, the miner does not dig ore by means of RPC access, how to access?
I don't have idea.
fn mine(
&self,
parent: &BlockId<B>,
pre_hash: &H256,
difficulty: Difficulty,
round: u32,
) -> Result<Option<RawSeal>, String> {
let mut rng = SmallRng::from_rng(&mut thread_rng())
.map_err(|e| format!("Initialize RNG failed for mining: {:?}", e))?;
let key_hash = key_hash(self.client.as_ref(), parent)?;
for _ in 0..round {
let nonce = H256::random_using(&mut rng);
let compute = Compute {
key_hash,
difficulty,
pre_hash: *pre_hash,
nonce,
};
let seal = compute.compute();
if is_valid_hash(&seal.work, difficulty) {
return Ok(Some(seal.encode()))
}
}
Ok(None)
}
I suggest you follow a pattern similar to Kulupu for creating a PoW Substrate blockchain.
In Kulupu, it seems the Substrate service starts mining if it detects your are an "authority":
/// Builds a new service for a full client.
pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>, author: Option<&str>, threads: usize, round: u32)
-> Result<impl AbstractService, ServiceError>
{
let is_authority = config.roles.is_authority();
let (builder, inherent_data_providers) = new_full_start!(config, author);
let service = builder
.with_network_protocol(|_| Ok(NodeProtocol::new()))?
.with_finality_proof_provider(|_client, _backend| {
Ok(Arc::new(()) as _)
})?
.build()?;
if is_authority {
for _ in 0..threads {
let proposer = basic_authorship::ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
};
consensus_pow::start_mine(
Box::new(service.client().clone()),
service.client(),
kulupu_pow::RandomXAlgorithm::new(service.client()),
proposer,
None,
round,
service.network(),
std::time::Duration::new(2, 0),
service.select_chain().map(|v| v.clone()),
inherent_data_providers.clone(),
);
}
}
Ok(service)
}
In this case, you just need to start your node with the --validator flag and an --author flag with address:
cargo run --release -- --validator --author 0x7e946b7dd192307b4538d664ead95474062ac3738e04b5f3084998b76bc5122d

Cannot use the futures-util crate with Actix because the trait Future is not implemented [duplicate]

This question already has an answer here:
Why is a trait not implemented for a type that clearly has it implemented?
(1 answer)
Closed 4 years ago.
Scala has a way to convert a iterable of futures to a single future of iterables via Futures.sequence
I was searching for same in Rust and found the futures_util crate. I used this crate in a program edited from the Actix example, but it failed to compile.
Cargo.toml
[package]
name = "actix"
version = "0.7.10"
authors = ["Nikolay Kim <fafhrd91#gmail.com>"]
description = "Actor framework for Rust"
readme = "README.md"
keywords = ["actor", "futures", "actix", "async", "tokio"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix.git"
documentation = "https://docs.rs/actix/"
categories = ["network-programming", "asynchronous"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
[badges]
travis-ci = { repository = "actix/actix", branch = "master" }
appveyor = { repository = "fafhrd91/actix-n9e64" }
codecov = { repository = "actix/actix", branch = "master", service = "github" }
[lib]
name = "actix"
path = "src/lib.rs"
[workspace]
members = ["examples/chat"]
[features]
default = ["signal", "resolver"]
# dns resolver
resolver = ["trust-dns-resolver", "trust-dns-proto"]
# signal handling
signal = ["tokio-signal"]
[dependencies]
actix_derive = "0.3"
# io
bytes = "0.4"
futures = "0.1"
futures-util = "0.2.1"
tokio = "0.1.7"
tokio-io = "0.1"
tokio-codec = "0.1"
tokio-executor = "0.1"
tokio-reactor = "0.1"
tokio-tcp = "0.1"
tokio-timer = "0.2"
# other
log = "0.4"
fnv = "1.0.5"
failure = "0.1.1"
bitflags = "1.0"
smallvec = "0.6"
crossbeam-channel = "0.3"
parking_lot = "0.7"
uuid = { version = "0.7", features = ["v4"] }
# signal handling
tokio-signal = { version = "0.2", optional = true }
# dns resolver
trust-dns-proto = { version = "^0.5.0", optional = true }
trust-dns-resolver = { version = "^0.10.0", optional = true }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[profile.release]
lto = true
opt-level = 3
codegen-units = 1
Code :
extern crate actix;
extern crate futures;
extern crate tokio;
extern crate futures_util;
use actix::prelude::*;
use futures::Future;
use futures_util::future::*;
use std::time::{SystemTime, UNIX_EPOCH};
/// Define `Ping` message
struct Ping(usize);
impl Message for Ping {
type Result = usize;
}
/// Actor
struct MyActor {
count: usize,
}
/// Declare actor and its context
impl Actor for MyActor {
type Context = Context<Self>;
}
/// Handler for `Ping` message
impl Handler<Ping> for MyActor {
type Result = usize;
fn handle(&mut self, msg: Ping, _: &mut Context<Self>) -> Self::Result {
self.count += msg.0;
self.count
}
}
fn main() {
// start system, this is required step
System::run(|| {
// start new actor
let addr = MyActor { count: 10 }.start();
let start = SystemTime::now();
// send message and get future for result
let res = join_all((1..10).into_iter().map(|x| addr.send(Ping(x))));
// handle() returns tokio handle
tokio::spawn(
res.map(|res| {
let difference = start.duration_since(start)
.expect("SystemTime::duration_since failed");
println!("Time taken: {:?}", difference);
// stop system and exit
System::current().stop();
}).map_err(|_| ()),
);
});
}
Even though the error is meaningful, I find it difficult to resolve as Request in Actix implements Future. Did I miss any imports?
error[E0277]: the trait bound `actix::prelude::Request<MyActor, Ping>: futures_core::future::Future` is not satisfied
--> examples/ping.rs:47:20
|
47 | let res = join_all((1..10).into_iter().map(|x| addr.send(Ping(x))));
| ^^^^^^^^ the trait `futures_core::future::Future` is not implemented for `actix::prelude::Request<MyActor, Ping>`
|
= note: required because of the requirements on the impl of `futures_core::future::IntoFuture` for `actix::prelude::Request<MyActor, Ping>`
= note: required by `futures_util::future::join_all`
error[E0277]: the trait bound `actix::prelude::Request<MyActor, Ping>: futures_core::future::Future` is not satisfied
--> examples/ping.rs:47:20
|
47 | let res = join_all((1..10).into_iter().map(|x| addr.send(Ping(x))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_core::future::Future` is not implemented for `actix::prelude::Request<MyActor, Ping>`
|
= note: required by `futures_util::future::JoinAll`
error[E0599]: no method named `map` found for type `futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>>` in the current scope
--> examples/ping.rs:55:12
|
55 | res.map(|res| {
| ^^^
|
= note: the method `map` exists but the following trait bounds were not satisfied:
`futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>> : futures_util::FutureExt`
`&futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>> : futures_util::FutureExt`
`&mut futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>> : futures_util::FutureExt`
`&mut futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>> : futures::Future`
`&mut futures_util::future::JoinAll<actix::prelude::Request<MyActor, Ping>> : std::iter::Iterator`
In your project, you use the join_all function of futures included in futures-util. It seems like this crate is in conflict with the actix version of futures.
In actix 0.7.10
futures = "0.1"
in futures-util 0.2.1:
futures = "~0.1.15"
I advise you to directly use join_all from futures:
[package]
name = "Battlefield Vietnam"
version = "0.0.1"
[dependencies]
actix = "0.7"
futures = "0.1"
tokio = "0.1.7"
extern crate actix;
extern crate futures;
extern crate tokio;
use actix::prelude::*;
use futures::future::*;
use futures::Future;
use std::time::SystemTime;
/// Define `Ping` message
struct Ping(usize);
impl Message for Ping {
type Result = usize;
}
/// Actor
struct MyActor {
count: usize,
}
/// Declare actor and its context
impl Actor for MyActor {
type Context = Context<Self>;
}
/// Handler for `Ping` message
impl Handler<Ping> for MyActor {
type Result = usize;
fn handle(&mut self, msg: Ping, _: &mut Context<Self>) -> Self::Result {
self.count += msg.0;
self.count
}
}
fn main() {
// start system, this is required step
System::run(|| {
// start new actor
let addr = MyActor { count: 10 }.start();
let start = SystemTime::now();
// send message and get future for result
let res = join_all((1..10).into_iter().map(move |x| addr.send(Ping(x))));
// handle() returns tokio handle
tokio::spawn(
res.map(move |res| {
let difference = start
.duration_since(start)
.expect("SystemTime::duration_since failed");
println!("Time taken: {:?}", difference);
// stop system and exit
System::current().stop();
})
.map_err(|_| ()),
);
});
}