| @@ -0,0 +1,76 @@ | |||
| // 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 api | |||
| import ( | |||
| "fmt" | |||
| "net/http" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common/response" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/param" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // OpenIMCallback | |||
| // @Tags openim | |||
| // @Summary OpenIMCallback | |||
| // @Description Support OpenIM callback | |||
| // @Produce application/json | |||
| // @Success 200 {object} response.Response{msg=string} "Success" | |||
| // @Router /api/v1/openim/callback [post]. | |||
| func OpenIMCallback(c *gin.Context) { | |||
| param := ¶m.OpenIMCallbackCommand{} | |||
| err := c.ShouldBindQuery(param) | |||
| if err != nil { | |||
| // todo | |||
| response.FailWithCode(common.INVALID_PARAMS, c) | |||
| return | |||
| } | |||
| // redirect to the corresponding router | |||
| callbackURL := fmt.Sprintf("%s%s", c.Request.URL.Path, param.Command) | |||
| c.Request.URL.Path = callbackURL | |||
| c.Redirect(http.StatusTemporaryRedirect, callbackURL) | |||
| } | |||
| // BeforeSendSingleMsg | |||
| func BeforeSendSingleMsg(c *gin.Context) { | |||
| } | |||
| // AfterSendSingleMsg | |||
| func AfterSendSingleMsg(c *gin.Context) { | |||
| } | |||
| // MsgModify | |||
| func MsgModify(c *gin.Context) { | |||
| } | |||
| // UserOnline | |||
| func UserOnline(c *gin.Context) { | |||
| } | |||
| // UserOffline | |||
| func UserOffline(c *gin.Context) { | |||
| } | |||
| // OfflinePush | |||
| func OfflinePush(c *gin.Context) { | |||
| } | |||
| // OnlinePush | |||
| func OnlinePush(c *gin.Context) { | |||
| } | |||
| @@ -15,12 +15,13 @@ | |||
| package api | |||
| import ( | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common/response" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/param" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/service" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // SendCode | |||
| @@ -19,4 +19,8 @@ const ( | |||
| SUCCESS = 200 | |||
| ERROR = 500 | |||
| INVALID_PARAMS = 400 | |||
| // OpenIM callback code. | |||
| OPENIM_SERVER_ALLOW_ACTION = 0 | |||
| OPENIM_SERVER_DENY_ACTION = 1 | |||
| ) | |||
| @@ -19,6 +19,10 @@ var msg = map[int]string{ | |||
| SUCCESS: "success", | |||
| ERROR: "error", | |||
| INVALID_PARAMS: "request params error", | |||
| // OpenIM callback code | |||
| OPENIM_SERVER_ALLOW_ACTION: "OpenIM allow action", | |||
| OPENIM_SERVER_DENY_ACTION: "OpenIM deny action", | |||
| } | |||
| // GetMsg get the message by code. | |||
| @@ -0,0 +1,174 @@ | |||
| // 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 response | |||
| import ( | |||
| "net/http" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common" | |||
| ) | |||
| // CommonCallbackResp Common callback response. | |||
| type CommonCallbackResp struct { | |||
| ActionCode int `json:"actionCode"` | |||
| ErrCode int32 `json:"errCode"` | |||
| ErrMsg string `json:"errMsg"` | |||
| ErrDlt string `json:"errDlt"` | |||
| } | |||
| // NewCommonCallbackResp Create a new CommonCallbackResp. | |||
| func NewCommonCallbackResp(actionCode int, errCode int32, errMsg string, errDlt string, c *gin.Context) { | |||
| c.JSON(http.StatusOK, &CommonCallbackResp{ | |||
| ActionCode: actionCode, | |||
| ErrCode: errCode, | |||
| ErrMsg: errMsg, | |||
| ErrDlt: errDlt, | |||
| }) | |||
| } | |||
| // CallbackBeforeSendSingleMsgResp Response body for BeforeSendSingleMsgCommand. | |||
| type CallbackBeforeSendSingleMsgResp struct { | |||
| CommonCallbackResp | |||
| } | |||
| // CallbackBeforeSendSingleMsgRespSuccess CallbackBeforeSendSingleMsgResp success response. | |||
| func CallbackBeforeSendSingleMsgRespSuccess(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackBeforeSendSingleMsgRespFail CallbackBeforeSendSingleMsgResp fail response. | |||
| func CallbackBeforeSendSingleMsgRespFail(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_DENY_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackAfterSendSingleMsgResp Response body for AfterSendSingleMsgCommand. | |||
| type CallbackAfterSendSingleMsgResp struct { | |||
| CommonCallbackResp | |||
| } | |||
| // CallbackAfterSendSingleMsgRespSuccess CallbackAfterSendSingleMsgResp success response. | |||
| func CallbackAfterSendSingleMsgRespSuccess(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackAfterSendSingleMsgRespFail CallbackAfterSendSingleMsgResp fail response. | |||
| func CallbackAfterSendSingleMsgRespFail(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_DENY_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackMsgModifyCommandResp Response body for MsgModifyCommand. | |||
| type CallbackMsgModifyCommandResp struct { | |||
| // todo: need to modify | |||
| CommonCallbackResp | |||
| Content *string `json:"content"` | |||
| RecvID *string `json:"recvID"` | |||
| GroupID *string `json:"groupID"` | |||
| ClientMsgID *string `json:"clientMsgID"` | |||
| ServerMsgID *string `json:"serverMsgID"` | |||
| SenderPlatformID *int32 `json:"senderPlatformID"` | |||
| SenderNickname *string `json:"senderNickname"` | |||
| SenderFaceURL *string `json:"senderFaceURL"` | |||
| SessionType *int32 `json:"sessionType"` | |||
| MsgFrom *int32 `json:"msgFrom"` | |||
| ContentType *int32 `json:"contentType"` | |||
| Status *int32 `json:"status"` | |||
| Options *map[string]bool `json:"options"` | |||
| OfflinePushInfo interface{} `json:"offlinePushInfo"` | |||
| // OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"` | |||
| AtUserIDList *[]string `json:"atUserIDList"` | |||
| MsgDataList *[]byte `json:"msgDataList"` | |||
| AttachedInfo *string `json:"attachedInfo"` | |||
| Ex *string `json:"ex"` | |||
| } | |||
| // CallbackUserOnlineResp Response body for UserOnlineCommand. | |||
| type CallbackUserOnlineResp struct { | |||
| CommonCallbackResp | |||
| } | |||
| // CallbackUserOnlineRespSuccess CallbackUserOnlineResp success response. | |||
| func CallbackUserOnlineRespSuccess(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackUserOnlineRespFail CallbackUserOnlineResp fail response. | |||
| func CallbackUserOnlineRespFail(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_DENY_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackUserOfflineResp Response body for UserOfflineCommand. | |||
| type CallbackUserOfflineResp struct { | |||
| CommonCallbackResp | |||
| } | |||
| // CallbackUserOfflineRespSuccess CallbackUserOfflineResp success response. | |||
| func CallbackUserOfflineRespSuccess(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| // CallbackUserOfflineRespFail CallbackUserOfflineResp fail response. | |||
| func CallbackUserOfflineRespFail(c *gin.Context) { | |||
| NewCommonCallbackResp( | |||
| common.OPENIM_SERVER_DENY_ACTION, | |||
| common.OPENIM_SERVER_ALLOW_ACTION, | |||
| common.GetMsg(common.OPENIM_SERVER_ALLOW_ACTION), | |||
| "", // todo | |||
| c, | |||
| ) | |||
| } | |||
| @@ -17,18 +17,19 @@ package response | |||
| import ( | |||
| "net/http" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/common" | |||
| ) | |||
| // Response is a common struct for response | |||
| // 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 | |||
| // NewResponse returns a new Response. | |||
| func NewResponse(code int, msg string, data interface{}, c *gin.Context) { | |||
| c.JSON(http.StatusOK, &Response{ | |||
| Code: code, | |||
| @@ -37,42 +38,42 @@ func NewResponse(code int, msg string, data interface{}, c *gin.Context) { | |||
| }) | |||
| } | |||
| // Success returns a success response | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // 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) | |||
| } | |||
| @@ -14,10 +14,10 @@ | |||
| package config | |||
| // Config global config instance | |||
| // Config global config instance. | |||
| var Config *config | |||
| // ConfigInit init config | |||
| // ConfigInit init config. | |||
| func ConfigInit(configPath string) { | |||
| // init viper | |||
| initViper(configPath) | |||
| @@ -83,27 +83,27 @@ type config struct { | |||
| Email Email | |||
| } | |||
| // App config | |||
| // App config. | |||
| type App struct { | |||
| Version string `mapstructure:"version"` | |||
| Debug bool `mapstructure:"debug"` | |||
| LogFile string `mapstructure:"log_file"` | |||
| } | |||
| // JWT config | |||
| // JWT config. | |||
| type JWT struct { | |||
| Secret string `mapstructure:"secret"` | |||
| Issuer string `mapstructure:"issuer"` | |||
| ExpireDays int `mapstructure:"expire_days"` | |||
| } | |||
| // Server config | |||
| // Server config. | |||
| type Server struct { | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| } | |||
| // Mysql config | |||
| // Mysql config. | |||
| type Mysql struct { | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| @@ -115,7 +115,7 @@ type Mysql struct { | |||
| MaxIdleConns int `mapstructure:"max_idle_conns"` | |||
| } | |||
| // Redis config | |||
| // Redis config. | |||
| type Redis struct { | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| @@ -123,7 +123,7 @@ type Redis struct { | |||
| Database int `mapstructure:"database"` | |||
| } | |||
| // Minio config | |||
| // Minio config. | |||
| type Minio struct { | |||
| Ip string `mapstructure:"ip"` | |||
| Port int `mapstructure:"port"` | |||
| @@ -134,7 +134,7 @@ type Minio struct { | |||
| Location string `mapstructure:"location"` | |||
| } | |||
| // Email config | |||
| // Email config. | |||
| type Email struct { | |||
| Host string `mapstructure:"host"` | |||
| Port int `mapstructure:"port"` | |||
| @@ -18,14 +18,15 @@ import ( | |||
| "fmt" | |||
| "net/smtp" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/jordan-wright/email" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| ) | |||
| // 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 | |||
| // SendEmail send email. | |||
| func SendEmail(to string, subject string, body string) error { | |||
| email := email.NewEmail() | |||
| @@ -46,7 +47,7 @@ func SendEmail(to string, subject string, body string) error { | |||
| return nil | |||
| } | |||
| // SendHtmlEmail send html email | |||
| // SendHtmlEmail send html email. | |||
| func SendHtmlEmail(to string, subject string, html string) error { | |||
| email := email.NewEmail() | |||
| @@ -19,16 +19,19 @@ import ( | |||
| "fmt" | |||
| "io" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/minio/minio-go/v7" | |||
| "github.com/minio/minio-go/v7/pkg/credentials" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| var _minioClient *minio.Client | |||
| var _bucket string | |||
| var ( | |||
| _minioClient *minio.Client | |||
| _bucket string | |||
| ) | |||
| // InitMinio init minio client | |||
| // InitMinio init minio client. | |||
| func InitMinio() { | |||
| endpoint := fmt.Sprintf("%s:%d", config.Config.Minio.Ip, config.Config.Minio.Port) | |||
| accessKeyID := config.Config.Minio.AccessKeyId | |||
| @@ -66,14 +69,14 @@ func InitMinio() { | |||
| _minioClient = minioClient | |||
| } | |||
| // PutObject put object to minio | |||
| // 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 | |||
| // GetObject get object from minio. | |||
| func GetObject(objectName string) (io.Reader, error) { | |||
| object, err := _minioClient.GetObject(context.Background(), _bucket, objectName, minio.GetObjectOptions{}) | |||
| @@ -18,18 +18,19 @@ import ( | |||
| "fmt" | |||
| "time" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "gorm.io/driver/mysql" | |||
| "gorm.io/gorm" | |||
| "gorm.io/gorm/logger" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| var d *gorm.DB | |||
| type writer struct{} | |||
| // Write implement log writer interface | |||
| // Write implement log writer interface. | |||
| func (w writer) Printf(format string, args ...interface{}) { | |||
| fmt.Printf(format, args...) | |||
| } | |||
| @@ -18,14 +18,15 @@ import ( | |||
| "context" | |||
| "fmt" | |||
| "github.com/go-redis/redis/v8" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/go-redis/redis/v8" | |||
| ) | |||
| var r *redis.Client | |||
| // InitRedisDB init 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), | |||
| @@ -40,12 +41,12 @@ func InitRedisDB() { | |||
| } | |||
| } | |||
| // GetRedis get redis client instance | |||
| // GetRedis get redis client instance. | |||
| func GetRedis() *redis.Client { | |||
| return r | |||
| } | |||
| // CloseRedis close redis client instance | |||
| // CloseRedis close redis client instance. | |||
| func CloseRedis() { | |||
| if r != nil { | |||
| err := r.Close() | |||
| @@ -20,7 +20,7 @@ import ( | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // EnableCROS enable cros | |||
| // EnableCROS enable cros. | |||
| func EnableCROS() gin.HandlerFunc { | |||
| return func(c *gin.Context) { | |||
| // c.Writer.Header().Set("Access-Control-Allow-Origin", "*") | |||
| @@ -7,16 +7,16 @@ import ( | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // define rate limit struct | |||
| // define rate limit struct. | |||
| type frequencyControlByTokenBucket struct { | |||
| refreshRate float64 // 令牌的刷新速率 | |||
| capacity int64 // bucket's capacity | |||
| tokens float64 // tokens' count | |||
| lastToken time.Time //latest time token stored | |||
| refreshRate float64 // token refresh rate | |||
| capacity int64 // bucket capacity | |||
| tokens float64 // token count | |||
| lastToken time.Time // latest time token stored | |||
| mtx sync.Mutex // mutex | |||
| } | |||
| // allow frequency | |||
| // allow frequency. | |||
| func (tb *frequencyControlByTokenBucket) Allow() bool { | |||
| tb.mtx.Lock() | |||
| defer tb.mtx.Unlock() | |||
| @@ -30,13 +30,14 @@ func (tb *frequencyControlByTokenBucket) Allow() bool { | |||
| if tb.tokens >= 1 { | |||
| tb.tokens-- | |||
| tb.lastToken = now | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| // LimitHandler registried a middle ware to use | |||
| // LimitHandler registried a middle ware to use. | |||
| func LimitHandler(maxConn int, refreshRate float64) gin.HandlerFunc { | |||
| tb := &frequencyControlByTokenBucket{ | |||
| capacity: int64(maxConn), | |||
| @@ -44,11 +45,12 @@ func LimitHandler(maxConn int, refreshRate float64) gin.HandlerFunc { | |||
| tokens: 0, | |||
| lastToken: time.Now(), | |||
| } | |||
| return func(c *gin.Context) { | |||
| if !tb.Allow() { | |||
| c.String(503, "Too many request") | |||
| c.Abort() | |||
| return | |||
| } | |||
| c.Next() | |||
| @@ -17,9 +17,9 @@ 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" | |||
| urltrie "github.com/OpenIMSDK/OpenKF/server/internal/middleware/hooks/url_trie" | |||
| ) | |||
| func init() { | |||
| @@ -27,23 +27,22 @@ func init() { | |||
| fmt.Println("RegisterHook", "Register Hook[GlobalHook] success...") | |||
| } | |||
| // GlobalHook implement urltrie.Hook | |||
| // GlobalHook implement urltrie.Hook. | |||
| type GlobalHook struct { | |||
| urltrie.Hook | |||
| } | |||
| // Pattern return pattern | |||
| // Pattern return pattern. | |||
| func (h GlobalHook) Pattern() string { | |||
| return "/*" | |||
| } | |||
| // BeforeRun do something before controller run | |||
| // 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 | |||
| // AfterRun do something after controller run. | |||
| func (h GlobalHook) AfterRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| @@ -14,6 +14,6 @@ | |||
| package hooks | |||
| // InitHooks manual import hooks packages and do init | |||
| // InitHooks manual import hooks packages and do init. | |||
| func InitHooks() { | |||
| } | |||
| @@ -17,9 +17,10 @@ package hooks | |||
| import ( | |||
| "fmt" | |||
| "github.com/gin-gonic/gin" | |||
| 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() { | |||
| @@ -27,23 +28,23 @@ func init() { | |||
| fmt.Println("RegisterHook", "Register Hook[MailHook] success...") | |||
| } | |||
| // MailHook implement urltrie.Hook | |||
| // MailHook implement urltrie.Hook. | |||
| type MailHook struct { | |||
| urltrie.Hook | |||
| } | |||
| // Pattern return pattern | |||
| // Pattern return pattern. | |||
| func (h MailHook) Pattern() string { | |||
| return "/api/v1/register/email/code" | |||
| } | |||
| // BeforeRun do something before controller run | |||
| // 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 | |||
| // AfterRun do something after controller run. | |||
| func (h MailHook) AfterRun(c *gin.Context) { | |||
| c.Next() | |||
| } | |||
| @@ -17,23 +17,24 @@ package urltrie | |||
| import ( | |||
| "net/url" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| // Mapping for store url pattern and hook | |||
| // Mapping for store url pattern and hook. | |||
| var hookTrie *Trie | |||
| func init() { | |||
| hookTrie = NewTrie() | |||
| } | |||
| // RegisterHook register url & hook to trie | |||
| // RegisterHook register url & hook to trie. | |||
| func RegisterHook(hook Hook) { | |||
| hookTrie.Insert(hook.Pattern(), hook) | |||
| } | |||
| // RunHook enable hook for interceptor | |||
| // RunHook enable hook for interceptor. | |||
| func RunHook() gin.HandlerFunc { | |||
| return func(c *gin.Context) { | |||
| raw := c.Request.URL.Path | |||
| @@ -20,7 +20,7 @@ import ( | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // Hook for interceptor | |||
| // Hook for interceptor. | |||
| type Hook interface { | |||
| // Register with url pattern | |||
| // Support * wildcard, you can use it like this: | |||
| @@ -46,12 +46,12 @@ type node struct { | |||
| isEnd bool | |||
| } | |||
| // Trie is a tree for url | |||
| // Trie is a tree for url. | |||
| type Trie struct { | |||
| root *node | |||
| } | |||
| // NewTrie returns a new Trie | |||
| // NewTrie returns a new Trie. | |||
| func NewTrie() *Trie { | |||
| return &Trie{ | |||
| root: &node{ | |||
| @@ -60,7 +60,7 @@ func NewTrie() *Trie { | |||
| } | |||
| } | |||
| // Insert insert url with hooks | |||
| // Insert insert url with hooks. | |||
| func (t *Trie) Insert(url string, hooks ...Hook) { | |||
| current := t.root | |||
| @@ -94,7 +94,7 @@ func (t *Trie) Insert(url string, hooks ...Hook) { | |||
| current.hooks = append(current.hooks, hooks...) | |||
| } | |||
| // Match match url with hooks | |||
| // Match match url with hooks. | |||
| func (t *Trie) Match(url string) ([]Hook, bool) { | |||
| current := t.root | |||
| @@ -18,11 +18,12 @@ import ( | |||
| "net/http" | |||
| "strings" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/utils" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/utils" | |||
| ) | |||
| // EnableAuth enable auth middleware | |||
| // EnableAuth enable auth middleware. | |||
| func EnableAuth() gin.HandlerFunc { | |||
| return func(c *gin.Context) { | |||
| token := c.GetHeader("Authorization") | |||
| @@ -16,7 +16,7 @@ package models | |||
| import "time" | |||
| // Model base model | |||
| // Model base model. | |||
| type Model struct { | |||
| ID uint `gorm:"primary_key" json:"id"` | |||
| CreatedAt time.Time `json:"created_at"` | |||
| @@ -14,7 +14,7 @@ | |||
| package models | |||
| // User user model | |||
| // User user model. | |||
| type User struct { | |||
| Model | |||
| Username string `json:"username" gorm:"type:varchar(20);not null;unique"` | |||
| @@ -0,0 +1,83 @@ | |||
| // 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 param | |||
| // OpenIMCallbackCommand OpenIM callback request command. | |||
| type OpenIMCallbackCommand struct { | |||
| Command string `form:"command" json:"command"` | |||
| } | |||
| // CommonCallbackReq Common callback request command. | |||
| type CommonCallbackReq struct { | |||
| SendID string `json:"sendID"` | |||
| CallbackCommand string `json:"callbackCommand"` | |||
| ServerMsgID string `json:"serverMsgID"` | |||
| ClientMsgID string `json:"clientMsgID"` | |||
| OperationID string `json:"operationID"` | |||
| SenderPlatformID int32 `json:"senderPlatformID"` | |||
| SenderNickname string `json:"senderNickname"` | |||
| SessionType int32 `json:"sessionType"` | |||
| MsgFrom int32 `json:"msgFrom"` | |||
| ContentType int32 `json:"contentType"` | |||
| Status int32 `json:"status"` | |||
| CreateTime int64 `json:"createTime"` | |||
| Content string `json:"content"` | |||
| Seq uint32 `json:"seq"` | |||
| AtUserIDList []string `json:"atUserList"` | |||
| SenderFaceURL string `json:"faceURL"` | |||
| Ex string `json:"ex"` | |||
| } | |||
| // CallbackBeforeSendSingleMsgReq Request body for BeforeSendSingleMsgCommand. | |||
| type CallbackBeforeSendSingleMsgReq struct { | |||
| CommonCallbackReq | |||
| RecvID string `json:"recvID"` | |||
| } | |||
| // CallbackAfterSendSingleMsgReq Request body for AfterSendSingleMsgCommand. | |||
| type CallbackAfterSendSingleMsgReq struct { | |||
| CommonCallbackReq | |||
| RecvID string `json:"recvID"` | |||
| } | |||
| // CallbackMsgModifyCommandReq Request body for MsgModifyCommand. | |||
| type CallbackMsgModifyCommandReq struct { | |||
| CommonCallbackReq | |||
| } | |||
| // UserStatusBaseCallback Common user callback request command. | |||
| type UserStatusBaseCallback struct { | |||
| CallbackCommand string `json:"callbackCommand"` | |||
| OperationID string `json:"operationID"` | |||
| PlatformID int `json:"platformID"` | |||
| Platform string `json:"platform"` | |||
| UserID string `json:"userID"` | |||
| } | |||
| // CallbackUserOnlineReq Request body for UserOnlineCommand. | |||
| type CallbackUserOnlineReq struct { | |||
| UserStatusBaseCallback | |||
| // Token string `json:"token"` | |||
| Seq int64 `json:"seq"` | |||
| IsAppBackground bool `json:"isAppBackground"` | |||
| ConnID string `json:"connID"` | |||
| } | |||
| // CallbackUserOfflineReq Request body for UserOfflineCommand. | |||
| type CallbackUserOfflineReq struct { | |||
| UserStatusBaseCallback | |||
| Seq int64 `json:"seq"` | |||
| ConnID string `json:"connID"` | |||
| } | |||
| @@ -47,6 +47,19 @@ func InitRouter() *gin.Engine { | |||
| register.POST("/email/code", api.SendCode) | |||
| // register.POST("/github", api.GithubRegister) | |||
| } | |||
| // OpenIM callback api | |||
| command := apiv1.Group("/openim/callback") | |||
| { | |||
| command.POST("/", api.OpenIMCallback) | |||
| command.POST("/callbackBeforeSendSingleMsgCommand", api.BeforeSendSingleMsg) | |||
| command.POST("/callbackAfterSendSingleMsgCommand", api.AfterSendSingleMsg) | |||
| command.POST("/callbackMsgModifyCommand", api.MsgModify) | |||
| command.POST("/callbackUserOnlineCommand", api.UserOnline) | |||
| command.POST("/callbackUserOfflineCommand", api.UserOffline) | |||
| command.POST("/callbackOfflinePushCommand", api.OfflinePush) | |||
| command.POST("/callbackOnlinePushCommand", api.OnlinePush) | |||
| } | |||
| } | |||
| return r | |||
| @@ -17,13 +17,14 @@ package service | |||
| import ( | |||
| "context" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/db" | |||
| "github.com/gin-gonic/gin" | |||
| "github.com/go-redis/redis/v8" | |||
| "gorm.io/gorm" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/conn/db" | |||
| ) | |||
| // Service service | |||
| // Service service. | |||
| type Service struct { | |||
| // Context | |||
| Ctx context.Context | |||
| @@ -33,7 +34,7 @@ type Service struct { | |||
| Cache *redis.Client | |||
| } | |||
| // NewService return new service with context | |||
| // NewService return new service with context. | |||
| func NewService() *Service { | |||
| return &Service{ | |||
| Ctx: context.Background(), | |||
| @@ -42,7 +43,7 @@ func NewService() *Service { | |||
| } | |||
| } | |||
| // NewServiceWithGin return new service with gin context | |||
| // NewServiceWithGin return new service with gin context. | |||
| func NewServiceWithGin(c *gin.Context) *Service { | |||
| return &Service{ | |||
| Ctx: c.Request.Context(), | |||
| @@ -22,7 +22,7 @@ import ( | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/log" | |||
| ) | |||
| // SendCode send code to email | |||
| // 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) | |||
| @@ -42,7 +42,7 @@ func (svc *Service) SendCode(email string) (err error) { | |||
| return err | |||
| } | |||
| // Test test | |||
| // Test test. | |||
| func (svc *Service) Test() { | |||
| log.Info("test...") | |||
| } | |||
| @@ -0,0 +1,77 @@ | |||
| # 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. | |||
| # diff config in OpenIM-Server | |||
| secret: openkf | |||
| callback: | |||
| url: http://127.0.0.1:10010/api/v1/openim/callback | |||
| beforeSendSingleMsg: | |||
| enable: true | |||
| timeout: 5 | |||
| failedContinue: true | |||
| afterSendSingleMsg: | |||
| enable: true | |||
| timeout: 5 | |||
| beforeSendGroupMsg: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| afterSendGroupMsg: | |||
| enable: false | |||
| timeout: 5 | |||
| msgModify: | |||
| enable: true | |||
| timeout: 5 | |||
| failedContinue: true | |||
| userOnline: | |||
| enable: true | |||
| timeout: 5 | |||
| userOffline: | |||
| enable: true | |||
| timeout: 5 | |||
| userKickOff: | |||
| enable: false | |||
| timeout: 5 | |||
| offlinePush: | |||
| enable: true | |||
| timeout: 5 | |||
| failedContinue: true | |||
| onlinePush: | |||
| enable: true | |||
| timeout: 5 | |||
| failedContinue: true | |||
| superGroupOnlinePush: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| beforeAddFriend: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| beforeCreateGroup: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| beforeMemberJoinGroup: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| beforeSetGroupMemberInfo: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| setMessageReactionExtensions: | |||
| enable: false | |||
| timeout: 5 | |||
| failedContinue: true | |||
| @@ -18,8 +18,9 @@ import ( | |||
| "runtime" | |||
| "strings" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/utils" | |||
| "github.com/sirupsen/logrus" | |||
| "github.com/OpenIMSDK/OpenKF/server/pkg/utils" | |||
| ) | |||
| type filelineHook struct{} | |||
| @@ -20,16 +20,17 @@ import ( | |||
| "os" | |||
| "time" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| nested "github.com/antonfisher/nested-logrus-formatter" | |||
| rotatelogs "github.com/lestrrat-go/file-rotatelogs" | |||
| "github.com/rifflock/lfshook" | |||
| "github.com/sirupsen/logrus" | |||
| "github.com/OpenIMSDK/OpenKF/server/internal/config" | |||
| ) | |||
| var _logger *logrus.Logger | |||
| // InitLogger init logger | |||
| // InitLogger init logger. | |||
| func InitLogger() { | |||
| _logger = loggerInit() | |||
| } | |||
| @@ -70,7 +71,7 @@ func loggerInit() *logrus.Logger { | |||
| return logger | |||
| } | |||
| // NewLfsHook add fileline hook | |||
| // NewLfsHook add fileline hook. | |||
| func NewLfsHook(rotationTime time.Duration, maxRemainNum uint) logrus.Hook { | |||
| lfsHook := lfshook.NewHook(lfshook.WriterMap{ | |||
| logrus.DebugLevel: initRotateLogs(rotationTime, maxRemainNum), | |||
| @@ -99,61 +100,61 @@ func initRotateLogs(rotationTime time.Duration, maxRemainNum uint) *rotatelogs.R | |||
| } | |||
| } | |||
| // GetLogger get logger instance | |||
| // GetLogger get logger instance. | |||
| func GetLogger() *logrus.Logger { | |||
| return _logger | |||
| } | |||
| // Info log info | |||
| // Info log info. | |||
| func Info(Operation string, args ...interface{}) { | |||
| _logger.WithFields(logrus.Fields{ | |||
| "Operation": Operation, | |||
| }).Infoln(args...) | |||
| } | |||
| // Error log error | |||
| // Error log error. | |||
| func Error(Operation string, args ...interface{}) { | |||
| _logger.WithFields(logrus.Fields{ | |||
| "Operation": Operation, | |||
| }).Errorln(args...) | |||
| } | |||
| // Debug log debug | |||
| // Debug log debug. | |||
| func Debug(Operation string, args ...interface{}) { | |||
| _logger.WithFields(logrus.Fields{ | |||
| "Operation": Operation, | |||
| }).Debugln(args...) | |||
| } | |||
| // Panic log panic | |||
| // Panic log panic. | |||
| func Panic(Operation string, args ...interface{}) { | |||
| _logger.WithFields(logrus.Fields{ | |||
| "Operation": Operation, | |||
| }).Panicln(args...) | |||
| } | |||
| // Infof log info with format | |||
| // 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 | |||
| // 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 | |||
| // 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 | |||
| // Panicf log panic with format. | |||
| func Panicf(Operation string, format string, args ...interface{}) { | |||
| _logger.WithFields(logrus.Fields{ | |||
| "Operation": Operation, | |||
| @@ -21,12 +21,12 @@ import ( | |||
| "github.com/gin-gonic/gin" | |||
| ) | |||
| // Server server interface | |||
| // Server server interface. | |||
| type Server interface { | |||
| ListenAndServe() error | |||
| } | |||
| // InitServer init server | |||
| // InitServer init server. | |||
| func InitServer(address string, r *gin.Engine) Server { | |||
| server := endless.NewServer(address, r) | |||