Rust Migration
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export POSTGRES_USER=
|
||||
export POSTGRES_PASSWORD=
|
||||
export POSTGRES_DB=
|
||||
DISCORD_TOKEN=
|
||||
POSTGRES_USER=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_DB=
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
.idea/
|
||||
**/target/
|
||||
**/data/
|
||||
**/app/
|
||||
**/settings.json
|
||||
**/logs/
|
||||
**/audio/
|
||||
.env
|
||||
target/
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
audio/
|
||||
logs/
|
||||
settings.json
|
||||
|
||||
2414
Cargo.lock
generated
Normal file
2414
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "siren"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dotenv = "0.15.0"
|
||||
serenity = "0.11"
|
||||
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
reqwest = { version = "0.11.18", features = ["json"] }
|
||||
async-recursion = "1.0.4"
|
||||
log = "0.4.19"
|
||||
songbird = "0.3.2"
|
||||
env_logger = "0.10.0"
|
||||
18
Dockerfile
18
Dockerfile
@@ -1,10 +1,10 @@
|
||||
FROM amazoncorretto:17
|
||||
FROM rust:1.67 as builder
|
||||
RUN apt-get update && apt-get install -y cmake && rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /usr/src/siren
|
||||
COPY . .
|
||||
RUN cargo install --path .
|
||||
|
||||
ARG VERSION
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD https://repo.local.bensherriff.com/artifactory/libs-release/com/bensherriff/siren/${VERSION}/siren-${VERSION}.jar /usr/local/lib/
|
||||
RUN mv /usr/local/lib/siren-${VERSION}.jar /usr/local/lib/siren.jar
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "/usr/local/lib/siren.jar"]
|
||||
FROM debian:bullseye-slim
|
||||
RUN apt-get update && apt-get install -y libopus-dev ffmpeg youtube-dl && rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=builder /usr/local/cargo/bin/siren /usr/local/bin/siren
|
||||
CMD ["siren"]
|
||||
|
||||
6
Makefile
6
Makefile
@@ -3,10 +3,12 @@ include .version
|
||||
include .env
|
||||
|
||||
build:
|
||||
if docker inspect siren > /dev/null 2>&1; then docker rmi siren; fi; docker-compose build
|
||||
# if docker inspect siren > /dev/null 2>&1; then docker rmi siren; fi; docker-compose build
|
||||
docker build -t siren .
|
||||
|
||||
test:
|
||||
docker run --rm -it siren:latest bash
|
||||
# docker run --rm -it siren:latest bash
|
||||
docker run --env-file .env -it --rm --name siren siren:latest
|
||||
|
||||
up:
|
||||
if [[ ! $$(docker images -q siren 2> /dev/null) ]]; then docker-compose build; fi; \
|
||||
|
||||
72
README.md
72
README.md
@@ -1,72 +1,24 @@
|
||||
<img src="siren.png" alt="drawing" width="200"/>
|
||||
|
||||
# Siren
|
||||
A Java/Docker Discord music bot
|
||||
A D&D Bot built for Discord. Includes music support and assistant DM tools.
|
||||
|
||||
## Running
|
||||
Visit the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application.
|
||||
Guides and more information are available [here](https://discord.com/developers/docs/intro).
|
||||
|
||||
### OAuth2 URL Generator
|
||||
The bot requires the following permissions/scopes:
|
||||
- bot
|
||||
- applications.commands
|
||||
## Contributing
|
||||
Rust must be installed to run locally.
|
||||
|
||||
Furthermore, the following packages must be installed for [serenity-rs/songbird](https://github.com/serenity-rs/songbird)
|
||||
```
|
||||
https://discord.com/api/oauth2/authorize?client_id=<Client ID>&permissions=1088840792896&scope=applications.commands%20bot
|
||||
https://discord.com/api/oauth2/authorize?client_id=<Client ID>&permissions=5469678065984&scope=applications.commands%20bot - bot
|
||||
- text permissions
|
||||
- send messages
|
||||
- create public threads
|
||||
- create private threads
|
||||
- send messages in threads
|
||||
- send tts messages
|
||||
- embed links
|
||||
- attach files
|
||||
- read message history
|
||||
- mention everyone
|
||||
- use external emojis
|
||||
- use external stickers
|
||||
- add reactions
|
||||
- use slash commands
|
||||
- voice permissions
|
||||
- connect
|
||||
- speak
|
||||
- use voice activity
|
||||
- priority speaker
|
||||
- request to speak
|
||||
- use embedded activities
|
||||
- use soundboard
|
||||
- applications.commands
|
||||
sudo apt install libopus-dev
|
||||
sudo apt install ffmpeg
|
||||
sudo apt apt install youtube-dl
|
||||
```
|
||||
|
||||
The application can instead be tested from within a docker container.
|
||||
```
|
||||
make build
|
||||
make up
|
||||
docker build -t siren .
|
||||
docker run --env-file .env -it --rm --name siren siren
|
||||
```
|
||||
|
||||
## Development
|
||||
Build container
|
||||
|
||||
`make build`
|
||||
|
||||
Run container locally
|
||||
|
||||
```
|
||||
docker container run --name siren_test -d -t siren bash
|
||||
docker exec -it siren_test bash
|
||||
```
|
||||
|
||||
## Commands
|
||||
### Play
|
||||
|
||||
### Skip
|
||||
|
||||
### Stop
|
||||
|
||||
### Volume
|
||||
|
||||
### Pause
|
||||
|
||||
### Resume
|
||||
|
||||
### Settings
|
||||
View settings on the current guild.
|
||||
@@ -12,6 +12,7 @@ services:
|
||||
volumes:
|
||||
- ./app:/app
|
||||
environment:
|
||||
DISCORD_TOKEN: ${DISCORD_TOKEN}
|
||||
DATABASE_URL: jdbc:postgresql://db:5432/${POSTGRES_DB}
|
||||
DATABASE_USERNAME: ${POSTGRES_USER}
|
||||
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
|
||||
181
pom.xml
181
pom.xml
@@ -1,181 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.bensherriff</groupId>
|
||||
<artifactId>siren</artifactId>
|
||||
<version>${env.SIREN_VERSION}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central</id>
|
||||
<name>libs-release</name>
|
||||
<url>https://repo.local.bensherriff.com/artifactory/libs-release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots />
|
||||
<id>snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>https://repo.local.bensherriff.com/artifactory/libs-snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dv8tion</id>
|
||||
<name>m2-dv8tion</name>
|
||||
<url>https://m2.dv8tion.net/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>maven_central</id>
|
||||
<name>Maven Central</name>
|
||||
<url>https://repo.maven.apache.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central</id>
|
||||
<name>libs-release</name>
|
||||
<url>https://repo.local.bensherriff.com/artifactory/libs-release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<snapshots />
|
||||
<id>snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>https://repo.local.bensherriff.com/artifactory/libs-snapshot</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>ffc58a58b429-releases</name>
|
||||
<url>https://repo.local.bensherriff.com/artifactory/libs-release</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<properties>
|
||||
<jda.version>5.0.0-beta.8</jda.version>
|
||||
<lavaplayer.version>1.4.0</lavaplayer.version>
|
||||
<lavaplayer-natives-extra.version>1.3.13</lavaplayer-natives-extra.version>
|
||||
<jackson.version>2.14.2</jackson.version>
|
||||
<theokanning-openai-gpt3.version>0.12.0</theokanning-openai-gpt3.version>
|
||||
<postgresql.version>42.6.0</postgresql.version>
|
||||
<corenlp.version>4.2.0</corenlp.version>
|
||||
<slf4j.version>2.0.7</slf4j.version>
|
||||
<log4j.version>2.20.0</log4j.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>${jda.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.walkyst</groupId>
|
||||
<artifactId>lavaplayer-fork</artifactId>
|
||||
<version>${lavaplayer.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.theokanning.openai-gpt3-java</groupId>
|
||||
<artifactId>service</artifactId>
|
||||
<version>${theokanning-openai-gpt3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.stanford.nlp</groupId>
|
||||
<artifactId>stanford-corenlp</artifactId>
|
||||
<version>${corenlp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.stanford.nlp</groupId>
|
||||
<artifactId>stanford-corenlp</artifactId>
|
||||
<version>${corenlp.version}</version>
|
||||
<classifier>models</classifier>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- <shadedArtifactAttached>true</shadedArtifactAttached>-->
|
||||
<!-- <shadedClassifierName>All</shadedClassifierName>-->
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>*:*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>reference.conf</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Main-Class>com.bensherriff.siren.Main</Main-Class>
|
||||
<Specification-Title>${project.artifactId}</Specification-Title>
|
||||
<Specification-Version>${project.version}</Specification-Version>
|
||||
<Implementation-Title>${project.artifactId}</Implementation-Title>
|
||||
<Implementation-Version>${project.version}</Implementation-Version>
|
||||
<Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
6
src/commands/audio/mod.rs
Normal file
6
src/commands/audio/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub mod pause;
|
||||
pub mod play;
|
||||
pub mod resume;
|
||||
pub mod skip;
|
||||
pub mod stop;
|
||||
pub mod volume;
|
||||
0
src/commands/audio/pause.rs
Normal file
0
src/commands/audio/pause.rs
Normal file
18
src/commands/audio/play.rs
Normal file
18
src/commands/audio/play.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use log::debug;
|
||||
use serenity::{model::prelude::{interaction::application_command::CommandDataOption, application_command::CommandDataOptionValue}, builder::CreateApplicationCommand};
|
||||
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
|
||||
|
||||
pub async fn run(command: &ApplicationCommandInteraction) -> String {
|
||||
let track_option: &CommandDataOptionValue = command.data.options.get(0).expect("Expected track option").resolved.as_ref().expect("Expected track option to be resolved");
|
||||
debug!("Play command executed with track: {:?}", track_option);
|
||||
"Playing xyz".to_string()
|
||||
}
|
||||
|
||||
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||
command.name("play").description("Plays the given track").create_option(|option| { option
|
||||
.name("track")
|
||||
.description("The track to be played")
|
||||
.kind(serenity::model::prelude::command::CommandOptionType::String)
|
||||
.required(true)
|
||||
})
|
||||
}
|
||||
0
src/commands/audio/resume.rs
Normal file
0
src/commands/audio/resume.rs
Normal file
0
src/commands/audio/skip.rs
Normal file
0
src/commands/audio/skip.rs
Normal file
0
src/commands/audio/stop.rs
Normal file
0
src/commands/audio/stop.rs
Normal file
0
src/commands/audio/volume.rs
Normal file
0
src/commands/audio/volume.rs
Normal file
0
src/commands/help.rs
Normal file
0
src/commands/help.rs
Normal file
2
src/commands/mod.rs
Normal file
2
src/commands/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod ping;
|
||||
pub mod audio;
|
||||
11
src/commands/ping.rs
Normal file
11
src/commands/ping.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use log::debug;
|
||||
use serenity::{model::prelude::interaction::application_command::CommandDataOption, builder::CreateApplicationCommand};
|
||||
|
||||
pub fn run(_options: &[CommandDataOption]) -> String {
|
||||
debug!("Ping command executed");
|
||||
"pong".to_string()
|
||||
}
|
||||
|
||||
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||
command.name("ping").description("Replies with pong")
|
||||
}
|
||||
94
src/main.rs
Normal file
94
src/main.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
|
||||
use dotenv::dotenv;
|
||||
use log::{error, warn, info};
|
||||
use serenity::async_trait;
|
||||
use serenity::framework::StandardFramework;
|
||||
use serenity::model::application::interaction::{Interaction, InteractionResponseType};
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::http::Http;
|
||||
use serenity::model::prelude::GuildId;
|
||||
use serenity::prelude::*;
|
||||
|
||||
mod commands;
|
||||
struct Handler;
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
if let Interaction::ApplicationCommand(command) = interaction {
|
||||
let content: String = match command.data.name.as_str() {
|
||||
"ping" => commands::ping::run(&command.data.options),
|
||||
"play" => commands::audio::play::run(&command).await,
|
||||
_ => "Unknown command".to_string()
|
||||
};
|
||||
|
||||
if let Err(why) = command.create_interaction_response(&ctx.http, |response: &mut serenity::builder::CreateInteractionResponse<'_>| {
|
||||
response
|
||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||
.interaction_response_data(|message: &mut serenity::builder::CreateInteractionResponseData<'_>| message.content(content))
|
||||
}).await {
|
||||
warn!("Cannot respond to slash command: {}", why);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
for guild in ready.guilds {
|
||||
if let Some(guild) = guild.id.to_guild_cached(&ctx.cache) {
|
||||
info!("{} is connected to {}", ready.user.name, guild.name);
|
||||
let commands: Result<Vec<serenity::model::prelude::command::Command>, SerenityError> = GuildId::set_application_commands(&guild.id, &ctx.http, |commands| {
|
||||
commands.create_application_command(|command: &mut serenity::builder::CreateApplicationCommand| { commands::ping::register(command) })
|
||||
.create_application_command(|command: &mut serenity::builder::CreateApplicationCommand| { commands::audio::play::register(command) })
|
||||
}).await;
|
||||
match commands {
|
||||
Ok(commands) => info!("Registered {} commands", commands.len()),
|
||||
Err(why) => error!("Could not register commands: {:?}", why)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
dotenv().ok();
|
||||
|
||||
let token: String = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
|
||||
let intents: GatewayIntents = GatewayIntents::all();
|
||||
|
||||
let http: Http = Http::new(&token);
|
||||
let (owners, _bot_id) = match http.get_current_application_info().await {
|
||||
Ok(info) => {
|
||||
let mut owners: HashSet<serenity::model::id::UserId> = HashSet::new();
|
||||
if let Some(team) = info.team {
|
||||
owners.insert(team.owner_user_id);
|
||||
} else {
|
||||
owners.insert(info.owner.id);
|
||||
}
|
||||
match http.get_current_user().await {
|
||||
Ok(bot) => (owners, bot.id),
|
||||
Err(why) => panic!("Could not access the bot id: {:?}", why)
|
||||
}
|
||||
},
|
||||
Err(why) => panic!("Could not access application info: {:?}", why)
|
||||
};
|
||||
|
||||
let framework = StandardFramework::new()
|
||||
.configure(|c| c
|
||||
.owners(owners)
|
||||
.prefix("!")
|
||||
);
|
||||
|
||||
let mut client = Client::builder(token, intents)
|
||||
.event_handler(Handler)
|
||||
.framework(framework)
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
|
||||
if let Err(why) = client.start_autosharded().await {
|
||||
error!("An error occurred while running the client: {:?}", why);
|
||||
}
|
||||
}
|
||||
14
start.sh
14
start.sh
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#if [ -f /config.txt ]; then
|
||||
# echo "configuration file found"
|
||||
# mv /config.txt .
|
||||
#fi
|
||||
#
|
||||
#if [ ! -f JMusicBot-${VERSION}.jar ]; then
|
||||
# wget https://github.com/jagrosh/MusicBot/releases/download/${VERSION}/JMusicBot-${VERSION}.jar
|
||||
#fi
|
||||
#
|
||||
#java -Dnogui=true -jar JMusicBot-${VERSION}.jar
|
||||
|
||||
java -jar /usr/local/lib/siren.jar
|
||||
Reference in New Issue
Block a user