#![allow(dead_code)]
use std::io;
use std::sync::Arc;
use azalea_protocol::connect::Proxy;
use tokio::sync::RwLock;
use tokio::task::JoinHandle;
use uuid::Uuid;
use crate::bot::Bot;
use crate::bot::events::EventInvoker;
use crate::bot::options::{BotInformation, BotPlugins};
use crate::bot::terminal::{BotCommand, BotTerminal};
use crate::bot::transmitter::{BotPackage, BotTransmitter, NullPackage};
use crate::bot::world::{Storage, StorageLock};
use crate::utils::time::sleep;
pub struct Swarm<P: BotPackage = NullPackage> {
pub bots: Vec<Bot<P>>,
pub terminals: Vec<Arc<BotTerminal>>,
pub transmitters: Vec<Arc<BotTransmitter<P>>>,
pub handles: Vec<JoinHandle<io::Result<()>>>,
pub shared_storage: StorageLock,
}
pub type SharedSwarm<P> = Arc<RwLock<Swarm<P>>>;
impl<P: BotPackage> Swarm<P> {
pub fn create() -> Self {
Self {
bots: Vec::new(),
terminals: Vec::new(),
transmitters: Vec::new(),
handles: Vec::new(),
shared_storage: Arc::new(RwLock::new(Storage::new())),
}
}
pub async fn for_each_async<F, Fut>(&self, f: F)
where
F: Fn(Arc<BotTerminal>) -> Fut,
Fut: std::future::Future<Output = ()>,
{
for terminal in &self.terminals {
f(Arc::clone(terminal)).await;
}
}
pub async fn for_each_parallel<F, Fut>(&self, f: F)
where
F: Fn(Arc<BotTerminal>) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = ()> + Send + 'static,
{
let f = Arc::new(f);
let mut handles = Vec::with_capacity(self.bots.len());
for terminal in &self.terminals {
let f_clone = Arc::clone(&f);
let terminal_clone = Arc::clone(terminal);
let handle = tokio::spawn(async move {
f_clone(terminal_clone).await;
});
handles.push(handle);
}
for handle in handles {
handle.await.ok();
}
}
pub fn for_each<F, Fut>(&self, f: F)
where
F: Fn(Arc<BotTerminal>) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = ()> + Send + 'static,
{
let f = Arc::new(f);
for terminal in &self.terminals {
let f_clone = Arc::clone(&f);
let terminal_clone = Arc::clone(terminal);
tokio::spawn(async move {
f_clone(terminal_clone).await;
});
}
}
pub fn for_each_transmitters<F, Fut>(&self, f: F)
where
F: Fn(Arc<BotTransmitter<P>>) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = ()> + Send + 'static,
{
let f = Arc::new(f);
for transmitter in &self.transmitters {
let f_clone = Arc::clone(&f);
let transmitter_clone = Arc::clone(transmitter);
tokio::spawn(async move {
f_clone(transmitter_clone).await;
});
}
}
pub fn add_object(&mut self, object: SwarmObject) {
let mut bot: Bot<P> = Bot::create(object.username)
.set_uuid(object.uuid)
.set_connection_timeout(object.connection_timeout)
.set_plugins(object.plugins)
.set_information(object.information)
.set_transmitter_interval(object.transmitter_interval);
if object.use_shared_storage {
bot = bot.set_shared_storage(self.shared_storage.clone());
}
if let Some(proxy) = object.proxy {
bot = bot.set_proxy(proxy);
}
if let Some(invoker) = object.event_invoker {
bot = bot.set_event_invoker(invoker);
}
let terminal = bot.get_terminal();
let transmitter = bot.get_transmitter();
self.bots.push(bot);
self.terminals.push(terminal);
self.transmitters.push(transmitter);
}
pub async fn launch(&mut self, server_host: &str, server_port: u16, join_delay: u64) {
let bots = std::mem::take(&mut self.bots);
for bot in bots {
self.handles.push(bot.spawn(server_host, server_port));
sleep(join_delay).await;
}
}
pub async fn send(&self, command: BotCommand) {
for terminal in &self.terminals {
terminal.send(command.clone()).await;
}
}
pub async fn send_to(&self, username: &str, command: BotCommand) {
for terminal in &self.terminals {
if terminal.username.as_str() == username {
terminal.send(command).await;
break;
}
}
}
pub async fn destroy(&mut self) {
for terminal in &self.terminals {
terminal.send(BotCommand::Disconnect).await;
}
sleep(1000).await;
for handle in &self.handles {
handle.abort();
}
self.clear();
}
pub fn force_destroy(&mut self) {
for handle in &self.handles {
handle.abort();
}
self.clear();
}
fn clear(&mut self) {
self.bots.clear();
self.terminals.clear();
self.handles.clear();
}
}
pub struct SwarmObject {
pub username: String,
uuid: Uuid,
plugins: BotPlugins,
event_invoker: Option<EventInvoker>,
transmitter_interval: u64,
connection_timeout: u64,
proxy: Option<Proxy>,
information: BotInformation,
use_shared_storage: bool,
}
impl SwarmObject {
pub fn new(username: impl Into<String>) -> Self {
Self {
username: username.into(),
uuid: Uuid::nil(),
plugins: BotPlugins::default(),
event_invoker: None,
transmitter_interval: 500,
connection_timeout: 14000,
proxy: None,
information: BotInformation::default(),
use_shared_storage: true,
}
}
pub fn set_uuid(mut self, uuid: Uuid) -> Self {
self.uuid = uuid;
self
}
pub fn set_plugins(mut self, plugins: BotPlugins) -> Self {
self.plugins = plugins;
self
}
pub fn set_event_invoker(mut self, invoker: EventInvoker) -> Self {
self.event_invoker = Some(invoker);
self
}
pub fn set_transmitter_interval(mut self, interval: u64) -> Self {
self.transmitter_interval = interval;
self
}
pub fn set_connection_timeout(mut self, timeout: u64) -> Self {
self.connection_timeout = timeout;
self
}
pub fn set_information(mut self, information: BotInformation) -> Self {
self.information = information;
self
}
pub fn set_proxy(mut self, proxy: Proxy) -> Self {
self.proxy = Some(proxy);
self
}
pub fn set_use_shared_storage(mut self, state: bool) -> Self {
self.use_shared_storage = state;
self
}
}