fix: 调整 chat WS/WT dev 接入
WT 目前沿用 JToken 的 JWT 校验;撤销一致性留到后续 WT 专用网关设计。
This commit is contained in:
@@ -7,7 +7,7 @@ Hybrid:
|
||||
Protocol: auto
|
||||
Ws:
|
||||
Name: chat-ws
|
||||
Addr: :8889
|
||||
Addr: :8888
|
||||
Path: /ws/chat
|
||||
MaxConnections: 10000
|
||||
Auth:
|
||||
@@ -19,12 +19,17 @@ Hybrid:
|
||||
Path: /wt/chat
|
||||
CertFile: /etc/certs/tls.crt
|
||||
KeyFile: /etc/certs/tls.key
|
||||
Auth:
|
||||
Enabled: true
|
||||
FallbackStrategy: auto
|
||||
MaxRetries: 3
|
||||
MaxConnections: 10000
|
||||
Auth:
|
||||
Enabled: true
|
||||
WsHeaderName: x-auth-user-id
|
||||
WtTokenSource: cookie
|
||||
WtTokenName: JToken
|
||||
WtJWTSecret: MGUyMWE3ZDhjMTQ5ZDg1MWViOWU0MGM3OTE2NWVkYTBlOTE5ZWRkZDU1YjYzOGJjOWRiNzM0NTc4NDIyMjlkZQ
|
||||
|
||||
Stateless:
|
||||
PollInterval: 100ms
|
||||
|
||||
@@ -64,6 +64,12 @@ func (h *Handler) handleJoin(conn protocol.Connection, msg *WsMessage) error {
|
||||
|
||||
func (h *Handler) handleLeave(conn protocol.Connection, msg *WsMessage) error {
|
||||
uid := h.getUserId(conn)
|
||||
if uid <= 0 {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "authentication required",
|
||||
})
|
||||
}
|
||||
sessionId := msg.SessionId
|
||||
if sessionId <= 0 {
|
||||
if sid, ok := conn.Metadata()["sessionId"].(int64); ok {
|
||||
@@ -73,6 +79,12 @@ func (h *Handler) handleLeave(conn protocol.Connection, msg *WsMessage) error {
|
||||
if sessionId <= 0 {
|
||||
return nil
|
||||
}
|
||||
if !h.svcCtx.Store.IsParticipant(sessionId, uid) {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "not a member of this session",
|
||||
})
|
||||
}
|
||||
|
||||
session, err := h.svcCtx.Store.GetSession(sessionId)
|
||||
if err == nil {
|
||||
@@ -108,6 +120,12 @@ func (h *Handler) handleMessage(conn protocol.Connection, msg *WsMessage) error
|
||||
Content: "sessionId is required, join a session first",
|
||||
})
|
||||
}
|
||||
if !h.svcCtx.Store.IsParticipant(sessionId, uid) {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "not a member of this session",
|
||||
})
|
||||
}
|
||||
|
||||
msgType := chatcore.MessageType(msg.MsgType)
|
||||
if msgType == "" {
|
||||
@@ -151,12 +169,25 @@ func (h *Handler) handleMessage(conn protocol.Connection, msg *WsMessage) error
|
||||
}
|
||||
|
||||
func (h *Handler) handleHistory(conn protocol.Connection, msg *WsMessage) error {
|
||||
uid := h.getUserId(conn)
|
||||
if uid <= 0 {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "authentication required",
|
||||
})
|
||||
}
|
||||
if msg.SessionId <= 0 {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "sessionId is required",
|
||||
})
|
||||
}
|
||||
if !h.svcCtx.Store.IsParticipant(msg.SessionId, uid) {
|
||||
return conn.SendJSON(context.Background(), WsResponse{
|
||||
Type: "error",
|
||||
Content: "not a member of this session",
|
||||
})
|
||||
}
|
||||
|
||||
messages := h.svcCtx.Store.GetMessages(msg.SessionId, 0, 50)
|
||||
|
||||
|
||||
@@ -109,6 +109,22 @@ func (s *Store) GetSession(id int64) (*Session, error) {
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (s *Store) IsParticipant(sessionId, userId int64) bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
session, ok := s.Sessions[sessionId]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, p := range session.Participants {
|
||||
if p == userId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Store) ListUserSessions(userId int64, page, limit int) []*Session {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
@@ -7,7 +7,7 @@ Hybrid:
|
||||
Protocol: auto
|
||||
Ws:
|
||||
Name: chat-ws
|
||||
Addr: :28889
|
||||
Addr: :28888
|
||||
Path: /ws/chat
|
||||
MaxConnections: 10000
|
||||
Auth:
|
||||
|
||||
@@ -7,7 +7,7 @@ Hybrid:
|
||||
Protocol: auto
|
||||
Ws:
|
||||
Name: chat-ws
|
||||
Addr: :8889
|
||||
Addr: :8888
|
||||
Path: /ws/chat
|
||||
MaxConnections: 10000
|
||||
Auth:
|
||||
@@ -19,6 +19,8 @@ Hybrid:
|
||||
Path: /wt/chat
|
||||
CertFile: /etc/certs/tls.crt
|
||||
KeyFile: /etc/certs/tls.key
|
||||
Auth:
|
||||
Enabled: true
|
||||
FallbackStrategy: auto
|
||||
MaxRetries: 3
|
||||
MaxConnections: 10000
|
||||
|
||||
@@ -6,7 +6,6 @@ services:
|
||||
container_name: chat-api-test
|
||||
ports:
|
||||
- "28888:8888"
|
||||
- "28889:8889"
|
||||
- "28443:8443/udp"
|
||||
volumes:
|
||||
- ./certs:/etc/certs:ro
|
||||
|
||||
@@ -14,7 +14,7 @@ except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "websockets", "-q"])
|
||||
import websockets
|
||||
|
||||
WS_URL = "ws://localhost:28889/ws/chat"
|
||||
WS_URL = "ws://localhost:28888/ws/chat"
|
||||
RESULTS = []
|
||||
|
||||
def log(tag, msg):
|
||||
|
||||
@@ -5,8 +5,6 @@ import asyncio
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
try:
|
||||
import websockets
|
||||
@@ -15,7 +13,7 @@ except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "websockets", "-q"])
|
||||
import websockets
|
||||
|
||||
WS_URL = "ws://localhost:28889/ws/chat"
|
||||
WS_URL = "ws://localhost:28888/ws/chat"
|
||||
API_BASE = "http://localhost:28888"
|
||||
RESULTS = []
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ func (m *JwtManager) New(ctx context.Context, payload *TokenPayload) (string, er
|
||||
ExpiresAt: jwt.NewNumericDate(expiresAt),
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
Issuer: m.issuer,
|
||||
Subject: strconv.FormatInt(payload.UserId, 10),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ docker compose down
|
||||
|
||||
端到端接口测试走网关 `http://127.0.0.1:18080`,`18801-18814` 是各服务的直连端口,不经过认证链路。
|
||||
|
||||
Chat WebSocket 通过网关 `ws://127.0.0.1:18080/ws/chat` 访问。WebTransport 使用 `18443/udp` 的 `/wt/chat` 入口。
|
||||
|
||||
如需只启动部分服务:
|
||||
|
||||
```bash
|
||||
@@ -40,7 +42,7 @@ docker compose up -d postgres redis snowflake player-rpc player-api
|
||||
## 端口映射
|
||||
|
||||
| 服务 | 宿主机端口 |
|
||||
| ---------------- | ---------- |
|
||||
| ---------------- | ---------------- |
|
||||
| PostgreSQL | 15432 |
|
||||
| Redis | 16379 |
|
||||
| Kafka | 19092 |
|
||||
@@ -54,7 +56,7 @@ docker compose up -d postgres redis snowflake player-rpc player-api
|
||||
| community-api | 18807 |
|
||||
| objectstory-api | 18808 |
|
||||
| email-api | 18809 |
|
||||
| chat-api | 18810 |
|
||||
| chat-api | 18810, 18443/udp |
|
||||
| review-api | 18811 |
|
||||
| dispute-api | 18812 |
|
||||
| notification-api | 18813 |
|
||||
|
||||
@@ -444,7 +444,6 @@ services:
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "18810:8888"
|
||||
- "18889:8889"
|
||||
- "18443:8443/udp"
|
||||
volumes:
|
||||
- ./certs:/etc/certs:ro
|
||||
@@ -464,6 +463,8 @@ services:
|
||||
condition: service_started
|
||||
order-rpc:
|
||||
condition: service_started
|
||||
player-rpc:
|
||||
condition: service_started
|
||||
|
||||
dispute-api:
|
||||
image: juwan/dispute-api:dev
|
||||
@@ -477,6 +478,8 @@ services:
|
||||
condition: service_started
|
||||
order-rpc:
|
||||
condition: service_started
|
||||
player-rpc:
|
||||
condition: service_started
|
||||
|
||||
notification-api:
|
||||
image: juwan/notification-api:dev
|
||||
|
||||
@@ -375,10 +375,12 @@ static_resources:
|
||||
timeout: 30s
|
||||
|
||||
- match:
|
||||
prefix: /api/v1/chat
|
||||
path: /ws/chat
|
||||
route:
|
||||
cluster: chat_api_cluster
|
||||
timeout: 30s
|
||||
timeout: 0s
|
||||
upgrade_configs:
|
||||
- upgrade_type: websocket
|
||||
|
||||
- match:
|
||||
path: /api/v1/upload
|
||||
@@ -597,6 +599,10 @@ static_resources:
|
||||
rules:
|
||||
- match:
|
||||
path: /healthz
|
||||
- match:
|
||||
path: /ws/chat
|
||||
requires:
|
||||
provider_name: juwan_user_jwt
|
||||
- match:
|
||||
prefix: /api/v1
|
||||
headers:
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
syntax = "v1"
|
||||
|
||||
import "common.api"
|
||||
|
||||
type (
|
||||
SessionIdReq {
|
||||
Id int64 `path:"id"`
|
||||
}
|
||||
CreateGroupReq {
|
||||
Name string `json:"name"`
|
||||
Participants []int64 `json:"participants,optional"`
|
||||
}
|
||||
CreateDMReq {
|
||||
TargetId int64 `json:"targetId"`
|
||||
}
|
||||
ChatSession {
|
||||
Id int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
CreatorId int64 `json:"creatorId"`
|
||||
Participants []int64 `json:"participants"`
|
||||
LastMessage string `json:"lastMessage"`
|
||||
LastMessageAt int64 `json:"lastMessageAt"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
ChatSessionListResp {
|
||||
Items []ChatSession `json:"items"`
|
||||
}
|
||||
ChatMessage {
|
||||
Id int64 `json:"id"`
|
||||
SessionId int64 `json:"sessionId"`
|
||||
SenderId int64 `json:"senderId"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
ChatMessageListResp {
|
||||
Items []ChatMessage `json:"items"`
|
||||
}
|
||||
ListMessageReq {
|
||||
SessionIdReq
|
||||
PageReq
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
prefix: api/v1/chat
|
||||
group: chat
|
||||
)
|
||||
service chat-api {
|
||||
@doc "create group session"
|
||||
@handler CreateGroup
|
||||
post /sessions/group (CreateGroupReq) returns (ChatSession)
|
||||
|
||||
@doc "create dm session"
|
||||
@handler CreateDM
|
||||
post /sessions/dm (CreateDMReq) returns (ChatSession)
|
||||
|
||||
@doc "list user sessions"
|
||||
@handler ListSessions
|
||||
get /sessions (PageReq) returns (ChatSessionListResp)
|
||||
|
||||
@doc "get session detail"
|
||||
@handler GetSession
|
||||
get /sessions/:id (SessionIdReq) returns (ChatSession)
|
||||
|
||||
@doc "get message history"
|
||||
@handler ListMessages
|
||||
get /sessions/:id/messages (ListMessageReq) returns (ChatMessageListResp)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ Juwan 是一个基于 Go-Zero 微服务框架的分布式后端系统,采用
|
||||
│ │
|
||||
┌───▼────────┐ ┌───▼────────┐
|
||||
│ User API │ │ Order API │
|
||||
│ (8888) │ │ (8889) │
|
||||
│ (8888) │ │ (8888) │
|
||||
└───┬────────┘ └────────────┘
|
||||
│
|
||||
┌───▼────────────────────┐
|
||||
|
||||
Reference in New Issue
Block a user