OpenIM JSSDK (三)

从下面的函数开始:

func (wsRouter *WsFuncRouter) GetSelfUserInfo(input string, operationID string) {
	userWorker := open_im_sdk.GetUserWorker(wsRouter.uId)
	if !wsRouter.checkResourceLoadingAndKeysIn(userWorker, input, operationID, runFuncName(), nil) {
		return
	}
	userWorker.User().GetSelfUserInfo(&BaseSuccessFailed{runFuncName(), operationID, wsRouter.uId}, operationID)
}

这段代码定义了 WsFuncRouter 结构的一个方法 SetSelfInfo。该方法主要用于设置用户信息。我们来逐步分析它的功能和逻辑:

  1. 获取与指定用户ID相关的登录管理器:

    userWorker := open_im_sdk.GetUserWorker(wsRouter.uId)
    

    这一行代码调用了之前解释过的 GetUserWorker 函数,传入的参数是 wsRouter 结构体中存储的 uId(用户ID)。该函数会返回与指定用户ID相关的 LoginMgr 实例(或者为此用户ID创建一个新的实例)。

  2. 检查资源是否已加载并检查关键信息:

    if !wsRouter.checkResourceLoadingAndKeysIn(userWorker, userInfo, operationID, runFuncName(), nil) {
        return
    }
    

    这里调用了 checkResourceLoadingAndKeysIn 方法(该方法的具体实现未提供)。这个方法似乎进行一些前置检查,例如资源是否已经加载、是否存在必要的关键信息等。如果这些检查不通过(方法返回 false),那么 SetSelfInfo 方法会提前返回并不执行后续的逻辑。

  3. 设置用户信息:

    userWorker.User().SetSelfInfo(&BaseSuccessFailed{runFuncName(), operationID, wsRouter.uId}, userInfo, operationID)
    

    这一行代码是该方法的核心部分,它实际上是调用了 userWorkerUser 方法(该方法可能返回用户相关的服务或操作接口)然后进一步调用了 SetSelfInfo 方法来更新用户的个人信息。

    SetSelfInfo 方法传递了三个参数:

    • 一个是 BaseSuccessFailed 结构体的实例,这可能是一个用于回调的结构,其中包含了函数名、操作ID和用户ID。
    • userInfo,这应该是一个字符串,表示要设置的用户信息。
    • operationID,这可能是一个操作或请求的唯一标识符,用于跟踪或日志记录。

SetSelfInfo 方法允许你为指定的用户设置其个人信息。在实际设置之前,它执行了一些前置检查以确保操作的有效性和安全性。

继续解析:

func runFuncName() string {
	pc := make([]uintptr, 1)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	return f.Name()
}

这个函数 runFuncName 的目的是获取调用它的函数的名称。我们来逐步分析:

  1. 创建一个uintptr切片:

    pc := make([]uintptr, 1)
    

    这里创建了一个长度为1的 uintptr 切片,名为 pc。这个切片用来存储返回的程序计数器地址。

  2. 获取调用者的信息:

    runtime.Callers(2, pc)
    

    Go的 runtime 包提供了 Callers 函数,它返回调用它的函数的调用栈。第一个参数是返回的调用栈的“深度”。这里使用的值是 2,这意味着它会跳过 runtime.CallersrunFuncName 自身,来获得调用 runFuncName 的函数的信息。

    返回的程序计数器地址存储在先前创建的 pc 切片中。

  3. 从程序计数器获取函数信息:

    f := runtime.FuncForPC(pc[0])
    

    使用 runtime.FuncForPC 函数,我们可以获取给定程序计数器地址对应的函数的信息。因为我们只存储了一个地址在 pc 切片中,所以我们使用 pc[0]

  4. 返回函数名称:

    return f.Name()
    

    最后,我们返回获取到的函数的名称。

我们再看看调用它的函数:

func (wsRouter *WsFuncRouter) checkResourceLoadingAndKeysIn(mgr *login.LoginMgr, input, operationID, funcName string, m map[string]interface{}, keys ...string) bool {
	for _, k := range keys {
		_, ok := m[k]
		if !ok {
			log.Info(operationID, "key not in", keys, input, operationID, funcName)
			wsRouter.GlobalSendMessage(EventData{cleanUpfuncName(funcName), StatusBadParameter, "key not in", "", operationID})
			return false
		}
	}

	if err := open_im_sdk.CheckResourceLoad(mgr); err != nil {
		log.Info(operationID, "Resource Loading ", mgr, err.Error())
		wsRouter.GlobalSendMessage(EventData{cleanUpfuncName(funcName), StatusResourceNotCompleted, "resource loading is not completed", "", operationID})
		return false
	}
	return true
}

这个函数 checkResourceLoadingAndKeysIn 似乎是一个预检查功能,确保资源加载并检查传入数据中是否存在必要的键。我们来详细分析每个部分:

  1. 函数参数:

    • mgr *login.LoginMgr: 这是一个登录管理器,从结构上看,它可能用于管理各种与用户登录、消息和其他功能相关的资源。
    • input string: 可能是传入的数据或JSON字符串,用于检查是否包含所需的键。
    • operationID string: 用于在日志中识别特定的操作。
    • funcName string: 调用此检查功能的函数的名称。
    • m map[string]interface{}: 要检查键是否存在的映射。
    • keys ...string: 一个可变参数列表,列出要在映射中查找的键。
  2. 检查所有的键是否存在于映射中:

    for _, k := range keys {
     	_, ok := m[k]
     	if !ok {
     		...
     		return false
     	}
    }
    

    这个循环遍历每一个要求存在的键,检查它们是否真的存在于映射中。如果一个键不存在,它会记录一个日志消息并发送一个全局消息,然后返回 false

  3. 检查资源是否已加载:

    if err := open_im_sdk.CheckResourceLoad(mgr); err != nil {
     	...
     	return false
    }
    

    这部分使用 open_im_sdk.CheckResourceLoad 来检查相关的资源(可能是登录或其他相关资源)是否已经加载。如果资源未加载或有错误,它会记录日志并发送一个全局消息,然后返回 false

  4. 返回成功:

    return true
    

    如果所有的键都在映射中存在,并且所有资源都已加载,那么函数返回 true 表示检查成功。