feat: dockerize p4bl0t #17
32
.dockerignore
Normal file
32
.dockerignore
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Include any files or directories that you don't want to be copied to your
|
||||||
|
# container here (e.g., local build artifacts, temporary files, etc.).
|
||||||
|
#
|
||||||
|
# For more help, visit the .dockerignore file reference guide at
|
||||||
|
# https://docs.docker.com/go/build-context-dockerignore/
|
||||||
|
|
||||||
|
**/.DS_Store
|
||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
/bin
|
||||||
|
/target
|
||||||
|
LICENSE
|
||||||
|
README.md
|
@ -1,2 +1 @@
|
|||||||
DISCORD_TOKEN=changeme
|
DISCORD_TOKEN=changeme
|
||||||
DATABASE_URL=sqlite:p4bl0t.db
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
/.env
|
/.env
|
||||||
*.db
|
*.db
|
||||||
/.sqlx/
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\nINSERT INTO guild_log_channels (guild_id, channel_id)\nVALUES ( ?1, ?2 )",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "5b44991d1514160fa00572e398f0577ad44f839a0470f9eeb89da8b5e77f0e03"
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\nSELECT channel_id\nFROM guild_log_channels\nWHERE guild_id = ?1",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "channel_id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "8444f7b7452a5ace6352aef943274f8a345a958257d896c7658b7700557959ab"
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\nDELETE FROM guild_log_channels\nWHERE guild_id = ?1 AND channel_id = ?2",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "d6e9f422d6ae29a00658f55165018119d1e13d407266440415dfcc17a97ba00e"
|
||||||
|
}
|
494
Cargo.lock
generated
494
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -10,12 +10,12 @@ homepage = "https://github.com/phundrak/p4bl0t"
|
|||||||
repository = "https://github.com/phundrak/p4bl0t"
|
repository = "https://github.com/phundrak/p4bl0t"
|
||||||
keywords = ["discord", "bot", "logging"]
|
keywords = ["discord", "bot", "logging"]
|
||||||
publish = false
|
publish = false
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
color-eyre = "0.6.2"
|
color-eyre = "0.6.2"
|
||||||
dotenvy = "0.15.7"
|
|
||||||
poise = { version = "0.5.7" }
|
poise = { version = "0.5.7" }
|
||||||
sqlx = { version = "0.7.2", features = ["sqlite", "tls-rustls", "runtime-tokio-rustls"] }
|
sqlx = { version = "0.7.3", features = ["sqlite", "tls-rustls", "runtime-tokio-rustls"] }
|
||||||
tokio = { version = "1.34.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.34.0", features = ["macros", "rt-multi-thread"] }
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
|
93
Dockerfile
Normal file
93
Dockerfile
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# Comments are provided throughout this file to help you get started.
|
||||||
|
# If you need more help, visit the Dockerfile reference guide at
|
||||||
|
# https://docs.docker.com/go/dockerfile-reference/
|
||||||
|
|
||||||
|
ARG RUST_VERSION=1.73.0
|
||||||
|
ARG APP_NAME=p4bl0t
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# xx is a helper for cross-compilation.
|
||||||
|
# See https://github.com/tonistiigi/xx/ for more information.
|
||||||
|
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.3.0 AS xx
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Create a stage for building the application.
|
||||||
|
FROM --platform=$BUILDPLATFORM rust:${RUST_VERSION}-alpine AS build
|
||||||
|
ARG APP_NAME
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy cross compilation utilities from the xx stage.
|
||||||
|
COPY --from=xx / /
|
||||||
|
|
||||||
|
# Install host build dependencies.
|
||||||
|
RUN apk add --no-cache clang lld musl-dev git file
|
||||||
|
|
||||||
|
# This is the architecture you’re building for, which is passed in by the builder.
|
||||||
|
# Placing it here allows the previous steps to be cached across architectures.
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
# Install cross compilation build dependencies.
|
||||||
|
RUN xx-apk add --no-cache musl-dev gcc
|
||||||
|
|
||||||
|
# Build the application.
|
||||||
|
# Leverage a cache mount to /usr/local/cargo/registry/
|
||||||
|
# for downloaded dependencies, a cache mount to /usr/local/cargo/git/db
|
||||||
|
# for git repository dependencies, and a cache mount to /app/target/ for
|
||||||
|
# compiled dependencies which will speed up subsequent builds.
|
||||||
|
# Leverage a bind mount to the src directory to avoid having to copy the
|
||||||
|
# source code into the container. Once built, copy the executable to an
|
||||||
|
# output directory before the cache mounted /app/target is unmounted.
|
||||||
|
RUN --mount=type=bind,source=src,target=src \
|
||||||
|
--mount=type=bind,source=Cargo.toml,target=Cargo.toml \
|
||||||
|
--mount=type=bind,source=Cargo.lock,target=Cargo.lock \
|
||||||
|
--mount=type=bind,source=build.rs,target=build.rs \
|
||||||
|
--mount=type=bind,source=.sqlx,target=.sqlx \
|
||||||
|
--mount=type=bind,source=migrations,target=migrations \
|
||||||
|
--mount=type=cache,target=/app/target/,id=rust-cache-${APP_NAME}-${TARGETPLATFORM} \
|
||||||
|
--mount=type=cache,target=/usr/local/cargo/git/db \
|
||||||
|
--mount=type=cache,target=/usr/local/cargo/registry/ \
|
||||||
|
<<EOF
|
||||||
|
set -e
|
||||||
|
# xx-cargo build --locked --release --target-dir ./target
|
||||||
|
xx-cargo build --locked --target-dir ./target
|
||||||
|
cp ./target/$(xx-cargo --print-target-triple)/debug/$APP_NAME /bin/server
|
||||||
|
xx-verify /bin/server
|
||||||
|
EOF
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Create a new stage for running the application that contains the minimal
|
||||||
|
# runtime dependencies for the application. This often uses a different base
|
||||||
|
# image from the build stage where the necessary files are copied from the build
|
||||||
|
# stage.
|
||||||
|
#
|
||||||
|
# The example below uses the alpine image as the foundation for running the app.
|
||||||
|
# By specifying the "3.18" tag, it will use version 3.18 of alpine. If
|
||||||
|
# reproducability is important, consider using a digest
|
||||||
|
# (e.g., alpine@sha256:664888ac9cfd28068e062c991ebcff4b4c7307dc8dd4df9e728bedde5c449d91).
|
||||||
|
FROM alpine:3.18 AS final
|
||||||
|
|
||||||
|
# Create a non-privileged user that the app will run under.
|
||||||
|
# See https://docs.docker.com/go/dockerfile-user-best-practices/
|
||||||
|
ARG UID=10001
|
||||||
|
RUN adduser \
|
||||||
|
--disabled-password \
|
||||||
|
--gecos "" \
|
||||||
|
--home "/nonexistent" \
|
||||||
|
--shell "/sbin/nologin" \
|
||||||
|
--no-create-home \
|
||||||
|
--uid "${UID}" \
|
||||||
|
appuser
|
||||||
|
WORKDIR /app
|
||||||
|
RUN chown -R appuser /app
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Copy the executable from the "build" stage.
|
||||||
|
COPY --from=build /bin/server /bin/
|
||||||
|
|
||||||
|
# Expose the port that the application listens on.
|
||||||
|
# EXPOSE 8080
|
||||||
|
|
||||||
|
# What the container should run when it is started.
|
||||||
|
CMD ["/bin/server"]
|
22
README.md
22
README.md
@ -3,11 +3,24 @@
|
|||||||
p4bl0t is a simple logging bot for Discord written in Rust.
|
p4bl0t is a simple logging bot for Discord written in Rust.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
### Preparation
|
||||||
In order to run p4bl0t, head over to your [developer
|
In order to run p4bl0t, you will need a Discord token with which your
|
||||||
|
bot will authenticate. Head over to your [developer
|
||||||
portal](https://discord.com/developers) on Discord’s website, and
|
portal](https://discord.com/developers) on Discord’s website, and
|
||||||
create a bot there. Then, copy the `.env.example` file to a `.env`
|
create a bot there. You will be able to get the bot’s token there.
|
||||||
file and fill in the details.
|
|
||||||
|
### Docker
|
||||||
|
The easiest way to run p4bl0t is using Docker. Copy
|
||||||
|
`docker-compose.example.yml` to `docker-compose.yml` and modify the
|
||||||
|
`DISCORD_TOKEN` variable.
|
||||||
|
|
||||||
|
Then, you can simply run
|
||||||
|
```sh
|
||||||
|
docker compose up # or docker-compose on some machines
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building and running it yourself
|
||||||
|
Copy the `.env.example` file to a `.env` file and fill in the details.
|
||||||
```sh
|
```sh
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
emacs .env
|
emacs .env
|
||||||
@ -27,7 +40,6 @@ cargo install sqlx-cli
|
|||||||
|
|
||||||
Setup your SQLite database.
|
Setup your SQLite database.
|
||||||
```sh
|
```sh
|
||||||
export DATABASE_URL=<your-database-url> # should be the same as in the .env file
|
|
||||||
sqlx database create
|
sqlx database create
|
||||||
sqlx migrate run
|
sqlx migrate run
|
||||||
```
|
```
|
||||||
|
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// generated by `sqlx migrate build-script`
|
||||||
|
fn main() {
|
||||||
|
// trigger recompilation when a new migration is added
|
||||||
|
println!("cargo:rerun-if-changed=migrations");
|
||||||
|
}
|
9
docker-compose.example.yml
Normal file
9
docker-compose.example.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
p4bl0t:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: final
|
||||||
|
environment:
|
||||||
|
DISCORD_TOKEN: changeme
|
||||||
|
volumes:
|
||||||
|
- ./p4bl0t.db:/app/p4bl0t.db
|
@ -1,10 +1,8 @@
|
|||||||
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
||||||
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
use poise::serenity_prelude::{ChannelId, GuildId};
|
use poise::serenity_prelude::{ChannelId, GuildId};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::{migrate::MigrateDatabase, Sqlite, SqlitePool};
|
||||||
use tracing::error;
|
use tracing::{error, info, debug};
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, sqlx::Error>;
|
pub type Result<T> = ::std::result::Result<T, sqlx::Error>;
|
||||||
|
|
||||||
@ -16,22 +14,23 @@ impl Database {
|
|||||||
/// The Sqlite database should already exist and have its
|
/// The Sqlite database should already exist and have its
|
||||||
/// migrations already executed.
|
/// migrations already executed.
|
||||||
///
|
///
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the environment variable `DATABASE_URL` is not set.
|
|
||||||
///
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will return an error if the Sqlite pool fails to
|
/// This function will return an error if the Sqlite pool fails to
|
||||||
/// create.
|
/// create.
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
Ok(Self(
|
let url = "sqlite:p4bl0t.db";
|
||||||
SqlitePool::connect(
|
if !Sqlite::database_exists(url).await? {
|
||||||
&env::var("DATABASE_URL")
|
info!("Creating database");
|
||||||
.expect("Missing enviroment variable DATABASE_URL"),
|
Sqlite::create_database(url).await?;
|
||||||
)
|
info!("Database created");
|
||||||
.await?,
|
}
|
||||||
))
|
debug!("Getting pool connection");
|
||||||
|
let pool = SqlitePool::connect(url).await?;
|
||||||
|
info!("Running migrations");
|
||||||
|
sqlx::migrate!().run(&pool).await?;
|
||||||
|
debug!("Database initialized");
|
||||||
|
Ok(Self(pool))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return from database all channels registered as loggers for a
|
/// Return from database all channels registered as loggers for a
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
#![warn(clippy::style, clippy::pedantic)]
|
#![warn(clippy::style, clippy::pedantic)]
|
||||||
|
|
||||||
mod utils;
|
|
||||||
mod db;
|
mod db;
|
||||||
mod discord;
|
mod discord;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
dotenvy::dotenv()?;
|
|
||||||
color_eyre::install()?;
|
|
||||||
utils::setup_logging();
|
utils::setup_logging();
|
||||||
|
color_eyre::install()?;
|
||||||
|
|
||||||
let bot = discord::make_bot();
|
let bot = discord::make_bot();
|
||||||
bot.run().await?;
|
bot.run().await?;
|
||||||
|
Loading…
Reference in New Issue
Block a user