| @@ -332,6 +332,7 @@ flycheck_*.el | |||
| # log | |||
| *.log | |||
| /server/logs | |||
| /server/cmd/dbmigration/logs | |||
| # data | |||
| /server/data | |||
| @@ -0,0 +1,57 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package main | |||
| import ( | |||
| "flag" | |||
| "reflect" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/db" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/models" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/utils" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| func init() { | |||
| // arg | |||
| configPath := flag.String("c", "../../config.yaml", "config file path") | |||
| flag.Parse() | |||
| config.ConfigInit(*configPath) | |||
| utils.OpenKFBanner() | |||
| log.InitLogger() | |||
| db.InitMysqlDB() | |||
| } | |||
| // migrate table | |||
| func main() { | |||
| // get db instance | |||
| db := db.GetMysqlDB() | |||
| // tables | |||
| tables := []interface{}{ | |||
| models.User{}, | |||
| } | |||
| // migrate | |||
| for _, table := range tables { | |||
| err := db.AutoMigrate(&table) | |||
| if err != nil { | |||
| log.Panicf("OpenKF Table Migration", "Migrate table %v... failed", reflect.TypeOf(table)) | |||
| } | |||
| log.Infof("OpenKF Table Migration", "Migrate table %v... ok", reflect.TypeOf(table)) | |||
| } | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package main | |||
| // todo: generate dao with template | |||
| @@ -0,0 +1,44 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package main | |||
| import ( | |||
| "flag" | |||
| "os" | |||
| "github.com/OpenIMSDK/OpenKF/server/cmd/genhooks/pkg" | |||
| ) | |||
| var ( | |||
| hookName string | |||
| urlPattern string | |||
| savePath string | |||
| ) | |||
| func init() { | |||
| flag.StringVar(&hookName, "name", "", "hook name") | |||
| flag.StringVar(&urlPattern, "pattern", "", "url pattern") | |||
| flag.StringVar(&savePath, "path", "../../internal/middleware/hooks", "save path") | |||
| flag.Parse() | |||
| if hookName == "" || savePath == "" { | |||
| flag.Usage() | |||
| os.Exit(1) | |||
| } | |||
| } | |||
| func main() { | |||
| pkg.NewHookGenerator(hookName, urlPattern, savePath).Generate().Format().Flush() | |||
| } | |||
| @@ -0,0 +1,75 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package pkg | |||
| import ( | |||
| "bytes" | |||
| "fmt" | |||
| "go/format" | |||
| "io/fs" | |||
| "io/ioutil" | |||
| "strings" | |||
| ) | |||
| type HookGenerator struct { | |||
| buf *bytes.Buffer | |||
| config *config | |||
| savePath string | |||
| } | |||
| type config struct { | |||
| HookName string | |||
| UrlPattern string | |||
| } | |||
| func NewHookGenerator(hookName, urlPattern, savePath string) *HookGenerator { | |||
| return &HookGenerator{ | |||
| buf: bytes.NewBuffer(nil), | |||
| config: &config{ | |||
| HookName: hookName, | |||
| UrlPattern: urlPattern, | |||
| }, | |||
| savePath: savePath, | |||
| } | |||
| } | |||
| func (g *HookGenerator) Generate() *HookGenerator { | |||
| if err := hookTemplate.Execute(g.buf, g.config); err != nil { | |||
| panic(err) | |||
| } | |||
| return g | |||
| } | |||
| func (g *HookGenerator) Format() *HookGenerator { | |||
| formatOut, err := format.Source(g.buf.Bytes()) | |||
| if err != nil { | |||
| panic(err) | |||
| } | |||
| g.buf = bytes.NewBuffer(formatOut) | |||
| return g | |||
| } | |||
| func (g *HookGenerator) Flush() { | |||
| filename := fmt.Sprintf("gen_%s_hook.go", strings.ToLower(g.config.HookName)) | |||
| if err := ioutil.WriteFile( | |||
| fmt.Sprintf("%s/%s", g.savePath, filename), | |||
| g.buf.Bytes(), | |||
| fs.ModePerm); err != nil { | |||
| panic(err) | |||
| } | |||
| fmt.Println("[OpenKF] gen file ok: ", fmt.Sprintf("%s/%s", g.savePath, filename)) | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package pkg | |||
| import "html/template" | |||
| func checkTemplate(t string) *template.Template { | |||
| return template.Must(template.New("").Parse(t)) | |||
| } | |||
| var hookTemplate = checkTemplate(` | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package hooks | |||
| import ( | |||
| urltrie "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks/url_trie" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| func init() { | |||
| urltrie.RegisterHook({{.HookName}}{}) | |||
| fmt.Println("RegisterHook", "Register Hook[{{.HookName}}] success...") | |||
| } | |||
| type {{.HookName}} struct { | |||
| urltrie.Hook | |||
| } | |||
| // EDIT THIS TO YOUR OWN HOOK PATTERN | |||
| func (h {{.HookName}}) Pattern() string { | |||
| return "{{.UrlPattern}}" | |||
| } | |||
| // EDIT THIS TO YOUR OWN HOOK BEFORE RUN | |||
| func (h {{.HookName}}) BeforeRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| // EDIT THIS TO YOUR OWN HOOK AFTER RUN | |||
| func (h {{.HookName}}) AfterRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| `) | |||
| @@ -32,6 +32,9 @@ mysql: | |||
| username: root | |||
| password: 123123 | |||
| database: openkf | |||
| max_lifetime: 120 | |||
| max_open_conns: 100 | |||
| max_idle_conns: 20 | |||
| redis: | |||
| ip: 127.0.0.1 | |||
| @@ -32,6 +32,9 @@ mysql: | |||
| username: root | |||
| password: 123123 | |||
| database: openkf | |||
| max_lifetime: 120 | |||
| max_open_conns: 100 | |||
| max_idle_conns: 20 | |||
| redis: | |||
| ip: 127.0.0.1 | |||
| @@ -37,11 +37,14 @@ func ConfigInit(configPath string) { | |||
| Port: GetInt("server.port"), | |||
| }, | |||
| Mysql: Mysql{ | |||
| Ip: GetString("mysql.ip"), | |||
| Port: GetInt("mysql.port"), | |||
| Username: GetString("mysql.username"), | |||
| Password: GetString("mysql.password"), | |||
| Database: GetString("mysql.database"), | |||
| Ip: GetString("mysql.ip"), | |||
| Port: GetInt("mysql.port"), | |||
| Username: GetString("mysql.username"), | |||
| Password: GetString("mysql.password"), | |||
| Database: GetString("mysql.database"), | |||
| MaxLifetime: GetIntOrDefault("mysql.max_lifetime", 120), | |||
| MaxOpenConns: GetIntOrDefault("mysql.max_open_conns", 100), | |||
| MaxIdleConns: GetIntOrDefault("mysql.max_idle_conns", 20), | |||
| }, | |||
| Redis: Redis{ | |||
| Ip: GetString("redis.ip"), | |||
| @@ -96,11 +99,14 @@ type Server struct { | |||
| } | |||
| type Mysql struct { | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| Username string `mapstructure:"username"` | |||
| Password string `mapstructure:"password"` | |||
| Database string `mapstructure:"database"` | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| Username string `mapstructure:"username"` | |||
| Password string `mapstructure:"password"` | |||
| Database string `mapstructure:"database"` | |||
| MaxLifetime int `mapstructure:"max_lifetime"` | |||
| MaxOpenConns int `mapstructure:"max_open_conns"` | |||
| MaxIdleConns int `mapstructure:"max_idle_conns"` | |||
| } | |||
| type Redis struct { | |||
| @@ -32,18 +32,36 @@ func initViper(configPath string) { | |||
| fmt.Println("Load ok") | |||
| } | |||
| // get config | |||
| func GetInterface(key string) interface{} { | |||
| return viper.Get(key) | |||
| } | |||
| func GetString(key string) string { | |||
| return viper.GetString(key) | |||
| } | |||
| func GetInt(key string) int { | |||
| return viper.GetInt(key) | |||
| } | |||
| func GetBool(key string) bool { | |||
| return viper.GetBool(key) | |||
| } | |||
| // get config or use default | |||
| func GetStringOrDefault(key string, defaultValue string) string { | |||
| if viper.IsSet(key) { | |||
| return viper.GetString(key) | |||
| } | |||
| return defaultValue | |||
| } | |||
| func GetIntOrDefault(key string, defaultValue int) int { | |||
| if viper.IsSet(key) { | |||
| return viper.GetInt(key) | |||
| } | |||
| return defaultValue | |||
| } | |||
| func GetBoolOrDefault(key string, defaultValue bool) bool { | |||
| if viper.IsSet(key) { | |||
| return viper.GetBool(key) | |||
| } | |||
| return defaultValue | |||
| } | |||
| @@ -90,10 +90,11 @@ func InitMysqlDB() { | |||
| if err != nil { | |||
| log.Panic("Mysql", err.Error(), " db.DB() failed ") | |||
| } | |||
| // default is unlimited | |||
| sqlDB.SetConnMaxLifetime(time.Second * time.Duration(0)) | |||
| sqlDB.SetMaxOpenConns(0) | |||
| sqlDB.SetMaxIdleConns(0) | |||
| // set connect result | |||
| sqlDB.SetConnMaxLifetime(time.Second * time.Duration(config.Config.Mysql.MaxLifetime)) | |||
| sqlDB.SetMaxOpenConns(config.Config.Mysql.MaxOpenConns) | |||
| sqlDB.SetMaxIdleConns(config.Config.Mysql.MaxIdleConns) | |||
| db.Set("gorm:table_options", "CHARSET=utf8mb4") | |||
| db.Set("gorm:table_options", "collation=utf8_unicode_ci") | |||
| @@ -0,0 +1,45 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package hooks | |||
| import ( | |||
| "fmt" | |||
| urltrie "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks/url_trie" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| func init() { | |||
| urltrie.RegisterHook(GlobalHook{}) | |||
| fmt.Println("RegisterHook", "Register Hook[GlobalHook] success...") | |||
| } | |||
| type GlobalHook struct { | |||
| urltrie.Hook | |||
| } | |||
| func (h GlobalHook) Pattern() string { | |||
| return "/*" | |||
| } | |||
| func (h GlobalHook) BeforeRun(c *gin.Context) { | |||
| log.Debugf("GlobalHook", "path: %v", c.Request.URL.Path) | |||
| c.Next() | |||
| } | |||
| func (h GlobalHook) AfterRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| @@ -0,0 +1,19 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package hooks | |||
| // Manual import hooks packages and do init | |||
| func InitHooks() { | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package hooks | |||
| import ( | |||
| "fmt" | |||
| urltrie "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks/url_trie" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| func init() { | |||
| urltrie.RegisterHook(MailHook{}) | |||
| fmt.Println("RegisterHook", "Register Hook[MailHook] success...") | |||
| } | |||
| type MailHook struct { | |||
| urltrie.Hook | |||
| } | |||
| func (h MailHook) Pattern() string { | |||
| return "/api/v1/register/email/code" | |||
| } | |||
| func (h MailHook) BeforeRun(c *gin.Context) { | |||
| log.Debugf("GlobalHook", "path: %v", c.Request.URL.Path) | |||
| c.Next() | |||
| } | |||
| func (h MailHook) AfterRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| @@ -0,0 +1,61 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package urltrie | |||
| import ( | |||
| "net/url" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // Mapping for store url pattern and hook | |||
| var hookTrie *Trie | |||
| func init() { | |||
| hookTrie = NewTrie() | |||
| } | |||
| // Register url & hook to trie | |||
| func RegisterHook(hook Hook) { | |||
| hookTrie.Insert(hook.Pattern(), hook) | |||
| } | |||
| // Enable hook for interceptor | |||
| func RunHook() gin.HandlerFunc { | |||
| return func(c *gin.Context) { | |||
| raw := c.Request.URL.Path | |||
| // get path from url | |||
| p, err := url.Parse(raw) | |||
| if err != nil { | |||
| log.Errorf("Hook", "parse url error: %v", err) | |||
| } | |||
| path := p.Path | |||
| hooks, ok := hookTrie.Match(path) | |||
| if !ok { | |||
| c.Next() | |||
| return | |||
| } | |||
| // run hooks | |||
| for _, hook := range hooks { | |||
| hook.BeforeRun(c) | |||
| c.Next() | |||
| hook.AfterRun(c) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,155 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package urltrie | |||
| import ( | |||
| "strings" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // Hook for interceptor | |||
| type Hook interface { | |||
| // Register with url pattern | |||
| // Support * wildcard, you can use it like this: | |||
| // /api/v1/*, and the url like /api/v1/123 will be matched | |||
| Pattern() string | |||
| // Hooks | |||
| // BeforeRun will be called before controller, you can do something here | |||
| BeforeRun(c *gin.Context) | |||
| // AfterRun will be called after controller, you can do something here | |||
| AfterRun(c *gin.Context) | |||
| } | |||
| const WILDCARD = "*" | |||
| type node struct { | |||
| children map[string]*node | |||
| hooks []Hook | |||
| data string | |||
| // for wildcard | |||
| isWildcard bool | |||
| isEnd bool | |||
| } | |||
| type Trie struct { | |||
| root *node | |||
| } | |||
| func NewTrie() *Trie { | |||
| return &Trie{ | |||
| root: &node{ | |||
| children: make(map[string]*node), | |||
| }, | |||
| } | |||
| } | |||
| // Insert url with hooks | |||
| func (t *Trie) Insert(url string, hooks ...Hook) { | |||
| current := t.root | |||
| // split url with '/' | |||
| parts := strings.Split(url, "/") | |||
| for _, part := range parts { | |||
| if part == "" { | |||
| continue | |||
| } | |||
| child, exists := current.children[part] | |||
| if !exists { | |||
| child = &node{ | |||
| children: make(map[string]*node), | |||
| data: part, | |||
| } | |||
| // match wildcard | |||
| if part == WILDCARD { | |||
| child.isWildcard = true | |||
| } | |||
| // set child node | |||
| current.children[part] = child | |||
| } | |||
| current = child | |||
| } | |||
| // Set hooks to last node | |||
| current.isEnd = true | |||
| current.hooks = append(current.hooks, hooks...) | |||
| } | |||
| // Match url with hooks | |||
| func (t *Trie) Match(url string) ([]Hook, bool) { | |||
| current := t.root | |||
| parts := strings.Split(url, "/") | |||
| var matchedValues []Hook | |||
| // use stack to save matched children nodes | |||
| stack := make([]*node, 0) | |||
| for _, c := range current.children { | |||
| stack = append(stack, c) | |||
| } | |||
| for _, part := range parts { | |||
| if part == "" { | |||
| continue | |||
| } | |||
| if len(stack) == 0 { | |||
| if len(matchedValues) > 0 { | |||
| return matchedValues, true | |||
| } else { | |||
| return matchedValues, false | |||
| } | |||
| } | |||
| // get current level length | |||
| levelLen := len(stack) | |||
| for i := 0; i < levelLen; i++ { | |||
| // pop | |||
| current = stack[0] | |||
| stack = 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) | |||
| } | |||
| } | |||
| // find expect node | |||
| if current.data == part { | |||
| for _, child := range current.children { | |||
| stack = append(stack, child) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if len(matchedValues) > 0 { | |||
| return matchedValues, true | |||
| } else { | |||
| return matchedValues, false | |||
| } | |||
| } | |||
| @@ -0,0 +1,59 @@ | |||
| // Copyright © 2023 OpenIM open source community. All rights reserved. | |||
| // | |||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| // You may obtain a copy of the License at | |||
| // | |||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||
| // | |||
| // Unless required by applicable law or agreed to in writing, software | |||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| // See the License for the specific language governing permissions and | |||
| // limitations under the License. | |||
| package urltrie | |||
| import ( | |||
| "fmt" | |||
| "reflect" | |||
| "testing" | |||
| ) | |||
| func TestUrlTrie(t *testing.T) { | |||
| type Hook1 struct { | |||
| Hook | |||
| } | |||
| type Hook2 struct { | |||
| Hook | |||
| } | |||
| type Hook3 struct { | |||
| Hook | |||
| } | |||
| trie := NewTrie() | |||
| trie.Insert("/gin", Hook1{}) | |||
| trie.Insert("/api/v1/123", Hook2{}) | |||
| trie.Insert("/openkf/*", Hook3{}) | |||
| values, matched := trie.Match("/gin") | |||
| if matched { | |||
| fmt.Printf("Matched, values: %#v\n", reflect.ValueOf(values)) // Output: Matched, values: [1 2] | |||
| } else { | |||
| fmt.Println("No match found") | |||
| } | |||
| values, matched = trie.Match("/openim") | |||
| if matched { | |||
| fmt.Printf("Matched, values: %#v\n", reflect.ValueOf(values)) // Output: Matched, values: [1 2] | |||
| } else { | |||
| fmt.Println("No match found") | |||
| } | |||
| values, matched = trie.Match("/openkf/v1") | |||
| if matched { | |||
| fmt.Printf("Matched, values: %#v\n", reflect.ValueOf(values)) // Output: Matched, values: [1 2] | |||
| } else { | |||
| fmt.Println("No match found") | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| // Copyright © 2023 OpenIMSDK open source community. All rights reserved. | |||
| // Licensed under the MIT License (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| package models | |||
| import "time" | |||
| type Model struct { | |||
| ID uint `gorm:"primary_key" json:"id"` | |||
| CreatedAt time.Time `json:"created_at"` | |||
| UpdatedAt time.Time `json:"updated_at"` | |||
| DeletedAt *time.Time `sql:"index" json:"deleted_at"` | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| // Copyright © 2023 OpenIMSDK open source community. All rights reserved. | |||
| // Licensed under the MIT License (the "License"); | |||
| // you may not use this file except in compliance with the License. | |||
| package models | |||
| type User struct { | |||
| Model | |||
| Username string `json:"username" gorm:"type:varchar(20);not null;unique"` | |||
| Password string `json:"password" gorm:"type:varchar(20);not null"` | |||
| } | |||
| @@ -22,6 +22,7 @@ import ( | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/api" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/middleware" | |||
| urltrie "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks/url_trie" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| @@ -33,16 +34,17 @@ func InitRouter() *gin.Engine { | |||
| } | |||
| r := gin.Default() | |||
| r.Use(middleware.EnableCROS()) | |||
| r.Use(urltrie.RunHook(), middleware.EnableCROS()) | |||
| // swagger | |||
| r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) | |||
| apiv1 := r.Group("/api/v1") | |||
| { | |||
| email := apiv1.Group("/email") | |||
| register := apiv1.Group("/register") | |||
| { | |||
| email.POST("/code", api.SendCode) | |||
| register.POST("/email/code", api.SendCode) | |||
| // register.POST("/github", api.GithubRegister) | |||
| } | |||
| } | |||
| @@ -7,7 +7,7 @@ package service | |||
| import ( | |||
| "context" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/db" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/db" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/go-redis/redis/v8" | |||
| "gorm.io/gorm" | |||
| @@ -7,8 +7,9 @@ package service | |||
| import ( | |||
| "time" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/client" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/client" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/utils" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| func (svc *Service) SendCode(email string) (err error) { | |||
| @@ -29,3 +30,7 @@ func (svc *Service) SendCode(email string) (err error) { | |||
| return err | |||
| } | |||
| func (svc *Service) Test() { | |||
| log.Info("test...") | |||
| } | |||
| @@ -18,9 +18,10 @@ import ( | |||
| "flag" | |||
| "fmt" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/client" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/db" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/client" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/db" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/router" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/utils" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| @@ -39,6 +40,7 @@ func init() { | |||
| db.InitMysqlDB() | |||
| db.InitRedisDB() | |||
| client.InitMinio() | |||
| hooks.InitHooks() | |||
| } | |||
| //go:generate go env -w GO111MODULE=on | |||