Commit 1776bb7a authored by 何 广一's avatar 何 广一
Browse files

created docker image

parent 9bf2ef80
module.exports = {
ignorePatterns: ['src/generated/prisma/**'],
extends: ['next/core-web-vitals'],
rules: {},
};
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
FROM node:20-alpine AS base FROM node:20-alpine AS base
WORKDIR /app WORKDIR /app
COPY package.json pnpm-lock.yaml ./ COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile --shamefully-hoist RUN npm install -g pnpm && pnpm install --shamefully-hoist
# ---------- Prisma + SQLite ---------- # ---------- Prisma + SQLite ----------
COPY prisma ./prisma COPY prisma ./prisma
...@@ -14,15 +14,17 @@ RUN pnpm prisma migrate deploy --schema ./prisma/schema.prisma ...@@ -14,15 +14,17 @@ RUN pnpm prisma migrate deploy --schema ./prisma/schema.prisma
# ---------- 构建 ---------- # ---------- 构建 ----------
COPY . . COPY . .
ENV REDIS_URL=
RUN pnpm build RUN pnpm build
# ---------- 运行时 ---------- # ---------- 运行时 ----------
FROM node:20-alpine AS runner FROM node:20-alpine AS runner
WORKDIR /app WORKDIR /app
RUN apk add --no-cache redis RUN apk add --no-cache redis
COPY --from=base /app/.next ./.next
COPY --from=base /app/node_modules ./node_modules COPY --from=base /app/.next/standalone ./
COPY --from=base /app/package.json ./package.json COPY --from=base /app/.next/static ./.next/static
COPY --from=base /app/public ./public
COPY --from=base /app/prisma ./prisma COPY --from=base /app/prisma ./prisma
COPY --from=base /app/.env.docker ./.env COPY --from=base /app/.env.docker ./.env
......
...@@ -11,6 +11,10 @@ const compat = new FlatCompat({ ...@@ -11,6 +11,10 @@ const compat = new FlatCompat({
const eslintConfig = [ const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"), ...compat.extends("next/core-web-vitals", "next/typescript"),
{
ignores: ["src/generated/prisma/**"],
},
]; ];
export default eslintConfig; export default eslintConfig;
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: 'standalone'
/* config options here */ /* config options here */
}; };
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"redis": "start redis-server --port 6379" "redis": "start redis-server --port 6379"
}, },
"dependencies": { "dependencies": {
"@types/node": "^20",
"@types/react": "^19", "@types/react": "^19",
"@types/react-dom": "^19", "@types/react-dom": "^19",
"@prisma/client": "6.14.0", "@prisma/client": "6.14.0",
......
This diff is collapsed.
...@@ -238,8 +238,8 @@ export async function AddMessage(data: Ty.MessageAddArgs): Promise<Ty.BackendRes ...@@ -238,8 +238,8 @@ export async function AddMessage(data: Ty.MessageAddArgs): Promise<Ty.BackendRes
export async function StartAuthSession() : Promise<Ty.BackendResponse<Auth.Session>> { export async function StartAuthSession() : Promise<Ty.BackendResponse<Auth.Session>> {
const sessionId = getRandomToken(); const sessionId = getRandomToken();
redis.set(`Session:${sessionId}`, "{}"); redis?.set(`Session:${sessionId}`, "{}");
redis.expire(`Session:${sessionId}`, 60 * 5); // 5分钟内登录/注册有效 redis?.expire(`Session:${sessionId}`, 60 * 5); // 5分钟内登录/注册有效
return { return {
code: 0, code: 0,
...@@ -252,7 +252,7 @@ export async function StartAuthSession() : Promise<Ty.BackendResponse<Auth.Sessi ...@@ -252,7 +252,7 @@ export async function StartAuthSession() : Promise<Ty.BackendResponse<Auth.Sessi
export async function Login(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.LoginResult | null>> { export async function Login(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.LoginResult | null>> {
const { sessionId, username, password, userAgent, userIP } = args; const { sessionId, username, password, userAgent, userIP } = args;
const sessionStr = await redis.get(`Session:${sessionId}`); const sessionStr = await redis?.get(`Session:${sessionId}`);
if(!sessionStr) if(!sessionStr)
{ {
return { return {
...@@ -289,7 +289,7 @@ export async function Login(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Au ...@@ -289,7 +289,7 @@ export async function Login(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Au
} }
}); });
await redis.del(`Session:${sessionId}`); await redis?.del(`Session:${sessionId}`);
return { return {
code: 0, code: 0,
...@@ -337,7 +337,7 @@ export async function AutoLogin(args: Auth.AutoLoginArgs) : Promise<Ty.BackendRe ...@@ -337,7 +337,7 @@ export async function AutoLogin(args: Auth.AutoLoginArgs) : Promise<Ty.BackendRe
export async function Register(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.RegisterResult | null>> { export async function Register(args: Auth.AuthArgs) : Promise<Ty.BackendResponse<Auth.RegisterResult | null>> {
const { sessionId, username, password } = args; const { sessionId, username, password } = args;
const sessionStr = await redis.get(`Session:${sessionId}`); const sessionStr = await redis?.get(`Session:${sessionId}`);
if(!sessionStr) if(!sessionStr)
{ {
return { return {
...@@ -372,7 +372,7 @@ export async function Register(args: Auth.AuthArgs) : Promise<Ty.BackendResponse ...@@ -372,7 +372,7 @@ export async function Register(args: Auth.AuthArgs) : Promise<Ty.BackendResponse
} }
}); });
await redis.del(`Session:${sessionId}`); await redis?.del(`Session:${sessionId}`);
return { return {
code: 0, code: 0,
......
...@@ -6,27 +6,30 @@ import UsernameCheck from './username-check'; ...@@ -6,27 +6,30 @@ import UsernameCheck from './username-check';
import PageHeaderProvider from './header' import PageHeaderProvider from './header'
import ConfirmModalProvider from './confirm-modal'; import ConfirmModalProvider from './confirm-modal';
import { RoomProvider } from './room-context' import { RoomProvider } from './room-context'
import { Suspense } from 'react';
export default function Home() { export default function Home() {
return ( return (
<RoomProvider> <Suspense fallback={<div>Loading...</div>}>
<UsernameCheck /> <RoomProvider>
<ConfirmModalProvider /> <UsernameCheck />
<div className="bg-gray-100 flex-col flex h-screen"> <ConfirmModalProvider />
<PageHeaderProvider /> <div className="bg-gray-100 flex-col flex h-screen">
<div className="flex flex-1 overflow-hidden"> <PageHeaderProvider />
<div className="w-1/4 bg-white p-4 overflow-y-auto"> <div className="flex flex-1 overflow-hidden">
<h2 className="text-lg font-bold mb-4">房间列表</h2> <div className="w-1/4 bg-white p-4 overflow-y-auto">
<RoomListProvider /> <h2 className="text-lg font-bold mb-4">房间列表</h2>
<RoomListProvider />
</div>
<div className="w-3/4 bg-gray-100 p-4">
<RoomHeaderProvider />
<RoomMessageProvider />
<SendMessageProvider />
</div>
</div>
</div> </div>
<div className="w-3/4 bg-gray-100 p-4"> </RoomProvider>
<RoomHeaderProvider /> </Suspense>
<RoomMessageProvider />
<SendMessageProvider />
</div>
</div>
</div>
</RoomProvider>
); );
} }
...@@ -8,14 +8,20 @@ declare global{ ...@@ -8,14 +8,20 @@ declare global{
var rateLimiter:RateLimiterRedis | undefined; var rateLimiter:RateLimiterRedis | undefined;
} }
const connectRedisClient = async () => { const connectRedisClient = async () => {
const client = createClient(); const isBuild = process.env.NEXT_PHASE === 'phase-production-build';
client.on('error', (err) => console.error('Redis Client Error', err));
await client.connect(); const client = isBuild ? undefined : createClient();
client?.on('error', (err) => console.error('Redis Client Error', err));
await client?.connect();
return client; return client;
}; };
const getRateLimiter = () => { const getRateLimiter = () => {
const isBuild = process.env.NEXT_PHASE === 'phase-production-build';
if(isBuild) return undefined;
const rateLimiter = new RateLimiterRedis({ const rateLimiter = new RateLimiterRedis({
storeClient: redis, storeClient: redis,
keyPrefix: 'rateLimiter', keyPrefix: 'rateLimiter',
...@@ -25,6 +31,8 @@ const getRateLimiter = () => { ...@@ -25,6 +31,8 @@ const getRateLimiter = () => {
return rateLimiter; return rateLimiter;
}; };
export const prisma = global.prisma || new PrismaClient(); export const prisma = global.prisma || new PrismaClient();
export const redis = global.redisClient || await connectRedisClient(); export const redis = global.redisClient || await connectRedisClient();
export const rateLimiter = global.rateLimiter || getRateLimiter(); export const rateLimiter = global.rateLimiter || getRateLimiter();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment