前言
基于上次 DEMO ,主要是解决 内存一直在增长 (需要改善) 增加了白名单及同IP限连接数 问题
1:环境
win10 64
RustRover2024.*
rustc 1.84.* (GNU)
2:直接上代码
1>cargo.toml
dashmap = “5.0” 新加的
[package]
name = "chatserver"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio-websockets= { version = "0.5",features = ["server","ring"] }
futures-util = { version = "0.3.30",features = ["sink"] }
rustls-pemfile = "2.0.0"
#tokio = { version = "1.35.1", features = ["full"] }
tokio = { version = "1.35", features = ["full", "tracing"] }
tokio-rustls = "0.25.0"
rustls = "0.22.1"
rustls-pki-types = "1.1.0"
tokio-stream = "0.1.14"
bytes = "1.5.0"
prost="0.12"
prost-types = "0.12"
rust-crypto = "^0.2"
serde_json = "^1.0"
base64 = "0.21.7"
log = "0.4.0"
env_logger = "0.11"
chrono = "0.4.33"
dashmap = "5.0"
#tracing-subscriber = { version = "0.3", default-features = false, features = ["alloc"] }
console-subscriber = "0.2.0"
#tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] }
#tokio-console = "0.1.10"
#[dependencies]
#hello_utils = { path = "hello_utils" }
# 以下路径也可以
# hello_utils = { path = "./hello_utils" }
# hello_utils = { path = "../hello_world/hello_utils" }
#运行测试时用到
[build-dependencies]
#tokio-websockets= { version = "0.5",features = ["server","ring"] }
#futures-util = { version = "0.3.30",features = ["sink"] }
#rustls-pemfile = "2.0.0"
#tokio = { version = "1.35.1", features = ["full"] }
#tokio-rustls = "0.25.0"
#rustls = "0.22.1"
#rustls-pki-types = "1.1.0"
#tokio-stream = "0.1.14"
#bytes = "1.5.0"
prost-build = { version = "0.12"}
#[build]
#rustflags = ["--cfg", "tokio_unstable"]
2>main.rs
use std::sync::atomic::AtomicU8;
mod gobal;
use gobal::*;
use std::any::Any;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::fmt::Debug;
use std::fs::copy;
use std::{
fs::File,
io::{self, BufReader},
net::SocketAddr,
sync::Arc,
};
use std::io::{ErrorKind, Read};
use std::pin::Pin;
use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use std::time::Duration;
use tokio::sync::{mpsc, oneshot};
use futures_util::{FutureExt, SinkExt, StreamExt, TryStreamExt};
use rustls_pemfile::{certs, pkcs8_private_keys};
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::{select, signal, time};
use tokio_rustls::{rustls, server, TlsAcceptor, TlsStream};
use tokio_websockets::{proto, Config, Limits, Message, Payload, WebSocketStream};
use dashmap::DashMap;
mod aes_fun;
mod gobalfun;
mod json_config;
mod pb;
mod useractor;
mod worldactor;
use crate::gobalfun::*;
use crate::pb::chatproto::Chatmsg;
use crate::useractor::MyUserActor;
use crate::worldactor::worldActor;
use bytes::Bytes;
use pb::chatproto;
use prost::Message as ProstMssage;
use tokio::sync::mpsc::UnboundedSender;
use crypto;
use crypto::aes::KeySize;
use crypto::digest::Digest;
use serde_json;
use serde_json::Value as json_value;
//use serde_json::Value::{String as json_String};
//use crate::json_config::u8_aes_128_len;
use env_logger::{Builder, Target};
use log::{debug, error, info, log_enabled, Level, LevelFilter};
use std::env;
use serde_json::Value::{String as JString};
//use tracing_subscriber::{filter, prelude::*};
//https://blog.youkuaiyun.com/BBinChina/article/details/119520531
// const PATH_TO_CERT: &str = "certs/ca.crt"; //"certs/localhost.crt"; //ca.crt //server.csr
// const PATH_TO_KEY: &str = "certs/server.key"; //"certs/localhost.key";
const PATH_TO_JSON: &str = "chatserver.json"; //配置文件
//const SAME_IP_COUNT :u32 = 1 ; //同一IP 最多500个
fn load_certs(path: &str) -> io::Result<Vec<CertificateDer<'static>>> {
if let Ok(f) = File::open(path) {
certs(&mut BufReader::new(f)).collect()
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
}
// certs(&mut BufReader::new(File::open(path)?)).collect()
}
fn load_key(path: &str) -> io::Result<PrivateKeyDer<'static>> {
if let Ok(f) = File::open(path) {
pkcs8_private_keys(&mut BufReader::new(f))
.next()
.unwrap()
.map(Into::into)
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
}
// pkcs8_private_keys(&mut BufReader::new(File::open(path)?))
// .next()
// .unwrap()
// .map(Into::into)
}
static NEXT_CONNECT_ID: AtomicU32 = AtomicU32::new(1);
fn init_log() {
use chrono::Local;
use std::io::Write;
//env_logger 库不合适要写入文件的日志,不能直接输出到文件和日志轮换(rotating)
let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "trace");
let mut builder = env_logger::Builder::from_env(env);
builder.format(|buf, record| {
writeln!(
buf,
"{} {} [{}:{}:{}]",
Local::now().format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.module_path().unwrap_or("<unnamed>"),
record.line().unwrap_or(0),
&record.args()
)
});
builder.target(Target::Stdout);
builder.filter_level(LevelFilter::Warn);
builder.init();
info!("env_logger initialized.");
}
#[cfg(unix)]
async fn sigal_ctrl() -> io::Result<()> {
if let (mut stream) = signal(SignalKind::hangup()) {
stream.recv().await;
}
Ok(())
}
#[cfg(not(unix))]
async fn sigal_ctrl() -> io::Result<()> {
signal::ctrl_c().await
}
//#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
//#[tokio::main(flavor = "current_thread")]
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> Result<(), Box<dyn Error>> {
//std::error::
// let mut builder = Builder::from_default_env();
// builder.target(Target::Stdout);
// console_subscriber::ConsoleLayer::builder()
// // set how long the console will retain data from completed tasks
// .retention(Duration::from_secs(60))
// // set the address the server is bound to
// .server_addr(([127, 0, 0, 1], 5555))
// // ... other configurations ...
// .init();
// console_subscriber::init();
//日志///
init_log();
// let mut builder = Builder::from_default_env();
// builder.target(Target::Stdout);
// builder.filter_level(LevelFilter::Warn);
// builder.init();
//
// debug!("this is a debug {}", "message");
// error!("this is printed by default");
// info!("this is infomsg");
//env_logger::init();
/
let chat_cfg = loadchatcfg(PATH_TO_JSON).await?;
//return Err(Box::try_from(io::Error::new(io::ErrorKind::Other, "something went wrong")).unwrap()); //Err("read json file error");
let addr = SocketAddr::from(([0, 0, 0, 0], chat_cfg.nlistenport as u16)); //default 8080
let certs = load_certs(chat_cfg.szcacrtfile.as_str())?; //load_certs(PATH_TO_CERT)?;
let key = load_key(chat_cfg.szprivatekeyfile.as_str())?; //load_key(PATH_TO_KEY)?;
let config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
let acceptor = TlsAcceptor::from(Arc::new(config));
let listener = TcpListener::bind(&addr).await?;
//let world_mgr = MyWorldHandle::new();
let (world_sender, receiver) = mpsc::unbounded_channel();
let (world_chan_sender, world_chan_receiver) = mpsc::unbounded_channel();
let world = worldActor::new(Arc::new(AtomicU8::new(1)), receiver, world_chan_receiver);
let world_handle = tokio::spawn(world.run());
let (aes_key, aes_iv) = (chat_cfg.u8AES128keyhandshake, chat_cfg.u8AES128iv);
println!(
"server running {} listen port:{}",
timestamp_seconds(),
chat_cfg.nlistenport
);
//
//读取或连接数据库得到白名单 ,定时或通过消息更换新白名单
let withemap = Arc::new(DashMap::new());
withemap.insert("192.168.1.7".to_string(), 0 as u32);
withemap.insert("192.168.1.8".to_string(), 0 as u32);
let t_singlemaxconn:u32 = chat_cfg.u8singleipmaxconn as u32 ;
//
loop {
select! {
accept_result = listener.accept() => {
let (mut stream2,addr) = accept_result?;
let acceptor = acceptor.clone();
println!("accept tcp connect {} ",timestamp_seconds());
///
let map_clone = withemap.clone();
if !safe_check(addr.clone().to_string(),map_clone,&t_singlemaxconn) {
println!("connection closed {} ",addr.to_string());
let _ = stream2.shutdown().await.as_ref();
}else{
let world_chan_sender_1 = world_chan_sender.clone();
let world_clone_1 = world_sender.clone();
tokio::spawn(tls_accept(stream2,acceptor,world_chan_sender_1,world_clone_1,addr.clone(),aes_key.clone(),aes_iv.clone())) ;
}
},
// 接收Ctrl+c SIGINT
// _ = signal::ctrl_c() => {
// //info!("KV Server is shutting down!!!");
// world_sender.send(ActorMessage::ctw_signal_event(signalType{signaltype:signalTypeId::Signal_Server_Close as u32,signalparam:0}));
// break ;
// }
_= sigal_ctrl()=>{
world_sender.send(ActorMessage::ctw_signal_event(signalType { signaltype: signalTypeId::Signal_Server_Close as u32, signalparam: 0 }));
break ;
}
} //end select!
} //end loop
// 等待服务器关闭
world_handle.await.unwrap();
println!("server exit {}", timestamp_seconds());
Ok(())
}
//async fn readjsonfile(path:&str)->Option<json_value>{
async fn readjsonfile(path: &str) -> Result<json_value, Box<dyn Error>> {
let mut f = File::open(path).expect("open file fail");
let mut data = vec![];
let s = f.read_to_end(&mut data).expect("read file fail");
if s < 10 {
//return Err(std::io::Error::other("data short"));
// Err("".into());
return Err(
Box::try_from(io::Error::new(io::ErrorKind::Other, "something went wrong")).unwrap(),
);
}
let string = std::string::String::from_utf8_lossy(&data);
Ok(serde_json::from_str(string.as_ref())?)
// if let Ok( mut f)= File::open(path) {
// let mut data = vec![];
// if let Ok(s) = f.read_to_end(&mut data) {
// if s < 10 {
// return None;
// }
// let string = String::from_utf8_lossy(&data); // 将字节向量转换为字符串
// if let Ok(v) = serde_json::from_str(string.as_ref()){
// return Some(v);
// }
// }
//
// }else{
// println!(" read file {} fail",path);
// }
// None
}
async fn stringtrimchar(string: std::string::String) -> std::string::String {
"".to_string()
}
async fn loadchatcfg(path: &str) -> Result<json_config::chatservercfg, Box<dyn Error>> {
let chat_v: json_value = readjsonfile(path).await?;
let mut chatcfg = json_config::chatservercfg::new();
const LISTENIP: &str = "listenip";
const LISTENPORT: &str = "listenport";
const USESSL: &str = "usessl";
const PRIVATEKEYFILE: &str = "privatekeyfile";
const SERVERCRTFILE: &str = "servercrtfile";
const CACRTFILE: &str = "cacrtfile";
const DOMAINNAME: &str = "domainname";
const CROSSDOMAINNAME: &str = "crossdomainname";
const AES128KEYHANDSHAKE: &str = "aes128keyhandshake";
const AES128IV: &str = "aes128iv";
const MAXCONN: &str = "maxconn";
const CHECKHEARTBEAT: &str = "checkheartbeat";
const OPENBLACKWHITEIP: &str = "openblackwhiteip";
const SINGLEIPMAXCONN: &str = "singleipmaxconn";
// macro_rules! getProp {
// ($x:expr, $y:expr) => {
// $x.get($y)
// };
// }
// macro_rules! getProp {
// ($x:expr)=>{
// chat_v.get($x)
// }
// }
// const type_num_u:u32 = 1 ;
// const type_num_i:u32 = 2 ;
// const type_string:u32 = 3 ;
//
// macro_rules! getProp {
// ($x:expr,$y:expr)=>{
// if let Some(v) = chat_v.get($x){
// match $y {
// type_num_u=>{
// if let Some(v2) = v.as_u64(){
// return Ok(v2) ;
// }
// }
// }
// }
// return Err("");
// }
// }
if let Some(ip) = chat_v.get(LISTENIP) {
chatcfg.szlistenip = ip.as_str().unwrap().to_string();
}
if let Some(port) = chat_v.get(LISTENPORT) {
chatcfg.nlistenport = port.as_u64().unwrap() as i32;
}
if let Some(bssl) = chat_v.get(USESSL) {
chatcfg.buseSsl = bssl.as_bool().is_some();
}
if let Some(maxconn) = chat_v.get(MAXCONN) {
chatcfg.u16maxconn = maxconn.as_u64().unwrap() as u16;
}
if let Some(keyfile) = chat_v.get(PRIVATEKEYFILE) {
chatcfg.szprivatekeyfile = keyfile.as_str().unwrap().to_string();
}
if let Some(cacrtfile) = chat_v.get(CACRTFILE) {
chatcfg.szcacrtfile = cacrtfile.as_str().unwrap().to_string();
}
if let Some(key) = chat_v.get(AES128KEYHANDSHAKE) {
//chatcfg.u8AES128keyhandshake = key.as_array().unwrap() ;
let mut v1 = key.as_str().unwrap().as_bytes(); //.as_slice();
//32 0x20 (space) 空格
//34 0x22 " 双引号
//10 0x0A 换行键 \n是换行
//13 0x0D CR (carriage return) 回车键 '\r'是回车
//39 0x27 ' 闭单引号 单引号的ASCII码是39
// let vlen = v1.len();
// if vlen < 16{
// return Err(Box::from(std::io::Error::new(ErrorKind::Other,"parse error")));
// }
//
// let tailch = v1[vlen-1] ;
// if 10 == tailch || 13 == tailch || 32 == tailch || 34 == tailch || 39 == tailch {
// // v1 = v1[..(vlen-1)].to_vec() ;
// v1.pop() ;
// }
//
// if 10 == v1[0] || 13 == v1[0] || 32 == v1[0] || 34 == v1[0] || 39 == v1[0] {
// v1 = v1[1..].to_vec() ;
// }
//0b_1010_1010
//let num1: u8 = 0b_1010_1010;
//println!("{:08b}", !num1);按位取反
let vlen = v1.len();
//es 128=16*8 192 =24*8 256=32*8
if vlen % 8 == 0
&& match vlen / 8 {
2 | 3 | 4 => true,
_ => false,
}
{
chatcfg.u8AES128keyhandshake = v1.to_vec();
}
//赋值数据到切片里
// let mut x = vec![0; 8];
// let y = [1, 2, 3];
// x[..3].clone_from_slice(&y);
// println!("{:?}", x);
// Output:
// [1, 2, 3, 0, 0, 0, 0, 0]
if let Some(singlemaxconn) = chat_v.get(SINGLEIPMAXCONN) {
chatcfg.u8singleipmaxconn = singlemaxconn.as_u64().unwrap() as u8;
}
}
if let Some(iv) = chat_v.get(AES128IV) {
let i = iv.as_str().unwrap().as_bytes();
if i.len() == 16 {
chatcfg.u8AES128iv.clone_from_slice(&i);
} else {
return Err(Box::from(std::io::Error::new(
ErrorKind::Other,
"parse error",
)));
}
} else {
return Err(Box::from(std::io::Error::new(
ErrorKind::Other,
"parse error",
)));
}
if chatcfg.u8AES128keyhandshake.len() < 16 {
return Err(Box::from(std::io::Error::new(
ErrorKind::Other,
"parse error",
)));
}
if chatcfg.u8AES128keyhandshake.len() < 16 {
return Err(Box::from(std::io::Error::new(
ErrorKind::Other,
"parse error",
)));
}
Ok(chatcfg)
// if let (Some(ip),Some(port),Some(bssl),Some(maxconn),Some(key),Some(iv)) = (getProp!(LISTENIP),getProp!(LISTENPORT),getProp!(USESSL),getProp!(MAXCONN),
// getProp!(AES128KEYHANDSHAKE),getProp!(AES128IV)){
// chatcfg.szlistenip = ip.to_string() ;
//
// }else{
// println!("parse error");
// return Err(Box::from(std::io::Error::new(ErrorKind::Other,"parse error")));
// }
// if (root[LISTENIP].empty() || root[LISTENPORT].empty() || root[MAXCONN].empty() \
// || root[USESSL].empty() || root[AES128KEYHANDSHAKE].empty() || root[AES128IV].empty()) {
// printf("read_json_file base fail\n");
// return false;
//
// }
// chatcfg.szlistenip = chat_v.get(LISTENIP).to_string().?;
// chatcfg.nlistenport = chat_v.get(LISTENPORT)?;
//
// chatcfg.buseSsl = chat_v.get(USESSL).expect("ssl")?;
// chatcfg.szprivatekeyfile = chat_v.get(PRIVATEKEYFILE).expect("keyfile")?;
// //chatcfg.szservercrtfile = chat_v.get(SERVERCRTFILE).expect("szservercrtfile")?;
//
// chatcfg.szcacrtfile = chat_v.get(CACRTFILE).expect("cacrtfile")?;
//
// chatcfg.u8AES128keyhandshake = chat_v.get(AES128KEYHANDSHAKE).expect("AES128keyhandshake")?;
// chatcfg.u8AES128iv = chat_v.get(AES128IV).expect("AES128iv")?;
// chatcfg.u16maxconn = chat_v.get(MAXCONN).expect("u16maxconn")?;
// chatcfg.bcheckheartbeat = chat_v.get(CHECKHEARTBEAT).expect("checkheartbeat")?;
//Ok(chatcfg)
// pub(crate) szlistenip:String,
// pub(crate) nlistenport:i32,
// pub(crate) buseSsl:bool,
// pub(crate) szprivatekeyfile:String,
// pub(crate) szservercrtfile:String,
// pub(crate) szcacrtfile:String,
// pub(crate) szdomainname:String,//域名
// pub(crate) szcrossdomainname:String, //跨域名
// pub(crate) u8AES128keyhandshake:[u8;u8_aes_128_len as usize], //16*8=128 16个字节就可以了 yyuilioudkiojun aes 128=16*8 192 =24*8 256=32*8
// pub(crate) u8AES128iv:[u8;16],//16个字节 固定的16个字节 不管是ase128 192 256
// pub(crate) u16maxconn:u16,//最大连接数(总的)
// pub(crate) bcheckheartbeat:bool,//检测心跳
// pub(crate) u8openblackwhiteip:u8,//开启黑白名单
// pub(crate)u8singleipmaxconn:u8,//单个IP 最大连接数
}
//&'static str
//Result<(),dyn std::error::Error> Box<dyn Error
证书校验 完成
async fn wait_tls_check(
stream2: TcpStream,
acceptor: TlsAcceptor,
timeoutcheck: u64,
) -> Result<server::TlsStream<TcpStream>, &'static str> {
//
let dur = Duration::from_millis(timeoutcheck);
match time::timeout(dur, acceptor.accept(stream2)).await {
Ok(v) => {
match v {
Ok(v1) => Ok(v1),
e => {
println!("wait_tls_check accept error");
println!("{:?}", e);
Err("accept error")
}
}
// if let Ok(v1) = v {
// Ok(v1)
// } else {
// println!("wait_tls_check accept error");
// // let _= stream2.shutdown().await ;
// // let _= stream2.borrow().shutdown().await.unwrap();
// Err("accept error")
// }
}
_ => {
// Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
// stream2.borrow().shutdown().await.unwrap();
// stream2.borrow().shutdown();
//怎么关闭 stream2 ????
println!("wait_tls_check timeout");
Err("time out")
}
}
}
async fn wait_handleshake(
stream: server::TlsStream<TcpStream>,
timeoutcheck: u64,
) -> Option<WebSocketStream<server::TlsStream<TcpStream>>> {
let f1 = async {
tokio_websockets::ServerBuilder::new()
.limits(Limits::default().max_payload_len(Some(MAX_PAYLOAD_LEN)))
.config(Config::default().frame_size(MAX_FRAME_SIZE))
.accept(stream)
.await
};
let dur = Duration::from_millis(timeoutcheck);
match time::timeout(dur, f1).await {
Ok(v) => {
if let Ok(v1) = v {
Some(v1)
} else {
None
}
}
_ => {
// stream.shutdown()
//关闭 stream
println!("wait_handleshake timeout");
None
}
}
}
async fn recv_frist_msg(
mut ws: WebSocketStream<server::TlsStream<TcpStream>>,
timeoutcheck: u64,
) -> Option<(WebSocketStream<server::TlsStream<TcpStream>>, Message)> {
let dur = Duration::from_millis(timeoutcheck);
let f1 = async { ws.next().await };
match time::timeout(dur, f1).await {
Ok(v) => {
if let Some(Ok(m)) = v {
Some((ws, m))
} else {
None
}
}
_ => {
println!("recv_frist_msg timeout {}", timestamp_seconds());
ws.close().await.unwrap();
None
}
}
}
async fn verify_user_login(
userid: &UserID,
username: &String,
guild_id: &GuildID,
ase_token: &String,
md5_v: &String,
ip_addr: &String,
aeskey: &VU8,
iv: &[u8; 16],
) -> Result<(), Box<dyn Error>> {
let v = concat_string_token(&userid, &username, &guild_id, &ase_token);
let mut sh = crypto::md5::Md5::new();
sh.input_str(v.as_str());
let md5str = sh.result_str();
if !md5_v.eq(&md5str) {
return Err("fail".into());
}
let keylen = match aeskey.len() as u16 {
24 | 32 => aeskey.len() as u16,
_ => 16,
};
if let Ok(mut v) = aes_fun::encrypt(ase_token.as_bytes(), &aeskey, iv.as_ref(), keylen * 8) {
let len_v = v.len();
if len_v > 10 {
if v[len_v - 1] == ']' as u8 {
v.pop();
}
if v[0] == '[' as u8 {
v = v[1..].to_vec();
}
}
if let Ok(str) = std::str::from_utf8(&v) {
let t_string = str.to_string();
let raw_parts: Vec<&str> = t_string.split("#").collect();
//username base64 //小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)
//[userid#username#guildid#ipaddr#timestamp#serverid#random] == 7 //username 为 base64encode 后的
if raw_parts.len() == 7 {
if let Ok(v_userid) = raw_parts[0].parse::<u32>() {
let v_username = raw_parts[1].to_string();
if let Ok(v_guildid) = raw_parts[2].parse::<u32>() {
let v_ipaddr = raw_parts[3].to_string();
if let Ok(v_timestampe) = raw_parts[4].parse::<u32>() {
if let Some(en_username) = aes_fun::base64encode(username.as_str()) { //加密后再比较也一样
}
if v_userid == *userid && v_guildid == *guild_id && *ip_addr == v_ipaddr
{
if gobalfun::timestamp_seconds() <= (v_timestampe + 30) as u64 {
//30秒内有效
return Ok(());
}
}
}
}
}
}
}
}
// let encrypted_data = aes_fun::encrypt(ase_token.as_bytes(), &aeskey, iv.as_ref(),128).ok().unwrap();
// if !md5str.eq(&md5_v) {
// return Err("fail".into());
// }
// let data ="1233" ;
// let v: Value = serde_json::from_str(data)?;
// crypto::aes::cbc_decryptor()
Err("fail".into())
}
async fn tls_accept(
mut stream2: TcpStream,
acceptor: TlsAcceptor,
world_chan_sender_1: UnboundedSender<ActorMessage2>,
world_clone_1: UnboundedSender<ActorMessage>,
addr: SocketAddr,
vecaeskey: VU8,
iv: [u8; 16],
) {
if let Ok(v) = wait_tls_check(stream2, acceptor, 6_000).await {
if let Some(mut ws) = wait_handleshake(v, 4_000).await {
if let Some((mut ws, req)) = recv_frist_msg(ws, 3_000).await {
//处理接受的第一个消息
let world_chan_sender_2 = world_chan_sender_1.clone();
let world_clone_2 = world_clone_1.clone();
let connid = NEXT_CONNECT_ID.fetch_add(1, Ordering::Relaxed);
let (t1, r1) = mpsc::unbounded_channel::<SendClientMsg>();
let msgData = Vec::from(req.as_payload().to_vec());
let (msgid, mask) = getProtoMsgIdAndMask(&msgData);
let res = match msgid {
msg_id_login => {
if let Ok(req) = chatproto::ChatMessageLoginReq::decode(&msgData[..]) {
// error!("recv frirst msg");
// crypto::aes::cbc_decryptor(KeySize::KeySize128,"12345678".to_string().encode_to_vec().borrow(),)
//检测 req.tokenstr req.tokenmd5
//检查合法性
// if req.tokenstr.len() > 20 { //[userid#username#guildid#ipaddr#timestamp#serverid#random]
// if let Ok(_) = verify_user_login(&req.userid,&req.username,&req.guildid,&req.tokenstr,&req.tokenmd5,&addr.to_string(),&vecaeskey,&iv).await {
//
// }else{
// let _ =ws.close();
// return;
// }
// }else{
// let _ =ws.close();
// return;
// }
//check_user_login()
let world_chan_sender_3 = world_chan_sender_2.clone();
if let Ok(res) = query_user_channel2(
req.userid,
world_chan_sender_2,
connid,
t1.clone(),
)
.await
{
if res.state > 0 {
if res.state > 1 {
//超过最大在线人数
let mut repmsg = chatproto::ChatMessageLoginRep {
msghead: Some(chatproto::ChatMessageHeadNoMask {
msgid: chatproto::Chatmsg::ChcLoginRep as u32,
}),
res: 2,
tokenrelogin: "".to_string(),
timestamp: 0,
};
// ws.send(Message::text(String::from("Hello, world!").into()))
let mut buf = Vec::new();
if let Ok(_) = repmsg.encode(&mut buf) {
// Payloads can be created by using the From<Bytes>, From<BytesMut> and From<String>
let sendmsg =
tokio_websockets::Message::binary(Bytes::from(buf));
let _ = ws.send(sendmsg).await;
}
}
let _ = ws.close().await;
} else if let Some(s) = res.op {
//用现成的 //挤号
let mut repmsg = chatproto::ChatMessageLoginRep {
msghead: Some(chatproto::ChatMessageHeadNoMask {
msgid: chatproto::Chatmsg::ChcLoginRep as u32,
}),
res: 1,
tokenrelogin: "".to_string(),
timestamp: 0,
};
let mut buf = Vec::new();
if let Ok(_) = repmsg.encode(&mut buf) {
let sendmsg =
tokio_websockets::Message::binary(Bytes::from(buf));
let _ = ws.send(sendmsg).await;
}
tokio::spawn(run_user_actor_network(
ws,
s.sendchann,
r1,
s.actorState,
connid.clone(),
));
} else {
// 创建新的 //登录
let (logicchantx, logicchanrx) = mpsc::unbounded_channel();
let mut useractor = MyUserActor::new(
connid.clone(),
logicchanrx,
t1,
world_clone_2,
);
useractor.setuserinfo(
req.userid.clone(),
req.username.clone(),
req.guildid.clone(),
UserState_INIT,
);
//把发送通道发送给worldactor
let userinfo = userChan_CTW {
msgtype: 0,
userid: req.userid,
username: req.username,
userguildid: req.guildid,
connectid: connid,
logicChann: logicchantx.clone(),
chanState: useractor.getuserstateclone(),
};
let _ = world_chan_sender_3.send(ActorMessage2::ctw_userhann {
respond_to: userinfo,
});
let ustate = useractor.getuserstateclone();
let mut repmsg = chatproto::ChatMessageLoginRep {
msghead: Some(chatproto::ChatMessageHeadNoMask {
msgid: chatproto::Chatmsg::ChcLoginRep as u32,
}),
res: 0,
tokenrelogin: "".to_string(),
timestamp: 0,
};
let mut buf = Vec::new();
if let Ok(_) = repmsg.encode(&mut buf) {
// buf.insert(0,MyMsgType::Binary as u8);
let sendmsg =
tokio_websockets::Message::binary(Bytes::from(buf));
let _ = ws.send(sendmsg).await;
}
useractor.setuserstate(UserState::UserState_NORMAL as u8);
tokio::spawn(run_my_user_actor(useractor)); //逻辑future
tokio::spawn(run_user_actor_network(
ws,
logicchantx,
r1,
ustate,
connid.clone(),
)); //网络发送接受 future
}
} else {
let _ = ws.close().await;
}
} else {
let _ = ws.close().await;
}
// return Ok(());
}
msg_id_relogin => {
if let Ok(req) = chatproto::ChatMessageReLoginReq::decode(&msgData[..]) {
// if let Ok(res) = world_clone_2.query_user_channel(req.userid).await {
//
// }
}
// return Ok(());
}
_ => {
let _ = ws.close().await;
//return Err("msg is error");
}
};
} // 3 wait
}
}
}
fn safe_check(ipaddr:String,whitemap:Arc<DashMap<String,u32>>,maxconn:&u32)->bool{
if ipaddr.len() < 7 {
return false ;
}else{
// if whitemap.get("key1")
// let mut flag :u32 = 0 ;
// 如果键存在则修改,否则插入新值
// if let Some( ) = whitemap.get_mut(&ipaddr)
// if ipaddr.split(":")
let mut flag:bool = false;
let v: Vec<&str> = ipaddr.split(':').collect();
if v.len() >0 {
let ip_addr = v[0].to_string() ;
if let Some(mut value) = whitemap.get_mut(&ip_addr) {
// *value = 100; // 直接修改值
if *value < *maxconn {
*value += 1 ;
flag = true;
}
}
if !flag {
println!("ip over or no existing white")
}
}
return flag ;
// whitemap.entry(ipaddr.clone()).and_modify(| value| *value +=1).or_insert(1);
// if let Some(value) = whitemap.get(&ipaddr) {
// if *value.value() > SAME_IP_COUNT {
// return false;
// }
// }
// return true;
// return flag ;
// if let Some(value) = whitemap.get(&ipaddr) {//引用为1
// whitemap.alter(|key, value| {
// // println!("线程 {:?} 修改键 {}", thread::current().id(), key);
// value + 1
// });
// return true ;
// }else{
// let mut flag :bool = true ;
// //stats.alter("Goals", |_, v| v * 2);
// whitemap.alter(ipaddr,|_, value| {
// // println!("线程 {:?} 修改键 {}", thread::current().id(), key);
// if value < SAME_IP_COUNT {
// flag = false;
// value + 1
// }
// });
//
// return flag ;
// }
}
}
3>配置文件
3:测试
前端原来的c++的找不到了,所以用go(1.20版)重写了个
1>白名单 及 同IP限连接数
2>测试内存
WIFI 带宽有线,没有极限测试,
4:DEMO 前后端会上传上去
DEMO_DOWNLOAD
如果还有什么没完善的,后面又时间再搞
5:如果对你又帮助,麻烦点个赞,加个关注,