pub use crate::ConnectionList;
use crate::{
connection::{Connection, SendInformation},
id_manager::IDManager,
router::Router,
server::{UpstreamConfig, VarDiffConfig},
types::{ExMessageGeneric, MessageValue},
BanManager, Error, Result, EX_MAGIC_NUMBER,
};
use async_std::{net::TcpStream, prelude::FutureExt, sync::Arc};
use extended_primitives::Buffer;
use futures::{
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
io::{AsyncBufReadExt, AsyncReadExt, BufReader, ReadHalf, WriteHalf},
AsyncWriteExt, SinkExt, StreamExt,
};
use log::{trace, warn};
use serde_json::{Map, Value};
use std::{net::SocketAddr, time::Duration};
use stop_token::future::FutureExt as stopFutureExt;
pub async fn proxy_protocol(
buffer_stream: &mut BufReader<ReadHalf<TcpStream>>,
expected_port: u16,
) -> Result<SocketAddr> {
let mut buf = String::new();
buffer_stream.read_line(&mut buf).await.unwrap();
let buf = buf.trim();
let pieces: Vec<&str> = buf.split(' ').collect();
let attempted_port: u16 = pieces[5].parse().unwrap();
if attempted_port != expected_port {
return Err(Error::StreamWrongPort);
}
Ok(format!("{}:{}", pieces[2], pieces[4]).parse()?)
}
pub async fn upstream_message_handler<
State: Clone + Send + Sync + 'static,
CState: Clone + Send + Sync + 'static,
>(
config: UpstreamConfig,
upstream_router: Arc<Router<State, CState>>,
urx: UnboundedReceiver<String>,
state: State,
connection: Arc<Connection<CState>>,
mut urtx: UnboundedSender<Map<String, Value>>,
) -> Result<()> {
if config.enabled {
let upstream = TcpStream::connect(config.url).await?;
let (urh, uwh) = upstream.split();
let mut upstream_buffer_stream = BufReader::new(urh);
async_std::task::spawn(async move {
match upstream_send_loop(urx, uwh).await {
Ok(_) => trace!("Upstream Send Loop is closing for connection"),
Err(e) => warn!(
"Upstream Send loop is closed for connection: {}, Reason: {}",
1, e
),
}
});
async_std::task::spawn({
let state = state.clone();
let connection = connection.clone();
let stop_token = connection.get_stop_token();
async move {
loop {
let next_message =
next_message(&mut upstream_buffer_stream).timeout_at(stop_token.clone());
let (method, values) = match next_message.await? {
Ok(mv) => mv,
Err(_) => {
break;
}
};
if method == "result" {
if let MessageValue::StratumV1(map) = values {
urtx.send(map).await?;
}
continue;
}
upstream_router
.call(&method, values, state.clone(), connection.clone())
.await;
}
Ok::<(), Error>(())
}
});
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub async fn handle_connection<
State: Clone + Send + Sync + 'static,
CState: Clone + Send + Sync + 'static,
>(
id_manager: Arc<IDManager>,
ban_manager: Arc<BanManager>,
mut addr: SocketAddr,
connection_list: Arc<ConnectionList<CState>>,
router: Arc<Router<State, CState>>,
upstream_router: Arc<Router<State, CState>>,
upstream_config: UpstreamConfig,
state: State,
stream: TcpStream,
var_diff_config: VarDiffConfig,
initial_difficulty: f64,
connection_state: CState,
proxy: bool,
expected_port: u16,
) -> Result<()> {
let (rh, wh) = stream.split();
let mut buffer_stream = BufReader::new(rh);
if proxy {
addr = proxy_protocol(&mut buffer_stream, expected_port).await?
}
if ban_manager.check_banned(&addr).await {
warn!(
"Banned connection attempting to connect: {}. Connection closed",
addr
);
return Ok(());
}
let (tx, rx) = unbounded();
let (utx, urx) = unbounded();
let (urtx, urrx) = unbounded();
let connection_id = match id_manager.allocate_session_id().await {
Some(id) => id,
None => {
warn!("Sessions full");
return Ok(());
}
};
let connection = Arc::new(Connection::new(
connection_id,
tx,
utx,
urrx,
initial_difficulty,
var_diff_config,
connection_state,
));
let stop_token = connection.get_stop_token();
upstream_message_handler(
upstream_config,
upstream_router,
urx,
state.clone(),
connection.clone(),
urtx,
)
.await?;
async_std::task::spawn(async move {
match send_loop(rx, wh).await {
Ok(_) => trace!("Send Loop is closing for connection"),
Err(e) => warn!("Send loop is closed for connection: {}, Reason: {}", 1, e),
}
});
connection_list
.add_miner(addr, connection.clone())
.await
.unwrap();
loop {
if connection.is_disconnected().await {
break;
}
let next_message = next_message(&mut buffer_stream)
.timeout(Duration::from_secs(60))
.timeout_at(stop_token.clone())
.await;
if let Ok(Ok(Ok((method, values)))) = next_message {
router
.call(&method, values, state.clone(), connection.clone())
.await;
} else {
break;
}
}
trace!("Closing stream from: {}", addr);
id_manager.remove_session_id(connection_id).await;
connection_list.remove_miner(addr).await;
if connection.needs_ban().await {
ban_manager.add_ban(&addr).await;
}
connection.shutdown().await;
Ok(())
}
pub async fn next_message(
stream: &mut BufReader<ReadHalf<TcpStream>>,
) -> Result<(String, MessageValue)> {
loop {
let peak = stream.fill_buf().await?;
if peak.is_empty() {
return Err(Error::StreamClosed);
}
if peak[0] == EX_MAGIC_NUMBER {
let mut header_bytes = vec![0u8; 4];
stream.read_exact(&mut header_bytes).await?;
let mut header_buffer = Buffer::from(header_bytes);
let mut saved_header_buffer = header_buffer.clone();
let _magic_number = header_buffer.read_u8().map_err(|_| Error::BrokenExHeader)?;
let _cmd = header_buffer.read_u8().map_err(|_| Error::BrokenExHeader)?;
let length = header_buffer
.read_u16()
.map_err(|_| Error::BrokenExHeader)?;
let mut buf = vec![0u8; length as usize - 4];
stream.read_exact(&mut buf).await?;
let buffer = Buffer::from(buf);
saved_header_buffer.extend(buffer);
let ex_message = ExMessageGeneric::from_buffer(&mut saved_header_buffer)?;
return Ok((
ex_message.cmd.to_string(),
MessageValue::ExMessage(ex_message),
));
}
let mut buf = String::new();
let num_bytes = stream.read_line(&mut buf).await?;
if num_bytes == 0 {
return Err(Error::StreamClosed);
}
if !buf.is_empty() {
buf = buf.trim().to_owned();
trace!("Received Message: {}", &buf);
if buf.is_empty() {
continue;
}
let msg: Map<String, Value> = match serde_json::from_str(&buf) {
Ok(msg) => msg,
Err(_) => continue,
};
let method = if msg.contains_key("method") {
match msg.get("method") {
Some(method) => method.as_str(),
None => return Err(Error::MethodDoesntExist),
}
} else if msg.contains_key("messsage") {
match msg.get("message") {
Some(method) => method.as_str(),
None => return Err(Error::MethodDoesntExist),
}
} else if msg.contains_key("result") {
Some("result")
} else {
Some("")
};
if let Some(method_string) = method {
return Ok((method_string.to_owned(), MessageValue::StratumV1(msg)));
} else {
return Err(Error::MethodDoesntExist);
}
};
}
}
pub async fn send_loop(
mut rx: UnboundedReceiver<SendInformation>,
mut rh: WriteHalf<TcpStream>,
) -> Result<()> {
while let Some(msg) = rx.next().await {
match msg {
SendInformation::Json(json) => {
rh.write_all(json.as_bytes()).await?;
rh.write_all(b"\n").await?;
}
SendInformation::Raw(buffer) => {
rh.write_all(&buffer).await?;
}
}
}
Ok(())
}
pub async fn upstream_send_loop(
mut rx: UnboundedReceiver<String>,
mut rh: WriteHalf<TcpStream>,
) -> Result<()> {
while let Some(msg) = rx.next().await {
rh.write_all(msg.as_bytes()).await?;
rh.write_all(b"\n").await?;
}
Ok(())
}