Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
何 广一
chatroom
Commits
9bf2ef80
Commit
9bf2ef80
authored
Aug 26, 2025
by
何 广一
Browse files
some bugfixes & docker support
parent
b5231b65
Changes
15
Hide whitespace changes
Inline
Side-by-side
chat-room/dockerfile
0 → 100644
View file @
9bf2ef80
# write a dockerfile for a react app
# ---------- 基础 ----------
FROM
node:20-alpine
AS
base
WORKDIR
/app
COPY
package.json pnpm-lock.yaml ./
RUN
npm
install
-g
pnpm
&&
pnpm
install
--frozen-lockfile
--shamefully-hoist
# ---------- Prisma + SQLite ----------
COPY
prisma ./prisma
ENV
DATABASE_URL=file:/app/data/db.sqlite
RUN
mkdir
-p
/app/data
RUN
pnpm prisma generate
RUN
pnpm prisma migrate deploy
--schema
./prisma/schema.prisma
# ---------- 构建 ----------
COPY
. .
RUN
pnpm build
# ---------- 运行时 ----------
FROM
node:20-alpine
AS
runner
WORKDIR
/app
RUN
apk add
--no-cache
redis
COPY
--from=base /app/.next ./.next
COPY
--from=base /app/node_modules ./node_modules
COPY
--from=base /app/package.json ./package.json
COPY
--from=base /app/prisma ./prisma
COPY
--from=base /app/.env.docker ./.env
# 启动脚本:后台起 Redis + Next.js
COPY
<<EOF /app/start.sh
#!/bin/sh
redis-server --daemonize yes
exec node .next/standalone/server.js
EOF
RUN
chmod
+x /app/start.sh
EXPOSE
3000
CMD
["sh", "/app/start.sh"]
\ No newline at end of file
chat-room/package.json
View file @
9bf2ef80
...
@@ -10,6 +10,8 @@
...
@@ -10,6 +10,8 @@
"redis"
:
"start redis-server --port 6379"
"redis"
:
"start redis-server --port 6379"
},
},
"dependencies"
:
{
"dependencies"
:
{
"@types/react"
:
"^19"
,
"@types/react-dom"
:
"^19"
,
"@prisma/client"
:
"6.14.0"
,
"@prisma/client"
:
"6.14.0"
,
"next"
:
"15.4.6"
,
"next"
:
"15.4.6"
,
"rate-limiter-flexible"
:
"^7.2.0"
,
"rate-limiter-flexible"
:
"^7.2.0"
,
...
...
chat-room/pnpm-lock.yaml
View file @
9bf2ef80
...
@@ -11,6 +11,12 @@ importers:
...
@@ -11,6 +11,12 @@ importers:
'
@prisma/client'
:
'
@prisma/client'
:
specifier
:
6.14.0
specifier
:
6.14.0
version
:
6.14.0(prisma@6.14.0(typescript@5.9.2))(typescript@5.9.2)
version
:
6.14.0(prisma@6.14.0(typescript@5.9.2))(typescript@5.9.2)
'
@types/react'
:
specifier
:
^19
version
:
19.1.9
'
@types/react-dom'
:
specifier
:
^19
version
:
19.1.7(@types/react@19.1.9)
next
:
next
:
specifier
:
15.4.6
specifier
:
15.4.6
version
:
15.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
version
:
15.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
...
@@ -39,12 +45,6 @@ importers:
...
@@ -39,12 +45,6 @@ importers:
'
@types/node'
:
'
@types/node'
:
specifier
:
^20
specifier
:
^20
version
:
20.19.10
version
:
20.19.10
'
@types/react'
:
specifier
:
^19
version
:
19.1.9
'
@types/react-dom'
:
specifier
:
^19
version
:
19.1.7(@types/react@19.1.9)
concurrently
:
concurrently
:
specifier
:
^9.2.0
specifier
:
^9.2.0
version
:
9.2.0
version
:
9.2.0
...
...
chat-room/src/app/(loginpage)/auto-login.tsx
View file @
9bf2ef80
'
use client
'
;
'
use client
'
;
import
{
useEffect
,
useState
}
from
'
react
'
;
import
{
useEffect
}
from
'
react
'
;
import
{
useRouter
}
from
'
next/navigation
'
;
import
{
useRouter
}
from
'
next/navigation
'
;
import
{
useLocalBackend
}
from
'
../interface
'
;
import
*
as
Auth
from
'
../api/login-interface
'
;
import
*
as
Auth
from
'
../api/login-interface
'
;
import
*
as
Ty
from
'
../interface
'
;
import
*
as
Ty
from
'
../interface
'
;
...
@@ -24,7 +23,7 @@ export default function AutoLoginProvider() {
...
@@ -24,7 +23,7 @@ export default function AutoLoginProvider() {
router
.
push
(
`/chat?username=
${
encodeURIComponent
(
data
.
data
.
user
)}
`
);
router
.
push
(
`/chat?username=
${
encodeURIComponent
(
data
.
data
.
user
)}
`
);
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
);
console
.
error
(
error
);
alert
(
error
.
message
);
alert
(
(
error
as
Error
)
.
message
);
}
}
};
};
...
@@ -32,5 +31,5 @@ export default function AutoLoginProvider() {
...
@@ -32,5 +31,5 @@ export default function AutoLoginProvider() {
autoLogin
();
autoLogin
();
},
[
router
]);
},
[
router
]);
return
<></>
;
return
null
;
}
}
\ No newline at end of file
chat-room/src/app/(loginpage)/page.tsx
View file @
9bf2ef80
...
@@ -142,7 +142,7 @@ function Home_Local(){
...
@@ -142,7 +142,7 @@ function Home_Local(){
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
);
console
.
error
(
error
);
setPageError
((
asLogin
?
'
登录错误!
'
:
'
注册错误!
'
)
+
error
.
message
);
setPageError
((
asLogin
?
'
登录错误!
'
:
'
注册错误!
'
)
+
(
error
as
Error
)
.
message
);
setIsErrorInstant
(
false
);
setIsErrorInstant
(
false
);
}
finally
{
}
finally
{
setPending
(
false
);
setPending
(
false
);
...
...
chat-room/src/app/api/auth/logout/route.tsx
View file @
9bf2ef80
import
{
NextRequest
,
NextResponse
}
from
'
next/server
'
;
import
{
NextRequest
,
NextResponse
}
from
'
next/server
'
;
import
*
as
Ty
from
'
../../../interface
'
import
*
as
Ty
from
'
../../../interface
'
import
*
as
Db
from
'
../../room-api
'
;
import
*
as
Db
from
'
../../room-api
'
;
import
*
as
Auth
from
'
../../login-interface
'
;
/*
/*
- url: /api/auth/logout
- url: /api/auth/logout
...
...
chat-room/src/app/api/auth/startSession/route.tsx
View file @
9bf2ef80
...
@@ -7,7 +7,8 @@ import * as Auth from '../../login-interface';
...
@@ -7,7 +7,8 @@ import * as Auth from '../../login-interface';
- url: /api/auth/startSession
- url: /api/auth/startSession
- method: GET
- method: GET
*/
*/
export
async
function
GET
(
req
:
NextRequest
):
Promise
<
NextResponse
<
Ty
.
BackendResponse
<
Auth
.
Session
|
null
>>>
{
export
async
function
GET
(
_req
:
NextRequest
):
Promise
<
NextResponse
<
Ty
.
BackendResponse
<
Auth
.
Session
|
null
>>>
{
const
result
=
await
Db
.
StartAuthSession
();
const
result
=
await
Db
.
StartAuthSession
();
return
NextResponse
.
json
(
result
);
return
NextResponse
.
json
(
result
);
...
...
chat-room/src/app/api/interface-schema.tsx
View file @
9bf2ef80
import
{
z
}
from
'
zod
'
;
import
{
z
}
from
'
zod
'
;
import
*
as
Ty
from
'
../interface
'
;
export
const
RoomAddArgsSchema
=
z
.
object
({
export
const
RoomAddArgsSchema
=
z
.
object
({
user
:
z
.
string
().
min
(
2
).
max
(
100
),
user
:
z
.
string
().
min
(
2
).
max
(
100
),
...
...
chat-room/src/app/api/room-api.tsx
View file @
9bf2ef80
import
{
NextRequest
,
NextResponse
}
from
'
next/server
'
;
import
{
NextResponse
}
from
'
next/server
'
;
import
{
RequestCookies
}
from
'
next/dist/compiled/@edge-runtime/cookies
'
;
import
{
RequestCookies
}
from
'
next/dist/compiled/@edge-runtime/cookies
'
;
import
{
createHash
,
randomBytes
}
from
'
crypto
'
;
import
{
createHash
,
randomBytes
}
from
'
crypto
'
;
import
*
as
Ty
from
'
../interface
'
import
*
as
Ty
from
'
../interface
'
...
@@ -22,7 +22,13 @@ const UserExists = async (name: string): Promise<boolean> => {
...
@@ -22,7 +22,13 @@ const UserExists = async (name: string): Promise<boolean> => {
return
user
!==
null
;
return
user
!==
null
;
};
};
const
toFrontMsg
=
async
(
m
:
any
)
:
Promise
<
Ty
.
Message
|
null
>
=>
{
const
toFrontMsg
=
async
(
m
:
{
createdAt
:
Date
;
id
:
number
;
content
:
string
;
roomId
:
number
;
senderName
:
string
;
})
:
Promise
<
Ty
.
Message
|
null
>
=>
{
if
(
!
m
.
senderName
.
length
)
return
null
;
if
(
!
m
.
senderName
.
length
)
return
null
;
if
(
!
await
UserExists
(
m
.
senderName
))
return
null
;
if
(
!
await
UserExists
(
m
.
senderName
))
return
null
;
return
{
return
{
...
@@ -174,7 +180,7 @@ export async function UpdateMessageList(data: Ty.RoomMessageGetUpdateArgs): Prom
...
@@ -174,7 +180,7 @@ export async function UpdateMessageList(data: Ty.RoomMessageGetUpdateArgs): Prom
}
}
export
async
function
DeleteRoom
(
data
:
Ty
.
RoomDeleteArgs
,
operatorToken
:
S
tring
):
Promise
<
Ty
.
BackendResponse
<
null
>>
{
export
async
function
DeleteRoom
(
data
:
Ty
.
RoomDeleteArgs
,
operatorToken
:
s
tring
):
Promise
<
Ty
.
BackendResponse
<
null
>>
{
const
{
user
,
roomId
}
=
data
;
const
{
user
,
roomId
}
=
data
;
const
room
=
await
prisma
.
room
.
findUnique
({
const
room
=
await
prisma
.
room
.
findUnique
({
...
...
chat-room/src/app/chat/confirm-modal.tsx
View file @
9bf2ef80
'
use client
'
'
use client
'
import
{
useEffect
,
useState
}
from
'
react
'
;
import
{
useEffect
,
useState
}
from
'
react
'
;
import
{
useRoom
}
from
'
./room-context
'
import
{
useRoom
}
from
'
./room-context
'
import
{
after
}
from
'
node:test
'
;
import
{
set
}
from
'
zod
'
;
export
default
function
ConfirmModalProvider
()
{
export
default
function
ConfirmModalProvider
()
{
...
...
chat-room/src/app/chat/current-room.tsx
View file @
9bf2ef80
'
use client
'
'
use client
'
import
{
createContext
,
useContext
,
useState
,
ReactNode
,
useEffect
}
from
'
react
'
import
{
useRoom
}
from
'
./room-context
'
import
{
useRoom
}
from
'
./room-context
'
export
default
function
RoomHeaderProvider
()
{
export
default
function
RoomHeaderProvider
()
{
...
...
chat-room/src/app/chat/header.tsx
View file @
9bf2ef80
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
import
{
useRoom
}
from
'
./room-context
'
import
{
useRoom
}
from
'
./room-context
'
import
{
useRouter
}
from
'
next/navigation
'
;
import
{
useRouter
}
from
'
next/navigation
'
;
import
*
as
Ty
from
'
../interface
'
import
*
as
Ty
from
'
../interface
'
import
*
as
Auth
from
'
../api/login-interface
'
export
default
function
PageHeaderProvider
()
{
export
default
function
PageHeaderProvider
()
{
...
...
chat-room/src/app/chat/page.tsx
View file @
9bf2ef80
import
*
as
Ty
from
'
../interface
'
import
RoomListProvider
from
'
./room-list
'
;
import
RoomListProvider
from
'
./room-list
'
;
import
RoomHeaderProvider
from
'
./current-room
'
;
import
RoomHeaderProvider
from
'
./current-room
'
;
import
RoomMessageProvider
from
'
./room-message
'
;
import
RoomMessageProvider
from
'
./room-message
'
;
...
...
chat-room/src/app/chat/room-list.tsx
View file @
9bf2ef80
...
@@ -262,7 +262,7 @@ export default function RoomListProvider() {
...
@@ -262,7 +262,7 @@ export default function RoomListProvider() {
triggerErrorModal
(
roomsError
);
triggerErrorModal
(
roomsError
);
setRoomsError
(
''
);
setRoomsError
(
''
);
}
}
},
[
roomsError
]);
},
[
roomsError
,
triggerErrorModal
]);
return
(
return
(
<
div
className
=
"room-container"
>
<
div
className
=
"room-container"
>
...
...
chat-room/src/app/chat/room-message.tsx
View file @
9bf2ef80
'
use client
'
'
use client
'
import
{
useState
,
useEffect
,
useRef
,
use
}
from
'
react
'
import
{
useState
,
useEffect
,
useRef
}
from
'
react
'
import
*
as
Ty
from
'
../interface
'
import
*
as
Ty
from
'
../interface
'
import
{
useRoom
}
from
'
./room-context
'
import
{
useRoom
}
from
'
./room-context
'
import
{
reloginErrorCode
}
from
'
../api/login-interface
'
import
{
reloginErrorCode
}
from
'
../api/login-interface
'
...
@@ -68,7 +68,7 @@ export default function RoomMessageProvider() {
...
@@ -68,7 +68,7 @@ export default function RoomMessageProvider() {
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'
房间列表获取失败:
'
,
error
);
console
.
error
(
'
房间列表获取失败:
'
,
error
);
setMessagesError
(
error
.
message
);
setMessagesError
(
(
error
as
Error
)
.
message
);
}
finally
{
}
finally
{
setMessagesLoading
(
false
);
setMessagesLoading
(
false
);
}
}
...
@@ -125,7 +125,7 @@ export default function RoomMessageProvider() {
...
@@ -125,7 +125,7 @@ export default function RoomMessageProvider() {
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'
房间列表获取失败:
'
,
error
);
console
.
error
(
'
房间列表获取失败:
'
,
error
);
setMessagesError
(
error
.
message
);
setMessagesError
(
(
error
as
Error
)
.
message
);
}
finally
{
}
finally
{
setMessagesLoading
(
false
);
setMessagesLoading
(
false
);
}
}
...
@@ -165,7 +165,7 @@ export default function RoomMessageProvider() {
...
@@ -165,7 +165,7 @@ export default function RoomMessageProvider() {
triggerErrorModal
(
messagesError
);
triggerErrorModal
(
messagesError
);
setMessagesError
(
''
);
setMessagesError
(
''
);
}
}
},
[
messagesError
]);
},
[
messagesError
,
triggerErrorModal
]);
if
(
currentRoomInfo
)
if
(
currentRoomInfo
)
{
{
...
@@ -174,6 +174,7 @@ export default function RoomMessageProvider() {
...
@@ -174,6 +174,7 @@ export default function RoomMessageProvider() {
ref
=
{
scrollRef
}
ref
=
{
scrollRef
}
className
=
"bg-white p-4 overflow-y-auto h-3/5"
className
=
"bg-white p-4 overflow-y-auto h-3/5"
>
>
{
messagesLoading
&&
<
div
>
Loading...
</
div
>
}
<
div
className
=
"bg-gray-100 min-h-full"
>
<
div
className
=
"bg-gray-100 min-h-full"
>
<
ul
className
=
"mb-2"
>
<
ul
className
=
"mb-2"
>
{
messages
?.
map
((
msg
)
=>
(
{
messages
?.
map
((
msg
)
=>
(
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment