From 2438993efa3fc4fca6acdbfe569f6bc87cc9610f Mon Sep 17 00:00:00 2001 From: Jochen Schalanda Date: Thu, 7 Nov 2024 09:57:12 +0100 Subject: [PATCH] feat: add support for other asset stores than S3 (#59) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hong Minhee (洪 民憙) --- .env.sample | 5 +- .gitignore | 1 + CHANGES.md | 12 ++ bun.lockb | Bin 159754 -> 179994 bytes compose-fs.yaml | 32 +++++ compose.yaml | 3 +- docs/src/content/docs/install/env.mdx | 135 +++++++++++++++----- docs/src/content/docs/ja/install/env.mdx | 134 ++++++++++++++----- docs/src/content/docs/ko/install/env.mdx | 132 ++++++++++++++----- docs/src/content/docs/zh-cn/install/env.mdx | 118 +++++++++++++---- package.json | 3 + src/api/v1/accounts.ts | 87 ++++++++----- src/api/v1/media.ts | 33 +++-- src/api/v1/statuses.ts | 7 +- src/api/v2/index.ts | 14 +- src/federation/account.ts | 19 ++- src/federation/inbox.ts | 46 ++++--- src/federation/post.ts | 31 +++-- src/index.tsx | 13 +- src/media.ts | 29 +++-- src/pages/accounts.tsx | 34 +++-- src/pages/emojis.tsx | 33 +++-- src/pages/federation.tsx | 7 +- src/s3.ts | 24 ---- src/storage.ts | 111 ++++++++++++++++ src/text.ts | 2 +- 26 files changed, 800 insertions(+), 265 deletions(-) create mode 100644 compose-fs.yaml delete mode 100644 src/s3.ts create mode 100644 src/storage.ts diff --git a/.env.sample b/.env.sample index cd4f879..4bf9526 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,4 @@ DATABASE_URL=postgresql://user:password@localhost:5432/dbname -REDIS_URL=redis://localhost/0 HOME_URL=https://example.com/ # optional; if present, the home page will redirect to this URL SECRET_KEY=secret_key # generate a secret key with `openssl rand -base64 32` LOG_LEVEL=info @@ -12,10 +11,12 @@ LISTEN_PORT=3000 # is implemented. ALLOW_PRIVATE_ADDRESS=false REMOTE_ACTOR_FETCH_POSTS=10 +DRIVE_DISK= +ASSET_URL_BASE= +FS_ASSET_PATH= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= S3_REGION= S3_ENDPOINT_URL= S3_BUCKET= -S3_URL_BASE= S3_FORCE_PATH_STYLE=false diff --git a/.gitignore b/.gitignore index ceb72e4..0768bb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env +assets/ fedify-hollo-*.tgz node_modules/ diff --git a/CHANGES.md b/CHANGES.md index ffdd334..cc281f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,18 @@ Version 0.3.0 To be released. + - Added support for local filesystem storage for media files. + You can now configure `DRIVE_DISK=fs` and `FS_ASSET_PATH` to store media + files in the local filesystem. [[#59]] + + - Added `DRIVE_DISK` environment variable. + - Added `FS_ASSET_PATH` environment variable. + - Added `ASSET_URL_BASE` environment variable to replace `S3_URL_BASE`. + - Deprecated `S3_URL_BASE` environment variable in favor of + `ASSET_URL_BASE`. + +[#59]: https://github.com/dahlia/hollo/pull/59 + Version 0.2.1 ------------- diff --git a/bun.lockb b/bun.lockb index f69ee4c10d770686dd2c1c75499b4d794c1af1cb..24736f9ae68ea93265e3ed229472e4b0885dcd8c 100755 GIT binary patch delta 40737 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 delta 29870 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 F{|EaF3sL|8 diff --git a/compose-fs.yaml b/compose-fs.yaml new file mode 100644 index 0000000..cd94e2c --- /dev/null +++ b/compose-fs.yaml @@ -0,0 +1,32 @@ +services: + hollo: + image: ghcr.io/dahlia/hollo:canary + ports: + - "3000:3000" + environment: + DATABASE_URL: "postgres://user:password@postgres:5432/database" + SECRET_KEY: "${SECRET_KEY}" + LOG_LEVEL: "${LOG_LEVEL}" + BEHIND_PROXY: "${BEHIND_PROXY}" + DRIVE_DISK: fs + ASSET_URL_BASE: http://localhost:3000/assets/ + FS_ASSET_PATH: /var/lib/hollo + depends_on: + - postgres + volumes: + - assets_data:/var/lib/hollo + restart: unless-stopped + + postgres: + image: postgres:17 + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_DB: database + volumes: + - postgres_data:/var/lib/postgresql/data + restart: unless-stopped + +volumes: + postgres_data: + assets_data: diff --git a/compose.yaml b/compose.yaml index a8769b6..6fed987 100644 --- a/compose.yaml +++ b/compose.yaml @@ -8,9 +8,10 @@ services: SECRET_KEY: "${SECRET_KEY}" LOG_LEVEL: "${LOG_LEVEL}" BEHIND_PROXY: "${BEHIND_PROXY}" + DRIVE_DISK: s3 + ASSET_URL_BASE: http://localhost:9000/hollo/ S3_REGION: us-east-1 S3_BUCKET: hollo - S3_URL_BASE: http://localhost:9000/hollo/ S3_ENDPOINT_URL: http://minio:9000 S3_FORCE_PATH_STYLE: "true" AWS_ACCESS_KEY_ID: minioadmin diff --git a/docs/src/content/docs/install/env.mdx b/docs/src/content/docs/install/env.mdx index 65cf33c..66fbabd 100644 --- a/docs/src/content/docs/install/env.mdx +++ b/docs/src/content/docs/install/env.mdx @@ -9,6 +9,10 @@ Hollo is configured using environment variables. You can set them in an *.env* file in the root directory of the project, or you can set them using Docker's `-e`/`--env` option or Railway's environment variables. + +Basic settings +-------------- + ### `PORT` The port number to listen on. 3000 by default. @@ -18,11 +22,6 @@ The port number to listen on. 3000 by default. The URL of the PostgreSQL database, e.g., `postgresql://hollo:password@localhost/hollo`. -### `HOME_URL` - -If present, the home page will redirect to this URL. If not set, the home page -will show the list of accounts on the instance. - ### `SECRET_KEY` The secret key for securing the session. You can generate a random secret key @@ -32,6 +31,41 @@ using the following command: openssl rand -hex 32 ~~~~ +### `BEHIND_PROXY` + +Set this to `true` if Hollo is behind a reverse proxy. If you place the Hollo +behind an L7 load balancer (you usually should do this), turn this on. + +Turned off by default. + + + +### `ALLOW_PRIVATE_ADDRESS` + +Setting this to `true` disables SSRF (Server-Side Request Forgery) protection. + +Turn on to test in local network. + +Turned off by default. + + + + +Additional features +------------------- + +### `HOME_URL` + +If present, the home page will redirect to this URL. If not set, the home page +will show the list of accounts on the instance. + ### `REMOTE_ACTOR_FETCH_POSTS` The number of recent public posts to fetch from remote actors when they are @@ -39,6 +73,10 @@ encountered first time. `10` by default. + +Logging +------- + ### `LOG_LEVEL` The log level for the application. `debug`, `info`, `warning`, `error`, and @@ -52,61 +90,96 @@ Set this to `true` to log SQL queries. Turned off by default. -### `BEHIND_PROXY` -Set this to `true` if Hollo is behind a reverse proxy. If you place the Hollo -behind an L7 load balancer (you usually should do this), turn this on. +Asset storage +------------- -Turned off by default. +### `DRIVE_DISK` -