修复:为 user-svc 添加健康检查和启动顺序控制

This commit is contained in:
fish
2026-03-28 21:54:09 +08:00
parent 5ac0a52bb1
commit c5260bcae8
31 changed files with 1995 additions and 167 deletions

View File

@@ -7,6 +7,7 @@ networks:
services: services:
# Nginx 网关 # Nginx 网关
nginx: nginx:
container_name: backend-nginx
image: nginx:1.25-alpine image: nginx:1.25-alpine
ports: ports:
- "8080:80" - "8080:80"
@@ -19,14 +20,16 @@ services:
# 网关服务 # 网关服务
gateway: gateway:
container_name: backend-gateway
build: build:
context: ./gateway context: .
dockerfile: Dockerfile dockerfile: ./gateway/Dockerfile
ports: ports:
- "8000:8000" - "8000:8000"
volumes: volumes:
- ./gateway:/app - ./gateway/cmd:/app/cmd
command: air -c .air.toml - ./gateway/internal:/app/internal
- ./shared:/shared
depends_on: depends_on:
- user-svc - user-svc
- redis - redis
@@ -35,21 +38,26 @@ services:
# 用户服务 # 用户服务
user-svc: user-svc:
container_name: backend-user-svc
build: build:
context: ./services/user-svc context: .
dockerfile: Dockerfile dockerfile: ./services/user-svc/Dockerfile
ports: ports:
- "9000:9000" - "9000:9000"
volumes: volumes:
- ./services/user-svc:/app - ./services/user-svc/cmd:/app/cmd
command: air -c .air.toml - ./services/user-svc/internal:/app/internal
- ./services/user-svc/proto:/app/proto
- ./shared:/shared
depends_on: depends_on:
- postgres postgres:
condition: service_healthy
networks: networks:
- backend-network - backend-network
# 数据库 # 数据库
postgres: postgres:
container_name: backend-postgres
image: postgres:18.3-alpine3.23 image: postgres:18.3-alpine3.23
environment: environment:
POSTGRES_USER: admin POSTGRES_USER: admin
@@ -62,9 +70,15 @@ services:
- ./services/user-svc/migrations:/docker-entrypoint-initdb.d - ./services/user-svc/migrations:/docker-entrypoint-initdb.d
networks: networks:
- backend-network - backend-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d backend"]
interval: 5s
timeout: 5s
retries: 5
# Redis # Redis
redis: redis:
container_name: backend-redis
image: redis:8.6.2-alpine image: redis:8.6.2-alpine
ports: ports:
- "6379:6379" - "6379:6379"

View File

@@ -73,7 +73,7 @@ services:
context: ./scripts/docker-proto-builder context: ./scripts/docker-proto-builder
dockerfile: Dockerfile dockerfile: Dockerfile
volumes: volumes:
- ./shared/proto:/proto - .:/proto
networks: networks:
- backend-network - backend-network

View File

@@ -1,16 +1,29 @@
FROM golang:1.26.1-alpine3.23 as builder FROM golang:1.25.8-alpine3.23 AS builder
# 设置工作目录 # 设置工作目录
WORKDIR /app WORKDIR /app
# 复制 go.mod 和 go.sum # 安装 git
COPY go.mod go.sum ./ RUN apk add --no-cache git
# 下载依赖 # 设置 Go 环境变量
RUN go mod download ENV GOPROXY=https://goproxy.io,direct
ENV GOSUMDB=off
# 复制共享包
COPY shared/ /shared/
# 复制 go.mod
COPY gateway/go.mod ./
# 复制 go.sum如果存在
COPY gateway/go.sum* ./
# 复制源代码 # 复制源代码
COPY . . COPY gateway/ .
# 生成 go.sum 并下载依赖
RUN go mod tidy
# 构建应用 # 构建应用
RUN go build -o gateway ./cmd/main.go RUN go build -o gateway ./cmd/main.go

View File

@@ -5,11 +5,12 @@ import (
"log" "log"
"net/http" "net/http"
"backend/gateway/internal/config" "gateway/internal/config"
"backend/gateway/internal/router" "gateway/internal/router"
"backend/gateway/internal/service" "gateway/internal/service"
"backend/gateway/internal/ws" "gateway/internal/ws"
"backend/shared/pkg/logger"
"shared/pkg/logger"
) )
func main() { func main() {

View File

@@ -1,10 +1,15 @@
module backend/gateway module gateway
go 1.26.1 go 1.25.8
require ( require (
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.1
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
google.golang.org/grpc v1.64.0 google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.33.0
shared v0.0.0
)
replace (
shared => /shared
) )

View File

@@ -36,10 +36,10 @@ func Load() (*Config, error) {
viper.AddConfigPath("../../config") viper.AddConfigPath("../../config")
viper.SetDefault("server.port", 8000) viper.SetDefault("server.port", 8000)
viper.SetDefault("redis.addr", "redis:6379") viper.SetDefault("redis.addr", "backend-redis:6379")
viper.SetDefault("redis.password", "") viper.SetDefault("redis.password", "")
viper.SetDefault("redis.db", 0) viper.SetDefault("redis.db", 0)
viper.SetDefault("services.userService.addr", "user-svc:9000") viper.SetDefault("services.userService.addr", "backend-user-svc:9000")
if err := viper.ReadInConfig(); err != nil { if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok { if _, ok := err.(viper.ConfigFileNotFoundError); !ok {

View File

@@ -1,12 +1,11 @@
package router package router
import ( import (
"encoding/json"
"log" "log"
"net/http" "net/http"
"backend/gateway/internal/service" "gateway/internal/service"
"backend/gateway/internal/ws" "gateway/internal/ws"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
@@ -54,11 +53,11 @@ func (r *Router) handleWebSocket(w http.ResponseWriter, req *http.Request) {
} }
client := ws.NewClient(r.hub, conn) client := ws.NewClient(r.hub, conn)
r.hub.register <- client r.hub.Register <- client
// 启动客户端的读写协程 // 启动客户端的读写协程
go client.writePump() go client.WritePump()
go client.readPump() go client.ReadPump()
} }
func (r *Router) handleHealth(w http.ResponseWriter, req *http.Request) { func (r *Router) handleHealth(w http.ResponseWriter, req *http.Request) {

View File

@@ -3,14 +3,14 @@ package service
import ( import (
"context" "context"
"backend/gateway/internal/config" "gateway/internal/config"
"backend/shared/pkg/logger" "shared/pkg/logger"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
// 导入生成的 proto 代码 // 导入生成的 proto 代码
userpb "backend/services/user-svc/proto" userpb "shared/proto/user"
) )
type UserService struct { type UserService struct {

View File

@@ -23,21 +23,21 @@ const (
) )
type Client struct { type Client struct {
hub *Hub Hub *Hub
conn *websocket.Conn Conn *websocket.Conn
send chan *Message Send chan *Message
} }
func NewClient(hub *Hub, conn *websocket.Conn) *Client { func NewClient(hub *Hub, conn *websocket.Conn) *Client {
return &Client{ return &Client{
hub: hub, Hub: hub,
conn: conn, Conn: conn,
send: make(chan *Message, 256), Send: make(chan *Message, 256),
} }
} }
// sendWs 发送 WebSocket 消息,自动生成 seq、cmd、timestamp // SendWs 发送 WebSocket 消息,自动生成 seq、cmd、timestamp
func (c *Client) sendWs(cmd string, data interface{}) error { func (c *Client) SendWs(cmd string, data interface{}) error {
// 生成唯一请求ID // 生成唯一请求ID
seq := "req_" + time.Now().Format("20060102150405") + "_" + generateRandomString(8) seq := "req_" + time.Now().Format("20060102150405") + "_" + generateRandomString(8)
@@ -57,8 +57,8 @@ func (c *Client) sendWs(cmd string, data interface{}) error {
} }
// 写入 WebSocket 连接 // 写入 WebSocket 连接
c.conn.SetWriteDeadline(time.Now().Add(writeWait)) c.Conn.SetWriteDeadline(time.Now().Add(writeWait))
if err := c.conn.WriteMessage(websocket.TextMessage, msgBytes); err != nil { if err := c.Conn.WriteMessage(websocket.TextMessage, msgBytes); err != nil {
log.Printf("error writing message: %v", err) log.Printf("error writing message: %v", err)
return err return err
} }
@@ -77,21 +77,21 @@ func generateRandomString(length int) string {
return string(result) return string(result)
} }
func (c *Client) readPump() { func (c *Client) ReadPump() {
defer func() { defer func() {
c.hub.unregister <- c c.Hub.Unregister <- c
c.conn.Close() c.Conn.Close()
}() }()
c.conn.SetReadLimit(maxMessageSize) c.Conn.SetReadLimit(maxMessageSize)
c.conn.SetReadDeadline(time.Now().Add(pongWait)) c.Conn.SetReadDeadline(time.Now().Add(pongWait))
c.conn.SetPongHandler(func(string) error { c.Conn.SetPongHandler(func(string) error {
c.conn.SetReadDeadline(time.Now().Add(pongWait)) c.Conn.SetReadDeadline(time.Now().Add(pongWait))
return nil return nil
}) })
for { for {
_, message, err := c.conn.ReadMessage() _, message, err := c.Conn.ReadMessage()
if err != nil { if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
log.Printf("error: %v", err) log.Printf("error: %v", err)
@@ -107,18 +107,19 @@ func (c *Client) readPump() {
} }
// 处理消息 // 处理消息
c.handleMessage(msgMap) c.HandleMessage(msgMap)
} }
} }
func (c *Client) handleMessage(msgMap map[string]interface{}) { func (c *Client) HandleMessage(msgMap map[string]interface{}) {
// 检查是否是 ping 消息(保持向后兼容) // 检查是否是 ping 消息(保持向后兼容)
if msgType, ok := msgMap["type"].(string); ok { if msgTypeStr, ok := msgMap["type"].(string); ok {
msgType := MessageType(msgTypeStr)
switch msgType { switch msgType {
case MessageTypePing: case MessageTypePing:
// 回复 pong // 回复 pong
pongMsg := &Message{Type: MessageTypePong} pongMsg := &Message{Type: MessageTypePong}
c.send <- pongMsg c.Send <- pongMsg
return return
case MessageTypeText: case MessageTypeText:
// 广播文本消息 // 广播文本消息
@@ -127,7 +128,7 @@ func (c *Client) handleMessage(msgMap map[string]interface{}) {
Content: msgMap["content"].(string), Content: msgMap["content"].(string),
Data: msgMap["data"], Data: msgMap["data"],
} }
c.hub.broadcast <- msg c.Hub.Broadcast <- msg
return return
case MessageTypeCommand: case MessageTypeCommand:
// 处理命令(保持向后兼容) // 处理命令(保持向后兼容)
@@ -135,7 +136,7 @@ func (c *Client) handleMessage(msgMap map[string]interface{}) {
Type: MessageTypeCommand, Type: MessageTypeCommand,
Data: msgMap["data"], Data: msgMap["data"],
} }
c.handleCommand(msg) c.HandleCommand(msg)
return return
} }
} }
@@ -147,28 +148,28 @@ func (c *Client) handleMessage(msgMap map[string]interface{}) {
seq := msgMap["seq"].(string) seq := msgMap["seq"].(string)
// 处理命令 // 处理命令
c.handleNewCommand(seq, cmd, data) c.HandleNewCommand(seq, cmd, data)
} }
} }
func (c *Client) writePump() { func (c *Client) WritePump() {
ticker := time.NewTicker(pingPeriod) ticker := time.NewTicker(pingPeriod)
defer func() { defer func() {
ticker.Stop() ticker.Stop()
c.conn.Close() c.Conn.Close()
}() }()
for { for {
select { select {
case message, ok := <-c.send: case message, ok := <-c.Send:
c.conn.SetWriteDeadline(time.Now().Add(writeWait)) c.Conn.SetWriteDeadline(time.Now().Add(writeWait))
if !ok { if !ok {
// Hub 关闭了通道 // Hub 关闭了通道
c.conn.WriteMessage(websocket.CloseMessage, []byte{}) c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
return return
} }
w, err := c.conn.NextWriter(websocket.TextMessage) w, err := c.Conn.NextWriter(websocket.TextMessage)
if err != nil { if err != nil {
return return
} }
@@ -186,20 +187,20 @@ func (c *Client) writePump() {
} }
case <-ticker.C: case <-ticker.C:
c.conn.SetWriteDeadline(time.Now().Add(writeWait)) c.Conn.SetWriteDeadline(time.Now().Add(writeWait))
pingMsg := &Message{Type: MessageTypePing} pingMsg := &Message{Type: MessageTypePing}
pingBytes, err := json.Marshal(pingMsg) pingBytes, err := json.Marshal(pingMsg)
if err != nil { if err != nil {
return return
} }
if err := c.conn.WriteMessage(websocket.TextMessage, pingBytes); err != nil { if err := c.Conn.WriteMessage(websocket.TextMessage, pingBytes); err != nil {
return return
} }
} }
} }
} }
func (c *Client) handleCommand(msg *Message) { func (c *Client) HandleCommand(msg *Message) {
// 处理命令逻辑 // 处理命令逻辑
// 这里可以根据命令类型执行不同的操作 // 这里可以根据命令类型执行不同的操作
log.Printf("Received command: %v", msg.Data) log.Printf("Received command: %v", msg.Data)
@@ -217,22 +218,22 @@ func (c *Client) handleCommand(msg *Message) {
Type: MessageTypeError, Type: MessageTypeError,
Content: "Invalid register command: missing account or password", Content: "Invalid register command: missing account or password",
} }
c.send <- errorResponse c.Send <- errorResponse
return return
} }
// 调用用户服务注册 // 调用用户服务注册
if c.hub.userService != nil { if c.Hub.UserService != nil {
// 异步调用用户服务注册 // 异步调用用户服务注册
go func() { go func() {
resp, err := c.hub.userService.Register(nil, account, password) resp, err := c.Hub.UserService.Register(nil, account, password)
if err != nil { if err != nil {
// 回复错误信息 // 回复错误信息
errorResponse := &Message{ errorResponse := &Message{
Type: MessageTypeError, Type: MessageTypeError,
Content: "Register failed: " + err.Error(), Content: "Register failed: " + err.Error(),
} }
c.send <- errorResponse c.Send <- errorResponse
return return
} }
@@ -247,7 +248,7 @@ func (c *Client) handleCommand(msg *Message) {
"code": resp.Response.Code, "code": resp.Response.Code,
}, },
} }
c.send <- successResponse c.Send <- successResponse
}() }()
} else { } else {
// 回复错误信息 // 回复错误信息
@@ -255,7 +256,7 @@ func (c *Client) handleCommand(msg *Message) {
Type: MessageTypeError, Type: MessageTypeError,
Content: "User service not available", Content: "User service not available",
} }
c.send <- errorResponse c.Send <- errorResponse
} }
return return
} }
@@ -268,10 +269,10 @@ func (c *Client) handleCommand(msg *Message) {
Data: msg.Data, Data: msg.Data,
} }
c.send <- response c.Send <- response
} }
func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) { func (c *Client) HandleNewCommand(seq string, cmd string, data interface{}) {
// 处理新的命令结构 // 处理新的命令结构
log.Printf("Received new command: %s, seq: %s, data: %v", cmd, seq, data) log.Printf("Received new command: %s, seq: %s, data: %v", cmd, seq, data)
@@ -285,7 +286,7 @@ func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) {
if !accountOk || !passwordOk { if !accountOk || !passwordOk {
// 回复错误信息 // 回复错误信息
c.sendWs(cmd, map[string]interface{}{ c.SendWs(cmd, map[string]interface{}{
"type": "error", "type": "error",
"content": "Invalid register command: missing account or password", "content": "Invalid register command: missing account or password",
}) })
@@ -293,13 +294,13 @@ func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) {
} }
// 调用用户服务注册 // 调用用户服务注册
if c.hub.userService != nil { if c.Hub.UserService != nil {
// 异步调用用户服务注册 // 异步调用用户服务注册
go func() { go func() {
resp, err := c.hub.userService.Register(nil, account, password) resp, err := c.Hub.UserService.Register(nil, account, password)
if err != nil { if err != nil {
// 回复错误信息 // 回复错误信息
c.sendWs(cmd, map[string]interface{}{ c.SendWs(cmd, map[string]interface{}{
"type": "error", "type": "error",
"content": "Register failed: " + err.Error(), "content": "Register failed: " + err.Error(),
}) })
@@ -307,7 +308,7 @@ func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) {
} }
// 回复成功信息 // 回复成功信息
c.sendWs(cmd, map[string]interface{}{ c.SendWs(cmd, map[string]interface{}{
"type": "text", "type": "text",
"content": "Register successful", "content": "Register successful",
"data": map[string]interface{}{ "data": map[string]interface{}{
@@ -320,7 +321,7 @@ func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) {
}() }()
} else { } else {
// 回复错误信息 // 回复错误信息
c.sendWs(cmd, map[string]interface{}{ c.SendWs(cmd, map[string]interface{}{
"type": "error", "type": "error",
"content": "User service not available", "content": "User service not available",
}) })
@@ -329,7 +330,7 @@ func (c *Client) handleNewCommand(seq string, cmd string, data interface{}) {
return return
default: default:
// 其他命令处理 // 其他命令处理
c.sendWs(cmd, map[string]interface{}{ c.SendWs(cmd, map[string]interface{}{
"type": "text", "type": "text",
"content": "Command executed successfully", "content": "Command executed successfully",
"data": data, "data": data,

View File

@@ -3,57 +3,57 @@ package ws
import ( import (
"log" "log"
"backend/gateway/internal/service" "gateway/internal/service"
) )
type Hub struct { type Hub struct {
// 注册的客户端 // 注册的客户端
clients map[*Client]bool Clients map[*Client]bool
// 从客户端接收的消息 // 从客户端接收的消息
broadcast chan *Message Broadcast chan *Message
// 注册请求 // 注册请求
register chan *Client Register chan *Client
// 注销请求 // 注销请求
unregister chan *Client Unregister chan *Client
// 用户服务 // 用户服务
userService *service.UserService UserService *service.UserService
} }
func NewHub(userService *service.UserService) *Hub { func NewHub(userService *service.UserService) *Hub {
return &Hub{ return &Hub{
broadcast: make(chan *Message), Broadcast: make(chan *Message),
register: make(chan *Client), Register: make(chan *Client),
unregister: make(chan *Client), Unregister: make(chan *Client),
clients: make(map[*Client]bool), Clients: make(map[*Client]bool),
userService: userService, UserService: userService,
} }
} }
func (h *Hub) Run() { func (h *Hub) Run() {
for { for {
select { select {
case client := <-h.register: case client := <-h.Register:
h.clients[client] = true h.Clients[client] = true
log.Printf("Client connected. Total clients: %d", len(h.clients)) log.Printf("Client connected. Total clients: %d", len(h.Clients))
case client := <-h.unregister: case client := <-h.Unregister:
if _, ok := h.clients[client]; ok { if _, ok := h.Clients[client]; ok {
delete(h.clients, client) delete(h.Clients, client)
close(client.send) close(client.Send)
log.Printf("Client disconnected. Total clients: %d", len(h.clients)) log.Printf("Client disconnected. Total clients: %d", len(h.Clients))
} }
case message := <-h.broadcast: case message := <-h.Broadcast:
for client := range h.clients { for client := range h.Clients {
select { select {
case client.send <- message: case client.Send <- message:
default: default:
close(client.send) close(client.Send)
delete(h.clients, client) delete(h.Clients, client)
} }
} }
} }

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.1-alpine3.23 FROM golang:1.25.8-alpine3.23
# 安装 protoc 和相关工具 # 安装 protoc 和相关工具
RUN apk add --no-cache protobuf-dev RUN apk add --no-cache protobuf-dev
@@ -11,4 +11,4 @@ RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
WORKDIR /proto WORKDIR /proto
# 生成 proto 文件的命令 # 生成 proto 文件的命令
CMD protoc --go_out=. --go-grpc_out=. common/*.proto CMD protoc --go_out=. --go-grpc_out=. shared/proto/common/*.proto shared/proto/user/*.proto

View File

@@ -1,16 +1,29 @@
FROM golang:1.26.1-alpine3.23 as builder FROM golang:1.25.8-alpine3.23 AS builder
# 设置工作目录 # 设置工作目录
WORKDIR /app WORKDIR /app
# 复制 go.mod 和 go.sum # 安装 git
COPY go.mod go.sum ./ RUN apk add --no-cache git
# 下载依赖 # 设置 Go 环境变量
RUN go mod download ENV GOPROXY=https://goproxy.io,direct
ENV GOSUMDB=off
# 复制共享包
COPY shared/ /shared/
# 复制 go.mod
COPY services/user-svc/go.mod ./
# 复制 go.sum如果存在
COPY services/user-svc/go.sum* ./
# 复制源代码 # 复制源代码
COPY . . COPY services/user-svc/ .
# 生成 go.sum 并下载依赖
RUN go mod tidy
# 构建应用 # 构建应用
RUN go build -o user-svc ./cmd/main.go RUN go build -o user-svc ./cmd/main.go

View File

@@ -4,12 +4,13 @@ import (
"fmt" "fmt"
"log" "log"
"backend/services/user-svc/internal/config" "user-svc/internal/config"
"backend/services/user-svc/internal/grpcserver" "user-svc/internal/grpcserver"
"backend/services/user-svc/internal/repository" "user-svc/internal/repository"
"backend/services/user-svc/internal/service" "user-svc/internal/service"
"backend/shared/pkg/database"
"backend/shared/pkg/logger" "shared/pkg/database"
"shared/pkg/logger"
) )
func main() { func main() {

View File

@@ -1,6 +1,6 @@
module backend/services/user-svc module user-svc
go 1.26.1 go 1.25.8
require ( require (
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
@@ -8,4 +8,9 @@ require (
golang.org/x/crypto v0.20.0 golang.org/x/crypto v0.20.0
google.golang.org/grpc v1.64.0 google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.33.0
shared v0.0.0
)
replace (
shared => /shared
) )

View File

@@ -30,7 +30,7 @@ func Load() (*Config, error) {
viper.AddConfigPath("../../config") viper.AddConfigPath("../../config")
viper.SetDefault("server.port", 9000) viper.SetDefault("server.port", 9000)
viper.SetDefault("database.host", "postgres") viper.SetDefault("database.host", "backend-postgres")
viper.SetDefault("database.port", 5432) viper.SetDefault("database.port", 5432)
viper.SetDefault("database.user", "admin") viper.SetDefault("database.user", "admin")
viper.SetDefault("database.password", "password") viper.SetDefault("database.password", "password")

View File

@@ -5,17 +5,18 @@ import (
"fmt" "fmt"
"net" "net"
"backend/services/user-svc/internal/domain" "user-svc/internal/domain"
"backend/services/user-svc/internal/service" "user-svc/internal/service"
"backend/shared/pkg/errors" "shared/pkg/errors"
"backend/shared/pkg/logger" "shared/pkg/logger"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
// 导入生成的 proto 代码 // 导入生成的 proto 代码
userpb "backend/services/user-svc/proto" userpb "shared/proto/user"
common "shared/proto/common"
) )
type UserServer struct { type UserServer struct {
@@ -44,21 +45,21 @@ func (s *UserServer) Register(ctx context.Context, req *userpb.RegisterRequest)
switch { switch {
case errors.IsConflict(err): case errors.IsConflict(err):
return &userpb.RegisterResponse{ return &userpb.RegisterResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 409, Code: 409,
Message: "账号已存在", Message: "账号已存在",
}, },
}, status.Errorf(codes.AlreadyExists, "账号已存在") }, status.Errorf(codes.AlreadyExists, "账号已存在")
case errors.IsInvalidInput(err): case errors.IsInvalidInput(err):
return &userpb.RegisterResponse{ return &userpb.RegisterResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 400, Code: 400,
Message: "无效的输入参数", Message: "无效的输入参数",
}, },
}, status.Errorf(codes.InvalidArgument, "无效的输入参数") }, status.Errorf(codes.InvalidArgument, "无效的输入参数")
default: default:
return &userpb.RegisterResponse{ return &userpb.RegisterResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 500, Code: 500,
Message: "内部服务器错误", Message: "内部服务器错误",
}, },
@@ -70,7 +71,7 @@ func (s *UserServer) Register(ctx context.Context, req *userpb.RegisterRequest)
return &userpb.RegisterResponse{ return &userpb.RegisterResponse{
UserId: resp.UserID.String(), UserId: resp.UserID.String(),
Account: resp.Account, Account: resp.Account,
Response: &userpb.Response{ Response: &common.Response{
Code: 200, Code: 200,
Message: "注册成功", Message: "注册成功",
}, },
@@ -88,21 +89,21 @@ func (s *UserServer) GetUserByAccount(ctx context.Context, req *userpb.GetUserBy
switch { switch {
case errors.IsNotFound(err): case errors.IsNotFound(err):
return &userpb.GetUserByAccountResponse{ return &userpb.GetUserByAccountResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 404, Code: 404,
Message: "用户不存在", Message: "用户不存在",
}, },
}, status.Errorf(codes.NotFound, "用户不存在") }, status.Errorf(codes.NotFound, "用户不存在")
case errors.IsInvalidInput(err): case errors.IsInvalidInput(err):
return &userpb.GetUserByAccountResponse{ return &userpb.GetUserByAccountResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 400, Code: 400,
Message: "无效的输入参数", Message: "无效的输入参数",
}, },
}, status.Errorf(codes.InvalidArgument, "无效的输入参数") }, status.Errorf(codes.InvalidArgument, "无效的输入参数")
default: default:
return &userpb.GetUserByAccountResponse{ return &userpb.GetUserByAccountResponse{
Response: &userpb.Response{ Response: &common.Response{
Code: 500, Code: 500,
Message: "内部服务器错误", Message: "内部服务器错误",
}, },
@@ -114,7 +115,7 @@ func (s *UserServer) GetUserByAccount(ctx context.Context, req *userpb.GetUserBy
return &userpb.GetUserByAccountResponse{ return &userpb.GetUserByAccountResponse{
UserId: user.ID.String(), UserId: user.ID.String(),
Account: account.Account, Account: account.Account,
Response: &userpb.Response{ Response: &common.Response{
Code: 200, Code: 200,
Message: "获取成功", Message: "获取成功",
}, },

View File

@@ -2,10 +2,9 @@ package repository
import ( import (
"database/sql" "database/sql"
"time"
"backend/services/user-svc/internal/domain" "user-svc/internal/domain"
"backend/shared/pkg/errors" "shared/pkg/errors"
"github.com/google/uuid" "github.com/google/uuid"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@@ -41,7 +40,11 @@ func (r *UserRepository) Register(req *domain.RegisterRequest) (*domain.Register
} }
// 创建用户 // 创建用户
userID := uuid.NewV7() userID, err := uuid.NewV7()
if err != nil {
tx.Rollback()
return nil, errors.WrapError(err, "failed to generate user ID")
}
userQuery := "INSERT INTO user_main (id, deleted) VALUES ($1, $2)" userQuery := "INSERT INTO user_main (id, deleted) VALUES ($1, $2)"
if _, err := tx.Exec(userQuery, userID, false); err != nil { if _, err := tx.Exec(userQuery, userID, false); err != nil {
@@ -50,7 +53,11 @@ func (r *UserRepository) Register(req *domain.RegisterRequest) (*domain.Register
} }
// 创建登录账号 // 创建登录账号
accountID := uuid.NewV7() accountID, err := uuid.NewV7()
if err != nil {
tx.Rollback()
return nil, errors.WrapError(err, "failed to generate account ID")
}
accountQuery := "INSERT INTO user_login_account (id, user_id, account, deleted) VALUES ($1, $2, $3, $4)" accountQuery := "INSERT INTO user_login_account (id, user_id, account, deleted) VALUES ($1, $2, $3, $4)"
if _, err := tx.Exec(accountQuery, accountID, userID, req.Account, false); err != nil { if _, err := tx.Exec(accountQuery, accountID, userID, req.Account, false); err != nil {
tx.Rollback() tx.Rollback()
@@ -65,7 +72,11 @@ func (r *UserRepository) Register(req *domain.RegisterRequest) (*domain.Register
} }
// 创建密码记录 // 创建密码记录
passwordID := uuid.NewV7() passwordID, err := uuid.NewV7()
if err != nil {
tx.Rollback()
return nil, errors.WrapError(err, "failed to generate password ID")
}
passwordQuery := "INSERT INTO user_login_password (id, user_id, password, deleted) VALUES ($1, $2, $3, $4)" passwordQuery := "INSERT INTO user_login_password (id, user_id, password, deleted) VALUES ($1, $2, $3, $4)"
if _, err := tx.Exec(passwordQuery, passwordID, userID, string(hashedPassword), false); err != nil { if _, err := tx.Exec(passwordQuery, passwordID, userID, string(hashedPassword), false); err != nil {
tx.Rollback() tx.Rollback()

View File

@@ -1,9 +1,10 @@
package service package service
import ( import (
"backend/services/user-svc/internal/domain" "user-svc/internal/domain"
"backend/services/user-svc/internal/repository" "user-svc/internal/repository"
"backend/shared/pkg/errors"
"shared/pkg/errors"
) )
type UserService struct { type UserService struct {

View File

@@ -0,0 +1,11 @@
module user-svc/proto
go 1.25.8
require (
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.33.0
shared v0.0.0
)
replace shared => /shared

View File

@@ -0,0 +1,323 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.31.1
// source: services/user-svc/proto/user.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
common "shared/proto/common"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 注册请求
type RegisterRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RegisterRequest) Reset() {
*x = RegisterRequest{}
mi := &file_services_user_svc_proto_user_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RegisterRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterRequest) ProtoMessage() {}
func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
mi := &file_services_user_svc_proto_user_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead.
func (*RegisterRequest) Descriptor() ([]byte, []int) {
return file_services_user_svc_proto_user_proto_rawDescGZIP(), []int{0}
}
func (x *RegisterRequest) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *RegisterRequest) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
// 注册响应
type RegisterResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"`
Response *common.Response `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RegisterResponse) Reset() {
*x = RegisterResponse{}
mi := &file_services_user_svc_proto_user_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RegisterResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterResponse) ProtoMessage() {}
func (x *RegisterResponse) ProtoReflect() protoreflect.Message {
mi := &file_services_user_svc_proto_user_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead.
func (*RegisterResponse) Descriptor() ([]byte, []int) {
return file_services_user_svc_proto_user_proto_rawDescGZIP(), []int{1}
}
func (x *RegisterResponse) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *RegisterResponse) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *RegisterResponse) GetResponse() *common.Response {
if x != nil {
return x.Response
}
return nil
}
// 获取用户信息请求
type GetUserByAccountRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetUserByAccountRequest) Reset() {
*x = GetUserByAccountRequest{}
mi := &file_services_user_svc_proto_user_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetUserByAccountRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetUserByAccountRequest) ProtoMessage() {}
func (x *GetUserByAccountRequest) ProtoReflect() protoreflect.Message {
mi := &file_services_user_svc_proto_user_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetUserByAccountRequest.ProtoReflect.Descriptor instead.
func (*GetUserByAccountRequest) Descriptor() ([]byte, []int) {
return file_services_user_svc_proto_user_proto_rawDescGZIP(), []int{2}
}
func (x *GetUserByAccountRequest) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
// 获取用户信息响应
type GetUserByAccountResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"`
Response *common.Response `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetUserByAccountResponse) Reset() {
*x = GetUserByAccountResponse{}
mi := &file_services_user_svc_proto_user_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetUserByAccountResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetUserByAccountResponse) ProtoMessage() {}
func (x *GetUserByAccountResponse) ProtoReflect() protoreflect.Message {
mi := &file_services_user_svc_proto_user_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetUserByAccountResponse.ProtoReflect.Descriptor instead.
func (*GetUserByAccountResponse) Descriptor() ([]byte, []int) {
return file_services_user_svc_proto_user_proto_rawDescGZIP(), []int{3}
}
func (x *GetUserByAccountResponse) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *GetUserByAccountResponse) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *GetUserByAccountResponse) GetResponse() *common.Response {
if x != nil {
return x.Response
}
return nil
}
var File_services_user_svc_proto_user_proto protoreflect.FileDescriptor
const file_services_user_svc_proto_user_proto_rawDesc = "" +
"\n" +
"\"services/user-svc/proto/user.proto\x12\x04user\x1a shared/proto/common/common.proto\"G\n" +
"\x0fRegisterRequest\x12\x18\n" +
"\aaccount\x18\x01 \x01(\tR\aaccount\x12\x1a\n" +
"\bpassword\x18\x02 \x01(\tR\bpassword\"s\n" +
"\x10RegisterResponse\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x18\n" +
"\aaccount\x18\x02 \x01(\tR\aaccount\x12,\n" +
"\bresponse\x18\x03 \x01(\v2\x10.common.ResponseR\bresponse\"3\n" +
"\x17GetUserByAccountRequest\x12\x18\n" +
"\aaccount\x18\x01 \x01(\tR\aaccount\"{\n" +
"\x18GetUserByAccountResponse\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x18\n" +
"\aaccount\x18\x02 \x01(\tR\aaccount\x12,\n" +
"\bresponse\x18\x03 \x01(\v2\x10.common.ResponseR\bresponse2\x9b\x01\n" +
"\vUserService\x129\n" +
"\bRegister\x12\x15.user.RegisterRequest\x1a\x16.user.RegisterResponse\x12Q\n" +
"\x10GetUserByAccount\x12\x1d.user.GetUserByAccountRequest\x1a\x1e.user.GetUserByAccountResponseB\x10Z\x0euser-svc/protob\x06proto3"
var (
file_services_user_svc_proto_user_proto_rawDescOnce sync.Once
file_services_user_svc_proto_user_proto_rawDescData []byte
)
func file_services_user_svc_proto_user_proto_rawDescGZIP() []byte {
file_services_user_svc_proto_user_proto_rawDescOnce.Do(func() {
file_services_user_svc_proto_user_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_services_user_svc_proto_user_proto_rawDesc), len(file_services_user_svc_proto_user_proto_rawDesc)))
})
return file_services_user_svc_proto_user_proto_rawDescData
}
var file_services_user_svc_proto_user_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_services_user_svc_proto_user_proto_goTypes = []any{
(*RegisterRequest)(nil), // 0: user.RegisterRequest
(*RegisterResponse)(nil), // 1: user.RegisterResponse
(*GetUserByAccountRequest)(nil), // 2: user.GetUserByAccountRequest
(*GetUserByAccountResponse)(nil), // 3: user.GetUserByAccountResponse
(*common.Response)(nil), // 4: common.Response
}
var file_services_user_svc_proto_user_proto_depIdxs = []int32{
4, // 0: user.RegisterResponse.response:type_name -> common.Response
4, // 1: user.GetUserByAccountResponse.response:type_name -> common.Response
0, // 2: user.UserService.Register:input_type -> user.RegisterRequest
2, // 3: user.UserService.GetUserByAccount:input_type -> user.GetUserByAccountRequest
1, // 4: user.UserService.Register:output_type -> user.RegisterResponse
3, // 5: user.UserService.GetUserByAccount:output_type -> user.GetUserByAccountResponse
4, // [4:6] is the sub-list for method output_type
2, // [2:4] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_services_user_svc_proto_user_proto_init() }
func file_services_user_svc_proto_user_proto_init() {
if File_services_user_svc_proto_user_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_services_user_svc_proto_user_proto_rawDesc), len(file_services_user_svc_proto_user_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_services_user_svc_proto_user_proto_goTypes,
DependencyIndexes: file_services_user_svc_proto_user_proto_depIdxs,
MessageInfos: file_services_user_svc_proto_user_proto_msgTypes,
}.Build()
File_services_user_svc_proto_user_proto = out.File
file_services_user_svc_proto_user_proto_goTypes = nil
file_services_user_svc_proto_user_proto_depIdxs = nil
}

View File

@@ -0,0 +1,167 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc v6.31.1
// source: services/user-svc/proto/user.proto
package proto
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
UserService_Register_FullMethodName = "/user.UserService/Register"
UserService_GetUserByAccount_FullMethodName = "/user.UserService/GetUserByAccount"
)
// UserServiceClient is the client API for UserService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// 用户服务
type UserServiceClient interface {
// 注册用户
Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error)
// 获取用户信息
GetUserByAccount(ctx context.Context, in *GetUserByAccountRequest, opts ...grpc.CallOption) (*GetUserByAccountResponse, error)
}
type userServiceClient struct {
cc grpc.ClientConnInterface
}
func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient {
return &userServiceClient{cc}
}
func (c *userServiceClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RegisterResponse)
err := c.cc.Invoke(ctx, UserService_Register_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userServiceClient) GetUserByAccount(ctx context.Context, in *GetUserByAccountRequest, opts ...grpc.CallOption) (*GetUserByAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserByAccountResponse)
err := c.cc.Invoke(ctx, UserService_GetUserByAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// UserServiceServer is the server API for UserService service.
// All implementations must embed UnimplementedUserServiceServer
// for forward compatibility.
//
// 用户服务
type UserServiceServer interface {
// 注册用户
Register(context.Context, *RegisterRequest) (*RegisterResponse, error)
// 获取用户信息
GetUserByAccount(context.Context, *GetUserByAccountRequest) (*GetUserByAccountResponse, error)
mustEmbedUnimplementedUserServiceServer()
}
// UnimplementedUserServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedUserServiceServer struct{}
func (UnimplementedUserServiceServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Register not implemented")
}
func (UnimplementedUserServiceServer) GetUserByAccount(context.Context, *GetUserByAccountRequest) (*GetUserByAccountResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserByAccount not implemented")
}
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
func (UnimplementedUserServiceServer) testEmbeddedByValue() {}
// UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to UserServiceServer will
// result in compilation errors.
type UnsafeUserServiceServer interface {
mustEmbedUnimplementedUserServiceServer()
}
func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
// If the following call panics, it indicates UnimplementedUserServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&UserService_ServiceDesc, srv)
}
func _UserService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RegisterRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServiceServer).Register(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserService_Register_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).Register(ctx, req.(*RegisterRequest))
}
return interceptor(ctx, in, info, handler)
}
func _UserService_GetUserByAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserByAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServiceServer).GetUserByAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserService_GetUserByAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).GetUserByAccount(ctx, req.(*GetUserByAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var UserService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "user.UserService",
HandlerType: (*UserServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Register",
Handler: _UserService_Register_Handler,
},
{
MethodName: "GetUserByAccount",
Handler: _UserService_GetUserByAccount_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "services/user-svc/proto/user.proto",
}

8
backend/shared/go.mod Normal file
View File

@@ -0,0 +1,8 @@
module shared
go 1.25.8
require (
github.com/go-redis/redis/v8 v8.11.5
github.com/lib/pq v1.10.9
)

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"time" "time"
"backend/shared/pkg/logger" "shared/pkg/logger"
_ "github.com/lib/pq" _ "github.com/lib/pq"
) )

View File

@@ -0,0 +1,572 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.31.1
// source: shared/proto/common/common.proto
package common
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 通用响应结构
type Response struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Response) Reset() {
*x = Response{}
mi := &file_shared_proto_common_common_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{0}
}
func (x *Response) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *Response) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *Response) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
// 分页请求
type PaginationRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PaginationRequest) Reset() {
*x = PaginationRequest{}
mi := &file_shared_proto_common_common_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PaginationRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PaginationRequest) ProtoMessage() {}
func (x *PaginationRequest) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PaginationRequest.ProtoReflect.Descriptor instead.
func (*PaginationRequest) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{1}
}
func (x *PaginationRequest) GetPage() int32 {
if x != nil {
return x.Page
}
return 0
}
func (x *PaginationRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
// 分页响应
type PaginationResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Total int32 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
Page int32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"`
PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
TotalPages int32 `protobuf:"varint,4,opt,name=total_pages,json=totalPages,proto3" json:"total_pages,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PaginationResponse) Reset() {
*x = PaginationResponse{}
mi := &file_shared_proto_common_common_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PaginationResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PaginationResponse) ProtoMessage() {}
func (x *PaginationResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PaginationResponse.ProtoReflect.Descriptor instead.
func (*PaginationResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{2}
}
func (x *PaginationResponse) GetTotal() int32 {
if x != nil {
return x.Total
}
return 0
}
func (x *PaginationResponse) GetPage() int32 {
if x != nil {
return x.Page
}
return 0
}
func (x *PaginationResponse) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *PaginationResponse) GetTotalPages() int32 {
if x != nil {
return x.TotalPages
}
return 0
}
// 错误信息
type Error struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Details string `protobuf:"bytes,3,opt,name=details,proto3" json:"details,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Error) Reset() {
*x = Error{}
mi := &file_shared_proto_common_common_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Error) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Error) ProtoMessage() {}
func (x *Error) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Error.ProtoReflect.Descriptor instead.
func (*Error) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{3}
}
func (x *Error) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *Error) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *Error) GetDetails() string {
if x != nil {
return x.Details
}
return ""
}
// 空请求
type EmptyRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EmptyRequest) Reset() {
*x = EmptyRequest{}
mi := &file_shared_proto_common_common_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EmptyRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EmptyRequest) ProtoMessage() {}
func (x *EmptyRequest) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EmptyRequest.ProtoReflect.Descriptor instead.
func (*EmptyRequest) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{4}
}
// 空响应
type EmptyResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EmptyResponse) Reset() {
*x = EmptyResponse{}
mi := &file_shared_proto_common_common_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EmptyResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EmptyResponse) ProtoMessage() {}
func (x *EmptyResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead.
func (*EmptyResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{5}
}
// ID 请求
type IDRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IDRequest) Reset() {
*x = IDRequest{}
mi := &file_shared_proto_common_common_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IDRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IDRequest) ProtoMessage() {}
func (x *IDRequest) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IDRequest.ProtoReflect.Descriptor instead.
func (*IDRequest) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{6}
}
func (x *IDRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
// ID 响应
type IDResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IDResponse) Reset() {
*x = IDResponse{}
mi := &file_shared_proto_common_common_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IDResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IDResponse) ProtoMessage() {}
func (x *IDResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IDResponse.ProtoReflect.Descriptor instead.
func (*IDResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{7}
}
func (x *IDResponse) GetId() string {
if x != nil {
return x.Id
}
return ""
}
// 状态响应
type StatusResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StatusResponse) Reset() {
*x = StatusResponse{}
mi := &file_shared_proto_common_common_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StatusResponse) ProtoMessage() {}
func (x *StatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_common_common_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead.
func (*StatusResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_common_common_proto_rawDescGZIP(), []int{8}
}
func (x *StatusResponse) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *StatusResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_shared_proto_common_common_proto protoreflect.FileDescriptor
const file_shared_proto_common_common_proto_rawDesc = "" +
"\n" +
" shared/proto/common/common.proto\x12\x06common\"L\n" +
"\bResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12\x12\n" +
"\x04data\x18\x03 \x01(\fR\x04data\"D\n" +
"\x11PaginationRequest\x12\x12\n" +
"\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" +
"\tpage_size\x18\x02 \x01(\x05R\bpageSize\"|\n" +
"\x12PaginationResponse\x12\x14\n" +
"\x05total\x18\x01 \x01(\x05R\x05total\x12\x12\n" +
"\x04page\x18\x02 \x01(\x05R\x04page\x12\x1b\n" +
"\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x1f\n" +
"\vtotal_pages\x18\x04 \x01(\x05R\n" +
"totalPages\"O\n" +
"\x05Error\x12\x12\n" +
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12\x18\n" +
"\adetails\x18\x03 \x01(\tR\adetails\"\x0e\n" +
"\fEmptyRequest\"\x0f\n" +
"\rEmptyResponse\"\x1b\n" +
"\tIDRequest\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\"\x1c\n" +
"\n" +
"IDResponse\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\"D\n" +
"\x0eStatusResponse\x12\x18\n" +
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessageB\x15Z\x13shared/proto/commonb\x06proto3"
var (
file_shared_proto_common_common_proto_rawDescOnce sync.Once
file_shared_proto_common_common_proto_rawDescData []byte
)
func file_shared_proto_common_common_proto_rawDescGZIP() []byte {
file_shared_proto_common_common_proto_rawDescOnce.Do(func() {
file_shared_proto_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_shared_proto_common_common_proto_rawDesc), len(file_shared_proto_common_common_proto_rawDesc)))
})
return file_shared_proto_common_common_proto_rawDescData
}
var file_shared_proto_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_shared_proto_common_common_proto_goTypes = []any{
(*Response)(nil), // 0: common.Response
(*PaginationRequest)(nil), // 1: common.PaginationRequest
(*PaginationResponse)(nil), // 2: common.PaginationResponse
(*Error)(nil), // 3: common.Error
(*EmptyRequest)(nil), // 4: common.EmptyRequest
(*EmptyResponse)(nil), // 5: common.EmptyResponse
(*IDRequest)(nil), // 6: common.IDRequest
(*IDResponse)(nil), // 7: common.IDResponse
(*StatusResponse)(nil), // 8: common.StatusResponse
}
var file_shared_proto_common_common_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_shared_proto_common_common_proto_init() }
func file_shared_proto_common_common_proto_init() {
if File_shared_proto_common_common_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_shared_proto_common_common_proto_rawDesc), len(file_shared_proto_common_common_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_shared_proto_common_common_proto_goTypes,
DependencyIndexes: file_shared_proto_common_common_proto_depIdxs,
MessageInfos: file_shared_proto_common_common_proto_msgTypes,
}.Build()
File_shared_proto_common_common_proto = out.File
file_shared_proto_common_common_proto_goTypes = nil
file_shared_proto_common_common_proto_depIdxs = nil
}

View File

@@ -2,6 +2,8 @@ syntax = "proto3";
package common; package common;
option go_package = "shared/proto/common";
// 通用响应结构 // 通用响应结构
message Response { message Response {
int32 code = 1; int32 code = 1;

View File

@@ -0,0 +1,323 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.31.1
// source: shared/proto/user/user.proto
package user
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
common "shared/proto/common"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 注册请求
type RegisterRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RegisterRequest) Reset() {
*x = RegisterRequest{}
mi := &file_shared_proto_user_user_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RegisterRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterRequest) ProtoMessage() {}
func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_user_user_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead.
func (*RegisterRequest) Descriptor() ([]byte, []int) {
return file_shared_proto_user_user_proto_rawDescGZIP(), []int{0}
}
func (x *RegisterRequest) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *RegisterRequest) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
// 注册响应
type RegisterResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"`
Response *common.Response `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RegisterResponse) Reset() {
*x = RegisterResponse{}
mi := &file_shared_proto_user_user_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RegisterResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterResponse) ProtoMessage() {}
func (x *RegisterResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_user_user_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead.
func (*RegisterResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_user_user_proto_rawDescGZIP(), []int{1}
}
func (x *RegisterResponse) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *RegisterResponse) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *RegisterResponse) GetResponse() *common.Response {
if x != nil {
return x.Response
}
return nil
}
// 获取用户信息请求
type GetUserByAccountRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetUserByAccountRequest) Reset() {
*x = GetUserByAccountRequest{}
mi := &file_shared_proto_user_user_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetUserByAccountRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetUserByAccountRequest) ProtoMessage() {}
func (x *GetUserByAccountRequest) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_user_user_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetUserByAccountRequest.ProtoReflect.Descriptor instead.
func (*GetUserByAccountRequest) Descriptor() ([]byte, []int) {
return file_shared_proto_user_user_proto_rawDescGZIP(), []int{2}
}
func (x *GetUserByAccountRequest) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
// 获取用户信息响应
type GetUserByAccountResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"`
Response *common.Response `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetUserByAccountResponse) Reset() {
*x = GetUserByAccountResponse{}
mi := &file_shared_proto_user_user_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetUserByAccountResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetUserByAccountResponse) ProtoMessage() {}
func (x *GetUserByAccountResponse) ProtoReflect() protoreflect.Message {
mi := &file_shared_proto_user_user_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetUserByAccountResponse.ProtoReflect.Descriptor instead.
func (*GetUserByAccountResponse) Descriptor() ([]byte, []int) {
return file_shared_proto_user_user_proto_rawDescGZIP(), []int{3}
}
func (x *GetUserByAccountResponse) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *GetUserByAccountResponse) GetAccount() string {
if x != nil {
return x.Account
}
return ""
}
func (x *GetUserByAccountResponse) GetResponse() *common.Response {
if x != nil {
return x.Response
}
return nil
}
var File_shared_proto_user_user_proto protoreflect.FileDescriptor
const file_shared_proto_user_user_proto_rawDesc = "" +
"\n" +
"\x1cshared/proto/user/user.proto\x12\x04user\x1a shared/proto/common/common.proto\"G\n" +
"\x0fRegisterRequest\x12\x18\n" +
"\aaccount\x18\x01 \x01(\tR\aaccount\x12\x1a\n" +
"\bpassword\x18\x02 \x01(\tR\bpassword\"s\n" +
"\x10RegisterResponse\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x18\n" +
"\aaccount\x18\x02 \x01(\tR\aaccount\x12,\n" +
"\bresponse\x18\x03 \x01(\v2\x10.common.ResponseR\bresponse\"3\n" +
"\x17GetUserByAccountRequest\x12\x18\n" +
"\aaccount\x18\x01 \x01(\tR\aaccount\"{\n" +
"\x18GetUserByAccountResponse\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x18\n" +
"\aaccount\x18\x02 \x01(\tR\aaccount\x12,\n" +
"\bresponse\x18\x03 \x01(\v2\x10.common.ResponseR\bresponse2\x9b\x01\n" +
"\vUserService\x129\n" +
"\bRegister\x12\x15.user.RegisterRequest\x1a\x16.user.RegisterResponse\x12Q\n" +
"\x10GetUserByAccount\x12\x1d.user.GetUserByAccountRequest\x1a\x1e.user.GetUserByAccountResponseB\x13Z\x11shared/proto/userb\x06proto3"
var (
file_shared_proto_user_user_proto_rawDescOnce sync.Once
file_shared_proto_user_user_proto_rawDescData []byte
)
func file_shared_proto_user_user_proto_rawDescGZIP() []byte {
file_shared_proto_user_user_proto_rawDescOnce.Do(func() {
file_shared_proto_user_user_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_shared_proto_user_user_proto_rawDesc), len(file_shared_proto_user_user_proto_rawDesc)))
})
return file_shared_proto_user_user_proto_rawDescData
}
var file_shared_proto_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_shared_proto_user_user_proto_goTypes = []any{
(*RegisterRequest)(nil), // 0: user.RegisterRequest
(*RegisterResponse)(nil), // 1: user.RegisterResponse
(*GetUserByAccountRequest)(nil), // 2: user.GetUserByAccountRequest
(*GetUserByAccountResponse)(nil), // 3: user.GetUserByAccountResponse
(*common.Response)(nil), // 4: common.Response
}
var file_shared_proto_user_user_proto_depIdxs = []int32{
4, // 0: user.RegisterResponse.response:type_name -> common.Response
4, // 1: user.GetUserByAccountResponse.response:type_name -> common.Response
0, // 2: user.UserService.Register:input_type -> user.RegisterRequest
2, // 3: user.UserService.GetUserByAccount:input_type -> user.GetUserByAccountRequest
1, // 4: user.UserService.Register:output_type -> user.RegisterResponse
3, // 5: user.UserService.GetUserByAccount:output_type -> user.GetUserByAccountResponse
4, // [4:6] is the sub-list for method output_type
2, // [2:4] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_shared_proto_user_user_proto_init() }
func file_shared_proto_user_user_proto_init() {
if File_shared_proto_user_user_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_shared_proto_user_user_proto_rawDesc), len(file_shared_proto_user_user_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_shared_proto_user_user_proto_goTypes,
DependencyIndexes: file_shared_proto_user_user_proto_depIdxs,
MessageInfos: file_shared_proto_user_user_proto_msgTypes,
}.Build()
File_shared_proto_user_user_proto = out.File
file_shared_proto_user_user_proto_goTypes = nil
file_shared_proto_user_user_proto_depIdxs = nil
}

View File

@@ -2,6 +2,8 @@ syntax = "proto3";
package user; package user;
option go_package = "shared/proto/user";
import "shared/proto/common/common.proto"; import "shared/proto/common/common.proto";
// //

View File

@@ -0,0 +1,167 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc v6.31.1
// source: shared/proto/user/user.proto
package user
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
UserService_Register_FullMethodName = "/user.UserService/Register"
UserService_GetUserByAccount_FullMethodName = "/user.UserService/GetUserByAccount"
)
// UserServiceClient is the client API for UserService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// 用户服务
type UserServiceClient interface {
// 注册用户
Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error)
// 获取用户信息
GetUserByAccount(ctx context.Context, in *GetUserByAccountRequest, opts ...grpc.CallOption) (*GetUserByAccountResponse, error)
}
type userServiceClient struct {
cc grpc.ClientConnInterface
}
func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient {
return &userServiceClient{cc}
}
func (c *userServiceClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RegisterResponse)
err := c.cc.Invoke(ctx, UserService_Register_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userServiceClient) GetUserByAccount(ctx context.Context, in *GetUserByAccountRequest, opts ...grpc.CallOption) (*GetUserByAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserByAccountResponse)
err := c.cc.Invoke(ctx, UserService_GetUserByAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// UserServiceServer is the server API for UserService service.
// All implementations must embed UnimplementedUserServiceServer
// for forward compatibility.
//
// 用户服务
type UserServiceServer interface {
// 注册用户
Register(context.Context, *RegisterRequest) (*RegisterResponse, error)
// 获取用户信息
GetUserByAccount(context.Context, *GetUserByAccountRequest) (*GetUserByAccountResponse, error)
mustEmbedUnimplementedUserServiceServer()
}
// UnimplementedUserServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedUserServiceServer struct{}
func (UnimplementedUserServiceServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Register not implemented")
}
func (UnimplementedUserServiceServer) GetUserByAccount(context.Context, *GetUserByAccountRequest) (*GetUserByAccountResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserByAccount not implemented")
}
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
func (UnimplementedUserServiceServer) testEmbeddedByValue() {}
// UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to UserServiceServer will
// result in compilation errors.
type UnsafeUserServiceServer interface {
mustEmbedUnimplementedUserServiceServer()
}
func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
// If the following call panics, it indicates UnimplementedUserServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&UserService_ServiceDesc, srv)
}
func _UserService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RegisterRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServiceServer).Register(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserService_Register_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).Register(ctx, req.(*RegisterRequest))
}
return interceptor(ctx, in, info, handler)
}
func _UserService_GetUserByAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserByAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServiceServer).GetUserByAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserService_GetUserByAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).GetUserByAccount(ctx, req.(*GetUserByAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var UserService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "user.UserService",
HandlerType: (*UserServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Register",
Handler: _UserService_Register_Handler,
},
{
MethodName: "GetUserByAccount",
Handler: _UserService_GetUserByAccount_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "shared/proto/user/user.proto",
}

10
backend/test.proto Normal file
View File

@@ -0,0 +1,10 @@
syntax = "proto3";
package test;
option go_package = "test/proto";
message TestMessage {
string name = 1;
int32 age = 2;
}

View File

@@ -0,0 +1,133 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.31.1
// source: test.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type TestMessage struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TestMessage) Reset() {
*x = TestMessage{}
mi := &file_test_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TestMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TestMessage) ProtoMessage() {}
func (x *TestMessage) ProtoReflect() protoreflect.Message {
mi := &file_test_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TestMessage.ProtoReflect.Descriptor instead.
func (*TestMessage) Descriptor() ([]byte, []int) {
return file_test_proto_rawDescGZIP(), []int{0}
}
func (x *TestMessage) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *TestMessage) GetAge() int32 {
if x != nil {
return x.Age
}
return 0
}
var File_test_proto protoreflect.FileDescriptor
const file_test_proto_rawDesc = "" +
"\n" +
"\n" +
"test.proto\x12\x04test\"3\n" +
"\vTestMessage\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x10\n" +
"\x03age\x18\x02 \x01(\x05R\x03ageB\fZ\n" +
"test/protob\x06proto3"
var (
file_test_proto_rawDescOnce sync.Once
file_test_proto_rawDescData []byte
)
func file_test_proto_rawDescGZIP() []byte {
file_test_proto_rawDescOnce.Do(func() {
file_test_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_test_proto_rawDesc), len(file_test_proto_rawDesc)))
})
return file_test_proto_rawDescData
}
var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_test_proto_goTypes = []any{
(*TestMessage)(nil), // 0: test.TestMessage
}
var file_test_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_test_proto_init() }
func file_test_proto_init() {
if File_test_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_test_proto_rawDesc), len(file_test_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_test_proto_goTypes,
DependencyIndexes: file_test_proto_depIdxs,
MessageInfos: file_test_proto_msgTypes,
}.Build()
File_test_proto = out.File
file_test_proto_goTypes = nil
file_test_proto_depIdxs = nil
}

45
prompt/v3.md Normal file
View File

@@ -0,0 +1,45 @@
设计用户第注册功能,数据库要求:
```
一、表名user_main
字段:
1、id uuidv7 default 主键。
2、deleted bool defalut false。
3、create_time ....
4、update_time ....
二、表名user_login_account
1、id uuidv7 default 主键。
2、user_id uuidv7 对应 user_main 表的 id。
3、account varchat not null。
4、deleted bool defalut false。
5、create_time ....
6、update_time ....
三、表名user_login_password
1、id uuidv7 default 主键。
2、user_id uuidv7 对应 user_main 表的 id。
3、password varchat not null。
4、deleted bool defalut false。
5、create_time ....
6、update_time ....
```