开发模块的顺序与逻辑
在开发过程中,我们首先从 User 服务 开始。为什么呢?因为当我们进入游戏页面时,微信登录 是第一个需要实现的功能。
微信登录与手机登录的逻辑
-
微信登录:这里我们假设有一个微信登录功能,但不会直接对接微信。我们将微信登录视为一种 注册方式,用户点击注册后,系统会生成一个账号(例如
openID
)。后续可以扩展为真实的微信登录逻辑。 -
手机登录:用户在微信登录后,可以在游戏中绑定手机号。绑定后,用户可以通过手机号登录,直接关联到之前的微信账号。这样就建立了一个账号与手机号的关联关系。
理解清楚需求后,我们开始实现 User 服务。
开发 User 服务
1. 创建项目结构
首先,我们需要创建一个工作目录,并采用 Go Work 模式组织项目。在工作目录下,依次创建以下模块目录:
-
Common:通用工具类和功能。
-
Config:存放配置文件。
-
User:用户相关逻辑,如登录、注册等。
-
其他模块:如
Core
、Game
等,后续会逐步开发。
2. 实现 User 服务
在 User 服务 中,我们首先创建一个入口文件 main.go
,用于启动应用。接下来,我们逐步实现以下功能:
第一步:加载配置文件
加载配置文件是启动服务的第一步。我们需要一个配置文件(如 application.yml
),并使用 Viper 库来加载和解析配置。
创建配置文件
在项目根目录下创建 application.yml
文件,内容如下:
yaml复制
grpc:
port: 50051
metrics:
port: 8080
加载配置代码
在 Common
模块中创建 config.go
文件,实现配置加载逻辑:
go复制
package common
import (
"fmt"
"log"
"os"
"github.com/spf13/viper"
)
var Config struct {
GRPCPort int `mapstructure:"grpc.port"`
MetricsPort int `mapstructure:"metrics.port"`
}
func LoadConfig(configFile string) {
viper.SetConfigFile(configFile)
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Failed to read config file: %v", err)
}
if err := viper.Unmarshal(&Config); err != nil {
log.Fatalf("Failed to unmarshal config: %v", err)
}
fmt.Printf("Loaded config: %+v\n", Config)
}
在 main.go
中调用加载配置
go复制
package main
import (
"log"
"your_project_path/common"
)
func main() {
common.LoadConfig("application.yml")
// 后续启动监控和 GRPC 服务
}
第二步:启动监控
为了方便调试和监控服务状态,我们使用 statsviz 库实现一个实时监控页面。
安装依赖
bash复制
go get github.com/canthefason/go-sockjs
go get github.com/canthefason/go-statsviz
实现监控代码
在 main.go
中添加监控启动逻辑:
go复制
package main
import (
"log"
"net/http"
"os"
"runtime"
"time"
"github.com/canthefason/go-statsviz"
"your_project_path/common"
)
func main() {
common.LoadConfig("application.yml")
// 启动监控
go func() {
statsviz.Register("/debug/statsviz")
log.Println(http.ListenAndServe(fmt.Sprintf(":%d", common.Config.MetricsPort), nil))
}()
// 启动 GRPC 服务
startGRPCServer()
}
func startGRPCServer() {
// GRPC 服务启动逻辑
}
运行程序后,访问 http://localhost:8080/debug/statsviz
,即可看到实时监控页面。
第三步:启动 GRPC 服务
接下来,我们启动 GRPC 服务端。
安装 GRPC 依赖
bash复制
go get google.golang.org/grpc
go get google.golang.org/protobuf
实现 GRPC 服务启动逻辑
在 main.go
中添加 GRPC 服务启动代码:
go复制
package main
import (
"context"
"log"
"net"
"os"
"time"
"google.golang.org/grpc"
"your_project_path/common"
)
func startGRPCServer() {
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", common.Config.GRPCPort))
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
s := grpc.NewServer()
defer s.Stop()
go func() {
if err := s.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}()
// 模拟优雅启停
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, os.Kill)
<-signalChan
log.Println("Received signal, stopping server...")
time.Sleep(3 * time.Second) // 等待 3 秒,确保所有操作完成
}
优雅启停
为了实现优雅启停,我们监听系统信号(如 Ctrl+C
),并在收到信号时执行停止操作。
完整的 main.go
示例
go复制
package main
import (
"context"
"fmt"
"log"
"net"
"os"
"os/signal"
"time"
"google.golang.org/grpc"
"your_project_path/common"
)
func main() {
common.LoadConfig("application.yml")
// 启动监控
go func() {
statsviz.Register("/debug/statsviz")
log.Println(http.ListenAndServe(fmt.Sprintf(":%d", common.Config.MetricsPort), nil))
}()
// 启动 GRPC 服务
startGRPCServer()
}
func startGRPCServer() {
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", common.Config.GRPCPort))
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
s := grpc.NewServer()
defer s.Stop()
go func() {
if err := s.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}()
// 模拟优雅启停
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, os.Kill)
<-signalChan
log.Println("Received signal, stopping server...")
time.Sleep(3 * time.Second) // 等待 3 秒,确保所有操作完成
}
总结
通过以上步骤,我们完成了 User 服务 的基础开发:
-
加载配置文件。
-
启动监控服务。
-
启动 GRPC 服务,并实现优雅启停。
接下来,我们可以继续完善 User 服务 的业务逻辑,如微信登录、账号注册等。