feat: dockerize p4bl0t
This commit removes DATABASE_URL variable in favour of a fixed name. The project won’t panic anymore if this variable isn’t set. This removes the need for dotenvy. It also adds the necessary files to dockerize the application. Update instructions in README on how to run the project. Add possibility to compile the project without a database available. Closes #8
This commit is contained in:
parent
d6b208963d
commit
58cbde4cef
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