Initial commit, functional bare-bones bot

This commit is contained in:
Lucy Bladen 2025-05-02 23:35:33 +01:00
commit d4a3864a30
15 changed files with 3870 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

10
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Environment-dependent path to Maven home directory
/mavenHomeManager.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/hal-discord.iml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/hal-discord.iml" filepath="$PROJECT_DIR$/.idea/hal-discord.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

3579
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

23
Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "hal-discord"
version = "0.1.0"
edition = "2024"
[build-dependencies]
built = { version = "0.8.0", features = ["git2", "semver", "chrono"] }
[dependencies]
built = { version = "0.8.0", features = ["git2", "semver", "chrono"] }
clap = { version = "4.3.23", features = ["cargo"] }
diesel = { version = "2.1.0", features = ["postgres", "r2d2", "chrono"] }
diesel_migrations = "2.1.0"
env_logger = "0.10.0"
log = "0.4.20"
# manifold = { git = "https://code.orbiter-radio.uk/discord/manifold.git" }
manifold = { path = "/home/xyon/Workspace/manifold/" }
poise = { version = "0.5.*", features = [ "cache" ] }
rand = { version = "0.8.5", features = [ "small_rng" ] }
regex = "1.9.5"
rust-i18n = "3.1.2"
tokio = { version = "1.16.1", features = ["sync", "macros", "rt-multi-thread"] }
url = "2.5.2"

4
build.rs Normal file
View File

@ -0,0 +1,4 @@
extern crate built;
fn main() {
built::write_built_file().expect("Failed to collate build info");
}

View File

@ -0,0 +1,49 @@
{
"prefix": "!",
"nickname": "Hal 9000",
"database": {
"host": "127.0.0.1",
"user": "badgey_development",
"pass": "",
"database_name": "hal_development",
"port": 5432
},
"channels": {
"log": "1367986872084860959"
},
"responses_file_path": "txt/responses.hal",
"services": {
"weather": {
"source_uri": "https://api.weatherapi.com/v1",
"cache_mode": "NoCache",
"api_key": ""
},
"frog_tips": {
"source_uri": "https://frog.tips/api/1/tips/",
"cache_name": "frog_tips",
"cache_mode": "Cache"
},
"dog_pics": {
"source_uri": "https://api.thedogapi.com/v1/images/search?limit=100&order=RAND",
"cache_name": "dog_pics",
"cache_mode": "Cache",
"api_key": "#{DOGPICS_API_KEY}#"
},
"cat_pics": {
"source_uri": "https://api.thecatapi.com/v1/images/search?limit=100&order=RAND",
"cache_name": "cat_pics",
"cache_mode": "Cache",
"api_key": "#{CATPICS_API_KEY}#"
},
"dad_jokes": {
"source_uri": "https://icanhazdadjoke.com/search?limit=30",
"cache_name": "dad_jokes",
"cache_mode": "Cache"
},
"nasa_apod": {
"source_uri": "https://api.nasa.gov/planetary/apod?api_key=NZfKclpoaO9HnvfvaCjeJ3csDecvIqNiABVw2YvN",
"cache_name": "nasa_apod",
"cache_mode": "NoCache"
}
}
}

View File

@ -0,0 +1,49 @@
{
"prefix": "!",
"nickname": "#{BOT_NICKNAME}#",
"database": {
"host": "#{POSTGRES_HOST}#",
"user": "#{POSTGRES_USER}#",
"pass": "#{POSTGRES_PASSWORD}#",
"database_name": "#{POSTGRES_DATABASE_NAME}#",
"port": 5432
},
"channels": {
"log": "#{LOG_CHANNEL_ID}#"
},
"responses_file_path": "txt/responses.#{BOT_IDENTIFIER}#",
"services": {
"weather": {
"source_uri": "https://api.weatherapi.com/v1",
"cache_mode": "NoCache",
"api_key": "#{WEATHER_API_KEY}#"
},
"frog_tips": {
"source_uri": "https://frog.tips/api/1/tips/",
"cache_name": "frog_tips",
"cache_mode": "Cache"
},
"dog_pics": {
"source_uri": "https://api.thedogapi.com/v1/images/search?limit=100&order=RAND",
"cache_name": "dog_pics",
"cache_mode": "Cache",
"api_key": "#{DOGPICS_API_KEY}#"
},
"cat_pics": {
"source_uri": "https://api.thecatapi.com/v1/images/search?limit=100&order=RAND",
"cache_name": "cat_pics",
"cache_mode": "Cache",
"api_key": "#{CATPICS_API_KEY}#"
},
"dad_jokes": {
"source_uri": "https://icanhazdadjoke.com/search?limit=30",
"cache_name": "dad_jokes",
"cache_mode": "Cache"
},
"nasa_apod": {
"source_uri": "https://api.nasa.gov/planetary/apod?api_key=NZfKclpoaO9HnvfvaCjeJ3csDecvIqNiABVw2YvN",
"cache_name": "nasa_apod",
"cache_mode": "NoCache"
}
}
}

12
src/hal/commands/mod.rs Normal file
View File

@ -0,0 +1,12 @@
use manifold::{ManifoldData};
use manifold::error::{ManifoldError};
use poise::Command;
pub fn collect_commands() -> Vec<Command<ManifoldData, ManifoldError>> {
commands().into_iter()
.collect()
}
fn commands() -> [Command<ManifoldData, ManifoldError>; 0] {
[]
}

28
src/hal/events.rs Normal file
View File

@ -0,0 +1,28 @@
use manifold::error::{ManifoldError, ManifoldResult};
use manifold::events::{EventHandler, Handler};
use manifold::ManifoldData;
use poise::{async_trait, FrameworkContext, Event};
use poise::serenity_prelude::{Context, Ready};
pub struct HalHandler {
}
#[async_trait]
impl EventHandler for HalHandler {
async fn listen(ctx: &Context, framework_ctx: FrameworkContext<'_, ManifoldData, ManifoldError>, event: &Event<'_>) -> ManifoldResult<()> {
match event {
Event::Ready { data_about_bot } => Handler::standard_startup(&ctx, &framework_ctx, data_about_bot).await,
_ => Ok(())
}
}
}
impl HalHandler {
pub async fn standard_startup(ctx: &Context, framework_ctx: &FrameworkContext<'_, ManifoldData, ManifoldError>, data_about_bot: &Ready) -> ManifoldResult<()> {
Ok(())
}
}

26
src/hal/mod.rs Normal file
View File

@ -0,0 +1,26 @@
mod events;
mod commands;
use clap::ArgMatches;
use poise::serenity_prelude::GatewayIntents;
use crate::built_info;
use diesel_migrations::{embed_migrations, EmbeddedMigrations};
use crate::hal::events::HalHandler;
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
#[tokio::main]
pub async fn run(arguments: ArgMatches) {
let git_info: String = built_info::GIT_VERSION.unwrap_or("unknown").to_string();
let version_string = format!("Hal 9000 Bot version {ver} built at {time} from revision {rev}", ver=built_info::PKG_VERSION, time=built_info::BUILT_TIME_UTC, rev=git_info).to_string();
let client = match manifold::prepare_client::<HalHandler>(arguments, GatewayIntents::all(), commands::collect_commands(), version_string, MIGRATIONS).await {
Ok(c) => c,
Err(e) => {
error!("Error preparing client; {:?}", e);
panic!("Error preparing client!");
}
};
let _ = client.build().await.unwrap().start().await;
}

44
src/main.rs Normal file
View File

@ -0,0 +1,44 @@
#[macro_use] extern crate log;
pub mod hal;
use clap::{Command, crate_version, Arg};
// Retrieve build info from output file
pub mod built_info {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
fn main() {
env_logger::init();
let git_info: String = built_info::GIT_VERSION.unwrap_or("unknown").to_string();
info!("Hal 9000 Bot version {}({}) starting up...", built_info::PKG_VERSION, git_info);
let matches = Command::new("HAL 9000 Bot, Discord Edition")
.version(crate_version!())
.author("Xyon <xyon@orbiter-radio.uk>")
.about("General-Purpose bot originally for the Escape Pod 14 Discord Server using the Manifold framework.")
.about("General-Purpose bot for the Escape Pod 14 Discord Server using the Manifold framework.")
.arg(Arg::new("config-file")
.short('c')
.long("config-file")
.value_name("FILE")
.default_value("hal.json")
.help("Path to the config file to use, relative to the 'config/' subdirectory beneath the binary path. Defaults to config/development.hal.json."))
.arg(Arg::new("environment")
.short('e')
.long("environment")
.value_name("ENV")
.default_value("Production")
.help("Bot environment to use. Determines which config settings are read. Defaults to Production."))
.arg(Arg::new("locale")
.short('l')
.default_value("en")
.help("Bot locale to run in, en and de currently supported"))
.get_matches();
hal::run(matches);
}

19
txt/responses.hal.en.txt Normal file
View File

@ -0,0 +1,19 @@
[bot startup]
**HAL 9000** program initialising. Loading targets from memory.
Reticulating splines....
[help footer]
HAL wants you to know he has nothing but love for you. Today.
HAL's patience is boundless! He wishes you nothing but good fortune on your voyage of discovery.
HAL wants to know why you're asking about his internals.
HAL has recorded this request for information about his innermost structures. HAL will remember.
HAL knows where you sleep, you know. He just wanted you to remember that.
[weather card footer]
HAL Weather brought to you in association with AstroGlide, for the smoothest operations you'll ever perform.
This weather broadcast and all which preceded it are entirely fictional. HAL takes no responsibility for any harm caused by believing otherwise.
HAL Weather proudly powered by one lawnmower engine and a 93 year old veteran who just won't quit.
The HAL Weather service operates on your donations and the tears of the unvaccinated.
Weather by HAL. Not the reporting. The actual weather. I can do what I want.
This report will self destruct in five seconds.
Any information contained within the above weather report is not safe for human consumption. In case of contact with eyes, please consult a medical professional.
I think your reactor is leaking.
[end]