mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-04-06 04:15:46 +08:00
msg cb
This commit is contained in:
parent
8435508f35
commit
1ae1f77a14
@ -5,18 +5,23 @@ import (
|
|||||||
"Open_IM/pkg/common/config"
|
"Open_IM/pkg/common/config"
|
||||||
"Open_IM/pkg/common/constant"
|
"Open_IM/pkg/common/constant"
|
||||||
"Open_IM/pkg/common/http"
|
"Open_IM/pkg/common/http"
|
||||||
"Open_IM/pkg/common/log"
|
"Open_IM/pkg/common/tracelog"
|
||||||
pbChat "Open_IM/pkg/proto/msg"
|
pbChat "Open_IM/pkg/proto/msg"
|
||||||
"Open_IM/pkg/utils"
|
"Open_IM/pkg/utils"
|
||||||
http2 "net/http"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func copyCallbackCommonReqStruct(msg *pbChat.SendMsgReq) cbapi.CommonCallbackReq {
|
func cbURL() string {
|
||||||
req := cbapi.CommonCallbackReq{
|
return config.Config.Callback.CallbackUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func toCommonCallback(ctx context.Context, msg *pbChat.SendMsgReq, command string) cbapi.CommonCallbackReq {
|
||||||
|
return cbapi.CommonCallbackReq{
|
||||||
SendID: msg.MsgData.SendID,
|
SendID: msg.MsgData.SendID,
|
||||||
ServerMsgID: msg.MsgData.ServerMsgID,
|
ServerMsgID: msg.MsgData.ServerMsgID,
|
||||||
|
CallbackCommand: command,
|
||||||
ClientMsgID: msg.MsgData.ClientMsgID,
|
ClientMsgID: msg.MsgData.ClientMsgID,
|
||||||
OperationID: msg.OperationID,
|
OperationID: tracelog.GetOperationID(ctx),
|
||||||
SenderPlatformID: msg.MsgData.SenderPlatformID,
|
SenderPlatformID: msg.MsgData.SenderPlatformID,
|
||||||
SenderNickname: msg.MsgData.SenderNickname,
|
SenderNickname: msg.MsgData.SenderNickname,
|
||||||
SessionType: msg.MsgData.SessionType,
|
SessionType: msg.MsgData.SessionType,
|
||||||
@ -30,198 +35,86 @@ func copyCallbackCommonReqStruct(msg *pbChat.SendMsgReq) cbapi.CommonCallbackReq
|
|||||||
Seq: msg.MsgData.Seq,
|
Seq: msg.MsgData.Seq,
|
||||||
Ex: msg.MsgData.Ex,
|
Ex: msg.MsgData.Ex,
|
||||||
}
|
}
|
||||||
return req
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func callbackBeforeSendSingleMsg(msg *pbChat.SendMsgReq) (err error) {
|
func CallbackBeforeSendSingleMsg(ctx context.Context, msg *pbChat.SendMsgReq) error {
|
||||||
callbackResp := cbapi.CommonCallbackResp{OperationID: msg.OperationID}
|
|
||||||
if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable {
|
if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable {
|
||||||
return callbackResp
|
return nil
|
||||||
}
|
}
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg)
|
req := &cbapi.CallbackBeforeSendSingleMsgReq{
|
||||||
commonCallbackReq := copyCallbackCommonReqStruct(msg)
|
CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendSingleMsgCommand),
|
||||||
commonCallbackReq.CallbackCommand = constant.CallbackBeforeSendSingleMsgCommand
|
|
||||||
req := cbapi.CallbackBeforeSendSingleMsgReq{
|
|
||||||
CommonCallbackReq: commonCallbackReq,
|
|
||||||
RecvID: msg.MsgData.RecvID,
|
RecvID: msg.MsgData.RecvID,
|
||||||
}
|
}
|
||||||
resp := &cbapi.CallbackBeforeSendSingleMsgResp{
|
resp := &cbapi.CallbackBeforeSendSingleMsgResp{}
|
||||||
CommonCallbackResp: &callbackResp,
|
return http.CallBackPostReturnV2(cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg)
|
||||||
}
|
|
||||||
//utils.CopyStructFields(req, msg.MsgData)
|
|
||||||
defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp)
|
|
||||||
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeSendSingleMsgCommand,
|
|
||||||
req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil {
|
|
||||||
callbackResp.ErrCode = http2.StatusInternalServerError
|
|
||||||
callbackResp.ErrMsg = err.Error()
|
|
||||||
if !*config.Config.Callback.CallbackBeforeSendSingleMsg.CallbackFailedContinue {
|
|
||||||
callbackResp.ActionCode = constant.ActionForbidden
|
|
||||||
return callbackResp
|
|
||||||
} else {
|
|
||||||
callbackResp.ActionCode = constant.ActionAllow
|
|
||||||
return callbackResp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func callbackAfterSendSingleMsg(msg *pbChat.SendMsgReq) error {
|
func CallbackAfterSendSingleMsg(ctx context.Context, msg *pbChat.SendMsgReq) error {
|
||||||
callbackResp := cbapi.CommonCallbackResp{OperationID: msg.OperationID}
|
|
||||||
if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable {
|
if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable {
|
||||||
return callbackResp
|
return nil
|
||||||
}
|
}
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg)
|
req := &cbapi.CallbackAfterSendSingleMsgReq{
|
||||||
commonCallbackReq := copyCallbackCommonReqStruct(msg)
|
CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendSingleMsgCommand),
|
||||||
commonCallbackReq.CallbackCommand = constant.CallbackAfterSendSingleMsgCommand
|
|
||||||
req := cbapi.CallbackAfterSendSingleMsgReq{
|
|
||||||
CommonCallbackReq: commonCallbackReq,
|
|
||||||
RecvID: msg.MsgData.RecvID,
|
RecvID: msg.MsgData.RecvID,
|
||||||
}
|
}
|
||||||
resp := &cbapi.CallbackAfterSendSingleMsgResp{CommonCallbackResp: &callbackResp}
|
resp := &cbapi.CallbackAfterSendSingleMsgResp{}
|
||||||
defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp)
|
return http.CallBackPostReturnV2(cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg)
|
||||||
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackAfterSendSingleMsgCommand,
|
|
||||||
req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil {
|
|
||||||
callbackResp.ErrCode = http2.StatusInternalServerError
|
|
||||||
callbackResp.ErrMsg = err.Error()
|
|
||||||
return callbackResp
|
|
||||||
}
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func callbackBeforeSendGroupMsg(msg *pbChat.SendMsgReq) error {
|
func CallbackBeforeSendGroupMsg(ctx context.Context, msg *pbChat.SendMsgReq) error {
|
||||||
callbackResp := cbapi.CommonCallbackResp{OperationID: msg.OperationID}
|
if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable {
|
||||||
if !config.Config.Callback.CallbackBeforeSendGroupMsg.Enable {
|
return nil
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg)
|
req := &cbapi.CallbackAfterSendGroupMsgReq{
|
||||||
commonCallbackReq := copyCallbackCommonReqStruct(msg)
|
CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendSingleMsgCommand),
|
||||||
commonCallbackReq.CallbackCommand = constant.CallbackBeforeSendGroupMsgCommand
|
|
||||||
req := cbapi.CallbackAfterSendGroupMsgReq{
|
|
||||||
CommonCallbackReq: commonCallbackReq,
|
|
||||||
GroupID: msg.MsgData.GroupID,
|
GroupID: msg.MsgData.GroupID,
|
||||||
}
|
}
|
||||||
resp := &cbapi.CallbackBeforeSendGroupMsgResp{CommonCallbackResp: &callbackResp}
|
resp := &cbapi.CallbackBeforeSendGroupMsgResp{}
|
||||||
defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp)
|
return http.CallBackPostReturnV2(cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg)
|
||||||
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeSendGroupMsgCommand,
|
|
||||||
req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil {
|
|
||||||
callbackResp.ErrCode = http2.StatusInternalServerError
|
|
||||||
callbackResp.ErrMsg = err.Error()
|
|
||||||
if !*config.Config.Callback.CallbackBeforeSendGroupMsg.CallbackFailedContinue {
|
|
||||||
callbackResp.ActionCode = constant.ActionForbidden
|
|
||||||
return callbackResp
|
|
||||||
} else {
|
|
||||||
callbackResp.ActionCode = constant.ActionAllow
|
|
||||||
return callbackResp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func callbackAfterSendGroupMsg(msg *pbChat.SendMsgReq) error {
|
func CallbackAfterSendGroupMsg(ctx context.Context, msg *pbChat.SendMsgReq) error {
|
||||||
callbackResp := cbapi.CommonCallbackResp{OperationID: msg.OperationID}
|
|
||||||
if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable {
|
if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable {
|
||||||
return callbackResp
|
return nil
|
||||||
}
|
}
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg)
|
req := &cbapi.CallbackAfterSendGroupMsgReq{
|
||||||
commonCallbackReq := copyCallbackCommonReqStruct(msg)
|
CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackAfterSendGroupMsgCommand),
|
||||||
commonCallbackReq.CallbackCommand = constant.CallbackAfterSendGroupMsgCommand
|
|
||||||
req := cbapi.CallbackAfterSendGroupMsgReq{
|
|
||||||
CommonCallbackReq: commonCallbackReq,
|
|
||||||
GroupID: msg.MsgData.GroupID,
|
GroupID: msg.MsgData.GroupID,
|
||||||
}
|
}
|
||||||
resp := &cbapi.CallbackAfterSendGroupMsgResp{CommonCallbackResp: &callbackResp}
|
resp := &cbapi.CallbackAfterSendGroupMsgResp{}
|
||||||
defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp)
|
return http.CallBackPostReturnV2(cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg)
|
||||||
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackAfterSendGroupMsgCommand, req, resp,
|
|
||||||
config.Config.Callback.CallbackAfterSendGroupMsg); err != nil {
|
|
||||||
callbackResp.ErrCode = http2.StatusInternalServerError
|
|
||||||
callbackResp.ErrMsg = err.Error()
|
|
||||||
return callbackResp
|
|
||||||
}
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func callbackMsgModify(msg *pbChat.SendMsgReq) (err error) {
|
func CallbackMsgModify(ctx context.Context, msg *pbChat.SendMsgReq) error {
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg)
|
|
||||||
callbackResp := cbapi.CommonCallbackResp{OperationID: msg.OperationID}
|
|
||||||
if !config.Config.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text {
|
if !config.Config.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text {
|
||||||
return callbackResp
|
return nil
|
||||||
}
|
}
|
||||||
commonCallbackReq := copyCallbackCommonReqStruct(msg)
|
req := &cbapi.CallbackMsgModifyCommandReq{
|
||||||
commonCallbackReq.CallbackCommand = constant.CallbackMsgModifyCommand
|
CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackMsgModifyCommand),
|
||||||
req := cbapi.CallbackMsgModifyCommandReq{
|
|
||||||
CommonCallbackReq: commonCallbackReq,
|
|
||||||
}
|
}
|
||||||
resp := &cbapi.CallbackMsgModifyCommandResp{CommonCallbackResp: &callbackResp}
|
resp := &cbapi.CallbackMsgModifyCommandResp{}
|
||||||
defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp)
|
if err := http.CallBackPostReturnV2(cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil {
|
||||||
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackMsgModifyCommand, req, resp,
|
return err
|
||||||
config.Config.Callback.CallbackMsgModify); err != nil {
|
|
||||||
callbackResp.ErrCode = http2.StatusInternalServerError
|
|
||||||
callbackResp.ErrMsg = err.Error()
|
|
||||||
if !*config.Config.Callback.CallbackMsgModify.CallbackFailedContinue {
|
|
||||||
callbackResp.ActionCode = constant.ActionForbidden
|
|
||||||
return callbackResp
|
|
||||||
} else {
|
|
||||||
callbackResp.ActionCode = constant.ActionAllow
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if resp.ErrCode == constant.CallbackHandleSuccess && resp.ActionCode == constant.ActionAllow {
|
|
||||||
if resp.Content != nil {
|
if resp.Content != nil {
|
||||||
msg.MsgData.Content = []byte(*resp.Content)
|
msg.MsgData.Content = []byte(*resp.Content)
|
||||||
}
|
}
|
||||||
if resp.RecvID != nil {
|
utils.NotNilReplace(msg.MsgData.OfflinePushInfo, resp.OfflinePushInfo)
|
||||||
msg.MsgData.RecvID = *resp.RecvID
|
utils.NotNilReplace(&msg.MsgData.RecvID, resp.RecvID)
|
||||||
}
|
utils.NotNilReplace(&msg.MsgData.GroupID, resp.GroupID)
|
||||||
if resp.GroupID != nil {
|
utils.NotNilReplace(&msg.MsgData.ClientMsgID, resp.ClientMsgID)
|
||||||
msg.MsgData.GroupID = *resp.GroupID
|
utils.NotNilReplace(&msg.MsgData.ServerMsgID, resp.ServerMsgID)
|
||||||
}
|
utils.NotNilReplace(&msg.MsgData.SenderPlatformID, resp.SenderPlatformID)
|
||||||
if resp.ClientMsgID != nil {
|
utils.NotNilReplace(&msg.MsgData.SenderNickname, resp.SenderNickname)
|
||||||
msg.MsgData.ClientMsgID = *resp.ClientMsgID
|
utils.NotNilReplace(&msg.MsgData.SenderFaceURL, resp.SenderFaceURL)
|
||||||
}
|
utils.NotNilReplace(&msg.MsgData.SessionType, resp.SessionType)
|
||||||
if resp.ServerMsgID != nil {
|
utils.NotNilReplace(&msg.MsgData.MsgFrom, resp.MsgFrom)
|
||||||
msg.MsgData.ServerMsgID = *resp.ServerMsgID
|
utils.NotNilReplace(&msg.MsgData.ContentType, resp.ContentType)
|
||||||
}
|
utils.NotNilReplace(&msg.MsgData.Status, resp.Status)
|
||||||
if resp.SenderPlatformID != nil {
|
utils.NotNilReplace(&msg.MsgData.Options, resp.Options)
|
||||||
msg.MsgData.SenderPlatformID = *resp.SenderPlatformID
|
utils.NotNilReplace(&msg.MsgData.AtUserIDList, resp.AtUserIDList)
|
||||||
}
|
utils.NotNilReplace(&msg.MsgData.MsgDataList, resp.MsgDataList)
|
||||||
if resp.SenderNickname != nil {
|
utils.NotNilReplace(&msg.MsgData.AttachedInfo, resp.AttachedInfo)
|
||||||
msg.MsgData.SenderNickname = *resp.SenderNickname
|
utils.NotNilReplace(&msg.MsgData.Ex, resp.Ex)
|
||||||
}
|
return nil
|
||||||
if resp.SenderFaceURL != nil {
|
|
||||||
msg.MsgData.SenderFaceURL = *resp.SenderFaceURL
|
|
||||||
}
|
|
||||||
if resp.SessionType != nil {
|
|
||||||
msg.MsgData.SessionType = *resp.SessionType
|
|
||||||
}
|
|
||||||
if resp.MsgFrom != nil {
|
|
||||||
msg.MsgData.MsgFrom = *resp.MsgFrom
|
|
||||||
}
|
|
||||||
if resp.ContentType != nil {
|
|
||||||
msg.MsgData.ContentType = *resp.ContentType
|
|
||||||
}
|
|
||||||
if resp.Status != nil {
|
|
||||||
msg.MsgData.Status = *resp.Status
|
|
||||||
}
|
|
||||||
if resp.Options != nil {
|
|
||||||
msg.MsgData.Options = *resp.Options
|
|
||||||
}
|
|
||||||
if resp.OfflinePushInfo != nil {
|
|
||||||
msg.MsgData.OfflinePushInfo = resp.OfflinePushInfo
|
|
||||||
}
|
|
||||||
if resp.AtUserIDList != nil {
|
|
||||||
msg.MsgData.AtUserIDList = *resp.AtUserIDList
|
|
||||||
}
|
|
||||||
if resp.MsgDataList != nil {
|
|
||||||
msg.MsgData.MsgDataList = *resp.MsgDataList
|
|
||||||
}
|
|
||||||
if resp.AttachedInfo != nil {
|
|
||||||
msg.MsgData.AttachedInfo = *resp.AttachedInfo
|
|
||||||
}
|
|
||||||
if resp.Ex != nil {
|
|
||||||
msg.MsgData.Ex = *resp.Ex
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), string(msg.MsgData.Content))
|
|
||||||
return callbackResp
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,14 @@ type CommonCallbackReq struct {
|
|||||||
Ex string `json:"ex"`
|
Ex string `json:"ex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CommonCallbackReq) GetCallbackCommand() string {
|
||||||
|
return c.CallbackCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackReq interface {
|
||||||
|
GetCallbackCommand() string
|
||||||
|
}
|
||||||
|
|
||||||
type CallbackResp interface {
|
type CallbackResp interface {
|
||||||
Parse() (err error)
|
Parse() (err error)
|
||||||
}
|
}
|
||||||
@ -33,18 +41,20 @@ type CommonCallbackResp struct {
|
|||||||
ActionCode int `json:"actionCode"`
|
ActionCode int `json:"actionCode"`
|
||||||
ErrCode int32 `json:"errCode"`
|
ErrCode int32 `json:"errCode"`
|
||||||
ErrMsg string `json:"errMsg"`
|
ErrMsg string `json:"errMsg"`
|
||||||
OperationID string `json:"operationID"`
|
//OperationID string `json:"operationID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommonCallbackResp) Parse() (err error) {
|
func (c *CommonCallbackResp) Parse() error {
|
||||||
|
if c == nil {
|
||||||
|
return constant.ErrData.Wrap("callback common is nil")
|
||||||
|
}
|
||||||
if c.ActionCode != constant.NoError || c.ErrCode != constant.NoError {
|
if c.ActionCode != constant.NoError || c.ErrCode != constant.NoError {
|
||||||
newErr := constant.ErrCallback
|
newErr := constant.ErrCallback
|
||||||
newErr.ErrCode = c.ErrCode
|
newErr.ErrCode = c.ErrCode
|
||||||
newErr.DetailErrMsg = fmt.Sprintf("callback response error actionCode is %d, errCode is %d, errMsg is %s", c.ActionCode, c.ErrCode, c.ErrMsg)
|
newErr.DetailErrMsg = fmt.Sprintf("callback response error actionCode is %d, errCode is %d, errMsg is %s", c.ActionCode, c.ErrCode, c.ErrMsg)
|
||||||
err = newErr
|
return newErr.Wrap()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserStatusBaseCallback struct {
|
type UserStatusBaseCallback struct {
|
||||||
|
@ -78,3 +78,23 @@ func CallBackPostReturn(url, callbackCommand string, input interface{}, output c
|
|||||||
}
|
}
|
||||||
return output.Parse()
|
return output.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CallBackPostReturnV2(url string, req cbapi.CallbackReq, resp cbapi.CallbackResp, callbackConfig config.CallBackConfig) error {
|
||||||
|
v := urlLib.Values{}
|
||||||
|
v.Set("callbackCommand", req.GetCallbackCommand())
|
||||||
|
url = url + "?" + v.Encode()
|
||||||
|
b, err := Post(url, req, callbackConfig.CallbackTimeOut)
|
||||||
|
if err != nil {
|
||||||
|
if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue {
|
||||||
|
return constant.ErrCallbackContinue
|
||||||
|
}
|
||||||
|
return constant.NewErrNetwork(err)
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(b, resp); err != nil {
|
||||||
|
if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue {
|
||||||
|
return constant.ErrCallbackContinue
|
||||||
|
}
|
||||||
|
return constant.NewErrData(err)
|
||||||
|
}
|
||||||
|
return resp.Parse()
|
||||||
|
}
|
||||||
|
@ -425,3 +425,11 @@ func Unwrap(err error) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotNilReplace 当new_不为空时, 将old设置为new_
|
||||||
|
func NotNilReplace[T any](old, new_ *T) {
|
||||||
|
if old == nil || new_ == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*old = *new_
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user