diff --git a/install_im_compose.sh b/install_im_compose.sh new file mode 100644 index 000000000..36d3a4b73 --- /dev/null +++ b/install_im_compose.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +internet_ip=`curl ifconfig.me -s` +echo $internet_ip + +source .env +echo $MINIO_ENDPOINT +if [ $MINIO_ENDPOINT == "http://127.0.0.1:10005" ]; then + sed -i "s/127.0.0.1/${internet_ip}/" .env + +fi + +cd script ; +chmod +x *.sh ; +./init_pwd.sh +./env_check.sh; +cd .. ; +docker-compose -f im-compose.yaml up -d +docker ps + + + diff --git a/internal/api/group/group.go b/internal/api/group/group.go index 1cddd7ede..f22b4a322 100644 --- a/internal/api/group/group.go +++ b/internal/api/group/group.go @@ -6,6 +6,7 @@ import ( "Open_IM/pkg/common/constant" "Open_IM/pkg/common/log" "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/common/trace_log" "Open_IM/pkg/grpc-etcdv3/getcdv3" rpc "Open_IM/pkg/proto/group" open_im_sdk "Open_IM/pkg/proto/sdk_ws" @@ -1020,44 +1021,45 @@ func MuteGroupMember(c *gin.Context) { // @Failure 400 {object} api.Swagger400Resp "errCode为400 一般为参数输入错误, token未带上等" // @Router /group/cancel_mute_group_member [post] func CancelMuteGroupMember(c *gin.Context) { + x := trace_log.NewCtx(c, utils.GetSelfFuncName()) + defer trace_log.ShowLog(c) + params := api.CancelMuteGroupMemberReq{} if err := c.BindJSON(¶ms); err != nil { - log.NewError("0", "BindJSON failed ", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + trace_log.WriteErrorResponse(c, err) + trace_log.SetContextInfo(c, "BindJSON", err) return } + constant.SetContextInfo(c, "BindJSON", nil, "params", params) req := &rpc.CancelMuteGroupMemberReq{} utils.CopyStructFields(req, ¶ms) - var ok bool - var errInfo string - ok, req.OpUserID, errInfo = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) - if !ok { - errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token") - log.NewError(req.OperationID, errMsg) - c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg}) - return - } - - log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api args ", req.String()) - - etcdConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName, req.OperationID) - if etcdConn == nil { - errMsg := req.OperationID + "getcdv3.GetDefaultConn == nil" - log.NewError(req.OperationID, errMsg) - c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) - return - } - client := rpc.NewGroupClient(etcdConn) - reply, err := client.CancelMuteGroupMember(context.Background(), req) + var err error + err, req.OpUserID, _ = token_verify.ParseUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) if err != nil { - log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) - c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + constant.WriteErrorResponse(c, err) + constant.SetContextInfo(c, "ParseUserIDFromToken", err) + return + } + constant.SetContextInfo(c, "ParseUserIDFromToken", nil, "token", c.Request.Header.Get("token"), "OpUserID", req.OpUserID) + + etcdConn, err := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName, req.OperationID) + if err != nil { + constant.WriteErrorResponse(c, err) + constant.SetContextInfo(c, "GetDefaultConn", err) return } + client := rpc.NewGroupClient(etcdConn) + reply, err := client.CancelMuteGroupMember(x, req) + if err != nil { + constant.WriteErrorResponse(c, err) + constant.SetContextInfo(c, "CancelMuteGroupMember", err) + return + } + + constant.SetContextInfo(c, "CancelMuteGroupMember", nil, "req", req.String(), "resp", reply.String()) resp := api.CancelMuteGroupMemberResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} - log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) c.JSON(http.StatusOK, resp) } diff --git a/pkg/common/constant/error.go b/pkg/common/constant/error.go index ceffa1425..e30f3ca87 100644 --- a/pkg/common/constant/error.go +++ b/pkg/common/constant/error.go @@ -1,63 +1,51 @@ package constant -import "errors" - -// key = errCode, string = errMsg type ErrInfo struct { ErrCode int32 ErrMsg string } -var ( - OK = ErrInfo{0, ""} - ErrServer = ErrInfo{500, "server error"} +func (e ErrInfo) Error() string { + return e.ErrMsg +} - ErrParseToken = ErrInfo{700, ParseTokenMsg.Error()} - - ErrTencentCredential = ErrInfo{400, ThirdPartyMsg.Error()} - - ErrTokenExpired = ErrInfo{701, TokenExpiredMsg.Error()} - ErrTokenInvalid = ErrInfo{702, TokenInvalidMsg.Error()} - ErrTokenMalformed = ErrInfo{703, TokenMalformedMsg.Error()} - ErrTokenNotValidYet = ErrInfo{704, TokenNotValidYetMsg.Error()} - ErrTokenUnknown = ErrInfo{705, TokenUnknownMsg.Error()} - ErrTokenKicked = ErrInfo{706, TokenUserKickedMsg.Error()} - ErrTokenDifferentPlatformID = ErrInfo{707, TokenDifferentPlatformIDMsg.Error()} - ErrTokenDifferentUserID = ErrInfo{708, TokenDifferentUserIDMsg.Error()} - - ErrAccess = ErrInfo{ErrCode: 801, ErrMsg: AccessMsg.Error()} - ErrDB = ErrInfo{ErrCode: 802, ErrMsg: DBMsg.Error()} - ErrArgs = ErrInfo{ErrCode: 803, ErrMsg: ArgsMsg.Error()} - ErrStatus = ErrInfo{ErrCode: 804, ErrMsg: StatusMsg.Error()} - ErrCallback = ErrInfo{ErrCode: 809, ErrMsg: CallBackMsg.Error()} - ErrSendLimit = ErrInfo{ErrCode: 810, ErrMsg: "send msg limit, to many request, try again later"} - ErrMessageHasReadDisable = ErrInfo{ErrCode: 811, ErrMsg: "message has read disable"} - ErrInternal = ErrInfo{ErrCode: 812, ErrMsg: "internal error"} - ErrWsConnNotExist = ErrInfo{ErrCode: 813, ErrMsg: "ws conn not exist"} -) +func (e ErrInfo) Code() int32 { + return e.ErrCode +} var ( - ParseTokenMsg = errors.New("parse token failed") - TokenExpiredMsg = errors.New("token is timed out, please log in again") - TokenInvalidMsg = errors.New("token has been invalidated") - TokenNotValidYetMsg = errors.New("token not active yet") - TokenMalformedMsg = errors.New("that's not even a token") - TokenUnknownMsg = errors.New("couldn't handle this token") - TokenUserKickedMsg = errors.New("user has been kicked") - TokenDifferentPlatformIDMsg = errors.New("different platformID") - TokenDifferentUserIDMsg = errors.New("different userID") - AccessMsg = errors.New("no permission") - StatusMsg = errors.New("status is abnormal") - DBMsg = errors.New("db failed") - ArgsMsg = errors.New("args failed") - CallBackMsg = errors.New("callback failed") - InvitationMsg = errors.New("invitationCode error") + ErrNone = ErrInfo{0, ""} + ErrArgs = ErrInfo{ArgsError, "ArgsError"} + ErrDatabase = ErrInfo{DatabaseError, "DatabaseError"} + ErrInternalServer = ErrInfo{ServerInternalError, "ServerInternalError"} + ErrNetwork = ErrInfo{NetworkError, "NetworkError"} + ErrNoPermission = ErrInfo{NoPermissionError, "NoPermissionError"} - ThirdPartyMsg = errors.New("third party error") + ErrUserIDNotFound = ErrInfo{UserIDNotFoundError, "UserIDNotFoundError"} + ErrGroupIDNotFound = ErrInfo{GroupIDNotFoundError, "GroupIDNotFoundError"} + + ErrRelationshipAlready = ErrInfo{RelationshipAlreadyError, "RelationshipAlreadyError"} + ErrNotRelationshipYet = ErrInfo{NotRelationshipYetError, "NotRelationshipYetError"} + + ErrOnlyOneOwner = ErrInfo{OnlyOneOwnerError, "OnlyOneOwnerError"} + ErrInGroupAlready = ErrInfo{InGroupAlreadyError, "InGroupAlreadyError"} + ErrNotInGroupYet = ErrInfo{NotInGroupYetError, "NotInGroupYetError"} + ErrDismissedAlready = ErrInfo{DismissedAlreadyError, "DismissedAlreadyError"} + ErrOwnerNotAllowedQuit = ErrInfo{OwnerNotAllowedQuitError, "OwnerNotAllowedQuitError"} + ErrRegisteredAlready = ErrInfo{RegisteredAlreadyError, "RegisteredAlreadyError"} + + ErrTokenExpired = ErrInfo{TokenExpiredError, "TokenExpiredError"} + ErrTokenInvalid = ErrInfo{TokenInvalidError, "TokenInvalidError"} // + ErrTokenMalformed = ErrInfo{TokenMalformedError, "TokenMalformedError"} //格式错误 + ErrTokenNotValidYet = ErrInfo{TokenNotValidYetError, "TokenNotValidYetError"} //还未生效 + ErrTokenUnknown = ErrInfo{TokenUnknownError, "TokenUnknownError"} //未知错误 + ErrTokenKicked = ErrInfo{TokenKickedError, "TokenKickedError"} + ErrTokenNotExist = ErrInfo{TokenNotExistError, "TokenNotExistError"} //在redis中不存在 + ErrTokenDifferentPlatformID = ErrInfo{TokenDifferentPlatformIDError, "TokenDifferentPlatformIDError"} + ErrTokenDifferentUserID = ErrInfo{TokenDifferentUserIDError, "TokenDifferentUserIDError"} ) const ( - NoError = 0 FormattingError = 10001 HasRegistered = 10002 NotRegistered = 10003 @@ -72,17 +60,53 @@ const ( RegisterLimit = 10012 LoginLimit = 10013 InvitationError = 10014 - DatabaseError = 10002 - ServerError = 10004 - HttpError = 10005 - IoError = 10006 - IntentionalError = 10007 ) -func (e ErrInfo) Error() string { - return e.ErrMsg -} +// 通用错误码 +const ( + NoError = 0 //无错误 + ArgsError = 90001 //输入参数错误 + DatabaseError = 90002 //redis/mysql等db错误 + ServerInternalError = 90003 //服务器内部错误 + NetworkError = 90004 //网络错误 + NoPermissionError = 90005 //权限不足 +) -func (e *ErrInfo) Code() int32 { - return e.ErrCode -} +// 账号错误码 +const ( + UserIDNotFoundError = 91001 //UserID不存在 或未注册 + GroupIDNotFoundError = 91002 //GroupID不存在 +) + +// 关系链错误码 +const ( + RelationshipAlreadyError = 92001 //已经是好友关系(或者黑名单) + NotRelationshipYetError = 92002 //不是好友关系(或者黑名单) +) + +// 群组错误码 +const ( + OnlyOneOwnerError = 93001 //只能有一个群主 + InGroupAlreadyError = 93003 //已在群组中 + NotInGroupYetError = 93004 //不在群组中 + DismissedAlreadyError = 93004 //群组已经解散 + OwnerNotAllowedQuitError = 93004 //群主不能退群 +) + +// 用户错误码 +const ( + RegisteredAlreadyError = 94001 //用户已经注册过了 +) + +// token错误码 +const ( + TokenExpiredError = 95001 + TokenInvalidError = 95002 + TokenMalformedError = 95003 + TokenNotValidYetError = 95004 + TokenUnknownError = 95005 + TokenKickedError = 95006 + TokenDifferentPlatformIDError = 95007 + TokenDifferentUserIDError = 95008 + TokenNotExistError = 95009 +) diff --git a/pkg/common/token_verify/jwt_token.go b/pkg/common/token_verify/jwt_token.go index 5c3c1e07a..738be85da 100644 --- a/pkg/common/token_verify/jwt_token.go +++ b/pkg/common/token_verify/jwt_token.go @@ -110,13 +110,13 @@ func GetClaimFromToken(tokensString string) (*Claims, error) { return nil, utils.Wrap(constant.ErrTokenUnknown, "") } } else { - return nil, utils.Wrap(constant.ErrTokenNotValidYet, "") + return nil, utils.Wrap(constant.ErrTokenUnknown, "") } } else { if claims, ok := token.Claims.(*Claims); ok && token.Valid { return claims, nil } - return nil, utils.Wrap(constant.ErrTokenNotValidYet, "") + return nil, utils.Wrap(constant.ErrTokenUnknown, "") } } @@ -159,6 +159,16 @@ func GetUserIDFromToken(token string, operationID string) (bool, string, string) return true, claims.UID, "" } +func ParseUserIDFromToken(token string, operationID string) (error, string, string) { + claims, err := ParseToken(token, operationID) + if err != nil { + log.Error(operationID, "ParseToken failed, ", err.Error(), token) + return err, "", err.Error() + } + log.Debug(operationID, "token claims.ExpiresAt.Second() ", claims.ExpiresAt.Unix()) + return nil, claims.UID, "" +} + func GetUserIDFromTokenExpireTime(token string, operationID string) (bool, string, string, int64) { claims, err := ParseToken(token, operationID) if err != nil { @@ -184,12 +194,12 @@ func ParseToken(tokensString, operationID string) (claims *Claims, err error) { m, err := commonDB.DB.GetTokenMapByUidPid(claims.UID, claims.Platform) if err != nil { - log.NewError(operationID, "get token from redis err", err.Error(), tokensString) - return nil, utils.Wrap(constant.ErrTokenInvalid, "get token from redis err") + log.NewError(operationID, "get token from redis err", err.Error(), claims.UID, claims.Platform) + return nil, utils.Wrap(constant.ErrTokenNotExist, "get token from redis err") } if m == nil { - log.NewError(operationID, "get token from redis err, not in redis ", "m is nil", tokensString) - return nil, utils.Wrap(constant.ErrTokenInvalid, "get token from redis err") + log.NewError(operationID, "get token from redis err, not in redis ", "m is nil ", claims.UID, claims.Platform) + return nil, utils.Wrap(constant.ErrTokenNotExist, "get token from redis err") } if v, ok := m[tokensString]; ok { switch v { @@ -203,8 +213,8 @@ func ParseToken(tokensString, operationID string) (claims *Claims, err error) { return nil, utils.Wrap(constant.ErrTokenUnknown, "") } } - log.NewError(operationID, "redis token map not find", constant.ErrTokenUnknown) - return nil, utils.Wrap(constant.ErrTokenUnknown, "redis token map not find") + log.NewError(operationID, "redis token map not find ", constant.ErrTokenNotExist, tokensString) + return nil, utils.Wrap(constant.ErrTokenNotExist, "redis token map not find") } //func MakeTheTokenInvalid(currentClaims *Claims, platformClass string) (bool, error) { @@ -227,7 +237,7 @@ func ParseRedisInterfaceToken(redisToken interface{}) (*Claims, error) { return GetClaimFromToken(string(redisToken.([]uint8))) } -//Validation token, false means failure, true means successful verification +// Validation token, false means failure, true means successful verification func VerifyToken(token, uid string) (bool, error) { claims, err := ParseToken(token, "") if err != nil { diff --git a/pkg/common/trace_log/ctx.go b/pkg/common/trace_log/ctx.go new file mode 100644 index 000000000..09cce52a3 --- /dev/null +++ b/pkg/common/trace_log/ctx.go @@ -0,0 +1,77 @@ +package trace_log + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "context" + "errors" + "fmt" + "github.com/gin-gonic/gin" +) + +const TraceLogKey = "trace_log" +const GinContextKey = "gin_context" + +func ToErrInfoWithErr(errCode int32, errMsg string) *ErrInfo { + return nil +} + +func getAPIErrorResponse(c *gin.Context, errInfo ErrInfo) { + +} + +func NewCtx(c *gin.Context, api string) context.Context { + req := ApiInfo{ApiName: api} + return context.WithValue(c, GinContextKey, req) +} + +func ShowLog(ctx context.Context) { + t := ctx.Value(TraceLogKey).(ApiInfo) + log.Info(t.OperationID, "api: ", t.ApiName) + for _, v := range t.Funcs { + if v.Err != nil { + log.Error(v.FuncName, v.Err, v.Args) + } else { + log.Info(v.FuncName, v.Err, v.Args) + } + } + +} + +func WriteErrorResponse(c *gin.Context, err error) { + e := new(constant.ErrInfo) + if errors.As(err, &e) { + + } +} + +type FuncInfo struct { + FuncName string + Args map[string]interface{} + Err error +} + +type ApiInfo struct { + ApiName string + OperationID string + Funcs []FuncInfo +} + +func SetContextInfo(ctx context.Context, funcName string, err error, args ...interface{}) { + var req ReqInfo + t := ctx.Value("f").([]ReqInfo) + argsHandle(args, req.Args) + req.FuncName = funcName + req.Err = err + t = append(t, req) +} + +func argsHandle(args []interface{}, fields map[string]interface{}) { + for i := 0; i < len(args); i += 2 { + if i+1 < len(args) { + fields[fmt.Sprintf("%v", args[i])] = args[i+1] + } else { + fields[fmt.Sprintf("%v", args[i])] = "" + } + } +} diff --git a/pkg/grpc-etcdv3/getcdv3/resolver.go b/pkg/grpc-etcdv3/getcdv3/resolver.go index d2fda0cd9..ce987294f 100644 --- a/pkg/grpc-etcdv3/getcdv3/resolver.go +++ b/pkg/grpc-etcdv3/getcdv3/resolver.go @@ -175,14 +175,14 @@ func GetConfigConn(serviceName string, operationID string) *grpc.ClientConn { return conn } -func GetDefaultConn(schema, etcdaddr, serviceName string, operationID string) *grpc.ClientConn { +func GetDefaultConn(schema, etcdaddr, serviceName string, operationID string) (*grpc.ClientConn, error) { con := getConn(schema, etcdaddr, serviceName, operationID) if con != nil { - return con + return con, nil } log.NewWarn(operationID, utils.GetSelfFuncName(), "conn is nil !!!!!", schema, etcdaddr, serviceName, operationID) con = GetConfigConn(serviceName, operationID) - return con + return con, nil } func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {