From 3c475664ac1ee6f4c7b9e0cec9f77a4624ad2711 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Sat, 23 Sep 2023 23:35:09 +0200 Subject: [PATCH 01/21] Remove OpenSSL dep --- COMPILING.md | 8 +-- Cargo.lock | 151 --------------------------------------------------- Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 156 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index 56c784d..2b9c7f8 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -27,17 +27,17 @@ sudo pacman -S base-devel sudo dnf install gcc ``` -Additionally, you will need to install CMake and OpenSSL (Linux only). On Windows, you can download CMake [here](https://cmake.org/download/). On Linux, you can use your package manager to install them: +Additionally, you will need to install CMake. On Windows, you can download CMake [here](https://cmake.org/download/). On Linux, you can use your package manager to install it: ```sh # Debian/Ubuntu -sudo apt install cmake libssl-dev +sudo apt install cmake # Arch -sudo pacman -S cmake openssl +sudo pacman -S cmake # Fedora -sudo dnf install cmake openssl-devel +sudo dnf install cmake ``` ## Compiling diff --git a/Cargo.lock b/Cargo.lock index 331a3af..bd4ce83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,16 +328,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -580,21 +570,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.0" @@ -940,19 +915,6 @@ dependencies = [ "tokio-rustls 0.24.1", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1409,24 +1371,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nix" version = "0.23.2" @@ -1531,50 +1475,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "ordered-float" version = "2.10.0" @@ -1910,13 +1810,11 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", - "hyper-tls", "ipnet", "js-sys", "log", "mime", "mime_guess", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1926,7 +1824,6 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-native-tls", "tokio-rustls 0.24.1", "tokio-util", "tower-service", @@ -2068,15 +1965,6 @@ dependencies = [ "libsamplerate-sys", ] -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -2099,29 +1987,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.19" @@ -2614,16 +2479,6 @@ dependencies = [ "syn 2.0.37", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.23.4" @@ -2888,12 +2743,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "vergen" version = "3.2.0" diff --git a/Cargo.toml b/Cargo.toml index e60abe8..64539d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ librespot = { version = "0.4.2", default-features = false } log = "0.4.20" protobuf = "2.28.0" redis = { version = "0.23.3", optional = true } -reqwest = "0.11.20" +reqwest = { version = "0.11.20", default-features = false } samplerate = "0.2.4" serde = "1.0.188" serde_json = "1.0.107" From 1393d04ebc2662a392419c6512eb58b6ef13f2b5 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Sat, 23 Sep 2023 23:50:28 +0200 Subject: [PATCH 02/21] Add aarch64 compiler support --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cargo/config.toml b/.cargo/config.toml index 913f2d5..3707b70 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,3 +4,5 @@ protocol = "sparse" [target.x86_64-pc-windows-gnu] rustflags = "-C link-args=-lssp" # Does not compile without this line +[target.aarch64-unknown-linux-gnu] +rustflags = "-C linker=aarch64-linux-gnu-gcc" \ No newline at end of file From baa4e044ca4860e516669dce24af8585bcc0e80f Mon Sep 17 00:00:00 2001 From: Tyrone Faulhaber <20131658+spectrapulse@users.noreply.github.com> Date: Sun, 24 Sep 2023 11:43:30 +0000 Subject: [PATCH 03/21] Added arm64 support to image - Modified Dockerfile to cross-compilate to x86_64 and arm64 - Modified build-push.yml workflow and changed conditions to run workflow - Modified build-push.yml workflow to build form x86_64 and arm64 - Modified build-push.yml workflow cache and push to GitHub's Container Registry - Modified build-push.yml workflow and added build step to login to GitHub's Container Registry - Modified build-push.yml workflow and added build step to generate image metadata - Modified build-push.yml workflow docker/build-push-action step to v5 --- .github/workflows/build-push.yml | 60 +++++++++++++++++++++++++------- Dockerfile | 37 +++++++++++++++----- 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index b04fb13..045f3d1 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -1,34 +1,70 @@ -name: Build and push to repository +name: Build and push to registry on: push: - branches: [ "main" ] + branches: [ "main", "dev" ] + tags: [ "v*.*.*" ] + pull_request: + branches: [ "main", "dev" ] + workflow_dispatch: + +permissions: + packages: write jobs: build-and-push: - name: Build Docker image and push to repository + name: Build Docker image and push to registry runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - + - name: Set up Docker buildx id: buildx uses: docker/setup-buildx-action@v2 - - - name: Login to repository + + - name: Login to private registry uses: docker/login-action@v2 with: registry: ${{ secrets.REGISTRY_URL }} username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} - + + - name: Login to GitHub's container registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate image metadata + id: spoticord # used in next step + uses: docker/metadata-action@v5 + with: + # list of Docker images to use as base name for tags + images: | + ghcr.io/spoticord/spoticord + ${{ secrets.REGISTRY_URL }}/spoticord/spoticord + # Docker tags based on the following events/attributes + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + - name: Build image and push to registry - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: context: . - file: ./Dockerfile - tags: | - ${{ secrets.REGISTRY_URL }}/spoticord/spoticord:latest - push: ${{ github.ref == 'refs/heads/main' }} + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.spoticord.outputs.tags }} + labels: ${{ steps.spoticord.outputs.labels }} + # Some basic caching of the layers... + cache-from: ghcr.io/spoticord/spoticord:latest-cache + cache-to: ghcr.io/spoticord/spoticord:latest-cache diff --git a/Dockerfile b/Dockerfile index 266e340..5b7f864 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,44 @@ # Builder -FROM rust:1.72.1-buster as builder +FROM --platform=linux/amd64 rust:1.72.1-buster as builder WORKDIR /app # Add extra build dependencies here -RUN apt-get update && apt-get install -y cmake +RUN apt-get update && apt-get install -yqq \ + cmake gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu COPY . . -# Remove `--features stats` if you want to deploy without stats collection -RUN cargo install --path . --features stats +RUN rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu + +# Remove `--features=stats` if you want to deploy without stats collection +RUN cargo build --features=stats --release \ + --target=x86_64-unknown-linux-gnu --target=aarch64-unknown-linux-gnu # Runtime FROM debian:buster-slim -WORKDIR /app +ARG TARGETPLATFORM +ENV TARGETPLATFORM=$TARGETPLATFORM # Add extra runtime dependencies here -RUN apt-get update && apt-get install -y openssl ca-certificates && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -yqq --no-install-recommends \ + openssl ca-certificates && rm -rf /var/lib/apt/lists/* -# Copy spoticord binary from builder -COPY --from=builder /usr/local/cargo/bin/spoticord ./spoticord +# Copy spoticord binaries from builder to /tmp +COPY --from=builder \ + /app/target/x86_64-unknown-linux-gnu/release/spoticord /tmp/x86_64 +COPY --from=builder \ + /app/target/aarch64-unknown-linux-gnu/release/spoticord /tmp/aarch64 -CMD ["./spoticord"] \ No newline at end of file +# Copy appropiate binary for target arch from /tmp +RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ + cp /tmp/x86_64 /usr/local/bin/spoticord; \ + elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ + cp /tmp/aarch64 /usr/local/bin/spoticord; \ + fi + +# Delete unused binaries +RUN rm -rvf /tmp/x86_64 /tmp/aarch64 + +ENTRYPOINT [ "/usr/local/bin/spoticord" ] From d8c8573f75e18fa33036b8779d0bcc66d174a2cb Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 18:39:34 +0200 Subject: [PATCH 04/21] Update build-push.yml Remove private registry in favor of GHCR --- .github/workflows/build-push.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 045f3d1..0852225 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -24,13 +24,6 @@ jobs: id: buildx uses: docker/setup-buildx-action@v2 - - name: Login to private registry - uses: docker/login-action@v2 - with: - registry: ${{ secrets.REGISTRY_URL }} - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_PASSWORD }} - - name: Login to GitHub's container registry if: github.event_name != 'pull_request' uses: docker/login-action@v2 @@ -46,7 +39,6 @@ jobs: # list of Docker images to use as base name for tags images: | ghcr.io/spoticord/spoticord - ${{ secrets.REGISTRY_URL }}/spoticord/spoticord # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} From 0eadc020d054b6b60120037e4af3e55d7ba8bb26 Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:15:30 +0200 Subject: [PATCH 05/21] =?UTF-8?q?=F0=9F=A4=B7=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-push.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 0852225..3b4bf6b 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -8,13 +8,14 @@ on: branches: [ "main", "dev" ] workflow_dispatch: -permissions: - packages: write - jobs: build-and-push: name: Build Docker image and push to registry runs-on: ubuntu-latest + + permissions: + packages: write + contents: read steps: - name: Checkout code From 7405e1e66225e4453d865a0f44be57ea83949a60 Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:53:00 +0200 Subject: [PATCH 06/21] It's war between us and GHCR now --- Dockerfile | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5b7f864..c3443a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,10 @@ COPY . . RUN rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu # Remove `--features=stats` if you want to deploy without stats collection -RUN cargo build --features=stats --release \ - --target=x86_64-unknown-linux-gnu --target=aarch64-unknown-linux-gnu +#RUN cargo build --features=stats --release \ +# --target=x86_64-unknown-linux-gnu --target=aarch64-unknown-linux-gnu + +RUN echo woah # Runtime FROM debian:buster-slim @@ -22,23 +24,23 @@ ARG TARGETPLATFORM ENV TARGETPLATFORM=$TARGETPLATFORM # Add extra runtime dependencies here -RUN apt-get update && apt-get install -yqq --no-install-recommends \ - openssl ca-certificates && rm -rf /var/lib/apt/lists/* +# RUN apt-get update && apt-get install -yqq --no-install-recommends \ +# openssl ca-certificates && rm -rf /var/lib/apt/lists/* # Copy spoticord binaries from builder to /tmp -COPY --from=builder \ - /app/target/x86_64-unknown-linux-gnu/release/spoticord /tmp/x86_64 -COPY --from=builder \ - /app/target/aarch64-unknown-linux-gnu/release/spoticord /tmp/aarch64 +#COPY --from=builder \ +# /app/target/x86_64-unknown-linux-gnu/release/spoticord /tmp/x86_64 +#COPY --from=builder \ +# /app/target/aarch64-unknown-linux-gnu/release/spoticord /tmp/aarch64 # Copy appropiate binary for target arch from /tmp -RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ - cp /tmp/x86_64 /usr/local/bin/spoticord; \ - elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ - cp /tmp/aarch64 /usr/local/bin/spoticord; \ - fi +#RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ +# cp /tmp/x86_64 /usr/local/bin/spoticord; \ +# elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ +# cp /tmp/aarch64 /usr/local/bin/spoticord; \ +# fi # Delete unused binaries -RUN rm -rvf /tmp/x86_64 /tmp/aarch64 +# RUN rm -rvf /tmp/x86_64 /tmp/aarch64 ENTRYPOINT [ "/usr/local/bin/spoticord" ] From 0b70de72c99fb057e75f13a332c874ee1e9a720f Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 22:04:53 +0200 Subject: [PATCH 07/21] Update build-push.yml --- .github/workflows/build-push.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 3b4bf6b..40e1d15 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -39,7 +39,7 @@ jobs: with: # list of Docker images to use as base name for tags images: | - ghcr.io/spoticord/spoticord + ghcr.io/SpoticordMusic/spoticord # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} @@ -59,5 +59,5 @@ jobs: tags: ${{ steps.spoticord.outputs.tags }} labels: ${{ steps.spoticord.outputs.labels }} # Some basic caching of the layers... - cache-from: ghcr.io/spoticord/spoticord:latest-cache - cache-to: ghcr.io/spoticord/spoticord:latest-cache + cache-from: ghcr.io/SpoticordMusic/spoticord:latest-cache + cache-to: ghcr.io/SpoticordMusic/spoticord:latest-cache From 0c73046101fb931c44813e5ee8b2971c6ef66d55 Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 22:09:06 +0200 Subject: [PATCH 08/21] Update build-push.yml --- .github/workflows/build-push.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 40e1d15..7f31bda 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -39,7 +39,7 @@ jobs: with: # list of Docker images to use as base name for tags images: | - ghcr.io/SpoticordMusic/spoticord + ghcr.io/spoticordmusic/spoticord # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} @@ -59,5 +59,5 @@ jobs: tags: ${{ steps.spoticord.outputs.tags }} labels: ${{ steps.spoticord.outputs.labels }} # Some basic caching of the layers... - cache-from: ghcr.io/SpoticordMusic/spoticord:latest-cache - cache-to: ghcr.io/SpoticordMusic/spoticord:latest-cache + cache-from: ghcr.io/spoticordmusic/spoticord:latest-cache + cache-to: ghcr.io/spoticordmusic/spoticord:latest-cache From c33d1ea2cea75eb11630334e89e84a2e32a4c04d Mon Sep 17 00:00:00 2001 From: Daniel <46288749+DaXcess@users.noreply.github.com> Date: Sun, 24 Sep 2023 22:12:15 +0200 Subject: [PATCH 09/21] Update Dockerfile --- Dockerfile | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index c3443a7..38e72a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,10 +12,8 @@ COPY . . RUN rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu # Remove `--features=stats` if you want to deploy without stats collection -#RUN cargo build --features=stats --release \ -# --target=x86_64-unknown-linux-gnu --target=aarch64-unknown-linux-gnu - -RUN echo woah +RUN cargo build --features=stats --release \ + --target=x86_64-unknown-linux-gnu --target=aarch64-unknown-linux-gnu # Runtime FROM debian:buster-slim @@ -25,22 +23,22 @@ ENV TARGETPLATFORM=$TARGETPLATFORM # Add extra runtime dependencies here # RUN apt-get update && apt-get install -yqq --no-install-recommends \ -# openssl ca-certificates && rm -rf /var/lib/apt/lists/* +# openssl ca-certificates && rm -rf /var/lib/apt/lists/* # Copy spoticord binaries from builder to /tmp -#COPY --from=builder \ -# /app/target/x86_64-unknown-linux-gnu/release/spoticord /tmp/x86_64 -#COPY --from=builder \ -# /app/target/aarch64-unknown-linux-gnu/release/spoticord /tmp/aarch64 +COPY --from=builder \ + /app/target/x86_64-unknown-linux-gnu/release/spoticord /tmp/x86_64 +COPY --from=builder \ + /app/target/aarch64-unknown-linux-gnu/release/spoticord /tmp/aarch64 # Copy appropiate binary for target arch from /tmp -#RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ -# cp /tmp/x86_64 /usr/local/bin/spoticord; \ -# elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ -# cp /tmp/aarch64 /usr/local/bin/spoticord; \ -# fi +RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ + cp /tmp/x86_64 /usr/local/bin/spoticord; \ + elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ + cp /tmp/aarch64 /usr/local/bin/spoticord; \ + fi # Delete unused binaries -# RUN rm -rvf /tmp/x86_64 /tmp/aarch64 +RUN rm -rvf /tmp/x86_64 /tmp/aarch64 ENTRYPOINT [ "/usr/local/bin/spoticord" ] From fddf1ae68a3391b05589a50749587fcde532aeb0 Mon Sep 17 00:00:00 2001 From: Tyrone Faulhaber <20131658+spectrapulse@users.noreply.github.com> Date: Sun, 24 Sep 2023 23:08:28 +0200 Subject: [PATCH 10/21] Update build-push.yml --- .github/workflows/build-push.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 7f31bda..866f19f 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -39,7 +39,7 @@ jobs: with: # list of Docker images to use as base name for tags images: | - ghcr.io/spoticordmusic/spoticord + ghcr.io/kankerdev/spoticord/bot # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} @@ -59,5 +59,5 @@ jobs: tags: ${{ steps.spoticord.outputs.tags }} labels: ${{ steps.spoticord.outputs.labels }} # Some basic caching of the layers... - cache-from: ghcr.io/spoticordmusic/spoticord:latest-cache - cache-to: ghcr.io/spoticordmusic/spoticord:latest-cache + cache-from: ghcr.io/kankerdev/spoticord/bot:latest-cache + cache-to: ghcr.io/kankerdev/spoticord/bot:latest-cache From 2daed2f7048d27d0b31ca9f88b1fc0e0273eee3b Mon Sep 17 00:00:00 2001 From: DaXcess Date: Mon, 25 Sep 2023 12:01:44 +0200 Subject: [PATCH 11/21] Added changelog and removed total guilds in KV in favor of Discord API --- CHANGELOG.md | 34 +++++++++++++++++++++++++++++++++- src/main.rs | 8 -------- src/stats.rs | 6 ------ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4666bd..9175e13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ # Changelog + +## 2.1.1 | September 23rd 2023 +Reduced the amount of CPU that the bot uses from ~15%-25% per user to 1%-2% per user (percentage per core, benched on an AMD Ryzen 9 5950X). + +### Changes +* Fixed issue #20 + +**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v.2.1.0...v2.1.1 + +## 2.1.0 | September 20th 2023 +So, it's been a while since I worked on this project, and some bugs have since been discovered. +The main focus for this version is to stop using multiple processes for every player, and instead do everything in threads. + +### Changes + +- Remove metrics, as I wasn't using this feature anyways +- Bring back KV for storing total/active sessions, as prometheus is no longer being used +- Allocate new players in-memory, instead of using subprocesses +- Fix issue #17 +- Fix some issues with the auto-disconnect +- Removed the automatic device switching on bot join, which was causing some people to not be able to use the bot +- Force communication through the closest Spotify AP, reducing latency +- Potential jitter reduction +- Enable autoplay +- After skipping a song, you will no longer hear a tiny bit of the previous song after the silence + + +**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v2.0.0...v.2.1.0 + +### Issues +- Currently, the CPU usage is much higher than it used to be. I really wanted to push this update out before taking the time to do some optimizations, as the bot and server are still easily able to hold up the limited amount of Spoticord users (and v2.0.0 was just falling apart). Issue is being tracked in #20 + ## 2.0.0 | June 8th 2023 -- Initial Release +- Initial Release \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 89593f7..bc4cca2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,9 +85,6 @@ async fn main() { let shard_manager = client.shard_manager.clone(); - #[cfg(feature = "stats")] - let cache = client.cache_and_http.cache.clone(); - #[cfg(unix)] let mut term: Option> = Some(Box::new( tokio::signal::unix::signal(SignalKind::terminate()) @@ -104,13 +101,8 @@ async fn main() { _ = tokio::time::sleep(std::time::Duration::from_secs(60)) => { #[cfg(feature = "stats")] { - let guild_count = cache.guilds().len(); let active_count = session_manager.get_active_session_count().await; - if let Err(why) = stats_manager.set_server_count(guild_count) { - error!("Failed to update server count: {why}"); - } - if let Err(why) = stats_manager.set_active_count(active_count) { error!("Failed to update active count: {why}"); } diff --git a/src/stats.rs b/src/stats.rs index 7b54e2c..7dde73a 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -12,12 +12,6 @@ impl StatsManager { Ok(StatsManager { redis }) } - pub fn set_server_count(&self, count: usize) -> Result<()> { - let mut con = self.redis.get_connection()?; - - con.set("sc-bot-total-servers", count.to_string()) - } - pub fn set_active_count(&self, count: usize) -> Result<()> { let mut con = self.redis.get_connection()?; From 1201e4431389a2776c4440eceaadd4e6e71303a3 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Mon, 25 Sep 2023 16:37:12 +0200 Subject: [PATCH 12/21] Remove unnecessary impl and add dev changelog --- CHANGELOG.md | 9 +++++ src/bot/events.rs | 84 +++++++++++++++++++++++------------------------ 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9175e13..e01de79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## Current dev branch +In this section of the change log all current changes that have been made since the last version will be documented. This list will grow as more changes are made, until the next release. Upon the next release the list will be cleared. + +### Changes +* Removed OpenSSL dependency +* Added aarch64 support +* Added cross compilation to Github Actions +* Added `dev` branch to Github Actions + ## 2.1.1 | September 23rd 2023 Reduced the amount of CPU that the bot uses from ~15%-25% per user to 1%-2% per user (percentage per core, benched on an AMD Ryzen 9 5950X). diff --git a/src/bot/events.rs b/src/bot/events.rs index 3668150..f70639a 100644 --- a/src/bot/events.rs +++ b/src/bot/events.rs @@ -54,23 +54,22 @@ impl EventHandler for Handler { // INTERACTION_CREATE event, emitted when the bot receives an interaction (slash command, button, etc.) async fn interaction_create(&self, ctx: Context, interaction: Interaction) { match interaction { - Interaction::ApplicationCommand(command) => self.handle_command(ctx, command).await, - Interaction::MessageComponent(component) => self.handle_component(ctx, component).await, + Interaction::ApplicationCommand(command) => handle_command(ctx, command).await, + Interaction::MessageComponent(component) => handle_component(ctx, component).await, _ => {} } } } -impl Handler { - async fn handle_command(&self, ctx: Context, command: ApplicationCommandInteraction) { - enforce_guild!(command); +async fn handle_command(ctx: Context, command: ApplicationCommandInteraction) { + enforce_guild!(command); - // Commands must only be executed inside of guilds + // Commands must only be executed inside of guilds - let guild_id = match command.guild_id { - Some(guild_id) => guild_id, - None => { - if let Err(why) = command + let guild_id = match command.guild_id { + Some(guild_id) => guild_id, + None => { + if let Err(why) = command .create_interaction_response(&ctx.http, |response| { response .kind(serenity::model::prelude::interaction::InteractionResponseType::ChannelMessageWithSource) @@ -82,32 +81,32 @@ impl Handler { error!("Failed to send run-in-guild-only error message: {}", why); } - return; - } - }; + return; + } + }; - trace!( - "Received command interaction: command={} user={} guild={}", - command.data.name, - command.user.id, - guild_id - ); + trace!( + "Received command interaction: command={} user={} guild={}", + command.data.name, + command.user.id, + guild_id + ); - let data = ctx.data.read().await; - let command_manager = data.get::().expect("to contain a value"); + let data = ctx.data.read().await; + let command_manager = data.get::().expect("to contain a value"); - command_manager.execute_command(&ctx, command).await; - } + command_manager.execute_command(&ctx, command).await; +} - async fn handle_component(&self, ctx: Context, component: MessageComponentInteraction) { - enforce_guild!(component); +async fn handle_component(ctx: Context, component: MessageComponentInteraction) { + enforce_guild!(component); - // Components can only be interacted with inside of guilds + // Components can only be interacted with inside of guilds - let guild_id = match component.guild_id { - Some(guild_id) => guild_id, - None => { - if let Err(why) = component + let guild_id = match component.guild_id { + Some(guild_id) => guild_id, + None => { + if let Err(why) = component .create_interaction_response(&ctx.http, |response| { response .kind(serenity::model::prelude::interaction::InteractionResponseType::ChannelMessageWithSource) @@ -119,20 +118,19 @@ impl Handler { error!("Failed to send run-in-guild-only error message: {}", why); } - return; - } - }; + return; + } + }; - trace!( - "Received component interaction: command={} user={} guild={}", - component.data.custom_id, - component.user.id, - guild_id - ); + trace!( + "Received component interaction: command={} user={} guild={}", + component.data.custom_id, + component.user.id, + guild_id + ); - let data = ctx.data.read().await; - let command_manager = data.get::().expect("to contain a value"); + let data = ctx.data.read().await; + let command_manager = data.get::().expect("to contain a value"); - command_manager.execute_component(&ctx, component).await; - } + command_manager.execute_component(&ctx, component).await; } From 35ca9603e60ba2681f44547f750ffca4b24a6774 Mon Sep 17 00:00:00 2001 From: Tyrone Faulhaber <20131658+spectrapulse@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:30:23 +0200 Subject: [PATCH 13/21] Update build-push.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use GitHub's provided vars to avoid headaches for everyone™ --- .github/workflows/build-push.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 866f19f..dfbcbf6 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -8,15 +8,14 @@ on: branches: [ "main", "dev" ] workflow_dispatch: +permissions: + packages: write + contents: read + jobs: build-and-push: name: Build Docker image and push to registry runs-on: ubuntu-latest - - permissions: - packages: write - contents: read - steps: - name: Checkout code uses: actions/checkout@v3 @@ -39,7 +38,7 @@ jobs: with: # list of Docker images to use as base name for tags images: | - ghcr.io/kankerdev/spoticord/bot + ghcr.io/${{ github.repository }} # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} @@ -59,5 +58,5 @@ jobs: tags: ${{ steps.spoticord.outputs.tags }} labels: ${{ steps.spoticord.outputs.labels }} # Some basic caching of the layers... - cache-from: ghcr.io/kankerdev/spoticord/bot:latest-cache - cache-to: ghcr.io/kankerdev/spoticord/bot:latest-cache + cache-from: ghcr.io/${{ github.repository }}:latest-cache + cache-to: ghcr.io/${{ github.repository }}:latest-cache From 57935081a1f7aab5b223972f87c7f2e331f73cd8 Mon Sep 17 00:00:00 2001 From: Tyrone Faulhaber <20131658+spectrapulse@users.noreply.github.com> Date: Mon, 25 Sep 2023 19:17:26 +0200 Subject: [PATCH 14/21] Update build-push.yml --- .github/workflows/build-push.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index dfbcbf6..7a216c4 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -32,13 +32,17 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - uses: Entepotenz/change-string-case-action@v1 # https://github.com/orgs/community/discussions/10553 + id: repo-uri-string + with: + string: ghcr.io/${{ github.repository }} + - name: Generate image metadata - id: spoticord # used in next step + id: docker-meta # used in next step uses: docker/metadata-action@v5 with: # list of Docker images to use as base name for tags - images: | - ghcr.io/${{ github.repository }} + images: ${{ steps.repo-uri-string.outputs.lowercase }} # Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable={{is_default_branch}} @@ -55,8 +59,8 @@ jobs: context: . platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.spoticord.outputs.tags }} - labels: ${{ steps.spoticord.outputs.labels }} + tags: ${{ steps.docker-meta.outputs.tags }} + labels: ${{ steps.docker-meta.outputs.labels }} # Some basic caching of the layers... - cache-from: ghcr.io/${{ github.repository }}:latest-cache - cache-to: ghcr.io/${{ github.repository }}:latest-cache + cache-from: ${{ steps.repo-uri-string.outputs.lowercase }}:latest-cache + cache-to: ${{ steps.repo-uri-string.outputs.lowercase }}:latest-cache From f385a9d5b21437ea183ddb4e91de09487e5228cf Mon Sep 17 00:00:00 2001 From: Tyrone Faulhaber <20131658+spectrapulse@users.noreply.github.com> Date: Mon, 25 Sep 2023 19:23:24 +0200 Subject: [PATCH 15/21] Update build-push.yml --- .github/workflows/build-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 7a216c4..8e143c3 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -32,7 +32,7 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: Entepotenz/change-string-case-action@v1 # https://github.com/orgs/community/discussions/10553 + - uses: Entepotenz/change-string-case-action-min-dependencies@v1 # https://github.com/orgs/community/discussions/10553 id: repo-uri-string with: string: ghcr.io/${{ github.repository }} From b5999fe718bbb61788a374a9176c6a0365971ce3 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Tue, 26 Sep 2023 09:46:15 +0200 Subject: [PATCH 16/21] Removed hardcoded URL in /join --- CHANGELOG.md | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- src/bot/commands/core/link.rs | 15 +- src/bot/commands/music/join.rs | 5 +- src/bot/commands/music/playing.rs | 226 +++++++++++++----------------- src/consts.rs | 17 +++ src/main.rs | 25 ++-- 8 files changed, 147 insertions(+), 146 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e01de79..c67aa04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ In this section of the change log all current changes that have been made since * Added aarch64 support * Added cross compilation to Github Actions * Added `dev` branch to Github Actions +* Removed hardcoded URL in the /join command ## 2.1.1 | September 23rd 2023 Reduced the amount of CPU that the bot uses from ~15%-25% per user to 1%-2% per user (percentage per core, benched on an AMD Ryzen 9 5950X). diff --git a/Cargo.lock b/Cargo.lock index bd4ce83..beace56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2269,6 +2269,7 @@ dependencies = [ "dotenv", "env_logger 0.10.0", "hex", + "lazy_static", "librespot", "log", "protobuf", @@ -2280,7 +2281,6 @@ dependencies = [ "serenity", "songbird", "thiserror", - "time", "tokio", "zerocopy 0.7.5", ] diff --git a/Cargo.toml b/Cargo.toml index 64539d2..bf9151f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ anyhow = "1.0.75" dotenv = "0.15.0" env_logger = "0.10.0" hex = "0.4.3" +lazy_static = "1.4.0" librespot = { version = "0.4.2", default-features = false } log = "0.4.20" protobuf = "2.28.0" @@ -27,7 +28,6 @@ serde_json = "1.0.107" serenity = { version = "0.11.6", features = ["framework", "cache", "standard_framework"], default-features = false } songbird = "0.3.2" thiserror = "1.0.48" -time = "0.3.28" tokio = { version = "1.32.0", features = ["rt", "full"] } zerocopy = "0.7.5" diff --git a/src/bot/commands/core/link.rs b/src/bot/commands/core/link.rs index 14b238f..bf606d6 100644 --- a/src/bot/commands/core/link.rs +++ b/src/bot/commands/core/link.rs @@ -8,6 +8,7 @@ use serenity::{ use crate::{ bot::commands::{respond_message, CommandOutput}, + consts::SPOTICORD_ACCOUNTS_URL, database::{Database, DatabaseError}, utils::embed::{EmbedBuilder, Status}, }; @@ -39,8 +40,11 @@ pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandO } if let Ok(request) = database.get_user_request(command.user.id.to_string()).await { - let base = std::env::var("SPOTICORD_ACCOUNTS_URL").expect("to be present"); - let link = format!("{}/spotify/{}", base, request.token); + let link = format!( + "{}/spotify/{}", + SPOTICORD_ACCOUNTS_URL.as_str(), + request.token + ); respond_message( &ctx, @@ -106,8 +110,11 @@ pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandO .await { Ok(request) => { - let base = std::env::var("SPOTICORD_ACCOUNTS_URL").expect("to be present"); - let link = format!("{}/spotify/{}", base, request.token); + let link = format!( + "{}/spotify/{}", + SPOTICORD_ACCOUNTS_URL.as_str(), + request.token + ); respond_message( &ctx, diff --git a/src/bot/commands/music/join.rs b/src/bot/commands/music/join.rs index fcb5fcc..8c5cf5f 100644 --- a/src/bot/commands/music/join.rs +++ b/src/bot/commands/music/join.rs @@ -7,6 +7,7 @@ use serenity::{ use crate::{ bot::commands::{defer_message, respond_message, update_message, CommandOutput}, + consts::SPOTICORD_ACCOUNTS_URL, session::manager::{SessionCreateError, SessionManager}, utils::embed::{EmbedBuilder, Status}, }; @@ -241,7 +242,7 @@ pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandO &command, EmbedBuilder::new() .title("Cannot join voice channel") - .description("You need to link your Spotify account. Use or go to [the accounts website](https://account.spoticord.com/) to get started.") + .description(format!("You need to link your Spotify account. Use or go to [the accounts website]({}) to get started.", SPOTICORD_ACCOUNTS_URL.as_str())) .status(Status::Error) .build(), ) @@ -255,7 +256,7 @@ pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandO &command, EmbedBuilder::new() .title("Cannot join voice channel") - .description("Spoticord no longer has access to your Spotify account. Use or go to [the accounts website](https://account.spoticord.com/) to relink your Spotify account.") + .description(format!("Spoticord no longer has access to your Spotify account. Use or go to [the accounts website]({}) to relink your Spotify account.", SPOTICORD_ACCOUNTS_URL.as_str())) .status(Status::Error) .build(), ).await; diff --git a/src/bot/commands/music/playing.rs b/src/bot/commands/music/playing.rs index 9dbe5ad..f0aae85 100644 --- a/src/bot/commands/music/playing.rs +++ b/src/bot/commands/music/playing.rs @@ -30,20 +30,22 @@ pub const NAME: &str = "playing"; pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutput { Box::pin(async move { - let not_playing = async { - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("Cannot get track info") - .icon_url("https://spoticord.com/forbidden.png") - .description("I'm currently not playing any music in this server") - .status(Status::Error) - .build(), - true, - ) - .await; - }; + macro_rules! not_playing { + () => { + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("Cannot get track info") + .icon_url("https://spoticord.com/forbidden.png") + .description("I'm currently not playing any music in this server") + .status(Status::Error) + .build(), + true, + ) + .await; + }; + } let data = ctx.data.read().await; let session_manager = data @@ -51,62 +53,50 @@ pub fn command(ctx: Context, command: ApplicationCommandInteraction) -> CommandO .expect("to contain a value") .clone(); - let session = match session_manager + let Some(session) = session_manager .get_session(command.guild_id.expect("to contain a value")) .await - { - Some(session) => session, - None => { - not_playing.await; + else { + not_playing!(); - return; - } + return; }; - let owner = match session.owner().await { - Some(owner) => owner, - None => { - not_playing.await; + let Some(owner) = session.owner().await else { + not_playing!(); - return; - } + return; }; // Get Playback Info from session - let pbi = match session.playback_info().await { - Some(pbi) => pbi, - None => { - not_playing.await; + let Some(pbi) = session.playback_info().await else { + not_playing!(); - return; - } + return; }; // Get owner of session - let owner = match utils::discord::get_user(&ctx, owner).await { - Some(user) => user, - None => { - // This shouldn't happen + let Some(owner) = utils::discord::get_user(&ctx, owner).await else { + // This shouldn't happen - error!("Could not find user with ID: {owner}"); + error!("Could not find user with ID: {owner}"); - respond_message( - &ctx, - &command, - EmbedBuilder::new() - .title("[INTERNAL ERROR] Cannot get track info") - .description(format!( - "Could not find user with ID `{}`\nThis is an issue with the bot!", - owner - )) - .status(Status::Error) - .build(), - true, - ) - .await; + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("[INTERNAL ERROR] Cannot get track info") + .description(format!( + "Could not find user with ID `{}`\nThis is an issue with the bot!", + owner + )) + .status(Status::Error) + .build(), + true, + ) + .await; - return; - } + return; }; // Get metadata @@ -188,48 +178,39 @@ pub fn component(ctx: Context, mut interaction: MessageComponentInteraction) -> .clone(); // Check if session still exists - let mut session = match session_manager + let Some(mut session) = session_manager .get_session(interaction.guild_id.expect("to contain a value")) .await - { - Some(session) => session, - None => { - error_edit( - "Cannot perform action", - "I'm currently not playing any music in this server", - ) - .await; + else { + error_edit( + "Cannot perform action", + "I'm currently not playing any music in this server", + ) + .await; - return; - } + return; }; // Check if the session contains an owner - let owner = match session.owner().await { - Some(owner) => owner, - None => { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; + let Some(owner) = session.owner().await else { + error_edit( + "Cannot change playback state", + "I'm currently not playing any music in this server", + ) + .await; - return; - } + return; }; // Get Playback Info from session - let pbi = match session.playback_info().await { - Some(pbi) => pbi, - None => { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; + let Some(pbi) = session.playback_info().await else { + error_edit( + "Cannot change playback state", + "I'm currently not playing any music in this server", + ) + .await; - return; - } + return; }; // Check if the user is the owner of the session @@ -244,30 +225,27 @@ pub fn component(ctx: Context, mut interaction: MessageComponentInteraction) -> } // Get owner of session - let owner = match utils::discord::get_user(&ctx, owner).await { - Some(user) => user, - None => { - // This shouldn't happen + let Some(owner) = utils::discord::get_user(&ctx, owner).await else { + // This shouldn't happen - error!("Could not find user with ID: {owner}"); + error!("Could not find user with ID: {owner}"); - respond_component_message( - &ctx, - &interaction, - EmbedBuilder::new() - .title("[INTERNAL ERROR] Cannot get track info") - .description(format!( - "Could not find user with ID `{}`\nThis is an issue with the bot!", - owner - )) - .status(Status::Error) - .build(), - true, - ) - .await; + respond_component_message( + &ctx, + &interaction, + EmbedBuilder::new() + .title("[INTERNAL ERROR] Cannot get track info") + .description(format!( + "Could not find user with ID `{}`\nThis is an issue with the bot!", + owner + )) + .status(Status::Error) + .build(), + true, + ) + .await; - return; - } + return; }; // Send the desired command to the session @@ -370,34 +348,28 @@ async fn update_embed(interaction: &mut MessageComponentInteraction, ctx: &Conte .clone(); // Check if session still exists - let session = match session_manager + let Some(session) = session_manager .get_session(interaction.guild_id.expect("to contain a value")) .await - { - Some(session) => session, - None => { - error_edit( - "Cannot perform action", - "I'm currently not playing any music in this server", - ) - .await; + else { + error_edit( + "Cannot perform action", + "I'm currently not playing any music in this server", + ) + .await; - return; - } + return; }; // Get Playback Info from session - let pbi = match session.playback_info().await { - Some(pbi) => pbi, - None => { - error_edit( - "Cannot change playback state", - "I'm currently not playing any music in this server", - ) - .await; + let Some(pbi) = session.playback_info().await else { + error_edit( + "Cannot change playback state", + "I'm currently not playing any music in this server", + ) + .await; - return; - } + return; }; let (title, description, thumbnail) = get_metadata(&pbi); diff --git a/src/consts.rs b/src/consts.rs index c050977..d3326bf 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,3 +1,5 @@ +use lazy_static::lazy_static; + #[cfg(not(debug_assertions))] pub const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -8,3 +10,18 @@ pub const MOTD: &str = "some good 'ol music"; /// The time it takes for Spoticord to disconnect when no music is being played pub const DISCONNECT_TIME: u64 = 5 * 60; + +lazy_static! { + pub static ref DISCORD_TOKEN: String = + std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN environment variable"); + pub static ref DATABASE_URL: String = + std::env::var("DATABASE_URL").expect("missing DATABASE_URL environment variable"); + pub static ref SPOTICORD_ACCOUNTS_URL: String = std::env::var("SPOTICORD_ACCOUNTS_URL") + .expect("missing SPOTICORD_ACCOUNTS_URL environment variable"); +} + +#[cfg(feature = "stats")] +lazy_static! { + pub static ref KV_URL: String = + std::env::var("KV_URL").expect("missing KV_URL environment variable"); +} diff --git a/src/main.rs b/src/main.rs index bc4cca2..f8b6f01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,18 @@ use dotenv::dotenv; -use crate::{bot::commands::CommandManager, database::Database, session::manager::SessionManager}; +#[cfg(feature = "stats")] +use crate::consts::KV_URL; + +use crate::{ + bot::commands::CommandManager, + consts::{DATABASE_URL, DISCORD_TOKEN, MOTD}, + database::Database, + session::manager::SessionManager, +}; use log::*; use serenity::{framework::StandardFramework, prelude::GatewayIntents, Client}; use songbird::SerenityInit; -use std::{any::Any, env, process::exit}; +use std::{any::Any, process::exit}; #[cfg(unix)] use tokio::signal::unix::SignalKind; @@ -41,7 +49,7 @@ async fn main() { env_logger::init(); info!("It's a good day"); - info!(" - Spoticord {}", time::OffsetDateTime::now_utc().year()); + info!(" - Spoticord, {}", MOTD); let result = dotenv(); @@ -54,19 +62,14 @@ async fn main() { warn!("No .env file found, expecting all necessary environment variables"); } - let token = env::var("DISCORD_TOKEN").expect("a token in the environment"); - let db_url = env::var("DATABASE_URL").expect("a database URL in the environment"); - #[cfg(feature = "stats")] - let stats_manager = - StatsManager::new(env::var("KV_URL").expect("a redis URL in the environment")) - .expect("Failed to connect to redis"); + let stats_manager = StatsManager::new(KV_URL.as_str()).expect("Failed to connect to redis"); let session_manager = SessionManager::new(); // Create client let mut client = Client::builder( - token, + DISCORD_TOKEN.as_str(), GatewayIntents::GUILDS | GatewayIntents::GUILD_VOICE_STATES, ) .event_handler(crate::bot::events::Handler) @@ -78,7 +81,7 @@ async fn main() { { let mut data = client.data.write().await; - data.insert::(Database::new(db_url, None)); + data.insert::(Database::new(DATABASE_URL.as_str(), None)); data.insert::(CommandManager::new()); data.insert::(session_manager.clone()); } From e4752444cf17ee86cbfdb8b245d0e3386771a5b3 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Tue, 26 Sep 2023 10:09:58 +0200 Subject: [PATCH 17/21] Trying to reduce the amount of deps --- Cargo.lock | 8 -------- Cargo.toml | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index beace56..3317a76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1727,8 +1727,6 @@ dependencies = [ "itoa", "percent-encoding", "ryu", - "sha1_smol", - "socket2 0.4.9", "url", ] @@ -2139,12 +2137,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "shannon" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index bf9151f..1ef97c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,13 +20,13 @@ lazy_static = "1.4.0" librespot = { version = "0.4.2", default-features = false } log = "0.4.20" protobuf = "2.28.0" -redis = { version = "0.23.3", optional = true } +redis = { version = "0.23.3", optional = true, default-features = false } reqwest = { version = "0.11.20", default-features = false } samplerate = "0.2.4" serde = "1.0.188" serde_json = "1.0.107" -serenity = { version = "0.11.6", features = ["framework", "cache", "standard_framework"], default-features = false } -songbird = "0.3.2" +serenity = { version = "0.11.6", features = ["framework", "cache", "standard_framework", "rustls_backend", "gateway"], default-features = false } +songbird = { version = "0.3.2", features = ["driver", "serenity-rustls"], default-features = false } thiserror = "1.0.48" tokio = { version = "1.32.0", features = ["rt", "full"] } zerocopy = "0.7.5" From d93758e2504b2c8c7add8956fc4ea14fe47d0e34 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Tue, 26 Sep 2023 13:56:55 +0200 Subject: [PATCH 18/21] Fixed potential resource leak --- src/session/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/session/mod.rs b/src/session/mod.rs index 5a00063..e6f9b2c 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -24,7 +24,7 @@ use songbird::{ create_player, input::{Codec, Container, Input, Reader}, tracks::TrackHandle, - Call, Event, EventContext, EventHandler, + Call, Event, EventContext, EventHandler, Songbird, }; use std::{ ops::{Deref, DerefMut}, @@ -46,6 +46,7 @@ struct InnerSpoticordSession { session_manager: SessionManager, + songbird: Arc, call: Arc>, track: Option, player: Option, @@ -89,6 +90,7 @@ impl SpoticordSession { text_channel_id, http: ctx.http.clone(), session_manager: session_manager.clone(), + songbird: songbird.clone(), call: call.clone(), track: None, player: None, @@ -97,7 +99,11 @@ impl SpoticordSession { }; let mut instance = Self(Arc::new(RwLock::new(inner))); - instance.create_player(ctx).await?; + if let Err(why) = instance.create_player(ctx).await { + songbird.remove(guild_id).await.ok(); + + return Err(why); + } let mut call = call.lock().await; @@ -499,17 +505,13 @@ impl InnerSpoticordSession { .remove_session(self.guild_id, self.owner) .await; - let mut call = self.call.lock().await; - if let Some(track) = self.track.take() { if let Err(why) = track.stop() { error!("Failed to stop track: {:?}", why); } - } + }; - call.remove_all_global_events(); - - if let Err(why) = call.leave().await { + if let Err(why) = self.songbird.remove(self.guild_id).await { error!("Failed to leave voice channel: {:?}", why); } } From 4a90cb87187705d2021db5fa9e325efb81113fcd Mon Sep 17 00:00:00 2001 From: DaXcess Date: Tue, 26 Sep 2023 14:56:31 +0200 Subject: [PATCH 19/21] Nah that didn't work, here's some auto-disconnect bugfixes --- Cargo.lock | 16 ++++++++-------- src/player/mod.rs | 4 ++-- src/session/manager.rs | 8 ++++---- src/session/mod.rs | 28 ++++++++++++++++++++++++---- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3317a76..5db581a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -531,9 +531,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fixedbitset" @@ -2400,9 +2400,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -2413,15 +2413,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] diff --git a/src/player/mod.rs b/src/player/mod.rs index b651852..ef03233 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -318,13 +318,13 @@ impl PlayerTask { match pbi.as_mut() { Some(pbi) => { pbi.update_track(spotify_id, current); - pbi.update_pos_dur(position_ms, duration_ms, true); + pbi.update_pos_dur(position_ms, duration_ms, playing); } None => { *pbi = Some(PlaybackInfo::new( duration_ms, position_ms, - true, + playing, current, spotify_id, )); diff --git a/src/session/manager.rs b/src/session/manager.rs index 5d3d186..d639b2d 100644 --- a/src/session/manager.rs +++ b/src/session/manager.rs @@ -56,11 +56,9 @@ impl InnerSessionManager { session: SpoticordSession, guild_id: GuildId, owner_id: UserId, - ) -> Result<(), SessionCreateError> { + ) { self.sessions.insert(guild_id, session); self.owner_map.insert(owner_id, guild_id); - - Ok(()) } /// Remove a session @@ -147,7 +145,9 @@ impl SessionManager { .write() .await .create_session(session, guild_id, owner_id) - .await + .await; + + Ok(()) } /// Remove a session diff --git a/src/session/mod.rs b/src/session/mod.rs index e6f9b2c..a0f0ca5 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -24,7 +24,7 @@ use songbird::{ create_player, input::{Codec, Container, Input, Reader}, tracks::TrackHandle, - Call, Event, EventContext, EventHandler, Songbird, + Call, Event, EventContext, EventHandler, }; use std::{ ops::{Deref, DerefMut}, @@ -36,6 +36,12 @@ use tokio::sync::{Mutex, RwLockReadGuard, RwLockWriteGuard}; #[derive(Clone)] pub struct SpoticordSession(Arc>); +impl Drop for SpoticordSession { + fn drop(&mut self) { + log::trace!("drop SpoticordSession"); + } +} + struct InnerSpoticordSession { owner: Option, guild_id: GuildId, @@ -46,7 +52,6 @@ struct InnerSpoticordSession { session_manager: SessionManager, - songbird: Arc, call: Arc>, track: Option, player: Option, @@ -90,7 +95,6 @@ impl SpoticordSession { text_channel_id, http: ctx.http.clone(), session_manager: session_manager.clone(), - songbird: songbird.clone(), call: call.clone(), track: None, player: None, @@ -342,6 +346,8 @@ impl SpoticordSession { timer.tick().await; timer.tick().await; + trace!("Ring ring, time to check :)"); + // Make sure this task has not been aborted, if it has this will automatically stop execution. tokio::task::yield_now().await; @@ -351,6 +357,8 @@ impl SpoticordSession { .map(|pbi| pbi.is_playing) .unwrap_or(false); + trace!("is_playing = {is_playing}"); + if !is_playing { info!("Player is not playing, disconnecting"); session @@ -511,9 +519,13 @@ impl InnerSpoticordSession { } }; - if let Err(why) = self.songbird.remove(self.guild_id).await { + let mut call = self.call.lock().await; + + if let Err(why) = call.leave().await { error!("Failed to leave voice channel: {:?}", why); } + + call.remove_all_global_events(); } } @@ -523,10 +535,12 @@ impl EventHandler for SpoticordSession { match ctx { EventContext::DriverDisconnect(_) => { debug!("Driver disconnected, leaving voice channel"); + trace!("Arc strong count: {}", Arc::strong_count(&self.0)); self.disconnect().await; } EventContext::ClientDisconnect(who) => { trace!("Client disconnected, {}", who.user_id.to_string()); + trace!("Arc strong count: {}", Arc::strong_count(&self.0)); if let Some(session) = self .session_manager() @@ -547,3 +561,9 @@ impl EventHandler for SpoticordSession { return None; } } + +impl Drop for InnerSpoticordSession { + fn drop(&mut self) { + log::trace!("drop InnerSpoticordSession"); + } +} From d2a2b2205d39fc40167106d3cb855c36c42ff4b3 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Thu, 28 Sep 2023 13:48:46 +0200 Subject: [PATCH 20/21] Prepare for v2.1.2 --- CHANGELOG.md | 10 ++++++---- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c67aa04..8213056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ # Changelog -## Current dev branch -In this section of the change log all current changes that have been made since the last version will be documented. This list will grow as more changes are made, until the next release. Upon the next release the list will be cleared. +## 2.1.2 | September 28th 2023 ### Changes * Removed OpenSSL dependency @@ -9,6 +8,9 @@ In this section of the change log all current changes that have been made since * Added cross compilation to Github Actions * Added `dev` branch to Github Actions * Removed hardcoded URL in the /join command +* Fixed an issue in /playing where the bot showed it was playing even though it was paused + +**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v2.1.1...v2.1.2 ## 2.1.1 | September 23rd 2023 Reduced the amount of CPU that the bot uses from ~15%-25% per user to 1%-2% per user (percentage per core, benched on an AMD Ryzen 9 5950X). @@ -16,7 +18,7 @@ Reduced the amount of CPU that the bot uses from ~15%-25% per user to 1%-2% per ### Changes * Fixed issue #20 -**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v.2.1.0...v2.1.1 +**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v2.1.0...v2.1.1 ## 2.1.0 | September 20th 2023 So, it's been a while since I worked on this project, and some bugs have since been discovered. @@ -36,7 +38,7 @@ The main focus for this version is to stop using multiple processes for every pl - After skipping a song, you will no longer hear a tiny bit of the previous song after the silence -**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v2.0.0...v.2.1.0 +**Full Changelog**: https://github.com/SpoticordMusic/spoticord/compare/v2.0.0...v2.1.0 ### Issues - Currently, the CPU usage is much higher than it used to be. I really wanted to push this update out before taking the time to do some optimizations, as the bot and server are still easily able to hold up the limited amount of Spoticord users (and v2.0.0 was just falling apart). Issue is being tracked in #20 diff --git a/Cargo.toml b/Cargo.toml index 1ef97c8..6005d64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spoticord" -version = "2.1.1" +version = "2.1.2" edition = "2021" rust-version = "1.65.0" From e8115e558592b92858577049f587cfeebdc6fdad Mon Sep 17 00:00:00 2001 From: DaXcess Date: Thu, 28 Sep 2023 14:15:08 +0200 Subject: [PATCH 21/21] They thought they could hide... --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5db581a..0fe5cb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2255,7 +2255,7 @@ dependencies = [ [[package]] name = "spoticord" -version = "2.1.1" +version = "2.1.2" dependencies = [ "anyhow", "dotenv",