This is Mensatt's image service. It handles uploads of images and serves them.
This section defines the steps an image that is uploaded to this service undergoes from upload to serving.
-
Upload: Typically images are uploaded to this service during creation of reviews in the frontend. Once uploaded, images are saved in their original format to
RAW_PATH, then rotated, stripped of their EXIF metadata and saved as AVIF inPENDING_PATH.Note: Uploading images before a review is submitted is done to speed up the review submission, as the image is likely to be uploaded by the time the user enters their username and/or review text. Also, images that stay in the pending folder for longer than an hour will be deleted on a regular basis. Raw images are deleted as well if the corresponding image in the pending folder is deleted.
-
Submission: Once a review is submitted, the image is moved from
PENDING_PATHtoUNAPPROVED_PATH. -
Approval: Images need to be approved by an administrator. Once an image is approved it is moved from
UNAPPROVED_PATHtoORIGINAL_PATHand the corresponding raw image inRAW_PATHis retained. -
Serving requests: The first time an image (with a specific size and quality) is requested, it gets generated from the image in
ORIGINAL_PATHand cached toCACHE_PATH. Every following request (with the same size and quality) gets served fromCACHE_PATH.
The paths mentioned here are constant and defined in src/constants.rs.
| Name | Method | Description | Authorization required? |
|---|---|---|---|
/upload |
POST | Upload an image. Step 1 of Image Flow. |
no |
/submit/:id |
POST | Submit image with id. Step 2 of Image Flow. |
yes |
/approve/:id |
POST | Approve image with id. Step 3 of Image Flow. |
yes |
/image/:id |
GET | Get image with id. Step 4 of Image Flow. |
no¹ |
/image/:id |
DELETE | Delete image with id. Also deletes it from cache. |
yes |
/unapprove/:id |
POST | Reverse operation of approving. Also deletes image from cache. |
yes |
/rotate |
POST | Rotates an existing image. Requires id and angle parameter. |
yes |
Authorization is done by providing this header in a request:
Authorization: Bearer api_key_goes_here
¹: Authorization is required if you want to view unapproved images
-
Clone this repo on the target machine
-
Build and start the service in the background with
docker compose up -dThe service will be listening on the address defined by
LISTEN_ADDRinsrc/constants.rs
If needed you can manually (re)build the image with
docker compose build
-
Make sure to have
cargo-watchinstalled by runningcargo install cargo-watchNote:
cargo-watchist not a requirement for building/running this project, but we found it makes development easier by providing auto reload when a file is changed. For more details on what it does see here. -
Make sure you have
API_KEY_HASHdefined in.env(see.env.distfor an example) and source it withexport $(grep -Ev '^\s*(#|;|/|$)' .env | xargs)Note: The regex ensures empty lines and comments are ignored.
If you want to use any other characters for comments in.env, make sure to add them to the reqex. -
You can then build and run the current version of the code with
RUST_LOG=mensatt_img=debug cargo watch -w src -x runwhere
RUST_LOG=mensatt_img=debugsets the loglevel formensatt_imgpackage todebugIf you do not want to (or cannot) use
cargo-watch, you can also simply runRUST_LOG=mensatt_img=debug cargo run
Configuration is done via a YAML-File. The default path is config.yml in the current working directory (of the executable).
If desired, the configuration path can be overwritten via the CONFIG_PATH environment variable.
A sample configuration is provided as config.dist.yml.
| Name | Description | Default | Required? |
|---|---|---|---|
API_KEY_HASHES |
Argon2id hash of the API key to be used. Can be generated here. Make sure to use Encoded Form. |
- | yes |
CORS_ALLOWED_ORIGINS |
List of allowed CORS origins | - | yes |
CORS_ALLOWED_METHODS |
List of allowed CORS methods | GET |
no |
Configuration options from the configuration file can be overwritten via environment variables.
Note that overriding list values (arrays), works using ';' as the separator. For example, API_KEY_HASHES='HASH_1;HASH:2'.