Commit 11abbdeab9a30e15143603f3d17b656e8d2b578b

Authored by zhangqijia
1 parent 1b1ad555

csv 读取加载

.gitignore
... ... @@ -2,5 +2,7 @@
2 2 vendor
3 3 bin
4 4 protos
  5 +csvdata
  6 +*.csv
5 7  
6 8 *.log
7 9 \ No newline at end of file
... ...
Makefile
... ... @@ -13,8 +13,9 @@ account:
13 13 game:
14 14 go run cmd/game.go
15 15 build:
16   - go build -o bin/account account.go
17   - go build -o bin/game game.go
  16 + go build -o bin/account cmd/account.go
  17 + go build -o bin/game cmd/game.go
  18 + go build -o bin/test test/client.go
18 19  
19 20 cert:
20 21 openssl req \
... ...
README.md
... ... @@ -29,9 +29,10 @@ $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
29 29  
30 30  
31 31 ## Usage
32   -编译 & 运行
  32 +编译 & 运行 游戏服 & 登录服务
33 33 ```shell
34   -$ make run
  34 +$ make account
  35 +$ make game
35 36 ```
36 37 测试
37 38 ```shell
... ...
actions/accountaction.go renamed to actions/AccountAction.go
actions/roleaction.go renamed to actions/RoleAction.go
... ... @@ -3,6 +3,7 @@ module pro2d
3 3 go 1.17
4 4  
5 5 require (
  6 + github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
6 7 github.com/dgrijalva/jwt-go v3.2.0+incompatible
7 8 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
8 9 go.etcd.io/etcd/api/v3 v3.5.2
... ...
... ... @@ -8,6 +8,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
8 8 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
9 9 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
10 10 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
  11 +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
  12 +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
11 13 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
12 14 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
13 15 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
... ...
1   -Subproject commit cee7537250bcee3ddd04e03d2d142d6d1ac6417e
  1 +Subproject commit f39667f517b4d302674707983210d7ac53460c6b
... ...
tools/csvtostruct.go 0 → 100644
... ... @@ -0,0 +1,350 @@
  1 +package main
  2 +
  3 +import (
  4 + "encoding/csv"
  5 + "fmt"
  6 + "github.com/axgle/mahonia"
  7 + "io"
  8 + "io/ioutil"
  9 + "log"
  10 + "os"
  11 + "path"
  12 + "pro2d/csvdata"
  13 + "reflect"
  14 + "strconv"
  15 + "strings"
  16 + "unicode"
  17 +)
  18 +
  19 +/**
  20 + * 将excel中的前四列转化为struct
  21 + * 第一列字段类型 如 int
  22 + * 第二列字段名称 如 显示顺序
  23 + * 第三列字段名 如 id
  24 + * 第四列s,c,all s表示服务端使用 c表示客户端使用 all表示都使用
  25 + */
  26 +
  27 +var (
  28 + lineNumber = 4 // 每个工作表至少需要读取的行数
  29 + structBegin = "type %s struct {\n" // 结构体开始
  30 + structValue = " %s %s `json:\"%s\" client:\"%s\"`" // 结构体的内容
  31 + structValueForServer = " %s %s `json:\"%s\"`" // 服务端使用的结构体内容
  32 + structRemarks = " // %s" // 结构体备注
  33 + structValueEnd = "\n" // 结构体内容结束
  34 + structEnd = "}\n" // 结构体结束
  35 + header = "package %s\n\r" // 文件头
  36 +
  37 + initpkg ="package csvdata\n\nimport \"sync\"\n\nvar CsvStruct map[string]interface{}\nvar CsvData *sync.Map\n\nfunc init() {\n\tCsvStruct = make(map[string]interface{})\n\tCsvData = new(sync.Map)\n\n\t%s\n}\n\nfunc GetCsv(key string) interface{}{\n\tif data, ok := CsvData.Load(key); ok {\n\t\treturn data\n\t}\n\treturn nil\n}\nfunc SetCsv(key, value interface{}) {\n\tCsvData.Store(key, value)\n}"
  38 + initline = "CsvStruct[\"%s\"] = %s{}\n"
  39 +)
  40 +
  41 +type Generate struct {
  42 + savePath string // 生成文件的保存路径
  43 + data string // 生成文件的内容
  44 + allType string // 文件当中的数据类型
  45 +}
  46 +
  47 +func NewGenerate(savePath, allType string) *Generate {
  48 + return &Generate{
  49 + savePath: savePath,
  50 + allType: allType,
  51 + }
  52 +}
  53 +
  54 +// GBK 转 UTF-8
  55 +func GbkToUtf8(s string) string {
  56 + decoder := mahonia.NewDecoder("GBK")
  57 + return decoder.ConvertString(s)
  58 +}
  59 +
  60 +// UTF-8 转 GBK
  61 +func Utf8ToGbk(s string) string {
  62 + decoder := mahonia.NewDecoder("UTF-8")
  63 + return decoder.ConvertString(s)
  64 +}
  65 +
  66 +func GetGoTByCustomerT(t string) string {
  67 + switch t {
  68 + case "IntSlice":
  69 + return "[]int"
  70 + case "StringSlice":
  71 + return "[]string"
  72 + case "FloatSlice":
  73 + return "[]float32"
  74 + default:
  75 + return t
  76 + }
  77 +}
  78 +
  79 +func CustomerTypeToGo(allType string) map[string]bool {
  80 + s := strings.Split(allType, ",")
  81 + mt := make(map[string]bool)
  82 + for _, t := range s {
  83 + mt[GetGoTByCustomerT(t)] = true
  84 + }
  85 + return mt
  86 +}
  87 +
  88 +//csv to struct
  89 +func (g *Generate) CsvToStruct(csvpath, filename string) error {
  90 + csvfile, err := os.Open(csvpath+filename)
  91 + if err != nil {
  92 + return fmt.Errorf("ReadExcel|xlsx.OpenFile is err :%v", err)
  93 + }
  94 + defer csvfile.Close()
  95 +
  96 + r := csv.NewReader(csvfile)
  97 + i := 0
  98 + sheetData := make([][]string, 0)
  99 + for {
  100 + if i >= lineNumber {
  101 + break
  102 + }
  103 + record, err := r.Read()
  104 + if err == io.EOF {
  105 + break
  106 + }
  107 + if err != nil {
  108 + log.Fatal(err)
  109 + }
  110 + i++
  111 + sheetData = append(sheetData, record)
  112 + }
  113 + name := strings.Replace(filename, ".csv", "", -1)
  114 + data, err := g.SplicingData(sheetData, name)
  115 + if err != nil {
  116 + return fmt.Errorf("fileName:\"%v\" is err:%v", name, err)
  117 + }
  118 +
  119 + if data == "" {
  120 + return fmt.Errorf("ReadExcel|this.data is nil")
  121 + }
  122 + err = g.WriteNewFile(name, data)
  123 + if err != nil {
  124 + return err
  125 + }
  126 +
  127 + return nil
  128 +}
  129 +
  130 +//csv to mem
  131 +func (g *Generate)CsvToMem(csvpath, filename string) error {
  132 + csvfile, err := os.Open(csvpath+filename)
  133 + if err != nil {
  134 + return fmt.Errorf("ReadExcel|xlsx.OpenFile is err :%v", err)
  135 + }
  136 + defer csvfile.Close()
  137 +
  138 + r := csv.NewReader(csvfile)
  139 + i := 0
  140 + sheetData := make([][]string, 0)
  141 + name := strings.Replace(filename, ".csv", "", -1)
  142 + for {
  143 + record, err := r.Read()
  144 + if err == io.EOF {
  145 + break
  146 + }
  147 + if err != nil {
  148 + log.Fatal(err)
  149 + }
  150 +
  151 + if i < lineNumber {
  152 + sheetData = append(sheetData, record)
  153 + }else {
  154 + //4行之后
  155 + fields := sheetData[1]
  156 + typs := sheetData[2] //int, string
  157 + //keys := sheetData[3] //all, s, c
  158 +
  159 + t := reflect.ValueOf(csvdata.CsvStruct[name]).Type()
  160 + v := reflect.New(t).Elem()
  161 + for idx, field := range fields {
  162 + if field == "" || record[idx] == "" {
  163 + continue
  164 + }
  165 +
  166 + f := v.FieldByName(firstRuneToUpper(field))
  167 + switch typs[idx] {
  168 + case "int":
  169 + id, err := strconv.Atoi(record[idx])
  170 + if err != nil {
  171 + return err
  172 + }
  173 + f.SetInt(int64(id))
  174 + case "string":
  175 + f.SetString(record[idx])
  176 + }
  177 +
  178 + //fmt.Printf("%d, %s: %v, %v\n", idx, firstRuneToUpper(field), v.Field(idx), v.Interface())
  179 + csvdata.SetCsv(name, v.Interface())
  180 + }
  181 + }
  182 + i++
  183 + }
  184 + return nil
  185 +}
  186 +
  187 +//拼装struct
  188 +func (g *Generate) SplicingData(data [][]string, structName string) (string, error) {
  189 + if len(data) != lineNumber {
  190 + return "", fmt.Errorf("SplicingData|sheetName:%v col's len:%d is err", data, len(data))
  191 + }
  192 + marks := data[0]
  193 + fields := data[1]
  194 + typs := data[2]
  195 + keys := data[3]
  196 + structData := fmt.Sprintf(structBegin, firstRuneToUpper(structName))
  197 +
  198 + for i, field := range fields {
  199 + err := g.CheckType(typs[i], structName)
  200 + if err != nil {
  201 + return "", err
  202 + }
  203 + switch keys[i] {
  204 + case "key","all":
  205 + structData += fmt.Sprintf(structValue, firstRuneToUpper(field), GetGoTByCustomerT(typs[i]), strings.ToLower(field), strings.ToLower(field))
  206 + if field != "" {
  207 + structData += fmt.Sprintf(structRemarks, GbkToUtf8(marks[i]))
  208 + }
  209 + structData += fmt.Sprintf(structValueEnd)
  210 + case "s":
  211 + structData += fmt.Sprintf(structValueForServer, firstRuneToUpper(field), GetGoTByCustomerT(typs[i]), strings.ToLower(field))
  212 + if field != "" {
  213 + structData += fmt.Sprintf(structRemarks,GbkToUtf8(marks[i]))
  214 + }
  215 + structData += fmt.Sprintf(structValueEnd)
  216 + case "c":
  217 + continue
  218 + default:
  219 + return "", fmt.Errorf("SplicingData|keys[%d]:\"%v\" is not in s,c,all", i, keys[i])
  220 + }
  221 + }
  222 + structData += structEnd
  223 + return structData, nil
  224 +}
  225 +
  226 +// 拼装好的struct写入新的文件
  227 +func (g *Generate) WriteNewFile(filename, data string) error {
  228 + str := strings.Split(g.savePath, "/")
  229 + if len(str) == 0 {
  230 + return fmt.Errorf("WriteNewFile|len(str) is 0")
  231 + }
  232 +
  233 + header = fmt.Sprintf(header, str[len(str)-1])
  234 + data = header + data
  235 +
  236 + fw, err := os.OpenFile(g.savePath +"/" +filename+".go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  237 + if err != nil {
  238 + return fmt.Errorf("WriteNewFile|OpenFile is err:%v", err)
  239 + }
  240 + defer fw.Close()
  241 +
  242 + _, err = fw.Write([]byte(data))
  243 + if err != nil {
  244 + return fmt.Errorf("WriteNewFile|Write is err:%v", err)
  245 + }
  246 +
  247 + return nil
  248 +}
  249 +
  250 +// 拼装好的初始化写入init.go文件
  251 +func (g *Generate) WriteInitPkg(data string) error {
  252 + str := strings.Split(g.savePath, "/")
  253 + if len(str) == 0 {
  254 + return fmt.Errorf("WriteNewFile|len(str) is 0")
  255 + }
  256 +
  257 + fw, err := os.OpenFile(g.savePath +"/init.go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  258 + if err != nil {
  259 + return fmt.Errorf("WriteNewFile|OpenFile is err:%v", err)
  260 + }
  261 + defer fw.Close()
  262 +
  263 + _, err = fw.Write([]byte(fmt.Sprintf(initpkg, data)))
  264 + if err != nil {
  265 + return fmt.Errorf("WriteNewFile|Write is err:%v", err)
  266 + }
  267 +
  268 + return nil
  269 +}
  270 +
  271 +// 检测解析出来的字段类型是否符合要求
  272 +func (g *Generate) CheckType(dataType, structName string) error {
  273 + res := strings.Index(g.allType, dataType)
  274 + if res == -1 {
  275 + return fmt.Errorf("CheckType|struct:\"%v\" dataType:\"%v\" is not in provide dataType", structName, dataType)
  276 + }
  277 + return nil
  278 +}
  279 +
  280 +// 字符串首字母转换成大写
  281 +func firstRuneToUpper(str string) string {
  282 + data := []byte(str)
  283 + for k, v := range data {
  284 + if k == 0 {
  285 + first := []byte(strings.ToUpper(string(v)))
  286 + newData := data[1:]
  287 + data = append(first, newData...)
  288 + break
  289 + }
  290 + }
  291 + return string(data[:])
  292 +}
  293 +
  294 +// 判断是否存在汉字或者是否为默认的工作表
  295 +func hasChineseOrDefault(r string) bool {
  296 + if strings.Index(r, "Sheet") != -1 {
  297 + return true
  298 + }
  299 + for _, v := range []rune(r) {
  300 + if unicode.Is(unicode.Han, v) {
  301 + return true
  302 + }
  303 + }
  304 + return false
  305 +}
  306 +
  307 +// 读取Csv 转化为 struct
  308 +func (g *Generate) ReadCsvToStruct(readPath string) error {
  309 + files, err := ioutil.ReadDir(readPath)
  310 + if err != nil {
  311 + return fmt.Errorf("ReadExcel|ReadDir is err:%v", err)
  312 + }
  313 +
  314 +
  315 + data := ""
  316 + for _, file := range files {
  317 + if path.Ext(file.Name()) != ".csv" || hasChineseOrDefault(file.Name()) {
  318 + continue
  319 + }
  320 + err := g.CsvToStruct(readPath, file.Name())
  321 + if err != nil {
  322 + return err
  323 + }
  324 +
  325 + name := strings.Replace(file.Name(), ".csv", "", -1)
  326 + data += fmt.Sprintf(initline, name, firstRuneToUpper(name))
  327 + }
  328 + g.WriteInitPkg(data)
  329 + return nil
  330 +}
  331 +
  332 +// 读取Csv 转化为 memory数据
  333 +func (g *Generate) ReadCsvToMemory(readPath string) error {
  334 + files, err := ioutil.ReadDir(readPath)
  335 + if err != nil {
  336 + return fmt.Errorf("ReadExcel|ReadDir is err:%v", err)
  337 + }
  338 +
  339 + for _, file := range files {
  340 + if path.Ext(file.Name()) != ".csv" || hasChineseOrDefault(file.Name()) {
  341 + continue
  342 + }
  343 + err := g.CsvToMem(readPath, file.Name())
  344 + if err != nil {
  345 + return err
  346 + }
  347 +
  348 + }
  349 + return nil
  350 +}
... ...
tools/main.go 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +package main
  2 +
  3 +import (
  4 + "flag"
  5 + "fmt"
  6 + _ "pro2d/csvdata"
  7 +)
  8 +
  9 +var (
  10 + savePath = flag.String("savePath", "/Users/mac/Documents/project/Pro2D/Pro2DServer/csvdata", "Path to save the makefile")
  11 + readPath = flag.String("readPath", "/Users/mac/Documents/project/Pro2D/Pro2DServer/tools/", "The path of reading Excel")
  12 + allType = flag.String("allType", "int, string", "Specified field type")
  13 +)
  14 +
  15 +func main() {
  16 + flag.Parse()
  17 + if *savePath == "" || *readPath == "" || *allType == "" {
  18 + fmt.Println("savePath, readPath or allType is nil")
  19 + return
  20 + }
  21 +
  22 + gt := NewGenerate(*savePath, *allType)
  23 + //err := gt.ReadCsvToStruct(*readPath)
  24 + err := gt.ReadCsvToMemory(*readPath)
  25 + if err != nil {
  26 + fmt.Printf("something err:%v\n", err)
  27 + return
  28 + }
  29 +}
0 30 \ No newline at end of file
... ...
utils/utils.go
... ... @@ -44,4 +44,13 @@ func FindIndex(schema interface{}) (string, []string){
44 44 }
45 45 }
46 46 return strings.ToLower(s.Name()), index
  47 +}
  48 +
  49 +func GetIdxBySlice(s []interface{}, i interface{}) (int){
  50 + for idx, v := range s {
  51 + if v == i {
  52 + return idx
  53 + }
  54 + }
  55 + return -1
47 56 }
48 57 \ No newline at end of file
... ...