Compare commits

...
72 Commits
Author SHA1 Message Date
phoenix a2c9d938f9 ci: Changed url
pr CI / Test Suite (pull_request) Successful in 1m46s
2026-08-08 12:19:51 -04:00
phoenix 14f197d472 ci: Maybe this time?
pr CI / Test Suite (pull_request) Failing after 3m18s
2026-08-08 12:11:31 -04:00
phoenix efaa7122e2 ci: Getting somewhere
pr CI / Test Suite (pull_request) Canceled after 1m26s
2026-08-08 12:08:23 -04:00
phoenix 74dda6c9ef ci: Try it
pr CI / Test Suite (pull_request) Failing after 1m27s
2026-08-08 12:05:25 -04:00
phoenix 4c4326bb88 ci: Try it
pr CI / Test Suite (pull_request) Failing after 1m56s
2026-08-08 11:58:25 -04:00
phoenix fc01503b12 ci: Try it again
pr CI / Test Suite (pull_request) Failing after 2m21s
2026-08-07 12:42:13 -04:00
phoenix 2b70eeb1a9 ci: Checking it
pr CI / Test Suite (pull_request) Failing after 1m59s
2026-08-07 12:34:06 -04:00
phoenix 3106242640 ci: Try
pr CI / Test Suite (pull_request) Failing after 1m57s
2026-08-07 12:32:47 -04:00
phoenix 43d2625e69 ci: Go for it
pr CI / Test Suite (pull_request) Failing after 1m42s
2026-08-07 12:28:29 -04:00
phoenix 5ce07d8eb2 ci: Using docker
pr CI / Test Suite (pull_request) Failing after 1m24s
2026-08-07 12:25:09 -04:00
phoenix 9c57caa860 ci: Get it up
pr CI / Test Suite (pull_request) Failing after 1m23s
2026-08-07 11:48:31 -04:00
phoenix 2fd93cae64 Fix typo
pr CI / Test Suite (pull_request) Failing after 3m29s
2026-08-07 11:40:00 -04:00
phoenix 41d6ed0334 ci: Switching s3
pr CI / Test Suite (pull_request) Canceled after 2m44s
2026-08-07 11:39:13 -04:00
phoenix 6c0b0fa7f0 ci: Fix
pr CI / Test Suite (pull_request) Failing after 4m24s
2026-08-07 11:30:17 -04:00
phoenix dfa1dc4487 ci: This is a doozy 2026-08-07 11:29:04 -04:00
phoenix b3fb8b3088 Trying it out
pr CI / Test Suite (pull_request) Failing after 2m51s
2026-08-07 11:24:46 -04:00
phoenix 9368e80abe ci: Maybe this time
pr CI / Test Suite (pull_request) Canceled after 5m40s
2026-08-07 11:19:12 -04:00
phoenix 21928f7eac ci: Do it
pr CI / Test Suite (pull_request) Canceled after 6m14s
2026-08-07 11:13:02 -04:00
phoenix c28f1dd0a9 ci: Updating fake s3 port
pr CI / Test Suite (pull_request) Canceled after 3m0s
2026-08-07 11:10:06 -04:00
phoenix 84bd59f488 ci: Trying out fake s3
pr CI / Test Suite (pull_request) Canceled after 3m59s
2026-08-07 11:06:09 -04:00
phoenix f3f9d10ed5 ci: Focusing on test for now
pr CI / Test Suite (pull_request) Failing after 1m16s
2026-08-07 11:00:19 -04:00
phoenix a47694164c Fixing workflow
pr CI / Check (pull_request) Successful in 1m55s
pr CI / Test Suite (pull_request) Canceled after 8m14s
2026-08-07 10:52:15 -04:00
phoenix 25c745e951 Updating workflow
pr CI / Check (pull_request) Canceled after 1m52s
pr CI / Test Suite (pull_request) Canceled after 1m54s
2026-08-07 10:50:20 -04:00
phoenix 61df07732d Try it again
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m11s
soaricarus_api CI / Test Suite (pull_request) Failing after 2m30s
soaricarus_api CI / Clippy (pull_request) Successful in 1m33s
soaricarus_api CI / build (pull_request) Successful in 1m51s
soaricarus_api CI / Check (pull_request) Successful in 5m14s
2026-08-06 18:56:19 -04:00
phoenix 685f2f9257 Let's try this
soaricarus_api CI / Check (pull_request) Successful in 2m26s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m38s
soaricarus_api CI / Test Suite (pull_request) Failing after 5m13s
soaricarus_api CI / Clippy (pull_request) Successful in 3m33s
soaricarus_api CI / build (pull_request) Successful in 3m28s
2026-08-06 18:49:48 -04:00
phoenix 9042ba13e7 ci: Change sleep time in s3 setup
soaricarus_api CI / Check (pull_request) Successful in 2m22s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m35s
soaricarus_api CI / Test Suite (pull_request) Failing after 2m36s
soaricarus_api CI / Clippy (pull_request) Successful in 2m16s
soaricarus_api CI / build (pull_request) Successful in 2m40s
2026-08-06 18:01:02 -04:00
phoenix 27e6b51616 bump: labyrinth
soaricarus_api CI / Check (pull_request) Successful in 2m3s
soaricarus_api CI / Test Suite (pull_request) Failing after 2m28s
soaricarus_api CI / Rustfmt (pull_request) Successful in 3m28s
soaricarus_api CI / Clippy (pull_request) Successful in 1m43s
soaricarus_api CI / build (pull_request) Successful in 3m41s
2026-08-06 17:56:05 -04:00
phoenix 4eee8e3b03 Updating workflow
soaricarus_api CI / Clippy (pull_request) Canceled after 0s
soaricarus_api CI / build (pull_request) Canceled after 0s
soaricarus_api CI / Check (pull_request) Canceled after 3m32s
soaricarus_api CI / Test Suite (pull_request) Canceled after 3m30s
soaricarus_api CI / Rustfmt (pull_request) Canceled after 3m29s
2026-08-06 17:55:17 -04:00
phoenix a05dae25d7 Let's see if the test passes
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m27s
soaricarus_api CI / Test Suite (pull_request) Failing after 3m59s
soaricarus_api CI / Check (pull_request) Successful in 4m24s
soaricarus_api CI / Clippy (pull_request) Successful in 2m10s
soaricarus_api CI / build (pull_request) Successful in 3m15s
2026-08-06 17:39:46 -04:00
phoenix 78d74cf6f3 Updated sample env files
soaricarus_api CI / Check (pull_request) Successful in 6m15s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m58s
soaricarus_api CI / Clippy (pull_request) Successful in 3m29s
soaricarus_api CI / build (pull_request) Successful in 5m33s
soaricarus_api CI / Test Suite (pull_request) Successful in 5m27s
2026-08-06 17:17:59 -04:00
phoenix f7a1918462 ci: Updated docker compose 2026-08-06 17:17:45 -04:00
phoenix 9b6e6716c4 Updated code 2026-08-06 17:17:26 -04:00
phoenix 569c684c1c Added labyrinth 2026-08-06 11:45:34 -04:00
phoenix 6c910ab212 ci: Updated workflow
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m25s
soaricarus_api CI / Check (pull_request) Successful in 2m30s
soaricarus_api CI / Clippy (pull_request) Successful in 1m35s
soaricarus_api CI / build (pull_request) Successful in 2m42s
soaricarus_api CI / Test Suite (pull_request) Successful in 7m52s
2026-08-06 11:37:00 -04:00
phoenix 6490f51d17 ci: Maybe this time
soaricarus_api CI / Check (pull_request) Successful in 1m41s
soaricarus_api CI / Rustfmt (pull_request) Successful in 1m46s
soaricarus_api CI / Test Suite (pull_request) Successful in 3m3s
soaricarus_api CI / Clippy (pull_request) Successful in 2m0s
soaricarus_api CI / build (pull_request) Successful in 2m41s
2026-08-06 11:29:17 -04:00
phoenix d50959c602 ci: Maybe this
soaricarus_api CI / Check (pull_request) Failing after 14m43s
soaricarus_api CI / Rustfmt (pull_request) Failing after 9m0s
soaricarus_api CI / Clippy (pull_request) Successful in 1m55s
soaricarus_api CI / build (pull_request) Successful in 2m3s
soaricarus_api CI / Test Suite (pull_request) Failing after 4m44s
2026-08-06 10:51:39 -04:00
phoenix edf109e4d9 ci: Maybe this time
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m32s
soaricarus_api CI / Check (pull_request) Successful in 2m45s
soaricarus_api CI / Test Suite (pull_request) Failing after 3m23s
soaricarus_api CI / build (pull_request) Successful in 1m58s
soaricarus_api CI / Clippy (pull_request) Successful in 6m34s
2026-08-05 18:24:12 -04:00
phoenix d214ed106a Updating dockerfile 2026-08-05 18:07:15 -04:00
phoenix 77ec72dff4 ci: Added timeout
soaricarus_api CI / Check (pull_request) Successful in 3m11s
soaricarus_api CI / Test Suite (pull_request) Failing after 3m20s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m14s
soaricarus_api CI / Clippy (pull_request) Successful in 2m24s
soaricarus_api CI / build (pull_request) Successful in 2m9s
2026-08-05 18:03:46 -04:00
phoenix 40c41c1c1b ci: Updated yml
soaricarus_api CI / Test Suite (pull_request) Failing after 2m31s
soaricarus_api CI / Check (pull_request) Successful in 2m42s
soaricarus_api CI / Rustfmt (pull_request) Successful in 3m2s
soaricarus_api CI / Clippy (pull_request) Canceled after 1m9s
soaricarus_api CI / build (pull_request) Canceled after 3m55s
2026-08-05 18:00:08 -04:00
phoenix a34bc7c0ae Removing init script
soaricarus_api CI / Check (pull_request) Successful in 2m36s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m40s
soaricarus_api CI / Test Suite (pull_request) Failing after 3m24s
soaricarus_api CI / build (pull_request) Successful in 2m5s
soaricarus_api CI / Clippy (pull_request) Canceled after 2m37s
2026-08-05 17:53:56 -04:00
phoenix b436a1cd0a ci: Adding container name
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m27s
soaricarus_api CI / Check (pull_request) Successful in 2m43s
soaricarus_api CI / Test Suite (pull_request) Failing after 3m31s
soaricarus_api CI / Clippy (pull_request) Successful in 1m25s
soaricarus_api CI / build (pull_request) Successful in 1m52s
2026-08-05 17:49:50 -04:00
phoenix 3648c65aa2 Removing unused garage files 2026-08-05 17:49:38 -04:00
phoenix ac1575f2d1 Tweak it
soaricarus_api CI / Check (pull_request) Successful in 2m26s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m21s
soaricarus_api CI / Clippy (pull_request) Successful in 1m43s
soaricarus_api CI / build (pull_request) Successful in 4m42s
soaricarus_api CI / Test Suite (pull_request) Failing after 1m12s
2026-08-05 17:38:06 -04:00
phoenix e86420f19c ci: Updated yml
soaricarus_api CI / Test Suite (pull_request) Failing after 5s
soaricarus_api CI / build (pull_request) Canceled after 0s
soaricarus_api CI / Check (pull_request) Canceled after 1m53s
soaricarus_api CI / Clippy (pull_request) Canceled after 1m48s
soaricarus_api CI / Rustfmt (pull_request) Canceled after 1m57s
2026-08-05 17:36:21 -04:00
phoenix efbeaf2f7e ci: Updated workflow
soaricarus_api CI / Test Suite (pull_request) Failing after 20s
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m18s
soaricarus_api CI / Clippy (pull_request) Successful in 3m0s
soaricarus_api CI / build (pull_request) Successful in 1m27s
soaricarus_api CI / Check (pull_request) Successful in 4m45s
2026-08-04 18:19:44 -04:00
phoenix db07f2c39d Updated yml 2026-08-04 18:19:27 -04:00
phoenix bae1dd4173 Updating docker file
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m24s
soaricarus_api CI / Check (pull_request) Successful in 3m15s
soaricarus_api CI / Clippy (pull_request) Successful in 1m34s
soaricarus_api CI / build (pull_request) Successful in 1m27s
soaricarus_api CI / Test Suite (pull_request) Successful in 8m55s
2026-08-04 17:54:39 -04:00
phoenix b02cabc016 Updating sample env files 2026-08-04 17:54:28 -04:00
phoenix f5be2a44b9 Got it working
soaricarus_api CI / Rustfmt (pull_request) Successful in 3m54s
soaricarus_api CI / Check (pull_request) Successful in 4m31s
soaricarus_api CI / Test Suite (pull_request) Successful in 4m51s
soaricarus_api CI / Clippy (pull_request) Successful in 2m34s
soaricarus_api CI / build (pull_request) Successful in 3m32s
2026-08-04 17:36:22 -04:00
phoenix 82515b4ad7 Updating garage.toml 2026-08-04 17:03:39 -04:00
phoenix 45534a9d18 Updated sample env 2026-08-04 17:02:35 -04:00
phoenix 6392169878 Saving changes. Just going to stick with one docker service for storage
soaricarus_api CI / Rustfmt (pull_request) Successful in 5m54s
soaricarus_api CI / Check (pull_request) Successful in 6m4s
soaricarus_api CI / Test Suite (pull_request) Successful in 7m40s
soaricarus_api CI / build (pull_request) Successful in 3m18s
soaricarus_api CI / Clippy (pull_request) Successful in 4m41s
2026-08-04 12:34:39 -04:00
phoenix b583ff8ef1 Saving files 2026-08-04 11:08:30 -04:00
phoenix 140b9dba45 Saving script change
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m57s
soaricarus_api CI / Test Suite (pull_request) Successful in 3m34s
soaricarus_api CI / Check (pull_request) Successful in 3m54s
soaricarus_api CI / Clippy (pull_request) Successful in 2m31s
soaricarus_api CI / build (pull_request) Successful in 2m59s
2026-07-30 16:59:58 -04:00
phoenix 10cec1d7c7 Getting closer
soaricarus_api CI / Rustfmt (pull_request) Failing after 14m32s
soaricarus_api CI / Test Suite (pull_request) Failing after 14m33s
soaricarus_api CI / Check (pull_request) Failing after 14m34s
soaricarus_api CI / Clippy (pull_request) Successful in 3m11s
soaricarus_api CI / build (pull_request) Successful in 3m46s
2026-07-30 13:23:17 -04:00
phoenix f07e0108cd Getting closer
soaricarus_api CI / Check (pull_request) Successful in 6m2s
soaricarus_api CI / Rustfmt (pull_request) Successful in 6m11s
soaricarus_api CI / Test Suite (pull_request) Successful in 8m25s
soaricarus_api CI / Clippy (pull_request) Successful in 3m12s
soaricarus_api CI / build (pull_request) Successful in 4m34s
2026-07-28 13:08:33 -04:00
phoenix e2a5e02aad Trying
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m21s
soaricarus_api CI / Test Suite (pull_request) Successful in 3m55s
soaricarus_api CI / Check (pull_request) Successful in 4m15s
soaricarus_api CI / Clippy (pull_request) Successful in 4m22s
soaricarus_api CI / build (pull_request) Successful in 3m48s
2026-07-24 19:12:19 -04:00
phoenix 6574d0ee8f I am tired boss
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m26s
soaricarus_api CI / Check (pull_request) Successful in 3m24s
soaricarus_api CI / Clippy (pull_request) Successful in 3m43s
soaricarus_api CI / Test Suite (pull_request) Successful in 6m32s
soaricarus_api CI / build (pull_request) Successful in 3m25s
2026-07-24 15:33:18 -04:00
phoenix 75f4d9fa76 Saving changes. No real progress yet
soaricarus_api CI / Test Suite (pull_request) Successful in 3m36s
soaricarus_api CI / Check (pull_request) Successful in 4m3s
soaricarus_api CI / Rustfmt (pull_request) Successful in 5m49s
soaricarus_api CI / Clippy (pull_request) Successful in 2m24s
soaricarus_api CI / build (pull_request) Successful in 4m32s
2026-07-24 12:23:48 -04:00
phoenix 3de818f280 Saving changes
soaricarus_api CI / Rustfmt (pull_request) Successful in 3m50s
soaricarus_api CI / Check (pull_request) Successful in 5m0s
soaricarus_api CI / Test Suite (pull_request) Successful in 6m7s
soaricarus_api CI / Clippy (pull_request) Successful in 3m28s
soaricarus_api CI / build (pull_request) Successful in 3m42s
2026-07-23 17:19:29 -04:00
phoenix f116adffdb Saving changes. Nothing yet 2026-07-23 16:26:14 -04:00
phoenix 3965d86d54 Saving script 2026-07-23 16:21:40 -04:00
phoenix 8fae71b086 Getting somewhere. Object Storage is initialized but not initializing hangs 2026-07-23 16:05:21 -04:00
phoenix 2bfb8c6aee Got garage to run in docker
soaricarus_api CI / Rustfmt (pull_request) Successful in 2m13s
soaricarus_api CI / Check (pull_request) Successful in 4m13s
soaricarus_api CI / Test Suite (pull_request) Successful in 5m55s
soaricarus_api CI / Clippy (pull_request) Successful in 4m30s
soaricarus_api CI / build (pull_request) Successful in 4m57s
2026-07-23 15:31:41 -04:00
phoenix 327d04e8a9 Revert "Removing garage.toml"
soaricarus_api CI / Clippy (pull_request) Canceled after 0s
soaricarus_api CI / build (pull_request) Canceled after 0s
soaricarus_api CI / Check (pull_request) Canceled after 2m22s
soaricarus_api CI / Rustfmt (pull_request) Canceled after 2m10s
soaricarus_api CI / Test Suite (pull_request) Canceled after 4m15s
This reverts commit 7a209eeb5e.
2026-07-23 15:28:58 -04:00
phoenix 7a209eeb5e Removing garage.toml 2026-07-23 15:15:11 -04:00
phoenix 7460f0d157 Updating some of the sample env
soaricarus_api CI / Rustfmt (pull_request) Successful in 3m17s
soaricarus_api CI / Check (pull_request) Successful in 4m30s
soaricarus_api CI / Test Suite (pull_request) Successful in 4m38s
soaricarus_api CI / Clippy (pull_request) Successful in 3m58s
soaricarus_api CI / build (pull_request) Successful in 3m8s
2026-07-22 17:20:58 -04:00
phoenix 4b7816e117 Adding image to store data 2026-07-22 17:20:37 -04:00
phoenix 59a7e31641 Updating name (#253)
soaricarus_api CI / Check (push) Successful in 3m21s
soaricarus_api CI / Test Suite (push) Successful in 4m25s
soaricarus_api CI / Rustfmt (push) Successful in 3m8s
soaricarus_api CI / Clippy (push) Successful in 3m56s
soaricarus_api CI / build (push) Successful in 3m3s
Reviewed-on: #253
2026-07-21 15:28:48 -04:00
phoenix 8a64a71339 Update postgres (#252)
Rust CI / Test Suite (push) Successful in 3m43s
Rust CI / Rustfmt (push) Successful in 2m2s
Rust CI / Check (push) Successful in 3m9s
Rust CI / build (push) Successful in 2m58s
Rust CI / Clippy (push) Successful in 4m28s
Reviewed-on: phoenix/icarus#252
2026-07-09 11:05:12 -04:00
phoenix 7ca4c655a4 Update (#251)
Rust CI / build (push) Failing after 2m53s
Reviewed-on: phoenix/icarus#251
2026-07-07 23:25:45 -04:00
22 changed files with 2018 additions and 871 deletions
+26 -4
View File
@@ -4,9 +4,31 @@ FRONTEND_URL=http://localhost:4200
RUST_LOG=debug RUST_LOG=debug
ALLOWED_ORIGINS=https://soaricarus.com,https://www.soaricarus.com ALLOWED_ORIGINS=https://soaricarus.com,https://www.soaricarus.com
SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
ROOT_DIRECTORY=/home/icarus/mydata ROOT_DIRECTORY=/home/soaricarus/mydata
POSTGRES_MAIN_USER=icarus POSTGRES_MAIN_USER=soaricarus
POSTGRES_MAIN_PASSWORD=password POSTGRES_MAIN_PASSWORD=password
POSTGRES_MAIN_DB=icarus_db POSTGRES_MAIN_DB=soaricarus_db
POSTGRES_MAIN_HOST=main_db POSTGRES_MAIN_HOST=main_db
DATABASE_URL=postgres://${POSTGRES_MAIN_USER}:${POSTGRES_MAIN_PASSWORD}@${POSTGRES_MAIN_HOST}:5432/${POSTGRES_MAIN_DB} POSTGRES_MAIN_PORT=5432
DATABASE_URL=postgres://${POSTGRES_MAIN_USER}:${POSTGRES_MAIN_PASSWORD}@${POSTGRES_MAIN_HOST}:${POSTGRES_MAIN_PORT}/${POSTGRES_MAIN_DB}
S3_BUCKET_NAME=soaricarus-bucket
S3_ENDPOINT_URL=http://maze:3900
GARAGE_S3_REGION=maze
GARAGE_RPC_SECRET=c2bde5c3f9c04116a7563e25ea5ba6fab25319daa2fe8a952ad57d0b8159b590
GARAGE_METRICS_TOKEN=sD2g4jiYV66KdZWtIuj2amezuryzv81mZNktpMNcmU4=
GARAGE_DEFAULT_ACCESS_KEY=GK8eb91557b9a18dcbdc834c16a25ac6fc
GARAGE_DEFAULT_SECRET_KEY=WhFAtnAtWgYaa0pMfl9jwygalZSwYaVliY3Ndm7nYHo=
GARAGE_DEFAULT_BUCKET=${S3_BUCKET_NAME}
GARAGE_ADMIN_TOKEN=5yMAjSINa6U04wr4pDbcTYfsXKl3S9ZjKdiPXWYUbNw=
GARAGE_METADATA_DIR=/var/lib/garage/meta
GARAGE_DATA_DIR=/var/lib/garage/data
GARAGE_DB_ENGINE=sqlite
GARAGE_REPLICATION_FACTOR=1
GARAGE_RPC_BIND_ADDR=[::]:3901
GARAGE_S3_API_BIND_ADDR=[::]:3900
GARAGE_S3_WEB_BIND_ADDR=[::]:3902
GARAGE_ROOT_DOMAIN=.localhost
AWS_DEFAULT_REGION=${GARAGE_S3_REGION}
AWS_SECRET_ACCESS_KEY=${GARAGE_DEFAULT_ACCESS_KEY}
AWS_ACCESS_KEY_ID=${GARAGE_DEFAULT_SECRET_KEY}
+26 -4
View File
@@ -4,9 +4,31 @@ FRONTEND_URL=http://localhost:4200
RUST_LOG=debug RUST_LOG=debug
ALLOWED_ORIGINS=https://soaricarus.com,https://www.soaricarus.com ALLOWED_ORIGINS=https://soaricarus.com,https://www.soaricarus.com
SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
ROOT_DIRECTORY=/home/icarus/mydata ROOT_DIRECTORY=/home/soaricarus/mydata
POSTGRES_MAIN_USER=icarus POSTGRES_MAIN_USER=soaricarus
POSTGRES_MAIN_PASSWORD=password POSTGRES_MAIN_PASSWORD=password
POSTGRES_MAIN_DB=icarus_db POSTGRES_MAIN_DB=soaricarus_db
POSTGRES_MAIN_HOST=main_db POSTGRES_MAIN_HOST=main_db
DATABASE_URL=postgres://${POSTGRES_MAIN_USER}:${POSTGRES_MAIN_PASSWORD}@${POSTGRES_MAIN_HOST}:5432/${POSTGRES_MAIN_DB} POSTGRES_MAIN_PORT=5432
DATABASE_URL=postgres://${POSTGRES_MAIN_USER}:${POSTGRES_MAIN_PASSWORD}@${POSTGRES_MAIN_HOST}:${POSTGRES_MAIN_PORT}/${POSTGRES_MAIN_DB}
S3_BUCKET_NAME=soaricarus-bucket
S3_ENDPOINT_URL=http://maze:3900
GARAGE_S3_REGION=maze
GARAGE_RPC_SECRET=c2bde5c3f9c04116a7563e25ea5ba6fab25319daa2fe8a952ad57d0b8159b590
GARAGE_METRICS_TOKEN=sD2g4jiYV66KdZWtIuj2amezuryzv81mZNktpMNcmU4=
GARAGE_DEFAULT_ACCESS_KEY=GK8eb91557b9a18dcbdc834c16a25ac6fc
GARAGE_DEFAULT_SECRET_KEY=WhFAtnAtWgYaa0pMfl9jwygalZSwYaVliY3Ndm7nYHo=
GARAGE_DEFAULT_BUCKET=${S3_BUCKET_NAME}
GARAGE_ADMIN_TOKEN=5yMAjSINa6U04wr4pDbcTYfsXKl3S9ZjKdiPXWYUbNw=
GARAGE_METADATA_DIR=/var/lib/garage/meta
GARAGE_DATA_DIR=/var/lib/garage/data
GARAGE_DB_ENGINE=sqlite
GARAGE_REPLICATION_FACTOR=1
GARAGE_RPC_BIND_ADDR=[::]:3901
GARAGE_S3_API_BIND_ADDR=[::]:3900
GARAGE_S3_WEB_BIND_ADDR=[::]:3902
GARAGE_ROOT_DOMAIN=.localhost
AWS_DEFAULT_REGION=${GARAGE_S3_REGION}
AWS_SECRET_ACCESS_KEY=${GARAGE_DEFAULT_ACCESS_KEY}
AWS_ACCESS_KEY_ID=${GARAGE_DEFAULT_SECRET_KEY}
-12
View File
@@ -1,12 +0,0 @@
APP_ENV=production
BACKEND_PORT=8000
FRONTEND_URL=http://localhost:4200
RUST_LOG=debug
ALLOWED_ORIGINS=https://soaricarus.com,https://www.soaricarus.com,http://localhost:8000,http://127.0.0.1:8000
SECRET_MAIN_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
ROOT_DIRECTORY=/home/icarus/mydata
POSTGRES_MAIN_USER=icarus
POSTGRES_MAIN_PASSWORD=password
POSTGRES_MAIN_DB=icarus_db
POSTGRES_MAIN_HOST=localhost
DATABASE_URL=postgres://${POSTGRES_MAIN_USER}:${POSTGRES_MAIN_PASSWORD}@${POSTGRES_MAIN_HOST}:5432/${POSTGRES_MAIN_DB}
+106
View File
@@ -0,0 +1,106 @@
name: pr CI
on:
pull_request:
branches: [ "main" ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: Test Suite
runs-on: ubuntu-24.04
timeout-minutes: 20
services:
postgres:
image: postgres:18.4-alpine
env:
POSTGRES_USER: ${{ secrets.DB_TEST_USER || 'testuser' }}
POSTGRES_PASSWORD: ${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}
POSTGRES_DB: ${{ secrets.DB_TEST_NAME || 'testdb' }}
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- name: Verify Docker Environment
run: |
echo "Runner User Info:"
id
echo "Checking Docker Version:"
docker --version
echo "Checking Docker Daemon Status (info):"
docker info
echo "Checking Docker Daemon Status (ps):"
docker ps -a
echo "Docker environment check complete."
- name: Setup S3
env:
GARAGE_DEFAULT_ACCESS_KEY: "${{ secrets.GARAGE_KEY_ID }}"
GARAGE_DEFAULT_SECRET_KEY: "${{ secrets.GARAGE_SECRET }}"
GARAGE_DEFAULT_BUCKET: "soaricarus-ci-bucket"
AWS_ACCESS_KEY_ID: "${{ secrets.GARAGE_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.GARAGE_SECRET }}"
AWS_DEFAULT_REGION: us-east-1
run: |
sudo apt update
sudo apt install curl unzip -y
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
# curl -v ${{ secrets.S3_CI_ENDPOINT_URL }}
# Create bucket
aws --endpoint-url=${{ secrets.S3_CI_ENDPOINT_URL }} s3 mb s3://soaricarus-ci-bucket --region us-east-1
- name: Run tests
env:
# Define DATABASE_URL for tests to use
DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }}
RUST_LOG: info # Optional: configure test log level
SECRET_MAIN_KEY: ${{ secrets.TOKEN_SECRET_KEY }}
SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }}
ROOT_DIRECTORY: "/tmp"
AWS_ACCESS_KEY_ID: "${{ secrets.GARAGE_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.GARAGE_SECRET }}"
AWS_DEFAULT_REGION: us-east-1
GARAGE_DEFAULT_ACCESS_KEY: "${{ secrets.GARAGE_KEY_ID }}"
GARAGE_DEFAULT_SECRET_KEY: "${{ secrets.GARAGE_SECRET }}"
GARAGE_S3_REGION: us-east-1
S3_BUCKET_NAME: "soaricarus-ci-bucket"
S3_ENDPOINT_URL: "${{ secrets.S3_CI_ENDPOINT_URL }}"
AWS_S3_FORCE_PATH_STYLE: "true"
run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo test
- name: Cleanup
if: always()
run: |
aws --endpoint-url=${{ secrets.S3_CI_ENDPOINT_URL }} \
s3 rb s3://soaricarus-ci-bucket --force \
--region us-east-1
env:
AWS_ACCESS_KEY_ID: "${{ secrets.GARAGE_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.GARAGE_SECRET }}"
AWS_DEFAULT_REGION: us-east-1
continue-on-error: true
+2 -2
View File
@@ -9,14 +9,14 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
fetch-depth: 0 # Important for git describe --tags fetch-depth: 0 # Important for git describe --tags
- name: Install Rust - name: Install Rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.95 toolchain: 1.97
components: cargo components: cargo
- name: Extract Version from Cargo.toml - name: Extract Version from Cargo.toml
+160 -62
View File
@@ -1,23 +1,46 @@
name: Rust CI name: soaricarus_api CI
on: on:
push: push:
branches: [ "main" ] branches: [ "main" ]
pull_request:
branches: [ "main" ] concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build: check:
name: Check
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo check
test:
name: Test Suite
runs-on: ubuntu-24.04
timeout-minutes: 20
services: services:
postgres: postgres:
image: postgres:18.3-alpine image: postgres:18.4-alpine
env: env:
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} POSTGRES_USER: ${{ secrets.DB_TEST_USER || 'testuser' }}
POSTGRES_USER: ${{ secrets.POSTGRES_USER }} POSTGRES_PASSWORD: ${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}
POSTGRES_DB: ${{ secrets.POSTGRES_DB }} POSTGRES_DB: ${{ secrets.DB_TEST_NAME || 'testdb' }}
ports:
- 5432:5432
options: >- options: >-
--health-cmd pg_isready --health-cmd pg_isready
--health-interval 10s --health-interval 10s
@@ -25,55 +48,130 @@ jobs:
--health-retries 5 --health-retries 5
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Install Rust 1.95 with:
uses: actions-rs/toolchain@v1 toolchain: 1.97
with: - uses: Swatinem/rust-cache@v2
toolchain: 1.95 - name: Verify Docker Environment
components: clippy, rustfmt run: |
override: true echo "Runner User Info:"
id
- name: Cache dependencies echo "Checking Docker Version:"
uses: Swatinem/rust-cache@v2 docker --version
echo "Checking Docker Daemon Status (info):"
- name: Install libpq docker info
run: sudo apt-get install -y libpq-dev echo "Checking Docker Daemon Status (ps):"
docker ps -a
- name: Setup test database echo "Docker environment check complete."
env:
DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}" - name: Setup LocalStack S3
run: | run: |
# Wait for PostgreSQL to be ready # Install AWS CLI
for i in {1..10}; do sudo apt update
pg_isready -U ${{ secrets.POSTGRES_USER }} -d ${{ secrets.POSTGRES_DB }} && break sudo apt search awscli
sleep 2 pip install awscli
done
# Wait for LocalStack
# Run database migrations (if you use sqlx migrations) until curl -s http://localhost:4566/_localstack/health | grep -q '"s3":"available"'; do
cargo install sqlx-cli --no-default-features --features native-tls,postgres sleep 3
sqlx migrate run --database-url $DATABASE_URL done
- name: Build # CHOOSE A BUCKET NAME - this is whatever you want
run: | BUCKET_NAME="soaricarus-ci-bucket" # <-- CHANGE THIS TO WHAT YOUR APP EXPECTS
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/gitea_deploy_key # Create the bucket
chmod 600 ~/.ssh/gitea_deploy_key aws --endpoint-url=http://localhost:4566 s3 mb s3://$BUCKET_NAME --region ${{ secrets.GARAGE_REGION }}
ssh-keyscan ${{ vars.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s) # Set it as an environment variable for the test step
ssh-add -v ~/.ssh/gitea_deploy_key echo "BUCKET_NAME=$BUCKET_NAME" >> $GITHUB_ENV
cargo build --verbose --release env:
AWS_ACCESS_KEY_ID: ${{ secrets.GARAGE_KEY_ID }}
- name: Run tests AWS_SECRET_ACCESS_KEY: ${{ secrets.GARAGE_SECRET }}
env: AWS_DEFAULT_REGION: ${{ secrets.GARAGE_REGION }}
ROOT_DIRECTORY: "/tmp"
DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}" - name: Run tests
run: | env:
cat .env.sample | head -6 > .env # Define DATABASE_URL for tests to use
cargo test --verbose -- DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }}
RUST_LOG: info # Optional: configure test log level
- name: Run clippy SECRET_MAIN_KEY: ${{ secrets.TOKEN_SECRET_KEY }}
run: cargo clippy -- -D warnings SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }}
ROOT_DIRECTORY: "/tmp"
- name: Run rustfmt AWS_ACCESS_KEY_ID: ${{ secrets.GARAGE_KEY_ID }}
run: cargo fmt --all -- --check AWS_SECRET_ACCESS_KEY: ${{ secrets.GARAGE_SECRET }}
AWS_DEFAULT_REGION: ${{ secrets.GARAGE_REGION }}
GARAGE_DEFAULT_ACCESS_KEY: ${{ secrets.GARAGE_KEY_ID }}
GARAGE_DEFAULT_SECRET_KEY: ${{ secrets.GARAGE_SECRET }}
GARAGE_S3_REGION: ${{ secrets.GARAGE_REGION }}
S3_BUCKET_NAME: "soaricarus-ci-bucket"
S3_ENDPOINT_URL: "http://localhost:3900"
run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo test
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo clippy -- -D warnings
build:
name: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/soaricarus_models_deploy_key
chmod 600 ~/.ssh/soaricarus_models_deploy_key
ssh-keyscan ${{ secrets.MYHOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/soaricarus_models_deploy_key
cargo build --release
Generated
+1367 -577
View File
File diff suppressed because it is too large Load Diff
+14 -12
View File
@@ -1,33 +1,35 @@
[package] [package]
name = "icarus" name = "soaricarus_api"
version = "0.5.0" version = "0.5.2"
edition = "2024" edition = "2024"
rust-version = "1.95" rust-version = "1.95"
license = "MIT"
description = "Core API for interacting with soaricarus"
[dependencies] [dependencies]
axum = { version = "0.8.9", features = ["multipart"] } axum = { version = "0.8.9", features = ["multipart"] }
axum-extra = { version = "0.12.6", features = ["cookie"] } axum-extra = { version = "0.12.6", features = ["cookie"] }
openssl = { version = "0.10.81", features = ["vendored"] }
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.149" } serde_json = { version = "1.0.150" }
tokio = { version = "1.52.3", features = ["full"] } tokio = { version = "1.52.3", features = ["full"] }
tokio-util = { version = "0.7.18", features = ["io"] } tokio-util = { version = "0.7.18", features = ["io"] }
tower = { version = "0.5.3", features = ["full"] } tower = { version = "0.5.3", features = ["full"] }
tower-http = { version = "0.6.10", features = ["cors", "timeout"] } tower-http = { version = "0.7.0", features = ["cors", "timeout"] }
tracing-subscriber = "0.3.23" tracing-subscriber = "0.3.23"
futures = { version = "0.3.32" } futures = { version = "0.3.32" }
mime_guess = { version = "2.0.5" } mime_guess = { version = "2.0.5" }
uuid = { version = "1.23.1", features = ["v4", "serde"] } uuid = { version = "1.23.5", features = ["v4", "serde"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] } sqlx = { version = "0.9.0", features = ["postgres", "runtime-tokio", "tls-native-tls", "time", "uuid"] }
time = { version = "0.3.47", features = ["formatting", "macros", "parsing", "serde"] } time = { version = "0.3.53", features = ["formatting", "macros", "parsing", "serde"] }
thiserror = "2.0.18"
base64 = "0.22.1"
jsonwebtoken = { version = "10.3.0", features = ["rust_crypto"] } jsonwebtoken = { version = "10.3.0", features = ["rust_crypto"] }
josekit = { version = "0.10.3" } josekit = { version = "0.10.3" }
utoipa = { version = "5.5.0", features = ["axum_extras"] } utoipa = { version = "5.5.0", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] } utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
icarus_meta = { git = "ssh://git@git.kundeng.us/phoenix/icarus_meta.git", tag = "v0.6.0" } simeta = { git = "ssh://git@git.kundeng.us/phoenix/simeta.git", tag = "v0.6.1-main-b690995806-680" }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.11.1" } simodels = { git = "ssh://git@git.kundeng.us/phoenix/simodels.git", tag = "v0.11.3-main-fe9d101bd0-111" }
icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.7.0" } sienvy = { git = "ssh://git@git.kundeng.us/phoenix/sienvy.git", tag = "v0.8.0-main-d06c8fdf49-006" }
labyrinth = { git = "ssh://git@git.kundeng.us/phoenix/labyrinth.git", tag = "v0.0.2-1-84f98521c8-928" }
[dev-dependencies] [dev-dependencies]
common-multipart-rfc7578 = { version = "0.7.0" } common-multipart-rfc7578 = { version = "0.7.0" }
+4 -22
View File
@@ -1,5 +1,4 @@
# Stage 1: Build the application FROM rust:1.97 as builder
FROM rust:1.95 as builder
# Set the working directory inside the container # Set the working directory inside the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
@@ -17,34 +16,24 @@ RUN mkdir -p -m 0700 ~/.ssh && \
echo " User git" >> ~/.ssh/config && \ echo " User git" >> ~/.ssh/config && \
chmod 600 ~/.ssh/config chmod 600 ~/.ssh/config
# << --- ADD HOST KEY HERE --- >>
RUN ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts RUN ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts
# Copy Cargo manifests # Copy Cargo manifests
COPY Cargo.toml Cargo.lock ./ COPY Cargo.toml Cargo.lock ./
# Build *only* dependencies to leverage Docker cache
# This dummy build caches dependencies as a separate layer
RUN --mount=type=ssh mkdir src && \ RUN --mount=type=ssh mkdir src && \
echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \ echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \
cargo build --release --quiet && \ cargo build --release --quiet && \
rm -rf src target/release/deps/icarus* # Clean up dummy build artifacts (replace icarus) rm -rf src target/release/deps/soaricarus_api*
# Copy the actual source code # Copy the actual source code
COPY src ./src COPY src ./src
# If you have other directories like `templates` or `static`, copy them too
COPY .env ./.env COPY .env ./.env
COPY migrations ./migrations COPY migrations ./migrations
# << --- SSH MOUNT ADDED HERE --- >>
# Build *only* dependencies to leverage Docker cache
# This dummy build caches dependencies as a separate layer
# Mount the SSH agent socket for this command
RUN --mount=type=ssh \ RUN --mount=type=ssh \
cargo build --release --quiet cargo build --release --quiet
# Stage 2: Create the final, smaller runtime image
# Use a minimal base image like debian-slim or even distroless for security/size
FROM debian:trixie-slim FROM debian:trixie-slim
# Install runtime dependencies if needed (e.g., SSL certificates) # Install runtime dependencies if needed (e.g., SSL certificates)
@@ -53,18 +42,11 @@ RUN apt-get update && apt-get install -y ca-certificates libssl-dev libssl3 && r
# Set the working directory # Set the working directory
WORKDIR /usr/local/bin WORKDIR /usr/local/bin
# Copy the compiled binary from the builder stage COPY --from=builder /usr/src/app/target/release/soaricarus_api .
# Replace 'icarus' with the actual name of your binary (usually the crate name)
COPY --from=builder /usr/src/app/target/release/icarus .
# Copy other necessary files like .env (if used for runtime config) or static assets
# It's generally better to configure via environment variables in Docker though
COPY --from=builder /usr/src/app/.env . COPY --from=builder /usr/src/app/.env .
COPY --from=builder /usr/src/app/migrations ./migrations COPY --from=builder /usr/src/app/migrations ./migrations
# Expose the port your Axum app listens on (e.g., 3000 or 8000)
EXPOSE 8000 EXPOSE 8000
# Set the command to run your application CMD ["./soaricarus_api"]
# Ensure this matches the binary name copied above
CMD ["./icarus"]
+7 -7
View File
@@ -1,19 +1,19 @@
# Icarus # soaricarus_api
Web API for the Icarus project. Core web API for the soaricarus project.
### Requires ### Requires
`icarus_auth` v0.7.x `soaricarus_auth` v0.8.x
`songparser` v0.5.x `songparser` v0.6.x
### Compatible with ### Compatible with
`icarus-dm` v0.9.x `sidm` v0.10.x
## Getting Started ## Getting Started
Quickest way to get started is with docker. Make sure `icarus_auth` and `songparser` repositories Quickest way to get started is with docker. Make sure `soaricarus_auth` and `songparser` repositories
are located in the root of the parent directory. Check the respective repositories to ensure they are located in the root of the parent directory. Check the respective repositories to ensure they
are setup correctly before configuring `Icarus`. are setup correctly before configuring `soaricarus_api`.
Copy the `.env.docker.sample` file to `.env`. Ensure that the `ROOT_DIRECTORY` variable is populated Copy the `.env.docker.sample` file to `.env`. Ensure that the `ROOT_DIRECTORY` variable is populated
and exists on the docker image's filesystem. The credentials for the database doesn't need to be and exists on the docker image's filesystem. The credentials for the database doesn't need to be
+101 -34
View File
@@ -3,42 +3,44 @@ version: '3.8' # Use a recent version
services: services:
# --- Web API --- # --- Web API ---
api: api:
build: # Tells docker-compose to build the Dockerfile in the current directory build:
context: . context: .
ssh: ["default"] # Uses host's SSH agent ssh: ["default"]
container_name: icarus # Optional: Give the container a specific name container_name: api
ports: ports:
# Map host port 8000 to container port 3000 (adjust as needed)
- "8000:8000" - "8000:8000"
env_file: env_file:
- .env - .env
volumes:
- shared_credentials:/shared:ro # Mount as read-only
depends_on: depends_on:
main_db: main_db:
condition: service_healthy condition: service_healthy
maze:
condition: service_started
auth_api:
condition: service_started
networks: networks:
- icarus-network - soaricarus-network
restart: unless-stopped # Optional: Restart policy restart: unless-stopped
# --- Web API auth --- # --- Web API auth ---
auth_api: auth_api:
build: build:
context: ../icarus_auth # IMPORTANT: Relative path to the local checkout of your web API repo (containing the Dockerfile) context: ../soaricarus_auth # IMPORTANT: Relative path to the local checkout of your web API repo (containing the Dockerfile)
ssh: ["default"] # Uses host's SSH agent ssh: ["default"]
dockerfile: Dockerfile # Optional: Specify if your Dockerfile has a non-standard name dockerfile: Dockerfile # Optional: Specify if your Dockerfile has a non-standard name
container_name: auth_api container_name: auth_api
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8001:8001" # Map host port 8000 to container port 8000 (adjust container port based on your app's EXPOSE in Dockerfile) - "8001:8001"
# environment:
# Environment variables your API needs, e.g., database connection
# Add other necessary environment variables
env_file: env_file:
- ../icarus_auth/.env - ../soaricarus_auth/.env
depends_on: depends_on:
auth_db: auth_db:
condition: service_healthy condition: service_healthy
networks: networks:
- icarus-network - soaricarus-network
# Optional: Mount local code for development (live reload) # Optional: Mount local code for development (live reload)
# volumes: # volumes:
# - ./path/to/your/web-api-repo:/app # - ./path/to/your/web-api-repo:/app
@@ -58,25 +60,89 @@ services:
- main_db - main_db
- auth_api - auth_api
- auth_db - auth_db
- maze
networks: networks:
- icarus-network - soaricarus-network
# --- storage service ---
maze:
image: dxflrs/garage:v2.3.0 # Use official Garage image
container_name: maze
restart: unless-stopped
environment:
# Garage configuration via environment variables
GARAGE_SERVER_BIND_ADDR: "0.0.0.0:3900"
GARAGE_SERVER_BIND_PUBLIC_ADDR: "0.0.0.0:3901"
GARAGE_S3_API_BIND_ADDR: "0.0.0.0:3900"
GARAGE_S3_API_PUBLIC_BIND_ADDR: "0.0.0.0:3901"
GARAGE_S3_API_PUBLIC_ADDRS: "http://localhost:3901"
GARAGE_S3_API_ROOT_DOMAIN: "${GARAGE_ROOT_DOMAIN}"
GARAGE_ADMIN_BIND_ADDR: "0.0.0.0:3902"
GARAGE_ADMIN_PUBLIC_BIND_ADDR: "0.0.0.0:3902"
# Cluster configuration (single node for simplicity)
GARAGE_CLUSTER_REPLICATION_MODE: "none" # Single node
GARAGE_CLUSTER_PEER_REPLICATION_STRATEGY: "ring"
# Data storage
GARAGE_DATA_DIR: "/data"
GARAGE_METADATA_DIR: "/data/meta"
# RPC configuration
GARAGE_RPC_PUBLIC_ADDR: "http://maze:3901"
GARAGE_RPC_BIND_ADDR: "0.0.0.0:3901"
GARAGE_RPC_SECRET: "${GARAGE_RPC_SECRET}" # 32+ chars
# Web Admin
GARAGE_ADMIN_TOKEN: "${GARAGE_ADMIN_TOKEN}"
# Logging
GARAGE_LOG_LEVEL: "info"
GARAGE_S3_BUCKET: "${S3_BUCKET_NAME}"
GARAGE_S3_REGION: "${GARAGE_S3_REGION}"
GARAGE_DEFAULT_ACCESS_KEY: "${GARAGE_DEFAULT_ACCESS_KEY}"
GARAGE_DEFAULT_SECRET_KEY: "${GARAGE_DEFAULT_SECRET_KEY}"
GARAGE_DEFAULT_BUCKET: "${GARAGE_DEFAULT_BUCKET}"
AWS_ACCESS_KEY_ID: "${GARAGE_DEFAULT_ACCESS_KEY}"
AWS_SECRET_ACCESS_KEY: "${GARAGE_DEFAULT_SECRET_KEY}"
AWS_DEFAULT_REGION: "${GARAGE_DEFAULT_BUCKET}"
AWS_S3_FORCE_PATH_STYLE: "true"
volumes:
- ./garage.toml:/etc/garage.toml:ro # Mount config file
- shared_credentials:/data # Persist Garage data
ports:
- "3900:3900" # S3 API
- "3901:3901" # S3 API public
- "3902:3902" # Admin API
command: ["/garage", "server", "--single-node", "--default-bucket"]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3900/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- soaricarus-network
extra_hosts:
- "garage.local:127.0.0.1"
# PostgreSQL Database Service # PostgreSQL Database Service
# --- icarus web api db ---
main_db: main_db:
image: postgres:18.3-alpine # Use an official Postgres image (Alpine variant is smaller) image: postgres:18.4-alpine
container_name: icarus_db # Optional: Give the container a specific name container_name: soaricarus_db
environment: environment:
# These MUST match the user, password, and database name in the DATABASE_URL above # These MUST match the user, password, and database name in the DATABASE_URL above
POSTGRES_USER: ${POSTGRES_MAIN_USER:-icarus} POSTGRES_USER: ${POSTGRES_MAIN_USER:-soaricarus}
POSTGRES_PASSWORD: ${POSTGRES_MAIN_PASSWORD:-password} POSTGRES_PASSWORD: ${POSTGRES_MAIN_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_MAIN_DB:-icarus_db} POSTGRES_DB: ${POSTGRES_MAIN_DB:-soaricarus_db}
volumes: volumes:
# Persist database data using a named volume # Persist database data using a named volume
- postgres_data:/var/lib/postgresql - postgres_data:/var/lib/postgresql
ports: ports:
# Optional: Expose port 5432 ONLY if you need to connect directly from your host machine (e.g., for debugging)
- "5432:5432" - "5432:5432"
healthcheck: healthcheck:
# Checks if Postgres is ready to accept connections # Checks if Postgres is ready to accept connections
@@ -85,24 +151,23 @@ services:
timeout: 5s timeout: 5s
retries: 5 retries: 5
start_period: 10s start_period: 10s
restart: always # Optional: Restart policy restart: always
networks: networks:
- icarus-network - soaricarus-network
# --- icarus web auth api db --- # --- soaricarus web auth api db ---
auth_db: auth_db:
image: postgres:18.3-alpine # Use an official Postgres image (Alpine variant is smaller) image: postgres:18.4-alpine
container_name: icarus_auth_db # Optional: Give the container a specific name container_name: soaricarus_auth_db
environment: environment:
# These MUST match the user, password, and database name in the DATABASE_URL above # These MUST match the user, password, and database name in the DATABASE_URL above
POSTGRES_USER: ${POSTGRES_AUTH_USER:-icarus_op} POSTGRES_USER: ${POSTGRES_AUTH_USER:-soaricarus_op}
POSTGRES_PASSWORD: ${POSTGRES_AUTH_PASSWORD:-password} POSTGRES_PASSWORD: ${POSTGRES_AUTH_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_AUTH_DB:-icarus_auth_db} POSTGRES_DB: ${POSTGRES_AUTH_DB:-soaricarus_auth_db}
volumes: volumes:
# Persist database data using a named volume # Persist database data using a named volume
- postgres_data_auth:/var/lib/postgresql - postgres_data_auth:/var/lib/postgresql
ports: ports:
# Optional: Expose port 5432 ONLY if you need to connect directly from your host machine (e.g., for debugging)
- "5433:5432" - "5433:5432"
healthcheck: healthcheck:
# Checks if Postgres is ready to accept connections # Checks if Postgres is ready to accept connections
@@ -111,18 +176,20 @@ services:
timeout: 5s timeout: 5s
retries: 5 retries: 5
start_period: 10s start_period: 10s
restart: always # Optional: Restart policy restart: always
networks: networks:
- icarus-network - soaricarus-network
# Define the named volume for data persistence
volumes: volumes:
postgres_data: postgres_data:
driver: local # Use the default local driver driver: local # Use the default local driver
postgres_data_auth: postgres_data_auth:
driver: local # Use the default local driver driver: local # Use the default local driver
object_data:
driver: local # Use the default local driver
shared_credentials: # New shared volume
driver: local
# Define the network (optional, but good practice)
networks: networks:
icarus-network: soaricarus-network:
driver: bridge driver: bridge
+24
View File
@@ -0,0 +1,24 @@
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite"
replication_factor = 1
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "${GARAGE_RPC_SECRET}"
rpc_bind_addr = "[::]:3901"
[s3_api]
s3_region = "maze"
api_bind_addr = "[::]:3900"
root_domain = ".s3.maze.localhost"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.maze.localhost"
index = "index.html"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "${GARAGE_ADMIN_TOKEN}"
metrics_token = "${GARAGE_METRICS_TOKEN}"
+3 -3
View File
@@ -36,11 +36,11 @@ pub async fn auth<B>(
(StatusCode::UNAUTHORIZED, Json(json_error)) (StatusCode::UNAUTHORIZED, Json(json_error))
})?; })?;
let secret_key = icarus_envy::environment::get_secret_main_key().await.value; let secret_key = sienvy::environment::get_secret_main_key().value;
let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256); let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256);
validation.set_audience(&["icarus"]); // Must match exactly what's in the token validation.set_audience(&["soaricarus"]);
let _claims = decode::<icarus_models::token::UserClaims>( let _claims = decode::<simodels::token::UserClaims>(
&token, &token,
&DecodingKey::from_secret(secret_key.as_ref()), &DecodingKey::from_secret(secret_key.as_ref()),
&validation, &validation,
+23 -26
View File
@@ -20,7 +20,7 @@ pub mod response {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct Response { pub struct Response {
pub message: String, pub message: String,
pub data: Vec<icarus_models::coverart::CoverArt>, pub data: Vec<simodels::coverart::CoverArt>,
} }
} }
@@ -28,7 +28,7 @@ pub mod response {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct Response { pub struct Response {
pub message: String, pub message: String,
pub data: Vec<icarus_models::coverart::CoverArt>, pub data: Vec<simodels::coverart::CoverArt>,
} }
} }
} }
@@ -68,21 +68,21 @@ pub mod endpoint {
let song_id = payload.song_id; let song_id = payload.song_id;
match crate::repo::song::get_song(&pool, &song_id).await { match crate::repo::song::get_song(&pool, &song_id).await {
Ok(song) => { Ok(song) => {
let directory = icarus_envy::environment::get_root_directory().await.value; let directory = sienvy::environment::get_root_directory().value;
let file_type = let file_type =
icarus_meta::detection::coverart::file_type_from_data(&data).unwrap(); simeta::detection::coverart::file_type_from_data(&data).unwrap();
let coverart_type = if file_type.file_type let coverart_type = if file_type.file_type
== icarus_meta::detection::coverart::constants::JPEG_TYPE == simeta::detection::coverart::constants::JPEG_TYPE
{ {
icarus_models::types::CoverArtType::JpegExtension simodels::types::CoverArtType::JpegExtension
} else if file_type.file_type } else if file_type.file_type
== icarus_meta::detection::coverart::constants::JPG_TYPE == simeta::detection::coverart::constants::JPG_TYPE
{ {
icarus_models::types::CoverArtType::JpgExtension simodels::types::CoverArtType::JpgExtension
} else if file_type.file_type } else if file_type.file_type
== icarus_meta::detection::coverart::constants::PNG_TYPE == simeta::detection::coverart::constants::PNG_TYPE
{ {
icarus_models::types::CoverArtType::PngExtension simodels::types::CoverArtType::PngExtension
} else { } else {
response.message = String::from("Invalid CoverArt type"); response.message = String::from("Invalid CoverArt type");
return ( return (
@@ -91,13 +91,11 @@ pub mod endpoint {
); );
}; };
let filename = let filename =
icarus_models::coverart::generate_filename(coverart_type, true) simodels::coverart::generate_filename(coverart_type, true).unwrap();
.unwrap();
let mut coverart = let mut coverart = simodels::coverart::init::init_coverart_dir_and_filename(
icarus_models::coverart::init::init_coverart_dir_and_filename( &directory, &filename,
&directory, &filename, );
);
coverart.title = song.album.clone(); coverart.title = song.album.clone();
coverart.file_type = file_type.file_type; coverart.file_type = file_type.file_type;
coverart.data = data; coverart.data = data;
@@ -200,23 +198,23 @@ pub mod endpoint {
axum::extract::Path(id): axum::extract::Path<uuid::Uuid>, axum::extract::Path(id): axum::extract::Path<uuid::Uuid>,
) -> (axum::http::StatusCode, axum::response::Response) { ) -> (axum::http::StatusCode, axum::response::Response) {
match repo::coverart::get_coverart(&pool, &id).await { match repo::coverart::get_coverart(&pool, &id).await {
Ok(coverart) => match icarus_models::coverart::io::to_data(&coverart) { Ok(coverart) => match simodels::coverart::io::to_data(&coverart) {
Ok(data) => { Ok(data) => {
let (file_type, img_type) = let (file_type, img_type) =
match icarus_meta::detection::coverart::file_type_from_data(&data) { match simeta::detection::coverart::file_type_from_data(&data) {
Ok(file_type) => { Ok(file_type) => {
if file_type.file_type if file_type.file_type
== icarus_meta::detection::coverart::constants::JPEG_TYPE == simeta::detection::coverart::constants::JPEG_TYPE
{ {
(file_type, icarus_models::types::CoverArtType::JpegExtension) (file_type, simodels::types::CoverArtType::JpegExtension)
} else if file_type.file_type } else if file_type.file_type
== icarus_meta::detection::coverart::constants::JPG_TYPE == simeta::detection::coverart::constants::JPG_TYPE
{ {
(file_type, icarus_models::types::CoverArtType::JpgExtension) (file_type, simodels::types::CoverArtType::JpgExtension)
} else if file_type.file_type } else if file_type.file_type
== icarus_meta::detection::coverart::constants::PNG_TYPE == simeta::detection::coverart::constants::PNG_TYPE
{ {
(file_type, icarus_models::types::CoverArtType::PngExtension) (file_type, simodels::types::CoverArtType::PngExtension)
} else { } else {
return ( return (
axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::http::StatusCode::INTERNAL_SERVER_ERROR,
@@ -235,8 +233,7 @@ pub mod endpoint {
let bytes = axum::body::Bytes::from(data); let bytes = axum::body::Bytes::from(data);
let mut response = bytes.into_response(); let mut response = bytes.into_response();
let headers = response.headers_mut(); let headers = response.headers_mut();
let filename = let filename = simodels::coverart::generate_filename(img_type, true).unwrap();
icarus_models::coverart::generate_filename(img_type, true).unwrap();
headers.insert( headers.insert(
axum::http::header::CONTENT_TYPE, axum::http::header::CONTENT_TYPE,
file_type.mime.parse().unwrap(), file_type.mime.parse().unwrap(),
+22 -29
View File
@@ -102,9 +102,9 @@ pub mod response {
mod helper { mod helper {
pub fn is_coverart_file_type_valid(file_type: &String) -> bool { pub fn is_coverart_file_type_valid(file_type: &String) -> bool {
let valid_file_types = vec![ let valid_file_types = vec![
String::from(icarus_meta::detection::coverart::constants::JPEG_TYPE), String::from(simeta::detection::coverart::constants::JPEG_TYPE),
String::from(icarus_meta::detection::coverart::constants::JPG_TYPE), String::from(simeta::detection::coverart::constants::JPG_TYPE),
String::from(icarus_meta::detection::coverart::constants::PNG_TYPE), String::from(simeta::detection::coverart::constants::PNG_TYPE),
]; ];
for valid_file_type in valid_file_types { for valid_file_type in valid_file_types {
@@ -150,18 +150,17 @@ pub mod endpoint {
let content_type = field.content_type().unwrap().to_string(); let content_type = field.content_type().unwrap().to_string();
let data = field.bytes().await.unwrap(); let data = field.bytes().await.unwrap();
let raw_data = data.to_vec(); let raw_data = data.to_vec();
let file_type = let file_type = match simeta::detection::coverart::file_type_from_data(&raw_data) {
match icarus_meta::detection::coverart::file_type_from_data(&raw_data) { Ok(file_type) => file_type,
Ok(file_type) => file_type, Err(err) => {
Err(err) => { eprintln!("Error: {err:?}");
eprintln!("Error: {err:?}"); response.message = err.to_string();
response.message = err.to_string(); return (
return ( axum::http::StatusCode::INTERNAL_SERVER_ERROR,
axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response),
axum::Json(response), );
); }
} };
};
if !super::helper::is_coverart_file_type_valid(&file_type.file_type) { if !super::helper::is_coverart_file_type_valid(&file_type.file_type) {
response.message = format!("CoverArt file type not supported: {file_type:?}"); response.message = format!("CoverArt file type not supported: {file_type:?}");
@@ -318,8 +317,7 @@ pub mod endpoint {
) -> (axum::http::StatusCode, axum::response::Response) { ) -> (axum::http::StatusCode, axum::response::Response) {
match repo::coverart::get_coverart_queue_data_with_id(&pool, &id).await { match repo::coverart::get_coverart_queue_data_with_id(&pool, &id).await {
Ok(data) => { Ok(data) => {
let file_type = let file_type = simeta::detection::coverart::file_type_from_data(&data).unwrap();
icarus_meta::detection::coverart::file_type_from_data(&data).unwrap();
let bytes = axum::body::Bytes::from(data); let bytes = axum::body::Bytes::from(data);
let mut response = bytes.into_response(); let mut response = bytes.into_response();
let headers = response.headers_mut(); let headers = response.headers_mut();
@@ -329,25 +327,20 @@ pub mod endpoint {
); );
let coverart_type = if file_type.file_type let coverart_type = if file_type.file_type
== icarus_meta::detection::coverart::constants::JPEG_TYPE == simeta::detection::coverart::constants::JPEG_TYPE
{ {
icarus_models::types::CoverArtType::JpegExtension simodels::types::CoverArtType::JpegExtension
} else if file_type.file_type } else if file_type.file_type == simeta::detection::coverart::constants::JPG_TYPE {
== icarus_meta::detection::coverart::constants::JPG_TYPE simodels::types::CoverArtType::JpgExtension
{ } else if file_type.file_type == simeta::detection::coverart::constants::PNG_TYPE {
icarus_models::types::CoverArtType::JpgExtension simodels::types::CoverArtType::PngExtension
} else if file_type.file_type
== icarus_meta::detection::coverart::constants::PNG_TYPE
{
icarus_models::types::CoverArtType::PngExtension
} else { } else {
return ( return (
axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::http::StatusCode::INTERNAL_SERVER_ERROR,
axum::response::Response::default(), axum::response::Response::default(),
); );
}; };
let filename = let filename = simodels::coverart::generate_filename(coverart_type, true).unwrap();
icarus_models::coverart::generate_filename(coverart_type, true).unwrap();
headers.insert( headers.insert(
axum::http::header::CONTENT_DISPOSITION, axum::http::header::CONTENT_DISPOSITION,
format!("attachment; filename=\"{filename}\"") format!("attachment; filename=\"{filename}\"")
+59 -2
View File
@@ -97,9 +97,9 @@ pub mod response {
} }
pub async fn is_song_valid(data: &[u8]) -> Result<bool, std::io::Error> { pub async fn is_song_valid(data: &[u8]) -> Result<bool, std::io::Error> {
match icarus_meta::detection::song::file_type_from_data(data) { match simeta::detection::song::file_type_from_data(data) {
Ok(file_type) => { Ok(file_type) => {
if file_type.file_type == icarus_meta::detection::song::constants::FLAC_TYPE { if file_type.file_type == simeta::detection::song::constants::FLAC_TYPE {
Ok(true) Ok(true)
} else { } else {
Ok(false) Ok(false)
@@ -156,6 +156,7 @@ pub mod endpoint {
); );
let raw_data: Vec<u8> = data.to_vec(); let raw_data: Vec<u8> = data.to_vec();
let copied_raw_data = data.to_vec();
match super::is_song_valid(&raw_data).await { match super::is_song_valid(&raw_data).await {
Ok(valid) => { Ok(valid) => {
if valid { if valid {
@@ -169,6 +170,62 @@ pub mod endpoint {
{ {
Ok(queued_song) => { Ok(queued_song) => {
results.push(queued_song); results.push(queued_song);
println!("Uploading to bucket");
let s3_endpoint_url =
sienvy::environment::get_env("S3_ENDPOINT_URL");
let bucket_name =
sienvy::environment::get_env("S3_BUCKET_NAME");
let region =
sienvy::environment::get_env("GARAGE_S3_REGION");
let access_key_id = sienvy::environment::get_env(
"GARAGE_DEFAULT_ACCESS_KEY",
);
let secret_key = sienvy::environment::get_env(
"GARAGE_DEFAULT_SECRET_KEY",
);
let lab_config = labyrinth::config::Config {
url: s3_endpoint_url.value,
bucket: bucket_name.value,
region: region.value,
access_key_id: access_key_id.value,
secret_key: secret_key.value,
};
println!("Labyrinth config: {lab_config:?}");
let lr = labyrinth::Labyrinth { config: lab_config };
let data = labyrinth::Data {
raw_data: copied_raw_data,
..Default::default()
};
let filename = simodels::song::generate_filename(
simodels::types::MusicType::FlacExtension,
true,
)
.unwrap();
println!("Filename: {filename:?}");
let file_path = format!("queued/song/{filename}");
println!("Path: {file_path:?}");
match lr.upload(&file_path, &data).await {
Ok(res) => {
println!("Result: {res:?}");
}
Err(err) => match err {
labyrinth::Error::Info(err_str) => {
eprintln!("Error: {:?}", err_str);
response.message = err_str.to_string();
return (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response));
}
labyrinth::Error::SError(err_s) => {
eprintln!("Error: {:?}", err_s);
response.message = err_s.to_string();
return (axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response));
}
},
}
} }
Err(err) => { Err(err) => {
response.message = err.to_string(); response.message = err.to_string();
+11 -13
View File
@@ -36,8 +36,8 @@ pub mod request {
|| !self.song_queue_id.is_nil() || !self.song_queue_id.is_nil()
} }
pub fn to_song(&self) -> icarus_models::song::Song { pub fn to_song(&self) -> simodels::song::Song {
icarus_models::song::Song { simodels::song::Song {
id: uuid::Uuid::nil(), id: uuid::Uuid::nil(),
title: self.title.clone(), title: self.title.clone(),
artist: self.artist.clone(), artist: self.artist.clone(),
@@ -71,7 +71,7 @@ pub mod response {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct Response { pub struct Response {
pub message: String, pub message: String,
pub data: Vec<icarus_models::song::Song>, pub data: Vec<simodels::song::Song>,
} }
} }
@@ -79,15 +79,15 @@ pub mod response {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct Response { pub struct Response {
pub message: String, pub message: String,
pub data: Vec<icarus_models::song::Song>, pub data: Vec<simodels::song::Song>,
} }
} }
pub mod delete_song { pub mod delete_song {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct SongAndCoverArt { pub struct SongAndCoverArt {
pub song: icarus_models::song::Song, pub song: simodels::song::Song,
pub coverart: icarus_models::coverart::CoverArt, pub coverart: simodels::coverart::CoverArt,
} }
#[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
@@ -134,12 +134,10 @@ pub mod endpoint {
if payload.is_valid() { if payload.is_valid() {
let mut song = payload.to_song(); let mut song = payload.to_song();
song.filename = icarus_models::song::generate_filename( song.filename =
icarus_models::types::MusicType::FlacExtension, simodels::song::generate_filename(simodels::types::MusicType::FlacExtension, true)
true, .unwrap();
) song.directory = sienvy::environment::get_root_directory().value;
.unwrap();
song.directory = icarus_envy::environment::get_root_directory().await.value;
match repo_queue::song::get_data(&pool, &payload.song_queue_id).await { match repo_queue::song::get_data(&pool, &payload.song_queue_id).await {
Ok(data) => { Ok(data) => {
@@ -340,7 +338,7 @@ pub mod endpoint {
axum::extract::Path(id): axum::extract::Path<uuid::Uuid>, axum::extract::Path(id): axum::extract::Path<uuid::Uuid>,
) -> (axum::http::StatusCode, axum::response::Response) { ) -> (axum::http::StatusCode, axum::response::Response) {
match repo::song::get_song(&pool, &id).await { match repo::song::get_song(&pool, &id).await {
Ok(song) => match icarus_models::song::io::to_data(&song) { Ok(song) => match simodels::song::io::to_data(&song) {
Ok(data) => { Ok(data) => {
let bytes = axum::body::Bytes::from(data); let bytes = axum::body::Bytes::from(data);
let mut response = bytes.into_response(); let mut response = bytes.into_response();
+15 -18
View File
@@ -28,20 +28,18 @@ mod cors {
axum::http::Method::POST, axum::http::Method::POST,
axum::http::Method::PUT, axum::http::Method::PUT,
axum::http::Method::DELETE, axum::http::Method::DELETE,
]) // Specify allowed methods:cite[2] ])
.allow_headers([ .allow_headers([
axum::http::header::CONTENT_TYPE, axum::http::header::CONTENT_TYPE,
axum::http::header::AUTHORIZATION, axum::http::header::AUTHORIZATION,
]) // Specify allowed headers:cite[2] ])
.allow_credentials(true) // If you need to send cookies or authentication headers:cite[2] .allow_credentials(true)
.max_age(std::time::Duration::from_secs(3600)); // Cache the preflight response for 1 hour:cite[2] .max_age(std::time::Duration::from_secs(3600)); // Cache the preflight response for 1 hour:cite[2]
// Dynamically set the allowed origin based on the environment match std::env::var(sienvy::keys::APP_ENV).as_deref() {
match std::env::var(icarus_envy::keys::APP_ENV).as_deref() {
Ok("production") => { Ok("production") => {
// In production, allow only your specific, trusted origins let allowed_origins_env = sienvy::environment::get_allowed_origins();
let allowed_origins_env = icarus_envy::environment::get_allowed_origins().await; match sienvy::utility::delimitize(&allowed_origins_env) {
match icarus_envy::utility::delimitize(&allowed_origins_env) {
Ok(alwd) => { Ok(alwd) => {
let allowed_origins: Vec<axum::http::HeaderValue> = alwd let allowed_origins: Vec<axum::http::HeaderValue> = alwd
.into_iter() .into_iter()
@@ -55,15 +53,14 @@ mod cors {
} }
} }
} }
_ => { _ => cors.allow_origin(vec![
// Development (default): Allow localhost origins "http://localhost:8000".parse().unwrap(),
cors.allow_origin(vec![ "http://127.0.0.1:8000".parse().unwrap(),
"http://localhost:8000".parse().unwrap(), "http://localhost:8001".parse().unwrap(),
"http://127.0.0.1:8000".parse().unwrap(), "http://127.0.0.1:8001".parse().unwrap(),
"http://localhost:4200".parse().unwrap(), "http://localhost:4200".parse().unwrap(),
"http://127.0.0.1:4200".parse().unwrap(), "http://127.0.0.1:4200".parse().unwrap(),
]) ]),
}
} }
} }
} }
@@ -84,7 +81,7 @@ mod cors {
coverart_queue_responses::wipe_data_from_coverart_queue::Response, coverart_responses::get_coverart::Response, coverart_queue_responses::wipe_data_from_coverart_queue::Response, coverart_responses::get_coverart::Response,
metadata_queue_responses::queue_metadata::Response, metadata_queue_responses::fetch_metadata::Response)), metadata_queue_responses::queue_metadata::Response, metadata_queue_responses::fetch_metadata::Response)),
tags( tags(
(name = "Icarus API", description = "Web API to manage music") (name = "soaricarus API", description = "Web API to manage music")
) )
)] )]
struct ApiDoc; struct ApiDoc;
+1 -3
View File
@@ -5,7 +5,7 @@ pub mod connection_settings {
} }
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let database_url = icarus_envy::environment::get_db_url().await.value; let database_url = sienvy::environment::get_db_url().value;
println!("Database url: {database_url}"); println!("Database url: {database_url}");
PgPoolOptions::new() PgPoolOptions::new()
@@ -15,8 +15,6 @@ pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
} }
pub async fn migrations(pool: &sqlx::PgPool) { pub async fn migrations(pool: &sqlx::PgPool) {
// Run migrations using the sqlx::migrate! macro
// Assumes your migrations are in a ./migrations folder relative to Cargo.toml
sqlx::migrate!("./migrations") sqlx::migrate!("./migrations")
.run(pool) .run(pool)
.await .await
+31 -23
View File
@@ -38,7 +38,7 @@ mod tests {
pub const LIMIT: usize = 6; pub const LIMIT: usize = 6;
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let tm_db_url = icarus_envy::environment::get_db_url().await.value; let tm_db_url = sienvy::environment::get_db_url().value;
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
sqlx::PgPool::connect_with(tm_options).await sqlx::PgPool::connect_with(tm_options).await
} }
@@ -51,7 +51,7 @@ mod tests {
} }
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> { pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
let db_url = icarus_envy::environment::get_db_url().await.value; let db_url = sienvy::environment::get_db_url().value;
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
sqlx::PgPool::connect_with(options).await sqlx::PgPool::connect_with(options).await
} }
@@ -61,7 +61,10 @@ mod tests {
db_name: &str, db_name: &str,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
let create_query = format!("CREATE DATABASE {}", db_name); let create_query = format!("CREATE DATABASE {}", db_name);
match sqlx::query(&create_query).execute(template_pool).await { match sqlx::query(sqlx::AssertSqlSafe(create_query))
.execute(template_pool)
.await
{
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(e), Err(e) => Err(e),
} }
@@ -73,12 +76,14 @@ mod tests {
db_name: &str, db_name: &str,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
let drop_query = format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name); let drop_query = format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name);
sqlx::query(&drop_query).execute(template_pool).await?; sqlx::query(sqlx::AssertSqlSafe(drop_query))
.execute(template_pool)
.await?;
Ok(()) Ok(())
} }
pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> { pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
let database_url = icarus_envy::environment::get_db_url().await.value; let database_url = sienvy::environment::get_db_url().value;
let parsed_url = url::Url::parse(&database_url)?; let parsed_url = url::Url::parse(&database_url)?;
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
@@ -106,13 +111,16 @@ mod tests {
} }
mod init { mod init {
use std::time::Duration;
pub async fn app(pool: sqlx::PgPool) -> axum::Router { pub async fn app(pool: sqlx::PgPool) -> axum::Router {
crate::config::init::routes() crate::config::init::routes()
.await .await
.layer(axum::Extension(pool)) .layer(axum::Extension(pool))
.layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024)) .layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024))
.layer(tower_http::timeout::TimeoutLayer::new( .layer(tower_http::timeout::TimeoutLayer::with_status_code(
std::time::Duration::from_secs(300), axum::http::StatusCode::OK,
Duration::from_secs(300),
)) ))
} }
} }
@@ -141,25 +149,25 @@ mod tests {
pub fn token_fields() -> (String, String, String) { pub fn token_fields() -> (String, String, String) {
( (
String::from("What a twist!"), String::from("What a twist!"),
String::from("icarus_test"), String::from("soaricarus_test"),
String::from("icarus"), String::from("soaricarus"),
) )
} }
pub const TEST_USER_ID: uuid::Uuid = uuid::uuid!("cc938368-615a-4694-b2ca-6e122fa31c52"); pub const TEST_USER_ID: uuid::Uuid = uuid::uuid!("cc938368-615a-4694-b2ca-6e122fa31c52");
pub async fn test_token() -> Result<String, josekit::JoseError> { pub async fn test_token() -> Result<String, josekit::JoseError> {
let key: String = icarus_envy::environment::get_secret_main_key().await.value; let key: String = sienvy::environment::get_secret_main_key().value;
let (message, issuer, audience) = token_fields(); let (message, issuer, audience) = token_fields();
let token_resource = icarus_models::token::TokenResource { let token_resource = simodels::token::TokenResource {
message: message, message: message,
issuer: issuer, issuer: issuer,
audiences: vec![audience], audiences: vec![audience],
id: TEST_USER_ID, id: TEST_USER_ID,
}; };
match icarus_models::token::create_token(&key, &token_resource, time::Duration::hours(1)) { match simodels::token::create_token(&key, &token_resource, time::Duration::hours(1)) {
Ok((access_token, _some_time)) => Ok(access_token), Ok((access_token, _some_time)) => Ok(access_token),
Err(err) => Err(err), Err(err) => Err(err),
} }
@@ -281,7 +289,7 @@ mod tests {
.uri(uri) .uri(uri)
.header( .header(
axum::http::header::CONTENT_TYPE, axum::http::header::CONTENT_TYPE,
icarus_meta::detection::song::constants::mime::FLAC, simeta::detection::song::constants::mime::FLAC,
) )
.header( .header(
axum::http::header::AUTHORIZATION, axum::http::header::AUTHORIZATION,
@@ -298,7 +306,7 @@ mod tests {
) -> Result<axum::response::Response, std::convert::Infallible> { ) -> Result<axum::response::Response, std::convert::Infallible> {
let mut form = MultipartForm::default(); let mut form = MultipartForm::default();
let _ = form.add_file( let _ = form.add_file(
icarus_meta::detection::coverart::constants::JPEG_TYPE, simeta::detection::coverart::constants::JPEG_TYPE,
"tests/I/Coverart-1.jpg", "tests/I/Coverart-1.jpg",
); );
@@ -905,10 +913,10 @@ mod tests {
let temp_file = let temp_file =
tempfile::tempdir().expect("Could not create test directory"); tempfile::tempdir().expect("Could not create test directory");
let test_dir = String::from(temp_file.path().to_str().unwrap()); let test_dir = String::from(temp_file.path().to_str().unwrap());
let song = icarus_models::song::Song { let song = simodels::song::Song {
directory: test_dir, directory: test_dir,
filename: icarus_models::song::generate_filename( filename: simodels::song::generate_filename(
icarus_models::types::MusicType::FlacExtension, simodels::types::MusicType::FlacExtension,
true, true,
) )
.unwrap(), .unwrap(),
@@ -2211,20 +2219,20 @@ mod tests {
coverart_directory: &String, coverart_directory: &String,
coverart_filename: &String, coverart_filename: &String,
) -> Result<(Vec<u8>, Vec<u8>), std::io::Error> { ) -> Result<(Vec<u8>, Vec<u8>), std::io::Error> {
let song = icarus_models::song::Song { let song = simodels::song::Song {
directory: song_directory.clone(), directory: song_directory.clone(),
filename: song_filename.clone(), filename: song_filename.clone(),
..Default::default() ..Default::default()
}; };
let coverart = icarus_models::coverart::CoverArt { let coverart = simodels::coverart::CoverArt {
directory: coverart_directory.clone(), directory: coverart_directory.clone(),
filename: coverart_filename.clone(), filename: coverart_filename.clone(),
..Default::default() ..Default::default()
}; };
match icarus_models::song::io::to_data(&song) { match simodels::song::io::to_data(&song) {
Ok(song_data) => match icarus_models::coverart::io::to_data(&coverart) { Ok(song_data) => match simodels::coverart::io::to_data(&coverart) {
Ok(coverart_data) => Ok((song_data, coverart_data)), Ok(coverart_data) => Ok((song_data, coverart_data)),
Err(err) => Err(err), Err(err) => Err(err),
}, },
@@ -2240,14 +2248,14 @@ mod tests {
coverart_filename: &String, coverart_filename: &String,
coverart_data: Vec<u8>, coverart_data: Vec<u8>,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
let song = icarus_models::song::Song { let song = simodels::song::Song {
directory: song_directory.clone(), directory: song_directory.clone(),
filename: song_filename.clone(), filename: song_filename.clone(),
data: song_data, data: song_data,
..Default::default() ..Default::default()
}; };
let coverart = icarus_models::coverart::CoverArt { let coverart = simodels::coverart::CoverArt {
directory: coverart_directory.clone(), directory: coverart_directory.clone(),
filename: coverart_filename.clone(), filename: coverart_filename.clone(),
data: coverart_data, data: coverart_data,
+7 -7
View File
@@ -2,7 +2,7 @@ use sqlx::Row;
pub async fn create( pub async fn create(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
coverart: &icarus_models::coverart::CoverArt, coverart: &simodels::coverart::CoverArt,
song_id: &uuid::Uuid, song_id: &uuid::Uuid,
) -> Result<uuid::Uuid, sqlx::Error> { ) -> Result<uuid::Uuid, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
@@ -36,7 +36,7 @@ pub async fn create(
pub async fn get_coverart( pub async fn get_coverart(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
id: &uuid::Uuid, id: &uuid::Uuid,
) -> Result<icarus_models::coverart::CoverArt, sqlx::Error> { ) -> Result<simodels::coverart::CoverArt, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
SELECT id, title, directory, filename, file_type, song_id FROM "coverart" WHERE id = $1; SELECT id, title, directory, filename, file_type, song_id FROM "coverart" WHERE id = $1;
@@ -50,7 +50,7 @@ pub async fn get_coverart(
}); });
match result { match result {
Ok(row) => Ok(icarus_models::coverart::CoverArt { Ok(row) => Ok(simodels::coverart::CoverArt {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
@@ -84,7 +84,7 @@ pub async fn get_coverart(
pub async fn get_coverart_with_song_id( pub async fn get_coverart_with_song_id(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
song_id: &uuid::Uuid, song_id: &uuid::Uuid,
) -> Result<icarus_models::coverart::CoverArt, sqlx::Error> { ) -> Result<simodels::coverart::CoverArt, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
SELECT id, title, directory, filename, file_type, song_id FROM "coverart" WHERE song_id = $1; SELECT id, title, directory, filename, file_type, song_id FROM "coverart" WHERE song_id = $1;
@@ -98,7 +98,7 @@ pub async fn get_coverart_with_song_id(
}); });
match result { match result {
Ok(row) => Ok(icarus_models::coverart::CoverArt { Ok(row) => Ok(simodels::coverart::CoverArt {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
@@ -132,7 +132,7 @@ pub async fn get_coverart_with_song_id(
pub async fn delete_coverart( pub async fn delete_coverart(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
id: &uuid::Uuid, id: &uuid::Uuid,
) -> Result<icarus_models::coverart::CoverArt, sqlx::Error> { ) -> Result<simodels::coverart::CoverArt, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
DELETE FROM "coverart" DELETE FROM "coverart"
@@ -148,7 +148,7 @@ pub async fn delete_coverart(
}); });
match result { match result {
Ok(row) => Ok(icarus_models::coverart::CoverArt { Ok(row) => Ok(simodels::coverart::CoverArt {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
+9 -11
View File
@@ -2,7 +2,7 @@ use sqlx::Row;
pub async fn insert( pub async fn insert(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
song: &icarus_models::song::Song, song: &simodels::song::Song,
) -> Result<(time::OffsetDateTime, uuid::Uuid), sqlx::Error> { ) -> Result<(time::OffsetDateTime, uuid::Uuid), sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
@@ -52,7 +52,7 @@ pub async fn insert(
pub async fn get_song( pub async fn get_song(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
id: &uuid::Uuid, id: &uuid::Uuid,
) -> Result<icarus_models::song::Song, sqlx::Error> { ) -> Result<simodels::song::Song, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
SELECT * FROM "song" WHERE id = $1 SELECT * FROM "song" WHERE id = $1
@@ -72,7 +72,7 @@ pub async fn get_song(
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
.unwrap(); .unwrap();
Ok(icarus_models::song::Song { Ok(simodels::song::Song {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
@@ -145,9 +145,7 @@ pub async fn get_song(
} }
} }
pub async fn get_all_songs( pub async fn get_all_songs(pool: &sqlx::PgPool) -> Result<Vec<simodels::song::Song>, sqlx::Error> {
pool: &sqlx::PgPool,
) -> Result<Vec<icarus_models::song::Song>, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
r#" r#"
SELECT * FROM "song"; SELECT * FROM "song";
@@ -161,7 +159,7 @@ pub async fn get_all_songs(
match result { match result {
Ok(rows) => { Ok(rows) => {
let mut songs: Vec<icarus_models::song::Song> = Vec::new(); let mut songs: Vec<simodels::song::Song> = Vec::new();
for row in rows { for row in rows {
let date_created_time: time::OffsetDateTime = row let date_created_time: time::OffsetDateTime = row
@@ -169,7 +167,7 @@ pub async fn get_all_songs(
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
.unwrap(); .unwrap();
let song = icarus_models::song::Song { let song = simodels::song::Song {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
@@ -250,9 +248,9 @@ pub async fn get_all_songs(
pub async fn delete_song( pub async fn delete_song(
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
id: &uuid::Uuid, id: &uuid::Uuid,
) -> Result<icarus_models::song::Song, sqlx::Error> { ) -> Result<simodels::song::Song, sqlx::Error> {
let result = sqlx::query( let result = sqlx::query(
// icarus_models::song::Song, // simodels::song::Song,
r#" r#"
DELETE FROM "song" DELETE FROM "song"
WHERE id = $1 WHERE id = $1
@@ -273,7 +271,7 @@ pub async fn delete_song(
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)
.unwrap(); .unwrap();
Ok(icarus_models::song::Song { Ok(simodels::song::Song {
id: row id: row
.try_get("id") .try_get("id")
.map_err(|_e| sqlx::Error::RowNotFound) .map_err(|_e| sqlx::Error::RowNotFound)