rust学习基于tokio_actor聊天服务器实战(三 )

前言
基于上次 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:如果对你又帮助,麻烦点个赞,加个关注,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值