Good enough for now, more later.
All checks were successful
Build and push container image / build (push) Successful in 9m55s

This commit is contained in:
toast 2024-01-31 05:22:08 +11:00
parent dd9ee41287
commit 8ecc3ff4ef
8 changed files with 264 additions and 3 deletions

2
Cargo.lock generated
View File

@ -822,7 +822,7 @@ dependencies = [
[[package]]
name = "kon"
version = "0.1.11"
version = "0.1.12"
dependencies = [
"cargo_toml",
"gamedig",

View File

@ -1,6 +1,6 @@
[package]
name = "kon"
version = "0.1.11"
version = "0.1.12"
rust-version = "1.74"
edition = "2021"

160
src/commands/gameserver.rs Normal file
View File

@ -0,0 +1,160 @@
use crate::{
Error,
EMBED_COLOR,
models::gameservers::Gameservers
};
use serenity::{
all::Mentionable,
builder::CreateActionRow,
builder::CreateEmbed
};
use poise::{
CreateReply,
serenity_prelude,
serenity_prelude::ButtonStyle
};
/// Manage the game servers for this guild
#[poise::command(slash_command, subcommands("add", "remove", "update", "list"), subcommand_required, guild_only)]
pub async fn gameserver(_: poise::Context<'_, (), Error>) -> Result<(), Error> {
Ok(())
}
/// Add a game server to the database
#[poise::command(slash_command)]
pub async fn add(
ctx: poise::Context<'_, (), Error>,
#[description = "Server name as shown in-game or friendly name"] server_name: String,
#[description = "Which game is this server running?"] game_name: String,
#[channel_types("Text")] #[description = "Which channel should this server be restricted to?"] guild_channel: serenity_prelude::GuildChannel,
#[description = "IP address/domain of the server (Include the port if it has one, e.g 127.0.0.1:8080)"] ip_address: String
) -> Result<(), Error> {
let unsupported_games_list = [
"ATS",
"ETS2",
"Euro Truck Simulator 2",
"American Truck Simulator",
];
if unsupported_games_list.contains(&game_name.as_str()) {
ctx.send(CreateReply::default()
.ephemeral(true)
.content(format!("Sorry, `{}` is not supported yet due to database design.", game_name))
).await?;
return Ok(());
}
let action_row = CreateActionRow::Buttons(vec![
serenity_prelude::CreateButton::new("confirm")
.style(ButtonStyle::Success)
.label("Yes"),
serenity_prelude::CreateButton::new("cancel")
.style(ButtonStyle::Danger)
.label("No")
]);
let reply = CreateReply::default()
.embed(CreateEmbed::new()
.title("Does this look correct?")
.description(format!("
**Server name:** `{}`
**Game name:** `{}`
**Channel:** {}
**IP Address:** `{}`
", server_name, game_name, guild_channel.mention(), ip_address))
.color(EMBED_COLOR)
)
.components(vec![action_row]);
ctx.send(reply).await?;
while let Some(collector) = serenity_prelude::ComponentInteractionCollector::new(ctx)
.channel_id(ctx.channel_id())
.guild_id(ctx.guild_id().unwrap())
.author_id(ctx.author().id)
.timeout(std::time::Duration::from_secs(30))
.await
{
if collector.data.custom_id == "confirm" {
let result = Gameservers::add_server(
ctx.guild_id().unwrap().into(),
server_name.as_str(),
game_name.as_str(),
guild_channel.id.into(),
ip_address.as_str()
).await;
let mut msg = collector.message.clone();
match result {
Ok(_) => {
msg.edit(
ctx,
serenity_prelude::EditMessage::new()
.content("*Confirmed, added the server to database*")
.components(Vec::new())
).await?;
},
Err(y) => {
msg.edit(
ctx,
serenity_prelude::EditMessage::new()
.content(format!("*Error adding server to database: {:?}*", y))
.components(Vec::new())
).await?;
}
}
} else if collector.data.custom_id == "cancel" {
let mut msg = collector.message.clone();
msg.edit(
ctx,
serenity_prelude::EditMessage::new()
.content("*Command cancelled*")
.components(Vec::new())
).await?;
}
}
Ok(())
}
/// Remove a game server from the database
#[poise::command(slash_command)]
pub async fn remove(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
ctx.send(CreateReply::default().content("Yet to be implemented.")).await?;
Ok(())
}
/// Update a game server in the database
#[poise::command(slash_command)]
pub async fn update(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
ctx.send(CreateReply::default().content("Yet to be implemented.")).await?;
Ok(())
}
/// List all the available game servers for this guild
#[poise::command(slash_command)]
pub async fn list(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
let servers = Gameservers::list_servers(ctx.guild_id().unwrap().into()).await?;
let mut embed_fields = Vec::new();
for server in servers {
embed_fields.push(
(server.server_name, format!("Game: `{}`\nIP: `{}`", server.game_name, server.ip_address), true)
);
}
ctx.send(CreateReply::default()
.embed(CreateEmbed::new()
.title("List of registered gameservers")
.fields(embed_fields)
.color(EMBED_COLOR)
)
).await?;
Ok(())
}

View File

@ -1,3 +1,4 @@
pub mod ping;
pub mod status;
pub mod uptime;
pub mod gameserver;

View File

@ -31,6 +31,17 @@ impl DatabaseController {
);
").await?;
// Gameservers
client.batch_execute("
CREATE TABLE IF NOT EXISTS gameservers (
server_name VARCHAR(255) NOT NULL PRIMARY KEY,
game_name VARCHAR(255) NOT NULL,
guild_owner BIGINT NOT NULL,
guild_channel BIGINT NOT NULL,
ip_address VARCHAR(255) NOT NULL
);
").await?;
Ok(DatabaseController { client })
}
}

View File

@ -66,7 +66,8 @@ async fn main() {
commands: vec![
commands::ping::ping(),
commands::uptime::uptime(),
commands::status::status()
commands::status::status(),
commands::gameserver::gameserver()
],
pre_command: |ctx| Box::pin(async move {
let get_guild_name = match ctx.guild() {

87
src/models/gameservers.rs Normal file
View File

@ -0,0 +1,87 @@
use crate::controllers::database::DatabaseController;
pub struct Gameservers {
pub server_name: String,
pub game_name: String,
pub guild_owner: i64,
pub guild_channel: i64,
pub ip_address: String
}
#[allow(dead_code)]
impl Gameservers {
pub async fn list_servers(guild_id: u64) -> Result<Vec<Self>, tokio_postgres::Error> {
let client = DatabaseController::new().await?.client;
let rows = client.query("
SELECT * FROM gameservers
WHERE guild_owner = $1
", &[&(guild_id as i64)]).await?;
let mut servers = Vec::new();
for row in rows {
servers.push(Self {
server_name: row.get("server_name"),
game_name: row.get("game_name"),
guild_owner: row.get("guild_owner"),
guild_channel: row.get("guild_channel"),
ip_address: row.get("ip_address")
});
}
Ok(servers)
}
pub async fn add_server(
guild_id: u64,
server_name: &str,
game_name: &str,
guild_channel: u64,
ip_address: &str
) -> Result<(), tokio_postgres::Error> {
let client = DatabaseController::new().await?.client;
client.execute("
INSERT INTO gameservers (server_name, game_name, guild_owner, guild_channel, ip_address)
VALUES ($1, $2, $3, $4, $5)
", &[&server_name, &game_name, &(guild_id as i64), &(guild_channel as i64), &ip_address]).await?;
Ok(())
}
pub async fn remove_server(guild_id: u64, server_name: &str) -> Result<(), tokio_postgres::Error> {
let client = DatabaseController::new().await?.client;
client.execute("
DELETE FROM gameservers
WHERE guild_owner = $1 AND server_name = $2
", &[&(guild_id as i64), &server_name]).await?;
Ok(())
}
pub async fn update_server(
guild_id: u64,
server_name: &str,
game_name: &str,
guild_channel: u64,
ip_address: &str
) -> Result<(), tokio_postgres::Error> {
let client = DatabaseController::new().await?.client;
client.execute("
UPDATE gameservers
SET game_name = $1, guild_channel = $2, ip_address = $3
WHERE guild_owner = $4 AND server_name = $5
", &[&game_name, &(guild_channel as i64), &ip_address, &(guild_id as i64), &server_name]).await?;
Ok(())
}
pub async fn update_name(guild_id: u64, server_name: &str, new_name: &str) -> Result<(), tokio_postgres::Error> {
let client = DatabaseController::new().await?.client;
client.execute("
UPDATE gameservers
SET server_name = $1
WHERE guild_owner = $2 AND server_name = $3
", &[&new_name, &(guild_id as i64), &server_name]).await?;
Ok(())
}
}

View File

@ -1 +1,2 @@
pub mod mpservers;
pub mod gameservers;