Browse Source

fix: Fix golang ci piplines and docs. (#39)

Co-authored-by: Xinwei Xiong <86140903+cubxxw@users.noreply.github.com>
tags/v0.1.0
Asklv GitHub 3 years ago
parent
commit
379e48ed7a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 195 additions and 103 deletions
  1. +1
    -1
      .github/workflows/golangci-lint.yml
  2. +14
    -12
      .github/workflows/kubekf.yml
  3. +26
    -25
      .golangci.yml
  4. +2
    -2
      Makefile
  5. +1
    -1
      README.md
  6. +1
    -1
      README_zh-CN.md
  7. +5
    -0
      server/cmd/genhooks/pkg/gen.go
  8. +4
    -1
      server/go.mod
  9. +8
    -4
      server/go.sum
  10. +2
    -0
      server/internal/api/mail.go
  11. +1
    -0
      server/internal/common/code.go
  12. +6
    -4
      server/internal/common/msg.go
  13. +10
    -0
      server/internal/common/response/response.go
  14. +9
    -0
      server/internal/config/config.go
  15. +15
    -2
      server/internal/config/viper.go
  16. +2
    -0
      server/internal/conn/client/mail.go
  17. +10
    -3
      server/internal/conn/client/minio.go
  18. +17
    -12
      server/internal/conn/db/mysql.go
  19. +3
    -0
      server/internal/conn/db/redis.go
  20. +1
    -0
      server/internal/middleware/cros.go
  21. +4
    -0
      server/internal/middleware/hooks/global_hook.go
  22. +1
    -1
      server/internal/middleware/hooks/init.go
  23. +4
    -0
      server/internal/middleware/hooks/mail_hook.go
  24. +3
    -2
      server/internal/middleware/hooks/url_trie/hook.go
  25. +12
    -25
      server/internal/middleware/hooks/url_trie/trie.go
  26. +3
    -0
      server/internal/middleware/jwt.go
  27. +1
    -0
      server/internal/models/base.go
  28. +1
    -0
      server/internal/models/user.go
  29. +1
    -0
      server/internal/param/mail.go
  30. +2
    -1
      server/internal/router/router.go
  31. +3
    -0
      server/internal/service/init.go
  32. +2
    -0
      server/internal/service/mail.go
  33. +1
    -0
      server/pkg/log/fileline_hook.go
  34. +17
    -6
      server/pkg/log/logrus.go
  35. +2
    -0
      server/pkg/server/server.go

+ 1
- 1
.github/workflows/golangci-lint.yml View File

@@ -45,7 +45,7 @@ jobs:
# args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0

# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true
# only-new-issues: true

# Optional:The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
install-mode: "goinstall"

+ 14
- 12
.github/workflows/kubekf.yml View File

@@ -58,9 +58,9 @@ jobs:
run: |
make cover

# - name: Build source code for host platform
# run: |
# make build
- name: Build source code for host platform
run: |
# make build # skip build for now

- name: Collect Test Coverage File
uses: actions/upload-artifact@v1.0.0
@@ -71,13 +71,15 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1

- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# skip for now
# - name: Login to DockerHub
# uses: docker/login-action@v1
# with:
# username: ${{ env.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }}

# - name: Build docker images for host arch and push images to registry
# run: |
# set -e
# make docker-push
# skip for now
# - name: Build docker images for host arch and push images to registry
# run: |
# set -e
# make docker-push

+ 26
- 25
.golangci.yml View File

@@ -160,15 +160,15 @@ linters-settings:
- '*.Embedded'
- '*.External'

forbidigo:
# Forbid the following identifiers (identifiers are written using regexp):
forbid:
- ^print.*$
- 'fmt\.Print.*'
- fmt.Println.* # too much log noise
- ginkgo\\.F.* # these are used just for local development
# Exclude godoc examples from forbidigo checks. Default is true.
exclude_godoc_examples: false
# forbidigo:
# # Forbid the following identifiers (identifiers are written using regexp):
# forbid:
# - ^print.*$
# - 'fmt\.Print.*'
# - fmt.Println.* # too much log noise
# - ginkgo\\.F.* # these are used just for local development
# # Exclude godoc examples from forbidigo checks. Default is true.
# exclude_godoc_examples: false
funlen:
lines: 150
statements: 50
@@ -296,7 +296,7 @@ linters-settings:

gofumpt:
# Select the Go version to target. The default is `1.18`.
lang-version: "1.18"
lang-version: "1.20"

# Choose whether or not to use the extra rules that are disabled
# by default
@@ -409,7 +409,7 @@ linters-settings:

gosimple:
# Select the Go version to target. The default is '1.13'.
go: "1.18"
go: "1.20"
# https://staticcheck.io/docs/options#checks
checks: [ "all" ]

@@ -433,14 +433,14 @@ linters-settings:
disable:
- shadow
disable-all: false
depguard:
list-type: blacklist
include-go-root: false
packages:
- github.com/Sirupsen/logrus
packages-with-error-message:
# specify an error message to output when a blacklisted package is used
- github.com/Sirupsen/logrus: "logging is allowed only by logutils.Log"
# depguard:
# list-type: blacklist
# include-go-root: false
# packages:
# - github.com/Sirupsen/logrus
# packages-with-error-message:
# # specify an error message to output when a blacklisted package is used
# - github.com/Sirupsen/logrus: "logging is allowed only by logutils.Log"
ifshort:
# Maximum length of variable declaration measured in number of lines, after which linter won't suggest using short syntax.
# Has higher priority than max-decl-chars.
@@ -722,7 +722,7 @@ linters:
- bodyclose
- cyclop
- deadcode
- depguard
# - depguard
- dogsled
- dupl
- durationcheck
@@ -730,10 +730,10 @@ linters:
- errorlint
- exhaustive
- exportloopref
- forbidigo
# - forbidigo
- funlen
#- gci
- gochecknoinits
# - gci
# - gochecknoinits
- gocognit
- goconst
- gocyclo
@@ -813,8 +813,9 @@ issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- linters:
- errorlint
path: (pkg/validator/.*)\.go
- golint
path: (internal/api/.*)\.go # exclude golint for internal/api/... files

- linters:
- revive
path: (log/.*)\.go


+ 2
- 2
Makefile View File

@@ -227,7 +227,7 @@ generate:
.PHONY: lint
lint: tools.verify.golangci-lint
@echo "===========> Run golangci to lint source codes"
@cd $(SERVER_DIR) && $(TOOLS_DIR)/golangci-lint run -c $(ROOT_DIR)/.golangci.yml $(ROOT_DIR)/$(SERVER_DIR)/...
@cd $(SERVER_DIR) && $(TOOLS_DIR)/golangci-lint run -c $(ROOT_DIR)/.golangci.yml

## test: Run unit test
.PHONY: test
@@ -237,7 +237,7 @@ test:
## cover: Run unit test with coverage.
.PHONY: cover
cover: test
@cd $(SERVER_DIR) && go test -cover
@cd $(SERVER_DIR) && go test -coverprofile=$(TMP_DIR)/coverage.out

## docker-build: Build docker image with the manager.
.PHONY: docker-build


+ 1
- 1
README.md View File

@@ -30,7 +30,7 @@

## 🧩 Awesome features

1. [OpenKF](https://https://github.com/OpenIMSDK/OpenKF) is an opensource customer service system based on [OpenIM](https://https://github.com/OpenIMSDK).
1. [OpenKF](https://github.com/OpenIMSDK/OpenKF) is an opensource customer service system based on [OpenIM](https://github.com/OpenIMSDK).
2. Support LLM(Local Knowledgebase) customer service.
3. Support multi-channel customer service, and easy to integrate with third-party systems.
4. Easy to deploy and secondary development.


+ 1
- 1
README_zh-CN.md View File

@@ -30,7 +30,7 @@

## 🧩 特性

1. [OpenKF](https://https://github.com/OpenIMSDK/OpenKF) 是基于 [OpenIM](https://https://github.com/OpenIMSDK) 的开源客服系统。
1. [OpenKF](https://github.com/OpenIMSDK/OpenKF) 是基于 [OpenIM](https://github.com/OpenIMSDK) 的开源客服系统。
2. 支持 LLM(本地知识库)客服。
3. 支持多渠道客服,并易于与第三方系统集成。
4. 易于部署和二次开发。


+ 5
- 0
server/cmd/genhooks/pkg/gen.go View File

@@ -23,6 +23,7 @@ import (
"strings"
)

// HookGenerator is a generator for hooks
type HookGenerator struct {
buf *bytes.Buffer
config *config
@@ -34,6 +35,7 @@ type config struct {
UrlPattern string
}

// NewHookGenerator returns a new HookGenerator
func NewHookGenerator(hookName, urlPattern, savePath string) *HookGenerator {
return &HookGenerator{
buf: bytes.NewBuffer(nil),
@@ -45,6 +47,7 @@ func NewHookGenerator(hookName, urlPattern, savePath string) *HookGenerator {
}
}

// Generate init the hook
func (g *HookGenerator) Generate() *HookGenerator {
if err := hookTemplate.Execute(g.buf, g.config); err != nil {
panic(err)
@@ -53,6 +56,7 @@ func (g *HookGenerator) Generate() *HookGenerator {
return g
}

// Format format the generated code
func (g *HookGenerator) Format() *HookGenerator {
formatOut, err := format.Source(g.buf.Bytes())
if err != nil {
@@ -63,6 +67,7 @@ func (g *HookGenerator) Format() *HookGenerator {
return g
}

// Flush write the generated code to file
func (g *HookGenerator) Flush() {
filename := fmt.Sprintf("gen_%s_hook.go", strings.ToLower(g.config.HookName))
if err := ioutil.WriteFile(


+ 4
- 1
server/go.mod View File

@@ -42,7 +42,7 @@ require (
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.2 // indirect
github.com/gookit/color v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
@@ -64,9 +64,11 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/onsi/gomega v1.27.6 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
@@ -79,6 +81,7 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect


+ 8
- 4
server/go.sum View File

@@ -179,8 +179,9 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@@ -257,7 +258,8 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -272,7 +274,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -352,8 +355,9 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4=
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=


+ 2
- 0
server/internal/api/mail.go View File

@@ -36,6 +36,7 @@ func SendCode(c *gin.Context) {
err := c.ShouldBindJSON(&params)
if err != nil {
response.FailWithCode(common.INVALID_PARAMS, c)

return
}

@@ -44,6 +45,7 @@ func SendCode(c *gin.Context) {
if err != nil {
log.Debug("SendCode error: ", err)
response.FailWithCode(common.ERROR, c)

return
}



+ 1
- 0
server/internal/common/code.go View File

@@ -14,6 +14,7 @@

package common

// Code.
const (
SUCCESS = 200
ERROR = 500


+ 6
- 4
server/internal/common/msg.go View File

@@ -14,17 +14,19 @@

package common

var Msg = map[int]string{
// msg is a mapping of message.
var msg = map[int]string{
SUCCESS: "success",
ERROR: "error",
INVALID_PARAMS: "request params error",
}

// GetMsg get the message by code.
func GetMsg(code int) string {
msg, ok := Msg[code]
m, ok := msg[code]
if ok {
return msg
return m
}

return Msg[ERROR]
return msg[ERROR]
}

+ 10
- 0
server/internal/common/response/response.go View File

@@ -21,12 +21,14 @@ import (
"github.com/gin-gonic/gin"
)

// Response is a common struct for response
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}

// NewResponse returns a new Response
func NewResponse(code int, msg string, data interface{}, c *gin.Context) {
c.JSON(http.StatusOK, &Response{
Code: code,
@@ -35,34 +37,42 @@ func NewResponse(code int, msg string, data interface{}, c *gin.Context) {
})
}

// Success returns a success response
func Success(c *gin.Context) {
NewResponse(common.SUCCESS, common.GetMsg(common.SUCCESS), nil, c)
}

// SuccessWithData returns a success response with data
func SuccessWithData(data interface{}, c *gin.Context) {
NewResponse(common.SUCCESS, common.GetMsg(common.SUCCESS), data, c)
}

// SuccessWithCode returns a success response with code
func SuccessWithCode(code int, c *gin.Context) {
NewResponse(code, common.GetMsg(code), nil, c)
}

// SuccessWithAll returns a success response with code and data
func SuccessWithAll(code int, data interface{}, c *gin.Context) {
NewResponse(code, common.GetMsg(code), data, c)
}

// Fail returns a fail response
func Fail(c *gin.Context) {
NewResponse(common.ERROR, common.GetMsg(common.ERROR), nil, c)
}

// FailWithData returns a fail response with data
func FailWithData(data interface{}, c *gin.Context) {
NewResponse(common.ERROR, common.GetMsg(common.ERROR), data, c)
}

// FailWithCode returns a fail response with code
func FailWithCode(code int, c *gin.Context) {
NewResponse(code, common.GetMsg(code), nil, c)
}

// FailWithAll returns a fail response with code and data
func FailWithAll(code int, data interface{}, c *gin.Context) {
NewResponse(code, common.GetMsg(code), data, c)
}

+ 9
- 0
server/internal/config/config.go View File

@@ -14,8 +14,10 @@

package config

// Config global config instance
var Config *config

// ConfigInit init config
func ConfigInit(configPath string) {
// init viper
initViper(configPath)
@@ -81,23 +83,27 @@ type config struct {
Email Email
}

// App config
type App struct {
Version string `mapstructure:"version"`
Debug bool `mapstructure:"debug"`
LogFile string `mapstructure:"log_file"`
}

// JWT config
type JWT struct {
Secret string `mapstructure:"secret"`
Issuer string `mapstructure:"issuer"`
ExpireDays int `mapstructure:"expire_days"`
}

// Server config
type Server struct {
Ip string `mapstructure:"ip"`
Port int `mapstructure:"port"`
}

// Mysql config
type Mysql struct {
Ip string `mapstructure:"ip"`
Port int `mapstructure:"port"`
@@ -109,6 +115,7 @@ type Mysql struct {
MaxIdleConns int `mapstructure:"max_idle_conns"`
}

// Redis config
type Redis struct {
Ip string `mapstructure:"ip"`
Port int `mapstructure:"port"`
@@ -116,6 +123,7 @@ type Redis struct {
Database int `mapstructure:"database"`
}

// Minio config
type Minio struct {
Ip string `mapstructure:"ip"`
Port int `mapstructure:"port"`
@@ -126,6 +134,7 @@ type Minio struct {
Location string `mapstructure:"location"`
}

// Email config
type Email struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`


+ 15
- 2
server/internal/config/viper.go View File

@@ -32,36 +32,49 @@ func initViper(configPath string) {
fmt.Println("Load ok")
}

// get config
// GetInterface get interface config
func GetInterface(key string) interface{} {
return viper.Get(key)
}

// GetString get string config
func GetString(key string) string {
return viper.GetString(key)
}

// GetInt get int config
func GetInt(key string) int {
return viper.GetInt(key)
}

// GetBool get bool config
func GetBool(key string) bool {
return viper.GetBool(key)
}

// get config or use default
// GetStringOrDefault get string config or use default
func GetStringOrDefault(key string, defaultValue string) string {
if viper.IsSet(key) {
return viper.GetString(key)
}

return defaultValue
}

// GetIntOrDefault get int config or use default
func GetIntOrDefault(key string, defaultValue int) int {
if viper.IsSet(key) {
return viper.GetInt(key)
}

return defaultValue
}

// GetBoolOrDefault get bool config or use default
func GetBoolOrDefault(key string, defaultValue bool) bool {
if viper.IsSet(key) {
return viper.GetBool(key)
}

return defaultValue
}

+ 2
- 0
server/internal/conn/client/mail.go View File

@@ -25,6 +25,7 @@ import (
// todo: use email connection pool to reduce the cost of creating a connection
// link: https://github.com/jordan-wright/email#a-pool-of-reusable-connections

// SendEmail send email
func SendEmail(to string, subject string, body string) error {
email := email.NewEmail()

@@ -45,6 +46,7 @@ func SendEmail(to string, subject string, body string) error {
return nil
}

// SendHtmlEmail send html email
func SendHtmlEmail(to string, subject string, html string) error {
email := email.NewEmail()



+ 10
- 3
server/internal/conn/client/minio.go View File

@@ -28,6 +28,7 @@ import (
var _minioClient *minio.Client
var _bucket string

// InitMinio init minio client
func InitMinio() {
endpoint := fmt.Sprintf("%s:%d", config.Config.Minio.Ip, config.Config.Minio.Port)
accessKeyID := config.Config.Minio.AccessKeyId
@@ -36,7 +37,7 @@ func InitMinio() {
_bucket = config.Config.Minio.Bucket

// Initialize _minioClient
_minioClient, err := minio.New(
minioClient, err := minio.New(
endpoint,
&minio.Options{
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
@@ -48,12 +49,12 @@ func InitMinio() {
}

// create bucket if not exists
exists, err := _minioClient.BucketExists(context.Background(), _bucket)
exists, err := minioClient.BucketExists(context.Background(), _bucket)
if err != nil {
log.Panicf("Minio", err.Error(), " Open Bucket failed ", endpoint)
}
if !exists {
if err = _minioClient.MakeBucket(
if err = minioClient.MakeBucket(
context.Background(),
_bucket,
minio.MakeBucketOptions{Region: location, ObjectLocking: true},
@@ -61,14 +62,20 @@ func InitMinio() {
log.Panicf("Minio", err.Error(), " Open failed ", endpoint)
}
}

_minioClient = minioClient
}

// PutObject put object to minio
func PutObject(objectName string, r io.Reader, objectSize int64) error {
_, err := _minioClient.PutObject(context.Background(), _bucket, objectName, r, objectSize, minio.PutObjectOptions{ContentType: "application/octet-stream"})

return err
}

// GetObject get object from minio
func GetObject(objectName string) (io.Reader, error) {
object, err := _minioClient.GetObject(context.Background(), _bucket, objectName, minio.GetObjectOptions{})

return object, err
}

+ 17
- 12
server/internal/conn/db/mysql.go View File

@@ -27,12 +27,14 @@ import (

var d *gorm.DB

type Writer struct{}
type writer struct{}

func (w Writer) Printf(format string, args ...interface{}) {
// Write implement log writer interface
func (w writer) Printf(format string, args ...interface{}) {
fmt.Printf(format, args...)
}

// InitMysqlDB init mysql connection.
func InitMysqlDB() {
// try to use default database [mysql]
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
@@ -71,7 +73,7 @@ func InitMysqlDB() {
)

logger := logger.New(
Writer{},
writer{},
logger.Config{
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
Colorful: true, // Disable color
@@ -103,21 +105,24 @@ func InitMysqlDB() {
log.Info("Mysql", "connect ok", dsn)
}

// get mysql connection.
// GetMysqlDB get mysql connection.
func GetMysqlDB() *gorm.DB {
return d
}

// CloseMysqlDB close mysql connection.
func CloseMysqlDB() {
if d != nil {
sqlDB, err := d.DB()
if d == nil {
return
}

sqlDB, err := d.DB()
if err != nil {
log.Error("Mysql", err.Error(), " db.DB() failed ")
} else {
err = sqlDB.Close()
if err != nil {
log.Error("Mysql", err.Error(), " db.DB() failed ")
} else {
err = sqlDB.Close()
if err != nil {
log.Error("Mysql", err.Error(), " sqlDB.Close() failed ")
}
log.Error("Mysql", err.Error(), " sqlDB.Close() failed ")
}
}
}

+ 3
- 0
server/internal/conn/db/redis.go View File

@@ -25,6 +25,7 @@ import (

var r *redis.Client

// InitRedisDB init redis client
func InitRedisDB() {
r = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", config.Config.Redis.Ip, config.Config.Redis.Port),
@@ -39,10 +40,12 @@ func InitRedisDB() {
}
}

// GetRedis get redis client instance
func GetRedis() *redis.Client {
return r
}

// CloseRedis close redis client instance
func CloseRedis() {
if r != nil {
err := r.Close()


+ 1
- 0
server/internal/middleware/cros.go View File

@@ -20,6 +20,7 @@ import (
"github.com/gin-gonic/gin"
)

// EnableCROS enable cros
func EnableCROS() gin.HandlerFunc {
return func(c *gin.Context) {
// c.Writer.Header().Set("Access-Control-Allow-Origin", "*")


+ 4
- 0
server/internal/middleware/hooks/global_hook.go View File

@@ -27,19 +27,23 @@ func init() {
fmt.Println("RegisterHook", "Register Hook[GlobalHook] success...")
}

// GlobalHook implement urltrie.Hook
type GlobalHook struct {
urltrie.Hook
}

// Pattern return pattern
func (h GlobalHook) Pattern() string {
return "/*"
}

// BeforeRun do something before controller run
func (h GlobalHook) BeforeRun(c *gin.Context) {
log.Debugf("GlobalHook", "path: %v", c.Request.URL.Path)
c.Next()
}

// AfterRun do something after controller run
func (h GlobalHook) AfterRun(c *gin.Context) {
c.Next()
}

+ 1
- 1
server/internal/middleware/hooks/init.go View File

@@ -14,6 +14,6 @@

package hooks

// Manual import hooks packages and do init
// InitHooks manual import hooks packages and do init
func InitHooks() {
}

+ 4
- 0
server/internal/middleware/hooks/mail_hook.go View File

@@ -27,19 +27,23 @@ func init() {
fmt.Println("RegisterHook", "Register Hook[MailHook] success...")
}

// MailHook implement urltrie.Hook
type MailHook struct {
urltrie.Hook
}

// Pattern return pattern
func (h MailHook) Pattern() string {
return "/api/v1/register/email/code"
}

// BeforeRun do something before controller run
func (h MailHook) BeforeRun(c *gin.Context) {
log.Debugf("GlobalHook", "path: %v", c.Request.URL.Path)
c.Next()
}

// AfterRun do something after controller run
func (h MailHook) AfterRun(c *gin.Context) {
c.Next()
}

+ 3
- 2
server/internal/middleware/hooks/url_trie/hook.go View File

@@ -28,12 +28,12 @@ func init() {
hookTrie = NewTrie()
}

// Register url & hook to trie
// RegisterHook register url & hook to trie
func RegisterHook(hook Hook) {
hookTrie.Insert(hook.Pattern(), hook)
}

// Enable hook for interceptor
// RunHook enable hook for interceptor
func RunHook() gin.HandlerFunc {
return func(c *gin.Context) {
raw := c.Request.URL.Path
@@ -48,6 +48,7 @@ func RunHook() gin.HandlerFunc {
hooks, ok := hookTrie.Match(path)
if !ok {
c.Next()

return
}



+ 12
- 25
server/internal/middleware/hooks/url_trie/trie.go View File

@@ -34,7 +34,7 @@ type Hook interface {
AfterRun(c *gin.Context)
}

const WILDCARD = "*"
const _wildcard = "*"

type node struct {
children map[string]*node
@@ -46,10 +46,12 @@ type node struct {
isEnd bool
}

// Trie is a tree for url
type Trie struct {
root *node
}

// NewTrie returns a new Trie
func NewTrie() *Trie {
return &Trie{
root: &node{
@@ -58,7 +60,7 @@ func NewTrie() *Trie {
}
}

// Insert url with hooks
// Insert insert url with hooks
func (t *Trie) Insert(url string, hooks ...Hook) {
current := t.root

@@ -76,7 +78,7 @@ func (t *Trie) Insert(url string, hooks ...Hook) {
data: part,
}
// match wildcard
if part == WILDCARD {
if part == _wildcard {
child.isWildcard = true
}

@@ -92,7 +94,7 @@ func (t *Trie) Insert(url string, hooks ...Hook) {
current.hooks = append(current.hooks, hooks...)
}

// Match url with hooks
// Match match url with hooks
func (t *Trie) Match(url string) ([]Hook, bool) {
current := t.root

@@ -110,36 +112,25 @@ func (t *Trie) Match(url string) ([]Hook, bool) {
}

if len(stack) == 0 {
if len(matchedValues) > 0 {
return matchedValues, true
} else {
return matchedValues, false
}
return matchedValues, len(matchedValues) > 0
}

// get current level length
levelLen := len(stack)
for i := 0; i < levelLen; i++ {
// pop
current = stack[0]
stack = stack[1:]
current, stack = stack[0], stack[1:]
if current.isEnd {
if current.isWildcard || current.data == part {
// Match the last node, append the values
matchedValues = append(matchedValues, current.hooks...)
}
continue
}

// find wildcard node
if current.isWildcard {
for _, child := range current.children {
stack = append(stack, child)
}
continue
}

// find expect node
if current.data == part {
// find wildcard node or expect node
if current.isWildcard || current.data == part {
for _, child := range current.children {
stack = append(stack, child)
}
@@ -147,9 +138,5 @@ func (t *Trie) Match(url string) ([]Hook, bool) {
}
}

if len(matchedValues) > 0 {
return matchedValues, true
} else {
return matchedValues, false
}
return matchedValues, len(matchedValues) > 0
}

+ 3
- 0
server/internal/middleware/jwt.go View File

@@ -22,17 +22,20 @@ import (
"github.com/gin-gonic/gin"
)

// EnableAuth enable auth middleware
func EnableAuth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" || strings.Fields(token)[0] != "Bearer" {
c.AbortWithStatus(http.StatusUnauthorized)

return
}

_, err := utils.ParseJwtToken(token)
if err != nil {
c.AbortWithStatus(http.StatusUnauthorized)

return
}



+ 1
- 0
server/internal/models/base.go View File

@@ -16,6 +16,7 @@ package models

import "time"

// Model base model
type Model struct {
ID uint `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`


+ 1
- 0
server/internal/models/user.go View File

@@ -14,6 +14,7 @@

package models

// User user model
type User struct {
Model
Username string `json:"username" gorm:"type:varchar(20);not null;unique"`


+ 1
- 0
server/internal/param/mail.go View File

@@ -14,6 +14,7 @@

package param

// SendToParams register params for email.
type SendToParams struct {
Email string `json:"email" binding:"required"`
}

+ 2
- 1
server/internal/router/router.go View File

@@ -15,7 +15,7 @@
package router

import (
_ "github.com/OpenIMSDK/OpenKF/server/docs"
_ "github.com/OpenIMSDK/OpenKF/server/docs" //nolint:golint
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"

@@ -26,6 +26,7 @@ import (
"github.com/gin-gonic/gin"
)

// InitRouter init router
func InitRouter() *gin.Engine {
if config.GetString("app.debug") == "true" {
gin.SetMode(gin.DebugMode)


+ 3
- 0
server/internal/service/init.go View File

@@ -23,6 +23,7 @@ import (
"gorm.io/gorm"
)

// Service service
type Service struct {
// Context
Ctx context.Context
@@ -32,6 +33,7 @@ type Service struct {
Cache *redis.Client
}

// NewService return new service with context
func NewService() *Service {
return &Service{
Ctx: context.Background(),
@@ -40,6 +42,7 @@ func NewService() *Service {
}
}

// NewServiceWithGin return new service with gin context
func NewServiceWithGin(c *gin.Context) *Service {
return &Service{
Ctx: c.Request.Context(),


+ 2
- 0
server/internal/service/mail.go View File

@@ -22,6 +22,7 @@ import (
"github.com/OpenIMSDK/OpenKF/server/pkg/log"
)

// SendCode send code to email
func (svc *Service) SendCode(email string) (err error) {
// check the code is exist
cmd := svc.Cache.Get(svc.Ctx, "code:"+email)
@@ -41,6 +42,7 @@ func (svc *Service) SendCode(email string) (err error) {
return err
}

// Test test
func (svc *Service) Test() {
log.Info("test...")
}

+ 1
- 0
server/pkg/log/fileline_hook.go View File

@@ -40,5 +40,6 @@ func (hook *filelineHook) Fire(entry *logrus.Entry) error {
s = i[len(i)-3] + i[len(i)-2] + i[len(i)-1] + ":" + utils.IntToString(line)
}
entry.Data["FilePath"] = s

return nil
}

+ 17
- 6
server/pkg/log/logrus.go View File

@@ -29,6 +29,7 @@ import (

var _logger *logrus.Logger

// InitLogger init logger
func InitLogger() {
_logger = loggerInit()
}
@@ -69,12 +70,13 @@ func loggerInit() *logrus.Logger {
return logger
}

// NewLfsHook add fileline hook
func NewLfsHook(rotationTime time.Duration, maxRemainNum uint) logrus.Hook {
lfsHook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: initRotateLogs(rotationTime, maxRemainNum, "all"),
logrus.InfoLevel: initRotateLogs(rotationTime, maxRemainNum, "all"),
logrus.WarnLevel: initRotateLogs(rotationTime, maxRemainNum, "all"),
logrus.ErrorLevel: initRotateLogs(rotationTime, maxRemainNum, "all"),
logrus.DebugLevel: initRotateLogs(rotationTime, maxRemainNum),
logrus.InfoLevel: initRotateLogs(rotationTime, maxRemainNum),
logrus.WarnLevel: initRotateLogs(rotationTime, maxRemainNum),
logrus.ErrorLevel: initRotateLogs(rotationTime, maxRemainNum),
}, &nested.Formatter{
TimestampFormat: "2006-01-02 15:04:05.000",
HideKeys: false,
@@ -84,9 +86,9 @@ func NewLfsHook(rotationTime time.Duration, maxRemainNum uint) logrus.Hook {
return lfsHook
}

func initRotateLogs(rotationTime time.Duration, maxRemainNum uint, level string) *rotatelogs.RotateLogs {
func initRotateLogs(rotationTime time.Duration, maxRemainNum uint) *rotatelogs.RotateLogs {
writer, err := rotatelogs.New(
config.Config.App.LogFile+level+".%Y%m%d%H%M",
config.Config.App.LogFile+".%Y%m%d%H%M",
rotatelogs.WithRotationTime(rotationTime),
rotatelogs.WithRotationCount(maxRemainNum),
)
@@ -97,52 +99,61 @@ func initRotateLogs(rotationTime time.Duration, maxRemainNum uint, level string)
}
}

// GetLogger get logger instance
func GetLogger() *logrus.Logger {
return _logger
}

// Info log info
func Info(Operation string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Infoln(args...)
}

// Error log error
func Error(Operation string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Errorln(args...)
}

// Debug log debug
func Debug(Operation string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Debugln(args...)
}

// Panic log panic
func Panic(Operation string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Panicln(args...)
}

// Infof log info with format
func Infof(Operation string, format string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Infof(format, args...)
}

// Errorf log error with format
func Errorf(Operation string, format string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Errorf(format, args...)
}

// Debugf log debug with format
func Debugf(Operation string, format string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,
}).Debugf(format, args...)
}

// Panicf log panic with format
func Panicf(Operation string, format string, args ...interface{}) {
_logger.WithFields(logrus.Fields{
"Operation": Operation,


+ 2
- 0
server/pkg/server/server.go View File

@@ -21,10 +21,12 @@ import (
"github.com/gin-gonic/gin"
)

// Server server interface
type Server interface {
ListenAndServe() error
}

// InitServer init server
func InitServer(address string, r *gin.Engine) Server {
server := endless.NewServer(address, r)



Loading…
Cancel
Save