fix: new storage architecture

This commit is contained in:
charlesgauthereau
2026-02-02 21:46:53 +01:00
parent 614a9e057c
commit cdd01e695c
8 changed files with 328 additions and 62 deletions
+124
View File
@@ -0,0 +1,124 @@
import {NextResponse} from "next/server";
import fs from "fs";
import path from "path";
//
// export async function POST(request: Request) {
// try {
// const body = await request.json();
// console.log("tusd hook payload:", body);
//
// return NextResponse.json({
// "Upload-Defer-Length": true,
// "Upload-Metadata": "name somefilename",
// });
// } catch (error) {
// console.error("Error in POST handler:", error);
// return NextResponse.json(
// { error: "Internal server error" },
// { status: 500 }
// );
// }
// }
// export async function POST(request: Request) {
// try {
// const body = await request.json();
// console.log("TUSD hook payload:", body);
//
// // Pre-create hook: must return Upload-Defer-Length or Upload-Length
// if (body.event === "pre-create") {
// return NextResponse.json({
// "Upload-Defer-Length": true, // defer the upload length
// "Upload-Metadata": "name somefilename" // optional metadata
// });
// }
//
// // Post-receive hook: handle finished uploads
// if (body.event === "post-receive") {
// console.log(`Upload finished: ${body.id}, size: ${body.upload_length}`);
// // process the file, AES encryption, move, etc.
// }
//
// return NextResponse.json({ ok: true }); // safe fallback for other events
// } catch (error) {
// console.error("Hook error:", error);
// return NextResponse.json({ error: "Internal server error" }, { status: 500 });
// }
// }
export async function POST(request: Request) {
try {
const body = await request.json();
console.log("TUSD hook payload:", body);
const event = body.Event
const headers = event.HTTPRequest.Header
// if (body.event === "pre-create") {
// return NextResponse.json({
// "Upload-Defer-Length": true
// });
// }
console.log("TUSD hook payload:", body.Type);
console.log("TUSD hook payload:", headers);
if (
body.Type === "post-receive" &&
event.Upload.SizeIsDeferred === false &&
event.Upload.Offset === event.Upload.Size
) {
const id = event.Upload.ID;
// const extensionFile = headers["X-Extension"]?.[0] ?? ".bin";
const extensionFile = ".enc";
const filePath = path.join(process.cwd(), "/private/uploads/backups/");
fs.renameSync(
`${filePath}${id}`,
`${filePath}${id}${extensionFile}`
);
}
// if (body.Type === "post-receive"){
// // const id = event.Upload.ID
// // const extensionFile = headers["X-Extension"]?.[0] ?? ".bin";
// // const extensionFile = ".enc";
// // const filePath = path.join(process.cwd(), "/private/uploads/backups/");
// //
// // fs.renameSync(
// // `${filePath}${id}`,
// // `${filePath}${id}${extensionFile}`
// // );
// }
// Post-receive hook: handle finished uploads
if (body.event === "post-receive") {
console.log(`Upload finished: ${body.id}, size: ${body.upload_length}`);
// process the file, AES encryption, move, etc.
const id = body.id;
const ext = body.upload.metaData?.extension ?? ".bin";
console.log(body)
console.log("Upload finished: ", id);
console.log("Ext: ", ext);
// fs.renameSync(
// `/data/uploads/backups/${id}`,
// `/data/uploads/backups/${id}${ext}`
// );
}
return NextResponse.json({}); // no Upload-Defer-Length
} catch (error) {
console.error("Hook error:", error);
return NextResponse.json({error: "Internal server error"}, {status: 500});
}
}
+17
View File
@@ -17,5 +17,22 @@ services:
timeout: 5s
retries: 5
tusd:
image: tusproject/tusd:v2.8.0
ports:
- "1080:8080"
command: >
-upload-dir /data/uploads/backups
-hooks-http http://localhost:8887/api/tus/hooks
-max-size 21474836480
# -max-size 54975581388
# -max-size 54975581388
extra_hosts:
- "localhost:host-gateway"
volumes:
- ./private/uploads/backups:/data/uploads/backups
volumes:
postgres-data:
+162 -58
View File
@@ -1,53 +1,177 @@
FROM node:22-alpine AS base
#FROM node:22-alpine AS base
#
#RUN apk add --update --no-cache \
# libc6-compat \
# openssl \
# tzdata
#
#FROM base AS tusd-base
#
#RUN apk add --no-cache curl ca-certificates bash \
# && TUSD_VERSION=1.28.0 \
# && curl -L -o /usr/local/bin/tusd https://github.com/tus/tusd/releases/download/v${TUSD_VERSION}/tusd-${TUSD_VERSION}-linux-amd64 \
# && chmod +x /usr/local/bin/tusd
#
#
#FROM base AS build-env
#
#RUN apk add --update --no-cache \
# build-base \
# g++ \
# make \
# libtool \
# autoconf \
# automake
#
#RUN corepack enable && corepack prepare pnpm@latest --activate
#
#
#FROM build-env AS deps
#
#WORKDIR /app
#
#COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
#
#RUN pnpm i --frozen-lockfile
#
#
#
#
#FROM build-env AS dev
#
#COPY --from=tusd-base /usr/local/bin/tusd /usr/local/bin/tusd
#
#
#WORKDIR /app
#
#COPY --from=deps /app/node_modules ./node_modules
#COPY . .
#
#USER root
#
#RUN chmod +x /app/docker/entrypoints/app-dev-entrypoint.sh
#ENTRYPOINT ["sh","/app/docker/entrypoints/app-dev-entrypoint.sh"]
#
#
#FROM build-env AS builder
#
#WORKDIR /app
#COPY --from=deps /app/node_modules ./node_modules
#COPY . .
#
#ENV NEXT_TELEMETRY_DISABLED=1
#
#RUN pnpm run build
#
#
#FROM base AS prod
#
#COPY --from=tusd-base /usr/local/bin/tusd /usr/local/bin/tusd
#
#WORKDIR /app
#
#ENV NODE_ENV=production
#ENV NEXT_TELEMETRY_DISABLED=1
#
#RUN addgroup --system --gid 1001 nodejs
#RUN adduser --system --uid 1001 nextjs
#
#COPY --from=builder /app/public ./public
#
#RUN mkdir .next
#RUN chown nextjs:nodejs .next
#RUN mkdir -p /app/private/uploads
#RUN chown -R nextjs:nodejs /app/private
#RUN chown -R nextjs:nodejs /app/public
#
#COPY --from=builder /app/next.config.ts ./
#
#COPY --from=builder /app/portabase.config.ts ./
#COPY --from=builder /app/drizzle.config.ts ./
#COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
#COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
#COPY --chown=nextjs:nodejs src/db ./src/db
#
#USER root
#
#COPY ./docker/entrypoints/app-prod-entrypoint.sh /app/app-prod-entrypoint.sh
#RUN chmod +x /app/app-prod-entrypoint.sh
#
#EXPOSE 80
#
#ENV PORT=80
#
#ENV HOSTNAME="0.0.0.0"
#
#USER nextjs
#
#ENTRYPOINT ["sh","/app/app-prod-entrypoint.sh"]
RUN apk add --update --no-cache \
libc6-compat \
openssl \
tzdata
FROM node:22-bullseye AS base
RUN apt-get update && apt-get install -y \
curl \
ca-certificates \
bash \
tzdata \
libc6 \
build-essential \
g++ \
make \
autoconf \
automake \
libtool \
git \
&& rm -rf /var/lib/apt/lists/*
FROM base AS tusd-base
ENV TUSD_VERSION=2.8.0
RUN apt-get update && apt-get install -y \
curl \
ca-certificates \
bash \
tar \
gzip \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# Download and extract tusd
RUN curl -L -o /tmp/tusd.tar.gz \
https://github.com/tus/tusd/releases/download/v${TUSD_VERSION}/tusd_linux_amd64.tar.gz \
&& mkdir -p /usr/local/bin \
&& tar -xzf /tmp/tusd.tar.gz -C /tmp \
# Move the actual binary, whatever its name/folder inside tar
&& mv /tmp/*/tusd /usr/local/bin/tusd \
&& chmod +x /usr/local/bin/tusd \
&& /usr/local/bin/tusd --version
FROM base AS build-env
RUN apk add --update --no-cache \
build-base \
g++ \
make \
libtool \
autoconf \
automake
RUN corepack enable && corepack prepare pnpm@latest --activate
FROM build-env AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm i --frozen-lockfile
FROM build-env AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=tusd-base /usr/local/bin/tusd /usr/local/bin/tusd
WORKDIR /app
COPY . .
USER root
RUN chmod +x /app/docker/entrypoints/app-dev-entrypoint.sh
ENTRYPOINT ["sh","/app/docker/entrypoints/app-dev-entrypoint.sh"]
FROM build-env AS builder
WORKDIR /app
@@ -55,57 +179,37 @@ COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm run build
FROM base AS prod
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN corepack enable && corepack prepare pnpm@latest --activate
ENV PORT=80
ENV HOSTNAME="0.0.0.0"
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
RUN mkdir -p /app/private/uploads
RUN chown -R nextjs:nodejs /app/private
RUN chown -R nextjs:nodejs /app/public
COPY --from=builder /app/next.config.ts ./
COPY --from=builder /app/server ./server
COPY --from=builder /app/src ./src
COPY --from=builder /app/portabase.config.ts ./
COPY --from=builder /app/drizzle.config.ts ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --chown=nextjs:nodejs src/db ./src/db
COPY --from=builder --chown=1001:1001 /app/.next/standalone ./
COPY --from=builder --chown=1001:1001 /app/.next/static ./.next/static
COPY --chown=1001:1001 src/db ./src/db
COPY --from=deps /app/node_modules ./node_modules
USER root
COPY --from=tusd-base /usr/local/bin/tusd /usr/local/bin/tusd
RUN mkdir -p .next /app/private/uploads \
&& chown -R nextjs:nodejs .next /app/private /app/public
USER root
COPY ./docker/entrypoints/app-prod-entrypoint.sh /app/app-prod-entrypoint.sh
RUN chmod +x /app/app-prod-entrypoint.sh
EXPOSE 80
ENV PORT=80
ENV HOSTNAME="0.0.0.0"
USER nextjs
ENTRYPOINT ["sh","/app/app-prod-entrypoint.sh"]
+6 -2
View File
@@ -7,8 +7,12 @@ else
echo "[WARN] No TZ provided, using default container timezone"
fi
pnpm run start
#node server.js
# Start tusd as background process
mkdir -p /app/private/uploads
echo "▶ Starting tusd server..."
tusd --dir /app/private/uploads --hooks-http http://localhost:80/api/tus/hooks --port 1080 &
node server.js
exec "$@"
+14
View File
@@ -47,6 +47,20 @@ const nextConfig: NextConfig = {
},
proxyClientMaxBodySize: '10gb',
},
async rewrites() {
return [
{
source: '/tus/metrics',
destination: 'http://localhost:1080/metrics',
},
{
source: '/tus/files',
destination: 'http://localhost:1080/files',
},
]
},
async headers() {
return [
{
+3 -2
View File
@@ -3,9 +3,10 @@
"version": "1.2.5-rc.8",
"private": true,
"scripts": {
"dev": "NODE_ENV=development tsx watch server/server.ts",
"dev": "next dev --turbopack -p 8887",
"build": "next build --experimental-build-mode compile",
"start": "NODE_ENV=production tsx server/server.ts",
"start": "next start",
"lint": "next lint",
"email": "email dev --dir ./src/components/emails",
+1
View File
@@ -56,6 +56,7 @@ function checkRouteExists(pathname: string) {
/^\/api\/agent\/[^/]+\/restore\/?$/,
/^\/api\/files\/images\/[^/]+\/?$/,
/^\/api\/files\/backups\/?$/,
/^\/api\/tus\/hooks\/?$/,
/^\/api\/events\/?$/,
/^\/api\/init\/?$/,
/^\/api\/config\/?$/,
@@ -77,6 +77,7 @@ export default async function uploadTempFileToProviders(
? await dispatchStorage(input, policy.id)
: await dispatchStorage(input, undefined, policy.storageChannelId);
} catch (err: any) {
console.error(err);
result = {success: false, provider: null, error: err.message};
}
await db.update(drizzleDb.schemas.backupStorage)