提交 af9d7893 编写于 作者: 威武堂堂's avatar 威武堂堂

调整文件位置

上级 f9fdbd1c

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
......@@ -13,13 +13,6 @@
-------------------
-------------------
#### 创新:(摆烂,不使用服务器校验做弊)
- 在卡牌对战中创建对局的客户端注册到Register提供服务,减少服务器运算和通信
- 对局随机值,对局状态,对局中一端掉线重连,都不走服务器,仅对局结果由双方提供给服务器
-------------------
-------------------
#### 文件夹介绍:
-------------------
......@@ -51,6 +44,9 @@ init阶段 链接数据库成功后 会自动根据定义的类在数据库中
-------------------
conf 定义常量
chanrpc 提供了一套基于 channel 的 RPC 机制,用于游戏服务器模块间通讯
gate 网关模块,负责游戏客户端的接入
network 网络相关,使用 TCP 协议,可自定义消息格式,目前 Leaf 提供了基于 protobuf 和 JSON 的消息格式
-------------------
share/db 数据库增删改查
......@@ -59,6 +55,11 @@ share/log 自定义日志
share/util 常用方法封装
share/go 用于创建能够被 Leaf 管理的 goroutine
share/recordfile 配置表读取
share/timer 定时器
-------------------
......
......@@ -2,7 +2,7 @@ package chanrpc_test
import (
"fmt"
"leaf/share/chanrpc"
"leaf/chanrpc"
"sync"
)
......
......@@ -6,7 +6,7 @@ import (
"reflect"
"time"
"leaf/share/chanrpc"
"leaf/chanrpc"
"leaf/network"
)
......
......@@ -7,7 +7,7 @@ import (
"leaf/share/log"
"reflect"
"leaf/share/chanrpc"
"leaf/chanrpc"
)
type Processor struct {
......
......@@ -8,7 +8,7 @@ import (
"math"
"reflect"
"leaf/share/chanrpc"
"leaf/chanrpc"
"github.com/golang/protobuf/proto"
)
......
package timer
// reference: https://github.com/robfig/cron
import (
"fmt"
"math"
"strconv"
"strings"
"time"
)
// Field name | Mandatory? | Allowed values | Allowed special characters
// ---------- | ---------- | -------------- | --------------------------
// Seconds | No | 0-59 | * / , -
// Minutes | Yes | 0-59 | * / , -
// Hours | Yes | 0-23 | * / , -
// Day of month | Yes | 1-31 | * / , -
// Month | Yes | 1-12 | * / , -
// Day of week | Yes | 0-6 | * / , -
type CronExpr struct {
sec uint64
min uint64
hour uint64
dom uint64
month uint64
dow uint64
}
// goroutine safe
func NewCronExpr(expr string) (cronExpr *CronExpr, err error) {
fields := strings.Fields(expr)
if len(fields) != 5 && len(fields) != 6 {
err = fmt.Errorf("invalid expr %v: expected 5 or 6 fields, got %v", expr, len(fields))
return
}
if len(fields) == 5 {
fields = append([]string{"0"}, fields...)
}
cronExpr = new(CronExpr)
// Seconds
cronExpr.sec, err = parseCronField(fields[0], 0, 59)
if err != nil {
goto onError
}
// Minutes
cronExpr.min, err = parseCronField(fields[1], 0, 59)
if err != nil {
goto onError
}
// Hours
cronExpr.hour, err = parseCronField(fields[2], 0, 23)
if err != nil {
goto onError
}
// Day of month
cronExpr.dom, err = parseCronField(fields[3], 1, 31)
if err != nil {
goto onError
}
// Month
cronExpr.month, err = parseCronField(fields[4], 1, 12)
if err != nil {
goto onError
}
// Day of week
cronExpr.dow, err = parseCronField(fields[5], 0, 6)
if err != nil {
goto onError
}
return
onError:
err = fmt.Errorf("invalid expr %v: %v", expr, err)
return
}
// 1. *
// 2. num
// 3. num-num
// 4. */num
// 5. num/num (means num-max/num)
// 6. num-num/num
func parseCronField(field string, min int, max int) (cronField uint64, err error) {
fields := strings.Split(field, ",")
for _, field := range fields {
rangeAndIncr := strings.Split(field, "/")
if len(rangeAndIncr) > 2 {
err = fmt.Errorf("too many slashes: %v", field)
return
}
// range
startAndEnd := strings.Split(rangeAndIncr[0], "-")
if len(startAndEnd) > 2 {
err = fmt.Errorf("too many hyphens: %v", rangeAndIncr[0])
return
}
var start, end int
if startAndEnd[0] == "*" {
if len(startAndEnd) != 1 {
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
return
}
start = min
end = max
} else {
// start
start, err = strconv.Atoi(startAndEnd[0])
if err != nil {
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
return
}
// end
if len(startAndEnd) == 1 {
if len(rangeAndIncr) == 2 {
end = max
} else {
end = start
}
} else {
end, err = strconv.Atoi(startAndEnd[1])
if err != nil {
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
return
}
}
}
if start > end {
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
return
}
if start < min {
err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0])
return
}
if end > max {
err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0])
return
}
// increment
var incr int
if len(rangeAndIncr) == 1 {
incr = 1
} else {
incr, err = strconv.Atoi(rangeAndIncr[1])
if err != nil {
err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1])
return
}
if incr <= 0 {
err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1])
return
}
}
// cronField
if incr == 1 {
cronField |= ^(math.MaxUint64 << uint(end+1)) & (math.MaxUint64 << uint(start))
} else {
for i := start; i <= end; i += incr {
cronField |= 1 << uint(i)
}
}
}
return
}
func (e *CronExpr) matchDay(t time.Time) bool {
// day-of-month blank
if e.dom == 0xfffffffe {
return 1<<uint(t.Weekday())&e.dow != 0
}
// day-of-week blank
if e.dow == 0x7f {
return 1<<uint(t.Day())&e.dom != 0
}
return 1<<uint(t.Weekday())&e.dow != 0 ||
1<<uint(t.Day())&e.dom != 0
}
// goroutine safe
func (e *CronExpr) Next(t time.Time) time.Time {
// the upcoming second
t = t.Truncate(time.Second).Add(time.Second)
year := t.Year()
initFlag := false
retry:
// Year
if t.Year() > year+1 {
return time.Time{}
}
// Month
for 1<<uint(t.Month())&e.month == 0 {
if !initFlag {
initFlag = true
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
}
t = t.AddDate(0, 1, 0)
if t.Month() == time.January {
goto retry
}
}
// Day
for !e.matchDay(t) {
if !initFlag {
initFlag = true
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
t = t.AddDate(0, 0, 1)
if t.Day() == 1 {
goto retry
}
}
// Hours
for 1<<uint(t.Hour())&e.hour == 0 {
if !initFlag {
initFlag = true
t = t.Truncate(time.Hour)
}
t = t.Add(time.Hour)
if t.Hour() == 0 {
goto retry
}
}
// Minutes
for 1<<uint(t.Minute())&e.min == 0 {
if !initFlag {
initFlag = true
t = t.Truncate(time.Minute)
}
t = t.Add(time.Minute)
if t.Minute() == 0 {
goto retry
}
}
// Seconds
for 1<<uint(t.Second())&e.sec == 0 {
if !initFlag {
initFlag = true
}
t = t.Add(time.Second)
if t.Second() == 0 {
goto retry
}
}
return t
}
package timer_test
import (
"fmt"
"leaf/share/timer"
"time"
)
func ExampleTimer() {
d := timer.NewDispatcher(10)
// timer 1
d.AfterFunc(1, func() {
fmt.Println("My name is Leaf")
})
// timer 2
t := d.AfterFunc(1, func() {
fmt.Println("will not print")
})
t.Stop()
// dispatch
(<-d.ChanTimer).Cb()
// Output:
// My name is Leaf
}
func ExampleCronExpr() {
cronExpr, err := timer.NewCronExpr("0 * * * *")
if err != nil {
return
}
fmt.Println(cronExpr.Next(time.Date(
2000, 1, 1,
20, 10, 5,
0, time.UTC,
)))
// Output:
// 2000-01-01 21:00:00 +0000 UTC
}
func ExampleCron() {
d := timer.NewDispatcher(10)
// cron expr
cronExpr, err := timer.NewCronExpr("* * * * * *")
if err != nil {
return
}
// cron
var c *timer.Cron
c = d.CronFunc(cronExpr, func() {
fmt.Println("My name is Leaf")
c.Stop()
})
// dispatch
(<-d.ChanTimer).Cb()
// Output:
// My name is Leaf
}
package timer
import (
"leaf/conf"
"leaf/share/log"
"runtime"
"time"
)
// one dispatcher per goroutine (goroutine not safe)
type Dispatcher struct {
ChanTimer chan *Timer
}
func NewDispatcher(l int) *Dispatcher {
disp := new(Dispatcher)
disp.ChanTimer = make(chan *Timer, l)
return disp
}
// Timer
type Timer struct {
t *time.Timer
cb func()
}
func (t *Timer) Stop() {
t.t.Stop()
t.cb = nil
}
func (t *Timer) Cb() {
defer func() {
t.cb = nil
if r := recover(); r != nil {
if conf.LenStackBuf > 0 {
buf := make([]byte, conf.LenStackBuf)
l := runtime.Stack(buf, false)
log.Error("%v: %s", r, buf[:l])
} else {
log.Error("%v", r)
}
}
}()
if t.cb != nil {
t.cb()
}
}
func (disp *Dispatcher) AfterFunc(d time.Duration, cb func()) *Timer {
t := new(Timer)
t.cb = cb
t.t = time.AfterFunc(d, func() {
disp.ChanTimer <- t
})
return t
}
// Cron
type Cron struct {
t *Timer
}
func (c *Cron) Stop() {
if c.t != nil {
c.t.Stop()
}
}
func (disp *Dispatcher) CronFunc(cronExpr *CronExpr, _cb func()) *Cron {
c := new(Cron)
now := time.Now()
nextTime := cronExpr.Next(now)
if nextTime.IsZero() {
return c
}
// callback
var cb func()
cb = func() {
defer _cb()
now := time.Now()
nextTime := cronExpr.Next(now)
if nextTime.IsZero() {
return
}
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
}
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
return c
}
#### 采用go-leaf开发的卡牌游戏服务器
-------------------
#### 技术方案:
- 服务器框架:go-leaf
- 服务器环境:windows
- 缓 存:redis
- 数据库:mysql
<!-- 容器 docker 只有一个服务器 暂缓-->
<!-- 负载均衡 只有一个服务器 暂缓 -->
<!-- 加密 kit 没有付费内容 暂缓-->
-------------------
-------------------
#### 创新:(摆烂,不使用服务器校验做弊)
- 在卡牌对战中创建对局的客户端注册到Register提供服务,减少服务器运算和通信
- 对局随机值,对局状态,对局中一端掉线重连,都不走服务器,仅对局结果由双方提供给服务器
-------------------
-------------------
#### 模块介绍:
用户模块
玩家未注册时 支持自动建号 分配Uid 本地uid+pass自动登录
注册后 mail+pass登录 支持邮箱验证修改密码
-------------------
-------------------
#### 文件夹介绍:
-------------------
proto 存放协议文件
bat描述:一键删除当前文件夹.go,读取.proto重新生成对应协议
bat使用前置条件 导入protoc-gen-micro(在pkg.go.dev找,有很多版本,挑一个)
go get 找到的网址 cd 下载目录 go.build
将生成的protoc-gen-micro.exe路径加入path
go mod tidy 自动导入依赖文件
-------------------
myclass 存放数据表结构
新建一个类的同时 需要在 InitTables 方法中 db.CreateClassTable(&类名{})
init阶段 链接数据库成功后 会自动根据定义的类在数据库中建表
已存在的类 添加新的属性会自动更新到表,但是删除不会(也不建议删除)
-------------------
share/config 定义常量
share/db 数据库增删改查
share/log 分卷日志 支持不同警报等级输出不同字体颜色的日志
share/Tools 常用方法封装
-------------------
\ No newline at end of file
module MyServer
go 1.19
require (
github.com/golang/protobuf v1.5.2
github.com/micro/micro/v3 v3.15.0
go.uber.org/zap v1.24.0
google.golang.org/protobuf v1.28.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch/v5 v5.5.0 // indirect
github.com/go-acme/lego/v3 v3.4.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/name5566/leafserver v0.0.0-20170223062139-6d4f51f87b82 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
golang.org/x/net v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
gorm.io/driver/mysql v1.4.4
gorm.io/gorm v1.24.2
)
此差异已折叠。
package main
import (
"MyServer/myclass"
"MyServer/share/db"
"MyServer/share/log"
// _ "github.com/micro/go-micro/v2"
)
func init() {
err := db.InitDb()
if err == nil {
myclass.InitTables()
}
log.NewLogger("R0-1")
}
func main() {
}
package myclass
import (
"MyServer/share/db"
"gorm.io/gorm"
)
// 自动创建类型对应的表
func InitTables() {
db.CreateClassTable(&Users{})
}
// 用户类
// 支持自动建号 分配Uid
// 玩家未注册时仅可使用本地保存的uid+pass自动登录
// 注册后mail+pass登录
type Users struct {
gorm.Model
Mail string
Password string
Name string
HeadImg string
}
del *.go
protoc --proto_path=. --micro_out=. --go_out=. ./*.proto
pause
\ No newline at end of file
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: UserService.proto
package proto
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/micro/v3/service/api"
client "github.com/micro/micro/v3/service/client"
server "github.com/micro/micro/v3/service/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for UserService service
func NewUserServiceEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for UserService service
type UserService interface {
// 注册临时用户
NewAccount(ctx context.Context, in *NewAccountReq, opts ...client.CallOption) (*NewAccountRsp, error)
// 绑定用户
RegistAccount(ctx context.Context, in *RegistAccountReq, opts ...client.CallOption) (*RegistAccountRsp, error)
// 用户登录
LoginAccount(ctx context.Context, in *LoginAccountReq, opts ...client.CallOption) (*LoginAccountRsp, error)
// 密码重置
ResetAccount(ctx context.Context, in *ResetAccountReq, opts ...client.CallOption) (*ResetAccountRsp, error)
// 修改用户信息
UpdateUserProfile(ctx context.Context, in *UpdateUserProfileReq, opts ...client.CallOption) (*UpdateUserProfileRsp, error)
}
type userService struct {
c client.Client
name string
}
func NewUserService(name string, c client.Client) UserService {
return &userService{
c: c,
name: name,
}
}
func (c *userService) NewAccount(ctx context.Context, in *NewAccountReq, opts ...client.CallOption) (*NewAccountRsp, error) {
req := c.c.NewRequest(c.name, "UserService.NewAccount", in)
out := new(NewAccountRsp)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userService) RegistAccount(ctx context.Context, in *RegistAccountReq, opts ...client.CallOption) (*RegistAccountRsp, error) {
req := c.c.NewRequest(c.name, "UserService.RegistAccount", in)
out := new(RegistAccountRsp)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userService) LoginAccount(ctx context.Context, in *LoginAccountReq, opts ...client.CallOption) (*LoginAccountRsp, error) {
req := c.c.NewRequest(c.name, "UserService.LoginAccount", in)
out := new(LoginAccountRsp)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userService) ResetAccount(ctx context.Context, in *ResetAccountReq, opts ...client.CallOption) (*ResetAccountRsp, error) {
req := c.c.NewRequest(c.name, "UserService.ResetAccount", in)
out := new(ResetAccountRsp)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userService) UpdateUserProfile(ctx context.Context, in *UpdateUserProfileReq, opts ...client.CallOption) (*UpdateUserProfileRsp, error) {
req := c.c.NewRequest(c.name, "UserService.UpdateUserProfile", in)
out := new(UpdateUserProfileRsp)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for UserService service
type UserServiceHandler interface {
// 注册临时用户
NewAccount(context.Context, *NewAccountReq, *NewAccountRsp) error
// 绑定用户
RegistAccount(context.Context, *RegistAccountReq, *RegistAccountRsp) error
// 用户登录
LoginAccount(context.Context, *LoginAccountReq, *LoginAccountRsp) error
// 密码重置
ResetAccount(context.Context, *ResetAccountReq, *ResetAccountRsp) error
// 修改用户信息
UpdateUserProfile(context.Context, *UpdateUserProfileReq, *UpdateUserProfileRsp) error
}
func RegisterUserServiceHandler(s server.Server, hdlr UserServiceHandler, opts ...server.HandlerOption) error {
type userService interface {
NewAccount(ctx context.Context, in *NewAccountReq, out *NewAccountRsp) error
RegistAccount(ctx context.Context, in *RegistAccountReq, out *RegistAccountRsp) error
LoginAccount(ctx context.Context, in *LoginAccountReq, out *LoginAccountRsp) error
ResetAccount(ctx context.Context, in *ResetAccountReq, out *ResetAccountRsp) error
UpdateUserProfile(ctx context.Context, in *UpdateUserProfileReq, out *UpdateUserProfileRsp) error
}
type UserService struct {
userService
}
h := &userServiceHandler{hdlr}
return s.Handle(s.NewHandler(&UserService{h}, opts...))
}
type userServiceHandler struct {
UserServiceHandler
}
func (h *userServiceHandler) NewAccount(ctx context.Context, in *NewAccountReq, out *NewAccountRsp) error {
return h.UserServiceHandler.NewAccount(ctx, in, out)
}
func (h *userServiceHandler) RegistAccount(ctx context.Context, in *RegistAccountReq, out *RegistAccountRsp) error {
return h.UserServiceHandler.RegistAccount(ctx, in, out)
}
func (h *userServiceHandler) LoginAccount(ctx context.Context, in *LoginAccountReq, out *LoginAccountRsp) error {
return h.UserServiceHandler.LoginAccount(ctx, in, out)
}
func (h *userServiceHandler) ResetAccount(ctx context.Context, in *ResetAccountReq, out *ResetAccountRsp) error {
return h.UserServiceHandler.ResetAccount(ctx, in, out)
}
func (h *userServiceHandler) UpdateUserProfile(ctx context.Context, in *UpdateUserProfileReq, out *UpdateUserProfileRsp) error {
return h.UserServiceHandler.UpdateUserProfile(ctx, in, out)
}
syntax = "proto3";
option go_package ="./;proto";
service UserService {
// 注册临时用户
rpc NewAccount(NewAccountReq) returns(NewAccountRsp) {}
// 绑定用户
rpc RegistAccount(RegistAccountReq) returns(RegistAccountRsp) {}
// 用户登录
rpc LoginAccount(LoginAccountReq) returns(LoginAccountRsp) {}
// 密码重置
rpc ResetAccount(ResetAccountReq) returns(ResetAccountRsp) {}
// 修改用户信息
rpc UpdateUserProfile(UpdateUserProfileReq) returns (UpdateUserProfileRsp) {}
}
message NewAccountReq {
}
message NewAccountRsp {
int64 err = 1 ;
int64 userID = 2 ;
string password = 3 ;
}
message RegistAccountReq {
int64 userID = 1 ;
string email = 2 ;
string password = 3 ;
string oldpassword = 4 ;
}
message RegistAccountRsp {
int64 err = 1 ;
}
message LoginAccountReq {
string email = 1 ;
string password = 2 ;
}
message LoginAccountRsp {
int64 err = 1 ;
}
message ResetAccountReq {
}
message ResetAccountRsp {
int64 err = 1 ;
}
message UpdateUserProfileReq {
}
message UpdateUserProfileRsp {
int64 err = 1 ;
}
\ No newline at end of file
// UserRegister
package server
import (
"MyServer/myclass"
s_user "MyServer/proto"
"MyServer/share/db"
"context"
)
// 用户自动注册具体实现
type NewAccount struct {
}
func (*NewAccount) NewAccount(ctx context.Context, req *s_user.NewAccountReq, res *s_user.NewAccountRsp) error {
db.InsertData(&myclass.Users{})
return nil
}
// 账户绑定具体实现
type RegistAccount struct {
}
func (*RegistAccount) RegistAccount(ctx context.Context, req *s_user.RegistAccountReq, res *s_user.RegistAccountRsp) error {
if req.Oldpassword != "16358" {
res.Err = 1
}
return nil
}
package tools
import (
"math/rand"
"time"
)
// 获取随机字符串
func GetRandomString(leng int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < leng; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}
// 月份字符串返回数值
func SwitchMonth(month string) int64 {
var mon int64
switch month {
case "January":
mon = 1
case "February":
mon = 2
case "March":
mon = 3
case "April":
mon = 4
case "May":
mon = 5
case "June":
mon = 6
case "July":
mon = 7
case "August":
mon = 8
case "September":
mon = 9
case "October":
mon = 10
case "November":
mon = 11
case "December":
mon = 12
default:
mon = 0
}
return mon
}
/*
常量
*/
package config
// 服务器相关常量
const (
//本地测试
MysqlDSN = "root:1638241511@(localhost:3306)/localtest"
//服务器
// MysqlDSN = "root:1638241511@tcp(172.31.109.174:3306)/localtest"
ServiceNameUser = "user"
ServiceNameFilm = "film"
ServiceNameComment = "comment"
ServiceNameCinema = "cinema"
ServiceNameOrder = "order"
ServiceNameCMS = "cms"
)
// 日志相关常量
const (
LogPath = "/data/log/"
LogMaxSize = 10 // log文件大小 单位: MB
LogMaxBackups = 30 //log保留数量
LogMaxAge = 28 //log保留时间
LogCompress = true // 确定是否应使用 gzip 压缩旋转的日志文件
)
// 日志相关常量
const (
Account = 10 //账号长度
)
/*
数据库
*/
package db
import (
"MyServer/share/config"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 数据库实例
var db *gorm.DB
// 打开并连接数据库
func InitDb() (err error) {
d, err := gorm.Open(mysql.Open(config.MysqlDSN), &gorm.Config{})
if err != nil {
fmt.Println("数据库链接失败:", err)
} else {
fmt.Println("数据库链接成功")
db = d
}
return err
}
// 传入结构体指针,建立对应类的数据表
func CreateClassTable(T any) {
err := db.AutoMigrate(T)
if err != nil {
fmt.Println("数据表创建失败:", err)
}
}
// 对应类的数据表插入数据
func InsertData(T any) {
tx := db.Create(T)
fmt.Println(".", tx)
}
// 对应类的数据表更新数据
func UpData(T any) {
db.Create(T)
}
package log
import (
"bytes"
"log"
"os"
"path"
"time"
"MyServer/share/config"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
var Logger *zap.Logger
// NewLogger 新建日志
func NewLogger(srvName string) {
directory := path.Join(config.LogPath, srvName)
writers := []zapcore.WriteSyncer{newRollingFile(directory)}
writers = append(writers, os.Stdout)
logger, dyn := newZapLogger(true, zapcore.NewMultiWriteSyncer(writers...))
zap.RedirectStdLog(logger)
go func() {
ticker := time.NewTicker(30 * time.Second)
for range ticker.C {
updateLogLevel(srvName, dyn, false)
}
}()
Logger = logger
}
func updateLogLevel(serviceName string, dyn *zap.AtomicLevel, isProduction bool) {
originLevelString := "info"
if !isProduction {
originLevelString = "debug"
}
levelConf := make(map[string]map[string]string)
newLevelString, ok := levelConf[serviceName]["127.0.0.1"]
if !ok {
newLevelString, ok = levelConf[serviceName]["*"]
if !ok {
newLevelString = originLevelString
}
}
if !ok {
newLevelString, ok = levelConf[serviceName]["*"]
if !ok {
newLevelString = originLevelString
}
}
newLevel := new(zapcore.Level)
if err := newLevel.Set(newLevelString); err != nil {
newLevel.Set(originLevelString)
}
if dyn.Level() != *newLevel {
log.Println("修改日志等级: ", dyn.Level().String(), "=>", newLevel.String())
dyn.SetLevel(*newLevel)
}
}
func newRollingFile(directory string) zapcore.WriteSyncer {
if err := os.MkdirAll(directory, 0766); err != nil {
log.Println("failed create log directory:", directory, ":", err)
return nil
}
return newLumberjackWriteSyncer(&lumberjack.Logger{
Filename: path.Join(directory, "output.log"),
MaxSize: 100, //megabytes
MaxAge: 7, //days
LocalTime: true,
Compress: false,
})
}
func newZapLogger(isProduction bool, output zapcore.WriteSyncer) (*zap.Logger, *zap.AtomicLevel) {
encCfg := zapcore.EncoderConfig{
TimeKey: "@timestamp",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
EncodeCaller: zapcore.ShortCallerEncoder,
EncodeDuration: zapcore.NanosDurationEncoder,
EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
},
}
var encoder zapcore.Encoder
dyn := zap.NewAtomicLevel()
if isProduction {
dyn.SetLevel(zap.InfoLevel)
encCfg.EncodeLevel = zapcore.LowercaseLevelEncoder
encoder = zapcore.NewConsoleEncoder(encCfg) // zapcore.NewJSONEncoder(encCfg)
} else {
dyn.SetLevel(zap.DebugLevel)
encCfg.EncodeLevel = zapcore.LowercaseColorLevelEncoder
encoder = zapcore.NewConsoleEncoder(encCfg)
}
return zap.New(zapcore.NewCore(encoder, output, dyn), zap.AddCaller()), &dyn
}
type lumberjackWriteSyncer struct {
*lumberjack.Logger
buf *bytes.Buffer
logChan chan []byte
closeChan chan interface{}
maxSize int
}
func newLumberjackWriteSyncer(l *lumberjack.Logger) *lumberjackWriteSyncer {
ws := &lumberjackWriteSyncer{
Logger: l,
buf: bytes.NewBuffer([]byte{}),
logChan: make(chan []byte, 5000),
closeChan: make(chan interface{}),
maxSize: 1024,
}
go ws.run()
return ws
}
func (l *lumberjackWriteSyncer) run() {
ticker := time.NewTicker(1 * time.Second)
for {
select {
case <-ticker.C:
if l.buf.Len() > 0 {
l.sync()
}
case bs := <-l.logChan:
_, err := l.buf.Write(bs)
if err != nil {
continue
}
if l.buf.Len() > l.maxSize {
l.sync()
}
case <-l.closeChan:
l.sync()
return
}
}
}
func (l *lumberjackWriteSyncer) Stop() {
close(l.closeChan)
}
func (l *lumberjackWriteSyncer) Write(bs []byte) (int, error) {
l.logChan <- bs
return 0, nil
}
func (l *lumberjackWriteSyncer) Sync() error {
return nil
}
func (l *lumberjackWriteSyncer) sync() error {
defer l.buf.Reset()
_, err := l.Logger.Write(l.buf.Bytes())
if err != nil {
return err
}
return nil
}
......@@ -9,7 +9,7 @@
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace></RootNamespace>
<ProjectGuid>{7E9390F1-73E5-730B-1B1D-5BE0F1A2D35B}</ProjectGuid>
<ProjectGuid>{D4CDA42C-9EDD-50EE-2002-C9787CA64E21}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AssemblyName>Assembly-CSharp-Editor</AssemblyName>
......@@ -857,11 +857,11 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="Assembly-CSharp-firstpass.csproj">
<Project>{AD57B843-5EDE-E353-A85B-063FB656F030}</Project>
<Project>{E8A752BE-9A90-3ABD-EFEA-0F0B752BA404}</Project>
<Name>Assembly-CSharp-firstpass</Name>
</ProjectReference>
<ProjectReference Include="Assembly-CSharp.csproj">
<Project>{75046635-29AB-71DB-C83B-4D4AAAF373F6}</Project>
<Project>{86489004-9A83-E913-A03D-5C927FDE3DFE}</Project>
<Name>Assembly-CSharp</Name>
</ProjectReference>
</ItemGroup>
......
......@@ -9,7 +9,7 @@
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace></RootNamespace>
<ProjectGuid>{AD57B843-5EDE-E353-A85B-063FB656F030}</ProjectGuid>
<ProjectGuid>{E8A752BE-9A90-3ABD-EFEA-0F0B752BA404}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AssemblyName>Assembly-CSharp-firstpass</AssemblyName>
......@@ -63,6 +63,7 @@
<Compile Include="Assets\Plugins\DOTween\Modules\DOTweenModuleUtils.cs" />
<Compile Include="Assets\Plugins\DOTween\Modules\DOTweenModulePhysics2D.cs" />
<Compile Include="Assets\Plugins\DOTween\Modules\DOTweenModuleUI.cs" />
<Compile Include="Assets\Plugins\Sproto\protocol\gen_cs\gamesproto.cs" />
<Compile Include="Assets\Plugins\DOTween\Modules\DOTweenModuleEPOOutline.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -9,7 +9,7 @@
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace></RootNamespace>
<ProjectGuid>{75046635-29AB-71DB-C83B-4D4AAAF373F6}</ProjectGuid>
<ProjectGuid>{86489004-9A83-E913-A03D-5C927FDE3DFE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AssemblyName>Assembly-CSharp</AssemblyName>
......@@ -258,6 +258,7 @@
<Compile Include="Assets\LuaFramework\ToLua\Source\Generate\PanelMgrWrap.cs" />
<Compile Include="Assets\Scripts\3rd\LitJson\Netstandard15Polyfill.cs" />
<Compile Include="Assets\LuaFramework\ToLua\Core\LuaState.cs" />
<Compile Include="Assets\Scripts\DontDestoryObject.cs" />
<Compile Include="Assets\LuaFramework\ToLua\BaseType\UnityEngine_ShaderWrap.cs" />
<Compile Include="Assets\Scripts\Framework\UGUIExpand\I18NText\I18NText.cs" />
<Compile Include="Assets\LuaFramework\ToLua\Source\Generate\UnityEngine_PhysicsWrap.cs" />
......@@ -317,7 +318,6 @@
<Compile Include="Assets\Scripts\Logic\HotUpdate\HotUpdater.cs" />
<Compile Include="Assets\LuaFramework\ToLua\BaseType\UnityEngine_LightWrap.cs" />
<Compile Include="Assets\LuaFramework\ToLua\Reflection\LuaField.cs" />
<Compile Include="Assets\Scripts\DontDestoryObject.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Assets\RawAssets\GuideMask\Shader\GuideMask.shader" />
......@@ -1030,7 +1030,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="Assembly-CSharp-firstpass.csproj">
<Project>{AD57B843-5EDE-E353-A85B-063FB656F030}</Project>
<Project>{E8A752BE-9A90-3ABD-EFEA-0F0B752BA404}</Project>
<Name>Assembly-CSharp-firstpass</Name>
</ProjectReference>
</ItemGroup>
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册