code-Review
code-Review
1.chainweaver-did
接口(post-get的包装部分)
login
调用了postRequest:json解析,用utils的post到指定的url
func Post(url string, body []byte, header map[string]string) (resp []byte, err error)
//其中为了测试跳过了https证书验证
解析postRequest的返回值
if r.Code != module.SUCCESS {
return c.login(phoneNumber, password)
} else {
if r.Data.OldAccessToken != "" {
r.Data.AccessToken = r.Data.OldAccessToken
}
if r.Data.OldExpiresIn != 0 {
r.Data.ExpiresIn = r.Data.OldExpiresIn
}
c.token = r.Data.AccessToken
c.logger.Infof("[Login] success, token: %s", c.token)
//go c.loginTimedExecution(login, 2)
duration := r.Data.ExpiresIn - int(time.Now().Unix())
go c.loginTimedExecution(login, duration)
}
return normalResponse(c, r.Data, r.Msg, r.Code)- 后台持续续签
goroutine 基本概念
go
关键字:用于启动一个新的 goroutine(轻量级线程)- 非阻塞执行:使用
go
启动的函数会在后台异步执行,不会阻塞当前函数继续执行 - 轻量级:goroutine 比系统线程更轻量,Go 运行时会自动管理它们
为什么使用 goroutine
在这个场景中使用 goroutine 的好处:
- 不阻塞主流程:登录操作完成后,主函数可以立即返回,而令牌续期在后台处理
- 长时间运行:
loginTimedExecution
包含一个无限循环,在客户端的整个生命周期内持续运行 - 计时器机制:使用 [time.NewTicker](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 实现定时触发,在令牌即将过期时自动更新
参数解释
- [login](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html):包含登录凭证的请求对象,用于自动重新登录
- [duration](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html):首次登录的令牌有效期(以秒为单位),用于设置定时器
这种模式在需要长时间维持会话,自动处理令牌续期的场景非常常见,特别是在与远程API交互的客户端中。
func (c *Client) loginTimedExecution(login *request.Login, after int) {
if !c.loginConfig.EnableAutoLogin {
return
}
if c.loginConfig.AutoLoginStatus {
return
}
c.loginConfig.AutoLoginStatus = true
// 设置定时器
ticker := time.NewTicker(time.Duration(after) * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
r, msg, code := c.Login(login.PhoneNumber, login.Password)
if code != module.SUCCESS {
c.logger.Debug("[Login] Auto Login Failed: ", msg)
}
c.logger.Debug("[Login] Login again ")
if r != nil && r.ExpiresIn > 0 {
newDuration := r.ExpiresIn - int(time.Now().Unix())
ticker.Stop()
c.logger.Debug("[Login] Log back in after ", newDuration)
ticker = time.NewTicker(time.Duration(newDuration) * time.Second)
}
case <-c.stop:
c.logger.Infof("[Login] timed execution stop")
return
}
}
}前置条件验证
函数首先检查两个条件:
EnableAutoLogin
标志:确认用户是否启用了自动登录功能if !c.loginConfig.EnableAutoLogin {
return
}
AutoLoginStatus
状态:确保不会启动多个自动登录 goroutineif c.loginConfig.AutoLoginStatus {
return
}
设置状态标志:标记自动登录已激活
c.loginConfig.AutoLoginStatus = true
定时器设置
ticker := time.NewTicker(time.Duration(after) * time.Second)
defer ticker.Stop()
这里使用 [time.NewTicker](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 创建一个定时器,它会定期向 channel [ticker.C](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 发送时间值:
- 初始延迟:[after](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 参数决定首次登录后的等待时间(一般是令牌到期前的一段时间)
- **[defer ticker.Stop()](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html)**:确保在函数退出时停止定时器,防止资源泄露
循环监听机制
for {
select {
case <-ticker.C:
// 定时器触发的操作
case <-c.stop:
// 停止信号触发的操作
}
}
这是Go并发编程的经典模式,使用
select
语句同时监听多个 channel:- [ticker.C](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) channel:
- 当定时器到期时,这个 channel 会收到一个时间值
- Go 运行时会选择对应的 case 分支执行
- [c.stop](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) channel:
- 这是一个用于停止 goroutine 的信号 channel
- 当客户端调用
Close()
方法时会发送信号到这个 channel
定时器触发分支处理
当定时器触发时,执行以下操作:
r, msg, code := c.Login(login.PhoneNumber, login.Password)
if code != module.SUCCESS {
c.logger.Debug(“[Login] Auto Login Failed: “, msg)
}
c.logger.Debug(“[Login] Login again “)
if r != nil && r.ExpiresIn > 0 {
newDuration := r.ExpiresIn - int(time.Now().Unix())
ticker.Stop()
c.logger.Debug(“[Login] Log back in after “, newDuration)
ticker = time.NewTicker(time.Duration(newDuration) * time.Second)
}
执行登录操作:使用保存的凭证再次调用登录接口
检查登录结果:记录任何登录失败的情况
动态调整定时器
:
- 计算新令牌的有效期:
newDuration := r.ExpiresIn - int(time.Now().Unix())
- 停止旧定时器:[ticker.Stop()](vscode-file://vscode-app/a:/MyProgram/Microsoft VS Code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html)
- 创建新定时器:
ticker = time.NewTicker(time.Duration(newDuration) * time.Second)
- 计算新令牌的有效期:
这种动态调整确保令牌在即将到期前自动续期,而不是使用固定的时间间隔。
停止信号处理
case <-c.stop:
c.logger.Infof(“[Login] timed execution stop”)
return
当
c.stop
channel 接收到值时(通常在客户端的Close()
方法中发送):- 记录停止日志
- 立即返回,结束 goroutine
defer ticker.Stop()
会在函数退出前执行,确保定时器资源被释放
documentGet
直接调用postRequest[*request.DocumentGet, *core.Document](c, module.DocumentGetUrl, req)
,业务函数最终会调用的golang泛型post
MsgVerify
func (c *Client) MsgVerify(req *module.Plaintext) (bool, string, int32) { |
VpVerify
func (c *Client) VpVerify(vp *core.VerifiablePresentation) (bool, string, int32) { |
Health
func (c *Client) Health() (*response.Health, string, int32) { |
略有不同,用了get
VcIssue
func (c *Client) VcIssue(req *request.VcIssue) (*core.VerifiableCredential, string, int32) { |
有了个时间的检测
VcRevoke
func (c *Client) VcRevoke(id string) (bool, string, int32) { |
···
很多的类似都是直接post/get一个request,除了两个例外的VpCreate
// VpCreateApplyLogin - 生成请求登录VP |
核心数据结构
客户端配置和配置方法
type loginConfig struct { |
会用这个结构来添加配置数据
// ClientOption define client option func |
用来初始化客户端,可以带一些Option函数修改配置
func NewDIDClient(opts ...ClientOption) (*Client, error) { |
Vc相关
type VcIssue struct { |
密钥管理
没写居然,看得出来原本想写SM2类型的
Health
type Health struct { |
utils
test
type extend struct { |
omitempty可以在字段为空的时候忽略
// BenchmarkMarshalSortedJSON 基准测试:测量标准实现的性能 |
在普通的测试外有benchmark
json
两种实现方式,一种直接包装json库,另一种自己实现的,性能快但是支持不够完善
// MarshalSortedFast 自定义Marshal函数,用于生成按键排序的JSON字符串,只适用于结构体,基本数据类型或切片不行 |