diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..762c4f3 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +vet: + go vet ./rongcloud + +mod: + go mod tidy \ No newline at end of file diff --git a/README.md b/README.md index 7295a0d..5e41f6c 100644 --- a/README.md +++ b/README.md @@ -4,94 +4,84 @@ server-sdk-go Rong Cloud Server SDK in Go. # 版本说明 - -- 为方便开发者的接入使用,更好的对融云 Server SDK 进行维护管理,融云 Server SDK v3 统一规范了命名及调用方式,结构更加清晰。老版本的 Server SDK 已经切入 v1 v2.0.1 分支,仍然可以使用,但不会再做新的功能更新。 -- 如果您是新接入的开发者,建议您使用 Server SDK v3 版本。 对已集成使用老版本 Server SDK 的开发者,不能直接升级使用,强烈建议您重新测试后使用 +当前版本为v4, 该版本将保持向后兼容, 但不兼容旧的v3,v2等版本, 旧版本不再更新, 请升级后使用。 # API文档 - [官方文档](https://doc.rongcloud.cn/imserver/server/v1/overview) ## 如何使用 -### 1. go mod 使用旧版本 - -- go mod 文件: `require github.com/rongcloud/server-sdk-go` -- go 文件引入 : `import "github.com/rongcloud/server-sdk-go/sdk"` - -### 2. go mode 方式使用 v3 - -- v3 版本 : `require github.com/rongcloud/server-sdk-go/v3` -- go 文件引入: `import "github.com/rongcloud/server-sdk-go/v3/sdk"` - -### 3. 非 go mod 直接使用 - -- 直接下载/更新包到 GOPATH:`go get -u github.com/rongcloud/server-sdk-go` -- go 文件引入: `import "github.com/rongcloud/server-sdk-go/sdk"` - -## 方法调用 - -* 请参考 rongcloud_test.go 上面提供了所有的 API 接口的调用用例。 +### 安装 +```shell +go get github.com/rongcloud/server-sdk-go/v4 +``` +### 示例1: 发送单聊消息 ```go package main -import "fmt" +import ( + "context" + "fmt" -//旧版本引入 或者 非go mod方式使用 -import "github.com/rongcloud/server-sdk-go/sdk" - -// go mod v3 版本引入 -//import "github.com/rongcloud/server-sdk-go/v3/sdk" + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) func main() { - rc := sdk.NewRongCloud("appKey", "appSecret") - msg := sdk.TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.PrivateSend( - "userId", - []string{"toUserId"}, - "RC:TxtMsg", - &msg, - "", - "", - 1, - 0, - 1, - 0, - 0, - ) - - fmt.Println(err) + rc := rongcloud.NewRongCloud("appKey", "appSecret") + // 单聊文本消息 + txtMsg := &rongcloud.TXTMsg{ + Content: "hello world", + } + ctx := context.Background() + + // 自定义requestId + requestId := uuid.New().String() + rongcloud.AddHttpRequestId(ctx, requestId) + + // 发送单聊消息 + resp, err := rc.MessagePrivatePublish(ctx, &rongcloud.MessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: rongcloud.StringPtr("u02"), + RCMsg: txtMsg, + }) + fmt.Println(err) + + // 获取http.Response + httpResp := resp.GetHttpResponse() + + // 快捷方法获取x-request-id + requestIdResp := resp.GetRequestId() } ``` +> 更多示例请参考 [examples](./examples/README.md) + ### http 参数优化 - http连接相关的性能优化 -- `sdk.WithMaxIdleConnsPerHost` : 每个域名最大活跃连接数,默认 100 -- `sdk.WithTimeout` : 连接超时设置,默认 10 秒;最小单位为秒, `sdk.WithTimeout(30)` 表示设置为30秒 -- `sdk.WithKeepAlive` : 连接保活时间,默认 30 秒;最小单位为秒, `sdk.WithKeepAlive(30)` 表示设置保活时间为30秒 -- `rc.SetHttpTransport` : 手动设置 http client -- `rc.GetHttpTransport` : 获得当前全局 http client +- `rongcloud.WithMaxIdleConnsPerHost` : 每个域名最大活跃连接数,默认 100. +- `rongcloud.WithTimeout` : 连接超时设置,默认 10 秒;最小单位为秒, `sdk.WithTimeout(30*time.Second)` 表示设置为30秒. +- `rongcloud.WithKeepAlive` : 连接保活时间,默认 30 秒;最小单位为秒, `sdk.WithKeepAlive(30*time.Second)` 表示设置保活时间为30秒. +- `rongcloud.WithTransport`: 设置 http client transport 参数,优先级大于其他http参数. +- `rc.SetHttpTransport` : 实例上设置 http client transport 参数,优先级大于其他http参数. +- `rc.GetHttpTransport` : 获得当前实例http client transport. ```go package main -import "fmt" import "time" import "net" import "net/http" -import "github.com/rongcloud/server-sdk-go/sdk" +import "github.com/rongcloud/server-sdk-go/v4/rongcloud" func main() { // 方法1: 创建对象时设置 - rc := sdk.NewRongCloud("appKey", + rc := rongcloud.NewRongCloud( + "appKey", "appSecret", // 每个域名最大活跃连接数 - sdk.WithMaxIdleConnsPerHost(100), + rongcloud.WithMaxIdleConnsPerHost(100), ) // 方法2: 自定义 http client, 调用 set 方法设置 @@ -108,88 +98,13 @@ func main() { } ``` -### GO SDK 功能支持的版本清单 - -| 模块 | 方法名 | 说明 | master | -|:-----------------------------------------------------------------------------------------|:------------------------------|:-------------------------------------------------|:-------| -| [用户信息](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/user_test.go) | UserRegister | 注册, 获取 token | √ | -| | UserUpdate | 更新用户信息 | √ | -| | OnlineStatusCheck | 检查用户在线状态 | √ | -| | BlacklistAdd | 添加黑名单 | √ | -| | BlacklistGet | 获取黑名单列表 | √ | -| | BlacklistRemove | 移除黑名单 | √ | -| | BlockAdd | 添加用户封禁 | √ | -| | BlockGetList | 获取用户封禁列表 | √ | -| | BlockRemove | 移除用户封禁 | √ | -| | TagSet | 添加用户标签 | √ | -| | TagBatchSet | 批量添加用户标签 | √ | -| | TagGet | 获取用户标签 | √ | -| | GroupMuteAdd | 添加全局群组禁言用户,添加后用户在应用下的所有群组中都不能发送消息 | | -| | GroupMuteRemove | 移除全局群组禁言用户 | | -| | GroupMuteGetList | 获取全局群组禁言用户列表 | | -| | ChatRoomMuteAdd | 添加全局聊天室禁言用户,添加后用户在应用下的所有聊天室中都不能发送消息 | | -| | ChatRoomMuteRemove | 移除全局聊天室禁言用户 | | -| | ChatRoomMuteGetList | 获取全局聊天室禁言用户列表 | | -| | UserDeactivate | 注销用户 | √ | -| | UserDeactivateQuery | 查询已注销用户 | √ | -| | UserReactivate | 重新激活注销用户 | √ | -| [敏感词](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/sensitive_test.go) | SensitiveAdd | 添加敏感词,添加后默认 2 小时生效 | √ | -| | SensitiveGetList | 获取敏感词列表 | √ | -| | SensitiveRemove | 移除敏感词,支持批量移除功能,移除后默认 2 小时生效 | √ | -| [消息发送](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/message_test.go) | PrivateSend | 发送单聊消息 | √ | -| | PrivateSendTemplate | 发送单聊模板消息 | √ | -| | PrivateRecall | 消息单聊撤回 | √ | -| | ChatRoomSend | 发送聊天室消息 | √ | -| | ChatRoomBroadcast | 发送聊天室广播消息 | √ | -| | GroupSend | 发送群组消息 | √ | -| | GroupSendMention | 发送群组 @ 消息 | √ | -| | GroupRecall | 撤回群组消息 | √ | -| | SystemSend | 发送系统消息 | √ | -| | SystemSendTemplate | 发送系统模板消息 | √ | -| | SystemBroadcast | 发送广播消息,单个应用每小时只能发送 2 次,每天最多发送 3 次。 | √ | -| [消息历史记录](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/message_test.go) | HistoryGet | 消息历史记录下载地址获取 | √ | -| | HistoryRemove | 消息历史记录删除方法 | √ | -| [广播推送](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/push_test.go) | PushSend | 发送推送,推送和广播消息合计,单个应用每小时只能发送 2 次,每天最多发送 3 次。 | √ | -| [群组](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/group_test.go) | GroupCreate | 创建群组 | √ | -| | GroupSync | 同步群关系 | √ | -| | GroupUpdate | 更新群信息 | √ | -| | GroupGet | 获取群信息 | √ | -| | GroupJoin | 邀请人加入群组 | √ | -| | GroupQuit | 退出群组 | √ | -| | GroupDismiss | 解散群组 | √ | -| | GroupMuteMembersAdd | 添加指定群组禁言用户,该用户在指定群组中不能发送消息 | √ | -| | GroupMuteMembersRemove | 移除指定群组禁言用户 | √ | -| | GroupMuteMembersGetList | 获取指定群组禁言用户列表 | √ | -| | GroupMuteAllMembersAdd | 添加指定群组全部成员禁言,添加后该群组中所有用户不能在此群组中发送消息 | √ | -| | GroupMuteAllMembersRemove | 移除指定群组全部成员禁言 | √ | -| | GroupMuteAllMembersGetList | 获取群组禁言列表 | √ | -| | GroupMuteWhiteListUserAdd | 添加群组禁言白名单用户,群组被禁言后,该群白名单中用户可以在群组中发送消息 | √ | -| | GroupMuteWhiteListUserRemove | 移除群组禁言白名单用户 | √ | -| | GroupMuteWhiteListUserGetList | 获取群组禁言白名单用户列表 | √ | -| [会话免打扰](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/conversation_test.go) | ConversationMute | 添加免打扰会话 | √ | -| | ConversationUnmute | 移除免打扰会话 | √ | -| | ConversationGet | 免打扰会话状态获取 | √ | -| [聊天室](https://github.com/rongcloud/server-sdk-go/blob/master/sdk/chatroom_test.go) | ChatRoomCreate | 创建聊天室 | √ | -| | ChatRoomDestroy | 销毁聊天室 | √ | -| | ChatRoomGet | 查询聊天室信息 | √ | -| | ChatRoomIsExist | 检查用户是否在聊天室 | √ | -| | ChatRoomBlockAdd | 添加聊天室封禁用户,被封禁后用户无法加入该聊天室,如用户正在聊天室中将被踢出聊天室 | √ | -| | ChatRoomBlockGetList | 获取聊天室封禁用户列表 | √ | -| | ChatRoomBlockRemove | 移除聊天室封禁用户 | √ | -| | ChatRoomMuteMembersAdd | 添加聊天室禁言用户,用户无法在该聊天室中发送消息 | √ | -| | ChatRoomMuteMembersGetList | 获取聊天室禁言用户列表 | √ | -| | ChatRoomMuteMembersRemove | 移除聊天室禁言用户 | √ | -| | ChatRoomDemotionAdd | 添加聊天室低优先级消息,添加后因消息量激增导致服务器压力较大时,默认丢弃低级别的消息 | √ | -| | ChatRoomDemotionGetList | 查询聊天室低优先级消息列表 | √ | -| | ChatRoomDemotionRemove | 移除聊天室低优先级消息 | √ | -| | ChatRoomDistributionStop | 停止聊天室消息分发,服务端收到上行消息后不进行下行发送 | √ | -| | ChatRoomDistributionResume | 恢复聊天室消息分发 | √ | -| | ChatRoomKeepAliveAdd | 添加保活聊天室,保活中的聊天室不会被自动销毁 | √ | -| | ChatRoomKeepAliveRemove | 移除保活聊天室 | √ | -| | ChatRoomKeepAliveGetList | 获取保活聊天室列表 | √ | -| | ChatRoomWhitelistAdd | 添加白名单消息类型,白名单中的消息类型,在消息量激增导致服务器压力较大时不会被丢弃,确保消息到达 | √ | -| | ChatRoomWhitelistRemove | 移除白名单消息类型 | √ | -| | ChatRoomWhitelistGetList | 获取白名单消息类型列表 | √ | -| | ChatRoomUserWhitelistAdd | 添加白名单用户,白名单中用户发送的消息,在消息量激增导致服务器压力较大时不会被丢弃,确保消息到达 | √ | -| | ChatRoomUserWhitelistRemove | 移除白名单用户 | √ | -| | ChatRoomUserWhitelistGetList | 获取白名单用户列表 | √ | +### GO SDK 功能支持清单 + +* [消息发送](./examples/message/README.md) +* [用户管理](./examples/user/README.md) +* [聊天室](./examples/chatroom/README.md) +* [群组](./examples/group/README.md) +* [超级群](./examples/ultragroup/README.md) +* [会话](./examples/conversation/README.md) +* [推送](./examples/push/README.md) +* [敏感词](./examples/sensitive/README.md) \ No newline at end of file diff --git a/doc.go b/doc.go deleted file mode 100644 index 43dda82..0000000 --- a/doc.go +++ /dev/null @@ -1 +0,0 @@ -package serversdkgo diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..5cfc901 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,3 @@ +## RongCloud Go Server SDK Example + +当前目录下保留sdk使用示例, 如需更多示例, 非常欢迎提交PR。 \ No newline at end of file diff --git a/examples/chatroom/README.md b/examples/chatroom/README.md new file mode 100644 index 0000000..7a32654 --- /dev/null +++ b/examples/chatroom/README.md @@ -0,0 +1,41 @@ +## 聊天室 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|----------------------------------|---------------|------------------------------------------------| +| ChatroomBanAdd | 设置聊天室全体禁言 | [chatroomban.go](./chatroomban.go) | +| ChatroomBanQuery | 查询聊天室全体禁言列表 | [chatroomban.go](./chatroomban.go) | +| ChatroomBanRollback | 取消聊天室全体禁言 | [chatroomban.go](./chatroomban.go) | +| ChatroomUserBanWhitelistAdd | 加入聊天室全体禁言白名单 | [chatroomban.go](./chatroomban.go) | +| ChatroomUserBanWhitelistQuery | 查询聊天室全体禁言白名单 | [chatroomban.go](./chatroomban.go) | +| ChatroomUserBanWhitelistRollback | 移出聊天室全体禁言白名单 | [chatroomban.go](./chatroomban.go) | +| ChatroomEntrySet | 设置聊天室属性(KV) | [chatroomentry.go.go](./chatroomentry.go.go) | +| ChatroomEntryBatchSet | 批量设置聊天室属性(KV) | [chatroomentry.go](./chatroomentry.go) | +| ChatroomEntryRemove | 删除聊天室属性(KV) | [chatroomentry.go](./chatroomentry.go) | +| ChatroomDestroySet | 设置聊天室销毁类型 | [chatroommeta.go.go](./chatroommeta.go.go) | +| ChatroomGet | 查询聊天室信息 | [chatroommeta.go](./chatroommeta.go) | +| ChatroomDestroy | 销毁聊天室 | [chatroommeta.go](./chatroommeta.go) | +| ChatroomUserExist | 查询用户是否在聊天室中 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUsersExist | 批量查询用户是否在聊天室中 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserQuery | 获取聊天室成员 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBlockAdd | 封禁聊天室用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBlockList | 查询聊天室封禁用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBlockRollback | 解除封禁聊天室用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBanAdd | 全局禁言用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBanQuery | 查询全局禁言用户列表 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserBanRemove | 取消全局禁言用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserGagAdd | 禁言指定聊天室用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserGagList | 查询聊天室禁言用户列表 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomUserGagRollback | 取消禁言指定聊天室用户 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomMessagePriorityAdd | 添加低级别消息类型 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomMessagePriorityQuery | 查询低级别消息类型 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomMessagePriorityRemove | 移除低级别消息类型 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomKeepaliveAdd | 保活聊天室 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomKeepaliveQuery | 查询保活聊天室 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomKeepaliveRemove | 取消保活聊天室 | [chatroomuser.go](./chatroomuser.go) | +| ChatroomWhitelistAdd | 加入聊天室消息白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | +| ChatroomWhitelistQuery | 查询聊天室消息白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | +| ChatroomWhitelistRemove | 移出聊天室消息白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | +| ChatroomUserWhitelistAdd | 加入聊天室用户白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | +| ChatroomUserWhitelistQuery | 查询聊天室用户白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | +| ChatroomUserWhitelistRemove | 移出聊天室用户白名单 | [chatroomwhitelist.go](./chatroomwhitelist.go) | diff --git a/examples/chatroom/chatroomban.go b/examples/chatroom/chatroomban.go new file mode 100644 index 0000000..4984897 --- /dev/null +++ b/examples/chatroom/chatroomban.go @@ -0,0 +1,109 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + chatroomBan(ctx, rc) +} + +func chatroomBan(ctx context.Context, rc *rongcloud.RongCloud) { + grp := "grp1" + // 创建测试chatroom + _, err := rc.ChatroomCreateNew(ctx, &rongcloud.ChatroomCreateNewRequest{ChatroomId: rongcloud.StringPtr(grp)}) + if err != nil { + log.Fatalf("chatroom create error %s", err) + } + + banReq := rongcloud.ChatroomBanRequest{ + ChatroomId: rongcloud.StringPtr(grp), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + } + + // 设置聊天室全体禁言 + banAddRequest := &rongcloud.ChatroomBanAddRequest{ + ChatroomBanRequest: banReq, + } + _, err = rc.ChatroomBanAdd(ctx, banAddRequest) + if err != nil { + log.Fatalf("chatroom ban add error %s", err) + } + + // 查询聊天室全体禁言列表 + banQueryResp, err := rc.ChatroomBanQuery(ctx, &rongcloud.ChatroomBanQueryRequest{ + Size: rongcloud.IntPtr(50), + Page: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("chatroom ban query error %s", err) + } + banQueryRespData, _ := json.Marshal(banQueryResp) + log.Printf("chatroom ban query resp data: %s", banQueryRespData) + + banCheckResp, err := rc.ChatroomBanCheck(ctx, &rongcloud.ChatroomBanCheckRequest{ChatroomId: rongcloud.StringPtr(grp)}) + if err != nil { + log.Fatalf("chatroom ban check error %s", err) + } + banCheckRespData, _ := json.Marshal(banCheckResp) + log.Printf("chatroom ban check resp data: %s", banCheckRespData) + + // 取消聊天室全体禁言 + banRollbackRequest := &rongcloud.ChatroomBanRollbackRequest{ + ChatroomBanRequest: banReq, + } + _, err = rc.ChatroomBanRollback(ctx, banRollbackRequest) + if err != nil { + log.Fatalf("chatroom ban rollback error %s", err) + } + + // 加入聊天室全体禁言白名单 + userBanWhiteListReq := rongcloud.ChatroomUserBanWhitelistRequest{ + ChatroomId: rongcloud.StringPtr(grp), + UserIds: []string{"u01", "u02"}, + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + } + userBanWhitelistAddReq := &rongcloud.ChatroomUserBanWhitelistAddRequest{ + ChatroomUserBanWhitelistRequest: userBanWhiteListReq, + } + _, err = rc.ChatroomUserBanWhitelistAdd(ctx, userBanWhitelistAddReq) + if err != nil { + log.Fatalf("chatroom user ban whitelist add error %s", err) + } + + // 查询聊天室全体禁言白名单 + userBanWhitelistQueryReq := &rongcloud.ChatroomUserBanWhitelistQueryRequest{ + ChatroomId: rongcloud.StringPtr(grp), + } + userBanWhitelistQueryResp, err := rc.ChatroomUserBanWhitelistQuery(ctx, userBanWhitelistQueryReq) + if err != nil { + log.Fatalf("chatroom user ban whitelist query error %s", err) + } + userBanWhitelistQueryRespData, _ := json.Marshal(userBanWhitelistQueryResp) + log.Printf("chatroom user ban whitelist query resp data: %s", userBanWhitelistQueryRespData) + + // 移出聊天室全体禁言白名单 + userBanWhitelistRollbackReq := &rongcloud.ChatroomUserBanWhitelistRollbackRequest{ + ChatroomUserBanWhitelistRequest: userBanWhiteListReq, + } + _, err = rc.ChatroomUserBanWhitelistRollback(ctx, userBanWhitelistRollbackReq) + if err != nil { + log.Fatalf("chatroom user ban whitelist rollback error %s", err) + } + + // 销毁测试chatroom + _, err = rc.ChatroomDestroy(ctx, &rongcloud.ChatroomDestroyRequest{ChatroomIds: []string{grp}}) + if err != nil { + log.Fatalf("chatroom create error %s", err) + } +} diff --git a/examples/chatroom/chatroomentry.go b/examples/chatroom/chatroomentry.go new file mode 100644 index 0000000..1568a5f --- /dev/null +++ b/examples/chatroom/chatroomentry.go @@ -0,0 +1,90 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + chatroomEntry(ctx, rc) +} + +func chatroomEntry(ctx context.Context, rc *rongcloud.RongCloud) { + grp := "grp1" + _, err := rc.ChatroomCreateNew(ctx, &rongcloud.ChatroomCreateNewRequest{ + ChatroomId: rongcloud.StringPtr(grp), + }) + if err != nil { + log.Fatalf("chatroom create error: %s", err) + } + + // 设置聊天室属性(KV) + _, err = rc.ChatroomEntrySet(ctx, &rongcloud.ChatroomEntrySetRequest{ + ChatroomId: rongcloud.StringPtr(grp), + UserId: rongcloud.StringPtr("u01"), + Key: rongcloud.StringPtr("key1"), + Value: rongcloud.StringPtr("val1"), + AutoDelete: rongcloud.IntPtr(1), + RCMsg: &rongcloud.ChrmKVNotiMsg{ + Type: 1, + Key: "key1", + Value: "val1", + Extra: "extra info", + }, + }) + if err != nil { + log.Fatalf("chatroom entry set err %s", err) + } + + // 批量设置聊天室属性(KV) + _, err = rc.ChatroomEntryBatchSet(ctx, &rongcloud.ChatroomEntryBatchSetRequest{ + ChatroomId: rongcloud.StringPtr(grp), + AutoDelete: rongcloud.IntPtr(1), + EntryOwnerId: rongcloud.StringPtr("u01"), + EntryInfo: map[string]string{"k1": "k2"}, + }) + if err != nil { + log.Fatalf("chatroom entry batch set err %s", err) + } + + entryQueryResp, err := rc.ChatroomEntryQuery(ctx, &rongcloud.ChatroomEntryQueryRequest{ + ChatroomId: rongcloud.StringPtr(grp), + Keys: []string{"key1"}, + }) + if err != nil { + log.Fatalf("chatroom entry query error %s", err) + } + entryQueryRespData, err := json.Marshal(entryQueryResp) + log.Printf("chatroom entry query resp: %s", entryQueryRespData) + + // 删除聊天室属性(KV) + _, err = rc.ChatroomEntryRemove(ctx, &rongcloud.ChatroomEntryRemoveRequest{ + ChatroomId: rongcloud.StringPtr(grp), + UserId: rongcloud.StringPtr("u01"), + Key: rongcloud.StringPtr("key1"), + RCMsg: &rongcloud.ChrmKVNotiMsg{ + Type: 2, + Key: "key1", + Value: "val1", + Extra: "extra info", + }, + }) + if err != nil { + log.Fatalf("chatroom entry remove %s", err) + } + + // 销毁测试聊天室 + _, err = rc.ChatroomDestroy(ctx, &rongcloud.ChatroomDestroyRequest{ + ChatroomIds: []string{grp}, + }) + if err != nil { + log.Fatalf("chatroom destroy error: %s", err) + } +} diff --git a/examples/chatroom/chatroommeta.go b/examples/chatroom/chatroommeta.go new file mode 100644 index 0000000..f6a1014 --- /dev/null +++ b/examples/chatroom/chatroommeta.go @@ -0,0 +1,60 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + chatroomMetaOp(ctx, rc) +} + +func chatroomMetaOp(ctx context.Context, rc *rongcloud.RongCloud) { + // create chatroom + resp, err := rc.ChatroomCreateNew(ctx, &rongcloud.ChatroomCreateNewRequest{ + ChatroomId: rongcloud.StringPtr("grp1"), + }) + if err != nil { + log.Fatalf("chatroom create err %s", err) + } + b, _ := json.Marshal(resp) + log.Printf("chat room create resp: %s", b) + log.Printf("http response get %+v", resp.GetHttpResponse()) + + // 设置聊天室销毁类型 + destroySetResp, err := rc.ChatroomDestroySet(ctx, &rongcloud.ChatroomDestroySetRequest{ + ChatroomId: rongcloud.StringPtr("grp1"), + DestroyTime: rongcloud.IntPtr(60), + DestroyType: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("chatroom destroy set err %s", err) + } + destroySetData, _ := json.Marshal(destroySetResp) + log.Printf("chatroom destroy set resp: %s", destroySetData) + + // 查询聊天室信息 + chatroomGetResp, err := rc.ChatroomGet(ctx, &rongcloud.ChatroomGetRequest{ChatroomId: rongcloud.StringPtr("grp1")}) + if err != nil { + log.Fatalf("chatroom get err %s", err) + } + chatroomGetData, _ := json.Marshal(chatroomGetResp) + log.Printf("chatroom get resp: %s", chatroomGetData) + + // 销毁聊天室 + destroyChatroomResp, err := rc.ChatroomDestroy(ctx, &rongcloud.ChatroomDestroyRequest{ + ChatroomIds: []string{"grp1", "grp2"}, + }) + if err != nil { + log.Fatalf("chatroom destroy err %s", err) + } + destroyChatRoomData, _ := json.Marshal(destroyChatroomResp) + log.Printf("chatroom destroy: %s", destroyChatRoomData) +} diff --git a/examples/chatroom/chatroomuser.go b/examples/chatroom/chatroomuser.go new file mode 100644 index 0000000..3c31ebe --- /dev/null +++ b/examples/chatroom/chatroomuser.go @@ -0,0 +1,247 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +const ( + testChatroomId = "grp1" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // create test chatroom + _, err := rc.ChatroomCreateNew(ctx, &rongcloud.ChatroomCreateNewRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId), + }) + if err != nil { + log.Fatalf("chatroom create new error %s", err) + } + + chatroomUser(ctx, rc) + + chatroomUserBlock(ctx, rc) + + chatroomMessagePriority(ctx, rc) + + chatroomKeepAlive(ctx, rc) + + // destroy test chatroom + _, err = rc.ChatroomDestroy(ctx, &rongcloud.ChatroomDestroyRequest{ + ChatroomIds: []string{testChatroomId}, + }) + if err != nil { + log.Fatalf("chatroom destroy error %s", err) + } +} + +func chatroomUser(ctx context.Context, rc *rongcloud.RongCloud) { + // 查询用户是否在聊天室中 + userExistResp, err := rc.ChatroomUserExist(ctx, + &rongcloud.ChatroomUserExistRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId), + UserId: rongcloud.StringPtr("u01"), + }, + ) + if err != nil { + log.Fatalf("chatroom user exit err %s", err) + } + b, _ := json.Marshal(userExistResp) + log.Printf("chatroom user exist resp data: %s", b) + + // 批量查询用户是否在聊天室中 + usersExistResp, err := rc.ChatroomUsersExist(ctx, &rongcloud.ChatroomUsersExistRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId), + UserIds: []string{"u01", "u02"}, + }) + if err != nil { + log.Fatalf("chatroom users exist err %s", err) + } + usersExistRespData, _ := json.Marshal(usersExistResp) + log.Printf("chatroom users exist resp: %s", usersExistRespData) + + // 获取聊天室成员 + chatroomUserQueryResp, err := rc.ChatroomUserQuery(ctx, &rongcloud.ChatroomUserQueryRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId), + Count: rongcloud.IntPtr(200), + Order: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("chatroom user query err %s", err) + } + data, _ := json.Marshal(chatroomUserQueryResp) + log.Printf("chatroom user query resp data: %s", data) +} + +func chatroomUserBlock(ctx context.Context, rc *rongcloud.RongCloud) { + // 封禁聊天室用户 + resp, err := rc.ChatroomUserBlockAdd(ctx, &rongcloud.ChatroomUserBlockAddRequest{ + UserIds: []string{"u01", "u02"}, + ChatroomId: rongcloud.StringPtr(testChatroomId), + Minute: rongcloud.IntPtr(10), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user block add err %s", err) + } + d, _ := json.Marshal(resp) + log.Printf("chatroom user block data: %s", d) + + // 查询聊天室封禁用户 + userBlockListResp, err := rc.ChatroomUserBlockList(ctx, &rongcloud.ChatroomUserBlockListRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId)}) + if err != nil { + log.Fatalf("chatroom user block list err: %s", err) + } + userBlockListData, _ := json.Marshal(userBlockListResp) + log.Printf("chatroom user block list data: %s", userBlockListData) + + // 解除封禁聊天室用户 + rollbackResp, err := rc.ChatroomUserBlockRollback(ctx, &rongcloud.ChatroomUserBlockRollbackRequest{ + UserIds: []string{"u01", "u02"}, + ChatroomId: rongcloud.StringPtr(testChatroomId), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user block rollback err %s", err) + } + rollbackData, _ := json.Marshal(rollbackResp) + log.Printf("chatroom user rollback data: %s", rollbackData) + + // 全局禁言用户 + userBanAddResp, err := rc.ChatroomUserBanAdd(ctx, &rongcloud.ChatroomUserBanAddRequest{ + UserIds: []string{"u01", "u02"}, + Minute: rongcloud.IntPtr(10), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user ban add err %s", err) + } + userBanAddData, _ := json.Marshal(userBanAddResp) + log.Printf("chatroom user ban add data: %s", userBanAddData) + + // 查询全局禁言用户列表 + userBanQueryResp, err := rc.ChatroomUserBanQuery(ctx, nil) + if err != nil { + log.Fatalf("chatroom user ban query err %s", err) + } + userBanQueryData, _ := json.Marshal(userBanQueryResp) + log.Printf("chatroom user ban query data: %s", userBanQueryData) + + // 取消全局禁言用户 + userBanRemoveResp, err := rc.ChatroomUserBanRemove(ctx, &rongcloud.ChatroomUserBanRemoveRequest{ + UserIds: []string{"u01", "u02"}, + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user ban remove data: %s", err) + } + userBanRemoveData, _ := json.Marshal(userBanRemoveResp) + log.Printf("chatroom user ban remove data: %s", userBanRemoveData) + + // 禁言指定聊天室用户 + userGagAddResp, err := rc.ChatroomUserGagAdd(ctx, &rongcloud.ChatroomUserGagAddRequest{ + UserIds: []string{"u01", "u02"}, + ChatroomId: rongcloud.StringPtr(testChatroomId), + Minute: rongcloud.IntPtr(10), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user gag add err %s", err) + } + userGagAddData, _ := json.Marshal(userGagAddResp) + log.Printf("chatroom user gag add data: %s", userGagAddData) + + // 查询聊天室禁言用户列表 + userGagListResp, err := rc.ChatroomUserGagList(ctx, &rongcloud.ChatroomUserGagListRequest{ + ChatroomId: rongcloud.StringPtr(testChatroomId), + }) + if err != nil { + log.Fatalf("chatroom user gag list err %s", err) + } + userGagListData, _ := json.Marshal(userGagListResp) + log.Printf("chatroom user gag list data: %s", userGagListData) + + // 取消禁言指定聊天室用户 + userGagRollbackResp, err := rc.ChatroomUserGagRollback(ctx, &rongcloud.ChatroomUserGagRollbackRequest{ + UserIds: []string{"u01", "u02"}, + ChatroomId: rongcloud.StringPtr(testChatroomId), + Extra: rongcloud.StringPtr(""), + NeedNotify: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("chatroom user gag rollback err %s", err) + } + userGagRollbackData, _ := json.Marshal(userGagRollbackResp) + log.Printf("chatroom user gag rollback data: %s", userGagRollbackData) +} + +func chatroomMessagePriority(ctx context.Context, rc *rongcloud.RongCloud) { + // 添加低级别消息类型 + vcMsg := "RC:VcMsg" + imgMsg := "RC:ImgMsg" + addResp, err := rc.ChatroomMessagePriorityAdd(ctx, &rongcloud.ChatroomMessagePriorityAddRequest{ + ObjectNames: []string{vcMsg, imgMsg}, + }) + if err != nil { + log.Fatalf("chatroom message priority add err %s", err) + } + addData, _ := json.Marshal(addResp) + log.Printf("chatroom message priority add resp: %s", addData) + + // 查询低级别消息类型 + query2Resp, err := rc.ChatroomMessagePriorityQuery(ctx, nil) + if err != nil { + log.Fatalf("chatroom message priority query err: %s", err) + } + query2Data, _ := json.Marshal(query2Resp) + log.Printf("chatroom query response data %s", query2Data) + + // 移除低级别消息类型 + removeResp, err := rc.ChatroomMessagePriorityRemove(ctx, &rongcloud.ChatroomMessagePriorityRemoveRequest{ + ObjectNames: []string{vcMsg, imgMsg}, + }) + if err != nil { + log.Fatalf("chatroom message priority remove err %s", err) + } + removeData, _ := json.Marshal(removeResp) + log.Printf("chatroom message priority remove resp: %s", removeData) +} + +func chatroomKeepAlive(ctx context.Context, rc *rongcloud.RongCloud) { + // 保活聊天室 + addResp, err := rc.ChatroomKeepaliveAdd(ctx, &rongcloud.ChatroomKeepaliveAddRequest{ChatroomId: rongcloud.StringPtr("grp1")}) + if err != nil { + log.Fatalf("chatroom keepalive add resp err %s", err) + } + addData, _ := json.Marshal(addResp) + log.Printf("chatroom keepalive add resp: %s", addData) + + // 查询保活聊天室 + queryResp, err := rc.ChatroomKeepaliveQuery(ctx, nil) + if err != nil { + log.Fatalf("chatroom keepalive query resp err %s", err) + } + queryData, _ := json.Marshal(queryResp) + log.Printf("chatroom keepalive query resp: %s", queryData) + + // 取消保活聊天室 + removeResp, err := rc.ChatroomKeepaliveRemove(ctx, &rongcloud.ChatroomKeepaliveRemoveRequest{ChatroomId: rongcloud.StringPtr("grp1")}) + if err != nil { + log.Fatalf("chatroom keepalive remove err %s", err) + } + removeData, _ := json.Marshal(removeResp) + log.Printf("chatroom keepalive remove resp %s", removeData) +} diff --git a/examples/chatroom/chatroomwhitelist.go b/examples/chatroom/chatroomwhitelist.go new file mode 100644 index 0000000..aaf0350 --- /dev/null +++ b/examples/chatroom/chatroomwhitelist.go @@ -0,0 +1,87 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + chatroomWhitelist(ctx, rc) + + chatroomUserWhitelist(ctx, rc) +} + +func chatroomWhitelist(ctx context.Context, rc *rongcloud.RongCloud) { + // 加入聊天室消息白名单 + _, err := rc.ChatroomWhitelistAdd(ctx, &rongcloud.ChatroomWhitelistAddRequest{ + ObjectNames: []string{"RC:VcMsg", "RC:ImgTextMsg"}}) + if err != nil { + log.Fatalf("chatroom white list add error %s", err) + } + + // 查询聊天室消息白名单 + whitelistQueryResp, err := rc.ChatroomWhitelistQuery(ctx, nil) + if err != nil { + log.Fatalf("chatroom white list query error %s", err) + } + whitelistQueryData, _ := json.Marshal(whitelistQueryResp) + log.Printf("chatroom white list query data: %s", whitelistQueryData) + + // 移出聊天室消息白名单 + _, err = rc.ChatroomWhitelistRemove(ctx, &rongcloud.ChatroomWhitelistRemoveRequest{ + ObjectNames: []string{"RC:VcMsg", "RC:ImgTextMsg"}, + }) + if err != nil { + log.Fatalf("chatroom white list remove error: %s", err) + } +} + +func chatroomUserWhitelist(ctx context.Context, rc *rongcloud.RongCloud) { + // 创建测试chatroom + grp := "grp1" + _, err := rc.ChatroomCreateNew(ctx, &rongcloud.ChatroomCreateNewRequest{ + ChatroomId: rongcloud.StringPtr(grp), + }) + if err != nil { + log.Fatalf("chatroom create error %s", err) + } + + // 加入聊天室用户白名单 + _, err = rc.ChatroomUserWhitelistAdd(ctx, &rongcloud.ChatroomUserWhitelistAddRequest{ + ChatroomId: rongcloud.StringPtr(grp), + UserIds: []string{"u01", "u02"}, + }) + if err != nil { + log.Fatalf("chatroom user whitelist add error %s", err) + } + + // 查询聊天室用户白名单 + queryUserWhitelistResp, err := rc.ChatroomUserWhitelistQuery(ctx, &rongcloud.ChatroomUserWhitelistQueryRequest{ChatroomId: rongcloud.StringPtr(grp)}) + if err != nil { + log.Fatalf("chatroom user whitelist query error %s", err) + } + queryUserWhitelistRespData, _ := json.Marshal(queryUserWhitelistResp) + log.Printf("query user whitelist resp data: %s", queryUserWhitelistRespData) + + // 移出聊天室用户白名单 + _, err = rc.ChatroomUserWhitelistRemove(ctx, &rongcloud.ChatroomUserWhitelistRemoveRequest{ + ChatroomId: rongcloud.StringPtr(grp), + UserIds: []string{"u01", "u02"}, + }) + if err != nil { + log.Printf("chatroom user whitlist ") + } + + // 销毁测试chatroom + _, err = rc.ChatroomDestroy(ctx, &rongcloud.ChatroomDestroyRequest{ChatroomIds: []string{grp}}) + if err != nil { + log.Fatalf("chatroom destroy error %s", err) + } +} diff --git a/examples/conversation/README.md b/examples/conversation/README.md new file mode 100644 index 0000000..ceb1541 --- /dev/null +++ b/examples/conversation/README.md @@ -0,0 +1,10 @@ +## 会话管理 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|---------------------------------|-------------|--------------------------------------| +| ConversationTopSet | 会话置顶 | [conversation.go](./conversation.go) | +| ConversationNotificationSet | 设置指定会话免打扰 | [conversation.go](./conversation.go) | +| ConversationNotificationGet | 查询指定会话免打扰 | [conversation.go](./conversation.go) | +| ConversationTypeNotificationSet | 设置指定会话类型免打扰 | [conversation.go](./conversation.go) | +| ConversationTypeNotificationGet | 查询指定会话类型免打扰 | [conversation.go](./conversation.go) | diff --git a/examples/conversation/conversation.go b/examples/conversation/conversation.go new file mode 100644 index 0000000..9844943 --- /dev/null +++ b/examples/conversation/conversation.go @@ -0,0 +1,73 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 会话置顶 + _, err := rc.ConversationTopSet(ctx, &rongcloud.ConversationTopSetRequest{ + UserId: rongcloud.StringPtr("u01"), + ConversationType: rongcloud.IntPtr(1), + TargetId: rongcloud.StringPtr("u02"), + SetTop: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("conversation top set error %s", err) + } + + // 设置指定会话免打扰 + _, err = rc.ConversationNotificationSet(ctx, &rongcloud.ConversationNotificationSetRequest{ + ConversationType: rongcloud.IntPtr(1), + RequestId: rongcloud.StringPtr("u01"), + TargetId: rongcloud.StringPtr("u02"), + IsMuted: nil, + BusChannel: nil, + UnpushLevel: rongcloud.IntPtr(-1), + }) + if err != nil { + log.Fatalf("conversation notification set error %s", err) + } + + // 查询指定会话免打扰 + notificationGetResp, err := rc.ConversationNotificationGet(ctx, &rongcloud.ConversationNotificationGetRequest{ + ConversationType: rongcloud.IntPtr(1), + RequestId: rongcloud.StringPtr("u01"), + TargetId: rongcloud.StringPtr("u02"), + BusChannel: nil, + }) + if err != nil { + log.Fatalf("conversation notification get error %s", err) + } + notificationGetRespData, _ := json.Marshal(notificationGetResp) + log.Printf("conversation notification get resp data: %s", notificationGetRespData) + + // 设置指定会话类型免打扰 + _, err = rc.ConversationTypeNotificationSet(ctx, &rongcloud.ConversationTypeNotificationSetRequest{ + ConversationType: rongcloud.IntPtr(1), + RequestId: rongcloud.StringPtr("u01"), + UnpushLevel: rongcloud.IntPtr(-1), + }) + if err != nil { + log.Fatalf("conversation notification type set error %s", err) + } + + // 查询指定会话类型免打扰 + typeNotificationGetResp, err := rc.ConversationTypeNotificationGet(ctx, &rongcloud.ConversationTypeNotificationGetRequest{ + ConversationType: rongcloud.IntPtr(1), + RequestId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("conversation type notification get error %s", err) + } + typeNotificationGetRespData, _ := json.Marshal(typeNotificationGetResp) + log.Printf("conversation type notification get resp data: %s", typeNotificationGetRespData) +} diff --git a/examples/group/README.md b/examples/group/README.md new file mode 100644 index 0000000..047dfb8 --- /dev/null +++ b/examples/group/README.md @@ -0,0 +1,23 @@ +## 群组管理 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|-------------------------------|-------------|--------------------------------------| +| GroupCreate | 创建群组 | [group.go](./group.go) | +| GroupJoin | 加入群组 | [group.go](./group.go) | +| GroupUserQuery | 查询群组成员 | [group.go](./group.go) | +| GroupDismiss | 解散群组 | [group.go](./group.go) | +| GroupBanAdd | 设置群组全体禁言 | [groupban.go](./groupban.go) | +| GroupBanQuery | 查询群组全体禁言 | [groupban.go](./groupban.go) | +| GroupUserBanWhitelistAdd | 加入群组全体禁言白名单 | [groupban.go](./groupban.go) | +| GroupUserBanWhitelistQuery | 查询群组全体禁言白名单 | [groupban.go](./groupban.go) | +| GroupUserBanWhitelistRollback | 移除群组全体禁言白名单 | [groupban.go](./groupban.go) | +| GroupRemarksSet | 设置群成员推送备注名 | [groupremarks.go](./groupremarks.go) | +| GroupRemarksGet | 查询群成员推送备注名 | [groupremarks.go](./groupremarks.go) | +| GroupRemarksDel | 删除群成员推送备注名 | [groupremarks.go](./groupremarks.go) | +| GroupUserGagAdd | 禁言指定群成员 | [groupusergag.go](./groupusergag.go) | +| GroupUserGagList | 查询群成员禁言列表 | [groupusergag.go](./groupusergag.go) | +| GroupUserGagRollback | 取消指定群成员禁言 | [groupusergag.go](./groupusergag.go) | +| UserGroupQuery | 查询用户所在群组 | [usergroup.go](./usergroup.go) | +| GroupSync | 同步用户所在群组 | [usergroup.go](./usergroup.go) | +| GroupRefresh | 刷新群组信息 | [usergroup.go](./usergroup.go) | diff --git a/examples/group/group.go b/examples/group/group.go new file mode 100644 index 0000000..4da7174 --- /dev/null +++ b/examples/group/group.go @@ -0,0 +1,63 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建群组 + _, err := rc.GroupCreate(ctx, &rongcloud.GroupCreateRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + GroupName: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group create error %s", err) + } + + // 加入群组 + _, err = rc.GroupJoin(ctx, &rongcloud.GroupJoinRequest{ + UserIds: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + GroupName: nil, + }) + if err != nil { + log.Fatalf("group join error %s", err) + } + + // 查询群组成员 + groupUserQueryResp, err := rc.GroupUserQuery(ctx, &rongcloud.GroupUserQueryRequest{ + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user query error: %s", err) + } + groupUserQueryRespData, _ := json.Marshal(groupUserQueryResp) + log.Printf("group user query response data: %s", groupUserQueryRespData) + + // 退出群组 + _, err = rc.GroupQuit(ctx, &rongcloud.GroupQuitRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group quit error %s", err) + } + + // 解散群组 + _, err = rc.GroupDismiss(ctx, &rongcloud.GroupDismissRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group dismiss error %s", err) + } +} diff --git a/examples/group/groupban.go b/examples/group/groupban.go new file mode 100644 index 0000000..f28f884 --- /dev/null +++ b/examples/group/groupban.go @@ -0,0 +1,79 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建群组 + _, err := rc.GroupCreate(ctx, &rongcloud.GroupCreateRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + GroupName: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group create error %s", err) + } + + // 设置群组全体禁言 + _, err = rc.GroupBanAdd(ctx, &rongcloud.GroupBanAddRequest{ + GroupIds: []string{"grp01", "grp02"}, + }) + if err != nil { + log.Fatalf("group ban add error %s", err) + } + + // 查询群组全体禁言 + groupBanQueryResp, err := rc.GroupBanQuery(ctx, &rongcloud.GroupBanQueryRequest{ + GroupIds: []string{"grp01", "grp02"}, + }) + if err != nil { + log.Fatalf("group ban query error %s", err) + } + groupBanQueryRespData, _ := json.Marshal(groupBanQueryResp) + log.Printf("group ban query response data: %s", groupBanQueryRespData) + + // 取消群组全体禁言 + _, err = rc.GroupBanRollback(ctx, &rongcloud.GroupBanRollbackRequest{ + GroupIds: []string{"grp01", "grp02"}, + }) + if err != nil { + log.Fatalf("group ban rollback error %s", err) + } + + // 加入群组全体禁言白名单 + _, err = rc.GroupUserBanWhitelistAdd(ctx, &rongcloud.GroupUserBanWhitelistAddRequest{ + UserIds: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user ban white list add error %s", err) + } + + // 查询群组全体禁言白名单 + groupUserBanWhitelistQueryResp, err := rc.GroupUserBanWhitelistQuery(ctx, &rongcloud.GroupUserBanWhitelistQueryRequest{ + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user ban whitelist query error %s", err) + } + groupUserBanWhitelistQueryRespData, _ := json.Marshal(groupUserBanWhitelistQueryResp) + log.Printf("group user ban white list query resp data: %s", groupUserBanWhitelistQueryRespData) + + // 移除群组全体禁言白名单 + _, err = rc.GroupUserBanWhitelistRollback(ctx, &rongcloud.GroupUserBanWhitelistRollbackRequest{ + UserIds: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user ban whitelist rollback error %s", err) + } +} diff --git a/examples/group/groupremarks.go b/examples/group/groupremarks.go new file mode 100644 index 0000000..7bc19b6 --- /dev/null +++ b/examples/group/groupremarks.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建群组 + _, err := rc.GroupCreate(ctx, &rongcloud.GroupCreateRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + GroupName: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group create error %s", err) + } + + // 设置群成员推送备注名 + _, err = rc.GroupRemarksSet(ctx, &rongcloud.GroupRemarksSetRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("grp01"), + Remark: rongcloud.StringPtr("u01Remarks"), + }) + if err != nil { + log.Fatalf("group remakrs set error %s", err) + } + + // 查询群成员推送备注名 + remarkGetResp, err := rc.GroupRemarksGet(ctx, &rongcloud.GroupRemarksGetRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group remarks get error %s", err) + } + remarkGetRespData, _ := json.Marshal(remarkGetResp) + log.Printf("group remarks get resp data: %s", remarkGetRespData) + + // 删除群成员推送备注名 + _, err = rc.GroupRemarksDel(ctx, &rongcloud.GroupRemarksDelRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group remark del error %s", err) + } +} diff --git a/examples/group/groupusergag.go b/examples/group/groupusergag.go new file mode 100644 index 0000000..690d891 --- /dev/null +++ b/examples/group/groupusergag.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 禁言指定群成员 + _, err := rc.GroupUserGagAdd(ctx, &rongcloud.GroupUserGagAddRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + Minute: rongcloud.IntPtr(30), + }) + if err != nil { + log.Fatalf("group user gaga add error %s", err) + } + + // 查询群成员禁言列表 + groupUserGagListResp, err := rc.GroupUserGagList(ctx, &rongcloud.GroupUserGagListRequest{ + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user gag list error %s", err) + } + groupUserGagListRespData, _ := json.Marshal(groupUserGagListResp) + log.Printf("group user gag list resp data: %s", groupUserGagListRespData) + + // 取消指定群成员禁言 + _, err = rc.GroupUserGagRollback(ctx, &rongcloud.GroupUserGagRollbackRequest{ + UserId: []string{"u01", "u02"}, + GroupId: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group user gag rollback error %s", err) + } +} diff --git a/examples/group/usergroup.go b/examples/group/usergroup.go new file mode 100644 index 0000000..cc35b71 --- /dev/null +++ b/examples/group/usergroup.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 查询用户所在群组 + userGroupQueryResp, err := rc.UserGroupQuery(ctx, &rongcloud.UserGroupQueryRequest{ + UserId: rongcloud.StringPtr("u01"), + Page: rongcloud.IntPtr(1), + Size: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("user group query error %s", err) + } + userGroupQueryRespData, _ := json.Marshal(userGroupQueryResp) + log.Printf("user group query resp data %s", userGroupQueryRespData) + + // 同步用户所在群组 + _, err = rc.GroupSync(ctx, &rongcloud.GroupSyncRequest{ + UserId: rongcloud.StringPtr("u01"), + Groups: rongcloud.SyncGroups{ + { + Id: "grp01", + Name: "grp01", + }, { + Id: "grp02", + Name: "grp02", + }, + }, + }) + if err != nil { + log.Fatalf("group sync error %s", err) + } + + // 刷新群组信息 + _, err = rc.GroupRefresh(ctx, &rongcloud.GroupRefreshRequest{ + GroupId: rongcloud.StringPtr("grp01"), + GroupName: rongcloud.StringPtr("grp01"), + }) + if err != nil { + log.Fatalf("group refresh error %s", err) + } +} diff --git a/examples/message/README.md b/examples/message/README.md new file mode 100644 index 0000000..0f73d93 --- /dev/null +++ b/examples/message/README.md @@ -0,0 +1,19 @@ +## 消息发送 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|-------------------------------|----------------|--------------------------------------------------------------------| +| MessagePrivatePublish | 发送单聊普通消息/自定义消息 | [messageprivate.go](./messageprivate.go) | +| MessageBroadcast | 发送全量用户落地通知 | [messagebroadcast.go](./messagebroadcast.go) | +| MessageChatroomPublish | 发送聊天室消息 | [messagechatroompublish.go](./messagechatroompublish.go) | +| MessageExpansionSet | 设置单群聊消息扩展 | [messageexpansion.go](./messageexpansion.go) | +| MessageExpansionQuery | 获取单群聊消息扩展 | [messageexpansion.go](./messageexpansion.go) | +| MessageExpansionDelete | 删除单群聊消息扩展 | [messageexpansion.go](./messageexpansion.go) | +| MessageGroupPublish | 发送群消息 | [messagegrouppublish.go](./messagegrouppublish.go) | +| MessageHistory | 获取历史消息日志 | [messagehistory.go](./messagehistory.go) | +| MessageHistoryDelete | 删除历史消息日志 | [messagehistory.go](./messagehistory.go) | +| MessagePrivatePublishTemplate | 发送单聊模板消息 | [messageprivatetemplate.go](./messageprivatetemplate.go) | +| MessageRecall | 撤回消息 | [messagerecall.go](./messagerecall.go) | +| MessageSystemPublish | 发送系统通知普通消息 | [messagesystempublish.go](./messagesystempublish.go) | +| MessageUltraGroupPublish | 发送超级群消息 | [messageultragroup.go](./messageultragroup.go) | +| StatusMessagePrivatePublish | 发送单聊状态消息 | [statusmessageprivatepublish.go](./statusmessageprivatepublish.go) | \ No newline at end of file diff --git a/examples/message/messagebroadcast.go b/examples/message/messagebroadcast.go new file mode 100644 index 0000000..fb59c6d --- /dev/null +++ b/examples/message/messagebroadcast.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送全量用户落地通知 + _, err := rc.MessageBroadcast(ctx, &rongcloud.MessageBroadcastRequest{ + FromUserId: rongcloud.StringPtr("u01"), + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + PushContent: nil, + PushData: nil, + ContentAvailable: nil, + PushExt: nil, + }) + if err != nil { + log.Fatalf("message broadcast error %s", err) + } + + // 发送全体聊天室广播消息 + _, err = rc.MessageChatroomBroadcast(ctx, &rongcloud.MessageChatroomBroadcastRequest{ + FromUserId: rongcloud.StringPtr("u01"), + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + IsIncludeSender: nil, + }) + if err != nil { + log.Fatalf("message chatroom broadcast error %s", err) + } + + // 发送在线用户广播 + _, err = rc.MessageOnlineBroadcast(ctx, &rongcloud.MessageOnlineBroadcastRequest{ + FromUserId: rongcloud.StringPtr("u01"), + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("message online broadcast error %s", err) + } +} diff --git a/examples/message/messagechatroompublish.go b/examples/message/messagechatroompublish.go new file mode 100644 index 0000000..338fbcf --- /dev/null +++ b/examples/message/messagechatroompublish.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送聊天室消息 + _, err := rc.MessageChatroomPublish(ctx, &rongcloud.MessageChatroomPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToChatroomId: []string{"chrm01", "chrm02"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("golang ") + } +} diff --git a/examples/message/messageexpansion.go b/examples/message/messageexpansion.go new file mode 100644 index 0000000..e76c6cb --- /dev/null +++ b/examples/message/messageexpansion.go @@ -0,0 +1,58 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + testMsgUID := "CDCV-7C6J-P604-3F9O" + // 设置单群聊消息扩展 + extraKeyVal := map[string]string{ + "key1": "val1", + } + _, err := rc.MessageExpansionSet(ctx, &rongcloud.MessageExpansionSetRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + UserId: rongcloud.StringPtr("u01"), + ConversationType: rongcloud.StringPtr(rongcloud.ConversationTypePrivate), + TargetId: rongcloud.StringPtr("u02"), + ExtraKeyVal: extraKeyVal, + IsSyncSender: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("message expansion set error %s", err) + } + log.Printf("message expansion set success") + + // 获取单群聊消息扩展 + expansionResp, err := rc.MessageExpansionQuery(ctx, &rongcloud.MessageExpansionQueryRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + PageNo: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("message expansion query error %s", err) + } + for k, value := range expansionResp.ExtraContent { + log.Printf("expansion query key: %s, value: %+v", k, value) + } + + // 删除单群聊消息扩展 + _, err = rc.MessageExpansionDelete(ctx, &rongcloud.MessageExpansionDeleteRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + UserId: rongcloud.StringPtr("u01"), + ConversationType: rongcloud.StringPtr(rongcloud.ConversationTypePrivate), + TargetId: rongcloud.StringPtr("u02"), + ExtraKey: []string{"key1", "key2"}, + IsSyncSender: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("message expansion delete error %s", err) + } + log.Printf("message expansion delete success") +} diff --git a/examples/message/messagegrouppublish.go b/examples/message/messagegrouppublish.go new file mode 100644 index 0000000..4ebff32 --- /dev/null +++ b/examples/message/messagegrouppublish.go @@ -0,0 +1,39 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送群消息 + _, err := rc.MessageGroupPublish(ctx, &rongcloud.MessageGroupPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToGroupId: []string{"g01", "g02"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("message group publish error %s", err) + } + + // 发送群定向消息 + _, err = rc.MessageGroupPublish(ctx, &rongcloud.MessageGroupPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToGroupId: []string{"g01"}, // 发送群聊定向消息时,仅支持传入一个群组 ID + ToUserId: []string{"u02", "u02"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("message group publish error %s", err) + } +} diff --git a/examples/message/messagehistory.go b/examples/message/messagehistory.go new file mode 100644 index 0000000..414929a --- /dev/null +++ b/examples/message/messagehistory.go @@ -0,0 +1,36 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "time" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + now := time.Now().Format("2006010215") + + // 获取历史消息日志 + messageHistory, err := rc.MessageHistory(ctx, &rongcloud.MessageHistoryRequest{ + Date: rongcloud.StringPtr(now), + }) + if err != nil { + log.Fatalf("message history error %s", err) + } + messageHistoryData, _ := json.Marshal(messageHistory) + log.Printf("message history %s", messageHistoryData) + + // 删除历史消息日志 + _, err = rc.MessageHistoryDelete(ctx, &rongcloud.MessageHistoryDeleteRequest{ + Date: rongcloud.StringPtr(now), + }) + if err != nil { + log.Fatalf("message history delete error %s", err) + } +} diff --git a/examples/message/messageprivate.go b/examples/message/messageprivate.go new file mode 100644 index 0000000..59e4a7e --- /dev/null +++ b/examples/message/messageprivate.go @@ -0,0 +1,97 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/google/uuid" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + messagePrivate(ctx, rc) +} + +func messagePrivate(ctx context.Context, rc *rongcloud.RongCloud) { + // 发送单聊文本消息 + txtMsg := &rongcloud.TXTMsg{ + Content: "hello world", + } + requestId := uuid.New().String() + rongcloud.AddHttpRequestId(ctx, requestId) + _, err := rc.MessagePrivatePublish(ctx, &rongcloud.MessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: rongcloud.StringPtr("u02"), + RCMsg: txtMsg, + }) + if err != nil { + log.Fatalf("msg private publish error: %s", err) + } + // 发送单聊语音消息 + hqvsMsg := &rongcloud.HQVCMsg{ + RemoteUrl: "http://example.com/1", + Duration: 2, + } + _, err = rc.MessagePrivatePublish(ctx, &rongcloud.MessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: rongcloud.StringPtr("u02"), + RCMsg: hqvsMsg, + }) + if err != nil { + log.Fatalf("hqvs msg private publish error: %s", err) + } + // 发送单聊图片消息 + // 更多信息请参考 https://doc.rongcloud.cn/imserver/server/v1/message/objectname#%E5%9B%BE%E7%89%87%E6%B6%88%E6%81%AF + imgMsg := &rongcloud.ImgMsg{ + Content: "/9j/4AAQSkZJRgABAgAAZABkAAD", + ImageURI: "http://p1.cdn.com/fds78ruhi.jpg", + Extra: "", + } + _, err = rc.MessagePrivatePublish(ctx, &rongcloud.MessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: rongcloud.StringPtr("u02"), + RCMsg: imgMsg, + }) + if err != nil { + log.Printf("img msg private publish error: %s", err) + } + + // 发送单聊自定义消息 + customMsg := &CustomJsonMsg{ + Field1: "custom json msg", + Field2: 1, + Field3: true, + } + _, err = rc.MessagePrivatePublish(ctx, &rongcloud.MessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: rongcloud.StringPtr("u02"), + RCMsg: customMsg, + }) + if err != nil { + log.Fatalf("custom msg private publish error: %s", err) + } +} + +// CustomJsonMsg +// 自定义消息类型需开发者自行实现rongcloud.RCMsg接口 +type CustomJsonMsg struct { + Field1 string + Field2 int + Field3 bool +} + +// ObjectName 自定义消息ObjectName尽量不要以RC:开头 +func (m *CustomJsonMsg) ObjectName() string { + return "XXX:CustomMsg" +} + +func (m *CustomJsonMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} diff --git a/examples/message/messageprivatetemplate.go b/examples/message/messageprivatetemplate.go new file mode 100644 index 0000000..fbdaf48 --- /dev/null +++ b/examples/message/messageprivatetemplate.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送单聊模板消息 + pushContent := "Dear {username}, please check your score." + _, err := rc.MessagePrivatePublishTemplate(ctx, &rongcloud.MessagePrivatePublishTemplateRequest{ + FromUserId: rongcloud.StringPtr("u01"), + RCMsg: &rongcloud.TXTMsg{ + Content: "Dear {username}, your score is {score}", + }, + MessageTemplate: []*rongcloud.MessageTemplate{ + { + ToUserId: "u02", + Value: map[string]string{ + "username": "u02", + "score": "1", + }, + PushContent: pushContent, + PushData: "", + }, { + ToUserId: "u03", + Value: map[string]string{ + "username": "u03", + "score": "2", + }, + PushContent: pushContent, + PushData: "", + }, + }, + }) + if err != nil { + log.Fatalf("message private publish template error %s", err) + } + + // 发送系统通知模板消息 + _, err = rc.MessageSystemPublishTemplate(ctx, &rongcloud.MessageSystemPublishTemplateRequest{ + FromUserId: rongcloud.StringPtr("u01"), + RCMsg: &rongcloud.TXTMsg{ + Content: "Dear {username}, your score is {score}", + }, + MessageTemplate: []*rongcloud.MessageTemplate{ + { + ToUserId: "u02", + Value: map[string]string{ + "username": "u02", + "score": "1", + }, + PushContent: pushContent, + PushData: "", + }, { + ToUserId: "u03", + Value: map[string]string{ + "username": "u03", + "score": "2", + }, + PushContent: pushContent, + PushData: "", + }, + }, + }) + if err != nil { + log.Fatalf("message system publish template error %s", err) + } +} diff --git a/examples/message/messagerecall.go b/examples/message/messagerecall.go new file mode 100644 index 0000000..e95e90d --- /dev/null +++ b/examples/message/messagerecall.go @@ -0,0 +1,32 @@ +package main + +import ( + "context" + "log" + "os" + "time" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 撤回消息 + _, err := rc.MessageRecall(ctx, &rongcloud.MessageRecallRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ConversationType: rongcloud.IntPtr(1), + TargetId: rongcloud.StringPtr("u02"), + BusChannel: nil, + MessageUID: rongcloud.StringPtr("CDCF-J1T2-UJ64-3F9N"), + SentTime: rongcloud.Int64Ptr(time.Now().Unix()), + IsAdmin: nil, + IsDelete: nil, + DisablePush: nil, + Extra: nil, + }) + if err != nil { + log.Fatalf("message recall error %s", err) + } +} diff --git a/examples/message/messagesystempublish.go b/examples/message/messagesystempublish.go new file mode 100644 index 0000000..22ab207 --- /dev/null +++ b/examples/message/messagesystempublish.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送系统通知普通消息 + _, err := rc.MessageSystemPublish(ctx, &rongcloud.MessageSystemPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserId: []string{"u02", "u03"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("message system publish error %s", err) + } +} diff --git a/examples/message/messageultragroup.go b/examples/message/messageultragroup.go new file mode 100644 index 0000000..c870032 --- /dev/null +++ b/examples/message/messageultragroup.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送超级群消息 + txtMsg := &rongcloud.TXTMsg{ + Content: "hello world", + } + content, err := txtMsg.ToString() + if err != nil { + log.Fatalf("txt msg marshal content error %s", err) + } + extraContent := map[string]string{ + "key1": "key2", + } + extraContentStr, err := json.Marshal(extraContent) + if err != nil { + log.Fatalf("json.Marshal extraContent error %s", err) + } + _, err = rc.MessageUltraGroupPublish(ctx, &rongcloud.MessageUltraGroupPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToGroupIds: []string{"ug01"}, + ObjectName: rongcloud.StringPtr(txtMsg.ObjectName()), + Content: rongcloud.StringPtr(content), + PushContent: nil, + PushData: nil, + IsPersisted: nil, + IsCounted: nil, + IsMentioned: nil, + ContentAvailable: nil, + PushExt: nil, + BusChannel: rongcloud.StringPtr("channel01"), + Expansion: rongcloud.BoolPtr(true), + ExtraContent: rongcloud.StringPtr(string(extraContentStr)), + }) + if err != nil { + log.Fatalf("message ultra group publish error %s", err) + } +} diff --git a/examples/message/statusmessageprivatepublish.go b/examples/message/statusmessageprivatepublish.go new file mode 100644 index 0000000..4878464 --- /dev/null +++ b/examples/message/statusmessageprivatepublish.go @@ -0,0 +1,40 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + ctx := context.Background() + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + + // 发送单聊状态消息 + _, err := rc.StatusMessagePrivatePublish(ctx, &rongcloud.StatusMessagePrivatePublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToUserIds: []string{"u02", "u03"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + VerifyBlacklist: nil, + IsIncludeSender: nil, + }) + if err != nil { + log.Fatalf("status message private publish error %s", err) + } + + // 发送群聊状态消息 + _, err = rc.StatusMessageGroupPublish(ctx, &rongcloud.StatusMessageGroupPublishRequest{ + FromUserId: rongcloud.StringPtr("u01"), + ToGroupId: []string{"g01", "g02"}, + RCMsg: &rongcloud.TXTMsg{ + Content: "hello world", + }, + }) + if err != nil { + log.Fatalf("status message group publish error %s", err) + } +} diff --git a/examples/option/option.go b/examples/option/option.go new file mode 100644 index 0000000..766e75c --- /dev/null +++ b/examples/option/option.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/google/uuid" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + requestId := uuid.New().String() + // 自定义requestId + rongcloud.AddHttpRequestId(ctx, requestId) + + resp, err := rc.UserGetToken(ctx, &rongcloud.UserGetTokenRequest{ + UserId: rongcloud.StringPtr("u01"), + Name: rongcloud.StringPtr("u01"), + PortraitUri: nil, + }) + if err != nil { + log.Fatalf("user get token error %s", err) + } + // 获取http.Response + httpResp := resp.GetHttpResponse() + // 快捷方法获取x-request-id + + requestIdResp := resp.GetRequestId() + log.Printf("http response %+v, requestId: %s, requestIdResp: %s", httpResp, requestId, requestIdResp) +} diff --git a/examples/push/README.md b/examples/push/README.md new file mode 100644 index 0000000..26082e0 --- /dev/null +++ b/examples/push/README.md @@ -0,0 +1,8 @@ +## 推送管理 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|------------|----------------------------|----------------------------------| +| Push | 发送全量用户通知/发送应用包名通知/发送标签用户通知 | [push.go](./push.go) | +| PushCustom | 推送Plus专用推送接口,发送不落地通知 | [pushcustom.go](./pushcustom.go) | +| PushUser | 发送指定用户不落地通知 | [pushuser.go](./pushuser.go) | diff --git a/examples/push/push.go b/examples/push/push.go new file mode 100644 index 0000000..a8da151 --- /dev/null +++ b/examples/push/push.go @@ -0,0 +1,108 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + platform := []string{"ios", "android"} + pushNotification := &rongcloud.PushNotification{ + Title: rongcloud.StringPtr("标题"), + ForceShowPushContent: nil, + Alert: rongcloud.StringPtr("this is a push"), + IOS: &rongcloud.PushNotificationIOS{ + Title: nil, + ContentAvailable: nil, + Alert: rongcloud.StringPtr("override alert"), + Badge: nil, + ThreadId: rongcloud.StringPtr("223"), + ApnsCollapseId: nil, + Category: nil, + RichMediaUri: nil, + InterruptionLevel: nil, + Extras: map[string]string{"id": "1", "name": "2"}, + }, + Android: &rongcloud.PushNotificationAndroid{ + Alert: rongcloud.StringPtr("override alert"), + Honor: &rongcloud.PushAndroidHonor{ + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + HW: &rongcloud.PushAndroidHW{ + ChannelId: rongcloud.StringPtr("NotificationKanong"), + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + Oppo: &rongcloud.PushAndroidOppo{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + }, + Vivo: &rongcloud.PushAndroidVivo{ + Classification: rongcloud.StringPtr("0"), + }, + Fcm: &rongcloud.PushAndroidFcm{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + ImageUrl: rongcloud.StringPtr("https://example.com/image.png"), + }, + Extras: map[string]string{ + "id": "1", + "name": "2", + }, + }, + } + txtMsg := &rongcloud.TXTMsg{ + Content: "hello world", + } + + // 发送全量用户通知 + pushResp, err := rc.Push(ctx, &rongcloud.PushRequest{ + Platform: platform, + Audience: &rongcloud.PushAudience{ + IsToAll: rongcloud.BoolPtr(true), + }, + Message: txtMsg, + Notification: pushNotification, + }) + if err != nil { + log.Fatalf("push response error %s", err) + } + pushRespData, _ := json.Marshal(pushResp) + log.Printf("push response data: %s", pushRespData) + + // 发送应用包名通知 + _, err = rc.Push(ctx, &rongcloud.PushRequest{ + Platform: platform, + FromUserid: rongcloud.StringPtr("u01"), + Audience: &rongcloud.PushAudience{ + PackageName: rongcloud.StringPtr("xxx.rong.xxx"), // 根据应用包名发送通知只需要设置这个参数 + IsToAll: rongcloud.BoolPtr(false), + }, + Message: txtMsg, + Notification: pushNotification, + }) + if err != nil { + log.Fatalf("push response by packageName error %s", err) + } + + // 发送标签用户通知 + _, err = rc.Push(ctx, &rongcloud.PushRequest{ + Platform: platform, + FromUserid: rongcloud.StringPtr("u01"), + Audience: &rongcloud.PushAudience{ + Tag: []string{"女", "年轻"}, + TagOr: []string{"北京", "上海"}, + IsToAll: rongcloud.BoolPtr(false), + }, + Message: txtMsg, + Notification: pushNotification, + }) + if err != nil { + log.Fatalf("push response by tag error %s", err) + } +} diff --git a/examples/push/pushcustom.go b/examples/push/pushcustom.go new file mode 100644 index 0000000..59bc1a8 --- /dev/null +++ b/examples/push/pushcustom.go @@ -0,0 +1,102 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + pushNotification := &rongcloud.PushCustomNotification{ + Title: rongcloud.StringPtr("标题"), + Alert: rongcloud.StringPtr("this is a push"), + IOS: &rongcloud.PushCustomNotificationIOS{ + ThreadId: rongcloud.StringPtr("223"), + ApnsCollapseId: rongcloud.StringPtr("111"), + Extras: map[string]string{ + "id": "1", + "name": "2", + }, + }, + Android: &rongcloud.PushAndroid{ + Honor: &rongcloud.PushAndroidHonor{ + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + HW: &rongcloud.PushAndroidHW{ + ChannelId: rongcloud.StringPtr("NotificationKanong"), + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + Oppo: &rongcloud.PushAndroidOppo{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + }, + Vivo: &rongcloud.PushAndroidVivo{ + Classification: rongcloud.StringPtr("0"), + }, + Fcm: &rongcloud.PushAndroidFcm{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + ImageUrl: rongcloud.StringPtr("https://example.com/image.png"), + }, + Extras: map[string]string{ + "id": "1", + "name": "2", + }, + }, + } + // 示例 1:按用户标签推送(同时使用 audience.tag 与 audience.tag_or) + pushResp, err := rc.PushCustom(ctx, &rongcloud.PushCustomRequest{ + Platform: []string{"ios", "android"}, + Audience: &rongcloud.PushCustomAudience{ + Tag: []string{"女", "年轻"}, + TagOr: []string{"北京", "上海"}, + PackageName: nil, + IsToAll: nil, + TagItems: nil, + }, + Notification: pushNotification, + }) + if err != nil { + log.Fatalf("push custom example 1 error %s", err) + } + pushRespData, _ := json.Marshal(pushResp) + log.Printf("push response data: %s", pushRespData) + + // 示例 2:按用户标签推送(使用 audience.tagItems) + pushResp2, err := rc.PushCustom(ctx, &rongcloud.PushCustomRequest{ + Platform: []string{"ios", "android"}, + Audience: &rongcloud.PushCustomAudience{ + TagItems: []*rongcloud.PushCustomAudienceTagItem{ + { + Tags: []string{"guangdong", "hunan"}, + IsNot: rongcloud.BoolPtr(false), + TagsOperator: rongcloud.StringPtr("OR"), + ItemsOperator: rongcloud.StringPtr("OR"), + }, { + Tags: []string{"20200408"}, + IsNot: rongcloud.BoolPtr(true), + TagsOperator: rongcloud.StringPtr("OR"), + ItemsOperator: rongcloud.StringPtr("AND"), + }, { + Tags: []string{"male", "female"}, + IsNot: rongcloud.BoolPtr(false), + TagsOperator: rongcloud.StringPtr("OR"), + ItemsOperator: rongcloud.StringPtr("OR"), + }, + }, + IsToAll: rongcloud.BoolPtr(false), + }, + Notification: pushNotification, + }) + if err != nil { + log.Fatalf("push custom example 2 error %s", err) + } + pushResp2Data, _ := json.Marshal(pushResp2) + log.Printf("push response example 2 data: %s", pushResp2Data) +} diff --git a/examples/push/pushuser.go b/examples/push/pushuser.go new file mode 100644 index 0000000..a37b10b --- /dev/null +++ b/examples/push/pushuser.go @@ -0,0 +1,64 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + pushUserNotification := &rongcloud.PushUserNotification{ + Title: rongcloud.StringPtr("标题"), + PushContent: rongcloud.StringPtr("this is a push"), + IOS: &rongcloud.PushUserNotificationIOS{ + ThreadId: rongcloud.StringPtr("223"), + ApnsCollapseId: rongcloud.StringPtr("111"), + Extras: map[string]string{ + "id": "1", + "name": "2", + }, + }, + Android: &rongcloud.PushAndroid{ + Honor: &rongcloud.PushAndroidHonor{ + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + HW: &rongcloud.PushAndroidHW{ + ChannelId: rongcloud.StringPtr("NotificationKanong"), + Importance: rongcloud.StringPtr("NORMAL"), + Image: rongcloud.StringPtr("https://example.com/image.png"), + }, + Oppo: &rongcloud.PushAndroidOppo{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + }, + Vivo: &rongcloud.PushAndroidVivo{ + Classification: rongcloud.StringPtr("0"), + }, + Fcm: &rongcloud.PushAndroidFcm{ + ChannelId: rongcloud.StringPtr("rc_notification_id"), + ImageUrl: rongcloud.StringPtr("https://example.com/image.png"), + }, + Extras: map[string]string{ + "id": "1", + "name": "2", + }, + }, + } + + // 发送指定用户不落地通知 + pushUserResp, err := rc.PushUser(ctx, &rongcloud.PushUserRequest{ + UserIds: []string{"u01", "u02"}, + Notification: pushUserNotification, + }) + if err != nil { + log.Fatalf("push user response error %s", err) + } + pushUserRespData, _ := json.Marshal(pushUserResp) + log.Printf("push user resp data: %s", pushUserRespData) +} diff --git a/examples/sensitive/README.md b/examples/sensitive/README.md new file mode 100644 index 0000000..2c43a16 --- /dev/null +++ b/examples/sensitive/README.md @@ -0,0 +1,8 @@ +## 敏感词管理 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|--------------------------|-----------|--------------------------------| +| SensitiveWordAdd | 添加消息敏感词 | [sensitive.go](./sensitive.go) | +| SensitiveWordList | 查询消息敏感词 | [sensitive.go](./sensitive.go) | +| SensitiveWordBatchDelete | 批量移除消息敏感词 | [sensitive.go](./sensitive.go) | diff --git a/examples/sensitive/sensitive.go b/examples/sensitive/sensitive.go new file mode 100644 index 0000000..65c7f09 --- /dev/null +++ b/examples/sensitive/sensitive.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 添加消息敏感词 + _, err := rc.SensitiveWordAdd(ctx, &rongcloud.SensitiveWordAddRequest{ + Word: rongcloud.StringPtr("money"), + ReplaceWord: rongcloud.StringPtr("***"), + }) + if err != nil { + log.Fatalf("sensitive word add error %s", err) + } + + // 查询消息敏感词 + listSensitiveWordResp, err := rc.SensitiveWordList(ctx, &rongcloud.SensitiveWordListRequest{ + Type: rongcloud.StringPtr("2"), + }) + if err != nil { + log.Fatalf("sensitive word list error %s", err) + } + listSensitiveWordRespData, _ := json.Marshal(listSensitiveWordResp) + log.Printf("sensitive word list response data: %s", listSensitiveWordRespData) + + // 批量移除消息敏感词 + _, err = rc.SensitiveWordBatchDelete(ctx, &rongcloud.SensitiveWordBatchDeleteRequest{ + Words: []string{"money"}, + }) + if err != nil { + log.Fatalf("sensitive word batch delete error %s", err) + } +} diff --git a/examples/ultragroup/README.md b/examples/ultragroup/README.md new file mode 100644 index 0000000..4cd91c1 --- /dev/null +++ b/examples/ultragroup/README.md @@ -0,0 +1,44 @@ +## 超级群管理 + +### 方法列表 +| 方法名 | 说明 | 调用示例 | +|----------------------------------|---------------|------------------------------------------------------------------------| +| UltraGroupCreate | 创建超级群 | [ultragroup.go](./ultragroup.go) | +| UltraGroupJoin | 加入超级群 | [ultragroup.go](./ultragroup.go) | +| UltraGroupMemberExist | 查询用户是否为群成员 | [ultragroup.go](./ultragroup.go) | +| UltraGroupQuit | 退出超级群 | [ultragroup.go](./ultragroup.go) | +| UltraGroupRefresh | 刷新超级群信息 | [ultragroup.go](./ultragroup.go) | +| UltraGroupDis | 解散超级群 | [ultragroup.go](./ultragroup.go) | +| UltraGroupBannedWhitelistAdd | 加入超级群全体禁言白名单 | [ultragroupbannedwhitelist.go](./ultragroupbannedwhitelist.go) | +| UltraGroupBannedWhitelistGet | 查询群组全体禁言白名单 | [ultragroupbannedwhitelist.go](./ultragroupbannedwhitelist.go) | +| UltraGroupBannedWhitelistDel | 移出超级群全体禁言白名单 | [ultragroupbannedwhitelist.go](./ultragroupbannedwhitelist.go) | +| UltraGroupChannelCreate | 创建频道 | [ultragroupchannel.go](./ultragroupchannel.go) | +| UltraGroupChannelGet | 查询频道列表 | [ultragroupchannel.go](./ultragroupchannel.go) | +| UltraGroupChannelTypeChange | 变更频道类型 | [ultragroupchannel.go](./ultragroupchannel.go) | +| UltraGroupChannelDel | 删除频道 | [ultragroupchannel.go](./ultragroupchannel.go) | +| UltraGroupChannelPrivateUsersAdd | 添加私有频道成员 | [ultragroupchannelprivateusers.go](./ultragroupchannelprivateusers.go) | +| UltraGroupChannelPrivateUsersGet | 查询私有频道成员列表 | [ultragroupchannelprivateusers.go](./ultragroupchannelprivateusers.go) | +| UltraGroupChannelPrivateUsersDel | 删除私有频道成员 | [ultragroupchannelprivateusers.go](./ultragroupchannelprivateusers.go) | +| UltraGroupGlobalBannedSet | 设置超级群全体禁言 | [ultragroupglobalban.go](./ultragroupglobalban.go) | +| UltraGroupGlobalBannedGet | 查询超级群全体禁言 | [ultragroupglobalban.go](./ultragroupglobalban.go) | +| UltraGroupHismsgQuery | 搜索超级群消息 | [ultragrouphismsg.go](./ultragrouphismsg.go) | +| UltraGroupHismsgMsgIdQuery | 搜索超级群消息上下文 | [ultragrouphismsg.go](./ultragrouphismsg.go) | +| UltraGroupMessageExpansionSet | 设置超级群消息扩展 | [ultragroupmessageexansion.go](./ultragroupmessageexansion.go) | +| UltraGroupMessageExpansionQuery | 获取超级群消息扩展 | [ultragroupmessageexansion.go](./ultragroupmessageexansion.go) | +| UltraGroupMessageExpansionDelete | 删除超级群消息扩展 | [ultragroupmessageexansion.go](./ultragroupmessageexansion.go) | +| UltraGroupNotDisturbSet | 设置群/频道默认免打扰 | [ultragroupnotdisturb.go](./ultragroupnotdisturb.go) | +| UltraGroupNotDisturbGet | 查询默认免打扰配置 | [ultragroupnotdisturb.go](./ultragroupnotdisturb.go) | +| UltraGroupUserBannedAdd | 禁言指定超级群成员 | [ultragroupuserbanned.go](./ultragroupuserbanned.go) | +| UltraGroupUserBannedGet | 查询超级群成员禁言列表 | [ultragroupuserbanned.go](./ultragroupuserbanned.go) | +| UltraGroupUserBannedDel | 取消指定超级群成员禁言 | [ultragroupuserbanned.go](./ultragroupuserbanned.go) | +| UltraGroupUserGroupAdd | 创建用户组 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupUserGroupDel | 删除用户组 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupUserGroupQuery | 查询用户组列表 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupChannelUserGroupBind | 超级群绑定频道与用户组 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupChannelUserGroupQuery | 超级群查询频道绑定的用户组 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupUserGroupChannelQuery | 超级群查询用户组绑定的频道 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupChannelUserGroupUnbind | 超级群解绑频道与用户组 | [ultragroupusergroup.go](./ultragroupusergroup.go) | +| UltraGroupUserGroupUserAdd | 超级群用户组添加用户 | [ultragroupusergroupuser.go](./ultragroupusergroupuser.go) | +| UltraGroupUserUserGroupQuery | 超级群查询用户所属用户组 | [ultragroupusergroupuser.go](./ultragroupusergroupuser.go) | +| UltraGroupUserGroupUserDel | 超级群用户组移出用户 | [ultragroupusergroupuser.go](./ultragroupusergroupuser.go) | +| UltraGroupMsgModify | 修改超级群消息 | [urlgragroupmsgmodify.go](./urlgragroupmsgmodify.go) | diff --git a/examples/ultragroup/ultragroup.go b/examples/ultragroup/ultragroup.go new file mode 100644 index 0000000..0f4e604 --- /dev/null +++ b/examples/ultragroup/ultragroup.go @@ -0,0 +1,66 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建超级群 + _, err := rc.UltraGroupCreate(ctx, &rongcloud.UltraGroupCreateRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("ug01"), + GroupName: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group create error %s", err) + } + + // 加入超级群 + _, err = rc.UltraGroupJoin(ctx, &rongcloud.UltraGroupJoinRequest{ + UserId: rongcloud.StringPtr("u02"), + GroupId: rongcloud.StringPtr("ug01"), + }) + + // 查询用户是否为群成员 + ultraGroupMemberExistResp, err := rc.UltraGroupMemberExist(ctx, &rongcloud.UltraGroupMemberExistRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group member exist error %s", err) + } + ultraGroupMemberExistRespData, _ := json.Marshal(ultraGroupMemberExistResp) + log.Printf("ultra group member exist resp data %s", ultraGroupMemberExistRespData) + + // 退出超级群 + _, err = rc.UltraGroupQuit(ctx, &rongcloud.UltraGroupQuitRequest{ + UserId: rongcloud.StringPtr("u02"), + GroupId: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group quit error %s", err) + } + + // 刷新超级群信息 + _, err = rc.UltraGroupRefresh(ctx, &rongcloud.UltraGroupRefreshRequest{ + GroupId: rongcloud.StringPtr("ug01"), + GroupName: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group refresh error %s", err) + } + + // 解散超级群 + _, err = rc.UltraGroupDis(ctx, &rongcloud.UltraGroupDisRequest{GroupId: rongcloud.StringPtr("ug01")}) + if err != nil { + log.Fatalf("ultra group dis error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupbannedwhitelist.go b/examples/ultragroup/ultragroupbannedwhitelist.go new file mode 100644 index 0000000..339f88d --- /dev/null +++ b/examples/ultragroup/ultragroupbannedwhitelist.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 加入超级群全体禁言白名单 + _, err := rc.UltraGroupBannedWhitelistAdd(ctx, &rongcloud.UltraGroupBannedWhitelistAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group banned whitelist add error %s", err) + } + + // 查询群组全体禁言白名单 + ugBannedWhitelistResp, err := rc.UltraGroupBannedWhitelistGet(ctx, &rongcloud.UltraGroupBannedWhitelistGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("ultra group banned whitelist get error %s", err) + } + ugBannedWhitelistRespData, _ := json.Marshal(ugBannedWhitelistResp) + log.Printf("ultra group whitelist resp data %s", ugBannedWhitelistRespData) + + // 移出超级群全体禁言白名单 + _, err = rc.UltraGroupBannedWhitelistDel(ctx, &rongcloud.UltraGroupBannedWhitelistDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group banned whitelist del error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupchannel.go b/examples/ultragroup/ultragroupchannel.go new file mode 100644 index 0000000..70c6f81 --- /dev/null +++ b/examples/ultragroup/ultragroupchannel.go @@ -0,0 +1,56 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建频道 + _, err := rc.UltraGroupChannelCreate(ctx, &rongcloud.UltraGroupChannelCreateRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Type: rongcloud.IntPtr(0), + }) + if err != nil { + log.Fatalf("ultra group channel create error %s", err) + } + + // 查询频道列表 + ultraGroupChannelResp, err := rc.UltraGroupChannelGet(ctx, &rongcloud.UltraGroupChannelGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + Page: rongcloud.IntPtr(1), + Limit: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("ultra group channel get error %s", err) + } + ultraGroupChannelRespData, _ := json.Marshal(ultraGroupChannelResp) + log.Printf("ultra group channel resp data: %s", ultraGroupChannelRespData) + + // 变更频道类型 + _, err = rc.UltraGroupChannelTypeChange(ctx, &rongcloud.UltraGroupChannelTypeChangeRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Type: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("ultra group channel type change error %s", err) + } + + // 删除频道 + _, err = rc.UltraGroupChannelDel(ctx, &rongcloud.UltraGroupChannelDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + }) + if err != nil { + log.Fatalf("ultra group channel del error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupchannelprivateusers.go b/examples/ultragroup/ultragroupchannelprivateusers.go new file mode 100644 index 0000000..bca7030 --- /dev/null +++ b/examples/ultragroup/ultragroupchannelprivateusers.go @@ -0,0 +1,83 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建超级群 + _, err := rc.UltraGroupCreate(ctx, &rongcloud.UltraGroupCreateRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("ug01"), + GroupName: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group create error %s", err) + } + + // 加入超级群 + _, err = rc.UltraGroupJoin(ctx, &rongcloud.UltraGroupJoinRequest{ + UserId: rongcloud.StringPtr("u02"), + GroupId: rongcloud.StringPtr("ug01"), + }) + + // 添加私有频道成员 + _, err = rc.UltraGroupChannelPrivateUsersAdd(ctx, &rongcloud.UltraGroupChannelPrivateUsersAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group channel private users add error: %s", err) + } + + // 查询私有频道成员列表 + usersQueryResp, err := rc.UltraGroupChannelPrivateUsersGet(ctx, &rongcloud.UltraGroupChannelPrivateUsersGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("ultra group channel private users get error %s", err) + } + usersQueryRespData, _ := json.Marshal(usersQueryResp) + log.Printf("ultra group channel private users get data %s", usersQueryRespData) + + // 查询用户所属的私有频道 + userChannelQueryResp, err := rc.UltraGroupUserChannelQuery(ctx, &rongcloud.UltraGroupUserChannelQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserId: rongcloud.StringPtr("u01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("ultra group user channel query error %s", err) + } + userChannelQueryRespData, _ := json.Marshal(userChannelQueryResp) + log.Printf("ultra group user channel query data %s", userChannelQueryRespData) + + // 删除私有频道成员 + _, err = rc.UltraGroupChannelPrivateUsersDel(ctx, &rongcloud.UltraGroupChannelPrivateUsersDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group channel private users del error: %s", err) + } + + // 解散超级群 + _, err = rc.UltraGroupDis(ctx, &rongcloud.UltraGroupDisRequest{GroupId: rongcloud.StringPtr("ug01")}) + if err != nil { + log.Fatalf("ultra group dis error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupglobalban.go b/examples/ultragroup/ultragroupglobalban.go new file mode 100644 index 0000000..837771a --- /dev/null +++ b/examples/ultragroup/ultragroupglobalban.go @@ -0,0 +1,36 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 设置超级群全体禁言 + _, err := rc.UltraGroupGlobalBannedSet(ctx, &rongcloud.UltraGroupGlobalBannedSetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Status: rongcloud.BoolPtr(true), + }) + if err != nil { + log.Fatalf("ultra group global banned set error %s", err) + } + + // 查询超级群全体禁言 + globalBannedGetResp, err := rc.UltraGroupGlobalBannedGet(ctx, &rongcloud.UltraGroupGlobalBannedGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + }) + if err != nil { + log.Fatalf("ultra group global banned get error %s", err) + } + globalBannedGetRespData, _ := json.Marshal(globalBannedGetResp) + log.Printf("ultra group global banned get resp data: %s", globalBannedGetRespData) +} diff --git a/examples/ultragroup/ultragrouphismsg.go b/examples/ultragroup/ultragrouphismsg.go new file mode 100644 index 0000000..60edfb5 --- /dev/null +++ b/examples/ultragroup/ultragrouphismsg.go @@ -0,0 +1,46 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "time" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 搜索超级群消息 + yesterday := time.Now().Add(-time.Hour * 24) + now := time.Now() + hisMsgResp, err := rc.UltraGroupHismsgQuery(ctx, &rongcloud.UltraGroupHismsgQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + StartTime: rongcloud.Int64Ptr(yesterday.UnixMilli()), + EndTime: rongcloud.Int64Ptr(now.UnixMilli()), + //FromUserId: rongcloud.StringPtr("u01"), + PageSize: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("ultra group his msg query error %s", err) + } + hisMsgData, _ := json.Marshal(hisMsgResp) + log.Printf("ultra group his msg query data %s", hisMsgData) + + // 搜索超级群消息上下文 + hisIdMsg, err := rc.UltraGroupHismsgMsgIdQuery(ctx, &rongcloud.UltraGroupHisMsgMsgIdQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + MsgUID: rongcloud.StringPtr("CDEV-2TTV-IKQ4-3F9N"), + PrevNum: nil, + }) + if err != nil { + log.Fatalf("ultra group his msg msgId query error %s", err) + } + hisMsgIdData, _ := json.Marshal(hisIdMsg) + log.Printf("ultra group his msg %s", hisMsgIdData) +} diff --git a/examples/ultragroup/ultragroupmessageexansion.go b/examples/ultragroup/ultragroupmessageexansion.go new file mode 100644 index 0000000..531e5b4 --- /dev/null +++ b/examples/ultragroup/ultragroupmessageexansion.go @@ -0,0 +1,62 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + testMsgUID := "CDF1-21C2-A73B-DE0J" + // 设置超级群消息扩展 + extraKeyVal := map[string]string{ + "k1": "v1", + "k2": "v2", + } + extraKeyValStr, err := json.Marshal(extraKeyVal) + if err != nil { + log.Fatalf("json marshal extraKeyVal error %s", err) + } + _, err = rc.UltraGroupMessageExpansionSet(ctx, &rongcloud.UltraGroupMessageExpansionSetRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + UserId: rongcloud.StringPtr("u01"), + BusChannel: rongcloud.StringPtr("channel01"), + GroupId: rongcloud.StringPtr("ug01"), + ExtraKeyVal: rongcloud.StringPtr(string(extraKeyValStr)), + }) + if err != nil { + log.Fatalf("ultra group message expansion set error %s", err) + } + + // 获取超级群消息扩展 + messageExpansionQueryResp, err := rc.UltraGroupMessageExpansionQuery(ctx, &rongcloud.UltraGroupMessageExpansionQueryRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + BusChannel: rongcloud.StringPtr("channel01"), + GroupId: rongcloud.StringPtr("ug01"), + PageNo: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("ultragroup message expansion query error %s", err) + } + messageExpansionQueryRespData, _ := json.Marshal(messageExpansionQueryResp) + log.Printf("ultra group message expansion query data %s", messageExpansionQueryRespData) + + // 删除超级群消息扩展 + extraKeys, err := json.Marshal([]string{"k1", "k2", "key1"}) + _, err = rc.UltraGroupMessageExpansionDelete(ctx, &rongcloud.UltraGroupMessageExpansionDeleteRequest{ + MsgUID: rongcloud.StringPtr(testMsgUID), + UserId: rongcloud.StringPtr("u01"), + BusChannel: rongcloud.StringPtr("channel01"), + GroupId: rongcloud.StringPtr("ug01"), + ExtraKey: rongcloud.StringPtr(string(extraKeys)), + }) + if err != nil { + log.Fatalf("ultra group message expansion delete error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupnotdisturb.go b/examples/ultragroup/ultragroupnotdisturb.go new file mode 100644 index 0000000..cf39913 --- /dev/null +++ b/examples/ultragroup/ultragroupnotdisturb.go @@ -0,0 +1,36 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 设置群/频道默认免打扰 + _, err := rc.UltraGroupNotDisturbSet(ctx, &rongcloud.UltraGroupNotDisturbSetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UnpushLevel: rongcloud.IntPtr(-1), + }) + if err != nil { + log.Fatalf("ultra group not disturb set error %s", err) + } + + // 查询默认免打扰配置 + ultraGroupNotDisturbGetResp, err := rc.UltraGroupNotDisturbGet(ctx, &rongcloud.UltraGroupNotDisturbGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + }) + if err != nil { + log.Fatalf("ultra group not disturb get error %s", err) + } + ultraGroupNotDisturbGetRespData, _ := json.Marshal(ultraGroupNotDisturbGetResp) + log.Printf("ultra group not disturb get resp data: %s", ultraGroupNotDisturbGetRespData) +} diff --git a/examples/ultragroup/ultragroupuserbanned.go b/examples/ultragroup/ultragroupuserbanned.go new file mode 100644 index 0000000..5f4338d --- /dev/null +++ b/examples/ultragroup/ultragroupuserbanned.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 禁言指定超级群成员 + _, err := rc.UltraGroupUserBannedAdd(ctx, &rongcloud.UltraGroupUserBannedAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group user banned add error %s", err) + } + + // 查询超级群成员禁言列表 + ultraGroupUserBannedResp, err := rc.UltraGroupUserBannedGet(ctx, &rongcloud.UltraGroupUserBannedGetRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("ultra group user banned get error %s", err) + } + ultraGroupUserBannedRespData, _ := json.Marshal(ultraGroupUserBannedResp) + log.Printf("ultra group user banned resp data: %s", ultraGroupUserBannedRespData) + + // 取消指定超级群成员禁言 + _, err = rc.UltraGroupUserBannedDel(ctx, &rongcloud.UltraGroupUserBannedDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group user banned del error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupusergroup.go b/examples/ultragroup/ultragroupusergroup.go new file mode 100644 index 0000000..776c101 --- /dev/null +++ b/examples/ultragroup/ultragroupusergroup.go @@ -0,0 +1,122 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + // 创建超级群 + _, err := rc.UltraGroupCreate(ctx, &rongcloud.UltraGroupCreateRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("ug01"), + GroupName: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group create error %s", err) + } + + // 创建频道 + _, err = rc.UltraGroupChannelCreate(ctx, &rongcloud.UltraGroupChannelCreateRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Type: rongcloud.IntPtr(0), + }) + if err != nil { + log.Fatalf("ultra group channel create error %s", err) + } + + // 创建用户组 + _, err = rc.UltraGroupUserGroupAdd(ctx, &rongcloud.UltraGroupUserGroupAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroups: []*rongcloud.UltraGroupUserGroup{ + { + UserGroupId: "usg01", + }, { + UserGroupId: "usg02", + }, + }, + }) + if err != nil { + log.Fatalf("ultra group user group add error %s", err) + } + + // 查询用户组列表 + userGroupQueryResp, err := rc.UltraGroupUserGroupQuery(ctx, &rongcloud.UltraGroupUserGroupQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("ultra group user group query error %s", err) + } + userGroupQueryRespData, _ := json.Marshal(userGroupQueryResp) + log.Printf("ultra group user query resp data: %s", userGroupQueryRespData) + + // 超级群绑定频道与用户组 + _, err = rc.UltraGroupChannelUserGroupBind(ctx, &rongcloud.UltraGroupChannelUserGroupBindRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserGroupIds: rongcloud.StringPtr("usg01,usg02"), + }) + if err != nil { + log.Fatalf("ultra group channel userGroup bind error %s", err) + } + + // 超级群查询频道绑定的用户组 + channelUserGroupQueryResp, err := rc.UltraGroupChannelUserGroupQuery(ctx, &rongcloud.UltraGroupChannelUserGroupQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("ultra group channel userGroup query error %s", err) + } + channelUserGroupQueryRespData, _ := json.Marshal(channelUserGroupQueryResp) + log.Printf("ultra group channel userGroup query data %s", channelUserGroupQueryRespData) + + // 超级群查询用户组绑定的频道 + userGroupChannelQueryResp, err := rc.UltraGroupUserGroupChannelQuery(ctx, &rongcloud.UltraGroupUserGroupChannelQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroupId: rongcloud.StringPtr("usg01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("ultra group userGroup channel query error %s", err) + } + userGroupChannelQueryRespData, _ := json.Marshal(userGroupChannelQueryResp) + log.Printf("ultra group userGroup channel query data %s", userGroupChannelQueryRespData) + + // 超级群解绑频道与用户组 + _, err = rc.UltraGroupChannelUserGroupUnbind(ctx, &rongcloud.UltraGroupChannelUserGroupUnbindRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + UserGroupIds: rongcloud.StringPtr("usg01,usg02"), + }) + if err != nil { + log.Fatalf("ultra group channel userGroup unbind error %s", err) + } + + // 删除用户组 + _, err = rc.UltraGroupUserGroupDel(ctx, &rongcloud.UltraGroupUserGroupDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroupIds: rongcloud.StringPtr("usg01,usg02"), + }) + if err != nil { + log.Fatalf("ultra group user group del error %s", err) + } + + // 解散超级群 + _, err = rc.UltraGroupDis(ctx, &rongcloud.UltraGroupDisRequest{GroupId: rongcloud.StringPtr("ug01")}) + if err != nil { + log.Fatalf("ultra group dis error %s", err) + } +} diff --git a/examples/ultragroup/ultragroupusergroupuser.go b/examples/ultragroup/ultragroupusergroupuser.go new file mode 100644 index 0000000..79d2946 --- /dev/null +++ b/examples/ultragroup/ultragroupusergroupuser.go @@ -0,0 +1,73 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 创建超级群 + _, err := rc.UltraGroupCreate(ctx, &rongcloud.UltraGroupCreateRequest{ + UserId: rongcloud.StringPtr("u01"), + GroupId: rongcloud.StringPtr("ug01"), + GroupName: rongcloud.StringPtr("ug01"), + }) + if err != nil { + log.Fatalf("ultra group create error %s", err) + } + + // 超级群创建用户组 + _, err = rc.UltraGroupUserGroupAdd(ctx, &rongcloud.UltraGroupUserGroupAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroups: []*rongcloud.UltraGroupUserGroup{ + { + UserGroupId: "usg01", + }, { + UserGroupId: "usg02", + }, + }, + }) + if err != nil { + log.Fatalf("ultra group user group add error %s", err) + } + + // 超级群用户组添加用户 + _, err = rc.UltraGroupUserGroupUserAdd(ctx, &rongcloud.UltraGroupUserGroupUserAddRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroupId: rongcloud.StringPtr("usg01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group user group user add error %s", err) + } + + // 超级群查询用户所属用户组 + userUserGroupQueryResp, err := rc.UltraGroupUserUserGroupQuery(ctx, &rongcloud.UltraGroupUserUserGroupQueryRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserId: rongcloud.StringPtr("u01"), + Page: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(10), + }) + if err != nil { + log.Fatalf("ultra group user user group query error %s", err) + } + userUserGroupQueryRespData, _ := json.Marshal(userUserGroupQueryResp) + log.Printf("user user group query resp data: %s", userUserGroupQueryRespData) + + // 超级群用户组移出用户 + _, err = rc.UltraGroupUserGroupUserDel(ctx, &rongcloud.UltraGroupUserGroupUserDelRequest{ + GroupId: rongcloud.StringPtr("ug01"), + UserGroupId: rongcloud.StringPtr("usg01"), + UserIds: rongcloud.StringPtr("u01,u02"), + }) + if err != nil { + log.Fatalf("ultra group user group user del error %s", err) + } +} diff --git a/examples/ultragroup/urlgragroupmsgmodify.go b/examples/ultragroup/urlgragroupmsgmodify.go new file mode 100644 index 0000000..f39d4ab --- /dev/null +++ b/examples/ultragroup/urlgragroupmsgmodify.go @@ -0,0 +1,33 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + txtMsg := &rongcloud.TXTMsg{ + Content: "modify hello world", + } + content, err := txtMsg.ToString() + if err != nil { + log.Fatalf("txtMsg ToString() error %s", err) + } + // 修改超级群消息 + _, err = rc.UltraGroupMsgModify(ctx, &rongcloud.UltraGroupMsgModifyRequest{ + GroupId: rongcloud.StringPtr("ug01"), + BusChannel: rongcloud.StringPtr("channel01"), + FromUserId: rongcloud.StringPtr("u01"), + MsgUID: rongcloud.StringPtr("CDEV-2TTV-IKQ4-3F9N"), + Content: rongcloud.StringPtr(content), + }) + if err != nil { + log.Fatalf("ultragroup msg modify error %s", err) + } +} diff --git a/examples/user/README.md b/examples/user/README.md new file mode 100644 index 0000000..144f4fc --- /dev/null +++ b/examples/user/README.md @@ -0,0 +1,33 @@ +## 用户管理 + +### 方法列表 + +| 方法名 | 说明 | 调用示例 | +|---------------------------|------------|----------------------------------------------------| +| UserBlacklistAdd | 添加用户到黑名单 | [userblacklist.go](./userblacklist.go) | +| UserBlacklistQuery | 获取黑名单用户列表 | [userblacklist.go](./userblacklist.go) | +| UserBlacklistRemove | 移除黑名单中用户 | [userblacklist.go](./userblacklist.go) | +| UserBlock | 封禁用户 | [userblock.go](./userblock.go) | +| UserBlockQuery | 获取封禁用户列表 | [userblock.go](./userblock.go) | +| UserUnBlock | 解除封禁 | [userblock.go](./userblock.go) | +| UserBlockPushPeriodSet | 设置用户免打扰时段 | [userblockpushperiod.go](./userblockpushperiod.go) | +| UserBlockPushPeriodGet | 查询用户免打扰时段 | [userblockpushperiod.go](./userblockpushperiod.go) | +| UserBlockPushPeriodDelete | 删除用户免打扰时段 | [userblockpushperiod.go](./userblockpushperiod.go) | +| UserChatFBSet | 设置用户单聊禁言 | [userchatfb.go](./userchatfb.go) | +| UserChatFBQueryList | 查询单聊禁言用户列表 | [userchatfb.go](./userchatfb.go) | +| UserCheckOnline | 查询用户在线状态 | [usercheckonline.go](./usercheckonline.go) | +| UserDeactivate | 注销用户 | [userdeactivate.go](./userdeactivate.go) | +| UserDeactivateQuery | 查询已注销用户 | [userdeactivate.go](./userdeactivate.go) | +| UserReactivate | 重新激活用户 ID | [userdeactivate.go](./userdeactivate.go) | +| UserRefresh | 修改用户信息 | [userrefresh.go](./userrefresh.go) | +| UserRemarksSet | 设置用户级推送备注名 | [userremarks.go](./userremarks.go) | +| UserRemarksGet | 查询用户级推送备注名 | [userremarks.go](./userremarks.go) | +| UserRemarksDel | 删除用户级推送备注名 | [userremarks.go](./userremarks.go) | +| UserTagSet | 设置用户标签 | [usertag.go](./usertag.go) | +| UserTagBatchSet | 批量设置用户标签 | [usertag.go](./usertag.go) | +| UserTagsGet | 获取用户标签 | [usertag.go](./usertag.go) | +| UserGetToken | 注册用户 | [usertoken.go](./usertoken.go) | +| UserTokenExpire | 作废token | [usertoken.go](./usertoken.go) | +| UserWhitelistAdd | 添加用户到白名单 | [userwhitelist.go](./userwhitelist.go) | +| UserWhitelistQuery | 移除白名单中用户 | [userwhitelist.go](./userwhitelist.go) | +| UserWhitelistRemove | 移除白名单中用户 | [userwhitelist.go](./userwhitelist.go) | diff --git a/examples/user/userblacklist.go b/examples/user/userblacklist.go new file mode 100644 index 0000000..4d8646c --- /dev/null +++ b/examples/user/userblacklist.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 添加用户到黑名单 + _, err := rc.UserBlacklistAdd(ctx, &rongcloud.UserBlacklistAddRequest{ + UserId: rongcloud.StringPtr("u01"), + BlackUserId: []string{"u02", "u03"}, + }) + if err != nil { + log.Fatalf("user black list add error %s", err) + } + + // 获取黑名单用户列表 + userBlackListQueryResp, err := rc.UserBlacklistQuery(ctx, &rongcloud.UserBlacklistQueryRequest{ + UserId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user blacklist query error %s", err) + } + userBlackListQueryRespData, _ := json.Marshal(userBlackListQueryResp) + log.Printf("user blacklist query response data: %s", userBlackListQueryRespData) + + // 移除黑名单中用户 + _, err = rc.UserBlacklistRemove(ctx, &rongcloud.UserBlacklistRemoveRequest{ + UserId: rongcloud.StringPtr("u01"), + BlackUserId: []string{"u02", "u03"}, + }) + if err != nil { + log.Fatalf("user blacklist remove error %s", err) + } +} diff --git a/examples/user/userblock.go b/examples/user/userblock.go new file mode 100644 index 0000000..7f60cdb --- /dev/null +++ b/examples/user/userblock.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 封禁用户 + _, err := rc.UserBlock(ctx, &rongcloud.UserBlockRequest{ + UserId: []string{"u01", "u02"}, + Minute: rongcloud.IntPtr(43200), + }) + if err != nil { + log.Fatalf("user block error %s", err) + } + + // 获取封禁用户列表 + userBlockQueryResp, err := rc.UserBlockQuery(ctx, &rongcloud.UserBlockQueryRequest{ + Page: rongcloud.IntPtr(1), + Size: rongcloud.IntPtr(50), + }) + if err != nil { + log.Fatalf("user block error %s", err) + } + userBlockQueryRespData, _ := json.Marshal(userBlockQueryResp) + log.Printf("user block query response data: %s", userBlockQueryRespData) + + // 解除封禁 + _, err = rc.UserUnBlock(ctx, &rongcloud.UserUnBlockRequest{ + UserId: []string{"u01", "u02"}, + }) + if err != nil { + log.Fatalf("user unblock error %s", err) + } +} diff --git a/examples/user/userblockpushperiod.go b/examples/user/userblockpushperiod.go new file mode 100644 index 0000000..dccca00 --- /dev/null +++ b/examples/user/userblockpushperiod.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 设置用户免打扰时段 + _, err := rc.UserBlockPushPeriodSet(ctx, &rongcloud.UserBlockPushPeriodSetRequest{ + UserId: rongcloud.StringPtr("u01"), + StartTime: rongcloud.StringPtr("22:00:00"), + Period: rongcloud.IntPtr(60 * 9), // 22:00:00 - 07:00:00 时段免打扰 + Level: rongcloud.IntPtr(1), + }) + if err != nil { + log.Fatalf("user block push period set error %s", err) + } + + // 查询用户免打扰时段 + userBlockPushPeriodGetResp, err := rc.UserBlockPushPeriodGet(ctx, &rongcloud.UserBlockPushPeriodGetRequest{ + UserId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user block push period get error %s", err) + } + userBlockPushPeriodGetRespData, _ := json.Marshal(userBlockPushPeriodGetResp) + log.Printf("user block push period get response data: %s", userBlockPushPeriodGetRespData) + + // 删除用户免打扰时段 + _, err = rc.UserBlockPushPeriodDelete(ctx, &rongcloud.UserBlockPushPeriodDeleteRequest{ + UserId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user block push period delete error %s", err) + } +} diff --git a/examples/user/userchatfb.go b/examples/user/userchatfb.go new file mode 100644 index 0000000..ff2935b --- /dev/null +++ b/examples/user/userchatfb.go @@ -0,0 +1,38 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + const personType = "PERSON" + + // 设置用户单聊禁言 + _, err := rc.UserChatFBSet(ctx, &rongcloud.UserChatFBSetRequest{ + UserId: []string{"u02", "u01"}, + State: rongcloud.IntPtr(1), + Type: rongcloud.StringPtr(personType), + }) + if err != nil { + log.Fatalf("user chat fb set error %s", err) + } + + // 查询单聊禁言用户列表 + userChatFBQueryListResp, err := rc.UserChatFBQueryList(ctx, &rongcloud.UserChatFBQueryListRequest{ + Num: rongcloud.IntPtr(50), + Offset: rongcloud.IntPtr(0), + Type: rongcloud.StringPtr(personType), + }) + if err != nil { + log.Fatalf("user chat fb query list error %s", err) + } + userChatFBQueryListRespData, _ := json.Marshal(userChatFBQueryListResp) + log.Printf("user chat fb query list response data: %s", userChatFBQueryListRespData) +} diff --git a/examples/user/usercheckonline.go b/examples/user/usercheckonline.go new file mode 100644 index 0000000..3ff82e7 --- /dev/null +++ b/examples/user/usercheckonline.go @@ -0,0 +1,25 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 查询用户在线状态 + userCheckOnlineResp, err := rc.UserCheckOnline(ctx, &rongcloud.UserCheckOnlineRequest{ + UserId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user check online error %s", err) + } + userCheckOnlineRespData, _ := json.Marshal(userCheckOnlineResp) + log.Printf("user check online response data: %s", userCheckOnlineRespData) +} diff --git a/examples/user/userdeactivate.go b/examples/user/userdeactivate.go new file mode 100644 index 0000000..a096c2c --- /dev/null +++ b/examples/user/userdeactivate.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "strings" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 注销用户 + _, err := rc.UserDeactivate(ctx, &rongcloud.UserDeactivateRequest{ + UserId: rongcloud.StringPtr(strings.Join([]string{"u01", "u02"}, ",")), + }) + if err != nil { + log.Fatalf("user deactivate error %s", err) + } + + // 查询已注销用户 + userDeactivateQueryResp, err := rc.UserDeactivateQuery(ctx, &rongcloud.UserDeactivateQueryRequest{ + PageNo: rongcloud.IntPtr(1), + PageSize: rongcloud.IntPtr(20), + }) + if err != nil { + log.Fatalf("user deactivate query error %s", err) + } + userDeactivateQueryRespData, _ := json.Marshal(userDeactivateQueryResp) + log.Printf("user deactivate query response data: %s", userDeactivateQueryRespData) + + // 重新激活用户 ID + _, err = rc.UserReactivate(ctx, &rongcloud.UserReactivateRequest{ + UserId: rongcloud.StringPtr(strings.Join([]string{"u01", "u02"}, ",")), + }) + if err != nil { + log.Fatalf("use reactivate error %s", err) + } +} diff --git a/examples/user/userrefresh.go b/examples/user/userrefresh.go new file mode 100644 index 0000000..d89307a --- /dev/null +++ b/examples/user/userrefresh.go @@ -0,0 +1,24 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 修改用户信息 + _, err := rc.UserRefresh(ctx, &rongcloud.UserRefreshRequest{ + UserId: rongcloud.StringPtr("u01"), + Name: rongcloud.StringPtr("u01"), + PortraitUri: nil, + }) + if err != nil { + log.Fatalf("user refresh error %s", err) + } +} diff --git a/examples/user/userremarks.go b/examples/user/userremarks.go new file mode 100644 index 0000000..71ebc9e --- /dev/null +++ b/examples/user/userremarks.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 设置用户级推送备注名 + _, err := rc.UserRemarksSet(ctx, &rongcloud.UserRemarksSetRequest{ + UserId: rongcloud.StringPtr("u01"), + Remarks: []*rongcloud.UserRemark{ + { + Id: "u02", + Remark: "alias-u02", + }, { + Id: "u03", + Remark: "alias-u03", + }, + }, + }) + if err != nil { + log.Fatalf("user remarks set error %s", err) + } + + // 查询用户级推送备注名 + userRemarksGetResp, err := rc.UserRemarksGet(ctx, &rongcloud.UserRemarksGetRequest{ + UserId: rongcloud.StringPtr("u01"), + Page: rongcloud.IntPtr(1), + Size: rongcloud.IntPtr(50), + }) + if err != nil { + log.Fatalf("user remarks get error %s", err) + } + userRemarksGetRespData, _ := json.Marshal(userRemarksGetResp) + log.Printf("user remarks get response data: %s", userRemarksGetRespData) + + // 删除用户级推送备注名 + _, err = rc.UserRemarksDel(ctx, &rongcloud.UserRemarksDelRequest{ + UserId: rongcloud.StringPtr("u01"), + TargetId: rongcloud.StringPtr("u02"), + }) + if err != nil { + log.Fatalf("user remarks del error %s", err) + } +} diff --git a/examples/user/usertag.go b/examples/user/usertag.go new file mode 100644 index 0000000..439148b --- /dev/null +++ b/examples/user/usertag.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 设置用户标签 + _, err := rc.UserTagSet(ctx, &rongcloud.UserTagSetRequest{ + UserId: rongcloud.StringPtr("u01"), + Tags: []string{"tag1", "tag2"}, + }) + if err != nil { + log.Fatalf("user tag set error %s", err) + } + + // 批量设置用户标签 + _, err = rc.UserTagBatchSet(ctx, &rongcloud.UserTagBatchSetRequest{ + UserIds: []string{"u01", "u02"}, + Tags: []string{"tag3", "tag4"}, + }) + if err != nil { + log.Fatalf("user tag batch set error %s", err) + } + + // 获取用户标签 + userTagsGetResp, err := rc.UserTagsGet(ctx, &rongcloud.UserTagsGetRequest{ + UserIds: []string{"u01", "u02"}, + }) + if err != nil { + log.Fatalf("user tags get error %s", err) + } + userTagsGetRespData, _ := json.Marshal(userTagsGetResp) + log.Printf("user tags get response data: %s", userTagsGetRespData) +} diff --git a/examples/user/usertoken.go b/examples/user/usertoken.go new file mode 100644 index 0000000..9411866 --- /dev/null +++ b/examples/user/usertoken.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "time" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 注册用户 + getTokenResp, err := rc.UserGetToken(ctx, &rongcloud.UserGetTokenRequest{ + UserId: rongcloud.StringPtr("uu01"), + Name: rongcloud.StringPtr("uu01"), + PortraitUri: rongcloud.StringPtr("http://a.b.com/a.jpg"), + }) + if err != nil { + log.Fatalf("user get token error %s", err) + } + getTokenRespData, _ := json.Marshal(getTokenResp) + log.Printf("use get token response data: %s", getTokenRespData) + + // 作废token + _, err = rc.UserTokenExpire(ctx, &rongcloud.UserTokenExpireRequest{ + UserId: []string{"uu01"}, + Time: rongcloud.Int64Ptr(time.Now().Add(time.Hour * 10).UnixMilli()), + }) + if err != nil { + log.Fatalf("user token expire error %s", err) + } +} diff --git a/examples/user/userwhitelist.go b/examples/user/userwhitelist.go new file mode 100644 index 0000000..fa0cb66 --- /dev/null +++ b/examples/user/userwhitelist.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + + "github.com/rongcloud/server-sdk-go/v4/rongcloud" +) + +func main() { + rc := rongcloud.NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + ctx := context.Background() + + // 添加用户到白名单 + _, err := rc.UserWhitelistAdd(ctx, &rongcloud.UserWhitelistAddRequest{ + UserId: rongcloud.StringPtr("u01"), + WhiteUserId: []string{"u02", "u03"}, + }) + if err != nil { + log.Fatalf("user whitelist add error %s", err) + } + + // 查询白名单中用户列表 + whitelistQueryResp, err := rc.UserWhitelistQuery(ctx, &rongcloud.UserWhitelistQueryRequest{ + UserId: rongcloud.StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user whitelist query error %s", err) + } + whitelistQueryRespData, _ := json.Marshal(whitelistQueryResp) + log.Printf("user whitelist query response data: %s", whitelistQueryRespData) + + // 移除白名单中用户 + _, err = rc.UserWhitelistRemove(ctx, &rongcloud.UserWhitelistRemoveRequest{ + UserId: rongcloud.StringPtr("u01"), + WhiteUserId: []string{"u02", "u03"}, + }) + if err != nil { + log.Fatalf("user whitelist remove error %s", err) + } +} diff --git a/go.mod b/go.mod index 8c41754..d17bb0a 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ -module github.com/rongcloud/server-sdk-go/v3 +module github.com/rongcloud/server-sdk-go/v4 require ( - github.com/astaxie/beego v1.12.0 + github.com/google/go-querystring v1.1.0 github.com/google/uuid v1.3.0 ) diff --git a/go.sum b/go.sum index 50f95f5..dc858ff 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,8 @@ -github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= -github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= -github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= -github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= -github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= -github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= -github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= -github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= -github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= -github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= -github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= -github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= -github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= -github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= -github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= -github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= -github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= -github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= -golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/rongcloud/chatroom.go b/rongcloud/chatroom.go new file mode 100644 index 0000000..8a8087a --- /dev/null +++ b/rongcloud/chatroom.go @@ -0,0 +1,1197 @@ +package rongcloud + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "strconv" +) + +// chatroom 聊天室 + +type ChatroomUserExistRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 要查询的聊天室 ID + UserId *string `json:"userId"` // [必传] 要查询的用户 ID +} + +type ChatroomUserExistResponse struct { + httpResponseGetter `json:"-"` + CodeResult + // 用户是否在聊天室中,true 表示在聊天室中,false 表示不在聊天室中。 + IsInChrm bool `json:"isInChrm"` +} + +// ChatroomUserExist 查询是否在聊天室中 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/check-member +func (rc *RongCloud) ChatroomUserExist(ctx context.Context, req *ChatroomUserExistRequest) (*ChatroomUserExistResponse, error) { + resp := &ChatroomUserExistResponse{} + params := url.Values{} + params.Set("chatroomId", StringValue(req.ChatroomId)) + params.Set("userId", StringValue(req.UserId)) + httpResponse, err := rc.postFormUrlencoded(ctx, "/chatroom/user/exist.json", params, &resp) + if err != nil { + return resp, err + } + resp.httpResponseGetter = &rawHttpResponseGetter{rawHttpResponseInternal: httpResponse} + return resp, nil +} + +type ChatroomCreateNewRequest struct { + // [必传] 聊天室 ID。 + ChatroomId *string `json:"chatroomId"` + // 指定聊天室的销毁类型。0:默认值,表示不活跃时销毁。默认情况下,所有聊天室的自动销毁方式均为不活跃时销毁,一旦不活跃长达到 60 分钟即被销毁,可通过 destroyTime 延长该时间。1:固定时间销毁,设置为该类型后,聊天室默认在创建 60 分钟后自动销毁,可通过 destroyTime 设置更长的存活时间。您也可以在聊天室创建成功后再设置,详见设置聊天室销毁类型。 + DestroyType *int `json:"destroyType"` + // 设置聊天室销毁时间。在 destroyType=0 时,表示聊天室应在不活跃达到该时长时自动销毁。在 destroyType=1 时,表示聊天室应在创建以后存活时间达到该时长后自动销毁。单位为分钟,最小值 60 分钟,最大 10080 分钟(7 天)。如果未设置,默认 60 分钟。 + DestroyTime *int `json:"destroyTime"` + // 是否禁言聊天室全体成员,默认 false。您也可以在聊天室创建成功后再设置,详见设置聊天室全体禁言。 + IsBan *bool `json:"isBan"` + // 禁言白名单用户列表,支持批量设置,最多不超过 20 个。您也可以在聊天室创建成功后再设置,详见加入聊天室全体禁言白名单。 + WhiteUserIds []string `json:"whiteUserIds"` + + // 聊天室自定义属性的所属用户 ID。仅在开通聊天室自定义属性服务后可使用该字段,且必须与 entryInfo 字段一起使用。如果未开启服务,或者设置该字段时未同时传入 entryInfo,API 会返回创建失败。仅支持 1 个用户 ID。您也可以在聊天室创建成功后再设置,详见聊天室属性概述。 + EntryOwnerId *string `json:"entryOwnerId"` + EntryInfo map[string]string `json:"entryInfo"` +} + +type ChatroomCreateNewResponse struct { + httpResponseGetter `json:"-"` + CodeResult +} + +// ChatroomCreateNew create new chatroom +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/create +func (rc *RongCloud) ChatroomCreateNew(ctx context.Context, req *ChatroomCreateNewRequest) (*ChatroomCreateNewResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.DestroyType != nil { + params.Set("destroyType", strconv.Itoa(IntValue(req.DestroyType))) + } + if req.DestroyTime != nil { + params.Set("destroyTime", strconv.Itoa(IntValue(req.DestroyTime))) + } + if req.IsBan != nil { + params.Set("isBan", strconv.FormatBool(BoolValue(req.IsBan))) + } + if req.WhiteUserIds != nil { + for _, item := range req.WhiteUserIds { + params.Add("whiteUserIds", item) + } + } + if req.EntryOwnerId != nil { + params.Set("entryOwnerId", StringValue(req.EntryOwnerId)) + } + if req.EntryInfo != nil { + entryInfo, err := json.Marshal(req.EntryInfo) + if err != nil { + return nil, fmt.Errorf("marshal entryInfo err: %w", err) + } + params.Set("entryInfo", string(entryInfo)) + } + + resp := &ChatroomCreateNewResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/create_new.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomDestroySetRequest struct { + // [必传] 聊天室 ID。 + ChatroomId *string `json:"chatroomId"` + // 指定聊天室的销毁类型。0:默认值,表示不活跃时销毁。默认情况下,所有聊天室的自动销毁方式均为不活跃时销毁,一旦不活跃长达到 60 分钟即被销毁,可通过 destroyTime 延长该时间。1:固定时间销毁,设置为该类型后,聊天室默认在创建 60 分钟后自动销毁,可通过 destroyTime 设置更长的存活时间。您也可以在聊天室创建成功后再设置,详见设置聊天室销毁类型。 + DestroyType *int `json:"destroyType"` + // 设置聊天室销毁时间。在 destroyType=0 时,表示聊天室应在不活跃达到该时长时自动销毁。在 destroyType=1 时,表示聊天室应在创建以后存活时间达到该时长后自动销毁。单位为分钟,最小值 60 分钟,最大 10080 分钟(7 天)。如果未设置,默认 60 分钟。 + DestroyTime *int `json:"destroyTime"` +} + +type ChatroomDestroySetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomDestroySet 设置聊天室销毁类型 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/set-destroy-type +func (rc *RongCloud) ChatroomDestroySet(ctx context.Context, req *ChatroomDestroySetRequest) (*ChatroomDestroySetResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.DestroyType != nil { + params.Set("destroyType", strconv.Itoa(IntValue(req.DestroyType))) + } + if req.DestroyTime != nil { + params.Set("destroyTime", strconv.Itoa(IntValue(req.DestroyTime))) + } + resp := &ChatroomDestroySetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/destroy/set.json", params, resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomGetRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID +} + +type ChatroomGetResponse struct { + CodeResult + ChatroomId string `json:"chatroomId"` // 聊天室 ID + CreateTime int64 `json:"createTime"` // 聊天室创建时间 + MemberCount int `json:"memberCount"` // 聊天室当前人数 + DestroyType int `json:"destroyType"` // 指定聊天室的销毁方式。0:默认值,表示不活跃时销毁。默认情况下,所有聊天室的自动销毁方式均为不活跃时销毁,一旦不活跃长达到 60 分钟即被销毁,可通过 destroyTime 延长该时间。1:固定时间销毁,设置为该类型后,聊天室默认在创建 60 分钟后自动销毁,可通过 destroyTime 设置更长的存活时间。 + DestroyTime int `json:"destroyTime"` // 设置聊天室销毁等待时间。在 destroyType=0 时,表示聊天室应在不活跃达到该时长时自动销毁。在 destroyType=1 时,表示聊天室应在创建以后存活时间达到该时长后自动销毁。单位为分钟,最小值 60 分钟,最大 10080 分钟(7 天)。 + IsBan bool `json:"ban"` // 是否已开启聊天室全体禁言,默认 false。 + + httpResponseGetter +} + +// ChatroomGet 查询聊天室信息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/get +func (rc *RongCloud) ChatroomGet(ctx context.Context, req *ChatroomGetRequest) (*ChatroomGetResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/get.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomEntrySetRequest struct { + ChatroomId *string `url:"chatroomId,omitempty"` // [必传] 聊天室 ID + UserId *string `url:"userId,omitempty"` // [必传] 操作用户 ID。通过 Server API 非聊天室中用户可以进行设置。 + Key *string `url:"key,omitempty"` // [必传] 聊天室属性名称,Key 支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,大小写敏感。最大长度 128 字符。每个聊天室中,最多允许设置 100 个属性 Key-Value 对。 + Value *string `url:"value,omitempty"` // [必传] 聊天室属性对应的值,最大长度 4096 个字符。 + AutoDelete *int `url:"autoDelete,omitempty"` // 属性的操作用户退出聊天室后,是否删除此 Key 值。为 1 时删除此 Key 值和对应的 Value,为 0 时用户退出后不删除,默认为 0。 + RCMsg RCMsg `url:"-"` // 聊天室属性变化通知消息的消息类型,一般为内置消息类型 RC:chrmKVNotiMsg,也可以是其他自定义消息类型。如果传入该字段,则在聊天室属性变化时发送一条消息。 +} + +type ChatroomEntrySetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomEntrySet set chatroom entry kv (设置聊天室属性(KV)) +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/set-kv-entry +func (rc *RongCloud) ChatroomEntrySet(ctx context.Context, req *ChatroomEntrySetRequest) (*ChatroomEntrySetResponse, error) { + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &ChatroomEntrySetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/entry/set.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomEntryBatchSetRequest struct { + ChatroomId *string `json:"chatroomId"` // 聊天室 ID + + AutoDelete *int `json:"autoDelete"` // 用户(entryOwnerId)退出聊天室后,是否删除此 Key 值。为 1 时删除此 Key 值和对应的 Value,为 0 时用户退出后不删除,默认为 0。 + + EntryOwnerId *string `json:"entryOwnerId"` // 聊天室自定义属性的所属用户 ID + + // 聊天室自定义属性 KV 对,JSON 结构,一次最多 20 个 KV。Key 为属性名,支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,大小写敏感。最大长度 128 字符。Value 为属性值,最大长度 4096 个字符。 + EntryInfo map[string]string `json:"entryInfo"` +} + +type ChatroomEntryBatchSetResponse struct { + httpResponseGetter `json:"-"` + CodeResult +} + +// ChatroomEntryBatchSet batch set chatroom kv entry 批量设置聊天室属性(KV) +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/set-kv-entry-batch +func (rc *RongCloud) ChatroomEntryBatchSet(ctx context.Context, req *ChatroomEntryBatchSetRequest) (*ChatroomEntryBatchSetResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.AutoDelete != nil { + params.Set("autoDelete", strconv.Itoa(IntValue(req.AutoDelete))) + } + if req.EntryOwnerId != nil { + params.Set("entryOwnerId", StringValue(req.EntryOwnerId)) + } + if req.EntryInfo != nil { + entryInfo, err := json.Marshal(req.EntryInfo) + if err != nil { + return nil, fmt.Errorf("json.Marshal entryInfo err %w", err) + } + params.Set("entryInfo", string(entryInfo)) + } + resp := &ChatroomEntryBatchSetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/entry/batch/set.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomEntryRemoveRequest struct { + ChatroomId *string `url:"chatroomId,omitempty"` // [必传] 聊天室 ID。 + UserId *string `url:"userId,omitempty"` // [必传] 操作用户 ID。通过 Server API 非聊天室中用户可以进行设置。 + Key *string `url:"key,omitempty"` // [必传] 聊天室属性名称,Key 支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,大小写敏感。最大长度 128 字。 + RCMsg RCMsg `url:"-"` // 通聊天室属性变化通知消息的消息类型,一般为内置消息类型 ChrmKVNotiMsg,也可以是其他自定义消息类型。如果传入该字段,则在聊天室属性变化时发送一条消息。 +} + +type ChatroomEntryRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomEntryRemove 删除聊天室属性(KV) +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-kv-entry +func (rc *RongCloud) ChatroomEntryRemove(ctx context.Context, req *ChatroomEntryRemoveRequest) (*ChatroomEntryRemoveResponse, error) { + path := "/chatroom/entry/remove.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &ChatroomEntryRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomEntryQueryRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 + Keys []string `json:"keys"` // 批量获取指定聊天室中的 Key 值,最多上限为 100 个,不传时获取全部 key 值。 +} + +type ChatroomEntryQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Keys []*ChatroomEntry `json:"keys"` +} + +type ChatroomEntry struct { + Key string `json:"key"` // 设置的属性名。 + Value string `json:"value"` // 属性对应的内容。 + UserId string `json:"userId"` // 最后一次设置此 Key 的用户 ID。 + AutoDelete string `json:"autoDelete"` // 用户退出聊天室后是否删除此 Key,"0" 为不删除、"1"为删除。 + LastSetTime string `json:"lastSetTime"` // 最近一次设置 Key 的时间。 +} + +// ChatroomEntryQuery 查询聊天室属性(KV) +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-kv-entry +func (rc *RongCloud) ChatroomEntryQuery(ctx context.Context, req *ChatroomEntryQueryRequest) (*ChatroomEntryQueryResponse, error) { + path := "/chatroom/entry/query.json" + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.Keys != nil { + for _, key := range req.Keys { + params.Set("keys", key) + } + } + resp := &ChatroomEntryQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomDestroyRequest struct { + ChatroomIds []string `json:"chatroomIds"` // 要销毁的聊天室的 ID。每次可销毁多个聊天室。 +} + +type ChatroomDestroyResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomDestroy 销毁聊天室 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/destroy +func (rc *RongCloud) ChatroomDestroy(ctx context.Context, req *ChatroomDestroyRequest) (*ChatroomDestroyResponse, error) { + params := url.Values{} + if req.ChatroomIds != nil { + for _, id := range req.ChatroomIds { + params.Add("chatroomId", id) + } + } + resp := &ChatroomDestroyResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/destroy.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomUserQueryRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 要查询的聊天室 ID + + Count *int `json:"count"` // [必传] 要获取的聊天室成员信息数,最多返回 500 个成员信息 + + Order *int `json:"order"` // [必传]加入聊天室的先后顺序, 1 为加入时间正序, 2 为加入时间倒序 +} + +type ChatroomUserQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + + Total int `json:"total"` + Users []string `json:"users"` + Id string `json:"id"` + Time string `json:"time"` +} + +// ChatroomUserQuery 获取聊天室成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-member-list +func (rc *RongCloud) ChatroomUserQuery(ctx context.Context, req *ChatroomUserQueryRequest) (*ChatroomUserQueryResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.Count != nil { + params.Set("count", strconv.Itoa(IntValue(req.Count))) + } + if req.Order != nil { + params.Set("order", strconv.Itoa(IntValue(req.Order))) + } + resp := &ChatroomUserQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/query.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomUsersExistRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 要查询的聊天室 ID + UserIds []string `json:"userIds"` // [必传] 要查询的用户 ID,每次最多不超过 1000 个用户 ID +} + +type ChatroomUsersExistResponse struct { + CodeResult + httpResponseGetter `json:"-"` + + Result []*ChatroomUserExistResult `json:"result"` +} + +type ChatroomUserExistResult struct { + UserId string `json:"userId"` // 聊天室中用户 ID。 + + IsInChrm int `json:"isInChrm"` // 用户是否在聊天室中,1 表示在聊天室中,0 表示不在聊天室中。 +} + +// ChatroomUsersExist 批量查询是否在聊天室中 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/check-members +func (rc *RongCloud) ChatroomUsersExist(ctx context.Context, req *ChatroomUsersExistRequest) (*ChatroomUsersExistResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + resp := &ChatroomUsersExistResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/users/exist.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + if err != nil { + return resp, err + } + return resp, nil +} + +type ChatroomUserBlockAddRequest struct { + UserIds []string `json:"userIds"` // [必传]用户 ID,可同时封禁多个用户,最多不超过 20 个。 + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 + Minute *int `json:"minute"` // [必传] 封禁时长,以分钟为单位,最大值为43200分钟。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:聊天室中所有成员,包括被封禁用户。 +} + +type ChatroomUserBlockAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBlockAdd 封禁聊天室用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/block-user +func (rc *RongCloud) ChatroomUserBlockAdd(ctx context.Context, req *ChatroomUserBlockAddRequest) (*ChatroomUserBlockAddResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Minute != nil { + params.Set("minute", strconv.Itoa(IntValue(req.Minute))) + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserBlockAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/block/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBlockRollbackRequest struct { + UserIds []string `json:"userIds"` // [必传] 用户 ID,可同时移除多个用户,最多不超过 20 个。 + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:被解除封禁的成员。 +} + +type ChatroomUserBlockRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBlockRollback 解除封禁聊天室用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/unblock-user +func (rc *RongCloud) ChatroomUserBlockRollback(ctx context.Context, req *ChatroomUserBlockRollbackRequest) (*ChatroomUserBlockRollbackResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserBlockRollbackResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/block/rollback.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBlockListRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID +} + +type ChatroomUserBlockListResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []*ChatroomUserBlockUser `json:"users"` // 被封禁用户数组。 +} + +type ChatroomUserBlockUser struct { + Time string `json:"time"` // 解禁时间。精确到秒,格式为 YYYY-MM-DD HH:MM:SS,例如 2022-09-25 16:12:38。注意:time 的值与应用所属数据中心有关。如您的 App 业务使用国内数据中心,则 time 为北京时间。如您的 App 业务使用海外数据中心,则 time 为 UTC 时间。 + UserId string `json:"userId"` // 被封禁用户 ID。 +} + +// ChatroomUserBlockList 查询聊天室封禁用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-blocked-user +func (rc *RongCloud) ChatroomUserBlockList(ctx context.Context, req *ChatroomUserBlockListRequest) (*ChatroomUserBlockListResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomUserBlockListResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/block/list.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanAddRequest struct { + UserIds []string `json:"userIds"` // [必传]用户 ID,可同时禁言多个用户,每次最多不超过 20 个。 + Minute *int `json:"minute"` // [必传]禁言时长,以分钟为单位,最大值为 43200 分钟。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:指定聊天室中所有成员。 +} + +type ChatroomUserBanAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBanAdd 全局禁言用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/gag-user-globally +func (rc *RongCloud) ChatroomUserBanAdd(ctx context.Context, req *ChatroomUserBanAddRequest) (*ChatroomUserBanAddResponse, error) { + params := url.Values{} + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Minute != nil { + params.Set("minute", strconv.Itoa(IntValue(req.Minute))) + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserBanAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/ban/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanRemoveRequest struct { + UserIds []string `json:"userIds"` // [必传]用户 ID,可同时移除多个用户,每次最多不超过 20 个。 + + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:被解除全局禁言的用户。 +} + +type ChatroomUserBanRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBanRemove 取消全局禁言用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/ungag-user-globally +func (rc *RongCloud) ChatroomUserBanRemove(ctx context.Context, req *ChatroomUserBanRemoveRequest) (*ChatroomUserBanRemoveResponse, error) { + params := url.Values{} + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserBanRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/ban/remove.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanQueryRequest struct { + // 暂无请求参数(预留) +} + +type ChatroomUserBanQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []ChatroomUserBlockUser `json:"users"` +} + +// ChatroomUserBanQuery 查询全局禁言用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-globally-gagged-user +func (rc *RongCloud) ChatroomUserBanQuery(ctx context.Context, req *ChatroomUserBanQueryRequest) (*ChatroomUserBanQueryResponse, error) { + resp := &ChatroomUserBanQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/ban/query.json", nil, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserGagAddRequest struct { + UserIds []string `json:"userIds"` // [必传]用户 ID,可同时禁言多个用户,最多不超过 20 个。 + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID。 + Minute *int `json:"minute"` // [必传]禁言时长,以分钟为单位,最大值为 43200 分钟。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:指定聊天室中所有成员。 +} + +type ChatroomUserGagAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserGagAdd 禁言指定聊天室用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/gag-user +func (rc *RongCloud) ChatroomUserGagAdd(ctx context.Context, req *ChatroomUserGagAddRequest) (*ChatroomUserGagAddResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Minute != nil { + params.Set("minute", strconv.Itoa(IntValue(req.Minute))) + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserGagAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/gag/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserGagRollbackRequest struct { + UserIds []string `json:"userIds"` // [必传]用户 ID,可同时移除多个用户,最多不超过 20 个。 + + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID。 + + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 + + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:指定聊天室中所有成员。 + +} + +type ChatroomUserGagRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserGagRollback 取消禁言指定聊天室用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/ungag-user +func (rc *RongCloud) ChatroomUserGagRollback(ctx context.Context, req *ChatroomUserGagRollbackRequest) (*ChatroomUserGagRollbackResponse, error) { + params := url.Values{} + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + resp := &ChatroomUserGagRollbackResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/gag/rollback.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserGagListRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID。 +} + +type ChatroomUserGagListResponse struct { + CodeResult + httpResponseGetter + Users []*ChatroomUserBlockUser `json:"users"` // 被禁言用户数组。 +} + +// ChatroomUserGagList 查询聊天室禁言用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-gagged-user +func (rc *RongCloud) ChatroomUserGagList(ctx context.Context, req *ChatroomUserGagListRequest) (*ChatroomUserGagListResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomUserGagListResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/gag/list.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomMessagePriorityAddRequest struct { + ObjectNames []string `json:"objectNames"` // 低优先级的消息类型,每次最多提交 5 个,设置的消息类型最多不超过 20 个。 +} + +type ChatroomMessagePriorityAddResponse struct { + CodeResult + httpResponseGetter +} + +// ChatroomMessagePriorityAdd 添加低级别消息类型 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/add-low-priority-message-type +func (rc *RongCloud) ChatroomMessagePriorityAdd(ctx context.Context, req *ChatroomMessagePriorityAddRequest) (*ChatroomMessagePriorityAddResponse, error) { + params := url.Values{} + if req.ObjectNames != nil { + for _, name := range req.ObjectNames { + params.Add("objectName", name) + } + } + resp := &ChatroomMessagePriorityAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/message/priority/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomMessagePriorityRemoveRequest struct { + ObjectNames []string `json:"objectNames"` // 低优先级的消息类型,每次最多提交 5 个 +} + +type ChatroomMessagePriorityRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomMessagePriorityRemove 移除低级别消息类型 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-low-priority-message-type +func (rc *RongCloud) ChatroomMessagePriorityRemove(ctx context.Context, req *ChatroomMessagePriorityRemoveRequest) (*ChatroomMessagePriorityRemoveResponse, error) { + params := url.Values{} + if req.ObjectNames != nil { + for _, name := range req.ObjectNames { + params.Add("objectName", name) + } + } + resp := &ChatroomMessagePriorityRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/message/priority/remove.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomMessagePriorityQueryRequest struct { + // 暂无请求参数(预留) +} + +type ChatroomMessagePriorityQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + ObjectNames []string `json:"objectNames"` // 消息类型数组。 +} + +// ChatroomMessagePriorityQuery 查询低级别消息类型 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-low-priority-message-type +func (rc *RongCloud) ChatroomMessagePriorityQuery(ctx context.Context, req *ChatroomMessagePriorityQueryRequest) (*ChatroomMessagePriorityQueryResponse, error) { + resp := &ChatroomMessagePriorityQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/message/priority/query.json", nil, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomKeepaliveAddRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID。 +} + +type ChatroomKeepaliveAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomKeepaliveAdd 保活聊天室 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/add-to-keep-alive +func (rc *RongCloud) ChatroomKeepaliveAdd(ctx context.Context, req *ChatroomKeepaliveAddRequest) (*ChatroomKeepaliveAddResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomKeepaliveAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/keepalive/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomKeepaliveRemoveRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传]聊天室 ID。 +} + +type ChatroomKeepaliveRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomKeepaliveRemove 取消保活聊天室 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-from-keep-alive +func (rc *RongCloud) ChatroomKeepaliveRemove(ctx context.Context, req *ChatroomKeepaliveRemoveRequest) (*ChatroomKeepaliveRemoveResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomKeepaliveRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/keepalive/remove.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomKeepaliveQueryRequest struct { + // 暂无请求参数(预留) +} + +type ChatroomKeepaliveQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + ChatroomIds []string `json:"chatroomIds,omitempty"` // 保活聊天室数组。 +} + +// ChatroomKeepaliveQuery 查询保活聊天室 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-keep-alive +func (rc *RongCloud) ChatroomKeepaliveQuery(ctx context.Context, req *ChatroomKeepaliveQueryRequest) (*ChatroomKeepaliveQueryResponse, error) { + resp := &ChatroomKeepaliveQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/keepalive/query.json", nil, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomWhitelistAddRequest struct { + ObjectNames []string `json:"objectnames"` // [必传] 消息标识,最多不超过 20 个,自定义消息类型,长度不超过 32 个字符 +} + +type ChatroomWhitelistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomWhitelistAdd 加入聊天室消息白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/add-to-message-type-whitelist +func (rc *RongCloud) ChatroomWhitelistAdd(ctx context.Context, req *ChatroomWhitelistAddRequest) (*ChatroomWhitelistAddResponse, error) { + params := url.Values{} + if req.ObjectNames != nil { + for _, name := range req.ObjectNames { + params.Add("objectnames", name) // no typo + } + } + resp := &ChatroomWhitelistAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/whitelist/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomWhitelistRemoveRequest struct { + ObjectNames []string `json:"objectnames"` // [必传] 消息标识,最多不超过 20 个,自定义消息类型,长度不超过 32 个字符 +} + +type ChatroomWhitelistRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomWhitelistRemove 移出聊天室消息白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-from-message-type-whitelist +func (rc *RongCloud) ChatroomWhitelistRemove(ctx context.Context, req *ChatroomWhitelistRemoveRequest) (*ChatroomWhitelistRemoveResponse, error) { + params := url.Values{} + if req.ObjectNames != nil { + for _, name := range req.ObjectNames { + params.Add("objectnames", name) + } + } + resp := &ChatroomWhitelistRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/whitelist/delete.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomWhitelistQueryRequest struct { + // 暂无请求参数(预留) +} + +type ChatroomWhitelistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + WhitelistMsgType []string `json:"whitlistMsgType"` // 消息类型数组。 +} + +// ChatroomWhitelistQuery 查询聊天室消息白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-message-type-whitelist +func (rc *RongCloud) ChatroomWhitelistQuery(ctx context.Context, req *ChatroomWhitelistQueryRequest) (*ChatroomWhitelistQueryResponse, error) { + resp := &ChatroomWhitelistQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/whitelist/query.json", nil, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserWhitelistAddRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 + UserIds []string `json:"userId"` // [必传] 聊天室中用户 ID,可提交多个。聊天室中白名单用户最多不超过 5 个。 +} + +type ChatroomUserWhitelistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserWhitelistAdd 加入聊天室用户白名单 +// https://doc.rongcloud.cn/imserver/server/v1/chatroom/add-to-user-whitelist +func (rc *RongCloud) ChatroomUserWhitelistAdd(ctx context.Context, req *ChatroomUserWhitelistAddRequest) (*ChatroomUserWhitelistAddResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + resp := &ChatroomUserWhitelistAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/whitelist/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserWhitelistRemoveRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 + UserIds []string `json:"userId"` // [必传] 聊天室中用户 ID,可提交多个。聊天室中白名单用户最多不超过 5 个。 +} + +type ChatroomUserWhitelistRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserWhitelistRemove 移出聊天室用户白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-from-user-whitelist +func (rc *RongCloud) ChatroomUserWhitelistRemove(ctx context.Context, req *ChatroomUserWhitelistRemoveRequest) (*ChatroomUserWhitelistRemoveResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + resp := &ChatroomUserWhitelistRemoveResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/whitelist/remove.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserWhitelistQueryRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID。 +} + +type ChatroomUserWhitelistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []string `json:"users"` // 白名单用户数组。 +} + +// ChatroomUserWhitelistQuery 查询聊天室用户白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-user-whitelist +func (rc *RongCloud) ChatroomUserWhitelistQuery(ctx context.Context, req *ChatroomUserWhitelistQueryRequest) (*ChatroomUserWhitelistQueryResponse, error) { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomUserWhitelistQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/user/whitelist/query.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomBanRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 需要设置为禁言的聊天室 ID。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 NeedNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:指定聊天室中所有成员 +} + +func (req ChatroomBanRequest) toUrlValues() url.Values { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + return params +} + +type ChatroomBanAddRequest struct { + ChatroomBanRequest `json:",inline"` +} + +type ChatroomBanAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomBanAdd 设置聊天室全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/ban-chatroom +func (rc *RongCloud) ChatroomBanAdd(ctx context.Context, req *ChatroomBanAddRequest) (*ChatroomBanAddResponse, error) { + params := req.toUrlValues() + resp := &ChatroomBanAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/ban/add.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomBanRollbackRequest struct { + ChatroomBanRequest `json:",inline"` +} + +type ChatroomBanRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomBanRollback 取消聊天室全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/unban-chatroom +func (rc *RongCloud) ChatroomBanRollback(ctx context.Context, req *ChatroomBanRollbackRequest) (*ChatroomBanRollbackResponse, error) { + params := req.toUrlValues() + resp := &ChatroomBanRollbackResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/ban/rollback.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomBanQueryRequest struct { + Size *int `json:"size"` // 获取聊天室禁言列表的每页条数,不传时默认为 50 条,上限为 1000 条。 + Page *int `json:"page"` // 当前页面数,不传时默认获取第 1 页。 +} + +type ChatroomBanQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + ChatroomIds []string `json:"chatroomIds"` // 被全体禁言的聊天室数组。 +} + +// ChatroomBanQuery 查询聊天室全体禁言列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-banned-list +func (rc *RongCloud) ChatroomBanQuery(ctx context.Context, req *ChatroomBanQueryRequest) (*ChatroomBanQueryResponse, error) { + params := url.Values{} + if req.Size != nil { + params.Set("size", strconv.Itoa(IntValue(req.Size))) + } + if req.Page != nil { + params.Set("page", strconv.Itoa(IntValue(req.Page))) + } + resp := &ChatroomBanQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, "/chatroom/ban/query.json", params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomBanCheckRequest struct { + ChatroomId *string `json:"chatroomId"` // 要查询的聊天室 ID +} + +type ChatroomBanCheckResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Status int `json:"status"` // 禁言状态,1 为全体禁言、0 为非全体禁言 +} + +// ChatroomBanCheck 查询聊天室全体禁言状态 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-banned-state +func (rc *RongCloud) ChatroomBanCheck(ctx context.Context, req *ChatroomBanCheckRequest) (*ChatroomBanCheckResponse, error) { + path := "/chatroom/ban/check.json" + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomBanCheckResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanWhitelistRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID + UserIds []string `json:"userId"` // [必传] 需要添加到白名单中的用户 ID,白名单中用户上限为 20 个,支持批量添加,单次添加上限不超过 20 个。 + Extra *string `json:"extra"` // 通知携带的 JSON 格式的扩展信息,仅在 NeedNotify 为 true 时有效。 + NeedNotify *bool `json:"needNotify"` // 是否通知成员。默认 false 不通知。如果为 true,客户端会触发相应回调方法(要求 Android/iOS IMLib ≧ 5.4.5;Web IMLib ≧ 5.7.9)。通知范围:指定聊天室中所有成员 +} + +func (req *ChatroomUserBanWhitelistRequest) toUrlValues() url.Values { + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + if req.UserIds != nil { + for _, id := range req.UserIds { + params.Add("userId", id) + } + } + if req.Extra != nil { + params.Set("extra", StringValue(req.Extra)) + } + if req.NeedNotify != nil { + params.Set("needNotify", strconv.FormatBool(BoolValue(req.NeedNotify))) + } + return params +} + +type ChatroomUserBanWhitelistAddRequest struct { + ChatroomUserBanWhitelistRequest `json:",inline"` +} + +type ChatroomUserBanWhiteListAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBanWhitelistAdd 加入聊天室全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/add-to-chatroom-ban-whitelist +func (rc *RongCloud) ChatroomUserBanWhitelistAdd(ctx context.Context, req *ChatroomUserBanWhitelistAddRequest) (*ChatroomUserBanWhiteListAddResponse, error) { + path := "/chatroom/user/ban/whitelist/add.json" + params := req.toUrlValues() + resp := &ChatroomUserBanWhiteListAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanWhitelistRollbackRequest struct { + ChatroomUserBanWhitelistRequest `json:",inline"` +} + +type ChatroomUserBanWhiteListRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ChatroomUserBanWhitelistRollback 移出聊天室全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/remove-from-chatroom-ban-whitelist +func (rc *RongCloud) ChatroomUserBanWhitelistRollback(ctx context.Context, req *ChatroomUserBanWhitelistRollbackRequest) (*ChatroomUserBanWhiteListRollbackResponse, error) { + path := "/chatroom/user/ban/whitelist/rollback.json" + params := req.toUrlValues() + resp := &ChatroomUserBanWhiteListRollbackResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ChatroomUserBanWhitelistQueryRequest struct { + ChatroomId *string `json:"chatroomId"` // [必传] 聊天室 ID +} + +type ChatroomUserBanWhitelistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + UserIds []string `json:"userIds"` // 聊天室中白名单用户数组。 +} + +// ChatroomUserBanWhitelistQuery 查询聊天室全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/chatroom/query-chatroom-ban-whitelist +func (rc *RongCloud) ChatroomUserBanWhitelistQuery(ctx context.Context, req *ChatroomUserBanWhitelistQueryRequest) (*ChatroomUserBanWhitelistQueryResponse, error) { + path := "/chatroom/user/ban/whitelist/query.json" + params := url.Values{} + if req.ChatroomId != nil { + params.Set("chatroomId", StringValue(req.ChatroomId)) + } + resp := &ChatroomUserBanWhitelistQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/conversation.go b/rongcloud/conversation.go new file mode 100644 index 0000000..e630750 --- /dev/null +++ b/rongcloud/conversation.go @@ -0,0 +1,164 @@ +package rongcloud + +import "context" + +type ConversationTopSetRequest struct { + // [必传] 用户 ID,会话所属的用户 + UserId *string `url:"userId,omitempty"` + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)、10(超级群会话)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 需要设置的目标 ID,根据会话类型不同为单聊用户 ID、群聊 ID、系统目标 ID + TargetId *string `url:"targetId,omitempty"` + // [必传] true 表示置顶,false 表示取消置顶。 + SetTop *bool `url:"setTop,omitempty"` +} + +type ConversationTopSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ConversationTopSet 会话置顶 +// More details see https://doc.rongcloud.cn/imserver/server/v1/conversation/top +func (rc *RongCloud) ConversationTopSet(ctx context.Context, req *ConversationTopSetRequest) (*ConversationTopSetResponse, error) { + path := "/conversation/top/set.json" + resp := &ConversationTopSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ConversationNotificationSetRequest struct { + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)、10(超级群会话)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 设置消息免打扰的用户 ID。 + RequestId *string `url:"requestId,omitempty"` + // [必传] 目标 ID,根据不同的会话类型(ConversationType),可能是用户 ID、群组 ID、超级群 ID 等。 + TargetId *string `url:"targetId,omitempty"` + // 消息免打扰设置状态,0 表示关闭,1 表示开启。 + // 该字段已废弃,推荐使用 unpushLevel。isMuted 与 unpushLevel 只需要传一个。如果都传,使用 unpushLevel。 + // Deprecated + IsMuted *int `url:"isMuted,omitempty"` + // 超级群的会话频道 ID。 + // 如果传入频道 ID,则针对该指定频道设置消息免打扰级别。 + // 注意:2022.09.01 之前开通超级群业务的客户,如果不指定频道 ID,则默认传 "" 空字符串,即仅针对指定超级群会话(targetId)中不属于任何频道的消息设置免打扰状态级别。如需修改请提交工单。 + BusChannel *string `url:"busChannel,omitempty"` + // -1: 全部消息通知 + // 0: 未设置(用户未设置情况下,默认以群 或者 APP级别的默认设置为准,如未设置则全部消息都通知) + // 1: 仅针对 @ 消息进行通知 + // 2: 仅针对 @ 指定用户进行通知 + // 如:@张三 则张三可以收到推送,@所有人 时不会收到推送。 + // 4: 仅针对 @ 群全员进行通知,只接收 @所有人 的推送信息。 + // 5: 不接收通知 + UnpushLevel *int `url:"unpushLevel,omitempty"` +} + +type ConversationNotificationSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ConversationNotificationSet 设置指定会话免打扰 +// More details see https://doc.rongcloud.cn/imserver/server/v1/conversation/set-do-not-disturb-by-id +func (rc *RongCloud) ConversationNotificationSet(ctx context.Context, req *ConversationNotificationSetRequest) (*ConversationNotificationSetResponse, error) { + path := "/conversation/notification/set.json" + resp := &ConversationNotificationSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ConversationNotificationGetRequest struct { + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)、10(超级群会话)。如需查询超级群指定频道的免打扰设置,请传入频道 ID(busChannel)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 设置消息免打扰的用户 ID。 + RequestId *string `url:"requestId,omitempty"` + // [必传] 目标 ID,根据不同的会话类型(ConversationType),可能是用户 ID、群组 ID。 + TargetId *string `url:"targetId,omitempty"` + // 超级群的会话频道 ID。 + // 如果传入频道 ID,则查询该频道的消息免打扰级别。 + // 注意:如果不指定频道 ID,则查询指定超级群会话(targetId)中不属于任何频道的消息的免打扰状态级别。 + BusChannel *string `url:"busChannel,omitempty"` +} + +type ConversationNotificationGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // 消息免打扰设置状态。 + // -1: 全部消息通知 + // 0: 未设置(用户未设置情况下,默认以群 或者 APP级别的默认设置为准,如未设置则全部消息都通知) + // 1: 仅针对 @ 消息进行通知 + // 2: 仅针对 @ 指定用户进行通知 + // 4: 仅针对 @ 群全员进行通知。 + // 5: 不接收通知 + IsMuted int `json:"isMuted"` +} + +// ConversationNotificationGet 查询指定会话免打扰 +// More details see https://doc.rongcloud.cn/imserver/server/v1/conversation/get-do-not-disturb-by-id +func (rc *RongCloud) ConversationNotificationGet(ctx context.Context, req *ConversationNotificationGetRequest) (*ConversationNotificationGetResponse, error) { + path := "/conversation/notification/get.json" + resp := &ConversationNotificationGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ConversationTypeNotificationSetRequest struct { + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)、10(超级群会话)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 设置消息免打扰的用户 ID。 + RequestId *string `url:"requestId,omitempty"` + // [必传] -1: 全部消息通知 + //0: 未设置(用户未设置情况下,默认以群或者 APP 级别的默认设置为准,如未设置则全部消息都通知) + //1: 仅针对 @ 消息进行通知 + //2: 仅针对 @ 指定用户进行通知 + //如:@张三 则张三可以收到推送,@所有人 时不会收到推送。 + //4: 仅针对 @ 群全员进行通知,只接收 @所有人 的推送信息。 + //5: 不接收通知 + UnpushLevel *int `url:"unpushLevel,omitempty"` +} + +type ConversationTypeNotificationSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// ConversationTypeNotificationSet 设置指定会话类型免打扰 +// More details see https://doc.rongcloud.cn/imserver/server/v1/conversation/set-do-not-disturb-by-type +func (rc *RongCloud) ConversationTypeNotificationSet(ctx context.Context, req *ConversationTypeNotificationSetRequest) (*ConversationTypeNotificationSetResponse, error) { + path := "/conversation/type/notification/set.json" + resp := &ConversationTypeNotificationSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type ConversationTypeNotificationGetRequest struct { + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)、10(超级群会话)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 设置消息免打扰的用户 ID。 + RequestId *string `url:"requestId,omitempty"` +} + +type ConversationTypeNotificationGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // -1: 全部消息通知 + // 0: 未设置(用户未设置情况下,默认以群 或者 APP级别的默认设置为准,如未设置则全部消息都通知) + // 1: 仅针对 @ 消息进行通知 + // 2: 仅针对 @ 指定用户进行通知 + // 4: 仅针对 @ 群全员进行通知。 + // 5: 不接收通知 + IsMuted int `json:"isMuted"` +} + +// ConversationTypeNotificationGet 查询指定会话类型免打扰 +// More details see https://doc.rongcloud.cn/imserver/server/v1/conversation/get-do-not-disturb-by-type +func (rc *RongCloud) ConversationTypeNotificationGet(ctx context.Context, req *ConversationTypeNotificationGetRequest) (*ConversationTypeNotificationGetResponse, error) { + path := "/conversation/type/notification/get.json" + resp := &ConversationTypeNotificationGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/errors.go b/rongcloud/errors.go new file mode 100644 index 0000000..f4c1bcb --- /dev/null +++ b/rongcloud/errors.go @@ -0,0 +1,27 @@ +package rongcloud + +import ( + "errors" + "fmt" +) + +type SDKError struct { + Msg string +} + +func NewSDKError(msg string) error { + return SDKError{Msg: msg} +} +func (e SDKError) Error() string { + return e.Msg +} + +// NewEncodeRequestError +// query parse values error help function +func NewEncodeRequestError(err error) error { + return NewSDKError(fmt.Sprintf("encode request error %s", err)) +} + +func IsSDKError(err error) bool { + return errors.Is(err, SDKError{}) +} diff --git a/rongcloud/group.go b/rongcloud/group.go new file mode 100644 index 0000000..c15a51f --- /dev/null +++ b/rongcloud/group.go @@ -0,0 +1,479 @@ +package rongcloud + +import ( + "context" + "fmt" + "net/url" +) + +type GroupRemarksSetRequest struct { + // [必传] 群成员用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 群成员推送备注。 + Remark *string `url:"remark,omitempty"` +} + +type GroupRemarksSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupRemarksSet 设置群成员推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/set-remark-for-group-push +func (rc *RongCloud) GroupRemarksSet(ctx context.Context, req *GroupRemarksSetRequest) (*GroupRemarksSetResponse, error) { + path := "/group/remarks/set.json" + resp := &GroupRemarksSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupRemarksDelRequest struct { + // [必传] 群成员用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 群 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupRemarksDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupRemarksDel 删除群成员推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/delete-remark-for-group-push +func (rc *RongCloud) GroupRemarksDel(ctx context.Context, req *GroupRemarksDelRequest) (*GroupRemarksDelResponse, error) { + path := "/group/remarks/del.json" + resp := &GroupRemarksDelResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupRemarksGetRequest struct { + // [必传] 群成员用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 群 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupRemarksGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Remark string `json:"remark"` // 备注名称。 +} + +// GroupRemarksGet 查询群成员推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/get-remark-for-group-push +func (rc *RongCloud) GroupRemarksGet(ctx context.Context, req *GroupRemarksGetRequest) (*GroupRemarksGetResponse, error) { + path := "/group/remarks/get.json" + resp := &GroupRemarksGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupCreateRequest struct { + // [必传] 要加入群的用户 ID,最多不超过 1000 个。 + UserId []string `url:"userId,omitempty"` + // [必传] 创建群组 ID,最大长度 64 个字符。支持大小写英文字母与数字的组合。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 群组 ID 对应的名称,用于在发送群组消息显示远程 Push 通知时使用,如群组名称改变需要调用刷新群组信息接口同步。 + GroupName *string `url:"groupName,omitempty"` +} + +type GroupCreateResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupCreate 创建群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/create-group +func (rc *RongCloud) GroupCreate(ctx context.Context, req *GroupCreateRequest) (*GroupCreateResponse, error) { + path := "/group/create.json" + resp := &GroupCreateResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserGagAddRequest struct { + // [必传] 用户 ID,每次添加最多不超过 20 个用户。 + UserId []string `url:"userId,omitempty"` + // 群组 ID,为空时则设置用户在加入的所有群组中都不能发送消息。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 禁言时长,以分钟为单位,最大值为 43200 分钟,为 0 表示永久禁言。 + Minute *int `url:"minute,omitempty"` +} + +type GroupUserGagAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupUserGagAdd 禁言指定群成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/gag-user +func (rc *RongCloud) GroupUserGagAdd(ctx context.Context, req *GroupUserGagAddRequest) (*GroupUserGagAddResponse, error) { + path := "/group/user/gag/add.json" + resp := &GroupUserGagAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserGagListRequest struct { + // 群组 ID,为空时则设置用户在加入的所有群组中都不能发送消息。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserGagListResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []*GagUser `json:"users"` // 禁言成员列表。 +} + +type GagUser struct { + UserId string `json:"userId"` // 群成员 Id。 + Time string `json:"time"` // 解禁时间。精确到秒,格式为 YYYY-MM-DD HH:MM:SS,例如 2022-09-25 16:12:38。注意:time 的值与应用所属数据中心有关。如您的 App 业务使用国内数据中心,则 time 为北京时间。如您的 App 业务使用海外数据中心,则 time 为 UTC 时间。 +} + +// GroupUserGagList 查询群成员禁言列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/query-gagged-user +func (rc *RongCloud) GroupUserGagList(ctx context.Context, req *GroupUserGagListRequest) (*GroupUserGagListResponse, error) { + path := "/group/user/gag/list.json" + resp := &GroupUserGagListResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserGagRollbackRequest struct { + // [必传] 用户 ID,每次最多移除 20 个用户。 + UserId []string `url:"userId,omitempty"` + // 群组 ID,为空时则移除用户在所有群组中的禁言设置。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserGagRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupUserGagRollback 取消指定群成员禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/ungag-user +func (rc *RongCloud) GroupUserGagRollback(ctx context.Context, req *GroupUserGagRollbackRequest) (*GroupUserGagRollbackResponse, error) { + path := "/group/user/gag/rollback.json" + resp := &GroupUserGagRollbackResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserGroupQueryRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // 当前页数,在分页查询时使用。如果进行分页查询,页面大小默认为 50,可使用 size 调整页面大小。如无需分页可不传(或传 0),可获得用户加入的前 5000 个群组列表。 + Page *int `url:"page,omitempty"` + // 页面大小,仅在 page 传入有效值时生效。默认每页 50 行,最大值 1000。 + Size *int `url:"size,omitempty"` +} + +type UserGroupQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Groups []*Group `json:"groups"` // 用户加入的群信息数组。 +} + +type Group struct { + Id string `json:"id"` // 群组 ID。 + Name string `json:"name"` // 群名称。 +} + +type SyncGroups []Group + +func (r SyncGroups) EncodeValues(key string, v *url.Values) error { + for _, grp := range r { + v.Set(fmt.Sprintf("%s[%s]", key, grp.Id), grp.Name) + } + return nil +} + +// UserGroupQuery 查询用户所在群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/query-group-by-user +func (rc *RongCloud) UserGroupQuery(ctx context.Context, req *UserGroupQueryRequest) (*UserGroupQueryResponse, error) { + path := "/user/group/query.json" + resp := &UserGroupQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupSyncRequest struct { + // [必传] 被同步群信息的用户 ID。 + UserId *string `url:"userId,omitempty"` + // 该用户所属的群信息,如群组 ID 已经存在,则同时刷新对应群组名称。此参数可传多个,参见下面示例。 + Groups SyncGroups `url:"group,omitempty"` +} + +type GroupSyncResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupSync 同步用户所在群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/sync-group +func (rc *RongCloud) GroupSync(ctx context.Context, req *GroupSyncRequest) (*GroupSyncResponse, error) { + path := "/group/sync.json" + resp := &GroupSyncResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupRefreshRequest struct { + // [必传] 群组 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 群组名称。 + GroupName *string `url:"groupName,omitempty"` +} + +type GroupRefreshResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupRefresh 刷新群组信息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/refresh-group-info +func (rc *RongCloud) GroupRefresh(ctx context.Context, req *GroupRefreshRequest) (*GroupRefreshResponse, error) { + path := "/group/refresh.json" + resp := &GroupRefreshResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupJoinRequest struct { + // [必传] 要加入群的用户 ID,可提交多个。最多不超过 1000 个。 + UserIds []string `url:"userId,omitempty"` + // [必传] 要加入的群的群组 ID。 + GroupId *string `url:"groupId,omitempty"` + // 要加入的群的名称。 + // 注意:加入群组时,如果传入 groupName,则会修改推送通知中携带的群组名称,效果与调用刷新群组信息一致。 + GroupName *string `url:"groupName,omitempty"` +} + +type GroupJoinResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupJoin 加入群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/join-group +func (rc *RongCloud) GroupJoin(ctx context.Context, req *GroupJoinRequest) (*GroupJoinResponse, error) { + path := "/group/join.json" + resp := &GroupJoinResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserQueryRequest struct { + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []*GroupUser `json:"users"` // 群成员数组。 +} + +type GroupUser struct { + Id string `json:"id"` // 群成员的用户 ID。 +} + +// GroupUserQuery 查询群组成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/query-group-member +func (rc *RongCloud) GroupUserQuery(ctx context.Context, req *GroupUserQueryRequest) (*GroupUserQueryResponse, error) { + path := "/group/user/query.json" + resp := &GroupUserQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupQuitRequest struct { + // [必传] 要退出群的用户 ID,可提交多个,最多不超过 1000 个。 + UserId []string `url:"userId,omitempty"` + // [必传] 要退出的群的群组 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupQuitResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupQuit 退出群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/quit-group +func (rc *RongCloud) GroupQuit(ctx context.Context, req *GroupQuitRequest) (*GroupQuitResponse, error) { + path := "/group/quit.json" + resp := &GroupQuitResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupDismissRequest struct { + // [必传] 操作解散群的用户 ID,可以为任何用户 ID ,非群组创建者也可以解散群组。 + UserId *string `url:"userId,omitempty"` + // [必传] 要解散的群的群组 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupDismissResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupDismiss 解散群组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/dismiss-group +func (rc *RongCloud) GroupDismiss(ctx context.Context, req *GroupDismissRequest) (*GroupDismissResponse, error) { + path := "/group/dismiss.json" + resp := &GroupDismissResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupBanAddRequest struct { + // [必传] 群组 ID,支持一次设置多个,最多不超过 20 个。 + GroupIds []string `url:"groupId,omitempty"` +} + +type GroupBanAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupBanAdd 设置群组全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/ban-group +func (rc *RongCloud) GroupBanAdd(ctx context.Context, req *GroupBanAddRequest) (*GroupBanAddResponse, error) { + path := "/group/ban/add.json" + resp := &GroupBanAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupBanRollbackRequest struct { + // [必传] 群组 ID,支持一次设置多个,最多不超过 20 个。 + GroupIds []string `url:"groupId,omitempty"` +} + +type GroupBanRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupBanRollback 取消群组全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/unban-group +func (rc *RongCloud) GroupBanRollback(ctx context.Context, req *GroupBanRollbackRequest) (*GroupBanRollbackResponse, error) { + path := "/group/ban/rollback.json" + resp := &GroupBanRollbackResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupBanQueryRequest struct { + // 群组 ID。单次可查询指定单个或多个群组,单次查询最多不超过 20 个群组。不传时,表示查询所有设置禁言的群组列表。 + GroupIds []string `url:"groupId,omitempty"` +} + +type GroupBanQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + GroupInfo []GroupBanQueryGroupInfo `json:"groupinfo"` // 禁言群组信息数据。 +} + +type GroupBanQueryGroupInfo struct { + GroupId string `json:"groupId"` // 群组 ID。 + Stat int `json:"stat"` // 禁言状态,0 表示为未禁言、1 表示为禁言。 +} + +// GroupBanQuery 查询群组全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/query-banned-state-or-list +func (rc *RongCloud) GroupBanQuery(ctx context.Context, req *GroupBanQueryRequest) (*GroupBanQueryResponse, error) { + path := "/group/ban/query.json" + resp := &GroupBanQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserBanWhitelistAddRequest struct { + // [必传] 用户 ID,支持一次添加多个用户,最多不超过 20 个。 + UserIds []string `url:"userId,omitempty"` + // [必传] 群组 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserBanWhitelistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupUserBanWhitelistAdd 加入群组全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/add-to-group-ban-whitelist +func (rc *RongCloud) GroupUserBanWhitelistAdd(ctx context.Context, req *GroupUserBanWhitelistAddRequest) (*GroupUserBanWhitelistAddResponse, error) { + path := "/group/user/ban/whitelist/add.json" + resp := &GroupUserBanWhitelistAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserBanWhitelistRollbackRequest struct { + // [必传] 用户 ID,支持一次添加多个用户,最多不超过 20 个。 + UserIds []string `url:"userId,omitempty"` + // [必传] 群组 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserBanWhitelistRollbackResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// GroupUserBanWhitelistRollback 移出群组全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/remove-from-group-ban-whitelist +func (rc *RongCloud) GroupUserBanWhitelistRollback(ctx context.Context, req *GroupUserBanWhitelistRollbackRequest) (*GroupUserBanWhitelistRollbackResponse, error) { + path := "/group/user/ban/whitelist/rollback.json" + resp := &GroupUserBanWhitelistRollbackResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type GroupUserBanWhitelistQueryRequest struct { + // [必传] 群组 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type GroupUserBanWhitelistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + UserIds []string `json:"userIds"` +} + +// GroupUserBanWhitelistQuery 查询群组全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/group/query-group-ban-whitelist +func (rc *RongCloud) GroupUserBanWhitelistQuery(ctx context.Context, req *GroupUserBanWhitelistQueryRequest) (*GroupUserBanWhitelistQueryResponse, error) { + path := "/group/user/ban/whitelist/query.json" + resp := &GroupUserBanWhitelistQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/http.go b/rongcloud/http.go new file mode 100644 index 0000000..62db646 --- /dev/null +++ b/rongcloud/http.go @@ -0,0 +1,215 @@ +package rongcloud + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/url" + "os" + "syscall" +) + +// 需要切换域名的网络错误 +func isNetError(err error) bool { + netErr, ok := err.(net.Error) + if !ok { + return false + } + // 超时 + if netErr.Timeout() { + return true + } + + var opErr *net.OpError + opErr, ok = netErr.(*net.OpError) + if !ok { + // url 错误 + urlErr, ok := netErr.(*url.Error) + if !ok { + return false + } + opErr, ok = urlErr.Err.(*net.OpError) + if !ok { + return false + } + } + + switch t := opErr.Err.(type) { + case *net.DNSError: + return true + case *os.SyscallError: + if errno, ok := t.Err.(syscall.Errno); ok { + switch errno { + case syscall.ECONNREFUSED: + return true + case syscall.ETIMEDOUT: + return true + } + } + } + + return false +} + +// do http request +func (rc *RongCloud) do(b *http.Request, data interface{}) (*http.Response, error) { + resp, err := rc.httpClient.Do(b) + if err != nil { + if isNetError(err) { + rc.changeURI() + } + return resp, err + } + if resp.Body == nil { + return resp, nil + } + rc.changeURIIfNeed(resp) + body, err := io.ReadAll(resp.Body) + err = json.Unmarshal(body, &data) + if err != nil { + return resp, err + } + resp.Body.Close() + resp.Body = io.NopCloser(bytes.NewBuffer(body)) + codeRes := &CodeResult{} + err = json.Unmarshal(body, &codeRes) + if err != nil { + // skip code result check failed + return resp, nil + } + if codeRes.Code != 200 && codeRes.Code != 10000 { + return resp, RCErrorNew(codeRes.Code, codeRes.ErrorMessage) + } + return resp, nil +} + +// CodeResult 融云返回状态码和错误码 +type CodeResult struct { + Code int `json:"code"` // 返回码,200 为正常。 + ErrorMessage string `json:"errorMessage,omitempty"` // 错误信息 +} + +// RCErrorNew 创建新的err信息 +func RCErrorNew(code int, text string) error { + return CodeResult{code, text} +} + +// Error 获取错误信息 +func (e CodeResult) Error() string { + return fmt.Sprintf("code:%d, errorMessage:%s", e.Code, e.ErrorMessage) +} + +// ErrorCode 获取错误码 +func (e CodeResult) ErrorCode() int { + return e.Code +} + +// 判断 http status code, 如果大于 500 就切换一次域名 +func (rc *RongCloud) changeURIIfNeed(resp *http.Response) { + if resp.StatusCode >= 500 && resp.StatusCode < 600 { + rc.changeURI() + } + + return +} + +// postJson +// @param ctx context with +// @param path url path, e.g. /a/b/c +// @param postBody any json able struct +// @param res response struct +func (rc *RongCloud) postJson(ctx context.Context, path string, postBody interface{}, res interface{}) (*http.Response, error) { + body := &bytes.Buffer{} + err := json.NewEncoder(body).Encode(postBody) + if err != nil { + return nil, err + } + return rc.doRequest(ctx, path, body, &res, "application/json") +} + +func (rc *RongCloud) doRequest(ctx context.Context, path string, body io.Reader, res interface{}, contentType string) (*http.Response, error) { + requestUrl := fmt.Sprintf("%s%s", rc.rongCloudURI, path) + var req *http.Request + var err error + if ctx == nil { + req, err = http.NewRequest(http.MethodPost, requestUrl, body) + } else { + req, err = http.NewRequestWithContext(ctx, http.MethodPost, requestUrl, body) + } + if err != nil { + return nil, fmt.Errorf("new http request error %w", err) + } + + req.Header.Set("Content-Type", contentType) + rc.fillHeader(ctx, req) + resp, err := rc.do(req, &res) + if err != nil { + return resp, err + } + return resp, nil +} + +// postFormUrlencoded +func (rc *RongCloud) postFormUrlencoded(ctx context.Context, path string, formParams url.Values, res interface{}) (*http.Response, error) { + body := &bytes.Buffer{} + body.WriteString(formParams.Encode()) + return rc.doRequest(ctx, path, body, &res, "application/x-www-form-urlencoded") +} + +// postForm post form with x-www-form-urlencoded format +// @param ctx context +// @param path url path e.g. /a/b/c +// @param req url request struct +// @param res response struct +func (rc *RongCloud) postForm(ctx context.Context, path string, req, res interface{}) (*http.Response, error) { + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + return rc.postFormUrlencoded(ctx, path, params, res) +} + +type httpResponseGetter interface { + GetHttpResponse() *http.Response + GetRequestId() string +} + +type rawHttpResponseGetter struct { + rawHttpResponseInternal *http.Response +} + +func newRawHttpResponseGetter(rawHttpResponseInternal *http.Response) *rawHttpResponseGetter { + return &rawHttpResponseGetter{rawHttpResponseInternal: rawHttpResponseInternal} +} + +func (r *rawHttpResponseGetter) GetHttpResponse() *http.Response { + return r.rawHttpResponseInternal +} + +func (r *rawHttpResponseGetter) GetRequestId() string { + return r.rawHttpResponseInternal.Header.Get(RCRequestIdHeader) +} + +type contextHttpHeaderKey string + +func (c contextHttpHeaderKey) String() string { + return RCHttpHeaderPrefix + string(c) +} + +const ( + RCHttpHeaderPrefix = "rc-http-header-" // http header context prefix for inhibiting context conflict + RCRequestIdHeader = "X-Request-Id" +) + +var ( + // ContextRequestIdKey represent RongCloud http request id, passing to server api + ContextRequestIdKey = contextHttpHeaderKey(RCRequestIdHeader) +) + +func AddHttpRequestId(ctx context.Context, requestId string) context.Context { + return context.WithValue(ctx, ContextRequestIdKey, requestId) +} diff --git a/rongcloud/message.go b/rongcloud/message.go new file mode 100644 index 0000000..5f6532a --- /dev/null +++ b/rongcloud/message.go @@ -0,0 +1,972 @@ +package rongcloud + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "strconv" +) + +// MessagePrivatePublishRequest 单聊消息 +type MessagePrivatePublishRequest struct { + // 发送人用户 ID。 + //注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `json:"fromUserId"` + + // 接收用户 ID,可以实现向多人发送消息,每次上限为 1000 人。 + ToUserId *string `json:"toUserId"` + + RCMsg RCMsg `json:"-"` // 消息类型参数的SDK封装, 例如: TXTMsg(文本消息), HQVCMsg(高清语音消息) + PushData *string `json:"pushData"` // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + + //指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。 + //如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中的用户内容类消息格式,可不填写该字段,远程推送通知默认使用服务端预置的推送通知内容。 + //如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中通知类、信令类("撤回命令消息" 除外),且需要支持远程推送通知,则必须填写 pushContent,否则收件人不在线时无法收到远程推送通知。如无需触发远程推送,可不填该字段。 + //如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + //如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段留空禁用远程推送通知 + PushContent *string `json:"pushContent"` + IsIncludeSender *int `json:"isIncludeSender"` // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。 + Count *int `json:"count"` // 仅目标用户为 iOS 设备有效,Push 时用来控制桌面角标未读消息数,只有在 toUserId 为一个用户 ID 时有效,客户端获取远程推送内容时为 badge。具体参见 iOS 客户端文档「APNs 推送开发指南」目录下的集成 APNs 远程推送。为 -1 时不改变角标数,传入相应数字表示把角标数改为指定的数字,最大不超过 9999。 + VerifyBlacklist *int `json:"verifyBlacklist"` // 是否过滤接收用户黑名单列表,0 表示为不过滤、 1 表示为过滤,默认为 0。 + IsPersisted *int `json:"isPersisted"` // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖单群聊消息云端存储服务)。 + ContentAvailable *int `json:"contentAvailable"` // 仅目标用户为 iOS 设备时有效,应用处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看[知识库文档](https://help.rongcloud.cn/t/topic/855)。1 表示为开启,0 表示为关闭,默认为 0。 + Expansion *bool `json:"expansion"` // 是否为可扩展消息,默认为 false,设为 true 时终端在收到该条消息后,可对该条消息设置扩展信息。移动端 SDK 4.0.3 版本、Web 端 3.0.7 版本支持此功能。 + + // 仅在 expansion 为 true 时有效。 + //自定义的消息扩展信息,该字段接受 JSON 字符串格式的键值对(key-value pairs)。请注意区别于消息体内的 extra 字段,extraContent 的值在消息发送后可修改,修改方式请参见服务端 API 接口文档消息扩展,或参考各客户端「消息扩展」接口文档。 + //KV 详细要求:以 Key、Value 的方式进行设置,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。单次可设置最多 100 对 KV 扩展信息,单条消息最多可设置 300 对 KV 扩展信息。 + ExtraContent map[string]string `json:"extraContent"` + + // 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。 + DisablePush *bool `json:"disablePush"` + + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。json string + PushExt *string `json:"pushExt"` +} + +func (r *MessagePrivatePublishRequest) MakeFormData() (url.Values, error) { + res := url.Values{} + if r.FromUserId != nil { + res.Set("fromUserId", StringValue(r.FromUserId)) + } + if r.ToUserId != nil { + res.Set("toUserId", StringValue(r.ToUserId)) + } + if r.RCMsg != nil { + err := makeRCMsgUrlValues(r.RCMsg, res) + if err != nil { + return nil, err + } + } + if r.PushData != nil { + res.Set("pushData", StringValue(r.PushData)) + } + if r.PushContent != nil { + res.Set("pushContent", StringValue(r.PushContent)) + } + if r.IsIncludeSender != nil { + res.Set("isIncludeSender", strconv.Itoa(IntValue(r.IsIncludeSender))) + } + if r.Count != nil { + res.Set("count", strconv.Itoa(IntValue(r.Count))) + } + if r.VerifyBlacklist != nil { + res.Set("verifyBlacklist", strconv.Itoa(IntValue(r.VerifyBlacklist))) + } + if r.IsPersisted != nil { + res.Set("isPersisted", strconv.Itoa(IntValue(r.IsPersisted))) + } + if r.ContentAvailable != nil { + res.Set("contentAvailable", strconv.Itoa(IntValue(r.ContentAvailable))) + } + if r.Expansion != nil { + res.Set("expansion", strconv.FormatBool(BoolValue(r.Expansion))) + } + if r.ExtraContent != nil { + b, err := json.Marshal(r.ExtraContent) + if err != nil { + return nil, fmt.Errorf("Marshal ExtraContent err: %w", err) + } + res.Set("extraContent", string(b)) + } + if r.DisablePush != nil { + res.Set("disablePush", strconv.FormatBool(BoolValue(r.DisablePush))) + } + if r.PushExt != nil { + res.Set("pushExt", StringValue(r.PushExt)) + } + return res, nil +} + +type MessagePrivatePublishResponse struct { + Code int `json:"code"` // 返回码,200 为正常。 + + httpResponseGetter `json:"-"` +} + +// MessagePrivatePublish 发送单聊普通消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-private +func (rc *RongCloud) MessagePrivatePublish(ctx context.Context, req *MessagePrivatePublishRequest) (*MessagePrivatePublishResponse, error) { + var resp *MessagePrivatePublishResponse + data, err := req.MakeFormData() + if err != nil { + return nil, err + } + httpResp, err := rc.postFormUrlencoded(ctx, "/message/private/publish.json", data, &resp) + if err != nil { + return nil, err + } + resp.httpResponseGetter = &rawHttpResponseGetter{rawHttpResponseInternal: httpResp} + return resp, nil +} + +const ( + ConversationTypePrivate = "1" // 二人会话 + ConversationTypeGroup = "3" // 群组会话 +) + +type MessageExpansionSetRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见[全量消息路由](https://doc.rongcloud.cn/imserver/server/v1/message/sync)。 + MsgUID *string `url:"msgUID,omitempty"` + // [必传] 操作者用户 ID,即需要为指定消息(msgUID)设置扩展信息的用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 会话类型。支持的会话类型包括:"1" ConversationTypePrivate(二人会话)、"3" ConversationTypeGroup(群组会话)。 + ConversationType *string `url:"conversationType,omitempty"` + // [必传] 目标 ID,根据不同的 conversationType,可能是用户 ID 或群组 ID。 + TargetId *string `url:"targetId,omitempty"` + // [必传] 消息扩展的内容,JSON 结构,以 Key、Value 的方式进行设置,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。单条消息可设置 300 个扩展信息,一次最多可以设置 100 个。 + ExtraKeyVal map[string]string `url:"-"` + // 删除操作会生成一条「扩展操作消息」。该字段指定是否将该「扩展操作消息」同步到发件人(扩展操作者)的客户端。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见[发件人客户端如何同步已发消息](https://doc.rongcloud.cn/imserver/server/v1/message/how-to-sync-to-sender-client)。 + IsSyncSender *int `url:"isSyncSender,omitempty"` +} + +type MessageExpansionSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageExpansionSet 设置单群聊消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/set-expansion +func (rc *RongCloud) MessageExpansionSet(ctx context.Context, req *MessageExpansionSetRequest) (*MessageExpansionSetResponse, error) { + path := "/message/expansion/set.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.ExtraKeyVal != nil { + kv, err := json.Marshal(req.ExtraKeyVal) + if err != nil { + return nil, NewSDKError(fmt.Sprintf("marshal ExtraKeyVal error %s", err)) + } + params.Set("extraKeyVal", string(kv)) + } + + resp := &MessageExpansionSetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageExpansionDeleteRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见[全量消息路由](https://doc.rongcloud.cn/imserver/server/v1/message/sync)。 + MsgUID *string `url:"msgUID,omitempty"` + // [必传] 操作者用户 ID,即需要为指定消息(msgUID)设置扩展信息的用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 会话类型。支持的会话类型包括:"1" ConversationTypePrivate(二人会话)、"3" ConversationTypeGroup(群组会话)。 + ConversationType *string `url:"conversationType,omitempty"` + // [必传] 目标 ID,根据不同的 conversationType,可能是用户 ID 或群组 ID。 + TargetId *string `url:"targetId,omitempty"` + // [必传] 需要删除的扩展信息的 Key 值,一次最多可以删除 100 个扩展信息。 + ExtraKey []string `url:"-"` + // 删除操作会生成一条「扩展操作消息」。该字段指定是否将该「扩展操作消息」同步到发件人(扩展操作者)的客户端。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见[发件人客户端如何同步已发消息](https://doc.rongcloud.cn/imserver/server/v1/message/how-to-sync-to-sender-client)。 + IsSyncSender *int `url:"isSyncSender,omitempty"` +} + +type MessageExpansionDeleteResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageExpansionDelete 删除单群聊消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/delete-expansion +func (rc *RongCloud) MessageExpansionDelete(ctx context.Context, req *MessageExpansionDeleteRequest) (*MessageExpansionDeleteResponse, error) { + path := "/message/expansion/delete.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.ExtraKey != nil { + extraKeys, err := json.Marshal(req.ExtraKey) + if err != nil { + return nil, NewSDKError(fmt.Sprintf("marshal extraKey error %s", err)) + } + params.Set("extraKey", string(extraKeys)) + } + resp := &MessageExpansionDeleteResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageExpansionQueryRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见[全量消息路由](https://doc.rongcloud.cn/imserver/server/v1/message/sync) + MsgUID *string `url:"msgUID,omitempty"` + // 页数,默认返回 300 个扩展信息。 + PageNo *int `url:"pageNo,omitempty"` +} + +type MessageExpansionQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // 消息扩展的内容 + ExtraContent map[string]*MessageExpansionQueryExtraContentValue `json:"extraContent"` +} + +type MessageExpansionQueryExtraContentValue struct { + Value string `json:"v"` // value + Timestamp int64 `json:"ts"` // 版本号 +} + +// MessageExpansionQuery 获取单群聊消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/get-expansion +func (rc *RongCloud) MessageExpansionQuery(ctx context.Context, req *MessageExpansionQueryRequest) (*MessageExpansionQueryResponse, error) { + path := "/message/expansion/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &MessageExpansionQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageUltraGroupPublishRequest struct { + // [必传] 发送人用户 ID,通过 Server API 非群成员也可以向群组中发送消息。 注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `json:"fromUserId,omitempty"` + // [必传] 接收群 ID,提供多个本参数可以实现向多群发送消息,最多不超过 3 个超级群。 + ToGroupIds []string `json:"toGroupIds,omitempty"` + // [必传] 消息类型,接受内置消息类型(见消息类型概述)或自定义消息的消息类型值。 + // 注意:在自定义消息时,消息类型不可以 "RC:" 开头,以免与系统内置消息类型重名;消息类型长度不可超过 32 个字符。SDK 中必须已注册过该自定义消息,否则 SDK 收到该消息后将无法解析。 + ObjectName *string `json:"objectName,omitempty"` + // [必传] 所发送消息的内容,单条消息最大 128k。 + //内置消息类型:将消息内容体 JSON 对象序列化为 JSON 字符串传入。消息内容 JSON 结构体详见用户内容类消息格式或其他内置消息类型的消息内容格式。 + //例如,文本消息内容 JSON 结构体内部包含 content 字段(此为 JSON 结构体内的 key 值,注意区分),则需要将 {"content":"Hello world!"} 序列化后的结果作为此处 content 字段的值。 + //自定义消息类型(objectName 字段必须指定为自定义消息类型):如果发送自定义消息,该参数可自定义格式,不限于 JSON。 + Content *string `json:"content,omitempty"` + // 指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中的用户内容类消息格式,可不填写该字段,远程推送通知默认使用服务端预置的推送通知内容。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中通知类、信令类("撤回命令消息" 除外),且需要支持远程推送通知,则必须填写 pushContent,否则收件人不在线时无法收到远程推送通知。如无需触发远程推送,可不填该字段。 + // 如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + // 如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段留空禁用远程推送通知 + PushContent *string `json:"pushContent,omitempty" ` + // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + PushData *string `json:"pushData,omitempty" ` + // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖单群聊消息云端存储服务)。 + IsPersisted *int `json:"isPersisted,omitempty" ` + // 用户未在线时是否计入未读消息数。0 表示为不计数、1 表示为计数,默认为 1。 + IsCounted *int `json:"isCounted,omitempty" ` + // 是否为 @ 消息,不传时默认为非 @ 消息(效果等于传 0)。如果需要发送 @ 消息,必须指定为 1,且必须在消息内容字段(content)内部携带 @ 相关信息(mentionedInfo,可参考下方请求示例)。关于 mentionedInfo 结构的详细说明,参见如何发送 @ 消息。 + IsMentioned *int `json:"isMentioned,omitempty" ` + // 仅目标用户为 iOS 设备时有效,应用处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看[知识库文档](https://help.rongcloud.cn/t/topic/855)。1 表示为开启,0 表示为关闭,默认为 0。 + ContentAvailable *int `json:"contentAvailable,omitempty" ` + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。json string + PushExt *string `json:"pushExt,omitempty" ` + // 频道 Id,发消息时会对群 ID 下的频道 ID 做合法性校验,如果群 ID 下无此频道 ID 则服务端不会下发此条消息。支持大小写英文字母、数字的组合方式,不支持特殊字符,最长为 20 个字符。 + BusChannel *string `json:"busChannel,omitempty" ` + // 是否为可扩展消息,默认为 false,设为 true 时终端在收到该条消息后,可对该条消息设置扩展信息 + Expansion *bool `json:"expansion,omitempty" ` + // 仅在 expansion 为 true 时有效。 + //自定义的消息扩展信息,该字段接受 JSON 字符串格式的键值对(key-value pairs)。请注意区别于消息体内的 extra 字段,extraContent 的值在消息发送后可修改,修改方式请参见服务端 API 接口文档消息扩展,或参考各客户端「消息扩展」接口文档。 + //KV 详细要求:以 Key、Value 的方式进行设置,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。单次可设置最多 100 对 KV 扩展信息,单条消息最多可设置 300 对 KV 扩展信息。 + ExtraContent *string `json:"extraContent,omitempty" ` +} + +type MessageUltraGroupPublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageUltraGroupPublish 发送超级群消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-ultragroup +func (rc *RongCloud) MessageUltraGroupPublish(ctx context.Context, req *MessageUltraGroupPublishRequest) (*MessageUltraGroupPublishResponse, error) { + path := "/message/ultragroup/publish.json" + resp := &MessageUltraGroupPublishResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageRecallRequest struct { + // [必传] 消息发送人用户 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + // [必传] 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、4(聊天室会话)、6(系统会话)、10(超级群会话)。 + ConversationType *int `url:"conversationType,omitempty"` + // [必传] 目标 ID,根据不同的会话类型(ConversationType),可能是用户 ID、群组 ID、聊天室 ID、超级群 ID,系统目标 ID。 + TargetId *string `url:"targetId,omitempty"` + // 超级群频道 ID,仅适用于撤回超级群消息。使用要求如下: + // 如果发送消息时指定了频道 ID,则撤回时必须指定频道 ID,否则无法撤回。 + // 如果发送消息时未指定频道 ID,则撤回时不可指定频道 ID,否则无法撤回。 + // 客户端发送超级群消息时,频道 ID 对应字段名称为 channelId。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 消息唯一标识。 + // 可通过全量消息路由服务获取消息唯一标识,对应名称为 msgUID。 + // 全量消息路由服务不支持的消息,目前只能通过历史消息日志获取,对应字段名称为 msgUID。 + MessageUID *string `url:"messageUID,omitempty"` + // [必传] 消息发送时间。 + // 可通过全量消息路由服务获取消息发送时间,对应名称为 msgTimestamp。 + // 全量消息路由服务不支持的消息,目前只能通过历史消息日志获取,对应字段名称为 dateTime。 + SentTime *int64 `url:"sentTime,omitempty"` + // 是否为管理员,默认为 0,设为 1 时,IMKit 收到此条消息后,小灰条默认显示为“管理员 撤回了一条消息”。 + IsAdmin *int `url:"isAdmin,omitempty"` + // 指定移动端接收方是否需要在本地删除原始消息记录及显示撤回消息提示,默认为 0。 + // 为 0 时,移动端接收方仅将原始消息内容替换为撤回提示(小灰条通知),不删除该原始消息记录。 + // 为 1 时,移动端接收方会删除原始消息记录,不显示撤回提示(小灰条通知)。 + // 注意:即时通讯服务端历史消息不保存已撤回的超级群消息记录。如果 isDelete 设置为 0,撤回超级群消息后,移动端本地会存有记录(显示为撤回提示),而 Web 端无记录,可能会造成用户体验差异。 + IsDelete *int `url:"isDelete,omitempty"` + // 是否为静默撤回,默认为 false,设为 true 时终端用户离线情况下不会收到撤回通知提醒。该字段不支持聊天室、超级群会话类型。 + DisablePush *bool `url:"disablePush,omitempty"` + // 扩展信息,可以放置任意的数据内容。不支持超级群会话(conversationType 为 10)。 + Extra *string `url:"extra,omitempty"` +} + +type MessageRecallResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageRecall 撤回消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/msgrecall +func (rc *RongCloud) MessageRecall(ctx context.Context, req *MessageRecallRequest) (*MessageRecallResponse, error) { + path := "/message/recall.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &MessageRecallResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageBroadcastRequest struct { + // [必传] 发送人用户 ID。 + // 注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `url:"fromUserId,omitempty"` + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息), HQVCMsg(高清语音消息) + RCMsg RCMsg `url:"-"` + // 指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中的用户内容类消息格式,可不填写该字段,远程推送通知默认使用服务端预置的推送通知内容。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中通知类、信令类("撤回命令消息" 除外),且需要支持远程推送通知,则必须填写 pushContent,否则收件人不在线时无法收到远程推送通知。如无需触发远程推送,可不填该字段。 + // 如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + // 如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段留空禁用远程推送通知。 + PushContent *string `url:"pushContent,omitempty"` + // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + PushData *string `url:"pushData,omitempty"` + // 针对 iOS 平台,对 SDK 处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `url:"contentAvailable,omitempty"` + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。具体请查看下方 pushExt 参数说明。json string + PushExt *string `url:"pushExt,omitempty"` +} + +type MessageBroadcastResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageBroadcast 发送全量用户落地通知 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-message-broadcast-to-all +func (rc *RongCloud) MessageBroadcast(ctx context.Context, req *MessageBroadcastRequest) (*MessageBroadcastResponse, error) { + path := "/message/broadcast.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &MessageBroadcastResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type StatusMessagePrivatePublishRequest struct { + // [必传] 发送人用户 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + // [必传] 接收用户 ID,支持向多人发送消息,每次上限为 1000 人。 + ToUserIds []string `url:"toUserId,omitempty"` + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息), HQVCMsg(高清语音消息) + RCMsg RCMsg `url:"-"` + // 是否过滤发送人黑名单列表,0 表示为不过滤、 1 表示为过滤,默认为 0 不过滤。 + VerifyBlacklist *int `url:"verifyBlacklist,omitempty"` + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,该接口用于发送状态消息,因此仅支持在发件人已登陆客户端(在线)的情况下同步已发消息。 + IsIncludeSender *int `url:"isIncludeSender,omitempty"` +} + +type StatusMessagePrivatePublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// StatusMessagePrivatePublish 发送单聊状态消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-status-private +func (rc *RongCloud) StatusMessagePrivatePublish(ctx context.Context, req *StatusMessagePrivatePublishRequest) (*StatusMessagePrivatePublishResponse, error) { + path := "/statusmessage/private/publish.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &StatusMessagePrivatePublishResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessagePrivatePublishTemplateRequest struct { + // [必传] 发送人用户 ID。 + // 注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `json:"fromUserId"` + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `json:"-"` + // [必传] SDK封装消息模板 + MessageTemplate []*MessageTemplate `json:"-"` + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见发件人客户端如何同步已发消息。 + IsIncludeSender *int `json:"isIncludeSender"` + // 是否过滤发送人黑名单列表,0 为不过滤、 1 为过滤,默认为 0 不过滤。 + VerifyBlacklist *int `json:"verifyBlacklist,omitempty"` + // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖单群聊消息云端存储服务)。 + // 此属性不影响离线消息功能,用户未在线时都会转为离线消息?存储。 + // 提示:一般情况下(第 1、2 种情况),客户端是否存储消息不依赖此参数。以下第 3 种情况属于例外: + // 如果消息属于内置消息类型,客户端 SDK 会根据消息类型本身的存储属性标识判断是否存入本地数据库。详见消息类型概述。 + // 如果消息属于自定义消息类型,则客户端 SDK 会根据该类型在客户端上注册时的存储属性标识判断是否需要存入本地数据库。 + // 如果消息属于客户端 App 上未注册自定义消息类型(例如客户端使用的 App 版本过旧),则客户端 SDK 会根据当前参数值确定是否将消息存储在本地。但因消息类型未注册,客户端无法解析显示该消息。 + IsPersisted *int `json:"isPersisted,omitempty"` + // 仅目标用户为 iOS 设备时有效,对 SDK 处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `json:"contentAvailable,omitempty"` + // 是否为可扩展消息,默认为 false,设为 true 时终端在收到该条消息后,可对该条消息设置扩展信息。 + Expansion *bool `json:"expansion,omitempty"` + // 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。 + DisablePush *bool `json:"disablePush,omitempty"` + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。json string + PushExt *string `json:"pushExt,omitempty"` +} + +func (r *MessagePrivatePublishTemplateRequest) MarshalJSON() ([]byte, error) { + req := messagePublishTemplateRequest{ + FromUserId: r.FromUserId, + IsIncludeSender: r.IsIncludeSender, + VerifyBlacklist: r.VerifyBlacklist, + IsPersisted: r.IsPersisted, + ContentAvailable: r.ContentAvailable, + Expansion: r.Expansion, + DisablePush: r.DisablePush, + PushExt: r.PushExt, + } + if r.RCMsg != nil { + req.ObjectName = r.RCMsg.ObjectName() + content, err := r.RCMsg.ToString() + if err != nil { + return nil, fmt.Errorf("%s RcMsg.ToString() error %s", req.ObjectName, err) + } + req.Content = content + } + if r.MessageTemplate != nil { + var values []map[string]string + var toUserIds []string + var pushContent []string + var pushData []string + for _, template := range r.MessageTemplate { + values = append(values, template.Value) + toUserIds = append(toUserIds, template.ToUserId) + pushContent = append(pushContent, template.PushContent) + pushData = append(pushData, template.PushData) + } + req.Values = values + req.ToUserId = toUserIds + req.PushContent = pushContent + req.PushData = pushData + } + return json.Marshal(req) +} + +type messagePublishTemplateRequest struct { + FromUserId *string `json:"fromUserId,omitempty"` + ToUserId []string `json:"toUserId,omitempty"` + ObjectName string `json:"objectName,omitempty"` + Content string `json:"content,omitempty"` + Values []map[string]string `json:"values,omitempty"` + PushContent []string `json:"pushContent,omitempty"` + PushData []string `json:"pushData,omitempty"` + IsIncludeSender *int `json:"isIncludeSender,omitempty"` + VerifyBlacklist *int `json:"verifyBlacklist,omitempty"` + IsPersisted *int `json:"isPersisted,omitempty"` + ContentAvailable *int `json:"contentAvailable,omitempty"` + Expansion *bool `json:"expansion,omitempty"` + DisablePush *bool `json:"disablePush,omitempty"` + PushExt *string `json:"pushExt,omitempty"` +} + +type MessageTemplate struct { + // [必传] 接收用户 ID。 + ToUserId string + // [必传] 为消息内容(content)、推送通知内容(pushContent)、推送数据(pushData)中的标识位(标识位示例:{d})提供对应的值。 + Value map[string]string + // [必传] 指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。支持定义模板标识位,使用 values 中的值进行替换。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义的消息类型,填写该字段后,离线推送通知中显示模板定义的推送内容,而非消息类型的默认推送内容。 + // 如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + // 如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段对应数组传空值禁用离线推送。 + PushContent string + // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + PushData string +} + +type MessagePrivatePublishTemplateResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessagePrivatePublishTemplate 发送单聊模板消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-private-template +func (rc *RongCloud) MessagePrivatePublishTemplate(ctx context.Context, req *MessagePrivatePublishTemplateRequest) (*MessagePrivatePublishTemplateResponse, error) { + path := "/message/private/publish_template.json" + resp := &MessagePrivatePublishTemplateResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageGroupPublishRequest struct { + // [必传] 发送人用户 ID,通过 Server API 非群成员也可以向群组中发送消息。 + //注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 接收消息的群 ID。支持最多 3 个群组 ID。发送群聊定向消息时,仅支持传入一个群组 ID。 + ToGroupId []string `url:"toGroupId,omitempty"` + + // 发送群聊定向消息时,接收消息的群成员用户 ID 列表,群中其他用户无法收到该定向消息。仅当 toGroupId 传入单个群组 ID 时有效。 + ToUserId []string `url:"toUserId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` + + // 指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中的用户内容类消息格式,可不填写该字段,远程推送通知默认使用服务端预置的推送通知内容。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中通知类、信令类("撤回命令消息" 除外),且需要支持远程推送通知,则必须填写 pushContent,否则收件人不在线时无法收到远程推送通知。如无需触发远程推送,可不填该字段。 + // 如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + // 如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段留空禁用远程推送通知。 + PushContent *string `url:"pushContent,omitempty"` + + // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + PushData *string `url:"pushData,omitempty"` + + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见发件人[客户端如何同步已发消息](https://doc.rongcloud.cn/imserver/server/v1/message/how-to-sync-to-sender-client)。 + IsIncludeSender *int `url:"isIncludeSender,omitempty"` + + // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖单群聊消息云端存储服务)。 + // 注意:即使已开通单群聊消息云存储功能,群组定向消息也不会存入服务端历史消息记录。如有需要,请提交工单申请开通群定向消息云存储服务。 + // 此属性不影响离线消息功能,用户未在线时都会转为离线消息?存储。 + // 提示:一般情况下(第 1、2 种情况),客户端是否存储消息不依赖此参数。以下第 3 种情况属于例外: + // 如果消息属于内置消息类型,客户端 SDK 会根据消息类型本身的存储属性标识判断是否存入本地数据库。详见消息类型概述。 + // 如果消息属于自定义消息类型,则客户端 SDK 会根据该类型在客户端上注册时的存储属性标识判断是否需要存入本地数据库。 + // 如果消息属于客户端 App 上未注册自定义消息类型(例如客户端使用的 App 版本过旧),则客户端 SDK 会根据当前参数值确定是否将消息存储在本地。但因消息类型未注册,客户端无法解析显示该消息。 + IsPersisted *int `url:"isPersisted,omitempty"` + + // 是否为 @ 消息,不传时默认为非 @ 消息(效果等于传 0)。如果需要发送 @ 消息,必须指定为 1,且必须在消息内容字段(content)内部携带 @ 相关信息(mentionedInfo,可参考下方请求示例)。关于 mentionedInfo 结构的详细说明,参见如何发送 @ 消息。 + IsMentioned *int `url:"isMentioned,omitempty"` + + // 仅目标用户为 iOS 设备时有效,应用处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看[知识库文档](https://help.rongcloud.cn/t/topic/855)。1 表示为开启,0 表示为关闭,默认为 0。 + ContentAvailable *int `url:"contentAvailable,omitempty"` + + // 是否为可扩展消息,默认为 false,设为 true 时终端在收到该条消息后,可对该条消息设置扩展信息。移动端 SDK 4.0.3 版本、Web 端 3.0.7 版本支持此功能。仅当 toGroupId 传入单个群组 ID 时有效。 + Expansion *bool `url:"expansion,omitempty"` + + // 仅在 expansion 为 true 时有效。 + //自定义的消息扩展信息,该字段接受 JSON 字符串格式的键值对(key-value pairs)。请注意区别于消息体内的 extra 字段,extraContent 的值在消息发送后可修改,修改方式请参见服务端 API 接口文档消息扩展,或参考各客户端「消息扩展」接口文档。 + //KV 详细要求:以 Key、Value 的方式进行设置,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。单次可设置最多 100 对 KV 扩展信息,单条消息最多可设置 300 对 KV 扩展信息。 + ExtraContent map[string]string `url:"-"` + + // 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。仅当 toGroupId 传入单个群组 ID 时有效。 + DisablePush *bool `url:"disablePush,omitempty"` + + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。仅当 toGroupId 传入单个群组 ID 时有效。json string + PushExt *string `url:"pushExt,omitempty"` +} + +type MessageGroupPublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageGroupPublish 发送群聊消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-group +func (rc *RongCloud) MessageGroupPublish(ctx context.Context, req *MessageGroupPublishRequest) (*MessageGroupPublishResponse, error) { + path := "/message/group/publish.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + if req.ExtraContent != nil { + extraContent, err := json.Marshal(req.ExtraContent) + if err != nil { + return nil, NewSDKError(fmt.Sprintf("extraContent marshal error %s", err)) + } + params.Set("extraContent", string(extraContent)) + } + resp := &MessageGroupPublishResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type StatusMessageGroupPublishRequest struct { + // [必传] 发送人用户 ID,通过 Server API 非群成员也可以向群组中发送消息。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 接收群ID,提供多个本参数可以实现向多群发送消息,最多不超过 3 个群组。 + ToGroupId []string `url:"toGroupId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` + + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,该接口用于发送状态消息,因此仅支持在发件人已登陆客户端(在线)的情况下同步已发消息。 + IsIncludeSender *int `url:"isIncludeSender,omitempty"` +} + +type StatusMessageGroupPublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// StatusMessageGroupPublish 发送群聊状态消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-status-group +func (rc *RongCloud) StatusMessageGroupPublish(ctx context.Context, req *StatusMessageGroupPublishRequest) (*StatusMessageGroupPublishResponse, error) { + path := "/statusmessage/group/publish.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &StatusMessageGroupPublishResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageChatroomPublishRequest struct { + // [必传] 发送人用户 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 接收聊天室 ID,提供多个本参数可以实现向多个聊天室发送消息,建议最多不超过 10 个聊天室。 + ToChatroomId []string `url:"toChatroomId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` + + // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖聊天室消息云端存储服务)。 + // 一般情况下(第 1、2 种情况),客户端是否存储消息不依赖此参数。以下第 3 种情况属于例外: + // 如果消息属于内置消息类型,客户端 SDK 会根据消息类型本身的存储属性标识判断是否存入本地数据库。详见消息类型概述。 + // 如果消息属于自定义消息类型,则客户端 SDK 会根据该类型在客户端上注册时的存储属性标识判断是否需要存入本地数据库。 + // 如果消息属于客户端 App 上未注册自定义消息类型(例如客户端使用的 App 版本过旧),则客户端 SDK 会根据当前参数值确定是否将消息存储在本地。但因消息类型未注册,客户端无法解析显示该消息。 + // 注意:客户端会在用户退出聊天室时自动清除本地的聊天室历史消息记录。 + IsPersisted *int `url:"isPersisted,omitempty"` + + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见发件人客户端如何同步已发消息。 + IsIncludeSender *int `url:"isIncludeSender,omitempty"` +} + +type MessageChatroomPublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageChatroomPublish 发送聊天室消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-chatroom +func (rc *RongCloud) MessageChatroomPublish(ctx context.Context, req *MessageChatroomPublishRequest) (*MessageChatroomPublishResponse, error) { + path := "/message/chatroom/publish.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &MessageChatroomPublishResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageChatroomBroadcastRequest struct { + // [必传] 发送人用户 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` + + // 是否向发件人客户端同步已发消息。1 表示同步,默认值为 0,即不同步。注意,仅设置该参数无法确保发件人客户端一定能获取到该条已发消息,您可能还需要启用其他服务。详见发件人客户端如何同步已发消息。 + IsIncludeSender *int `url:"isIncludeSender,omitempty"` +} + +type MessageChatroomBroadcastResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageChatroomBroadcast 发送全体聊天室广播消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/send-chatroom-broadcast +func (rc *RongCloud) MessageChatroomBroadcast(ctx context.Context, req *MessageChatroomBroadcastRequest) (*MessageChatroomBroadcastResponse, error) { + path := "/message/chatroom/broadcast.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &MessageChatroomBroadcastResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageOnlineBroadcastRequest struct { + // [必传] 发送人用户 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` +} + +type MessageOnlineBroadcastResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageOnlineBroadcast 发送在线用户广播 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-message-broadcast-online +func (rc *RongCloud) MessageOnlineBroadcast(ctx context.Context, req *MessageOnlineBroadcastRequest) (*MessageOnlineBroadcastResponse, error) { + path := "/message/online/broadcast.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &MessageOnlineBroadcastResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageSystemPublishRequest struct { + // [必传] 发送人用户 ID,通过 Server API 非群成员也可以向群组中发送消息。 + //注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `url:"fromUserId,omitempty"` + + // [必传] 接收用户 ID,提供多个本参数可以实现向多用户发送系统消息,上限为 100 人。 + ToUserId []string `url:"toUserId,omitempty"` + + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `url:"-"` + + // 指定收件人离线时触发的远程推送通知中的通知内容。注意:对于部分消息类型,该字段是否有值决定了是否触发远程推送通知。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中的用户内容类消息格式,可不填写该字段,远程推送通知默认使用服务端预置的推送通知内容。 + // 如果消息类型(objectName 字段)为即时通讯服务预定义消息类型中通知类、信令类("撤回命令消息" 除外),且需要支持远程推送通知,则必须填写 pushContent,否则收件人不在线时无法收到远程推送通知。如无需触发远程推送,可不填该字段。 + // 如果消息类型为自定义消息类型,且需要支持远程推送通知,则必须填写 pushContent 字段,否则收件人不在线时无法收到远程推送通知。 + // 如果消息类型为自定义消息类型,但不需要支持远程推送通知(例如通过自定义消息类型实现的 App 业务层操作指令),可将 pushContent 字段留空禁用远程推送通知。 + PushContent *string `url:"pushContent,omitempty"` + + // iOS 平台收到推送消息时,可从 payload 中获取 APNs 推送数据,对应字段名为 appData(提示:rc 字段中默认携带了消息基本信息)。Android 平台收到推送消息时对应字段名为 appData。 + PushData *string `url:"pushData,omitempty"` + + // 是否需要为收件人在历史消息云端存储服务中存储此条消息。0 表示不存储;1 表示存储。默认值为 1,存储(依赖单群聊消息云端存储服务)。 + // 注意:即使已开通单群聊消息云存储功能,群组定向消息也不会存入服务端历史消息记录。如有需要,请提交工单申请开通群定向消息云存储服务。 + // 此属性不影响离线消息功能,用户未在线时都会转为离线消息?存储。 + // 提示:一般情况下(第 1、2 种情况),客户端是否存储消息不依赖此参数。以下第 3 种情况属于例外: + // 如果消息属于内置消息类型,客户端 SDK 会根据消息类型本身的存储属性标识判断是否存入本地数据库。详见消息类型概述。 + // 如果消息属于自定义消息类型,则客户端 SDK 会根据该类型在客户端上注册时的存储属性标识判断是否需要存入本地数据库。 + // 如果消息属于客户端 App 上未注册自定义消息类型(例如客户端使用的 App 版本过旧),则客户端 SDK 会根据当前参数值确定是否将消息存储在本地。但因消息类型未注册,客户端无法解析显示该消息。 + IsPersisted *int `url:"isPersisted,omitempty"` + + // 仅目标用户为 iOS 设备时有效,应用处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看[知识库文档](https://help.rongcloud.cn/t/topic/855)。1 表示为开启,0 表示为关闭,默认为 0。 + ContentAvailable *int `url:"contentAvailable,omitempty"` + + // 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。 + DisablePush *bool `url:"disablePush,omitempty"` + + // 配置消息的推送通知,如推送通知的标题等。disablePush 属性为 true 时此属性无效。json string + PushExt *string `url:"pushExt,omitempty"` +} + +type MessageSystemPublishResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageSystemPublish 发送系统通知普通消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-private +func (rc *RongCloud) MessageSystemPublish(ctx context.Context, req *MessageSystemPublishRequest) (*MessageSystemPublishResponse, error) { + path := "/message/system/publish.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.RCMsg != nil { + err = makeRCMsgUrlValues(req.RCMsg, params) + if err != nil { + return nil, err + } + } + resp := &MessageSystemPublishResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageSystemPublishTemplateRequest struct { + // [必传] 发送人用户 ID。 + // 注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserId *string `json:"fromUserId,omitempty"` + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息) + RCMsg RCMsg `json:"-"` + // [必传] SDK封装消息模板 + MessageTemplate []*MessageTemplate `json:"-"` + // 针对 iOS 平台,对 SDK 处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `json:"contentAvailable,omitempty"` + // 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。 + DisablePush *bool `json:"disablePush,omitempty"` +} + +func (r *MessageSystemPublishTemplateRequest) MarshalJSON() ([]byte, error) { + req := messagePublishTemplateRequest{ + FromUserId: r.FromUserId, + ContentAvailable: r.ContentAvailable, + DisablePush: r.DisablePush, + } + if r.RCMsg != nil { + req.ObjectName = r.RCMsg.ObjectName() + content, err := r.RCMsg.ToString() + if err != nil { + return nil, fmt.Errorf("%s RcMsg.ToString() error %s", req.ObjectName, err) + } + req.Content = content + } + if r.MessageTemplate != nil { + var values []map[string]string + var toUserIds []string + var pushContent []string + var pushData []string + for _, template := range r.MessageTemplate { + values = append(values, template.Value) + toUserIds = append(toUserIds, template.ToUserId) + pushContent = append(pushContent, template.PushContent) + pushData = append(pushData, template.PushData) + } + req.Values = values + req.ToUserId = toUserIds + req.PushContent = pushContent + req.PushData = pushData + } + return json.Marshal(req) +} + +type MessageSystemPublishTemplateResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageSystemPublishTemplate 发送系统通知模板消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-private-template +func (rc *RongCloud) MessageSystemPublishTemplate(ctx context.Context, req *MessageSystemPublishTemplateRequest) (*MessageSystemPublishTemplateResponse, error) { + path := "/message/system/publish_template.json" + resp := &MessageSystemPublishTemplateResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageHistoryRequest struct { + // [必传] 指定时间,精确到某天某小时,格式为 YYYYMMDDHH。例如 2014010101 表示需要获取 2014 年 1 月 1 日凌晨 1 点至 2 点的数据。 + // 注意:date 的值与应用所属数据中心有关。如您的 App 业务使用新加坡数据中心,则获取消息日志时使用的时间(date),及日志中的消息时间(dateTime)均为 UTC 时间。如您仍需根据北京时间下载数据,请自行转换处理。如要下载北京时间 2019120109 的日志,需要输入 2019120101。 + Date *string `url:"date,omitempty"` +} + +type MessageHistoryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // 历史记录下载地址。如没有消息记录数据时,则 url 值为空。 + Url string `json:"url"` + // 历史记录时间。 + Date string `json:"date"` +} + +// MessageHistory 获取历史消息日志 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/get-message-history-log +func (rc *RongCloud) MessageHistory(ctx context.Context, req *MessageHistoryRequest) (*MessageHistoryResponse, error) { + path := "/message/history.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &MessageHistoryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type MessageHistoryDeleteRequest struct { + // [必传] 指定时间,精确到某天某小时,格式为 YYYYMMDDHH。例如 2014010101 表示需要删除 2014 年 1 月 1 日凌晨 1 点至 2 点的数据。返回成功后,消息记录文件将在随后的 10 分钟内被永久删除。 + // 注意:date 的值与应用所属数据中心有关。如您的 App 业务使用新加坡数据中心,则获取消息日志时使用的时间(date),及日志中的消息时间(dateTime)均为 UTC 时间。如您仍需根据北京时间下载数据,请自行转换处理。如要下载北京时间 2019120109 的日志,需要输入 2019120101。 + Date *string `url:"date,omitempty"` +} + +type MessageHistoryDeleteResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// MessageHistoryDelete 删除历史消息日志 +// More details see https://doc.rongcloud.cn/imserver/server/v1/message/delete-message-history-log +func (rc *RongCloud) MessageHistoryDelete(ctx context.Context, req *MessageHistoryDeleteRequest) (*MessageHistoryDeleteResponse, error) { + path := "/message/history/delete.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &MessageHistoryDeleteResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/sdk/options.go b/rongcloud/options.go similarity index 72% rename from sdk/options.go rename to rongcloud/options.go index dd9b998..3b44442 100644 --- a/sdk/options.go +++ b/rongcloud/options.go @@ -1,4 +1,4 @@ -package sdk +package rongcloud import ( "net/http" @@ -21,27 +21,28 @@ func WithRongCloudURI(rongCloudURI string) rongCloudOption { } } -// WithTimeout 设置超时时间,最小单位为秒 +// WithTimeout http client参数, 设置超时时间,最小单位为秒 func WithTimeout(t time.Duration) rongCloudOption { return func(o *RongCloud) { o.timeout = t } } -// WithKeepAlive 连接保活时间,最小单位为秒 +// WithKeepAlive http client参数, 连接保活时间,最小单位为秒 func WithKeepAlive(t time.Duration) rongCloudOption { return func(o *RongCloud) { o.keepAlive = t } } -// WithMaxIdleConnsPerHost 设置每个域名最大连接数 +// WithMaxIdleConnsPerHost http client参数, 设置每个域名最大连接数 func WithMaxIdleConnsPerHost(n int) rongCloudOption { return func(o *RongCloud) { o.maxIdleConnsPerHost = n } } +// WithTransport 自定义http client Transport, 优先级大于其他http client参数 func WithTransport(transport http.RoundTripper) rongCloudOption { return func(o *RongCloud) { o.globalTransport = transport diff --git a/sdk/options_test.go b/rongcloud/options_test.go similarity index 97% rename from sdk/options_test.go rename to rongcloud/options_test.go index 2e8baf1..bf61ffb 100644 --- a/sdk/options_test.go +++ b/rongcloud/options_test.go @@ -1,4 +1,4 @@ -package sdk +package rongcloud import ( "os" diff --git a/rongcloud/push.go b/rongcloud/push.go new file mode 100644 index 0000000..ba6416e --- /dev/null +++ b/rongcloud/push.go @@ -0,0 +1,328 @@ +package rongcloud + +import ( + "context" + "encoding/json" + "fmt" +) + +type PushCustomRequest struct { + // [必传] 目标平台(操作系统),可以为 ios、android 其中一个或全部。全部填写时给给 Android、iOS 两个平台推送消息。 + Platform []string `json:"platform,omitempty"` + // [必传] 推送条件。支持按用户标签推送(tag 、tag_or)、按应用包名推送(packageName)和按指定平台全部推送(is_to_all)。注意:如果推送条件中 is_to_all 为 true,则忽略其他推送条件。 + Audience *PushCustomAudience `json:"audience,omitempty"` + // [必传] 按平台(操作系统)指定推送内容。 + Notification *PushCustomNotification `json:"notification,omitempty"` +} + +type PushCustomAudience struct { + // 用户标签数组,标签之间为 AND 关系。数组中最多包含 20 个标签。 + Tag []string `json:"tag,omitempty"` + // 用户标签数组,标签之间为 OR 关系。数组中最多包含 20 个标签。 + TagOr []string `json:"tag_or,omitempty"` + // 应用包名。与 tag 或 tag_or 为逻辑与(AND)关系。 + PackageName *string `json:"packageName,omitempty"` + // [必传] 是否按指定平台(操作系统)全部推送。true 表示全部推送,此时其他推送条件字段均无效。false 表示按其他推送条件进行推送。 + IsToAll *bool `json:"is_to_all,omitempty"` + // [必传] 在按用户标签推送场景下,可通过 tagItems 实现复杂与或非逻辑。在 tagItems 包含有效内容的情况下,tag、tag_or 字段无效。 + TagItems []*PushCustomAudienceTagItem `json:"tagItems,omitempty"` +} + +type PushCustomAudienceTagItem struct { + // [必传] 用户标签数组。 + Tags []string `json:"tags,omitempty"` + // [必传] 是否对 tags 数组的运算结果进行非运算。默认为 false。 + IsNot *bool `json:"isNot,omitempty"` + // [必传] tags 数组内标签之间的运算符。 + TagsOperator *string `json:"tagsOperator,omitempty"` + // [必传] tagItems 数组内当前 Object 与上一个 Object 之间的运算符。注意:首个 Object 内的 itemsOperator 未被使用,为无效字段。 + ItemsOperator *string `json:"itemsOperator,omitempty"` +} + +type PushCustomNotification struct { + // 通知栏显示标题,最长不超过 50 个字符。 + Title *string `json:"title,omitempty"` + // 默认推送通知内容。 + Alert *string `json:"alert,omitempty"` + // 设置 iOS 平台下的推送及附加信息。 + IOS *PushCustomNotificationIOS `json:"ios,omitempty"` + // 设置 Android 平台下的推送及附加信息。 + Android *PushAndroid `json:"android,omitempty"` +} + +type PushCustomNotificationIOS struct { + // 通知栏显示的推送标题,仅针对 iOS 平台,支持 iOS 8.2 及以上版本,参数在 ios 节点下设置,详细可参考“设置 iOS 推送标题请求示例”,此属性优先级高于 notification 下的 title。 + Title *string `json:"title,omitempty"` + // 针对 iOS 平台,静默推送是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `json:"contentAvailable,omitempty"` + // 应用角标,仅针对 iOS 平台;不填时,表示不改变角标数;为 0 或负数时,表示 App 角标上的数字清零;否则传相应数字表示把角标数改为指定的数字,最大不超过 9999,参数在 ios 节点下设置,详细可参考“设置 iOS 角标数 HTTP 请求示例”。 + Badge *int `json:"badge,omitempty"` + // iOS 平台通知栏分组 ID,相同的 thread-id 推送分一组,单组超过 5 条推送会折叠展示 + ThreadId *string `json:"thread-id,omitempty"` + // iOS 平台,从 iOS10 开始支持,设置后设备收到有相同 ID 的消息,会合并成一条 + ApnsCollapseId *string `json:"apns-collapse-id,omitempty"` + // iOS 富文本推送的类型开发者自己定义,自己在 App 端进行解析判断,与 richMediaUri 一起使用,当设置 category 后,推送时默认携带 mutable-content 进行推送,属性值为 1。 + Category *string `json:"category,omitempty"` + // iOS 富文本推送内容的 URL,与 category 一起使用。 + RichMediaUri *string `json:"richMediaUri,omitempty"` + // 适用于 iOS 15 及之后的系统。取值为 passive,active(默认),time-sensitive,或 critical,取值说明详见对应的 APNs 的 interruption-level 字段。在 iOS 15 及以上版本中,系统的 “定时推送摘要”、“专注模式” 都可能导致重要的推送通知(例如余额变化)无法及时被用户感知的情况,可考虑设置该字段。 + InterruptionLevel *string `json:"interruption-level,omitempty"` + // 附加信息,如果开发者自己需要,可以自己在 App 端进行解析。 + Extras interface{} `json:"extras,omitempty"` +} + +type PushAndroid struct { + Honor *PushAndroidHonor `json:"honor,omitempty"` + HW *PushAndroidHW `json:"hw,omitempty"` + Oppo *PushAndroidOppo `json:"oppo,omitempty"` + Vivo *PushAndroidVivo `json:"vivo,omitempty"` + Fcm *PushAndroidFcm `json:"fcm,omitempty"` + Extras interface{} `json:"extras,omitempty"` +} + +type PushAndroidHonor struct { + // 荣耀通知栏消息优先级,取值: + // NORMAL(服务与通讯类消息) + // LOW(咨询营销类消息)。若资讯营销类消息发送时带图片,图片不会展示。 + Importance *string `json:"importance,omitempty"` + // 荣耀推送自定义通知栏消息右侧的大图标 URL,若不设置,则不展示通知栏右侧图标。 + // URL 使用的协议必须是 HTTPS 协议,取值样例:https://example.com/image.png。 + // 图标文件须小于 512KB,图标建议规格大小:40dp x 40dp,弧角大小为 8dp。 + // 超出建议规格大小的图标会存在图片压缩或显示不全的情况。 + Image *string `json:"image,omitempty"` +} + +type PushAndroidHW struct { + // 华为推送通知渠道的 ID。详见自定义通知渠道。 + ChannelId *string `json:"channelId,omitempty"` + // 华为推送通知栏消息优先级,取值 NORMAL、LOW,默认为 NORMAL 重要消息。 + Importance *string `json:"importance,omitempty"` + // 华为推送自定义的通知栏消息右侧大图标 URL,如果不设置,则不展示通知栏右侧图标。URL 使用的协议必须是 HTTPS 协议,取值样例:https://example.com/image.png。图标文件须小于 512KB,图标建议规格大小:40dp x 40dp,弧角大小为 8dp,超出建议规格大小的图标会存在图片压缩或显示不全的情况。 + Image *string `json:"image,omitempty"` + // 华为推送通道的消息自分类标识,category 取值必须为大写字母,例如 IM。App 根据华为要求完成自分类权益申请 或 申请特殊权限 后可传入该字段有效。详见华为推送官方文档消息分类标准。该字段优先级高于开发者后台为 App Key 下的应用标识配置的华为推送 Category。 + Category *string `json:"category,omitempty"` +} + +type PushAndroidMi struct { + // 小米推送通知渠道的 ID。详见小米推送消息分类新规。 + ChannelId *string `json:"channelId,omitempty"` + // (由于小米官方已停止支持该能力,该字段已失效)消息右侧图标 URL,如果不设置,则不展示通知栏右侧图标。国内版仅 MIUI12 以上版本支持,以下版本均不支持;国际版支持。图片要求:大小120 * 120px,格式为 png 或者 jpg 格式。 + // Deprecated + LargeIconUri *string `json:"large_icon_uri,omitempty"` +} + +type PushAndroidOppo struct { + // oppo 推送通知渠道的 ID。详见推送私信通道申请。 + ChannelId *string `json:"channelId,omitempty"` +} + +type PushAndroidVivo struct { + // VIVO 推送服务的消息类别。可选值 0(运营消息,默认值) 和 1(系统消息)。该参数对应 VIVO 推送服务的 classification 字段,见 VIVO 推送消息分类说明 。该字段优先级高于开发者后台为 App Key 下的应用标识配置的 VIVO 推送通道类型。 + Classification *string `json:"classification,omitempty"` + // VIVO 推送服务的消息二级分类。例如 IM(即时消息)。该参数对应 VIVO 推送服务的 category 字段。详细的 category 取值请参见 VIVO 推送消息分类说明 。如果指定 category ,必须同时传入与当前二级分类匹配的 classification 字段的值(系统消息场景或运营消息场景)。请注意遵照 VIVO 官方要求,确保二级分类(category)取值属于 VIVO 系统消息场景或运营消息场景下允许发送的内容。该字段优先级高于开发者后台为 App Key 下的应用标识配置的 VIVO 推送 Category。 + Category *string `json:"category,omitempty"` +} + +type PushAndroidFcm struct { + // Google FCM 推送通知渠道的 ID。应用程序必须先创建一个具有此频道 ID 的频道,然后才能收到具有此频道 ID 的任何通知。更多信息请参见 Android 官方文档。 + ChannelId *string `json:"channelId,omitempty"` + // Google FCM 推送中可以折叠的一组消息的标识符,以便在可以恢复传递时仅发送最后一条消息。 + CollapseKey *string `json:"collapse_key,omitempty"` + // Google FCM 推送自定义的通知栏消息右侧图标 URL,如果不设置,则不展示通知栏右侧图标。 + // 图片的大小上限为 1MB。 + // 要求开发者后台 FCM 推送配置为证书与通知消息方式。 + ImageUrl *string `json:"imageUrl,omitempty"` +} + +type PushCustomResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Id string `json:"id"` // 推送唯一标识。 +} + +// PushCustom 推送Plus专用推送接口,发送不落地通知 +// More details see https://doc.rongcloud.cn/imserver/server/v1/push/push-plus +func (rc *RongCloud) PushCustom(ctx context.Context, req *PushCustomRequest) (*PushCustomResponse, error) { + path := "/push/custom.json" + resp := &PushCustomResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type PushUserRequest struct { + // [必传] 用户 ID,每次发送时最多发送 100 个用户。 + UserIds []string `json:"userIds,omitempty"` + // [必传] 按操作系统类型推送消息内容。 + Notification *PushUserNotification `json:"notification,omitempty"` +} + +type PushUserNotification struct { + // 通知栏显示标题,最长不超过 50 个字符。 + Title *string `json:"title,omitempty"` + // [必传] 推送消息内容。 + PushContent *string `json:"pushContent,omitempty"` + IOS *PushUserNotificationIOS `json:"ios,omitempty"` + Android *PushAndroid `json:"android,omitempty"` +} + +// PushUserNotificationIOS +// Not same with PushCustomNotificationIOS, no Title field +type PushUserNotificationIOS struct { + // 针对 iOS 平台,静默推送是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `json:"contentAvailable,omitempty"` + // 应用角标,仅针对 iOS 平台;不填时,表示不改变角标数;为 0 或负数时,表示 App 角标上的数字清零;否则传相应数字表示把角标数改为指定的数字,最大不超过 9999,参数在 ios 节点下设置,详细可参考“设置 iOS 角标数 HTTP 请求示例”。 + Badge *int `json:"badge,omitempty"` + // iOS 平台通知栏分组 ID,相同的 thread-id 推送分一组,单组超过 5 条推送会折叠展示 + ThreadId *string `json:"thread-id,omitempty"` + // iOS 平台,从 iOS10 开始支持,设置后设备收到有相同 ID 的消息,会合并成一条 + ApnsCollapseId *string `json:"apns-collapse-id,omitempty"` + // iOS 富文本推送的类型开发者自己定义,自己在 App 端进行解析判断,与 RichMediaUri 一起使用,当设置 Category 后,推送时默认携带 mutable-content 进行推送,属性值为 1。 + Category *string `json:"category,omitempty"` + // iOS 富文本推送内容的 URL,与 category 一起使用。 + RichMediaUri *string `json:"richMediaUri,omitempty"` + // 适用于 iOS 15 及之后的系统。取值为 passive,active(默认),time-sensitive,或 critical,取值说明详见对应的 APNs 的 interruption-level 字段。在 iOS 15 及以上版本中,系统的 “定时推送摘要”、“专注模式” 都可能导致重要的推送通知(例如余额变化)无法及时被用户感知的情况,可考虑设置该字段。 + InterruptionLevel *string `json:"interruption-level,omitempty"` + // 附加信息,如果开发者自己需要,可以自己在 App 端进行解析。 + Extras interface{} `json:"extras,omitempty"` +} + +type PushUserResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Id string `json:"id"` +} + +// PushUser 发送指定用户不落地通知 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-push-by-user +func (rc *RongCloud) PushUser(ctx context.Context, req *PushUserRequest) (*PushUserResponse, error) { + path := "/push/user.json" + resp := &PushUserResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type PushRequest struct { + // [必传] 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写,发送时如目标用户在 Web 端登录也会收到此条消息。 + Platform []string `json:"platform,omitempty"` + // [必传] 发送人用户 ID。 + // 注意:发送消息所使用的用户 ID 必须已获取过用户 Token,否则消息一旦触发离线推送,通知内无法正确显示发送者的用户信息。 + FromUserid *string `json:"fromuserid,omitempty"` + // [必传] 推送条件。支持按用户 ID 推送,按用户标签推送(tag 、tag_or)、按应用包名推送(packageName)和按指定平台全部推送(is_to_all)。注意:如果推送条件中 is_to_all 为 true,则忽略其他推送条件。 + Audience *PushAudience `json:"audience,omitempty"` + // [必传] 消息类型参数的SDK封装, 例如: TXTMsg(文本消息), HQVCMsg(高清语音消息) + Message RCMsg `json:"message,omitempty"` + // 按操作系统类型推送通知内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容。 + Notification *PushNotification `json:"notification,omitempty"` +} + +func (r *PushRequest) MarshalJSON() ([]byte, error) { + req := shadowPushRequest{ + Platform: r.Platform, + FromUserid: r.FromUserid, + Audience: r.Audience, + Notification: r.Notification, + } + if r.Message != nil { + content, err := r.Message.ToString() + if err != nil { + return nil, fmt.Errorf("%s RCMsg.ToString() error %s", r.Message.ObjectName(), err) + } + req.Message = &shadowPushRequestMessage{ + ObjectName: r.Message.ObjectName(), + Content: content, + } + } + return json.Marshal(req) +} + +type shadowPushRequest struct { + Platform []string `json:"platform,omitempty"` + FromUserid *string `json:"fromuserid,omitempty"` + Audience *PushAudience `json:"audience,omitempty"` + Message *shadowPushRequestMessage `json:"message,omitempty"` + Notification *PushNotification `json:"notification,omitempty"` +} + +type shadowPushRequestMessage struct { + ObjectName string `json:"objectName,omitempty"` + Content string `json:"content,omitempty"` +} + +type PushAudience struct { + // 用户标签,每次发送时最多发送 20 个标签,标签之间为 AND 的关系,is_to_all 为 true 时参数无效。 + Tag []string `json:"tag,omitempty"` + // 用户标签,每次发送时最多发送 20 个标签,标签之间为 OR 的关系,is_to_all 为 true 时参数无效,tag_or 同 tag 参数可以同时存在。 + TagOr []string `json:"tag_or,omitempty"` + // 用户 ID,每次发送时最多发送 1000 个用户,如果 tag 和 userid 两个条件同时存在时,则以 userid 为准,如果 userid 有值时,则 platform 参数无效,is_to_all 为 true 时参数无效。 + Userid []string `json:"userid,omitempty"` + // 应用包名,is_to_all 为 true 时,此参数无效。与 tag、tag_or 同时存在时为 And 的关系,向同时满足条件的用户推送。与 userid 条件同时存在时,以 userid 为准进行推送。 + PackageName *string `json:"packageName,omitempty"` + // 是否全部推送,false 表示按 tag 、tag_or 或 userid 条件推送,true 表示向所有用户推送,tag、tag_or 和 userid 条件无效。 + IsToAll *bool `json:"is_to_all,omitempty"` +} + +type PushNotification struct { + // 通知栏显示标题,最长不超过 50 个字符。 + Title *string `json:"title,omitempty"` + // 是否越过客户端配置,强制在推送通知内显示通知内容(pushContent)。默认值 0 表示不强制,1 表示强制。 + // 说明:客户端设备可设置在接收推送通知时仅显示类似「您收到了一条通知」的提醒。从服务端发送消息时,可通过设置forceShowPushContent 为 1 越过该配置,强制客户端针在此条消息的推送通知中显示推送内容。 + ForceShowPushContent *int `json:"forceShowPushContent,omitempty"` + // 推送通知内容。注意,如果此处 Alert 不传,则必须在 IOS.Alert 和 Android.Alert 分别指定 IOS 和 Android 下的推送通知内容,否则无法正常推送。一旦指定了各平台推送内容,则推送内容以对应平台系统的 alert 为准。如果都不填写,则无法发起推送。 + Alert *string `json:"alert,omitempty"` + // 设置 IOS 平台下的推送及附加信息。 + IOS *PushNotificationIOS `json:"ios,omitempty"` + // 设置 Android 平台下的推送及附加信息 + Android *PushNotificationAndroid `json:"android"` +} + +type PushNotificationIOS struct { + // 通知栏显示的推送标题,仅针对 iOS 平台,支持 iOS 8.2 及以上版本。该属性优先级高于 PushNotification.Title。 + Title *string `json:"title,omitempty"` + // 针对 iOS 平台,静默推送是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。详情请查看知识库文档。1 表示为开启,0 表示为关闭,默认为 0 + ContentAvailable *int `json:"contentAvailable,omitempty"` + // 推送通知内容,传入后默认的推送通知内容失效。 + Alert *string `json:"alert,omitempty"` + // 应用角标,仅针对 iOS 平台;不填时,表示不改变角标数;为 0 或负数时,表示 App 角标上的数字清零;否则传相应数字表示把角标数改为指定的数字,最大不超过 9999,参数在 ios 节点下设置,详细可参考“设置 iOS 角标数 HTTP 请求示例”。 + Badge *int `json:"badge,omitempty"` + // iOS 平台通知栏分组 ID,相同的 thread-id 推送分一组,单组超过 5 条推送会折叠展示 + ThreadId *string `json:"thread-id,omitempty"` + // iOS 平台,从 iOS10 开始支持,设置后设备收到有相同 ID 的消息,会合并成一条 + ApnsCollapseId *string `json:"apns-collapse-id,omitempty"` + // iOS 富文本推送的类型开发者自己定义,自己在 App 端进行解析判断,与 RichMediaUri 一起使用,当设置 Category 后,推送时默认携带 mutable-content 进行推送,属性值为 1。 + Category *string `json:"category,omitempty"` + // iOS 富文本推送内容的 URL,与 category 一起使用。 + RichMediaUri *string `json:"richMediaUri,omitempty"` + // 适用于 iOS 15 及之后的系统。取值为 passive,active(默认),time-sensitive,或 critical,取值说明详见对应的 APNs 的 interruption-level 字段。在 iOS 15 及以上版本中,系统的 “定时推送摘要”、“专注模式” 都可能导致重要的推送通知(例如余额变化)无法及时被用户感知的情况,可考虑设置该字段。 + InterruptionLevel *string `json:"interruption-level,omitempty"` + // 附加信息,如果开发者自己需要,可以自己在 App 端进行解析。 + Extras interface{} `json:"extras,omitempty"` +} + +type PushNotificationAndroid struct { + // Android 平台下推送通知内容,传入后默认的推送通知内容失效。 + Alert *string `json:"alert,omitempty"` + Honor *PushAndroidHonor `json:"honor,omitempty"` + HW *PushAndroidHW `json:"hw,omitempty"` + Oppo *PushAndroidOppo `json:"oppo,omitempty"` + Vivo *PushAndroidVivo `json:"vivo,omitempty"` + Fcm *PushAndroidFcm `json:"fcm,omitempty"` + Extras interface{} `json:"extras,omitempty"` +} + +type PushResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Id string `json:"id"` +} + +// Push 发送全量用户不落地通知 +// More details see https://doc.rongcloud.cn/imserver/server/v1/system/send-push-to-all +func (rc *RongCloud) Push(ctx context.Context, req *PushRequest) (*PushResponse, error) { + path := "/push.json" + resp := &PushResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/rcmsg.go b/rongcloud/rcmsg.go new file mode 100644 index 0000000..703699d --- /dev/null +++ b/rongcloud/rcmsg.go @@ -0,0 +1,285 @@ +package rongcloud + +import ( + "encoding/json" +) + +// RCMsg +// 消息类型,接受内置消息类型(见消息类型概述)或自定义消息的消息类型值。 +// 注意:在自定义消息时,消息类型不可以 "RC:" 开头,以免与系统内置消息类型重名;消息类型长度不可超过 32 个字符。SDK 中必须已注册过该自定义消息,否则 SDK 收到该消息后将无法解析。 +// 所发送消息的内容,单条消息最大 128k。 +// 内置消息类型:将消息内容体 JSON 对象序列化为 JSON 字符串传入。消息内容 JSON 结构体详见用户内容类消息格式或其他内置消息类型的消息内容格式。 +// 例如,文本消息内容 JSON 结构体内部包含 content 字段(此为 JSON 结构体内的 key 值,注意区分),则需要将 {"content":"Hello world!"} 序列化后的结果作为此处 content 字段的值。 +// 自定义消息类型(objectName 字段必须指定为自定义消息类型):如果发送自定义消息,该参数可自定义格式,不限于 JSON。 +type RCMsg interface { + ObjectName() string + ToString() (string, error) +} + +// MsgUserInfo 融云内置消息用户信息 +type MsgUserInfo struct { + ID string `json:"id,omitempty"` // 消息中携带的消息发送者的用户信息。一般情况下不建议在消息中携带用户信息。建议仅在直播场景下使用。 + Name string `json:"name,omitempty"` // 消息发送者的用户昵称。 + Icon string `json:"icon,omitempty"` + Portrait string `json:"portrait,omitempty"` // 消息发送者的头象。 + Extra string `json:"extra,omitempty"` // 扩展信息,可以放置任意的数据内容。 +} + +// TXTMsg 消息 +type TXTMsg struct { + Content string `json:"content,omitempty"` // [必传] 文字消息的文字内容,包括表情。 + User *MsgUserInfo `json:"user,omitempty"` // 消息中携带的消息发送者的用户信息。一般情况下不建议在消息中携带用户信息。建议仅在直播场景下使用。 + Extra string `json:"extra,omitempty"` // 扩展信息,可以放置任意的数据内容,也可以去掉此属性。 +} + +func (m *TXTMsg) ObjectName() string { + return "RC:TxtMsg" +} + +func (m *TXTMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// ImgMsg 消息 +type ImgMsg struct { + Content string `json:"content,omitempty"` // [必传] 图片缩略图进行 Base64 编码的结果值。Base64 字符串长度建议为 5k,最大不超过 10k。注意在 Base64 进行 Encode 后需要将所有 \r\n 和 \r 和 \n 替换成空。 + User *MsgUserInfo `json:"user,omitempty"` // 消息中携带的消息发送者的用户信息。一般情况下不建议在消息中携带用户信息。建议仅在直播场景下使用。 + ImageURI string `json:"imageUri,omitempty"` // [必传] 图片上传到图片存储服务器后的地址。通过 IM Server API 发送图片消息时,需要自行上传文件到应用的文件服务器,生成图片地址后进行发送。 + Extra string `json:"extra,omitempty"` +} + +func (m *ImgMsg) ObjectName() string { + return "RC:ImgMsg" +} + +func (m *ImgMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// InfoNtf 提示(小灰条)通知消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-notification +type InfoNtf struct { + Message string `json:"message,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` + Extra string `json:"extra,omitempty"` +} + +func (m *InfoNtf) ObjectName() string { + return "RC:InfoNtf" +} + +func (m *InfoNtf) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// VCMsg 旧版语音消息, 推荐使用高清语音消息 HQVCMsg +// Deprecated +type VCMsg struct { + Content string `json:"content,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` + Extra string `json:"extra,omitempty"` + Duration interface{} `json:"duration,omitempty"` +} + +func (m *VCMsg) ObjectName() string { + return "RC:VCMsg" +} + +func (m *VCMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// HQVCMsg 高清语音消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname#%E9%AB%98%E6%B8%85%E8%AF%AD%E9%9F%B3%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%E7%BB%93%E6%9E%84%E4%BD%93 +type HQVCMsg struct { + RemoteUrl string `json:"remoteUrl,omitempty"` // 必传参数, 媒体内容上传服务器后的网络地址。通过 IM 服务端 API 发送高质量语音消息时,需要自行生成 AAC 格式文件并上传文件到应用的文件服务器,生成地址后进行发送。 + Duration int `json:"duration,omitempty"` // 必传参数, 语音消息的时长,最长为 60 秒(单位:秒)。 + User *MsgUserInfo `json:"user,omitempty"` + Extra string `json:"extra,omitempty"` // 扩展信息,可以放置任意的数据内容,也可以去掉此属性。 +} + +func (m *HQVCMsg) ObjectName() string { + return "RC:HQVCMsg" +} + +func (m *HQVCMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// IMGTextMsg 图文消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname#%E5%9B%BE%E6%96%87%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%E7%BB%93%E6%9E%84%E4%BD%93 +type IMGTextMsg struct { + Title string `json:"title,omitempty"` // 消息的标题。 + Content string `json:"content,omitempty"` // 消息的文字内容。 + User *MsgUserInfo `json:"user,omitempty"` + Extra string `json:"extra,omitempty"` + ImageUri string `json:"imageUri,omitempty"` // 消息中图片地址,图片尺寸为:120 x 120 像素。通过 IM Server API 发送图片消息时,需要自行上传文件到应用的文件服务器,生成图片地址后进行发送。 + URL string `json:"url,omitempty"` // 点击图片消息后跳转的 URL 地址。 +} + +func (m *IMGTextMsg) ObjectName() string { + return "RC:ImgTextMsg" +} + +func (m *IMGTextMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// FileMsg 文件消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname#%E6%96%87%E4%BB%B6%E6%B6%88%E6%81%AF +type FileMsg struct { + Name string `json:"name,omitempty"` // 文件名称。如不传,调用客户端 SDK 中的 downloadMediaMessage 方法下载后会默认生成一个名称。 + Size string `json:"size,omitempty"` // [必传参数] 文件大小,单位:Byte。 + Type string `json:"type,omitempty"` // [必传参数] 文件类型 + FileURL string `json:"fileUrl,omitempty"` // [必传参数] 文件的服务器地址。通过 IM Server API 发送文件消息时,需要自行上传文件到应用的文件服务器,生成文件地址后进行发送。 + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *FileMsg) ObjectName() string { + return "RC:FileMsg" +} + +func (m *FileMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// LBSMsg 位置消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname#%E4%BD%8D%E7%BD%AE%E6%B6%88%E6%81%AF +type LBSMsg struct { + Content string `json:"content,omitempty"` + Extra string `json:"extra,omitempty"` + POI string `json:"poi,omitempty"` + Latitude float64 `json:"latitude,omitempty"` + Longitude float64 `json:"longitude,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *LBSMsg) ObjectName() string { + return "RC:LBSMsg" +} + +func (m *LBSMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// ProfileNtf 资料变更通知消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-notification#%E8%B5%84%E6%96%99%E5%8F%98%E6%9B%B4%E9%80%9A%E7%9F%A5%E6%B6%88%E6%81%AF +type ProfileNtf struct { + Operation string `json:"operation,omitempty"` + Data string `json:"data,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` + Extra string `json:"extra,omitempty"` +} + +func (m *ProfileNtf) ObjectName() string { + return "RC:ProfileNtf" +} + +func (m *ProfileNtf) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// CMDNtf 命令提醒消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-notification#%E5%91%BD%E4%BB%A4%E6%8F%90%E9%86%92%E6%B6%88%E6%81%AF +type CMDNtf struct { + Name string `json:"operation,omitempty"` + Data string `json:"data,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *CMDNtf) ObjectName() string { + return "RC:CMDNtf" +} + +func (m *CMDNtf) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// CMDMsg 命令消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-callback#%E5%91%BD%E4%BB%A4%E6%B6%88%E6%81%AF +type CMDMsg struct { + Name string `json:"name,omitempty"` + Data string `json:"data,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *CMDMsg) ObjectName() string { + return "RC:CMDMsg" +} + +func (m *CMDMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// ContactNtf 联系人(好友)通知消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-notification#%E8%81%94%E7%B3%BB%E4%BA%BA%E5%A5%BD%E5%8F%8B%E9%80%9A%E7%9F%A5%E6%B6%88%E6%81%AF +type ContactNtf struct { + Operation string `json:"operation,omitempty"` // [必传]联系人操作的指令,官方针对 operation 属性定义了 "Request", "AcceptResponse", "RejectResponse" 几个常量,也可以由开发者自行扩展。 + SourceUserID string `json:"sourceUserId,omitempty"` // [必传]发出通知的用户 Id。 + TargetUserID string `json:"targetUserId,omitempty"` // [必传]单聊会话为接收通知的用户 Id,群聊、聊天室会话为会话 Id。 + Message string `json:"message,omitempty"` // [必传]表示请求或者响应消息,如添加理由或拒绝理由。 + Extra string `json:"extra,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *ContactNtf) ObjectName() string { + return "RC:ContactNtf" +} + +func (m *ContactNtf) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// GrpNtf 群组通知消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-notification#%E7%BE%A4%E7%BB%84%E9%80%9A%E7%9F%A5%E6%B6%88%E6%81%AF +type GrpNtf struct { + OperatorUserID string `json:"operatorUserId,omitempty"` // [必传] 操作人用户 Id + Operation string `json:"operation,omitempty"` // [必传] 群组中各种通知的操作名称。 + Data string `json:"data,omitempty"` // [必传] 操作数据 + Message string `json:"message,omitempty"` // [必传] 消息内容 + Extra string `json:"extra,omitempty"` + User *MsgUserInfo `json:"user,omitempty"` +} + +func (m *GrpNtf) ObjectName() string { + return "RC:GrpNtf" +} + +func (m *GrpNtf) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +// ChrmKVNotiMsg 聊天室属性通知消息 +// https://doc.rongcloud.cn/imserver/server/v1/message/objectname-callback#%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%B1%9E%E6%80%A7%E9%80%9A%E7%9F%A5%E6%B6%88%E6%81%AF +type ChrmKVNotiMsg struct { + // [必传] 聊天室中对属性操作后发送通知的类型,1 为设置属性内容、2 为删除属性内容。 + Type int `json:"type,omitempty"` + // [必传] 聊天室中属性名称,大小不超过 128 个字符。 + Key string `json:"key,omitempty"` + // [必传] 属性对应的内容,大小不超过 4096 个字符。 + Value string `json:"value,omitempty"` + // 通过消息中携带的附加信息,对应到设置属性接口中的 notificationExtra 值。 + Extra string `json:"extra,omitempty"` +} + +func (m *ChrmKVNotiMsg) ObjectName() string { + return "RC:ChrmKVNotiMsg" +} + +func (m *ChrmKVNotiMsg) ToString() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} diff --git a/rongcloud/request.go b/rongcloud/request.go new file mode 100644 index 0000000..c9b8d83 --- /dev/null +++ b/rongcloud/request.go @@ -0,0 +1,26 @@ +package rongcloud + +import ( + "fmt" + "net/url" + + "github.com/google/go-querystring/query" +) + +func makeUrlValues(v interface{}) (url.Values, error) { + values, err := query.Values(v) + if err != nil { + return values, NewEncodeRequestError(err) + } + return values, nil +} + +func makeRCMsgUrlValues(rcMsg RCMsg, v url.Values) error { + v.Set("objectName", rcMsg.ObjectName()) + content, err := rcMsg.ToString() + if err != nil { + return NewSDKError(fmt.Sprintf("%s RCMsg.ToString() error %s", rcMsg.ObjectName(), err)) + } + v.Set("content", content) + return nil +} diff --git a/sdk/rongcloud.go b/rongcloud/rongcloud.go similarity index 61% rename from sdk/rongcloud.go rename to rongcloud/rongcloud.go index a90823c..96c99c2 100644 --- a/sdk/rongcloud.go +++ b/rongcloud/rongcloud.go @@ -1,11 +1,4 @@ -/* - * @Descripttion: - * @version: - * @Author: ran.ding - * @Date: 2019-09-02 18:29:55 - * @LastEditors: ran.ding - * @LastEditTime: 2019-09-10 15:39:14 - */ +package rongcloud // The MIT License (MIT) @@ -29,16 +22,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -/* - * 融云 Server API go 客户端 - * create by RongCloud - * create datetime : 2018-11-28 - * v3 - */ - -package sdk +// 融云 Server API go 客户端 v4 import ( + "context" "crypto/sha1" "fmt" "io" @@ -49,7 +36,6 @@ import ( "sync" "time" - "github.com/astaxie/beego/httplib" "github.com/google/uuid" ) @@ -60,14 +46,12 @@ const ( RONGCLOUDURI = "http://api.rong-api.com" // RONGCLOUDURI2 融云备用 API 地址 RONGCLOUDURI2 = "http://api-b.rong-api.com" - // ReqType body类型 - ReqType = "json" // USERAGENT sdk 名称 - USERAGENT = "rc-go-sdk/3.2.23" + USERAGENT = "rc-go-sdk/4.0.0" // DEFAULTTIMEOUT 默认超时时间,10秒 - DEFAULTTIMEOUT = 10 + DEFAULTTIMEOUT = 10 * time.Second // DEFAULT_KEEPALIVE http 默认保活时间,30秒 - DEFAULT_KEEPALIVE = 30 + DEFAULT_KEEPALIVE = 30 * time.Second // DEFAULT_MAXIDLECONNSPERHOST http 默认每个域名连接数,100 DEFAULT_MAXIDLECONNSPERHOST = 100 // 自动切换 api 地址时间间隔,秒 @@ -83,10 +67,9 @@ var ( maxIdleConnsPerHost: DEFAULT_MAXIDLECONNSPERHOST, count: 0, changeUriDuration: DEFAULT_CHANGE_URI_DURATION, - lastChageUriTime: 0, + lastChangeUriTime: 0, } - rc *RongCloud - once sync.Once + rc *RongCloud ) // RongCloud appKey appSecret extra @@ -96,6 +79,7 @@ type RongCloud struct { *rongCloudExtra uriLock sync.Mutex globalTransport http.RoundTripper + httpClient *http.Client } // rongCloudExtra rongCloud扩展增加自定义融云服务器地址,请求超时时间 @@ -107,13 +91,13 @@ type rongCloudExtra struct { maxIdleConnsPerHost int count uint changeUriDuration int64 - lastChageUriTime int64 + lastChangeUriTime int64 } // getSignature 本地生成签名 // Signature (数据签名)计算方法:将系统分配的 App Secret、Nonce (随机数)、 // Timestamp (时间戳)三个字符串按先后顺序拼接成一个字符串并进行 SHA1 哈希计算。如果调用的数据签名验证失败,接口调用会返回 HTTP 状态码 401。 -func (rc RongCloud) getSignature() (nonce, timestamp, signature string) { +func (rc *RongCloud) getSignature() (nonce, timestamp, signature string) { nonceInt := rand.Int() nonce = strconv.Itoa(nonceInt) timeInt64 := time.Now().Unix() @@ -125,86 +109,71 @@ func (rc RongCloud) getSignature() (nonce, timestamp, signature string) { } // fillHeader 在 Http Header 增加API签名 -func (rc RongCloud) fillHeader(req *httplib.BeegoHTTPRequest) { - nonce, timestamp, signature := rc.getSignature() - req.Header("App-Key", rc.appKey) - req.Header("Nonce", nonce) - req.Header("Timestamp", timestamp) - req.Header("Signature", signature) - req.Header("Content-Type", "application/x-www-form-urlencoded") - req.Header("User-Agent", USERAGENT) -} - -// v2 sdk header -func (rc RongCloud) fillHeaderV2(req *httplib.BeegoHTTPRequest) string { - requestId := uuid.New().String() +func (rc *RongCloud) fillHeader(ctx context.Context, req *http.Request) { nonce, timestamp, signature := rc.getSignature() - req.Header("RC-App-Key", rc.appKey) - req.Header("RC-Timestamp", timestamp) - req.Header("RC-Nonce", nonce) - req.Header("RC-Signature", signature) - req.Header("Content-Type", "application/json") - req.Header("User-Agent", USERAGENT) - req.Header("RC-Request-Id", requestId) - return requestId -} - -// fillJSONHeader 在 Http Header Content-Type 设置为josn格式 -func fillJSONHeader(req *httplib.BeegoHTTPRequest) { - req.Header("Content-Type", "application/json") + req.Header.Set("RC-App-Key", rc.appKey) + req.Header.Set("RC-Timestamp", timestamp) + req.Header.Set("RC-Nonce", nonce) + req.Header.Set("RC-Signature", signature) + req.Header.Set("User-Agent", USERAGENT) + if customRequestId, ok := ctx.Value(ContextRequestIdKey).(string); ok { + req.Header.Set(RCRequestIdHeader, customRequestId) + } else { + requestId := uuid.New().String() + req.Header.Set(RCRequestIdHeader, requestId) + } } // NewRongCloud 创建 RongCloud 对象 func NewRongCloud(appKey, appSecret string, options ...rongCloudOption) *RongCloud { - once.Do(func() { - // 默认扩展配置 - defaultRongCloud := defaultExtra - defaultRongCloud.lastChageUriTime = 0 - rc = &RongCloud{ - appKey: appKey, - appSecret: appSecret, - rongCloudExtra: &defaultRongCloud, - } + // 默认扩展配置 + defaultRongCloud := defaultExtra + defaultRongCloud.lastChangeUriTime = 0 + rc = &RongCloud{ + appKey: appKey, + appSecret: appSecret, + rongCloudExtra: &defaultRongCloud, + } - for _, option := range options { - option(rc) - } + for _, option := range options { + option(rc) + } - if rc.globalTransport == nil { - rc.globalTransport = &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: rc.timeout * time.Second, - KeepAlive: rc.keepAlive * time.Second, - }).DialContext, - MaxIdleConnsPerHost: rc.maxIdleConnsPerHost, - } + if rc.httpClient == nil { + rc.httpClient = http.DefaultClient + } + if rc.globalTransport != nil { + rc.httpClient.Transport = rc.globalTransport + } else { + rc.httpClient.Transport = &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: rc.timeout, + KeepAlive: rc.keepAlive, + }).DialContext, + MaxIdleConnsPerHost: rc.maxIdleConnsPerHost, } - }) - - return rc -} - -// GetRongCloud 获取 RongCloud 对象 -func GetRongCloud() *RongCloud { + } return rc } -// 自定义 http 参数 +// SetHttpTransport 自定义 http client 传输层参数 func (rc *RongCloud) SetHttpTransport(httpTransport http.RoundTripper) { rc.globalTransport = httpTransport + rc.httpClient.Transport = rc.globalTransport } +// GetHttpTransport 获取http Client 传输层参数 func (rc *RongCloud) GetHttpTransport() http.RoundTripper { return rc.globalTransport } // changeURI 自动切换 Api 服务器地址 // 在 api、api2之间自动切换。无法切换其他域名。其他请使用 PrivateURI 设置 -func (rc *RongCloud) ChangeURI() { +func (rc *RongCloud) changeURI() { nowUnix := time.Now().Unix() // 检查距离上次更换uri的时间间隔 rc.uriLock.Lock() - if (nowUnix - rc.lastChageUriTime) >= rc.changeUriDuration { + if (nowUnix - rc.lastChangeUriTime) >= rc.changeUriDuration { switch rc.rongCloudURI { case RONGCLOUDURI: rc.rongCloudURI = RONGCLOUDURI2 @@ -212,7 +181,7 @@ func (rc *RongCloud) ChangeURI() { rc.rongCloudURI = RONGCLOUDURI default: } - rc.lastChageUriTime = nowUnix + rc.lastChangeUriTime = nowUnix } rc.uriLock.Unlock() } @@ -222,20 +191,3 @@ func (rc *RongCloud) PrivateURI(uri, sms string) { rc.rongCloudURI = uri rc.rongCloudSMSURI = sms } - -// urlError 判断是否为 url.Error -func (rc *RongCloud) urlError(err error) { - // 方法已废弃 -} - -/* -* -判断 http status code, 如果大于 500 就切换一次域名 -*/ -func (rc *RongCloud) checkStatusCode(resp *http.Response) { - if resp.StatusCode >= 500 && resp.StatusCode < 600 { - rc.ChangeURI() - } - - return -} diff --git a/rongcloud/rongcloud_test.go b/rongcloud/rongcloud_test.go new file mode 100644 index 0000000..b468859 --- /dev/null +++ b/rongcloud/rongcloud_test.go @@ -0,0 +1,67 @@ +package rongcloud + +import ( + "context" + "log" + "net" + "net/http" + "os" + "testing" + "time" +) + +func TestNewRongCloud(t *testing.T) { + rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) + dialer := &net.Dialer{ + Timeout: 123 * time.Second, + KeepAlive: 123 * time.Second, + } + globalTransport := &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + log.Printf("custom dialer works, timeout %s keepalive %s", dialer.Timeout, dialer.KeepAlive) + return dialer.DialContext(ctx, network, addr) + }, + MaxIdleConnsPerHost: 123, + } + ctx := context.Background() + _, err := rc.UserCheckOnline(ctx, &UserCheckOnlineRequest{UserId: StringPtr("u01")}) + if err != nil { + log.Fatalf("usercheck online error %s", err) + } + + oldTransport, ok := rc.httpClient.Transport.(*http.Transport) + if !ok { + log.Fatalf("RoundTrip convert to Transport failed") + } + rc.SetHttpTransport(globalTransport) + newTransport, ok := rc.GetHttpTransport().(*http.Transport) + if !ok { + log.Fatalf("RoundTrip convert to Transport failed") + } + log.Printf("oldTransport MaxIdleConnsPerHost %d, newTransport MaxIdleConnsPerHost %d", oldTransport.MaxIdleConnsPerHost, newTransport.MaxIdleConnsPerHost) + _, err = rc.UserCheckOnline(ctx, &UserCheckOnlineRequest{ + UserId: StringPtr("u01"), + }) + if err != nil { + log.Fatalf("user check online 2 error %s", err) + } +} + +func TestNewRongCloudInit(t *testing.T) { + dialer := &net.Dialer{ + Timeout: 123 * time.Second, + KeepAlive: 123 * time.Second, + } + globalTransport := &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + log.Printf("custom dialer works, timeout %s keepalive %s", dialer.Timeout, dialer.KeepAlive) + return dialer.DialContext(ctx, network, addr) + }, + } + rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET"), WithTransport(globalTransport), WithTimeout(1*time.Hour), WithKeepAlive(1*time.Hour)) // transport优先级高于其他http参数 + ctx := context.Background() + _, err := rc.UserCheckOnline(ctx, &UserCheckOnlineRequest{UserId: StringPtr("u01")}) + if err != nil { + log.Fatalf("usercheck online error %s", err) + } +} diff --git a/rongcloud/sensitive.go b/rongcloud/sensitive.go new file mode 100644 index 0000000..bd6c367 --- /dev/null +++ b/rongcloud/sensitive.go @@ -0,0 +1,72 @@ +package rongcloud + +import "context" + +type SensitiveWordAddRequest struct { + // [必传] 敏感词,最长不超过 32 个字符,格式为汉字、数字、字母。 + Word *string `url:"word,omitempty"` + // 替换后的词,最长不超过 32 个字符。如未设置,当消息中含有敏感词时,消息将被屏蔽,用户不会收到消息。如设置了,当消息中含有敏感词时,将被替换为指定的词进行发送。 + ReplaceWord *string `url:"replaceWord,omitempty"` +} + +type SensitiveWordAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// SensitiveWordAdd 添加消息敏感词 +// More details see https://doc.rongcloud.cn/imserver/server/v1/moderation/add-sensitive-word +func (rc *RongCloud) SensitiveWordAdd(ctx context.Context, req *SensitiveWordAddRequest) (*SensitiveWordAddResponse, error) { + path := "/sensitiveword/add.json" + resp := &SensitiveWordAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type SensitiveWordListRequest struct { + // 查询敏感词的类型。0 为查询替换敏感词。1 为查询屏蔽敏感词。2 为查询全部敏感词。默认为 1。 + Type *string `url:"type,omitempty"` +} + +type SensitiveWordListResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Words []*SensitiveWord `json:"words"` +} + +type SensitiveWord struct { + Word string `json:"word"` // 敏感词内容。 + ReplaceWord string `json:"replaceWord"` // 替换敏感词的内容,为空时对应 Word 敏感词类型为屏蔽敏感词。 + Type string `json:"type"` // 0 为替换敏感词。1 为屏蔽敏感词。 +} + +// SensitiveWordList 查询消息敏感词 +// More details see https://doc.rongcloud.cn/imserver/server/v1/moderation/query-sensitive-word +func (rc *RongCloud) SensitiveWordList(ctx context.Context, req *SensitiveWordListRequest) (*SensitiveWordListResponse, error) { + path := "/sensitiveword/list.json" + resp := &SensitiveWordListResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type SensitiveWordBatchDeleteRequest struct { + // [必传] 敏感词数组,一次最多移除 50 个敏感词。 + Words []string `url:"words,omitempty"` +} + +type SensitiveWordBatchDeleteResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// SensitiveWordBatchDelete 批量移除消息敏感词 +// More details see https://doc.rongcloud.cn/imserver/server/v1/moderation/batch-remove-sensitive-word +func (rc *RongCloud) SensitiveWordBatchDelete(ctx context.Context, req *SensitiveWordBatchDeleteRequest) (*SensitiveWordBatchDeleteResponse, error) { + path := "/sensitiveword/batch/delete.json" + resp := &SensitiveWordBatchDeleteResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/ultragroup.go b/rongcloud/ultragroup.go new file mode 100644 index 0000000..cd8e82a --- /dev/null +++ b/rongcloud/ultragroup.go @@ -0,0 +1,1251 @@ +package rongcloud + +import ( + "context" + "encoding/json" + "fmt" +) + +type UltraGroupMsgGetRequest struct { + GroupId *string `json:"groupId,omitempty" url:"groupId,omitempty"` // [必传] 超级群 ID + Msgs []*UltraGroupMsg `json:"msgs,omitempty" url:"-"` // [必传] 消息的查询参数,单次请求最多获取 20 条消息。 +} + +type UltraGroupMsg struct { + MsgUID string `json:"msgUID,omitempty"` // [必传] 全局唯一 ID,即消息 UID。 + BusChannel string `json:"busChannel,omitempty"` // 消息所在的超级群频道 ID。 +} + +type UltraGroupMsgGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []*UltraGroupMsgData `json:"data"` // 消息数组。 +} + +type UltraGroupMsgData struct { + FromUserId string `json:"fromUserId"` // 发送人用户 ID。 + GroupId string `json:"groupId"` // 超级群 ID。 + SentTime int64 `json:"sentTime"` // 消息发送时间。Unix 时间戳,单位为毫秒。 + BusChannel string `json:"busChannel"` // 频道 ID。 + MsgUID string `json:"msgUID"` // 全局唯一消息 ID,即消息 UID。 + ObjectName string `json:"objectName"` // 消息类型的唯一标识。 + Content string `json:"content"` // 消息的内容。 + Expansion bool `json:"expansion"` // 是否为扩展消息。 + ExtraContent string `json:"extraContent"` // 消息扩展的内容,JSON 结构的 Key、Value 对,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。 +} + +// UltraGroupMsgGet 获取指定超级群消息内容 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/get-messages-by-uid +func (rc *RongCloud) UltraGroupMsgGet(ctx context.Context, req *UltraGroupMsgGetRequest) (*UltraGroupMsgGetResponse, error) { + path := "/ultragroup/msg/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.Msgs != nil { + msgs, err := json.Marshal(req.Msgs) + if err != nil { + return nil, NewSDKError(fmt.Sprintf("marshal msgs error %s", err)) + } + params.Set("msgs", string(msgs)) + } + resp := &UltraGroupMsgGetResponse{} + httpRes, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpRes) + return resp, err +} + +type UltraGroupCreateRequest struct { + UserId *string `url:"userId,omitempty"` // [必传] 需要加入的用户 ID,创建后同时加入超级群。仅支持传入一个用户 ID。 + GroupId *string `url:"groupId,omitempty"` // [必传] 超级群 ID,最大长度 64 个字符。支持大小写英文字母与数字的组合。 + GroupName *string `url:"groupName,omitempty"` // [必传] 超级群 ID 对应的名称,用于在发送群组消息显示远程 Push 通知时使用,如超级群名称改变需要调用刷新超级群信息接口同步。 +} + +type UltraGroupCreateResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupCreate 创建超级群 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/create-ultragroup +func (rc *RongCloud) UltraGroupCreate(ctx context.Context, req *UltraGroupCreateRequest) (*UltraGroupCreateResponse, error) { + path := "/ultragroup/create.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupCreateResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupDisRequest struct { + // [必传] 要解散的超级群 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type UltraGroupDisResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupDis 解散超级群 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/dismiss-ultragroup +func (rc *RongCloud) UltraGroupDis(ctx context.Context, req *UltraGroupDisRequest) (*UltraGroupDisResponse, error) { + path := "/ultragroup/dis.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupDisResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupRefreshRequest struct { + // [必传] 群组 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 群组名称。 + GroupName *string `url:"groupName,omitempty"` +} + +type UltraGroupRefreshResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupRefresh 刷新超级群信息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/refresh-ultragroup-info +func (rc *RongCloud) UltraGroupRefresh(ctx context.Context, req *UltraGroupRefreshRequest) (*UltraGroupRefreshResponse, error) { + path := "/ultragroup/refresh.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupRefreshResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelGetRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 当前页数,默认为 1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认为 20 条,最大不超过 100 条。 + Limit *int `url:"limit,omitempty"` +} + +type UltraGroupChannelGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + ChannelList []*UltraGroupChannel `json:"channelList"` // 频道列表 +} + +type UltraGroupChannel struct { + ChannelId string `json:"channelId"` // 频道 ID + CreateTime string `json:"createTime"` // 频道创建时间 + Type int `json:"type"` // 频道类型。0 表示公有频道。1 表示私有频道。 +} + +// UltraGroupChannelGet 查询频道列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/get-channel-list +func (rc *RongCloud) UltraGroupChannelGet(ctx context.Context, req *UltraGroupChannelGetRequest) (*UltraGroupChannelGetResponse, error) { + path := "/ultragroup/channel/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupHisMsgMsgIdQueryRequest struct { + // [必传] 超级群 ID,请确保该超级群 ID 已存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 消息的 UID。返回结果中会包含该 msgUID 的消息。例如,该接口默认查询该消息前面 10 条和后面 10 条消息,默认情况下返回 21 条消息。 + MsgUID *string `url:"msgUID,omitempty"` + // 需要查询的上文消息数量。例如传入 20,即表示需要获取 msgUID 前的 20 消息数量。取值范围:0-50,默认 10。0 表示不需要获取 msgUID 前的消息。 + PrevNum *int `url:"prevNum,omitempty"` + // 需要查询的下文消息数量。例如传入 20,即表示需要获取 msgUID 前的 20 消息数量。取值范围:0-50,默认 10。0 表示不需要获取 msgUID 后的消息。 + LastNum *int `url:"lastNum,omitempty"` +} + +type UltraGroupHisMsgMsgIdQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []*UltraGroupHisMsg `json:"data"` // 查询结果。按消息时间戳升序排列。 +} + +type UltraGroupHisMsg struct { + GroupId string `json:"groupId"` // 超级群 ID。 + BusChannel string `json:"busChannel"` // 超级群频道 ID。 + FromUserId string `json:"fromUserId"` // 消息发送方用户 ID。 + MsgUID string `json:"msgUID"` // 消息 UID。 + MsgTime int64 `json:"msgTime"` // 发送消息的时间戳。Unix 时间戳(毫秒)。 + ObjectName string `json:"objectName"` // 消息类型。详见消息类型概述。 + ConversationType int `json:"conversationType"` // 会话类型。超级群的会话类型为 10。 + Content string `json:"content"` // 消息内容,JSON 格式。具体结构可通过 objectName 字段在 消息类型概述 中查询。 + Expansion bool `json:"expansion"` // 消息是否已被设置为可扩展消息。true 表示可扩展。false 表示不可扩展。 + ExtraContent map[string]string `json:"extraContent"` // 消息扩展的内容,JSON 结构的 Key、Value 对,如:{"type":"3"}。Key 最大 32 个字符,支持大小写英文字母、数字、 特殊字符+ = - _ 的组合方式,不支持汉字。Value 最大 4096 个字符。 +} + +// UltraGroupHismsgMsgIdQuery 搜索超级群消息上下文 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-history-by-message-uid +func (rc *RongCloud) UltraGroupHismsgMsgIdQuery(ctx context.Context, req *UltraGroupHisMsgMsgIdQueryRequest) (*UltraGroupHisMsgMsgIdQueryResponse, error) { + path := "/ultragroup/hismsg/msgid/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupHisMsgMsgIdQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupHismsgQueryRequest struct { + // [必传] 超级群 ID,请确保该超级群 ID 已存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 查询开始时间。Unix 时间戳(毫秒)。 + StartTime *int64 `url:"startTime,omitempty"` + // [必传] 查询结束时间。Unix 时间戳(毫秒)。需要保证比 startTime 大,且两者之间时间跨度最大14 天。 + EndTime *int64 `url:"endTime,omitempty"` + // 发送者用户 ID。不传该字段,查所有用户发送的历史消息。如果传入该参数,表示只查该用户 ID 发的历史消息。 + FromUserId *string `url:"fromUserId,omitempty"` + // 分页返回的页面大小。默认 20 条,最大 100 条。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupHismsgQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []*UltraGroupMsgData `json:"data"` // 查询结果。按消息时间戳升序排列。 +} + +// UltraGroupHismsgQuery 搜索超级群消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-history-messages +func (rc *RongCloud) UltraGroupHismsgQuery(ctx context.Context, req *UltraGroupHismsgQueryRequest) (*UltraGroupHismsgQueryResponse, error) { + path := "/ultragroup/hismsg/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupHismsgQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelCreateRequest struct { + // [必传] 超级群 ID,请确保该超级群 ID 已存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID,支持大小写字母、数字的组合方式,长度不超过 20 个字符。 + BusChannel *string `url:"busChannel,omitempty"` + // 频道类型。0 表示公有频道(默认)。1 表示私有频道。 + Type *int `url:"type,omitempty"` +} + +type UltraGroupChannelCreateResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelCreate 创建频道 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/create-channel +func (rc *RongCloud) UltraGroupChannelCreate(ctx context.Context, req *UltraGroupChannelCreateRequest) (*UltraGroupChannelCreateResponse, error) { + path := "/ultragroup/channel/create.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelCreateResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelDelRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID,支持大小写字母、数字的组合方式,长度不超过 20 个字符。 + BusChannel *string `url:"busChannel,omitempty"` +} + +type UltraGroupChannelDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelDel 删除频道 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/delete-channel +func (rc *RongCloud) UltraGroupChannelDel(ctx context.Context, req *UltraGroupChannelDelRequest) (*UltraGroupChannelDelResponse, error) { + path := "/ultragroup/channel/del.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelDelResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelTypeChangeRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 频道类型,0:公有频道,1:私有频道 + Type *int `url:"type,omitempty"` +} + +type UltraGroupChannelTypeChangeResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelTypeChange 变更频道类型 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/change-channel-type +func (rc *RongCloud) UltraGroupChannelTypeChange(ctx context.Context, req *UltraGroupChannelTypeChangeRequest) (*UltraGroupChannelTypeChangeResponse, error) { + path := "/ultragroup/channel/type/change.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelTypeChangeResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelPrivateUsersGetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // 查询页码,默认值 1 + Page *int `url:"page,omitempty"` + // 查询每页条数,可选值 1-100。默认 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupChannelPrivateUsersGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []string `json:"users"` // 用户 ID 列表 +} + +// UltraGroupChannelPrivateUsersGet 查询私有频道成员列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/get-private-channel-users +func (rc *RongCloud) UltraGroupChannelPrivateUsersGet(ctx context.Context, req *UltraGroupChannelPrivateUsersGetRequest) (*UltraGroupChannelPrivateUsersGetResponse, error) { + path := "/ultragroup/channel/private/users/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelPrivateUsersGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserChannelQueryRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户ID。 + UserId *string `url:"userId,omitempty"` + // 查询页码,默认 1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认 10,最多为 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupUserChannelQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []string `json:"data"` // 超级群频道 ID 列表。 +} + +// UltraGroupUserChannelQuery 查询用户所属的私有频道 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-channel-by-user +func (rc *RongCloud) UltraGroupUserChannelQuery(ctx context.Context, req *UltraGroupUserChannelQueryRequest) (*UltraGroupUserChannelQueryResponse, error) { + path := "/ultragroup/user/channel/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserChannelQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelPrivateUsersAddRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 群内的用户 ID。单次不超过 20 个。多个用户间用英文 ',' 分割 + UserIds *string `url:"userIds"` +} + +type UltraGroupChannelPrivateUsersAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelPrivateUsersAdd 添加私有频道成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/add-to-private-channel-users +func (rc *RongCloud) UltraGroupChannelPrivateUsersAdd(ctx context.Context, req *UltraGroupChannelPrivateUsersAddRequest) (*UltraGroupChannelPrivateUsersAddResponse, error) { + path := "/ultragroup/channel/private/users/add.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelPrivateUsersAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelPrivateUsersDelRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 群内的用户 ID。单次不超过 20 个。多个用户间用英文 ',' 分割 + UserIds *string `url:"userIds"` +} + +type UltraGroupChannelPrivateUsersDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelPrivateUsersDel 删除私有频道成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/delete-from-private-channel-users +func (rc *RongCloud) UltraGroupChannelPrivateUsersDel(ctx context.Context, req *UltraGroupChannelPrivateUsersDelRequest) (*UltraGroupChannelPrivateUsersDelResponse, error) { + path := "/ultragroup/channel/private/users/del.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelPrivateUsersDelResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupJoinRequest struct { + // [必传] 要加入群的用户 ID。单次仅支持 1 个用户。 + UserId *string `url:"userId,omitempty"` + // [必传] 要加入的群 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type UltraGroupJoinResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupJoin 加入超级群 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/join-ultragroup +func (rc *RongCloud) UltraGroupJoin(ctx context.Context, req *UltraGroupJoinRequest) (*UltraGroupJoinResponse, error) { + path := "/ultragroup/join.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupJoinResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupQuitRequest struct { + // [必传] 要退出群的用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 要退出的群 ID。 + GroupId *string `url:"groupId,omitempty"` +} + +type UltraGroupQuitResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupQuit 退出超级群 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/quit-ultragroup +func (rc *RongCloud) UltraGroupQuit(ctx context.Context, req *UltraGroupQuitRequest) (*UltraGroupQuitResponse, error) { + path := "/ultragroup/quit.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupQuitResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupMessageExpansionSetRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见全量消息路由。 + MsgUID *string `url:"msgUID,omitempty"` + // [必传] 操作者用户 ID,即需要为指定消息(msgUID)删除扩展信息的用户 ID。 + UserId *string `url:"userId,omitempty"` + // 超级群频道 ID。具体使用要求如下: + // 如果发送消息时指定了频道 ID,则必传频道 ID,否则无法成功设置扩展。 + // 如果发送消息时未指定频道 ID,则不可传入频道 ID,否则无法成功设置扩展。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 需要删除的扩展信息的 Key 值,一次最多可以删除 100 个扩展信息 + ExtraKeyVal *string `url:"extraKeyVal,omitempty"` +} + +type UltraGroupMessageExpansionSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupMessageExpansionSet 设置超级群消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/set-expansion +func (rc *RongCloud) UltraGroupMessageExpansionSet(ctx context.Context, req *UltraGroupMessageExpansionSetRequest) (*UltraGroupMessageExpansionSetResponse, error) { + path := "/ultragroup/message/expansion/set.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupMessageExpansionSetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupMessageExpansionDeleteRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见全量消息路由。 + MsgUID *string `url:"msgUID,omitempty"` + // [必传] 操作者用户 ID,即需要为指定消息(msgUID)删除扩展信息的用户 ID。 + UserId *string `url:"userId,omitempty"` + // 超级群频道 ID。具体使用要求如下: + // 如果发送消息时指定了频道 ID,则必传频道 ID,否则无法成功设置扩展。 + // 如果发送消息时未指定频道 ID,则不可传入频道 ID,否则无法成功设置扩展。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 需要删除的扩展信息的 Key 值,一次最多可以删除 100 个扩展信息 + ExtraKey *string `url:"extraKey,omitempty"` +} + +type UltraGroupMessageExpansionDeleteResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupMessageExpansionDelete 删除超级群消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/delete-expansion +func (rc *RongCloud) UltraGroupMessageExpansionDelete(ctx context.Context, req *UltraGroupMessageExpansionDeleteRequest) (*UltraGroupMessageExpansionDeleteResponse, error) { + path := "/ultragroup/message/expansion/delete.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupMessageExpansionDeleteResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupMessageExpansionQueryRequest struct { + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。详见全量消息路由。 + MsgUID *string `url:"msgUID,omitempty"` + // 超级群频道 ID。具体使用要求如下: + // 如果发送消息时指定了频道 ID,则必传频道 ID,否则无法成功获取扩展。 + // 如果发送消息时未指定频道 ID,则不可传入频道 ID,否则无法成功获取扩展 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 页数,默认返回 300 个扩展信息。 + PageNo *int `url:"pageNo,omitempty"` +} + +type UltraGroupMessageExpansionQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + ExtraContent map[string]*MessageExpansionQueryExtraContentValue `json:"extraContent"` +} + +// UltraGroupMessageExpansionQuery 获取超级群消息扩展 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/get-expansion +func (rc *RongCloud) UltraGroupMessageExpansionQuery(ctx context.Context, req *UltraGroupMessageExpansionQueryRequest) (*UltraGroupMessageExpansionQueryResponse, error) { + path := "/ultragroup/message/expansion/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupMessageExpansionQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupMemberExistRequest struct { + // [必传] 要查询的用户 ID + UserId *string `url:"userId,omitempty"` + // [必传] 要查询的超级群 ID + GroupId *string `url:"groupId,omitempty"` +} + +type UltraGroupMemberExistResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Status bool `json:"status"` // 用户是否在超级群中。true 表示在超级群中,false 表示不在超级群中。 +} + +// UltraGroupMemberExist 查询用户是否为群成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-member +func (rc *RongCloud) UltraGroupMemberExist(ctx context.Context, req *UltraGroupMemberExistRequest) (*UltraGroupMemberExistResponse, error) { + path := "/ultragroup/member/exist.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupMemberExistResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupNotDisturbSetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // 频道 ID,不传时为群的默认免打扰设置 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] -1:全部消息通知 + // 0:未设置(用户未设置时为此状态,为全部消息都通知,在此状态下,如设置了超级群默认状态以超级群的默认设置为准) + // 1:仅针对 @ 消息进行通知,包括 @指定用户 和 @所有人 + // 2:仅针对 @ 指定用户消息进行通知,且仅通知被 @ 的指定的用户进行通知。 + // 如:@张三 则张三可以收到推送,@所有人 时不会收到推送。 + // 4:仅针对 @群全员进行通知,只接收 @所有人 的推送信息 + // 5:不接收通知,即使为 @ 消息也不推送通知。 + UnpushLevel *int `url:"unpushLevel,omitempty"` +} + +type UltraGroupNotDisturbSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupNotDisturbSet 设置群/频道默认免打扰 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/set-do-not-disturb +func (rc *RongCloud) UltraGroupNotDisturbSet(ctx context.Context, req *UltraGroupNotDisturbSetRequest) (*UltraGroupNotDisturbSetResponse, error) { + path := "/ultragroup/notdisturb/set.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupNotDisturbSetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupNotDisturbGetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // 频道 ID,不传时为群的默认免打扰设置 + BusChannel *string `url:"busChannel,omitempty"` +} + +type UltraGroupNotDisturbGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // 超级群 ID + GroupId string `json:"groupId"` + // 频道 ID,不传时为群的默认免打扰设置 + BusChannel string `json:"busChannel"` + // -1:全部消息通知 + // 0:未设置(用户未设置时为此状态,为全部消息都通知,在此状态下,如设置了超级群默认状态以超级群的默认设置为准) + // 1:仅针对 @ 消息进行通知,包括 @指定用户 和 @所有人 + // 2:仅针对 @ 指定用户消息进行通知,且仅通知被 @ 的指定的用户进行通知。 + // 如:@张三 则张三可以收到推送,@所有人 时不会收到推送。 + // 4:仅针对 @群全员进行通知,只接收 @所有人 的推送信息 + // 5:不接收通知,即使为 @ 消息也不推送通知。 + UnpushLevel int `json:"unpushLevel"` +} + +// UltraGroupNotDisturbGet 查询默认免打扰配置 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/get-do-not-disturb +func (rc *RongCloud) UltraGroupNotDisturbGet(ctx context.Context, req *UltraGroupNotDisturbGetRequest) (*UltraGroupNotDisturbGetResponse, error) { + path := "/ultragroup/notdisturb/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupNotDisturbGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserBannedAddRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户 ID 列表,每次最多不超过 20 个用户,以逗号分隔。 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupUserBannedAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserBannedAdd 禁言指定超级群成员 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/ban-user +func (rc *RongCloud) UltraGroupUserBannedAdd(ctx context.Context, req *UltraGroupUserBannedAddRequest) (*UltraGroupUserBannedAddResponse, error) { + path := "/ultragroup/userbanned/add.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserBannedAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserBannedGetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // 当前页码,默认获取第一页。 + Page *int `url:"page,omitempty"` + // 每页条数,默认每页 50 条。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupUserBannedGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []*UltraGroupUserBannedGetUser `json:"users"` +} + +type UltraGroupUserBannedGetUser struct { + Id string `json:"id"` +} + +// UltraGroupUserBannedGet 查询超级群成员禁言列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-banned-user-list +func (rc *RongCloud) UltraGroupUserBannedGet(ctx context.Context, req *UltraGroupUserBannedGetRequest) (*UltraGroupUserBannedGetResponse, error) { + path := "/ultragroup/userbanned/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserBannedGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserBannedDelRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户 ID 列表,每次最多不超过 20 个用户,以逗号分隔。 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupUserBannedDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserBannedDel 取消指定超级群成员禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/unban-user +func (rc *RongCloud) UltraGroupUserBannedDel(ctx context.Context, req *UltraGroupUserBannedDelRequest) (*UltraGroupUserBannedDelResponse, error) { + path := "/ultragroup/userbanned/del.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserBannedDelResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupGlobalBannedSetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] true 为禁言,false 为取消禁言 + Status *bool `url:"status,omitempty"` +} + +type UltraGroupGlobalBannedSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupGlobalBannedSet 设置超级群全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/set-ultragroup-global-ban +func (rc *RongCloud) UltraGroupGlobalBannedSet(ctx context.Context, req *UltraGroupGlobalBannedSetRequest) (*UltraGroupGlobalBannedSetResponse, error) { + path := "/ultragroup/globalbanned/set.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupGlobalBannedSetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupGlobalBannedGetRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // 频道 ID。 + BusChannel *string `url:"busChannel,omitempty"` +} + +type UltraGroupGlobalBannedGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Status bool `json:"status"` // true 为禁言,false 未禁言 +} + +// UltraGroupGlobalBannedGet 查询超级群全体禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-ultragroup-global-ban +func (rc *RongCloud) UltraGroupGlobalBannedGet(ctx context.Context, req *UltraGroupGlobalBannedGetRequest) (*UltraGroupGlobalBannedGetResponse, error) { + path := "/ultragroup/globalbanned/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupGlobalBannedGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupBannedWhitelistAddRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 频道 ID 字段。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户 ID 列表,最多不超过 20 个。以逗号分割 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupBannedWhitelistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupBannedWhitelistAdd 加入超级群全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/add-to-global-ban-whitelist +func (rc *RongCloud) UltraGroupBannedWhitelistAdd(ctx context.Context, req *UltraGroupBannedWhitelistAddRequest) (*UltraGroupBannedWhitelistAddResponse, error) { + path := "/ultragroup/banned/whitelist/add.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupBannedWhitelistAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupBannedWhitelistDelRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 频道 ID 字段。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户 ID 列表,最多不超过 20 个。以逗号分割 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupBannedWhitelistDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupBannedWhitelistDel 移出超级群全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/remove-from-global-ban-whitelist +func (rc *RongCloud) UltraGroupBannedWhitelistDel(ctx context.Context, req *UltraGroupBannedWhitelistDelRequest) (*UltraGroupBannedWhitelistDelResponse, error) { + path := "/ultragroup/banned/whitelist/del.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupBannedWhitelistDelResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupBannedWhitelistGetRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 频道 ID 字段。 + BusChannel *string `url:"busChannel,omitempty"` + // 当前页码,默认1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认50。 上限 200 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupBannedWhitelistGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []*UltraGroupBannedWhitelistUser `json:"users"` // 用户列表 +} + +type UltraGroupBannedWhitelistUser struct { + Id string `json:"id"` // 用户 ID +} + +// UltraGroupBannedWhitelistGet 查询超级群全体禁言白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-global-ban-whitelist +func (rc *RongCloud) UltraGroupBannedWhitelistGet(ctx context.Context, req *UltraGroupBannedWhitelistGetRequest) (*UltraGroupBannedWhitelistGetResponse, error) { + path := "/ultragroup/banned/whitelist/get.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupBannedWhitelistGetResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupAddRequest struct { + // [必传] 超级群 ID,请确保超级群 ID 存在。 + GroupId *string `json:"groupId,omitempty"` + // [必传] 用户组信息列表,最大长度为 10。 + UserGroups []*UltraGroupUserGroup `json:"userGroups,omitempty"` +} + +type UltraGroupUserGroup struct { + // [必传] 用户组 ID,支持大小写字母、数字的组合方式,长度不超过 64 个字符。 + UserGroupId string `json:"userGroupId"` +} + +type UltraGroupUserGroupAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserGroupAdd 超级群创建用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/create-usergroup +func (rc *RongCloud) UltraGroupUserGroupAdd(ctx context.Context, req *UltraGroupUserGroupAddRequest) (*UltraGroupUserGroupAddResponse, error) { + path := "/ultragroup/usergroup/add.json" + resp := &UltraGroupUserGroupAddResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupDelRequest struct { + // [必传] 超级群 ID,请确保超级群 ID 存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户组 ID 列表,多个 ID 以逗号分隔。单次请求最大长度为 10 个,否则全部失败。 + UserGroupIds *string `url:"userGroupIds,omitempty"` +} + +type UltraGroupUserGroupDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserGroupDel 超级群删除用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/delete-usergroup +func (rc *RongCloud) UltraGroupUserGroupDel(ctx context.Context, req *UltraGroupUserGroupDelRequest) (*UltraGroupUserGroupDelResponse, error) { + path := "/ultragroup/usergroup/del.json" + resp := &UltraGroupUserGroupDelResponse{} + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupQueryRequest struct { + // [必传] 超级群 ID,请确保超级群 ID 存在。 + GroupId *string `url:"groupId,omitempty"` + // 查询页码,默认 1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认 10,最多为 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupUserGroupQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + UserGroups []*UltraGroupUserGroup `json:"userGroups"` // 用户组列表 +} + +// UltraGroupUserGroupQuery 超级群查询用户组列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-usergroup +func (rc *RongCloud) UltraGroupUserGroupQuery(ctx context.Context, req *UltraGroupUserGroupQueryRequest) (*UltraGroupUserGroupQueryResponse, error) { + path := "/ultragroup/usergroup/query.json" + resp := &UltraGroupUserGroupQueryResponse{} + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupUserAddRequest struct { + // [必传] 超级群 ID,请确保超级群 ID 存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户组 ID,请确保用户组 ID 存在。 + UserGroupId *string `url:"userGroupId,omitempty"` + // [必传] 群内用户 ID 列表,多个 ID 以逗号分隔。单次不得超过 20人,请确保用户 ID 存在,否则全部失败。 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupUserGroupUserAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserGroupUserAdd 超级群用户组添加用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/add-user-to-usergroup +func (rc *RongCloud) UltraGroupUserGroupUserAdd(ctx context.Context, req *UltraGroupUserGroupUserAddRequest) (*UltraGroupUserGroupUserAddResponse, error) { + path := "/ultragroup/usergroup/user/add.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserGroupUserAddResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupUserDelRequest struct { + // [必传] 超级群 ID,请确保超级群 ID 存在。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户组 ID,请确保用户组 ID 存在。 + UserGroupId *string `url:"userGroupId,omitempty"` + // [必传] 群内用户 ID 列表,多个 ID 以逗号分隔。单次不得超过 20人,请确保用户 ID 存在,否则全部失败。 + UserIds *string `url:"userIds,omitempty"` +} + +type UltraGroupUserGroupUserDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupUserGroupUserDel 超级群用户组移出用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/remove-user-from-usergroup +func (rc *RongCloud) UltraGroupUserGroupUserDel(ctx context.Context, req *UltraGroupUserGroupUserDelRequest) (*UltraGroupUserGroupUserDelResponse, error) { + path := "/ultragroup/usergroup/user/del.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserGroupUserDelResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserUserGroupQueryRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // 查询页码,默认 1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认 10,最多为 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupUserUserGroupQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []string `json:"data"` // 用户组 ID 列表 +} + +// UltraGroupUserUserGroupQuery 超级群查询用户所属用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-usergroup-by-user +func (rc *RongCloud) UltraGroupUserUserGroupQuery(ctx context.Context, req *UltraGroupUserUserGroupQueryRequest) (*UltraGroupUserUserGroupQueryResponse, error) { + path := "/ultragroup/user/usergroup/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserUserGroupQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelUserGroupBindRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户组 ID 列表,多个 ID 以逗号分隔。单次请求不能超过 10 个,否则全部失败。 + UserGroupIds *string `url:"userGroupIds,omitempty"` +} + +type UltraGroupChannelUserGroupBindResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelUserGroupBind 超级群绑定频道与用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/bind-channel-to-usergroup +func (rc *RongCloud) UltraGroupChannelUserGroupBind(ctx context.Context, req *UltraGroupChannelUserGroupBindRequest) (*UltraGroupChannelUserGroupBindResponse, error) { + path := "/ultragroup/channel/usergroup/bind.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelUserGroupBindResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelUserGroupUnbindRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道 ID + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 用户组 ID 列表,多个 ID 以逗号分隔。单次请求不能超过 10 个,否则全部失败。 + UserGroupIds *string `url:"userGroupIds,omitempty"` +} + +type UltraGroupChannelUserGroupUnbindResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupChannelUserGroupUnbind 超级群解绑频道与用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/unbind-channel-from-usergroup +func (rc *RongCloud) UltraGroupChannelUserGroupUnbind(ctx context.Context, req *UltraGroupChannelUserGroupUnbindRequest) (*UltraGroupChannelUserGroupUnbindResponse, error) { + path := "/ultragroup/channel/usergroup/unbind.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelUserGroupUnbindResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupChannelUserGroupQueryRequest struct { + // [必传] 超级群 ID + GroupId *string `url:"groupId,omitempty"` + // [必传] 频道ID + BusChannel *string `url:"busChannel,omitempty"` + // 查询页码,默认1 + Page *int `url:"page,omitempty"` + // 每页条数,默认10,最多为50 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupChannelUserGroupQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []string `json:"data"` // 用户组 ID 列表。 +} + +// UltraGroupChannelUserGroupQuery 超级群查询频道绑定的用户组 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-channel-bound-usergroup +func (rc *RongCloud) UltraGroupChannelUserGroupQuery(ctx context.Context, req *UltraGroupChannelUserGroupQueryRequest) (*UltraGroupChannelUserGroupQueryResponse, error) { + path := "/ultragroup/channel/usergroup/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupChannelUserGroupQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupUserGroupChannelQueryRequest struct { + // [必传] 超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // [必传] 用户组 ID。 + UserGroupId *string `url:"userGroupId,omitempty"` + // 查询页码,默认1。 + Page *int `url:"page,omitempty"` + // 每页条数,默认 10,最多为 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UltraGroupUserGroupChannelQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data []string `json:"data"` // 频道ID列表 +} + +// UltraGroupUserGroupChannelQuery 超级群查询用户组绑定的频道 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/query-usergroup-bound-channel +func (rc *RongCloud) UltraGroupUserGroupChannelQuery(ctx context.Context, req *UltraGroupUserGroupChannelQueryRequest) (*UltraGroupUserGroupChannelQueryResponse, error) { + path := "/ultragroup/usergroup/channel/query.json" + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + resp := &UltraGroupUserGroupChannelQueryResponse{} + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UltraGroupMsgModifyRequest struct { + // [必传] 消息所属的超级群 ID。 + GroupId *string `url:"groupId,omitempty"` + // 消息所属的超级群的会话频道 ID。仅在消息属于超级群默认频道(RCDefault)时可以不传该参数。 + BusChannel *string `url:"busChannel,omitempty"` + // [必传] 消息发送者 ID。 + FromUserId *string `url:"fromUserId,omitempty"` + // [必传] 消息唯一标识 ID,可通过全量消息路由功能获取。 + MsgUID *string `url:"msgUID,omitempty"` + // [必传] 修改后的消息内容,单条消息最大 128k。消息类型无法修改。如果改前为文本消息内容体,则传入的新消息内容体必须同样为文本消息内容体。 + Content *string `url:"content,omitempty"` +} + +type UltraGroupMsgModifyResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UltraGroupMsgModify 修改超级群消息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/ultragroup/modify-message +func (rc *RongCloud) UltraGroupMsgModify(ctx context.Context, req *UltraGroupMsgModifyRequest) (*UltraGroupMsgModifyResponse, error) { + path := "/ultragroup/msg/modify.json" + resp := &UltraGroupMsgModifyResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/user.go b/rongcloud/user.go new file mode 100644 index 0000000..87fcc56 --- /dev/null +++ b/rongcloud/user.go @@ -0,0 +1,647 @@ +package rongcloud + +import ( + "context" + "encoding/json" + "fmt" +) + +type UserBlockPushPeriodSetRequest struct { + // [必传] 用户 ID + UserId *string `url:"userId,omitempty"` + // [必传] 开始时间,精确到秒。格式为 HH:MM:SS,示例:22:00:00。注意:startTime 与应用所属数据中心有关。如您的 App 业务使用国内数据中心,请使用北京时间。如您的 App 业务使用海外数据中心,请使用 UTC 时间。 + StartTime *string `url:"startTime,omitempty"` + // [必传] 免打扰时间窗口大小,单位为分钟。支持范围为 [0-1439] 的整数。0 表示未设置。 + Period *int `url:"period,omitempty"` + // 免打扰级别。1:仅 @消息进行通知,普通消息不进行通知。0:所有消息都进行通知。5:所有消息都不进行通知。 默认 1。 + Level *int `url:"level,omitempty"` +} + +type UserBlockPushPeriodSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserBlockPushPeriodSet 设置用户免打扰时段 +// More details see https://doc.rongcloud.cn/imserver/server/v1/push/set-push-disabled-period +func (rc *RongCloud) UserBlockPushPeriodSet(ctx context.Context, req *UserBlockPushPeriodSetRequest) (*UserBlockPushPeriodSetResponse, error) { + path := "/user/blockPushPeriod/set.json" + resp := &UserBlockPushPeriodSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlockPushPeriodGetRequest struct { + // [必传] 用户 ID + UserId *string `url:"userId,omitempty"` +} + +type UserBlockPushPeriodGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Data *UserBlockPushPeriodData `json:"data"` +} + +type UserBlockPushPeriodData struct { + // 开始时间,精确到秒。格式为 HH:MM:SS,示例:22:00:00。注意:startTime 与应用所属数据中心有关。如您的 App 业务使用国内数据中心,该时间为北京时间。如您的 App 业务使用海外数据中心,该时间为 UTC 时间。 + StartTime string `json:"startTime"` + // 免打扰时间窗口大小,单位为分钟。范围为 [0-1439] 的整数。0 表示未设置。 + Period int `json:"period"` + // 免打扰级别。1:仅 @消息进行通知,普通消息不进行通知。0:所有消息都进行通知。5:所有消息都不进行通知。 + UnPushLevel int `json:"unPushLevel"` +} + +// UserBlockPushPeriodGet 查询用户免打扰时段 +// More details see https://doc.rongcloud.cn/imserver/server/v1/push/get-push-disabled-period +func (rc *RongCloud) UserBlockPushPeriodGet(ctx context.Context, req *UserBlockPushPeriodGetRequest) (*UserBlockPushPeriodGetResponse, error) { + path := "/user/blockPushPeriod/get.json" + resp := &UserBlockPushPeriodGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlockPushPeriodDeleteRequest struct { + // [必传] 用户ID + UserId *string `url:"userId,omitempty"` +} + +type UserBlockPushPeriodDeleteResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserBlockPushPeriodDelete 删除用户免打扰时段 +// More details see https://doc.rongcloud.cn/imserver/server/v1/push/delete-push-disabled-period +func (rc *RongCloud) UserBlockPushPeriodDelete(ctx context.Context, req *UserBlockPushPeriodDeleteRequest) (*UserBlockPushPeriodDeleteResponse, error) { + path := "/user/blockPushPeriod/delete.json" + resp := &UserBlockPushPeriodDeleteResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserGetTokenRequest struct { + // [必传] App 自行定义的用户 ID,用于换取 Token。支持大小写英文字母与数字的组合,最大长度 64 字节。 + UserId *string `url:"userId,omitempty"` + // [必传] 推送服务使用的用户名称。不区分符号、英文字符、中文字符,统一限制最多 64 个字符。注意:该 name 字段仅用于推送服务,作为在移动客户端推送通知中默认显示的用户名称。因为即时通讯服务端不提供用户信息托管服务,所以不支持客户端 SDK 主动获取该用户名称数据。 + Name *string `url:"name,omitempty"` + // 用户头像 URI,最大长度 1024 字节。注意:因为即时通讯服务端不提供用户信息托管服务,所以不支持客户端 SDK 主动获取该用户头像数据。 + PortraitUri *string `url:"portraitUri,omitempty"` +} + +type UserGetTokenResponse struct { + CodeResult + httpResponseGetter `json:"-"` + // 用户身份验证 Token,长度在 256 字节以内,可以保存应用内。Token 中携带 IM 服务动态导航地址,开发者不需要进行处理。 + Token string `json:"token"` + // 返回输入参数中提供的用户 ID。 + UserId string `json:"userId"` +} + +// UserGetToken 注册用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/register +func (rc *RongCloud) UserGetToken(ctx context.Context, req *UserGetTokenRequest) (*UserGetTokenResponse, error) { + path := "/user/getToken.json" + resp := &UserGetTokenResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserTokenExpireRequest struct { + // [必传] 需要设置 Token 失效的用户 ID,支持设置多个最多不超过 20 个。 + UserId []string `url:"userId,omitempty"` + // [必传] 过期时间戳精确到毫秒,该时间戳前用户获取的 Token 全部失效,使用时间戳之前的 Token 已经在连接中的用户不会立即失效,断开后无法进行连接。 + Time *int64 `url:"time,omitempty"` +} + +type UserTokenExpireResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserTokenExpire 作废Token +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/expire +func (rc *RongCloud) UserTokenExpire(ctx context.Context, req *UserTokenExpireRequest) (*UserTokenExpireResponse, error) { + path := "/user/token/expire.json" + resp := &UserTokenExpireResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserRemarksSetRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 设置的目标用户推送备注名 + Remarks []*UserRemark `url:"-"` +} + +type UserRemark struct { + // [必传] 目标用户 ID。单次最多设置 100 个。 + Id string `json:"id,omitempty"` + // [必传] 收到目标用户推送时显示的备注名。 + Remark string `json:"remark,omitempty"` +} + +type UserRemarksSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserRemarksSet 设置用户级推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/set-remark-for-push +func (rc *RongCloud) UserRemarksSet(ctx context.Context, req *UserRemarksSetRequest) (*UserRemarksSetResponse, error) { + path := "/user/remarks/set.json" + resp := &UserRemarksSetResponse{} + params, err := makeUrlValues(req) + if err != nil { + return nil, err + } + if req.Remarks != nil { + remarks, err := json.Marshal(req.Remarks) + if err != nil { + return nil, NewSDKError(fmt.Sprintf("json marshal remarks error %s", err)) + } + params.Set("remarks", string(remarks)) + } + httpResp, err := rc.postFormUrlencoded(ctx, path, params, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserRemarksGetRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // 页数,默认为第一页。 + Page *int `url:"page,omitempty"` + // 每页条数,默认每页 50 条。 + Size *int `url:"size,omitempty"` +} + +type UserRemarksGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Total int `json:"total"` // 用户的备注名总数。 + Users []*UserRemark `json:"users"` // 单次最多返回 50 个用户备注名。 +} + +// UserRemarksGet 查询用户级推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/get-remark-for-push +func (rc *RongCloud) UserRemarksGet(ctx context.Context, req *UserRemarksGetRequest) (*UserRemarksGetResponse, error) { + path := "/user/remarks/get.json" + resp := &UserRemarksGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserRemarksDelRequest struct { + // [必传] 操作者用户ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 需要删除推送备注名的用户 ID。 + TargetId *string `url:"targetId,omitempty"` +} + +type UserRemarksDelResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserRemarksDel 删除用户级推送备注名 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/delete-remark-for-push +func (rc *RongCloud) UserRemarksDel(ctx context.Context, req *UserRemarksDelRequest) (*UserRemarksDelResponse, error) { + path := "/user/remarks/del.json" + resp := &UserRemarksDelResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserChatFBSetRequest struct { + // [必传] 被禁言用户 ID,支持批量设置,最多不超过 1000 个。 + UserId []string `url:"userId,omitempty"` + // [必传] 禁言状态,0 解除禁言、1 添加禁言 + State *int `url:"state,omitempty"` + // [必传] 会话类型,目前支持单聊会话 PERSON + Type *string `url:"type,omitempty"` +} + +type UserChatFBSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserChatFBSet 设置用户单聊禁言 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/ban +func (rc *RongCloud) UserChatFBSet(ctx context.Context, req *UserChatFBSetRequest) (*UserChatFBSetResponse, error) { + path := "/user/chat/fb/set.json" + resp := &UserChatFBSetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserChatFBQueryListRequest struct { + // 获取行数,默认为 100,最大支持 200 个。 + Num *int `url:"num,omitempty"` + // 查询开始位置,默认为 0。 + Offset *int `url:"offset,omitempty"` + // [必传] 会话类型,目前支持单聊会话 PERSON + Type *string `url:"type,omitempty"` +} + +type UserChatFBQueryListResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Total int `json:"total"` + Users []string `json:"users"` +} + +// UserChatFBQueryList 查询单聊禁言用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/query-banned-list +func (rc *RongCloud) UserChatFBQueryList(ctx context.Context, req *UserChatFBQueryListRequest) (*UserChatFBQueryListResponse, error) { + path := "/user/chat/fb/querylist.json" + resp := &UserChatFBQueryListResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserWhitelistAddRequest struct { + // [必传] 用户ID + UserId *string `url:"userId,omitempty"` + // [必传] 被加入白名单的用户 ID。单次可添加最多 20 个 whiteUserId。 + WhiteUserId []string `url:"whiteUserId,omitempty"` +} + +type UserWhitelistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserWhitelistAdd 添加用户到白名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/add-to-whitelist +func (rc *RongCloud) UserWhitelistAdd(ctx context.Context, req *UserWhitelistAddRequest) (*UserWhitelistAddResponse, error) { + path := "/user/whitelist/add.json" + resp := &UserWhitelistAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserWhitelistRemoveRequest struct { + // [必传] 用户ID + UserId *string `url:"userId,omitempty"` + // [必传] 被移除的用户 ID,每次最多移除 20 个用户。 + WhiteUserId []string `url:"whiteUserId,omitempty"` +} + +type UserWhitelistRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserWhitelistRemove 移除白名单中用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/remove-from-whitelist +func (rc *RongCloud) UserWhitelistRemove(ctx context.Context, req *UserWhitelistRemoveRequest) (*UserWhitelistRemoveResponse, error) { + path := "/user/whitelist/remove.json" + resp := &UserWhitelistRemoveResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserWhitelistQueryRequest struct { + // [必传] 用户ID + UserId *string `url:"userId,omitempty"` +} + +type UserWhitelistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []string `json:"users"` // 白名单用户数组。 +} + +// UserWhitelistQuery 查询白名单中用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/query-whitelist +func (rc *RongCloud) UserWhitelistQuery(ctx context.Context, req *UserWhitelistQueryRequest) (*UserWhitelistQueryResponse, error) { + path := "/user/whitelist/query.json" + resp := &UserWhitelistQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserRefreshRequest struct { + // [必传] 用户 ID,支持大小写英文字母与数字的组合,最大长度 64 字节。 userId 是用户在 App 中的唯一标识,必须保证在同一个 App 内不重复,重复的用户 ID 将被当作是同一用户。 + UserId *string `url:"userId,omitempty"` + // 用户名称,最大长度 64 个字符(不区分符号、英文字符、中文字符,统一限制最多 64 个字符)。用来在 Push 推送时,显示用户的名称,不提供则不进行刷新。 + Name *string `url:"name,omitempty"` + // 用户头像 URI,最大长度 1024 字节。 + PortraitUri *string `url:"portraitUri,omitempty"` +} + +type UserRefreshResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserRefresh 修改用户信息 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/modify +func (rc *RongCloud) UserRefresh(ctx context.Context, req *UserRefreshRequest) (*UserRefreshResponse, error) { + path := "/user/refresh.json" + resp := &UserRefreshResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlockRequest struct { + // [必传] 用户 ID,支持一次封禁多个用户,最多不超过 20 个。 + UserId []string `url:"userId,omitempty"` + // [必传] 封禁时长,单位为分钟,最大值为 43200 分钟。 + Minute *int `url:"minute,omitempty"` +} + +type UserBlockResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserBlock 封禁用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/block +func (rc *RongCloud) UserBlock(ctx context.Context, req *UserBlockRequest) (*UserBlockResponse, error) { + path := "/user/block.json" + resp := &UserBlockResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlockQueryRequest struct { + // 分页获取封禁用户列表时当前页数,不传或传入 0 时不做分页处理,默认获取前 1000 个被封禁的用户列表,按封禁结束时间倒序排序。 + Page *int `url:"page,omitempty"` + // 分页获取封禁用户列表时每页行数,不传时默认为 50 条。 + Size *int `url:"size,omitempty"` +} + +type UserBlockQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []UserBlockQueryUser `json:"users"` // 被封禁用户数组。 +} + +type UserBlockQueryUser struct { + UserId string `json:"userId"` // 被封禁用户 ID。 + BlockEndTime string `json:"blockEndTime"` // 封禁结束时间。 +} + +// UserBlockQuery 获取封禁用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/query-blocked-list +func (rc *RongCloud) UserBlockQuery(ctx context.Context, req *UserBlockQueryRequest) (*UserBlockQueryResponse, error) { + path := "/user/block/query.json" + resp := &UserBlockQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserUnBlockRequest struct { + // [必传] 用户 ID,支持一次解除多个用户,最多不超过 20 个。 + UserId []string `url:"userId,omitempty"` +} + +type UserUnBlockResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserUnBlock 解除封禁 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/block +func (rc *RongCloud) UserUnBlock(ctx context.Context, req *UserUnBlockRequest) (*UserUnBlockResponse, error) { + path := "/user/unblock.json" + resp := &UserUnBlockResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlacklistAddRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 被加入黑名单的用户 ID。单次可添加最多 20 个 blackUserId。 + BlackUserId []string `url:"blackUserId,omitempty"` +} + +type UserBlacklistAddResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserBlacklistAdd 添加用户到黑名单 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/add-to-blacklist +func (rc *RongCloud) UserBlacklistAdd(ctx context.Context, req *UserBlacklistAddRequest) (*UserBlacklistAddResponse, error) { + path := "/user/blacklist/add.json" + resp := &UserBlacklistAddResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlacklistRemoveRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` + // [必传] 被移除黑名单的用户 ID,每次最多移除 20 个用户。 + BlackUserId []string `url:"blackUserId,omitempty"` +} + +type UserBlacklistRemoveResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserBlacklistRemove 移除黑名单中用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/remove-from-blacklist +func (rc *RongCloud) UserBlacklistRemove(ctx context.Context, req *UserBlacklistRemoveRequest) (*UserBlacklistRemoveResponse, error) { + path := "/user/blacklist/remove.json" + resp := &UserBlacklistRemoveResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserBlacklistQueryRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` +} + +type UserBlacklistQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []string `json:"users"` // 黑名单用户数组。 +} + +// UserBlacklistQuery 获取黑名单用户列表 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/query-blacklist +func (rc *RongCloud) UserBlacklistQuery(ctx context.Context, req *UserBlacklistQueryRequest) (*UserBlacklistQueryResponse, error) { + path := "/user/blacklist/query.json" + resp := &UserBlacklistQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserCheckOnlineRequest struct { + // [必传] 用户 ID。 + UserId *string `url:"userId,omitempty"` +} + +type UserCheckOnlineResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Status string `json:"status"` // 用户状态。1 - 用户当前在线。0 - 用户当前不在线。 +} + +// UserCheckOnline 查询用户在线状态 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/check-online-status-by-user +func (rc *RongCloud) UserCheckOnline(ctx context.Context, req *UserCheckOnlineRequest) (*UserCheckOnlineResponse, error) { + path := "/user/checkOnline.json" + resp := &UserCheckOnlineResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserTagSetRequest struct { + // [必传] 用户 ID。 + UserId *string `json:"userId,omitempty"` + // [必传] 用户标签,一个用户最多添加 20 个标签,每个 tag 最大不能超过 40 个字节,标签中不能包含特殊字符。每次设置时需要传入用户的全量标签数据。传入空数组表示清除该用户的所有标签。 + Tags []string `json:"tags,omitempty"` +} + +type UserTagSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserTagSet 设置用户标签 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/set-user-tag +func (rc *RongCloud) UserTagSet(ctx context.Context, req *UserTagSetRequest) (*UserTagSetResponse, error) { + path := "/user/tag/set.json" + resp := &UserTagSetResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserTagBatchSetRequest struct { + // [必传] 用户 ID,一次最多支持 1000 个用户。传入的所有用户的标签都被会覆盖更新为 tags 中的标签。 + UserIds []string `json:"userIds,omitempty"` + // [必传] 用户标签,一个用户最多添加 20 个标签,每个 tag 最大不能超过 40 个字节,标签中不能包含特殊字符。每次设置时需要传入用户的全量标签数据。传入空数组表示清除该用户的所有标签。 + Tags []string `json:"tags,omitempty"` +} + +type UserTagBatchSetResponse struct { + CodeResult + httpResponseGetter `json:"-"` +} + +// UserTagBatchSet 批量设置用户标签 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/batch-set-user-tag +func (rc *RongCloud) UserTagBatchSet(ctx context.Context, req *UserTagBatchSetRequest) (*UserTagBatchSetResponse, error) { + path := "/user/tag/batch/set.json" + resp := &UserTagBatchSetResponse{} + httpResp, err := rc.postJson(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserTagsGetRequest struct { + // [必传] 用户 ID,一次最多支持 50 个用户。 + UserIds []string `url:"userIds,omitempty"` +} + +type UserTagsGetResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Result map[string][]string `json:"result"` // 用户所有的标签数组。userId:tags + // {"code":200,"result":{"u02":["tag4","tag3"],"u01":["tag4","tag3"]}} +} + +// UserTagsGet 获取用户标签 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/get-user-tag +func (rc *RongCloud) UserTagsGet(ctx context.Context, req *UserTagsGetRequest) (*UserTagsGetResponse, error) { + path := "/user/tags/get.json" + resp := &UserTagsGetResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserDeactivateRequest struct { + // [必传] 被注销用户 ID,最多一次 100 个。逗号分割 + UserId *string `url:"userId,omitempty"` +} + +type UserDeactivateResponse struct { + CodeResult + httpResponseGetter `json:"-"` + OperateId string `json:"operateId"` // 操作 ID,为当前操作的唯一标识。开通用户注销与激活状态回调后,回调请求正文中会携带此参数。 +} + +// UserDeactivate 注销用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/deactivate +func (rc *RongCloud) UserDeactivate(ctx context.Context, req *UserDeactivateRequest) (*UserDeactivateResponse, error) { + path := "/user/deactivate.json" + resp := &UserDeactivateResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserDeactivateQueryRequest struct { + // 分页获取注销用户列表时的当前页数,默认 1,最小 1。 + PageNo *int `url:"pageNo,omitempty"` + // 分页获取注销用户列表时的每页行数,默认 50,最小 1,最大 50。 + PageSize *int `url:"pageSize,omitempty"` +} + +type UserDeactivateQueryResponse struct { + CodeResult + httpResponseGetter `json:"-"` + Users []string `json:"users"` // 已注销的用户 ID 列表 +} + +// UserDeactivateQuery 查询已注销用户 +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/query-deactivated-list +func (rc *RongCloud) UserDeactivateQuery(ctx context.Context, req *UserDeactivateQueryRequest) (*UserDeactivateQueryResponse, error) { + path := "/user/deactivate/query.json" + resp := &UserDeactivateQueryResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} + +type UserReactivateRequest struct { + // [必传] 激活用户 ID,单次请求最多传入 100 个用户 ID。逗号分割 + UserId *string `url:"userId,omitempty"` +} + +type UserReactivateResponse struct { + CodeResult + httpResponseGetter `json:"-"` + OperateId string `json:"operateId"` // 操作 ID,为当前操作的唯一标识。开通用户注销与激活状态回调后,回调请求正文中会携带此参数。 +} + +// UserReactivate 重新激活用户 ID +// More details see https://doc.rongcloud.cn/imserver/server/v1/user/reactivate +func (rc *RongCloud) UserReactivate(ctx context.Context, req *UserReactivateRequest) (*UserReactivateResponse, error) { + path := "/user/reactivate.json" + resp := &UserReactivateResponse{} + httpResp, err := rc.postForm(ctx, path, req, &resp) + resp.httpResponseGetter = newRawHttpResponseGetter(httpResp) + return resp, err +} diff --git a/rongcloud/utils.go b/rongcloud/utils.go new file mode 100644 index 0000000..7af27bd --- /dev/null +++ b/rongcloud/utils.go @@ -0,0 +1,45 @@ +package rongcloud + +func StringPtr(s string) *string { + return &s +} + +func StringValue(s *string) string { + if s != nil { + return *s + } + return "" +} + +func IntPtr(i int) *int { + return &i +} + +func IntValue(i *int) int { + if i != nil { + return *i + } + return 0 +} + +func Int64Ptr(i int64) *int64 { + return &i +} + +func Int64Value(i *int64) int64 { + if i != nil { + return *i + } + return 0 +} + +func BoolPtr(b bool) *bool { + return &b +} + +func BoolValue(b *bool) bool { + if b != nil { + return *b + } + return false +} diff --git a/sdk/chatroom.go b/sdk/chatroom.go deleted file mode 100644 index 996cc36..0000000 --- a/sdk/chatroom.go +++ /dev/null @@ -1,1620 +0,0 @@ -// ChatRoom 聊天室 - -package sdk - -import ( - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/astaxie/beego/httplib" -) - -// ChatRoomInfo 聊天室信息 -type ChatRoomInfo struct { - ID string `json:"id"` - Name string `json:"name"` -} - -// ChatRoom 聊天室信息 -type ChatRoom struct { - ChatRoomID string `json:"chrmId"` - Name string `json:"name"` - Time string `json:"time"` -} - -// ChatRoomQueryResult 聊天室查询接口返回数据 -type ChatRoomQueryResult struct { - ChatRooms []ChatRoom `json:"chatRooms"` -} - -// ChatRoomResult ChatRoom 返回结果 -type ChatRoomResult struct { - Total int `json:"total"` - Users []ChatRoomUser `json:"users"` - Result []ChatRoomUser `json:"result"` - ObjectNames []string `json:"objectNames"` - ChatRoomIDs []string `json:"chatroomids"` - WhitelistMsgType []string `json:"whitlistMsgType"` -} - -// 查询聊天室信息返回结果 -type ChatRoomGetResult struct { - Code int `json:"code"` - ChatroomId string `json:"chatroomId"` - CreateTime int64 `json:"createTime"` - MemberCount int `json:"memberCount"` - DestroyType int `json:"destroyType"` - DestroyTime int `json:"destroyTime"` - IsBan bool `json:"ban"` -} - -// ChatRoomUser 聊天室用户信息 -type ChatRoomUser struct { - ID string `json:"id"` - UserID string `json:"userId"` - Time string `json:"time"` - IsInChrm int `json:"isInChrm"` -} - -// ChatRoomAttr 聊天室属性自定义结构 -type ChatRoomAttr struct { - Key string `json:"key"` - Value string `json:"value"` - UserID string `json:"userID"` - AutoDelete string `json:"autoDelete"` - LastSetTime string `json:"lastSetTime"` -} - -// ChatRoomAttrResult 聊天室属性自定义返回结果 -type ChatRoomAttrResult struct { - Keys []ChatRoomAttr `json:"keys"` -} - -// ChatUserExistObj : ChatUserExistResObj的返回值 -type ChatUserExistObj struct { - // 200:成功。 - Code int `json:"code"` - - // 用户是否在聊天室中,true 表示在聊天室中,false 表示不在聊天室中。 - IsInChrm bool `json:"isInChrm"` -} - -// chatroomOptions is extra options for chatroom -type chatroomOptions struct { - needNotify bool - extra string - destroyType int - destroyTime int - isBan bool - whiteUserIds []string - entryOwnerId string - entryInfo map[string]interface{} -} - -// ChatroomOption 接口函数 -type ChatroomOption func(*chatroomOptions) - -// 是否通知成员。默认 false 不通知 -func WithChatroomNeedNotify(isNeedNotify bool) ChatroomOption { - return func(options *chatroomOptions) { - options.needNotify = isNeedNotify - } -} - -// 通知携带的 JSON 格式的扩展信息,仅在 needNotify 为 true 时有效。 -func WithChatroomExtra(extra string) ChatroomOption { - return func(options *chatroomOptions) { - options.extra = extra - } -} - -// 指定聊天室的销毁类型: 0:默认值,表示不活跃时销毁, 1:固定时间销毁 -func WithChatroomDestroyType(destroyType int) ChatroomOption { - return func(options *chatroomOptions) { - options.destroyType = destroyType - } -} - -// 设置聊天室销毁时间, destroyType=1时生效,单位为分钟,最小值 60 分钟,最大 10080 分钟(7 天)。如果未设置,默认 60 分钟。 -func WithChatroomDestroyTime(destroyTime int) ChatroomOption { - return func(options *chatroomOptions) { - options.destroyTime = destroyTime - } -} - -// 是否禁言聊天室全体成员,默认 false -func WithChatroomIsBan(isBan bool) ChatroomOption { - return func(options *chatroomOptions) { - options.isBan = isBan - } -} - -// 禁言白名单用户列表,支持批量设置,最多不超过 20 个 -func WithChatroomWhiteUserIds(whiteUserIds []string) ChatroomOption { - return func(options *chatroomOptions) { - options.whiteUserIds = whiteUserIds - } -} - -// 聊天室自定义属性的所属用户 ID -func WithChatroomEntryOwnerId(entryOwnerId string) ChatroomOption { - return func(options *chatroomOptions) { - options.entryOwnerId = entryOwnerId - } -} - -// 聊天室自定义属性 KV 对,JSON 结构 -func WithChatroomEntryInfo(entryInfo map[string]interface{}) ChatroomOption { - return func(options *chatroomOptions) { - options.entryInfo = entryInfo - } -} - -// 修改默认值 -func modifyChatroomOptions(options []ChatroomOption) chatroomOptions { - // 默认值 - defaultOptions := chatroomOptions{ - needNotify: false, - extra: "", - destroyType: 0, - destroyTime: 60, - isBan: false, - whiteUserIds: []string{}, - entryOwnerId: "", - entryInfo: map[string]interface{}{}, - } - - // 修改默认值 - for _, ext := range options { - ext(&defaultOptions) - } - - return defaultOptions -} - -// ChatUserExistResObj :/chatroom/user/exist.json 查询用户是否加入聊天室 -//* -// @param: chatroomId,要查询的聊天室 ID -// @param: userId, 要查询的用户 ID -// response: ChatUserExistObj -//*// -func (rc *RongCloud) ChatUserExistResObj(chatroomId, userId string) (ChatUserExistObj, error) { - var ( - result = ChatUserExistObj{} - ) - if len(chatroomId) == 0 { - return result, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - if len(userId) == 0 { - return result, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/exist.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatroomId) - req.Param("userId", userId) - - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// ChatUserExist :/chatroom/user/exist.json 查询用户是否加入聊天室 -//* -// @param: chatroomId,要查询的聊天室 ID -// @param: userId, 要查询的用户 ID -// response: byte数组 -//*// -func (rc *RongCloud) ChatUserExist(chatroomId, userId string) ([]byte, error) { - if len(chatroomId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - if len(userId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/exist.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatroomId) - req.Param("userId", userId) - - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// ChatRoomCreate 创建聊天室方法 -/* - *@param id:要创建的聊天室的ID; - *@param name:要创建的聊天室的name。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomCreate(id, name string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - if name == "" { - return RCErrorNew(1002, "Paramer 'name' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/create." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroom["+id+"]", name) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 创建聊天室 -func (rc *RongCloud) ChatRoomCreateNew(chatroomId string, options ...ChatroomOption) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/create_new." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatroomId) - req.Param("destroyType", strconv.Itoa(extOptions.destroyType)) - req.Param("destroyTime", strconv.Itoa(extOptions.destroyTime)) - req.Param("isBan", strconv.FormatBool(extOptions.isBan)) - - fmt.Println(strconv.FormatBool(extOptions.isBan)) - - for _, v := range extOptions.whiteUserIds { - req.Param("whiteUserIds", v) - } - - if "" != extOptions.entryOwnerId { - req.Param("entryOwnerId", extOptions.entryOwnerId) - } - - if len(extOptions.entryInfo) > 0 { - entryInfo, err := json.Marshal(extOptions.entryInfo) - if err != nil { - return err - } - req.Param("entryInfo", string(entryInfo)) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 设置聊天室销毁类型 -func (rc *RongCloud) ChatRoomDestroySet(chatroomId string, destroyType, destroyTime int) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/destroy/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatroomId) - req.Param("destroyType", strconv.Itoa(destroyType)) - req.Param("destroyTime", strconv.Itoa(destroyTime)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 查询聊天室信息 -func (rc *RongCloud) ChatRoomGetNew(chatroomId string) (ChatRoomGetResult, error) { - if chatroomId == "" { - return ChatRoomGetResult{}, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/get." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", chatroomId) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return ChatRoomGetResult{}, err - } - fmt.Println(string(resp)) - var dat ChatRoomGetResult - if err := json.Unmarshal(resp, &dat); err != nil { - return ChatRoomGetResult{}, err - } - return dat, nil -} - -// 批量设置聊天室属性(KV) -func (rc *RongCloud) ChatRoomEntryBatchSet(chatroomId string, autoDelete int, entryOwnerId string, entryInfo map[string]interface{}) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - if entryOwnerId == "" { - return RCErrorNew(1002, "Paramer 'entryOwnerId' is required") - } - - if len(entryInfo) < 1 { - return RCErrorNew(1002, "Paramer 'entryInfo' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/entry/batch/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatroomId) - req.Param("autoDelete", strconv.Itoa(autoDelete)) - - req.Param("entryOwnerId", entryOwnerId) - - entryInfoJson, e := json.Marshal(entryInfo) - if e != nil { - return e - } - req.Param("entryInfo", string(entryInfoJson)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomDestroy 销毁聊天室方法 -/** - * - *@param id:要销毁的聊天室 ID。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomDestroy(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/destroy." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomGet 查询聊天室内用户方法 -/* - *@param id:要查询的聊天室 ID。 - *@param count:要获取的聊天室成员数,上限为 500 ,超过 500 时最多返回 500 个成员。 - *@param order:加入聊天室的先后顺序, 1 为加入时间正序, 2 为加入时间倒序。 - * - *@return ChatRoomResult error - */ -func (rc *RongCloud) ChatRoomGet(id string, count, order int) (ChatRoomResult, error) { - if id == "" { - return ChatRoomResult{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - if count <= 0 { - return ChatRoomResult{}, RCErrorNew(1002, "Paramer 'count' is required") - } - - if order <= 0 { - return ChatRoomResult{}, RCErrorNew(1002, "Paramer 'order' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - req.Param("count", strconv.Itoa(count)) - req.Param("order", strconv.Itoa(order)) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return ChatRoomResult{}, err - } - var dat ChatRoomResult - if err := json.Unmarshal(resp, &dat); err != nil { - return ChatRoomResult{}, err - } - return dat, nil -} - -// ChatRoomIsExist 检查用户是否在聊天室 -/* - *@param id:要查询的聊天室 ID。 - *@param members:每次最多 1000 个成员。 - * - *@return ChatRoomResult error - */ -func (rc *RongCloud) ChatRoomIsExist(id string, members []string) ([]ChatRoomUser, error) { - if id == "" { - return []ChatRoomUser{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return []ChatRoomUser{}, RCErrorNew(1002, "Paramer 'count' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/users/exist." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - for _, v := range members { - req.Param("userId", v) - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []ChatRoomUser{}, err - } - var dat ChatRoomResult - if err := json.Unmarshal(resp, &dat); err != nil { - return []ChatRoomUser{}, err - } - return dat.Result, nil -} - -// ChatRoomBlockAdd 添加封禁聊天室成员方法 -/** - * - *@param id:聊天室 Id。 - *@param members:封禁列表。 - *@param minute:封禁时长,以分钟为单位,最大值为43200分钟。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomBlockAdd(id string, members []string, minute uint, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/block/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - for _, v := range members { - req.Param("userId", v) - } - req.Param("minute", strconv.Itoa(int(minute))) - - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomBlockRemove 移除封禁聊天室成员方法 -/* - * - *@param id:聊天室 ID。 - *@param members: 用户列表。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomBlockRemove(id string, members []string, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/block/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", id) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomBlockGetList 查询被封禁聊天室成员方法 -/* - *@param id:聊天室 ID。 - * - *@return ChatRoomResult error - */ -func (rc *RongCloud) ChatRoomBlockGetList(id string) (ChatRoomResult, error) { - var dat ChatRoomResult - if id == "" { - return dat, RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/block/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return dat, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return dat, err - } - return dat, nil -} - -// ChatRoomBanAdd 添加聊天室全局禁言 -/* - *@param members:成员列表,最多不超过 20 个。 - *@param minute:禁言时长,范围: 1 - 1 * 30 * 24 * 60 分钟。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomBanAdd(members []string, minute uint, options ...ChatroomOption) error { - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("minute", strconv.Itoa(int(minute))) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomBanRemove 解除聊天室全局禁言 -/* - *@param members:成员列表,最多不超过 20 个。 - * - *@return error - */ -func (rc *RongCloud) ChatRoomBanRemove(members []string, options ...ChatroomOption) error { - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomBanGetList 获取聊天室全局禁言列表 -/* - *@return []ChatRoomUser error - */ -func (rc *RongCloud) ChatRoomBanGetList() ([]ChatRoomUser, error) { - var dat ChatRoomResult - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []ChatRoomUser{}, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return []ChatRoomUser{}, err - } - return dat.Users, nil -} - -// ChatRoomGagAdd 添加禁言聊天室成员方法(在 App 中如果不想让某一用户在聊天室中发言时,可将此用户在聊天室中禁言,被禁言用户可以接收查看聊天室中用户聊天信息,但不能发送消息.) -/* - * - *@param id:聊天室 ID。 - *@param members:禁言列表。 - *@param minute:禁言时长,以分钟为单位,最大值为43200分钟。(必传) - * - *@return error - */ -func (rc *RongCloud) ChatRoomGagAdd(id string, members []string, minute uint, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", id) - req.Param("minute", strconv.Itoa(int(minute))) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomGagRemove 移除禁言聊天室成员方法 -/* - *@param id:聊天室Id。 - *@param members:解除禁言列表 - * - *@return error - */ -func (rc *RongCloud) ChatRoomGagRemove(id string, members []string, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", id) - - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomGagGetList 查询被禁言聊天室成员方法 -/* - *@param id:聊天室 ID。(必传) - * - *@return []ChatRoomUser error - */ -func (rc *RongCloud) ChatRoomGagGetList(id string) ([]ChatRoomUser, error) { - var dat ChatRoomResult - if id == "" { - return []ChatRoomUser{}, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []ChatRoomUser{}, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return []ChatRoomUser{}, err - } - return dat.Users, nil -} - -// ChatRoomDemotionAdd 添加聊天室消息优先级方法 -/* - *@param objectName:消息类型列表,最多 20 个。 - *@return err - */ -func (rc *RongCloud) ChatRoomDemotionAdd(objectNames []string) error { - if len(objectNames) == 0 { - return RCErrorNew(1002, "Paramer 'objectName' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/message/priority/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range objectNames { - req.Param("objectName", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomDemotionRemove 移除应用内聊天室降级消息 -/* - *@param objectName:消息类型列表。 - *@return err - */ -func (rc *RongCloud) ChatRoomDemotionRemove(objectNames []string) error { - if len(objectNames) == 0 { - return RCErrorNew(1002, "Paramer 'objectName' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/message/priority/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range objectNames { - req.Param("objectName", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomDemotionGetList 获取应用内聊天室降级消息 -/* - *@return []string error - */ -func (rc *RongCloud) ChatRoomDemotionGetList() ([]string, error) { - var dat ChatRoomResult - - req := httplib.Post(rc.rongCloudURI + "/chatroom/message/priority/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []string{}, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return []string{}, err - } - return dat.ObjectNames, nil -} - -// ChatRoomDistributionStop 聊天室消息停止分发方法(可实现控制对聊天室中消息是否进行分发,停止分发后聊天室中用户发送的消息,融云服务端不会再将消息发送给聊天室中其他用户。) -/* - *@param id:聊天室 ID。 - *@return error - */ -func (rc *RongCloud) ChatRoomDistributionStop(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/message/stopDistribution." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomDistributionResume 聊天室消息恢复分发方法 -/* - *@param id:聊天室 ID。 - *@return error - */ -func (rc *RongCloud) ChatRoomDistributionResume(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/message/resumeDistribution." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomKeepAliveAdd 添加保活聊天室 -/* - *@param id:聊天室 ID。 - *@return error - */ -func (rc *RongCloud) ChatRoomKeepAliveAdd(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/keepalive/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomKeepAliveRemove 删除保活聊天室 -/* - *@param id:聊天室 ID。 - *@return error - */ -func (rc *RongCloud) ChatRoomKeepAliveRemove(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/keepalive/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomKeepAliveGetList 获取保活聊天室 -/* - *@param id:聊天室 ID。 - *@return []string error - */ -func (rc *RongCloud) ChatRoomKeepAliveGetList() ([]string, error) { - var dat ChatRoomResult - // if id == "" { - // return []string{}, RCErrorNew(1002, "Paramer 'chatroomId' is required") - // } - req := httplib.Post(rc.rongCloudURI + "/chatroom/keepalive/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - // req.Param("chatroomId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []string{}, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return []string{}, err - } - return dat.ChatRoomIDs, nil -} - -// ChatRoomWhitelistAdd 添加聊天室消息白名单 -/* - *@param objectNames:消息类型列表。 - *@return error - */ -func (rc *RongCloud) ChatRoomWhitelistAdd(objectNames []string) error { - - if len(objectNames) == 0 { - return RCErrorNew(1002, "Paramer 'objectNames' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/whitelist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range objectNames { - req.Param("objectnames", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomWhitelistRemove 删除聊天室消息白名单 -/* - *@param objectNames:消息类型列表。 - *@return error - */ -func (rc *RongCloud) ChatRoomWhitelistRemove(objectNames []string) error { - - if len(objectNames) == 0 { - return RCErrorNew(1002, "Paramer 'objectNames' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/whitelist/delete." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, v := range objectNames { - req.Param("objectnames", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomWhitelistGetList 获取聊天室消息白名单 -/* - *@return []string error - */ -func (rc *RongCloud) ChatRoomWhitelistGetList() ([]string, error) { - var dat ChatRoomResult - - req := httplib.Post(rc.rongCloudURI + "/chatroom/whitelist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []string{}, err - } - if err := json.Unmarshal(resp, &dat); err != nil { - return []string{}, err - } - - return dat.WhitelistMsgType, nil -} - -// ChatRoomUserWhitelistAdd 添加聊天室白名单成员方法 -/* - *@param id:聊天室 ID。 - *@param members:白名单列表,最多不超过 5 个。 - *@return error - */ -func (rc *RongCloud) ChatRoomUserWhitelistAdd(id string, members []string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/whitelist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - for _, v := range members { - req.Param("userId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomUserWhitelistRemove 将用户从白名单中移除 -/* - *@param id:聊天室 ID。 - *@param members:白名单列表,最多不超过 5 个。 - *@return error - */ -func (rc *RongCloud) ChatRoomUserWhitelistRemove(id string, members []string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/whitelist/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - for _, v := range members { - req.Param("userId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomUserWhitelistGetList 获取聊天室用户白名单 -/* - *@param id:聊天室 ID。 - *@return []string error - */ -func (rc *RongCloud) ChatRoomUserWhitelistGetList(id string) ([]string, error) { - var dat map[string]interface{} - if id == "" { - return []string{}, RCErrorNew(1002, "Paramer 'id' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/whitelist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - response, err := req.Response() - if err != nil { - return []string{}, err - } - - rc.checkStatusCode(response) - - rep, err := req.Bytes() - if err != nil { - rc.urlError(err) - return []string{}, err - } - var code CodeResult - if err := json.Unmarshal(rep, &code); err != nil { - return []string{}, err - } - if code.Code != 200 { - return []string{}, code - } - if err := json.Unmarshal(rep, &dat); err != nil { - return []string{}, err - } - if dat["users"] == nil { - return []string{}, nil - } - var users []string - for _, v := range dat["users"].([]interface{}) { - users = append(users, v.(string)) - } - return users, nil -} - -// ChatRoomMuteMembersAdd 添加禁言聊天室成员方法(在 App 中如果不想让某一用户在聊天室中发言时,可将此用户在聊天室中禁言,被禁言用户可以接收查看聊天室中用户聊天信息,但不能发送消息.) -/* - * - *@param id:聊天室 ID。 - *@param members:禁言列表。 - *@param minute:禁言时长,以分钟为单位,最大值为43200分钟。(必传) - * - *@return error - */ -func (rc *RongCloud) ChatRoomMuteMembersAdd(id string, members []string, minute uint, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - - req.Param("chatroomId", id) - req.Param("minute", strconv.Itoa(int(minute))) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomMuteMembersGetList 查询被禁言聊天室成员方法 -/* - *@param id:聊天室 ID。(必传) - * - *@return []ChatRoomUser error - */ -func (rc *RongCloud) ChatRoomMuteMembersGetList(id string) ([]ChatRoomUser, error) { - var dat ChatRoomResult - if id == "" { - return []ChatRoomUser{}, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", id) - - response, err := req.Response() - if err != nil { - return []ChatRoomUser{}, err - } - - rc.checkStatusCode(response) - - rep, err := req.Bytes() - if err != nil { - rc.urlError(err) - return []ChatRoomUser{}, err - } - var code CodeResult - if err := json.Unmarshal(rep, &code); err != nil { - return []ChatRoomUser{}, err - } - if code.Code != 200 { - return []ChatRoomUser{}, code - } - if err := json.Unmarshal(rep, &dat); err != nil { - return []ChatRoomUser{}, err - } - return dat.Users, nil -} - -// ChatRoomMuteMembersRemove 移除禁言聊天室成员方法 -/* - *@param id:聊天室Id。 - *@param members:解除禁言列表 - * - *@return error - */ -func (rc *RongCloud) ChatRoomMuteMembersRemove(id string, members []string, options ...ChatroomOption) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/gag/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", id) - - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomEntrySet 设置聊天室自定义属性 -/** - * @param chatRoomID 聊天室 Id - * @param userID 操作用户 Id。通过 Server API 非聊天室中用户可以进行设置。 - * @param key 聊天室属性名称,Key 支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,大小写敏感。最大长度 128 字符 - * @param value 聊天室属性对应的值,最大长度 4096 个字符 - * @param autoDelete 用户退出聊天室后,是否删除此 Key 值。为 true 时删除此 Key 值,为 false 时用户退出后不删除此 Key - * - * @retrun error - */ -func (rc *RongCloud) ChatRoomEntrySet(chatRoomID, userID, key, value string, autoDelete bool) error { - if chatRoomID == "" { - return RCErrorNew(1002, "Paramer 'chatRoomID' is required") - } - - if userID == "" { - return RCErrorNew(1002, "Paramer 'userID' is required") - } - - if key == "" { - return RCErrorNew(1002, "Paramer 'key' is required") - } - - if value == "" { - return RCErrorNew(1002, "Paramer 'value' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/entry/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatRoomID) - req.Param("userId", userID) - req.Param("key", key) - req.Param("value", value) - req.Param("autoDelete", strconv.FormatBool(autoDelete)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - - return err -} - -// ChatRoomEntryRemove 删除聊天室自定义属性 -/** - * @param chatRoomID 聊天室 Id - * @param userID 操作用户 Id。通过 Server API 非聊天室中用户可以进行设置。 - * @param key 聊天室属性名称,Key 支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,大小写敏感。最大长度 128 字 - * - * @return error - */ -func (rc *RongCloud) ChatRoomEntryRemove(chatRoomID, userID, key string) error { - if chatRoomID == "" { - return RCErrorNew(1002, "Paramer 'chatRoomID' is required") - } - - if userID == "" { - return RCErrorNew(1002, "Paramer 'userID' is required") - } - - if key == "" { - return RCErrorNew(1002, "Paramer 'key' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/entry/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatRoomID) - req.Param("userId", userID) - req.Param("key", key) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - - return err -} - -// ChatRoomEntryQuery 获取聊天室属性自定义 -/** - * @param ChatRoomID 聊天室 Id - * @param keys 批量获取指定聊天室中的 Key 值,最多上限为 100 个,为空时获取全部 key 值。 - * - * @return []ChatRoomAttr 属性列表 - * @return error 错误 - */ -func (rc *RongCloud) ChatRoomEntryQuery(chatRoomID string, keys ...string) ([]ChatRoomAttr, error) { - if chatRoomID == "" { - return nil, RCErrorNew(1002, "Paramer 'chatRoomID' is required") - } - if len(keys) > 100 { - return nil, RCErrorNew(1002, "Paramer 'keys' more than 100") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/entry/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("chatroomId", chatRoomID) - if len(keys) != 0 { - for k := range keys { - req.Param("keys", keys[k]) - } - } - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return nil, err - } - var data ChatRoomAttrResult - if err := json.Unmarshal(resp, &data); err != nil { - return nil, err - } - return data.Keys, nil -} - -// ChatRoomQuery 查询聊天室基础信息 -/** - * @param chatRoomID 要查询的聊天室id - * - * @return []ChatRoom 聊天室信息数组 - * @return error 错误信息 - * - */ -func (rc *RongCloud) ChatRoomQuery(chatRoomID []string) ([]ChatRoom, error) { - if len(chatRoomID) <= 0 { - return nil, RCErrorNew(1002, "Paramer 'chatRoomID' is required") - } - - url := fmt.Sprintf(`%s/chatroom/query.%s`, rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, v := range chatRoomID { - req.Param("chatroomId", v) - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return nil, err - } - - var data ChatRoomQueryResult - if err := json.Unmarshal(resp, &data); err != nil { - return nil, err - } - - return data.ChatRooms, nil -} - -// 设置聊天室全体禁言 -func (rc *RongCloud) ChatRoomBan(chatroomId string, options ...ChatroomOption) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/ban/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", chatroomId) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 取消聊天室全体禁言 -func (rc *RongCloud) ChatRoomBanRollback(chatroomId string, options ...ChatroomOption) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/ban/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", chatroomId) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 查询聊天室全体禁言列表 -func (rc *RongCloud) ChatRoomBanQuery(size, page int) ([]string, error) { - req := httplib.Post(rc.rongCloudURI + "/chatroom/ban/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("page", strconv.Itoa(page)) - req.Param("size", strconv.Itoa(size)) - - resp, err := rc.do(req) - if err != nil { - return []string{}, err - } - var dat ChatRoomResult - if err := json.Unmarshal(resp, &dat); err != nil { - return []string{}, err - } - - return dat.ChatRoomIDs, nil -} - -// 查询聊天室全体禁言状态 -func (rc *RongCloud) ChatRoomBanCheck(chatroomId string) (bool, error) { - if chatroomId == "" { - return false, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/ban/check." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", chatroomId) - - resp, err := rc.do(req) - if err != nil { - return false, err - } - - data := struct { - Code int `json:"code"` - Status int `json:"status"` - }{} - - if err := json.Unmarshal(resp, &data); err != nil { - return false, err - } - - if data.Status == 1 { - return true, nil - } else { - return false, nil - } -} - -// 加入聊天室全体禁言白名单 -func (rc *RongCloud) ChatRoomUserBanWhitelistAdd(chatroomId string, members []string, options ...ChatroomOption) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/whitelist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", chatroomId) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 移出聊天室全体禁言白名单 -func (rc *RongCloud) ChatRoomUserBanWhitelistRollback(chatroomId string, members []string, options ...ChatroomOption) error { - if chatroomId == "" { - return RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - extOptions := modifyChatroomOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/whitelist/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range members { - req.Param("userId", v) - } - req.Param("chatroomId", chatroomId) - if extOptions.needNotify { - req.Param("needNotify", strconv.FormatBool(extOptions.needNotify)) - req.Param("extra", extOptions.extra) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 查询聊天室全体禁言白名单 -func (rc *RongCloud) ChatRoomUserBanWhitelistQuery(chatroomId string) ([]string, error) { - if chatroomId == "" { - return []string{}, RCErrorNew(1002, "Paramer 'chatroomId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/chatroom/user/ban/whitelist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("chatroomId", chatroomId) - - resp, err := rc.do(req) - if err != nil { - return []string{}, err - } - data := struct { - Code int `json:"code"` - UserIds []string `json:"userIds"` - }{} - - if err := json.Unmarshal(resp, &data); err != nil { - return []string{}, err - } - - return data.UserIds, nil -} diff --git a/sdk/chatroom_test.go b/sdk/chatroom_test.go deleted file mode 100644 index 8cece45..0000000 --- a/sdk/chatroom_test.go +++ /dev/null @@ -1,615 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestRongCloud_ChatUserExistResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - res, err := rc.ChatUserExistResObj( - "chrm01", - "rcchrm01", - ) - if err != nil { - t.Errorf("chat user exist err:%v", err) - return - } - t.Logf("suc :%v", res) -} - -func TestRongCloud_ChatUserExist(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - res, err := rc.ChatUserExist( - "chrm01", - "rcchrm01", - ) - if err != nil { - t.Errorf("chat user exist err:%v", err) - return - } - t.Log("suc", string(res)) -} - -func TestRongCloud_ChatRoomCreate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomCreate( - "chrm01", - "rcchrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomGet( - "chrm01", - 500, - 1, - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomIsExist(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomIsExist( - "chrm01", - []string{"u01"}, - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomDestroy(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomDestroy( - "chrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBanAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBanAdd( - []string{"u01"}, - 30) - t.Log(err) -} - -func TestRongCloud_ChatRoomBanGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomBanGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomBanRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBanRemove( - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBlockAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBlockAdd( - "chrm01", - []string{"u01"}, - 30, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBlockAddOptions(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBlockAdd( - "chrm01", - []string{"u01"}, - 30, - WithChatroomNeedNotify(true), - WithChatroomExtra("block u01"), - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBlockGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomBlockGetList( - "chrm01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomBlockRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBlockRemove( - "chrm01", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomDemotionAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - txtmsg := "RC:TxtMsg" - err := rc.ChatRoomDemotionAdd( - []string{ - txtmsg, - }, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomDemotionGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomDemotionGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomDemotionRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - txtmsg := "RC:TxtMsg" - err := rc.ChatRoomDemotionRemove( - []string{ - txtmsg, - }, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomDistributionStop(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomDistributionStop( - "chrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomDistributionResume(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomDistributionResume( - "chrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomGagAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomGagAdd( - "chrm01", - []string{"u01"}, - 30, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomGagGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomGagGetList( - "chrm01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomGagRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomGagRemove( - "chrm01", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomKeepAliveAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomKeepAliveAdd( - "chrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomKeepAliveGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomKeepAliveGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomKeepAliveRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomKeepAliveRemove( - "chrm01", - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomUserWhitelistAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.ChatRoomUserWhitelistAdd( - "chrm01", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomUserWhitelistGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomUserWhitelistGetList( - "chrm01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomUserWhitelistRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomUserWhitelistRemove( - "chrm01", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomWhitelistAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - txtmsg := "RC:TxtMsg" - - err := rc.ChatRoomWhitelistAdd( - []string{txtmsg}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomWhitelistGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomWhitelistGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomWhitelistRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - txtmsg := "RC:TxtMsg" - err := rc.ChatRoomWhitelistRemove( - []string{txtmsg}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomMuteMembersAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomMuteMembersAdd( - "chrm01", - []string{"u01"}, - 30, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomMuteMembersGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.ChatRoomMuteMembersGetList( - "chrm01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_ChatRoomMuteMembersRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomGagRemove( - "chrm01", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomEntrySet(t *testing.T) { - rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) - - t.Logf("app key: %s; app secret: %s", os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) - - if err := rc.ChatRoomEntrySet("chrm01", "abc", "aaa", "bbb", false); err != nil { - t.Errorf("failed to chatroom entry set. err: %v", err) - } else { - t.Log("success") - } -} - -func TestRongCloud_ChatRoomEntryQuery(t *testing.T) { - rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) - - if data, err := rc.ChatRoomEntryQuery("chrm01", "aaa"); err != nil { - t.Errorf("err: %v", err) - } else { - t.Logf("data: %v", data) - } -} - -func TestRongCloud_ChatRoomEntryRemove(t *testing.T) { - rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) - - if err := rc.ChatRoomEntryRemove("chrm01", "abc", "aaa"); err != nil { - t.Errorf("failed to remove chatroom entry. err: %v", err) - } else { - t.Log("success") - } -} - -func TestRongCloud_ChatRoomQuery(t *testing.T) { - rc := NewRongCloud(os.Getenv("APP_KEY"), os.Getenv("APP_SECRET")) - - if data, err := rc.ChatRoomQuery([]string{"chrm01"}); err != nil { - t.Errorf("err: %v", err) - } else { - t.Logf("data: %v", data) - } -} - -func TestRongCloud_ChatRoomBanOptions(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBan( - "chrm01", - WithChatroomNeedNotify(true), - WithChatroomExtra("block all"), - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBanRollbackOptions(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomBanRollback( - "chrm01", - WithChatroomNeedNotify(true), - WithChatroomExtra("block all"), - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomBanQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - chatroomIds, err := rc.ChatRoomBanQuery(50, 1) - if err != nil { - t.Log(err) - } else { - t.Log(chatroomIds) - } -} - -func TestRongCloud_ChatRoomBanCheck(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - isBan, err := rc.ChatRoomBanCheck("chrm01") - if err != nil { - t.Log(err) - } else { - t.Log(isBan) - } -} - -func TestRongCloud_ChatRoomUserBanWhitelistAddOptions(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomUserBanWhitelistAdd( - "chrm01", - []string{"uu1", "uu2"}, - WithChatroomNeedNotify(true), - WithChatroomExtra("uu1,uu2"), - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomUserBanWhitelistRollbackOptions(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomUserBanWhitelistRollback( - "chrm01", - []string{"uu1", "uu2"}, - WithChatroomNeedNotify(true), - WithChatroomExtra("uu1,uu2"), - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomUserBanWhitelistQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - userIds, err := rc.ChatRoomUserBanWhitelistQuery("chrm01") - if err != nil { - t.Log(err) - } else { - t.Log(userIds) - } -} - -func TestRongCloud_ChatRoomCreateNew(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - // 销毁聊天室 - _ = rc.ChatRoomDestroy("chatroom001") - - // 创建聊天室 - whiteUserIds := []string{"111", "222", "333"} - err := rc.ChatRoomCreateNew( - "chatroom001", - WithChatroomDestroyType(1), - WithChatroomDestroyTime(120), - WithChatroomIsBan(true), - WithChatroomWhiteUserIds(whiteUserIds), - ) - t.Log(err) - - // 查询聊天室用户禁言白名单 - userIds, err := rc.ChatRoomUserBanWhitelistQuery("chatroom001") - t.Log(err) - t.Log(userIds) -} - -func TestRongCloud_ChatRoomDestroySet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.ChatRoomDestroySet( - "chatroom001", - 1, - 140, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomGetNew(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - chatRoom, err := rc.ChatRoomGetNew( - "chatroom001", - ) - t.Log(err) - t.Log(chatRoom) -} - -func TestRongCloud_ChatRoomEntryBatchSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - entryInfo := make(map[string]interface{}) - entryInfo["key1"] = "value1" - entryInfo["key2"] = "value2" - - err := rc.ChatRoomEntryBatchSet( - "chatroom001", - 0, - "user1", - entryInfo, - ) - t.Log(err) -} diff --git a/sdk/conversation.go b/sdk/conversation.go deleted file mode 100644 index dee9010..0000000 --- a/sdk/conversation.go +++ /dev/null @@ -1,411 +0,0 @@ -// Conversation 会话 - -package sdk - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "time" - - "github.com/astaxie/beego/httplib" -) - -// ConversationType 会话类型 -type ConversationType int - -const ( - PRIVATE ConversationType = iota + 1 // PRIVATE 二人会话 - DISCUSSION // DISCUSSION 讨论组会话 - GROUP // GROUP 群组会话 - CHATROOM // CHATROOM 聊天室会话 - CUSTOM // CUSTOM 客服会话 - SYSTEM // SYSTEM 系统通知 - APP_PUBLIC_SERVICE // APP_PUBLIC_SERVICE 应用公众服务 - PUBLIC_SERVICE // PUBLIC_SERVICE 公众服务 - ULTRA_GROUP // ULTRA_GROUP 超级群服务 - - ConversationTypePrivate ConversationType = 1 // ConversationTypePrivate 二人会话 - ConversationTypeGroup ConversationType = 3 // ConversationTypeGroup 群组会话 - ConversationTypeSystem ConversationType = 6 // ConversationTypeSystem 系统 - ConversationTypeUG ConversationType = 10 // ConversationTypeUG 超级群 - - ConversationUnPushLevelAllMessage = -1 // ConversationUnPushLevelAllMessage 全部消息通知 - ConversationUnPushLevelNotSet = 0 // ConversationUnPushLevelNotSet 未设置 - ConversationUnPushLevelAtMessage = 1 // ConversationUnPushLevelAtMessage 仅@消息通知 - ConversationUnPushLevelAtUser = 2 // ConversationUnPushLevelAtUser @指定用户通知 - ConversationUnPushLevelAtAllGroupMembers = 4 // ConversationUnPushLevelAtAllGroupMembers @群全员通知 - ConversationUnPushLevelNotRecv = 5 // ConversationUnPushLevelNotRecv 不接收通知 -) - -// ConversationTop :会话置顶 -//* -//@param userId :必传 用户ID,会话所属的用户 -//@param conversationType:不必传 会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)、6(系统会话)。 -//@param targetId: 必传 需要设置的目标 ID,根据会话类型不同为单聊用户 ID、群聊 ID、系统目标 ID -//@param setTop : 必传 true 表示置顶,false 表示取消置顶。 -// -//@return error -//*/ -func (rc *RongCloud) ConversationTop(conversationType ConversationType, userId, targetId, setTop string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(targetId) == 0 { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - if len(setTop) == 0 { - return RCErrorNew(1002, "Paramer 'setTop' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/conversation/top/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("conversationType", fmt.Sprintf("%v", conversationType)) - req.Param("targetId", targetId) - req.Param("setTop", setTop) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ConversationMute 设置用户某个会话屏蔽 Push -/* -*@param conversationType:会话类型 PRIVATE、GROUP、DISCUSSION、SYSTEM。 -*@param userID:设置用户 ID。 -*@param targetID:需要屏蔽的目标 ID。 -* -*@return error - */ -func (rc *RongCloud) ConversationMute(conversationType ConversationType, userID, targetID string, - options ...MsgOption) error { - - if conversationType == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if userID == "" { - return RCErrorNew(1002, "Paramer 'userID' is required") - } - - if targetID == "" { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/conversation/notification/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("requestId", userID) - req.Param("conversationType", fmt.Sprintf("%v", conversationType)) - req.Param("targetId", targetID) - req.Param("isMuted", "1") - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ConversationUnmute 设置用户某个会话接收 Push -/* -*@param conversationType:会话类型 PRIVATE、GROUP、DISCUSSION、SYSTEM。 -*@param userID:设置用户 ID。 -*@param targetID:需要屏蔽的目标 ID。 -* -*@return error - */ -func (rc *RongCloud) ConversationUnmute(conversationType ConversationType, userID, targetID string, - options ...MsgOption) error { - if conversationType == 0 { - return RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if userID == "" { - return RCErrorNew(1002, "Paramer 'userID' is required") - } - - if targetID == "" { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/conversation/notification/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("requestId", userID) - req.Param("conversationType", fmt.Sprintf("%v", conversationType)) - req.Param("targetId", targetID) - req.Param("isMuted", "0") - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ConversationGet 免打扰会话状态获取 -/* -*@param conversationType:会话类型 PRIVATE、GROUP、DISCUSSION、SYSTEM。 -*@param userID:设置用户 ID。 -*@param targetID:需要屏蔽的目标 ID。 -* -*@return int error - */ -func (rc *RongCloud) ConversationGet(conversationType ConversationType, userID, targetID string, - options ...MsgOption) (int, error) { - if conversationType == 0 { - return -1, RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if userID == "" { - return -1, RCErrorNew(1002, "Paramer 'userID' is required") - } - - if targetID == "" { - return -1, RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/conversation/notification/get." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("requestId", userID) - req.Param("conversationType", fmt.Sprintf("%v", conversationType)) - req.Param("targetId", targetID) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - response, err := req.Response() - if err != nil { - return -1, err - } - - rc.checkStatusCode(response) - - rep, err := req.Bytes() - if err != nil { - rc.urlError(err) - return -1, err - } - var code CodeResult - var isMuted int - _ = json.Unmarshal(rep, &struct { - *CodeResult - IsMuted *int `json:"isMuted"` - }{ - &code, - &isMuted, - }) - if code.Code != 200 { - return -1, code - } - return isMuted, nil -} - -// ConversationTypeNotificationSet 按会话类型设置免打扰, 用户设置指定会话类型(单聊、群聊、超级群、系统消息)的免打扰状态。 -func (rc *RongCloud) ConversationTypeNotificationSet(ct ConversationType, requestId string, unPushLevel int) error { - if ct != ConversationTypePrivate && ct != ConversationTypeGroup && ct != ConversationTypeSystem && ct != ConversationTypeUG { - return RCErrorNew(1002, "Paramer 'conversationType' was wrong") - } - - if requestId == "" { - return RCErrorNew(1002, "Paramer 'requestId' was wrong") - } - - if unPushLevel != ConversationUnPushLevelAllMessage && unPushLevel != ConversationUnPushLevelNotSet && unPushLevel != ConversationUnPushLevelAtMessage && - unPushLevel != ConversationUnPushLevelAtUser && unPushLevel != ConversationUnPushLevelAtAllGroupMembers && unPushLevel != ConversationUnPushLevelNotRecv { - return RCErrorNew(1002, "Paramer 'unPushLevel' was wrong") - } - - req := httplib.Post(rc.rongCloudURI + "/conversation/type/notification/set.json") - - req.Param("conversationType", strconv.Itoa(int(ct))) - req.Param("requestId", requestId) - req.Param("unpushLevel", strconv.Itoa(unPushLevel)) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - body, err := rc.do(req) - if err != nil { - return err - } - - resp := struct { - Code int `json:"code"` - }{} - if err = json.Unmarshal(body, &resp); err != nil { - return err - } - - if resp.Code != http.StatusOK { - return fmt.Errorf("Response error. code: %d", resp.Code) - } - - return nil -} - -// ConversationTypeNotificationGet 查询用户指定会话类型(单聊、群聊、超级群、系统消息)的免打扰状态。 -func (rc *RongCloud) ConversationTypeNotificationGet(ct ConversationType, requestId string) (int, error) { - if ct != ConversationTypePrivate && ct != ConversationTypeGroup && ct != ConversationTypeSystem && ct != ConversationTypeUG { - return 0, RCErrorNew(1002, "Paramer 'conversationType' was wrong") - } - - if requestId == "" { - return 0, RCErrorNew(1002, "Paramer 'requestId' was wrong") - } - - req := httplib.Post(rc.rongCloudURI + "/conversation/type/notification/get.json") - - req.Param("conversationType", strconv.Itoa(int(ct))) - req.Param("requestId", requestId) - - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - body, err := rc.do(req) - if err != nil { - return 0, err - } - - resp := struct { - Code int `json:"code"` - IsMuted int `json:"isMuted"` - }{} - if err = json.Unmarshal(body, &resp); err != nil { - return 0, err - } - - if resp.Code != http.StatusOK { - return 0, fmt.Errorf("Response error. code: %d", resp.Code) - } - - return resp.IsMuted, nil -} - -// ConversationNotificationSet 设置指定会话消息免打扰接口, 设置用户指定会话消息提醒状态 -func (rc *RongCloud) ConversationNotificationSet(ct ConversationType, requestId, targetId, busChannel string, isMuted, unPushLevel int) error { - if ct != ConversationTypePrivate && ct != ConversationTypeGroup && ct != ConversationTypeSystem && ct != ConversationTypeUG { - return RCErrorNew(1002, "Paramer 'conversationType' was wrong") - } - - if requestId == "" { - return RCErrorNew(1002, "Paramer 'requestId' was wrong") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' was wrong") - } - - if isMuted != 0 && isMuted != 1 { - return RCErrorNew(1002, "Paramer 'isMuted' was wrong") - } - - if unPushLevel != ConversationUnPushLevelAllMessage && unPushLevel != ConversationUnPushLevelNotSet && unPushLevel != ConversationUnPushLevelAtMessage && - unPushLevel != ConversationUnPushLevelAtUser && unPushLevel != ConversationUnPushLevelAtAllGroupMembers && unPushLevel != ConversationUnPushLevelNotRecv { - return RCErrorNew(1002, "Paramer 'unPushLevel' was wrong") - } - - req := httplib.Post(rc.rongCloudURI + "/conversation/notification/set.json") - - req.Param("conversationType", strconv.Itoa(int(ct))) - req.Param("requestId", requestId) - req.Param("targetId", targetId) - req.Param("isMuted", strconv.Itoa(isMuted)) - req.Param("unpushLevel", strconv.Itoa(unPushLevel)) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - body, err := rc.do(req) - if err != nil { - return err - } - - resp := struct { - Code int `json:"code"` - }{} - if err = json.Unmarshal(body, &resp); err != nil { - return err - } - - if resp.Code != http.StatusOK { - return fmt.Errorf("Response error. code: %d", resp.Code) - } - - return nil -} - -// ConversationNotificationGet 查询指定会话消息免打扰接口 -func (rc *RongCloud) ConversationNotificationGet(ct ConversationType, requestId, targetId, busChannel string) (int, error) { - if ct != ConversationTypePrivate && ct != ConversationTypeGroup && ct != ConversationTypeSystem && ct != ConversationTypeUG { - return 0, RCErrorNew(1002, "Paramer 'conversationType' was wrong") - } - - if requestId == "" { - return 0, RCErrorNew(1002, "Paramer 'requestId' was wrong") - } - - if targetId == "" { - return 0, RCErrorNew(1002, "Paramer 'targetId' was wrong") - } - - req := httplib.Post(rc.rongCloudURI + "/conversation/notification/get.json") - - req.Param("conversationType", strconv.Itoa(int(ct))) - req.Param("requestId", requestId) - req.Param("targetId", targetId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - body, err := rc.do(req) - if err != nil { - return 0, err - } - - resp := struct { - Code int `json:"code"` - IsMuted int `json:"isMuted"` - }{} - if err = json.Unmarshal(body, &resp); err != nil { - return 0, err - } - - if resp.Code != http.StatusOK { - return 0, fmt.Errorf("Response error. code: %d", resp.Code) - } - - return resp.IsMuted, nil -} diff --git a/sdk/conversation_test.go b/sdk/conversation_test.go deleted file mode 100644 index d2e0853..0000000 --- a/sdk/conversation_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestRongCloud_ConversationTop(t *testing.T) { - conversation := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := conversation.ConversationTop( - PRIVATE, - "u01", - "u02", - "true", - ) - t.Log(err) -} - -func TestRongCloud_ConversationMute(t *testing.T) { - conversation := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := conversation.ConversationMute( - PRIVATE, - "u01", - "u02", - ) - t.Log(err) - -} - -func TestRongCloud_ConversationUnmute(t *testing.T) { - conversation := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := conversation.ConversationMute( - PRIVATE, - "u01", - "u02", - ) - - t.Log(err) - -} - -func TestRongCloud_ConversationGet(t *testing.T) { - conversation := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - isMuted, err := conversation.ConversationGet( - PRIVATE, - "u01", - "u02") - - t.Log(err) - t.Log(isMuted) - -} diff --git a/sdk/error.go b/sdk/error.go deleted file mode 100644 index caa9776..0000000 --- a/sdk/error.go +++ /dev/null @@ -1,60 +0,0 @@ -package sdk - -import ( - "strconv" - "sync" -) - -var codePool = sync.Pool{ - New: func() interface{} { - return CodeResult{} - }, -} - -// CodeResult 融云返回状态码和错误码 -type CodeResult struct { - Code int `json:"code"` // 返回码,200 为正常。 - ErrorMessage string `json:"errorMessage"` // 错误信息 -} - -// RCErrorNew 创建新的err信息 -func RCErrorNew(code int, text string) error { - return CodeResult{code, text} -} - -// Error 获取错误信息 -func (e CodeResult) Error() string { - return strconv.Itoa(e.Code) + ": " + e.ErrorMessage -} - -// ErrorCode 获取错误码 -func (e CodeResult) ErrorCode() int { - return e.Code -} - -// api v2 error -var codePoolV2 = sync.Pool{ - New: func() interface{} { - return CodeResultV2{} - }, -} - -type CodeResultV2 struct { - Code int `json:"code"` // 返回码,10000 为正常。 - Message string `json:"msg"` // 错误信息 -} - -// RCErrorNew 创建新的err信息 -func RCErrorNewV2(code int, text string) error { - return CodeResultV2{code, text} -} - -// Error 获取错误信息 -func (e CodeResultV2) Error() string { - return strconv.Itoa(e.Code) + ": " + e.Message -} - -// ErrorCode 获取错误码 -func (e CodeResultV2) ErrorCode() int { - return e.Code -} diff --git a/sdk/error_test.go b/sdk/error_test.go deleted file mode 100644 index a132cdb..0000000 --- a/sdk/error_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package sdk - -import ( - "testing" -) - -func TestRCErrorNew(t *testing.T) { - t.Log(RCErrorNew(200, "")) -} - -func TestCodeResult_Code(t *testing.T) { - err := CodeResult{200, ""} - t.Log(err.ErrorCode()) -} - -func TestCodeResult_Error(t *testing.T) { - err := CodeResult{200, "rcerr"} - t.Log(err.Error()) -} diff --git a/sdk/group.go b/sdk/group.go deleted file mode 100644 index 130070d..0000000 --- a/sdk/group.go +++ /dev/null @@ -1,840 +0,0 @@ -package sdk - -import ( - "encoding/json" - "strconv" - "time" - - "github.com/astaxie/beego/httplib" -) - -// Group 群组信息 -type Group struct { - ID string `json:"id"` - Users []GroupUser `json:"users"` - Name string `json:"name"` - Stat string `json:"stat"` -} - -// GroupUser 群组用户信息 -type GroupUser struct { - ID string `json:"id"` - UserID string `json:"userId"` - Time string `json:"time"` -} - -// GroupInfo 群组信息 -type GroupInfo struct { - GroupInfo []Group `json:"groupinfo"` -} - -type GroupRemarksGetObj struct { - // 返回码,200 为正常。 - Code int `json:"code"` - - // 备注名称 - Remark string `json:"remark"` -} - -// GroupRemarksGetResObj :/group/remarks/get.json 查询群成员推送备注名 -//* -// @param : userId : 群成员用户 ID -// @param : groupId : 群ID -// response : byte数组 -// 文档: https://doc.rongcloud.cn/imserver/server/v1/group/get-remark-for-group-push -//*/ -func (rc *RongCloud) GroupRemarksGetResObj(userId string, groupId string) (GroupRemarksGetObj, error) { - var ( - result = GroupRemarksGetObj{} - ) - if len(userId) == 0 { - return result, RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(groupId) == 0 { - return result, RCErrorNew(1002, "Paramer 'groupId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/remarks/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("groupId", groupId) - req.Param("userId", userId) - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// GroupRemarksGet :/group/remarks/get.json 查询群成员推送备注名 -//* -// @param : userId : 群成员用户 ID -// @param : groupId : 群ID -// response : byte数组 -// 文档: https://doc.rongcloud.cn/imserver/server/v1/group/get-remark-for-group-push -//*/ -func (rc *RongCloud) GroupRemarksGet(userId string, groupId string) ([]byte, error) { - if len(userId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(groupId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'groupId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/remarks/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("groupId", groupId) - req.Param("userId", userId) - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// GroupRemarksDel :/group/remarks/del.json 删除群成员推送备注名 -//* -// @param : userId : 群成员用户 ID -// @param : groupId : 群ID -// -// -//*/ -func (rc *RongCloud) GroupRemarksDel(userId string, groupId string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(groupId) == 0 { - return RCErrorNew(1002, "Paramer 'groupId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/remarks/del.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("groupId", groupId) - req.Param("userId", userId) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupRemarksSet :/group/remarks/set.json 设置指定群成员推送备注 -//* -// @param : userId : 群成员用户ID -// @param : groupId : 群ID -// @param : remark : 群成员推送备注 -// -//*/ -func (rc *RongCloud) GroupRemarksSet(userId string, groupId string, remark string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(groupId) == 0 { - return RCErrorNew(1002, "Paramer 'groupId' is required") - } - if len(remark) == 0 { - return RCErrorNew(1002, "Paramer 'remark' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/remarks/set.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("groupId", groupId) - req.Param("userId", userId) - req.Param("remark", remark) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupUserGagAdd : 添加禁言成员 /group/user/gag/add.json -//* -// @param userId:用户 ID,每次添加最多不超过 20 个用户。 -// @param groupId: 群组 ID,为空时则设置用户在加入的所有群组中都不能发送消息。 -// @param minute : // 禁言时长,以分钟为单位,最大值为 43200 分钟,为 0 表示永久禁言。 -//*/ -func (rc *RongCloud) GroupUserGagAdd(userId string, groupId string, minute string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(minute) == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/add.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - if len(groupId) > 0 { - req.Param("groupId", groupId) - } - req.Param("userId", userId) - req.Param("minute", minute) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupUserQueryObj : GroupUserQueryResObj 的返回值 -type GroupUserQueryObj struct { - // 返回码,200 为正常 - Code int `json:"code"` - - // 用户加入的群信息数组。 - Groups []GroupUserQueryGroup `json:"groups"` -} - -type GroupUserQueryGroup struct { - // 群名称。 - Name string `json:"name"` - - // 群组 ID。 - Id string `json:"id"` -} - -// GroupUserQueryResObj : 根据用户 ID 查询该用户加入的所有群组,返回群组 ID 及群组名称。 -//* -// @param userId:用户 ID -// response: GroupUserQueryObj -// 文档: https://doc.rongcloud.cn/imserver/server/v1/group/query-group-by-user -//*/ -func (rc *RongCloud) GroupUserQueryResObj(userId string) (GroupUserQueryObj, error) { - var ( - result = GroupUserQueryObj{} - ) - if len(userId) == 0 { - return result, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/group/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// GroupUserQuery : 根据用户 ID 查询该用户加入的所有群组,返回群组 ID 及群组名称。 -//* -// @param userId:用户 ID -// 文档 : https://doc.rongcloud.cn/imserver/server/v1/group/query-group-by-user -//*/ -func (rc *RongCloud) GroupUserQuery(userId string) ([]byte, error) { - if len(userId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/group/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// GroupCreate 创建群组方法(创建群组,并将用户加入该群组,用户将可以收到该群的消息,同一用户最多可加入 500 个群,每个群最大至 3000 人,App 内的群组数量没有限制.注:其实本方法是加入群组方法 /group/join 的别名。) -/* - *@param id:群组 Id,最大长度 30 个字符,建议使用 英文字母、数字 混排 - *@param name:群组名称,最大长度 60 个字符 - *@param members:加入群组的用户列表 - * - *@return error - */ -func (rc *RongCloud) GroupCreate(id, name string, members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if name == "" { - return RCErrorNew(1002, "Paramer 'name' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/create." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - req.Param("groupName", name) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupSync 同步用户所属群组方法(当第一次连接融云服务器时,需要向融云服务器提交 ID 对应的用户当前所加入的所有群组,此接口主要为防止应用中用户群信息同融云已知的用户所属群信息不同步。) -/* - *@param id:被同步群信息的用户 ID。(必传) - *@param groups:用户所在群组列表。 - * - *@return error - */ -func (rc *RongCloud) GroupSync(id string, groups []Group) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(groups) == 0 { - return RCErrorNew(1002, "Paramer 'groups' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/sync." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("userId", id) - for _, item := range groups { - req.Param("group["+item.ID+"]", item.Name) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupUpdate 刷新群组信息方法 -/* -*@param id:群组 Id。 -*@param name:群名称。 -* -*@return error - */ -func (rc *RongCloud) GroupUpdate(id, name string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if name == "" { - return RCErrorNew(1002, "Paramer 'name' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/refresh." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", id) - req.Param("groupName", name) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupJoin 批量将用户加入指定群组,用户将可以收到该群的消息。 -/* - *@param groupId:加入的群组 Id。 - *@param groupName:群组名称,最大长度 60 个字符。 - *@param memberId:要加入群组的用户,最大不超过1000人。 - * - *@return error - */ -func (rc *RongCloud) GroupJoin(groupId, groupName string, memberId ...string) error { - if len(groupId) == 0 { - return RCErrorNew(1002, "Paramer 'id' is required") - } - if len(memberId) == 0 { - return RCErrorNew(1002, "Paramer 'member' is required") - } - if len(memberId) > 1000 { - return RCErrorNew(1002, "Paramer 'member' More than 1000") - } - req := httplib.Post(rc.rongCloudURI + "/group/join." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for k := range memberId { - req.Param("userId", memberId[k]) - } - req.Param("groupId", groupId) - if len(groupName) > 0 { - req.Param("groupName", groupName) - } - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupGet 查询群成员方法 -/* - *@param id:群组Id。 - * - *@return Group error - */ -func (rc *RongCloud) GroupGet(id string) (Group, error) { - if id == "" { - return Group{}, RCErrorNew(1002, "Paramer 'id' is required") - } - req := httplib.Post(rc.rongCloudURI + "/group/user/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return Group{}, err - } - var dat Group - if err := json.Unmarshal(resp, &dat); err != nil { - return Group{}, err - } - return dat, nil - -} - -// GroupQuit 批量退出群组方法(将用户从群中移除,不再接收该群组的消息.) -/* - *@param id:要退出的群组 Id。 - *@param member:要退出群组的群成员,最多不能超过1000人。 - * - *@return error - */ -func (rc *RongCloud) GroupQuit(member []string, id string) error { - if len(member) == 0 { - return RCErrorNew(1002, "Paramer 'member' is required") - } - if len(member) > 1000 { - return RCErrorNew(1002, "Paramer 'member' More than 1000") - } - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/quit." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for k := range member { - req.Param("userId", member[k]) - } - req.Param("groupId", id) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupDismiss 解散群组方法 -/* - *@param id:群组 ID,最大长度 30 个字符,建议使用 英文字母、数字 混排 - *@param member:群主或群管理. - * - *@return error - */ -func (rc *RongCloud) GroupDismiss(id, member string) error { - if member == "" { - return RCErrorNew(1002, "Paramer 'member' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/dismiss." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("userId", member) - req.Param("groupId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupGagAdd 添加禁言群成员方法(在 App 中如果不想让某一用户在群中发言时,可将此用户在群组中禁言,被禁言用户可以接收查看群组中用户聊天信息,但不能发送消息。) -/* -*@param id:群组 ID。 -*@param members:禁言群成员列表。 -*@param minute:禁言时长,以分钟为单位,最大值为43200分钟。 -* -*@return error - */ -func (rc *RongCloud) GroupGagAdd(id string, members []string, minute int) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - req.Param("minute", strconv.Itoa(minute)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteMembersAdd 添加禁言群成员方法(在 App 中如果不想让某一用户在群中发言时,可将此用户在群组中禁言,被禁言用户可以接收查看群组中用户聊天信息,但不能发送消息。) -/* -*@param id:群组 ID。 -*@param members:禁言群成员列表。 -*@param minute:禁言时长,以分钟为单位,最大值为43200分钟。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteMembersAdd(id string, members []string, minute int) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if minute == 0 { - return RCErrorNew(1002, "Paramer 'minute' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - req.Param("minute", strconv.Itoa(minute)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupGagList 查询被禁言群成员方法 -/* -*@param id:群组ID。 -* -*@return Group error - */ -func (rc *RongCloud) GroupGagList(id string) (Group, error) { - if id == "" { - return Group{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return Group{}, err - } - var dat Group - if err := json.Unmarshal(resp, &dat); err != nil { - return Group{}, err - } - return dat, nil -} - -// GroupMuteMembersGetList 查询被禁言群成员方法 -/* -*@param id:群组ID。 -* -*@return Group error - */ -func (rc *RongCloud) GroupMuteMembersGetList(id string) (Group, error) { - if id == "" { - return Group{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return Group{}, err - } - var dat Group - if err := json.Unmarshal(resp, &dat); err != nil { - return Group{}, err - } - return dat, nil -} - -// GroupGagRemove 移除禁言群成员方法 -/* -*@param id:群组 Id。 -*@param members:解除禁言群成员列表 。 -* -*@return error - */ -func (rc *RongCloud) GroupGagRemove(id string, members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteMembersRemove 移除禁言群成员方法 -/* -*@param id:群组 Id。 -*@param members:解除禁言群成员列表 。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteMembersRemove(id string, members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/gag/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteAllMembersAdd 设置某一群组禁言,禁言后群组中所有成员禁止发送消息,如需要某些用户可以发言时,可将此用户加入到群禁言用户白名单中。 -/* -*@param members:禁言群成员列表。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteAllMembersAdd(members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/ban/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("groupId", item) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteAllMembersRemove 解除群组禁言 -/* -*@param members:禁言群成员列表。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteAllMembersRemove(members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/ban/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("groupId", item) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteAllMembersGetList 查询全部群组禁言列表 -/* -*@param id:群组ID。 -* -*@return Group error - */ -func (rc *RongCloud) GroupMuteAllMembersGetList(members []string) (GroupInfo, error) { - - req := httplib.Post(rc.rongCloudURI + "/group/ban/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - if len(members) > 0 { - for _, item := range members { - req.Param("groupId", item) - } - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return GroupInfo{}, err - } - var group GroupInfo - if err := json.Unmarshal(resp, &group); err != nil { - return GroupInfo{}, err - } - return group, nil -} - -// GroupMuteWhiteListUserAdd 在群组被禁言状态下,如果需要某些用户可以发言时,可将此用户加入到群组禁言用户白名单中。群禁言用户白名单,只有群组被设置为全部禁言时才会生效。 -/* -*@param id:群组 ID。 -*@param members:禁言群成员列表。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteWhiteListUserAdd(id string, members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/ban/whitelist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteWhiteListUserRemove 移除群禁言白名单用户。 -/* -*@param id:群组 ID。 -*@param members:禁言群成员列表。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteWhiteListUserRemove(id string, members []string) error { - if len(members) == 0 { - return RCErrorNew(1002, "Paramer 'members' is required") - } - - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/ban/whitelist/rollback." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - for _, item := range members { - req.Param("userId", item) - } - req.Param("groupId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupMuteWhiteListUserGetList 查询群禁言白名单用户列表。 -/* -*@param id:群组 ID。 -* -*@return error - */ -func (rc *RongCloud) GroupMuteWhiteListUserGetList(id string) ([]string, error) { - if id == "" { - return []string{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/group/user/ban/whitelist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return []string{}, err - } - var userIDs []string - if err := json.Unmarshal(resp, &struct { - UserIDs *[]string `json:"userids"` - }{ - &userIDs, - }); err != nil { - return []string{}, err - } - return userIDs, nil -} diff --git a/sdk/group_test.go b/sdk/group_test.go deleted file mode 100644 index ceda480..0000000 --- a/sdk/group_test.go +++ /dev/null @@ -1,393 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestRongCloud_GroupRemarksGetResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.GroupRemarksGetResObj( - "u02", - "1", - ); err != nil { - t.Error(err) - return - } else { - t.Logf(" suc :%+v", res) - } -} - -func TestRongCloud_GroupRemarksGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.GroupRemarksGet( - "u02", - "1", - ); err != nil { - t.Error(err) - return - } else { - t.Log(" suc", string(res)) - } -} - -func TestRongCloud_GroupRemarksDel(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.GroupRemarksDel( - "u02", - "1", - ); err != nil { - t.Error(err) - return - } - t.Log(" suc") -} - -func TestRongCloud_GroupRemarksSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.GroupRemarksSet( - "u02", - "1", - "1", - ); err != nil { - t.Error(err) - return - } - t.Log(" suc") -} - -func TestRongCloud_GroupUserGagAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.GroupUserGagAdd( - "u02", - "", - "1", - ); err != nil { - t.Error(err) - return - } - t.Log(" suc") - -} - -func TestRongCloud_GroupUserQueryResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - if res, err := rc.GroupUserQueryResObj( - "u02", - ); err != nil { - t.Error(err) - return - } else { - t.Logf("group user query suc,res is: %+v", res) - } -} - -func TestRongCloud_GroupUserQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - if res, err := rc.GroupUserQuery( - "u02", - ); err != nil { - t.Error(err) - return - } else { - t.Log("group user query suc,res is:", string(res)) - } -} - -func TestRongCloud_GroupCreate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupCreate( - "u02", - "rongcloud_group01", - []string{"u01", "u02"}, - ) - - t.Log(err) -} - -func TestRongCloud_GroupGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - rep, err := rc.GroupGet( - "u02", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_GroupJoin(t *testing.T) { - t.Log(os.Getenv("AppKey")) - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupJoin( - "u01", - "rongcloud_group01", - "u03", "u04", "u05", - ) - t.Log(err) - err = rc.GroupJoin( - "u01", - "", - "u03", "u04", "u05", - ) - t.Log(err) -} - -func TestRongCloud_GroupUpdate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupUpdate( - "u01", - "rongcloud_group02", - ) - t.Log(err) -} - -func TestRongCloud_GroupQuit(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupQuit( - []string{"u03", "u04"}, - "u01", - ) - t.Log(err) -} - -func TestRongCloud_GroupSync(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - group := Group{ID: "u02", Name: "rongcloud_group02"} - groups := []Group{} - groups = append(groups, group) - err := rc.GroupSync( - "u04", - groups, - ) - t.Log(err) -} - -func TestRongCloud_GroupGagAdd(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupGagAdd( - "u01", - []string{"u02"}, - 300, - ) - t.Log(err) -} - -func TestRongCloud_GROUPGagList(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - rep, err := rc.GroupGagList( - "u01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_GroupGagremove(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupGagRemove( - "u01", - []string{"u02"}, - ) - t.Log(err) -} - -func TestRongCloud_GroupDismiss(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupDismiss( - "u01", - "u01", - ) - t.Log(err) -} - -func TestRongCloud_GroupMuteAllMembersAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteAllMembersAdd( - []string{ - "group01", - "group02", - }) - t.Log(err) -} - -func TestRongCloud_GroupMuteAllMembersList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - group, err := rc.GroupMuteAllMembersGetList( - []string{ - "group01", - "group02", - }) - t.Log(err) - t.Log(group) -} - -func TestRongCloud_GroupMuteAllMembersRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteAllMembersRemove( - []string{ - "group01", - "group02", - }) - t.Log(err) -} - -func TestRongCloud_GroupGMuteMembersAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteMembersAdd( - "gourp01", - []string{ - "u01", - "u02", - }, - 30, - ) - t.Log(err) -} - -func TestRongCloud_GroupMuteMembersGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.GroupMuteMembersGetList( - "gourp01", - ) - if err != nil { - t.Error(err) - } - t.Log(rep) -} - -func TestRongCloud_GroupMuteMembersRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteMembersRemove( - "gourp01", - []string{ - "u01", - "u02", - }, - ) - t.Log(err) -} - -func TestRongCloud_GroupMuteWhiteListUserAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteWhiteListUserAdd( - "gourp01", - []string{ - "u01", - "u02", - }, - ) - t.Log(err) -} - -func TestRongCloud_GroupMuteWhiteListUserGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.GroupMuteWhiteListUserGetList( - "gourp01", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_GroupMuteWhiteListUserRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.GroupMuteWhiteListUserRemove( - "gourp01", - []string{ - "u01", - "u02", - }, - ) - t.Log(err) -} diff --git a/sdk/http.go b/sdk/http.go deleted file mode 100644 index 93a6f6f..0000000 --- a/sdk/http.go +++ /dev/null @@ -1,146 +0,0 @@ -package sdk - -import ( - "compress/gzip" - "encoding/json" - "io/ioutil" - "net" - "net/url" - "os" - "syscall" - - "github.com/astaxie/beego/httplib" -) - -func (rc *RongCloud) do(b *httplib.BeegoHTTPRequest) (body []byte, err error) { - return rc.httpRequest(b) -} - -// 需要切换域名的网络错误 -func isNetError(err error) bool { - netErr, ok := err.(net.Error) - if !ok { - return false - } - // 超时 - if netErr.Timeout() { - return true - } - - var opErr *net.OpError - opErr, ok = netErr.(*net.OpError) - if !ok { - // url 错误 - urlErr, ok := netErr.(*url.Error) - if !ok { - return false - } - opErr, ok = urlErr.Err.(*net.OpError) - if !ok { - return false - } - } - - switch t := opErr.Err.(type) { - case *net.DNSError: - return true - case *os.SyscallError: - if errno, ok := t.Err.(syscall.Errno); ok { - switch errno { - case syscall.ECONNREFUSED: - return true - case syscall.ETIMEDOUT: - return true - } - } - } - - return false -} - -func (rc *RongCloud) httpRequest(b *httplib.BeegoHTTPRequest) (body []byte, err error) { - // 使用全局 httpClient,解决 http 打开端口过多问题 - b.SetTransport(rc.globalTransport) - resp, err := b.DoRequest() - if err != nil { - if isNetError(err) { - rc.ChangeURI() - } - return nil, err - } - if resp.Body == nil { - return nil, nil - } - defer resp.Body.Close() - rc.checkStatusCode(resp) - if resp.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(resp.Body) - if err != nil { - return nil, err - } - body, err = ioutil.ReadAll(reader) - } else { - body, err = ioutil.ReadAll(resp.Body) - } - if err = checkHTTPResponseCode(body); err != nil { - return nil, err - } - return body, err -} - -// v2 api -func (rc *RongCloud) doV2(b *httplib.BeegoHTTPRequest) (body []byte, err error) { - // 使用全局 httpClient,解决 http 打开端口过多问题 - b.SetTransport(rc.globalTransport) - - resp, err := b.DoRequest() - if err != nil { - if isNetError(err) { - rc.ChangeURI() - } - return nil, err - } - if resp.Body == nil { - return nil, nil - } - defer resp.Body.Close() - rc.checkStatusCode(resp) - if resp.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(resp.Body) - if err != nil { - return nil, err - } - body, err = ioutil.ReadAll(reader) - } else { - body, err = ioutil.ReadAll(resp.Body) - } - if err = checkHTTPResponseCodeV2(body); err != nil { - return nil, err - } - return body, err -} - -func checkHTTPResponseCode(rep []byte) error { - code := codePool.Get().(CodeResult) - defer codePool.Put(code) - if err := json.Unmarshal(rep, &code); err != nil { - return err - } - if code.Code != 200 { - return code - } - return nil -} - -// v2 api error -func checkHTTPResponseCodeV2(rep []byte) error { - code := codePoolV2.Get().(CodeResultV2) - defer codePoolV2.Put(code) - if err := json.Unmarshal(rep, &code); err != nil { - return err - } - if code.Code != 10000 && code.Code != 200 { - return code - } - return nil -} diff --git a/sdk/message.go b/sdk/message.go deleted file mode 100644 index 95b7cfe..0000000 --- a/sdk/message.go +++ /dev/null @@ -1,1910 +0,0 @@ -/* - * @Descripttion: - * @version: - * @Author: ran.ding - * @Date: 2019-09-02 18:29:55 - * @LastEditors: ran.ding - * @LastEditTime: 2019-09-10 11:37:14 - */ -package sdk - -import ( - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/astaxie/beego/httplib" -) - -const ( - MessagePrivateType = 1 // MessagePrivateType 二人会话 - MessageGroupType = 3 // MessageGroupType 群组会话 -) - -// rcMsg rcMsg接口 -type rcMsg interface { - ToString() (string, error) -} - -// MsgUserInfo 融云内置消息用户信息 -type MsgUserInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Icon string `json:"icon"` - Portrait string `json:"portrait"` - Extra string `json:"extra"` -} - -// TXTMsg 消息 -type TXTMsg struct { - Content string `json:"content"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` -} - -// ImgMsg 消息 -type ImgMsg struct { - Content string `json:"content"` - User MsgUserInfo `json:"user"` - ImageURI string `json:"imageUri"` - Extra string `json:"extra"` -} - -// InfoNtf 消息 -type InfoNtf struct { - Message string `json:"message"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` -} - -// VCMsg 消息 -type VCMsg struct { - Content string `json:"content"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` - Duration interface{} `json:"duration"` -} - -// 高清语音消息 RC:HQVCMsg -type HQVCMsg struct { - LocalPath string `json:"localPath"` - RemoteUrl string `json:"remoteUrl"` - Duration interface{} `json:"duration"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` -} - -// IMGTextMsg 消息 -type IMGTextMsg struct { - Title string `json:"title"` - Content string `json:"content"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` - ImageUri string `json:"imageUri"` - URL string `json:"url"` -} - -// FileMsg 消息 -type FileMsg struct { - Name string `json:"name"` - Size string `json:"size"` - Type string `json:"type"` - FileURL string `json:"fileUrl"` - User MsgUserInfo `json:"user"` -} - -// LBSMsg 消息 -type LBSMsg struct { - Content string `json:"content"` - Extra string `json:"extra"` - POI string `json:"poi"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - User MsgUserInfo `json:"user"` -} - -// ProfileNtf 消息 -type ProfileNtf struct { - Operation string `json:"operation"` - Data string `json:"data"` - User MsgUserInfo `json:"user"` - Extra string `json:"extra"` -} - -// CMDNtf 消息 -type CMDNtf struct { - Name string `json:"operation"` - Data string `json:"data"` - User MsgUserInfo `json:"user"` -} - -// CMDMsg 消息 -type CMDMsg struct { - Name string `json:"name"` - Data string `json:"data"` - User MsgUserInfo `json:"user"` -} - -// ContactNtf 消息 -type ContactNtf struct { - Operation string `json:"operation"` - SourceUserID string `json:"sourceUserId"` - TargetUserID string `json:"targetUserId"` - Message string `json:"message"` - Extra string `json:"extra"` - User MsgUserInfo `json:"user"` -} - -// GrpNtf 消息 -type GrpNtf struct { - OperatorUserID string `json:"operatorUserId"` - Operation string `json:"operation"` - Data string `json:"data"` - Message string `json:"message"` - Extra string `json:"extra"` - User MsgUserInfo `json:"user"` -} - -// DizNtf 消息 -type DizNtf struct { - Type int `json:"type"` - Extension string `json:"extension"` - Operation string `json:"operation"` - User MsgUserInfo `json:"user"` -} - -// TemplateMsgContent 消息模版 -type TemplateMsgContent struct { - TargetID string - Data map[string]string - PushContent string - PushData string -} - -// MentionedInfo Mentioned -type MentionedInfo struct { - Type int `json:"type"` - UserIDs []string `json:"userIdList"` - PushContent string `json:"mentionedContent"` -} - -// MentionMsgContent MentionMsgContent -type MentionMsgContent struct { - Content string `json:"content"` - MentionedInfo MentionedInfo `json:"mentionedInfo"` -} - -// History History -type History struct { - URL string `json:"url"` -} - -// BroadcastRecallContent content of message broadcast recall -type BroadcastRecallContent struct { - MessageId string `json:"messageUId"` - ConversationType int `json:"conversationType"` - IsAdmin int `json:"isAdmin"` - IsDelete int `json:"isDelete"` -} - -// ChatRoomKVNotiMessage 聊天室属性通知消息 -type ChatRoomKVNotiMessage struct { - Type int `json:"type"` - Key string `json:"string"` - Value string `json:"value"` - Extra string `json:"extra"` -} - -// ToString ChatRoomKVNotiMessage -func (msg *ChatRoomKVNotiMessage) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - - return string(bytes), nil -} - -/** - * @name: ToString - * @test: - * @msg: 将广播消息撤回接口需要的 content 结构体参数转换为 json - * @param {type} - * @return: string error - */ -func (content *BroadcastRecallContent) ToString() (string, error) { - bytes, err := json.Marshal(content) - if err != nil { - return "", err - } - - return string(bytes), nil -} - -// ToString TXTMsg -func (msg *TXTMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString ImgMsg -func (msg *ImgMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString InfoNtf -func (msg *InfoNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString VCMsg -func (msg *VCMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString HQVCMsg -func (msg *HQVCMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString IMGTextMsg -func (msg *IMGTextMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString FileMsg -func (msg *FileMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString LBSMsg -func (msg *LBSMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString ProfileNtf -func (msg *ProfileNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString CMDNtf -func (msg *CMDNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString CMDMsg -func (msg *CMDMsg) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString ContactNtf -func (msg *ContactNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString GrpNtf -func (msg *GrpNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// ToString DizNtf -func (msg *DizNtf) ToString() (string, error) { - bytes, err := json.Marshal(msg) - if err != nil { - return "", err - } - return string(bytes), nil -} - -// msgOptions is extra options for sending messages -type msgOptions struct { - isMentioned int - contentAvailable int - verifyBlacklist int - expansion bool - disablePush bool - pushExt string - pushContent string - pushData string - busChannel string - isAdmin int - isDelete int - extraContent string - isCounted int -} - -// MsgOption 接口函数 -type MsgOption func(*msgOptions) - -// 是否为 @消息,0 表示为普通消息,1 表示为 @消息,默认为 0 -func WithMsgMentioned(isMentioned int) MsgOption { - return func(options *msgOptions) { - options.isMentioned = isMentioned - } -} - -// 针对 iOS 平台,对 SDK 处于后台暂停状态时为静默推送 -// iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行 -// 1 表示为开启,0 表示为关闭,默认为 0 -func WithMsgContentAvailable(contentAvailable int) MsgOption { - return func(options *msgOptions) { - options.contentAvailable = contentAvailable - } -} - -// 是否过滤发送人黑名单列表,0 为不过滤、 1 为过滤,默认为 0 不过滤。 -func WithMsgVerifyBlacklist(verifyBlacklist int) MsgOption { - return func(options *msgOptions) { - options.verifyBlacklist = verifyBlacklist - } -} - -// 是否为可扩展消息,默认为 false,设为 true 时终端在收到该条消息后,可对该条消息设置扩展信息。 -func WithMsgExpansion(isExpansion bool) MsgOption { - return func(options *msgOptions) { - options.expansion = isExpansion - } -} - -// disablePush Boolean 是否为静默消息,默认为 false,设为 true 时终端用户离线情况下不会收到通知提醒。 -func WithMsgDisablePush(isDisablePush bool) MsgOption { - return func(options *msgOptions) { - options.disablePush = isDisablePush - } -} - -// pushExt String 推送通知属性设置,详细查看 pushExt 结构说明,pushExt 为 JSON 结构请求时需要做转义处理。 -// disablePush 为 true 时此属性无效。 -func WithMsgPushExt(pushExt string) MsgOption { - return func(options *msgOptions) { - options.pushExt = pushExt - } -} - -// pushContent String 定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息。 -// 如果为自定义消息,则 pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。 -func WithMsgPushContent(pushContent string) MsgOption { - return func(options *msgOptions) { - options.pushContent = pushContent - } -} - -// pushData String 针对 iOS 平台为 Push 通知时附加到 payload 中,客户端获取远程推送内容时为 appData, -// 同时融云默认携带了消息基本信息,客户端可通过 'rc' 属性获取,Android 客户端收到推送消息时对应字段名为 pushData。 -func WithMsgPushData(pushData string) MsgOption { - return func(options *msgOptions) { - options.pushData = pushData - } -} - -// busChannel 创建子会话 -func WithMsgBusChannel(busChannel string) MsgOption { - return func(options *msgOptions) { - options.busChannel = busChannel - } -} - -// 是否为管理员,默认为 0,设为 1 时,IMKit 收到此条消息后,小灰条默认显示为“管理员 撤回了一条消息”。 -func WithIsAdmin(isAdmin int) MsgOption { - return func(options *msgOptions) { - options.isAdmin = isAdmin - } -} - -// 默认为 0 撤回该条消息同时,用户端将该条消息删除并替换为一条小灰条撤回提示消息;为 1 时,该条消息删除后,不替换为小灰条提示消息。 -func WithIsDelete(isDelete int) MsgOption { - return func(options *msgOptions) { - options.isDelete = isDelete - } -} - -// WithExtraContent 自定义的消息扩展信息,该字段接受 JSON 字符串格式的键值对(key-value pairs)。 -func WithExtraContent(extraContent string) MsgOption { - return func(options *msgOptions) { - options.extraContent = extraContent - } -} - -// WithMsgIsCounted 用户未在线时是否计入未读消息数。0 表示为不计数、1 表示为计数,默认为 1 -func WithMsgIsCounted(isCounted int) MsgOption { - return func(options *msgOptions) { - options.isCounted = isCounted - } -} - -// 修改默认值 -func modifyMsgOptions(options []MsgOption) msgOptions { - // 默认值 - defaultMsgOptions := msgOptions{ - isMentioned: 0, - contentAvailable: 0, - verifyBlacklist: 0, - expansion: false, - disablePush: false, - pushExt: "", - pushContent: "", - pushData: "", - busChannel: "", - isAdmin: 0, - isDelete: 0, - extraContent: "", - isCounted: 1, - } - - // 修改默认值 - for _, ext := range options { - ext(&defaultMsgOptions) - } - - return defaultMsgOptions -} - -// UgMessageExtension :根据消息 ID 批量获取超级群消息的扩展消息,可选填 -type UgMessageExtension struct { - // 频道 Id,支持英文字母、数字组合,最长为 20 个字符 - BusChannel string - - // 请求唯一标识,,保证一分钟之内的请求幂等 - MsgRandom int64 -} - -// MessageExpansionSet : 设置消息扩展 /message/expansion/set.json -//* -// @param msgUID:消息唯一标识 ID,可通过全量消息路由功能获取。详见全量消息路由。 -// @param userId:操作者用户 ID,即需要为指定消息(msgUID)设置扩展信息的用户 ID。 -// @param conversationType:会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)。 -// @param targetId:目标 ID,根据不同的 conversationType,可能是用户 ID 或群组 ID。 -// @param extraKeyVal:消息自定义扩展内容,JSON 结构,以 Key、Value 的方式进行设置,如:{"type":"3"},单条消息可设置 300 个扩展信息,一次最多可以设置 100 个。 -// @param isSyncSender:设置操作会生成“扩展操作消息”。该字段指定“扩展操作消息”的发送者是否可在客户端接收该消息。https://doc.rongcloud.cn/imserver/server/v1/message/expansion#set -//*/ -func (rc *RongCloud) MessageExpansionSet(msgUID, userId, conversationType, targetId, extraKeyVal string, isSyncSender int) error { - if len(msgUID) == 0 { - return RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if len(conversationType) == 0 { - return RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if len(targetId) == 0 { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if len(extraKeyVal) == 0 { - return RCErrorNew(1002, "Paramer 'extraKeyVal' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/expansion/set.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("conversationType", conversationType) - req.Param("targetId", targetId) - req.Param("extraKeyVal", extraKeyVal) - req.Param("isSyncSender", strconv.Itoa(isSyncSender)) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// MessageExpansionDel : 删除消息扩展 /message/expansion/delete.json -//* -// @param msgUID:消息唯一标识 ID,可通过全量消息路由功能获取。详见全量消息路由。 -// @param userId:操作者用户 ID,即需要为指定消息(msgUID)删除扩展信息的用户 ID。 -// @param conversationType:会话类型。支持的会话类型包括:1(二人会话)、3(群组会话)。 -// @param targetId:目标 ID,根据不同的 conversationType,可能是用户 ID 或群组 ID。 -// @param extraKeyVal:消息自定义扩展内容,JSON 结构,以 Key、Value 的方式进行设置,如:{"type":"3"},单条消息可设置 300 个扩展信息,一次最多可以设置 100 个。 -// @param isSyncSender:设置操作会生成“扩展操作消息”。该字段指定“扩展操作消息”的发送者是否可在客户端接收该消息。具体请看。https://doc.rongcloud.cn/imserver/server/v1/message/expansion#delete -//*/ -func (rc *RongCloud) MessageExpansionDel(msgUID, userId, conversationType, targetId, extraKey string, isSyncSender int) error { - if len(msgUID) == 0 { - return RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if len(conversationType) == 0 { - return RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if len(targetId) == 0 { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if len(extraKey) == 0 { - return RCErrorNew(1002, "Paramer 'extraKey' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/expansion/delete.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("conversationType", conversationType) - req.Param("targetId", targetId) - req.Param("extraKey", extraKey) - req.Param("isSyncSender", strconv.Itoa(isSyncSender)) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 超级群消息修改 - -// UGMessageModify : 超级群消息修改 /ultragroup/msg/modify.json -//* -// @param groupId:超级群 ID -// @param fromUserId:消息发送者 -// @param msgUID:消息唯一标识 -// @param content:消息所发送内容 最大128k -// @param busChannel:频道 Id,支持英文字母、数字组合,最长为 20 个字符 -// @param msgRandom:请求唯一标识,,保证一分钟之内的请求幂等 -//*/ -func (rc *RongCloud) UGMessageModify(groupId, fromUserId, msgUID, content string, options ...UgMessageExtension) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'groupId' is required") - } - - if len(fromUserId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'fromUserId' is required") - } - - if len(msgUID) == 0 { - return nil, RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if len(content) == 0 { - return nil, RCErrorNew(1002, "Paramer 'content' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/msg/modify.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("fromUserId", fromUserId) - req.Param("msgUID", msgUID) - req.Param("content", content) - - if len(options) == 1 { - req.Param("busChannel", options[0].BusChannel) - req.Param("msgRandom", fmt.Sprintf("%v", options[0].MsgRandom)) - } - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// UGMessageData :UGMessageGet方法中的消息参数数组 -type UGMessageData struct { - // 消息唯一标识 ID - MsgUid string `json:"msgUID"` - - // 频道 Id,支持英文字母、数字组合,最长为 20 个字符 - BusChannel string `json:"busChannel,omitempty"` -} - -type UGMessageGetData struct { - Code int `json:"code"` - Data []UGMessageGetDataList `json:"data"` -} - -type UGMessageGetDataList struct { - FromUserId string `json:"fromUserId"` - GroupId string `json:"groupId"` - SentTime uint64 `json:"sentTime"` - BusChannel string `json:"busChannel"` - MsgUid string `json:"msgUID"` - ObjectName string `json:"objectName"` - Content string `json:"content"` - Expansion bool `json:"expansion"` - ExtraContent string `json:"extraContent"` -} - -// UGMessageGetObj : 根据消息 ID 批量获取超级群消息 /ultragroup/msg/get -//* -// @param groupId:超级群 ID -// @param msgList:消息参数数组 每个元素是UGMessageData -// response: 返回结构体 -//*/ -func (rc *RongCloud) UGMessageGetObj(groupId string, msgList []UGMessageData, options ...MsgOption) (UGMessageGetData, error) { - respData := UGMessageGetData{} - if len(groupId) == 0 { - return respData, RCErrorNew(1002, "Paramer 'groupId' is required") - } - - if len(msgList) == 0 { - return respData, RCErrorNew(1002, "Paramer 'msgList' is required") - } - - msg, err := json.Marshal(msgList) - if err != nil { - return respData, err - } - extOptions := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/msg/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("msgs", string(msg)) - - if extOptions.busChannel != "" { - req.Param("busChannel", extOptions.busChannel) - } - res, err := rc.do(req) - if err != nil { - return respData, err - } - if err := json.Unmarshal(res, &respData); err != nil { - return respData, err - } - return respData, err -} - -// UGMessageGet : 根据消息 ID 批量获取超级群消息 /ultragroup/msg/get -//* -// @param groupId:超级群 ID -// @param msgList:消息参数数组 每个元素是UGMessageData -// response: 返回byte数组 -//*/ -func (rc *RongCloud) UGMessageGet(groupId string, msgList []UGMessageData, options ...MsgOption) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'groupId' is required") - } - - if len(msgList) == 0 { - return nil, RCErrorNew(1002, "Paramer 'msgList' is required") - } - - msg, err := json.Marshal(msgList) - if err != nil { - return nil, err - } - extOptions := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/msg/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("msgs", string(msg)) - - if extOptions.busChannel != "" { - req.Param("busChannel", extOptions.busChannel) - } - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// UGMessageRecall 超级群消息撤回 -func (rc *RongCloud) UGMessageRecall(userId, targetId, messageId string, sentTime int, options ...MsgOption) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if messageId == "" { - return RCErrorNew(1002, "Paramer 'messageId' is required") - } - - if sentTime == 0 { - return RCErrorNew(1002, "Paramer 'sentTime' is required") - } - - extOptions := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/recall." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("fromUserId", userId) - req.Param("conversationType", strconv.Itoa(10)) - req.Param("targetId", targetId) - req.Param("messageUID", messageId) - req.Param("sentTime", strconv.Itoa(sentTime)) - req.Param("disablePush", strconv.FormatBool(extOptions.disablePush)) - req.Param("isAdmin", strconv.Itoa(extOptions.isAdmin)) - req.Param("isDelete", strconv.Itoa(extOptions.isDelete)) - - if extOptions.busChannel != "" { - req.Param("busChannel", extOptions.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: MessageBroadcastRecall - * @test: - * @msg:广播消息撤回 - * @param string userId - * @param string objectName - * @param BroadcastRecallContent content - * @return: error - */ -func (rc *RongCloud) MessageBroadcastRecall(userId string, objectName string, content BroadcastRecallContent) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if objectName == "" { - return RCErrorNew(1002, "Paramer 'objectName' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/broadcast." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", userId) - req.Param("objectName", objectName) - - msg, err := content.ToString() - if err != nil { - return err - } - req.Param("content", msg) - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: ChatRoomRecall - * @test: - * @msg: 消息撤回 - 聊天室 - * @param string userId - * @param string targetId - * @param string messageId - * @param int sentTime - * @param int isAdmin - * @param int isDelete - * @param bool disablePush - * @return: error - */ -func (rc *RongCloud) ChatRoomRecall(userId string, targetId string, messageId string, sentTime int, - options ...MsgOption) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if messageId == "" { - return RCErrorNew(1002, "Paramer 'messageId' is required") - } - - if sentTime == 0 { - return RCErrorNew(1002, "Paramer 'sentTime' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/recall." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("fromUserId", userId) - req.Param("conversationType", strconv.Itoa(4)) - req.Param("targetId", targetId) - req.Param("messageUID", messageId) - req.Param("sentTime", strconv.Itoa(sentTime)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - req.Param("isAdmin", strconv.Itoa(extraOptins.isAdmin)) - req.Param("isDelete", strconv.Itoa(extraOptins.isDelete)) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: SystemRecall - * @test: - * @msg: 消息撤回 - 系统会话 - * @param string userId - * @param string targetId - * @param string messageId - * @param int sentTime - * @param int isAdmin - * @param int isDelete - * @param bool disablePush - * @return: error - */ -func (rc *RongCloud) SystemRecall(userId string, targetId string, messageId string, sentTime int, - options ...MsgOption) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if messageId == "" { - return RCErrorNew(1002, "Paramer 'messageId' is required") - } - - if sentTime == 0 { - return RCErrorNew(1002, "Paramer 'sentTime' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/recall." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("fromUserId", userId) - req.Param("conversationType", strconv.Itoa(6)) - req.Param("targetId", targetId) - req.Param("messageUID", messageId) - req.Param("sentTime", strconv.Itoa(sentTime)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - req.Param("isAdmin", strconv.Itoa(extraOptins.isAdmin)) - req.Param("isDelete", strconv.Itoa(extraOptins.isDelete)) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// PrivateSend 发送单聊消息方法(一个用户向多个用户发送消息,单条消息最大 128k。每分钟最多发送 6000 条信息,每次发送用户上限为 1000 人,如:一次发送 1000 人时,示为 1000 条消息。) -/* - *@param senderID:发送人用户 ID。 - *@param targetID:接收用户 ID。可以实现向多人发送消息,每次上限为 1000 人。 - *@param objectName:发送的消息类型。 - *@param msg:消息内容。 - *@param pushContent:定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息。如果为自定义消息,则 pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。 - *@param pushData:针对 iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。 - *@param count:针对 iOS 平台,Push 时用来控制未读消息显示数,只有在 toUserId 为一个用户 Id 的时候有效。 - *@param verifyBlacklist:是否过滤发送人黑名单列表,0 表示为不过滤、 1 表示为过滤,默认为 0 不过滤。 - *@param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0 表示为不存储、 1 表示为存储,默认为 1 存储消息。 - *@param isIncludeSender:发送用户自已是否接收消息,0 表示为不接收,1 表示为接收,默认为 0 不接收。 - *@param contentAvailable:针对 iOS 平台,对 SDK 处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行,查看详细。1 表示为开启,0 表示为关闭,默认为 0。 - *@param options 发送消息需要用的其他扩展参数 - * - *@return error - */ -func (rc *RongCloud) PrivateSend(senderID string, targetID []string, objectName string, msg rcMsg, - pushContent, pushData string, count, verifyBlacklist, isPersisted, isIncludeSender, contentAvailable int, - options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/private/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toUserId", v) - } - req.Param("objectName", objectName) - - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - req.Param("pushData", pushData) - req.Param("pushContent", pushContent) - req.Param("count", strconv.Itoa(count)) - req.Param("verifyBlacklist", strconv.Itoa(verifyBlacklist)) - req.Param("isPersisted", strconv.Itoa(isPersisted)) - req.Param("contentAvailable", strconv.Itoa(contentAvailable)) - req.Param("isIncludeSender", strconv.Itoa(isIncludeSender)) - req.Param("expansion", strconv.FormatBool(extraOptins.expansion)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - req.Param("isCounted", strconv.Itoa(extraOptins.isCounted)) - - if !extraOptins.disablePush && extraOptins.pushExt != "" { - req.Param("pushExt", extraOptins.pushExt) - } - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - if extraOptins.expansion && extraOptins.extraContent != "" { - req.Param("extraContent", extraOptins.extraContent) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 私聊状态消息发送 -// senderID: 发送人用户 ID。 -// targetID: 接收用户 ID,支持向多人发送消息,每次上限为 1000 人。 -// objectName: 消息类型 -// msg: 所发送消息的内容 -// verifyBlacklist: 是否过滤发送人黑名单列表,0 表示为不过滤、 1 表示为过滤,默认为 0 不过滤。 -// isIncludeSender: 发送用户自己是否接收消息,0 表示为不接收,1 表示为接收,默认为 0 不接收。 -func (rc *RongCloud) PrivateStatusSend(senderID string, targetID []string, objectName string, msg rcMsg, - verifyBlacklist int, isIncludeSender int, options ...MsgOption) error { - - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/statusmessage/private/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toUserId", v) - } - req.Param("objectName", objectName) - - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - req.Param("verifyBlacklist", strconv.Itoa(verifyBlacklist)) - req.Param("isIncludeSender", strconv.Itoa(isIncludeSender)) - req.Param("isCounted", strconv.Itoa(extraOptins.isCounted)) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// PrivateRecall 撤回单聊消息方法 -/* -* -*@param senderID:发送人用户 ID。 -*@param targetID:接收用户 ID。 -*@param uID:消息的唯一标识,各端 SDK 发送消息成功后会返回 uID。 -*@param sentTime:消息的发送时间,各端 SDK 发送消息成功后会返回 sentTime。 -* @param int isAdmin -* @param int isDelete -* @param bool disablePush -*@return error - */ -func (rc *RongCloud) PrivateRecall(senderID, targetID, uID string, sentTime int, - options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if targetID == "" { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/recall." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - req.Param("targetId", targetID) - req.Param("messageUID", uID) - req.Param("sentTime", strconv.Itoa(sentTime)) - req.Param("conversationType", strconv.Itoa(1)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - req.Param("isAdmin", strconv.Itoa(extraOptins.isAdmin)) - req.Param("isDelete", strconv.Itoa(extraOptins.isDelete)) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// PrivateSendTemplate 向多个用户发送不同内容消息 -/* - *@param senderID:发送人用户 ID。 - *@param objectName:发送的消息类型。 - *@param template:消息模版。 - *@param content:数据内容,包含消息内容和接收者。 - *@param options 发送消息需要用的其他扩展参数 - * - *@return error - */ -func (rc *RongCloud) PrivateSendTemplate(senderID, objectName string, template TXTMsg, content []TemplateMsgContent, - options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/private/publish_template." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - var toUserIDs, push, pushData []string - var values []map[string]string - - for _, v := range content { - if v.TargetID == "" { - return RCErrorNew(1002, "Paramer 'TargetID' is required") - } - toUserIDs = append(toUserIDs, v.TargetID) - values = append(values, v.Data) - push = append(push, v.PushContent) - pushData = append(pushData, v.PushData) - } - - bytes, err := json.Marshal(template) - if err != nil { - return err - } - - param := map[string]interface{}{} - param["fromUserId"] = senderID - param["objectName"] = objectName - param["content"] = string(bytes) - param["toUserId"] = toUserIDs - param["values"] = values - param["pushContent"] = push - param["pushData"] = pushData - param["verifyBlacklist"] = extraOptins.verifyBlacklist - param["contentAvailable"] = extraOptins.contentAvailable - param["disablePush"] = extraOptins.disablePush - param["isCounted"] = extraOptins.isCounted - - if extraOptins.busChannel != "" { - param["busChannel"] = extraOptins.busChannel - } - - req, err = req.JSONBody(param) - if err != nil { - return err - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupSend 发送群组消息方法(以一个用户身份向群组发送消息,单条消息最大 128k.每秒钟最多发送 20 条消息,每次最多向 3 个群组发送,如:一次向 3 个群组发送消息,示为 3 条消息。) -/* - *@param senderID:发送人用户 ID 。 - *@param targetID:接收群ID. - *@param objectName:消息类型。 - *@param userID:群定向消群定向消息功能,向群中指定的一个或多个用户发送消息,群中其他用户无法收到该消息,当 targetID 为一个群组时此参数有效。注:如果开通了“单群聊消息云存储”功能,群定向消息不会存储到云端,向群中部分用户发送消息阅读状态回执时可使用此功能。(可选) - *@param msg:发送消息内容 - *@param pushContent:定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息. 如果为自定义消息,则 pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。 - *@param pushData:针对 iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。 - *@param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0 表示为不存储、 1 表示为存储,默认为 1 存储消息。 - *@param isIncludeSender:发送用户自已是否接收消息,0 表示为不接收,1 表示为接收,默认为 0 不接收。 - *@param options 发送消息需要用的其他扩展参数 - * - *@return error - */ -func (rc *RongCloud) GroupSend(senderID string, targetID, userID []string, objectName string, msg rcMsg, - pushContent string, pushData string, isPersisted, isIncludeSender int, options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/group/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toGroupId", v) - } - req.Param("objectName", objectName) - msgr, err := msg.ToString() - if err != nil { - rc.urlError(err) - return err - } - req.Param("content", msgr) - req.Param("pushContent", pushContent) - req.Param("pushData", pushData) - req.Param("isPersisted", strconv.Itoa(isPersisted)) - req.Param("isIncludeSender", strconv.Itoa(isIncludeSender)) - req.Param("isMentioned", strconv.Itoa(extraOptins.isMentioned)) - req.Param("contentAvailable", strconv.Itoa(extraOptins.contentAvailable)) - req.Param("expansion", strconv.FormatBool(extraOptins.expansion)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - - if !extraOptins.disablePush && extraOptins.pushExt != "" { - req.Param("pushExt", extraOptins.pushExt) - } - - if len(userID) > 0 { - for _, v := range userID { - req.Param("toUserId", v) - } - } - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - if extraOptins.expansion && extraOptins.extraContent != "" { - req.Param("extraContent", extraOptins.extraContent) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 群聊状态消息发送 -// senderID: 发送人用户 ID。 -// toGroupIds: 接收群ID,提供多个本参数可以实现向多群发送消息,最多不超过 3 个群组。 -// objectName: 消息类型 -// msg: 所发送消息的内容 -// verifyBlacklist: 是否过滤发送人黑名单列表,0 表示为不过滤、 1 表示为过滤,默认为 0 不过滤。 -// isIncludeSender: 发送用户自己是否接收消息,0 表示为不接收,1 表示为接收,默认为 0 不接收。 -func (rc *RongCloud) GroupStatusSend(senderID string, toGroupIds []string, objectName string, msg rcMsg, - verifyBlacklist int, isIncludeSender int, options ...MsgOption) error { - - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(toGroupIds) == 0 { - return RCErrorNew(1002, "Paramer 'toGroupIds' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/statusmessage/group/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range toGroupIds { - req.Param("toGroupId", v) - } - req.Param("objectName", objectName) - - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - req.Param("verifyBlacklist", strconv.Itoa(verifyBlacklist)) - req.Param("isIncludeSender", strconv.Itoa(isIncludeSender)) - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupRecall 撤回群聊消息 -/* -*@param senderID:发送人用户 ID。 -*@param targetID:接收用户 ID。 -*@param uID:消息的唯一标识,各端 SDK 发送消息成功后会返回 uID。 -*@param sentTime:消息的发送时间,各端 SDK 发送消息成功后会返回 sentTime。 -* @param int isAdmin -* @param int isDelete -* @param bool disablePush -*@return error - */ -func (rc *RongCloud) GroupRecall(senderID, targetID, uID string, sentTime int, - options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if targetID == "" { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/recall." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - req.Param("targetId", targetID) - req.Param("messageUID", uID) - req.Param("sentTime", strconv.Itoa(sentTime)) - req.Param("conversationType", strconv.Itoa(3)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - req.Param("isAdmin", strconv.Itoa(extraOptins.isAdmin)) - req.Param("isDelete", strconv.Itoa(extraOptins.isDelete)) - - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// GroupSendMention 发送群组 @ 消息 -/* -*@param senderID:发送人用户 ID 。 -*@param targetID:接收群ID,最多不超过 3 个群组。 -*@param objectName:消息类型。 -*@param msg:发送消息内容。 -*@param pushContent:定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息. 如果为自定义消息,则 pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。 -*@param pushData:针对 iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。 -*@param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0 表示为不存储、 1 表示为存储,默认为 1 存储消息。 -*@param isIncludeSender:发送用户自已是否接收消息,0 表示为不接收,1 表示为接收,默认为 0 不接收。 -*@param isMentioned:是否为 @消息,0 表示为普通消息,1 表示为 @消息,默认为 0。当为 1 时 content 参数中必须携带 mentionedInfo @消息的详细内容。为 0 时则不需要携带 mentionedInfo。当指定了 toUserId 时,则 @ 的用户必须为 toUserId 中的用户。 -*@param contentAvailable:针对 iOS 平台,对 SDK 处于后台暂停状态时为静默推送,是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行,查看详细。1 表示为开启,0 表示为关闭,默认为 0 -* -*@return error - */ -func (rc *RongCloud) GroupSendMention(senderID string, targetID []string, objectName string, msg MentionMsgContent, - pushContent, pushData string, isPersisted, isIncludeSender, isMentioned, contentAvailable int, options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 && len(targetID) > 3 { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/group/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toGroupId", v) - } - req.Param("objectName", objectName) - - bytes, err := json.Marshal(msg) - if err != nil { - return err - } - req.Param("content", string(bytes)) - req.Param("pushContent", pushContent) - req.Param("pushData", pushData) - req.Param("isPersisted", strconv.Itoa(isPersisted)) - req.Param("isIncludeSender", strconv.Itoa(isIncludeSender)) - req.Param("isMentioned", strconv.Itoa(isMentioned)) - req.Param("contentAvailable", strconv.Itoa(contentAvailable)) - req.Param("expansion", strconv.FormatBool(extraOptins.expansion)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - if !extraOptins.disablePush && extraOptins.pushExt != "" { - req.Param("pushExt", extraOptins.pushExt) - } - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomSend 发送聊天室消息方法。(以一个用户身份向群组发送消息,单条消息最大 128k.每秒钟最多发送 20 条消息,每次最多向 3 个群组发送,如:一次向 3 个群组发送消息,示为 3 条消息。) -/* -*@param senderID:发送人用户 ID 。 -*@param targetID:接收聊天室ID, 建议最多不超过 10 个聊天室。 -*@param objectName:消息类型 -*@param msg:发送消息内容 -* -*@return error - */ -func (rc *RongCloud) ChatRoomSend(senderID string, targetID []string, objectName string, msg rcMsg, isPersisted, isIncludeSender int) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/chatroom/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toChatroomId", v) - } - req.Param("objectName", objectName) - req.Param("isPersisted", fmt.Sprint(isPersisted)) - - if isIncludeSender > 0 { - req.Param("isIncludeSender", fmt.Sprint(isIncludeSender)) - } - - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// ChatRoomBroadcast 向应用内所有聊天室广播消息方法,此功能需开通 专属服务(以一个用户身份向群组发送消息,单条消息最大 128k.每秒钟最多发送 20 条消息。) -/* -*@param senderID:发送人用户 ID 。 -*@param objectName:消息类型 -*@param msg:发送消息内容 -* @param isIncludeSender:0或者1 -*@return error - */ -func (rc *RongCloud) ChatRoomBroadcast(senderID, objectName string, msg rcMsg, isIncludeSender ...string) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/chatroom/broadcast." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - req.Param("objectName", objectName) - if len(isIncludeSender) > 0 { - req.Param("isIncludeSender", isIncludeSender[0]) - } - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// 在线广播消息 -// 是指系统向 App 中所有在线用户发送消息的行为。当用户正在使用 App 时,消息会展示在聊天界面和会话列表界面,会话类型为 SYSTEM。 -// @param fromUserId 发送人用户 Id -// @param objectName 消息类型, -// @param content 发送消息内容 -func (rc *RongCloud) OnlineBroadcast(fromUserId string, objectName string, content string) ([]byte, error) { - - if fromUserId == "" { - return nil, RCErrorNew(1002, "Paramer 'fromUserId' is required") - } - if objectName == "" { - return nil, RCErrorNew(1002, "Paramer 'objectName' is required") - } - if content == "" { - return nil, RCErrorNew(1002, "Paramer 'content' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/message/online/broadcast." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", fromUserId) - req.Param("objectName", objectName) - req.Param("content", content) - - code, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - - return code, err -} - -// SystemSend 一个用户向一个或多个用户发送系统消息,单条消息最大 128k,会话类型为 SYSTEM。 -/* -*@param senderID:发送人用户 ID。 -*@param targetID:接收用户 ID, 上限为 100 人。 -*@param objectName:发送的消息类型。 -*@param msg:消息。 -*@param pushContent:定义显示的 Push 内容,如果 objectName 为融云内置消息类型时,则发送后用户一定会收到 Push 信息。如果为自定义消息,则 pushContent 为自定义消息显示的 Push 内容,如果不传则用户不会收到 Push 通知。 -*@param pushData:针对 iOS 平台为 Push 通知时附加到 payload 中,Android 客户端收到推送消息时对应字段名为 pushData。 -*@param count:针对 iOS 平台,Push 时用来控制未读消息显示数,只有在 toUserId 为一个用户 Id 的时候有效。 -*@param isPersisted:当前版本有新的自定义消息,而老版本没有该自定义消息时,老版本客户端收到消息后是否进行存储,0 表示为不存储、 1 表示为存储,默认为 1 存储消息。 -*@param options 发送消息需要用的其他扩展参数 - -* -*@return error - */ -func (rc *RongCloud) SystemSend(senderID string, targetID []string, objectName string, msg rcMsg, - pushContent, pushData string, count, isPersisted int, options ...MsgOption) error { - - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - if len(targetID) == 0 { - return RCErrorNew(1002, "Paramer 'targetID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/system/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - for _, v := range targetID { - req.Param("toUserId", v) - } - req.Param("objectName", objectName) - msgr, err := msg.ToString() - if err != nil { - return err - } - - req.Param("content", msgr) - req.Param("pushData", pushData) - req.Param("pushContent", pushContent) - req.Param("count", strconv.Itoa(count)) - req.Param("isPersisted", strconv.Itoa(isPersisted)) - req.Param("contentAvailable", strconv.Itoa(extraOptins.contentAvailable)) - req.Param("disablePush", strconv.FormatBool(extraOptins.disablePush)) - if !extraOptins.disablePush && extraOptins.pushExt != "" { - req.Param("pushExt", extraOptins.pushExt) - } - if extraOptins.busChannel != "" { - req.Param("busChannel", extraOptins.busChannel) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// SystemBroadcast 给应用内所有用户发送消息方法,每小时最多发 2 次,每天最多发送 3 次(以一个用户身份向群组发送消息,单条消息最大 128k.每秒钟最多发送 20 条消息。) -/* -*@param senderID:发送人用户 ID 。 -*@param objectName:消息类型 -*@param msg:发送消息内容 -* -*@return error - */ -func (rc *RongCloud) SystemBroadcast(senderID, objectName string, msg rcMsg, options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/broadcast." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("fromUserId", senderID) - req.Param("objectName", objectName) - msgr, err := msg.ToString() - if err != nil { - return err - } - req.Param("content", msgr) - - if extraOptins.pushContent != "" { - req.Param("pushContent", extraOptins.pushContent) - } - if extraOptins.pushData != "" { - req.Param("pushData", extraOptins.pushData) - } - req.Param("contentAvailable", strconv.Itoa(extraOptins.contentAvailable)) - if extraOptins.pushExt != "" { - req.Param("pushExt", extraOptins.pushExt) - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// SystemSendTemplate 一个用户向一个或多个用户发送系统消息,单条消息最大 128k,会话类型为 SYSTEM -/* -*@param senderID:发送人用户 ID。 -*@param objectName:发送的消息类型。 -*@param template:消息模版。 -*@param content:数据内容,包含消息内容和接收者。 -* -*@return error - */ -func (rc *RongCloud) SystemSendTemplate(senderID, objectName string, template TXTMsg, content []TemplateMsgContent, - options ...MsgOption) error { - if senderID == "" { - return RCErrorNew(1002, "Paramer 'senderID' is required") - } - - extraOptins := modifyMsgOptions(options) - - req := httplib.Post(rc.rongCloudURI + "/message/system/publish_template." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - var toUserIDs, push, pushData []string - var values []map[string]string - - for _, v := range content { - if v.TargetID == "" { - return RCErrorNew(1002, "Paramer 'TargetID' is required") - } - toUserIDs = append(toUserIDs, v.TargetID) - values = append(values, v.Data) - push = append(push, v.PushContent) - pushData = append(pushData, v.PushData) - } - - bytes, err := json.Marshal(template) - if err != nil { - return err - } - - param := map[string]interface{}{} - param["fromUserId"] = senderID - param["objectName"] = objectName - param["content"] = string(bytes) - param["toUserId"] = toUserIDs - param["values"] = values - param["pushContent"] = push - param["verifyBlacklist"] = 0 - param["pushData"] = pushData - param["contentAvailable"] = extraOptins.contentAvailable - param["disablePush"] = extraOptins.disablePush - if extraOptins.busChannel != "" { - param["busChannel"] = extraOptins.busChannel - } - - _, _ = req.JSONBody(param) - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// HistoryGet 按小时获取历史消息日志文件 URL,包含小时内应用产生的所有消息,消息日志文件无论是否已下载,3 天后将从融云服务器删除 -/* -*@param date:精确到小时,例如: 2018030210 表示获取 2018 年 3 月 2 日 10 点至 11 点产生的数据 -* -*@return History error - */ -func (rc *RongCloud) HistoryGet(date string) (History, error) { - req := httplib.Post(rc.rongCloudURI + "/message/history." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("date", date) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return History{}, err - } - var history History - if err := json.Unmarshal(resp, &history); err != nil { - return History{}, err - } - return history, nil -} - -// HistoryRemove 删除历史消息日志文件 -/* -*@param date:精确到小时,例如: 2018030210 表示获取 2018 年 3 月 2 日 10 点至 11 点产生的数据 -* -*@return error - */ -func (rc *RongCloud) HistoryRemove(date string) error { - if date == "" { - return RCErrorNew(1002, "Paramer 'date' is required") - } - req := httplib.Post(rc.rongCloudURI + "/message/history/delete." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("date", date) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err - -} - -// SetMessageExpansion 设置消息扩展 -// 发送消息时,如设置了 expansion 为 true,可对该条消息进行扩展信息设置,每次最多可以设置 100 个扩展属性信息,最多可设置 300 个。 -func (rc *RongCloud) SetMessageExpansion(msgUID, userId, conversationType, targetId string, extra map[string]string, isSyncSender int) error { - if msgUID == "" { - return RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if conversationType == "" { - return RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if conversationType != strconv.Itoa(MessagePrivateType) && conversationType != strconv.Itoa(MessageGroupType) { - return RCErrorNew(1002, "Paramer 'conversationType' must be 1 or 3 to string") - } - - if isSyncSender != 0 && isSyncSender != 1 { - return RCErrorNew(1002, "Paramer 'isSyncSender' is error") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if extra == nil { - return RCErrorNew(1002, "Paramer 'extra' is required") - } - - encExtra, err := json.Marshal(extra) - if err != nil { - return err - } - - req := httplib.Post(rc.rongCloudURI + "/message/expansion/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("conversationType", conversationType) - req.Param("targetId", targetId) - req.Param("extraKeyVal", string(encExtra)) - req.Param("isSyncSender", strconv.Itoa(isSyncSender)) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// DeleteMessageExpansion 删除消息扩展 -func (rc *RongCloud) DeleteMessageExpansion(msgUID, userId, conversationType, targetId string, isSyncSender int, keys ...string) error { - if msgUID == "" { - return RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if conversationType == "" { - return RCErrorNew(1002, "Paramer 'conversationType' is required") - } - - if conversationType != strconv.Itoa(MessagePrivateType) && conversationType != strconv.Itoa(MessageGroupType) { - return RCErrorNew(1002, "Paramer 'conversationType' must be 1 or 3 to string") - } - - if targetId == "" { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - - if len(keys) <= 0 { - return RCErrorNew(1002, "Paramer 'keys' is required") - } - - if isSyncSender != 0 && isSyncSender != 1 { - return RCErrorNew(1002, "Paramer 'isSyncSender' is error") - } - - encKeys, err := json.Marshal(keys) - if err != nil { - return err - } - - req := httplib.Post(rc.rongCloudURI + "/message/expansion/delete." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("conversationType", conversationType) - req.Param("targetId", targetId) - req.Param("extraKey", string(encKeys)) - req.Param("isSyncSender", strconv.Itoa(isSyncSender)) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -type MessageExpansionItem struct { - Key string `json:"key"` - Value string `json:"value"` - Timestamp int64 `json:"timestamp"` -} - -// QueryMessageExpansion 获取扩展信息 -// 根据消息 ID 获取指定消息扩展信息 -func (rc *RongCloud) QueryMessageExpansion(msgUID string, page int) ([]MessageExpansionItem, error) { - if msgUID == "" { - return nil, RCErrorNew(1002, "Paramer 'msgUID' is required") - } - - if page <= 0 { - page = 1 - } - - req := httplib.Post(rc.rongCloudURI + "/message/expansion/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("pageNo", strconv.Itoa(page)) - - body, err := rc.do(req) - if err != nil { - return nil, err - } - - resp := struct { - Code int `json:"code"` - ExtraContent map[string]map[string]interface{} `json:"extraContent"` - }{} - - if err = json.Unmarshal(body, &resp); err != nil { - return nil, err - } - - if resp.Code != 200 { - return nil, fmt.Errorf("response error: %d", resp.Code) - } - - var data []MessageExpansionItem - for key, val := range resp.ExtraContent { - item := MessageExpansionItem{ - Key: key, - } - - if v, ok := val["v"]; ok { - item.Value = v.(string) - } - - if ts, ok := val["ts"]; ok { - item.Timestamp = int64(ts.(float64)) - } - - data = append(data, item) - } - - return data, nil -} diff --git a/sdk/message_test.go b/sdk/message_test.go deleted file mode 100644 index 63ff938..0000000 --- a/sdk/message_test.go +++ /dev/null @@ -1,583 +0,0 @@ -/* - * @Descripttion: - * @version: - * @Author: ran.ding - * @Date: 2019-09-02 18:29:55 - * @LastEditors: ran.ding - * @LastEditTime: 2019-09-10 11:37:27 - */ -package sdk - -import ( - "encoding/json" - "os" - "testing" - "time" -) - -func TestRongCloud_MessageExpansionDel(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.MessageExpansionDel("C16R-VBGG-1IE5-SD0C", - "u01", - "3", - "testExp0309", - "[\"key1\",\"key2\"]", - 1, - ); err != nil { - t.Error(err) - return - } - t.Log("do UGMessageGet suc") -} - -func TestRongCloud_MessageExpansionSet(t *testing.T) { - data, err := json.Marshal(map[string]string{"type": "3"}) - if err != nil { - t.Log("marshal err", err) - return - } - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.MessageExpansionSet("C16R-VBGG-1IE5-SD0C", - "u01", - "3", - "testExp0309", - string(data), - 1, - ); err != nil { - t.Error(err) - return - } - t.Log("do UGMessageGet suc") -} - -func TestRongCloud_UGMessageGetObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UGMessageGetObj("target_001", []UGMessageData{ - { - MsgUid: "C16R-VBGG-1IE5-SD0C", - BusChannel: "001", - }, - }); err != nil { - t.Error(err) - return - } else { - t.Logf("do UGMessageGet suc :%+v", res) - } -} - -func TestRongCloud_UGMessageGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UGMessageGet("target_001", []UGMessageData{ - { - MsgUid: "C16R-VBGG-1IE5-SD0C", - BusChannel: "001", - }, - }); err != nil { - t.Error(err) - return - } else { - t.Log("do UGMessageGet suc", string(res)) - } - -} - -func TestRongCloud_UGMessageModify(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.UGMessagePublish("aa", "RC:TxtMsg", "{\"content\":\"1234455667788-0309-1-test\"}", - "", "", "1", "", "0", "0", "", "{\"key1\":\"key1\"}", - false, false, &PushExt{ - Title: "you have a new message.", - TemplateId: "123456", - ForceShowPushContent: 0, - PushConfigs: []map[string]map[string]string{ - { - "HW": { - "channelId": "NotificationKanong", - }, - }, - { - "MI": { - "channelId": "rongcloud_kanong", - }, - }, - { - "OPPO": { - "channelId": "rc_notification_id", - }, - }, - { - "VIVO": { - "classification": "0", - }, - }, - { - "APNs": { - "thread-id": "1", - "apns-collapse-id": "1", - }, - }, - }, - }, "testExp0309") - if err != nil { - t.Errorf("ug message send err:%v", err) - return - } - t.Log("ug message send suc") - time.Sleep(1 * time.Second) - // note : msgUID是通过全量消息路由获取, 详情:https://doc.rongcloud.cn/imserver/server/v1/message/sync - if res, err := rc.UGMessageModify("testExp0309", "aa", "C1PL-LJQR-0U1B-ADFN", "哈喽", UgMessageExtension{ - BusChannel: "", - MsgRandom: 0, - }); err != nil { - t.Errorf("UGMessageModify request err:%v", err) - return - } else { - t.Log("UGMessageModify suc", string(res)) - } -} - -func TestMessageBroadcastRecall(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - content := BroadcastRecallContent{ - MessageId: "BC52-ESJ0-022O-001H", - ConversationType: 6, - IsAdmin: 0, - IsDelete: 0, - } - - if err := rc.MessageBroadcastRecall("123", "RC:RcCmd", content); err != nil { - t.Errorf("ERROR: %v", err) - } else { - t.Log("PASS") - } -} - -func TestChatRoomRecall(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - if err := rc.ChatRoomRecall("fDR2cVpxxR5zSMUNh3yAwh", "MersNRhaKwJkRV9mJR5JXY", "5FGT-7VA9-G4DD-4V5P", 1507778882124); err != nil { - t.Errorf("error: %v", err) - } else { - t.Log("Pass") - } -} - -func TestSystemRecall(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.SystemRecall("fDR2cVpxxR5zSMUNh3yAwh", - "MersNRhaKwJkRV9mJR5JXY", - "5FGT-7VA9-G4DD-4V5P", - 1507778882124, - WithIsAdmin(1), - WithIsDelete(1), - ) - - if err != nil { - t.Errorf("error: %v", err) - } else { - t.Log("Pass") - } -} - -func TestMessage_PrivateSend(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.PrivateSend( - "7Szq13MKRVortoknTAk7W8", - []string{"4kIvGJmETlYqDoVFgWdYdM"}, - "RC:TxtMsg", - &msg, - "", - "", - 1, - 0, - 1, - 0, - 0, - ) - t.Log(err) -} - -func TestMessage_PrivateSendOptions(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.PrivateSend( - "7Szq13MKRVortoknTAk7W8", - []string{"4kIvGJmETlYqDoVFgWdYdM"}, - "RC:TxtMsg", - &msg, - "", - "", - 1, - 0, - 1, - 0, - 0, - WithMsgDisablePush(true), - WithMsgPushExt(""), - WithMsgBusChannel("bus"), - ) - t.Log(err) -} - -func TestMessage_PrivateRecall(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.PrivateRecall( - "7Szq13MKRVortoknTAk7W8", - "4kIvGJmETlYqDoVFgWdYdM", - "B7CE-U880-31M6-D3EE", - 1543566558208, - ) - t.Log(err) -} - -func TestMessage_PrivateSendTemplate(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - tpl1 := TemplateMsgContent{ - TargetID: "4kIvGJmETlYqDoVFgWdYdM", - Data: map[string]string{ - "{name}": "小明", - "{score}": "90", - }, - PushContent: "{name} 你的成绩出来了", - } - - tpl2 := TemplateMsgContent{ - TargetID: "GvYBoFJQTggripS_qoiVaA", - Data: map[string]string{ - "{name}": "小红", - "{score}": "95", - }, - PushContent: "{name} 你的成绩出来了", - } - - msg := TXTMsg{ - Content: "{name}, 语文成绩 {score} 分", - Extra: "helloExtra", - } - - var tpl []TemplateMsgContent - tpl = append(tpl, tpl1) - tpl = append(tpl, tpl2) - err := rc.PrivateSendTemplate( - "7Szq13MKRVortoknTAk7W8", - "RC:TxtMsg", - msg, - tpl) - t.Log(err) -} - -func TestRongCloud_GroupSend(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.GroupSend( - "7Szq13MKRVortoknTAk7W8", - []string{"CFtiYbXNQNYtSr7rzUfHco"}, - []string{}, - "RC:TxtMsg", - &msg, - "", - "", - 1, - 0, - ) - t.Log(err) -} - -func TestRongCloud_PrivateRecall(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.GroupRecall( - "7Szq13MKRVortoknTAk7W8", - "CFtiYbXNQNYtSr7rzUfHco", - "B7CE-U880-31M6-D3EE", - 1543566558208, - ) - - t.Log(err) -} - -func TestRongCloud_GroupSendMention(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := MentionMsgContent{ - Content: "@user_2 hello", - MentionedInfo: MentionedInfo{Type: 2, UserIDs: []string{"4kIvGJmETlYqDoVFgWdYdM"}, PushContent: "有人@你"}, - } - err := rc.GroupSendMention( - "7Szq13MKRVortoknTAk7W8", - []string{"cYgiKZzRSUsrfrx6C3u_GI"}, - "RC:TxtMsg", - msg, - "", - "", - 1, - 0, - 1, - 0, - ) - t.Log(err) -} - -func TestRongCloud_ChatRoomSend(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.ChatRoomSend( - "7Szq13MKRVortoknTAk7W8", - []string{"4kIvGJmETlYqDoVFgWdYdM"}, - "RC:TxtMsg", - &msg, 0, 0, - ) - t.Log(err) - -} - -func TestRongCloud_ChatroomBroadcast(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.ChatRoomBroadcast( - "7Szq13MKRVortoknTAk7W8", - "RC:TxtMsg", - &msg, - ) - t.Log(err) -} - -func TestRongCloud_OnlineBroadcast(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - code, err := rc.OnlineBroadcast( - "someone", - "RC:TxtMsg", - "hello everyone", - ) - t.Log(string(code)) - t.Log(err) -} - -func TestRongCloud_SystemSend(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.SystemSend( - "7Szq13MKRVortoknTAk7W8", - []string{"4kIvGJmETlYqDoVFgWdYdM"}, - "RC:TxtMsg", - &msg, - "", - "", - 0, - 1, - ) - t.Log(err) -} - -func TestRongCloud_SystemBroadcast(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.SystemBroadcast( - "7Szq13MKRVortoknTAk7W8", - "RC:TxtMsg", - &msg, - ) - t.Log(err) -} - -func TestRongCloud_SystemBroadcastOption(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - err := rc.SystemBroadcast( - "7Szq13MKRVortoknTAk7W8", - "RC:TxtMsg", - &msg, - WithMsgPushContent("thisisapush"), - ) - t.Log(err) -} - -func TestRongCloud_SystemSendTemplate(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - tpl1 := TemplateMsgContent{ - TargetID: "4kIvGJmETlYqDoVFgWdYdM", - Data: map[string]string{ - "{name}": "小明", - "{score}": "90", - }, - PushContent: "{name} 你的成绩出来了", - } - - tpl2 := TemplateMsgContent{ - TargetID: "GvYBoFJQTggripS_qoiVaA", - Data: map[string]string{ - "{name}": "小红", - "{score}": "95", - }, - PushContent: "{name} 你的成绩出来了", - } - - msg := TXTMsg{ - Content: "{name}, 语文成绩 {score} 分", - Extra: "helloExtra", - } - - var tpl []TemplateMsgContent - tpl = append(tpl, tpl1) - tpl = append(tpl, tpl2) - err := rc.SystemSendTemplate( - "7Szq13MKRVortoknTAk7W8", - "RC:TxtMsg", - msg, - tpl) - t.Log(err) -} - -func TestRongCloud_HistoryGet(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - history, err := rc.HistoryGet( - "2018030210", - ) - t.Log(err) - t.Log(history) -} - -func TestRongCloud_HistoryRemove(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.HistoryRemove( - "2018030210", - ) - t.Log(err) -} diff --git a/sdk/push.go b/sdk/push.go deleted file mode 100644 index 94d8d6f..0000000 --- a/sdk/push.go +++ /dev/null @@ -1,352 +0,0 @@ -package sdk - -import ( - "encoding/json" - "errors" - "fmt" - "net/http" - "strings" - "time" - - "github.com/astaxie/beego/httplib" -) - -// PlatForm 广播类型 -type PlatForm string - -const ( - // IOSPlatForm 广播 - IOSPlatForm PlatForm = "ios" - // AndroidPlatForm 广播 - AndroidPlatForm PlatForm = "android" -) - -// Extras 请自行实现 IOSBroadcast AndroidBroadcast 中 Extras 接口 -type Extras interface { - ToJSON() ([]byte, error) -} - -// Sender 广播推送接口 -type Sender interface { - sender() -} - -// PushResult Send 函数返回 -type PushResult struct { - *CodeResult - ID string `json:"id"` -} - -// Broadcast 广播消息 -type Broadcast struct { - PlatForm []PlatForm `json:"platform"` // 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写。(必传) - FromUserID string `json:"fromuserid"` // 发送人用户 Id。 (必传) - Message Message `json:"message"` // 广播消息。(必传) - Audience Audience `json:"audience"` // 推送条件,包括:tag 、userid 、packageName 、 is_to_all。(必传) - Notification Notification `json:"notification,omitempty"` // 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容。(非必传) -} - -// Push 广播推送 -type Push struct { - PlatForm []PlatForm `json:"platform"` // 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写。(必传) - Audience Audience `json:"audience"` // 推送条件,包括:tag 、userid 、packageName 、 is_to_all。(必传) - Notification Notification `json:"notification"` // 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容。(必传) -} - -// Message 广播消息内容 -type Message struct { - Content string `json:"content"` // 融云的内置消息,请务必参考 RCMsg Interface 。自定义消息请,自行实现 RCMsg Interface 转换成 String 传入 - ObjectName string `json:"objectName"` // 融云的内置消息,自定义消息 -} - -// IOSPush 设置 iOS 平台下的推送及附加信息。 -type IOSPush struct { - Title string `json:"title,omitempty"` // 通知栏显示的推送标题,仅针对 iOS 平台,支持 iOS 8.2 及以上版本,参数在 ios 节点下设置,详细可参考“设置 iOS 推送标题请求示例”。(非必传) - ContentAvailable int `json:"contentAvailable,omitempty"` // 针对 iOS 平台,静默推送是 iOS7 之后推出的一种推送方式。 允许应用在收到通知后在后台运行一段代码,且能够马上执行。1 表示为开启,0 表示为关闭,默认为 0(非必传) - Alert string `json:"alert,omitempty"` // iOS 或 Android 不同平台下的推送消息内容,传入后默认的推送消息内容失效,不能为空。(非必传) - Extras Extras `json:"extras,omitempty"` // Extras 请自行实现 Extras Interface,iOS 或 Android 不同平台下的附加信息,如果开发者自己需要,可以自己在 App 端进行解析。(非必传) - Badge int `json:"badge,omitempty"` // 应用角标,仅针对 iOS 平台;不填时,表示不改变角标数;为 0 或负数时,表示 App 角标上的数字清零;否则传相应数字表示把角标数改为指定的数字,最大不超过 9999,参数在 ios 节点下设置,详细可参考“设置 iOS 角标数 HTTP 请求示例”。(非必传) - Category string `json:"category,omitempty"` // iOS 富文本推送的类型开发者自已定义,自已在 App 端进行解析判断,与 richMediaUri 一起使用。(非必传) - RichMediaURI string `json:"richMediaUri,omitempty"` // iOS 富文本推送内容的 URL,与 category 一起使用。(非必传) - ThreadId string `json:"threadId,omitempty"` // ThreadId iOS 平台通知栏分组 ID,相同的 thread-id 推送分一组,单组超过 5 条推送会折叠展示 - ApnsCollapseId string `json:"apns-collapse-id,omitempty"` // ApnsCollapseId iOS 平台,从 iOS10 开始支持,设置后设备收到有相同 ID 的消息,会合并成一条 -} - -// AndroidPush 设置 Android 平台下的推送及附加信息。 -type AndroidPush struct { - Alert string `json:"alert,omitempty"` // iOS 或 Android 不同平台下的推送消息内容,传入后默认的推送消息内容失效,不能为空。(非必传) - Extras Extras `json:"extras,omitempty"` // Extras 请自行实现 Extras Interface,iOS 或 Android 不同平台下的附加信息,如果开发者自己需要,可以自己在 App 端进行解析, PushNotification 没有该字段(非必传) - ChannelId string `json:"channelId,omitempty"` // ChannelId 渠道 ID,该条消息针对各厂商使用的推送渠道,目前支持的厂商包括:”MI” 小米、”HW” 华为、”OPPO” - Importance string `json:"importance,omitempty"` // Importance 华为通知栏消息优先级,取值 NORMAL、LOW,默认为 NORMAL 重要消息 - Image string `json:"image,omitempty"` // Image 华为推送自定义的通知栏消息右侧大图标 URL,如果不设置,则不展示通知栏右侧图标。URL 使用的协议必须是 HTTPS 协议,取值样例:https://example.com/image.png。图标文件须小于 512KB,图标建议规格大小:40dp x 40dp,弧角大小为 8dp,超出建议规格大小的图标会存在图片压缩或显示不全的情况。 - LargeIconUri string `json:"large_icon_uri,omitempty"` // LargeIconUri 小米推送自定义的通知栏消息右侧图标 URL,如果不设置,则不展示通知栏右侧图标。国内版仅 MIUI12 以上版本支持,以下版本均不支持;国际版支持。图片要求:大小120 * 120px,格式为 png 或者 jpg 格式。 - Classification string `json:"classification,omitempty"` // Classification vivo 推送通道类型。0 为运营消息、1 为系统消息,默认为你在开发者后台应用标识 vivo 推送中设置的推送通道类型。 -} - -// Notification 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容。(必传) -type Notification struct { - Alert string `json:"alert"` // 默认推送消息内容,如填写了 iOS 或 Android 下的 alert 时,则推送内容以对应平台系统的 alert 为准。(必传) - IOS IOSPush `json:"ios,omitempty"` // 设置 iOS 平台下的推送及附加信息。 - Android AndroidPush `json:"android,omitempty"` // 设置 Android 平台下的推送及附加信息。 -} - -// Audience 推送条件。 -type Audience struct { - Tag []string `json:"tag,omitempty"` // 用户标签,每次发送时最多发送 20 个标签,标签之间为 AND 的关系,is_to_all 为 true 时参数无效。(非必传) - TagOr []string `json:"tag_or,omitempty"` // 用户标签,每次发送时最多发送 20 个标签,标签之间为 OR 的关系,is_to_all 为 true 时参数无效,tag_or 同 tag 参数可以同时存在。(非必传) - UserID []string `json:"userid,omitempty"` // 用户 Id,每次发送时最多发送 1000 个用户,如果 tag 和 userid 两个条件同时存在时,则以 userid 为准,如果 userid 有值时,则 platform 参数无效,is_to_all 为 true 时参数无效。(非必传) - IsToAll bool `json:"is_to_all"` // 是否全部推送,false 表示按 tag 、tag_or 或 userid 条件推送,true 表示向所有用户推送,tag、tag_or 和 userid 条件无效。(必传) - PackageName string `json:"packageName"` // 应用包名,is_to_all 为 true 时,此参数无效。与 tag、tag_or 同时存在时为 And 的关系,向同时满足条件的用户推送。与 userid 条件同时存在时,以 userid 为准进行推送。(非必传) -} - -type PushNotification struct { - Title string `json:"title,omitempty"` // Title 通知栏显示标题,最长不超过 50 个字符。 - PushContent string `json:"pushContent"` // PushContent 推送消息内容。 - IOS IOSPush `json:"ios,omitempty"` // IOS 设置 iOS 平台下的推送及附加信息,详细查看 ios 结构说明。 - Android map[string]interface{} `json:"android,omitempty"` // Android 设置 Android 平台下的推送及附加信息,详细查看 android 结构说明。 -} - -type PushCustomData struct { - Platform []string `json:"platform"` - Audience struct { - Tag []string `json:"tag"` - TagOr []string `json:"tag_or"` - Packages string `json:"packageName"` - TagItems []struct { - Tags []string `json:"tags"` - IsNot bool `json:"isNot"` - TagsOperator string `json:"tagsOperator"` - ItemsOperator string `json:"itemsOperator"` - } `json:"tagItems,omitempty"` - IsToAll bool `json:"is_to_all"` - } `json:"audience"` - Notification struct { - Title string `json:"title"` - Alert string `json:"alert"` - Ios struct { - Title string `json:"title,omitempty"` - ContentAvailable int `json:"contentAvailable"` - Badge int `json:"badge,omitempty"` - ThreadId string `json:"thread-id"` - ApnsCollapseId string `json:"apns-collapse-id"` - Category string `json:"category,omitempty"` - RichMediaUri string `json:"richMediaUri,omitempty"` - Extras interface{} `json:"extras"` - } `json:"ios"` - Android struct { - Hw struct { - ChannelId string `json:"channelId"` - Importance string `json:"importance"` - Image string `json:"image"` - } `json:"hw"` - Mi struct { - ChannelId string `json:"channelId"` - LargeIconUri string `json:"large_icon_uri"` - } `json:"mi"` - Oppo struct { - ChannelId string `json:"channelId"` - } `json:"oppo"` - Vivo struct { - Classification string `json:"classification"` - } `json:"vivo"` - Extras struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"extras"` - } `json:"android"` - } `json:"notification"` -} - -// PushCustomObj :PushCustomResObj方法的返回值 -type PushCustomObj struct { - // 返回码,200 为正常。 - Code int `json:"code"` - - // 推送唯一标识。 - Id string `json:"id"` -} - -// PushCustomObj : 全量用户不落地通知 /push/custom.json -//* -// @param: p:参考这个TestRongCloud_PushCustom 单元测试传递的参数 -// @param: platform []string 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写。 -// @param: audience string 推送条件,包括:tag 、tag_or 、packageName 、 is_to_all。 -// @param: notification string 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容,详细查看 notification 结构说明。 -// 可以构建为上面的map或者struct 进行json序列化之后调用PushCustom -// response: 返回结构体 -// 文档: https://doc.rongcloud.cn/imserver/server/v1/push-plus#push_custom -//*// -func (rc *RongCloud) PushCustomObj(data PushCustomData) (PushCustomObj, error) { - var ( - err error - result = PushCustomObj{} - ) - body, err := json.Marshal(data) - if err != nil { - return result, err - } - req := httplib.Post(rc.rongCloudURI + "/push/custom.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Body(body) - req.Header("Content-Type", "application/json") - code, err := rc.do(req) - if err != nil { - fmt.Println("do err", err) - return result, err - } - if err := json.Unmarshal(code, &result); err != nil { - fmt.Println("unmarshal err", err) - return result, err - } - return result, err -} - -// PushCustomResObj : 全量用户不落地通知 /push/custom.json -//* -// @param: p:参考这个TestRongCloud_PushCustom 单元测试传递的参数 -// @param: platform []string 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写。 -// @param: audience string 推送条件,包括:tag 、tag_or 、packageName 、 is_to_all。 -// @param: notification string 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容,详细查看 notification 结构说明。 -// 可以构建为上面的map或者struct 进行json序列化之后调用PushCustom -// 请求按照PushCustomData结构体请求: -// response: 返回结构体 -// 文档: https://doc.rongcloud.cn/imserver/server/v1/push-plus#push_custom -//*// -func (rc *RongCloud) PushCustomResObj(p []byte) (PushCustomObj, error) { - var ( - err error - result = PushCustomObj{} - ) - url := rc.rongCloudURI + "/push/custom.json" - fmt.Println(url) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Body(p) - req.Header("Content-Type", "application/json") - code, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(code, &result); err != nil { - return result, err - } - return result, err -} - -// PushCustom : 全量用户不落地通知 /push/custom.json -//* -// @param: p:参考这个TestRongCloud_PushCustom 单元测试传递的参数 -// @param: platform []string 目标操作系统,iOS、Android 最少传递一个。如果需要给两个系统推送消息时,则需要全部填写。 -// @param: audience string 推送条件,包括:tag 、tag_or 、packageName 、 is_to_all。 -// @param: notification string 按操作系统类型推送消息内容,如 platform 中设置了给 iOS 和 Android 系统推送消息,而在 notification 中只设置了 iOS 的推送内容,则 Android 的推送内容为最初 alert 设置的内容,详细查看 notification 结构说明。 -//请求按照PushCustomData结构体请求: -// 可以构建为上面的map或者struct 进行json序列化之后调用PushCustom -// response: 返回byte数组 -// 文档 : https://doc.rongcloud.cn/imserver/server/v1/push-plus#push_custom -//*// -func (rc *RongCloud) PushCustom(p []byte) ([]byte, error) { - var err error - req := httplib.Post(rc.rongCloudURI + "/push/custom.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Body(p) - req.Header("Content-Type", "application/json") - code, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return code, err -} - -// PushUser 向应用中指定用户发送不落地通知,不落地通知无论用户是否正在使用 App,都会向该用户发送通知,通知只会展示在通知栏,通知中不携带消息内容,登录 App 后不会在聊天页面看到该内容,不会存储到本地数据库。 -func (rc *RongCloud) PushUser(notification *PushNotification, users ...string) error { - if notification == nil { - return errors.New("Invalid notification") - } - - if userLens := len(users); userLens > 100 || userLens <= 0 { - return errors.New("Invalid users") - } - - if notification.Android != nil { - android := make(map[string]interface{}) - for key, val := range notification.Android { - k := strings.ToLower(key) - android[k] = val - } - notification.Android = android - } - - var err error - - req := httplib.Post(rc.rongCloudURI + "/push/user." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req, err = req.JSONBody(map[string]interface{}{ - "userIds": users, - "notification": notification, - }) - if err != nil { - return err - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := make(map[string]interface{}) - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - code, ok := data["code"] - if !ok { - return errors.New("Failed to request") - } - - if int(code.(float64)) != http.StatusOK { - return fmt.Errorf("Response error. code: %d", int(code.(float64))) - } - - return nil -} - -// PushSend 此方法与 /message/broadcast 广播消息方法发送机制一样,可选择更多发送条件。 该功能开发环境下可免费使用。生产环境下,您需要在开发者后台高级功能设置中开通 IM 商用版后,在“广播消息和推送”中,开启后才能使用。 -// 推送和广播消息合计每小时只能发送 2 次,每天最多发送 3 次。如需要调整发送频率. -/* -*@param Push: 广播消息体 push。 -* -*@return PushResult, error - */ -func (rc *RongCloud) PushSend(sender Sender) (PushResult, error) { - req := httplib.Post(rc.rongCloudURI + "/push." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req, err := req.JSONBody(sender) - if err != nil { - rc.urlError(err) - return PushResult{}, err - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return PushResult{}, err - } - var pushResult PushResult - if err := json.Unmarshal(resp, &pushResult); err != nil { - return PushResult{}, err - } - return pushResult, nil -} - -func (p Push) sender() { - -} - -func (b Broadcast) sender() { - -} diff --git a/sdk/push_test.go b/sdk/push_test.go deleted file mode 100644 index 4286942..0000000 --- a/sdk/push_test.go +++ /dev/null @@ -1,423 +0,0 @@ -package sdk - -import ( - "encoding/json" - "os" - "testing" -) - -type selfExtras struct { - ID int `json:"id"` -} - -// ToJSON 实现 Extras Interface -func (s selfExtras) ToJSON() ([]byte, error) { - return json.Marshal(s) -} - -func TestRongCloud_PushCustomObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - res, err := rc.PushCustomObj(PushCustomData{ - Platform: []string{"ios", "android"}, - Audience: struct { - Tag []string `json:"tag"` - TagOr []string `json:"tag_or"` - Packages string `json:"packageName"` - TagItems []struct { - Tags []string `json:"tags"` - IsNot bool `json:"isNot"` - TagsOperator string `json:"tagsOperator"` - ItemsOperator string `json:"itemsOperator"` - } `json:"tagItems,omitempty"` - IsToAll bool `json:"is_to_all"` - }{ - Tag: []string{"女", "年轻"}, - TagOr: []string{"北京", "上海"}, - TagItems: []struct { - Tags []string `json:"tags"` - IsNot bool `json:"isNot"` - TagsOperator string `json:"tagsOperator"` - ItemsOperator string `json:"itemsOperator"` - }{ - { - Tags: []string{"guangdong", "hunan"}, - IsNot: false, - TagsOperator: "OR", - ItemsOperator: "OR", - }, - { - Tags: []string{"20200408"}, - IsNot: true, - TagsOperator: "OR", - ItemsOperator: "AND", - }, - { - Tags: []string{"male", "female"}, - IsNot: false, - TagsOperator: "OR", - ItemsOperator: "AND", - }, - }, - IsToAll: false, - }, - Notification: struct { - Title string `json:"title"` - Alert string `json:"alert"` - Ios struct { - Title string `json:"title,omitempty"` - ContentAvailable int `json:"contentAvailable"` - Badge int `json:"badge,omitempty"` - ThreadId string `json:"thread-id"` - ApnsCollapseId string `json:"apns-collapse-id"` - Category string `json:"category,omitempty"` - RichMediaUri string `json:"richMediaUri,omitempty"` - Extras interface{} `json:"extras"` - } `json:"ios"` - Android struct { - Hw struct { - ChannelId string `json:"channelId"` - Importance string `json:"importance"` - Image string `json:"image"` - } `json:"hw"` - Mi struct { - ChannelId string `json:"channelId"` - LargeIconUri string `json:"large_icon_uri"` - } `json:"mi"` - Oppo struct { - ChannelId string `json:"channelId"` - } `json:"oppo"` - Vivo struct { - Classification string `json:"classification"` - } `json:"vivo"` - Extras struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"extras"` - } `json:"android"` - }{ - Title: "标题", - Alert: "this is a push", - Ios: struct { - Title string `json:"title,omitempty"` - ContentAvailable int `json:"contentAvailable"` - Badge int `json:"badge,omitempty"` - ThreadId string `json:"thread-id"` - ApnsCollapseId string `json:"apns-collapse-id"` - Category string `json:"category,omitempty"` - RichMediaUri string `json:"richMediaUri,omitempty"` - Extras interface{} `json:"extras"` - }{ - ThreadId: "223", - ApnsCollapseId: "111", - Extras: struct { - Id string `json:"id"` - Name string `json:"name"` - }{ - Id: "1", - Name: "2", - }, - }, - Android: struct { - Hw struct { - ChannelId string `json:"channelId"` - Importance string `json:"importance"` - Image string `json:"image"` - } `json:"hw"` - Mi struct { - ChannelId string `json:"channelId"` - LargeIconUri string `json:"large_icon_uri"` - } `json:"mi"` - Oppo struct { - ChannelId string `json:"channelId"` - } `json:"oppo"` - Vivo struct { - Classification string `json:"classification"` - } `json:"vivo"` - Extras struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"extras"` - }{ - Hw: struct { - ChannelId string `json:"channelId"` - Importance string `json:"importance"` - Image string `json:"image"` - }{ - ChannelId: "NotificationKanong", - Importance: "NORMAL", - Image: "https://example.com/image.png", - }, - Mi: struct { - ChannelId string `json:"channelId"` - LargeIconUri string `json:"large_icon_uri"` - }{ - ChannelId: "rongcloud_kanong", - LargeIconUri: "https://example.com/image.png", - }, - Oppo: struct { - ChannelId string `json:"channelId"` - }{ - ChannelId: "rc_notification_id", - }, - Vivo: struct { - Classification string `json:"classification"` - }{ - Classification: "0", - }, - Extras: struct { - Id string `json:"id"` - Name string `json:"name"` - }{ - Id: "1", - Name: "2", - }, - }, - }, - }) - if err != nil { - t.Errorf("push custom err:%v", err) - return - } - t.Log("push suc res is:", res) -} - -func TestRongCloud_PushCustomResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - str := `{ - "platform": ["ios", "android"], - "audience": { - "tag": [ - "女", - "年轻" - ], - "tag_or": [ - "北京", - "上海" - ], - "tagItems": [{ - "tags": [ - "guangdong", - "hunan" - ], - "isNot": false, - "tagsOperator": "OR", - "itemsOperator": "OR" - }, - { - "tags": [ - "20200408" - ], - "isNot": true, - "tagsOperator": "OR", - "itemsOperator": "AND" - }, - { - "tags": [ - "male", - "female" - ], - "isNot": false, - "tagsOperator": "OR", - "itemsOperator": "OR" - } - ], - "userid": ["123","456"], - "is_to_all": false - }, - "notification": { - "title": "标题", - "alert": "this is a push", - "ios": { - "thread-id": "223", - "apns-collapse-id": "111", - "extras": { - "id": "1", - "name": "2" - } - }, - "android": { - "hw": { - "channelId": "NotificationKanong", - "importance": "NORMAL", - "image": "https://example.com/image.png" - }, - "mi": { - "channelId": "rongcloud_kanong", - "large_icon_uri": "https://example.com/image.png" - }, - "oppo": { - "channelId": "rc_notification_id" - }, - "vivo": { - "classification": "0" - }, - "extras": { - "id": "1", - "name": "2" - } - } - } -}` - res, err := rc.PushCustomResObj([]byte(str)) - if err != nil { - t.Errorf("push custom err:%v", err) - return - } - t.Log("push suc res is:", res) -} - -func TestRongCloud_PushCustom(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - str := `{ - "platform":["ios","android"], - "audience":{ - "tag":["女","年轻"], - "tag_or":["北京","上海"], - "tagItems":[ - { - "tags":[ - "guangdong", - "hunan" - ], - "isNot":false, - "tagsOperator":"OR", - "itemsOperator":"OR" - }, - { - "tags":[ - "20200408" - ], - "isNot":true, - "tagsOperator":"OR", - "itemsOperator":"AND" - }, - { - "tags":[ - "male", - "female" - ], - "isNot":false, - "tagsOperator":"OR", - "itemsOperator":"OR" - } - ], - "userid":[ - "123", - "456" - ], - "is_to_all":false - }, - "notification":{ - "title":"标题", - "alert":"this is a push", - "ios": - { - "thread-id":"223", - "apns-collapse-id":"111", - "extras": {"id": "1","name": "2"} - }, - "android": { - "hw":{ - "channelId":"NotificationKanong", - "importance": "NORMAL", - "image":"https://example.com/image.png" - }, - "mi":{ - "channelId":"rongcloud_kanong", - "large_icon_uri":"https://example.com/image.png" - }, - "oppo":{ - "channelId":"rc_notification_id" - }, - "vivo":{ - "classification":"0" - }, - "extras": {"id": "1","name": "2"} - } - } -}` - res, err := rc.PushCustom([]byte(str)) - if err != nil { - t.Errorf("push custom err:%v", err) - return - } - t.Log("push suc res is:", res) -} - -func TestRongCloud_PushSend(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - push := Push{ - PlatForm: []PlatForm{ - IOSPlatForm, - AndroidPlatForm, - }, - Audience: Audience{ - IsToAll: true, - }, - Notification: Notification{ - Alert: "this is a push", - IOS: IOSPush{ - Title: "iOS 平台显示标题", - Alert: "iOS 平台显示内容", - Extras: selfExtras{ - ID: 1, - }, - }, - Android: AndroidPush{ - Alert: "Android 平台显示内容", - Extras: selfExtras{ - ID: 1, - }, - }, - }, - } - p, err := rc.PushSend(push) - if err != nil { - t.Log(err) - } else { - t.Log(p.Code) - t.Log(p.ID) - } - - msg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - msgr, err := msg.ToString() - if err != nil { - t.Fatal(err) - } - broadcast := Broadcast{ - PlatForm: []PlatForm{ - IOSPlatForm, - AndroidPlatForm, - }, - FromUserID: "u01", - Audience: Audience{ - IsToAll: true, - }, - Message: Message{ - Content: msgr, - ObjectName: "RC:TxtMsg", - }, - } - p, err = rc.PushSend(broadcast) - if err != nil { - t.Log(err) - } else { - t.Log(p.Code) - t.Log(p.ID) - } -} diff --git a/sdk/rongcloud_test.go b/sdk/rongcloud_test.go deleted file mode 100644 index 0d40d3f..0000000 --- a/sdk/rongcloud_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestNewRongCloud(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - t.Log(rc) -} - -func TestGetRongCloud(t *testing.T) { - NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rc := GetRongCloud() - t.Log(rc) -} diff --git a/sdk/sensitive.go b/sdk/sensitive.go deleted file mode 100644 index cdf038f..0000000 --- a/sdk/sensitive.go +++ /dev/null @@ -1,104 +0,0 @@ -package sdk - -import ( - "encoding/json" - "github.com/astaxie/beego/httplib" - "time" -) - -// ListWordFilterResult listWordFilter返回结果 -type ListWordFilterResult struct { - Words []SensitiveWord `json:"words"` -} - -// SensitiveWord 敏感词 -type SensitiveWord struct { - Type string `json:"type"` - Word string `json:"word"` - ReplaceWord string `json:"replaceWord"` -} - -// SensitiveAdd 添加敏感词 -/* -*@param keyword:敏感词,最长不超过 32 个字符,格式为汉字、数字、字母 -*@param replace:敏感词替换,最长不超过 32 个字符, 敏感词屏蔽可以为空 -*@param sensitiveType:0: 敏感词替换 1: 敏感词屏蔽 -* -*@return error - */ -func (rc *RongCloud) SensitiveAdd(keyword, replace string, sensitiveType int) error { - if keyword == "" { - return RCErrorNew(1002, "Paramer 'keyword' is required") - } - if replace == "" { - return RCErrorNew(1002, "Paramer 'replace' is required") - } - req := httplib.Post(rc.rongCloudURI + "/sensitiveword/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("word", keyword) - switch sensitiveType { - case 0: - req.Param("replaceWord", replace) - case 1: - - default: - return RCErrorNew(1002, "Paramer 'replace' is required") - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// SensitiveGetList 查询敏感词列表方法 -/* -*@return ListWordFilterResult error - */ -func (rc *RongCloud) SensitiveGetList() (ListWordFilterResult, error) { - - req := httplib.Post(rc.rongCloudURI + "/sensitiveword/list." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return ListWordFilterResult{}, err - } - - var ret ListWordFilterResult - if err := json.Unmarshal(resp, &ret); err != nil { - return ListWordFilterResult{}, err - } - return ret, err - -} - -// SensitiveRemove 移除敏感词方法(从敏感词列表中,移除某一敏感词。) -/* -*@param keywords:每次最多删除 50 个敏感词,2 小时后生效 -* -*@return error - */ -func (rc *RongCloud) SensitiveRemove(keywords []string) error { - if len(keywords) == 0 { - return RCErrorNew(1002, "Paramer 'keywords' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/sensitiveword/batch/delete." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range keywords { - req.Param("words", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err - -} diff --git a/sdk/sensitive_test.go b/sdk/sensitive_test.go deleted file mode 100644 index 652e17e..0000000 --- a/sdk/sensitive_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestRongCloud_SensitiveAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.SensitiveAdd( - "7Szq13MKRVortoknTAk7W8", - "7Szq13MKRVortoknTAk7W8", - 1, - ) - t.Log(err) -} - -func TestRongCloud_SensitiveGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.SensitiveGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_SensitiveRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.SensitiveRemove( - []string{"7Szq13MKRVortoknTAk7W8"}, - ) - t.Log(err) -} diff --git a/sdk/ultragroup.go b/sdk/ultragroup.go deleted file mode 100644 index b3f4c44..0000000 --- a/sdk/ultragroup.go +++ /dev/null @@ -1,2516 +0,0 @@ -package sdk - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "github.com/astaxie/beego/httplib" -) - -const ( - UGUnPushLevelAllMessage = -1 // UGUnPushLevelAllMessage 全部消息通知 - UGUnPushLevelNotSet = 0 // UGUnPushLevelNotSet 未设置 - UGUnPushLevelAtMessage = 1 // UGUnPushLevelAtMessage 仅@消息通知 - UGUnPushLevelAtUser = 2 // UGUnPushLevelAtUser @指定用户通知 - UGUnPushLevelAtAllGroupMembers = 4 // UGUnPushLevelAtAllGroupMembers @群全员通知 - UGUnPushLevelNotRecv = 5 // UGUnPushLevelNotRecv 不接收通知 -) - -// api 返回结果, data 数组 -type RespDataArray struct { - Code int `json:"code"` - Data map[string][]map[string]interface{} `json:"data"` -} - -// api 返回结果, data -type RespDataKV struct { - Code int `json:"code"` - Data map[string]interface{} `json:"data"` -} - -// 超级群 群组信息 -type UGGroupInfo struct { - GroupId string `json:"group_id"` - GroupName string `json:"group_name"` -} - -// 超级群 用户信息 -type UGUserInfo struct { - Id string `json:"id"` - MutedTime string `json:"time"` -} - -// 超级群 频道信息 -type UGChannelInfo struct { - ChannelId string `json:"channel_id"` - CreateTime string `json:"create_time"` -} - -// 超级群 用户组信息 -type UGUserGroupInfo struct { - UserGroupId string `json:"userGroupId"` -} - -// 超级群 消息结构 -type UGMessage struct { - FromUserId string `json:"from_user_id"` - ToGroupIds []string `json:"to_group_ids"` - ToUserIds []string `json:"to_user_ids,omitempty"` - ObjectName string `json:"object_name"` - Content string `json:"content"` - PushContent string `json:"push_content,omitempty"` - PushData string `json:"push_data,omitempty"` - IncludeSenderEnable bool `json:"include_sender_enable,omitempty"` - StoreFlag bool `json:"store_flag"` - MentionedFlag bool `json:"mentioned_flag,omitempty"` - SilencePush bool `json:"silence_push,omitempty"` - PushExt string `json:"push_ext,omitempty"` - BusChannel string `json:"bus_channel,omitempty"` -} - -// UGGroupChannelGet :频道查询-返回结果带频道类型 /ultragroup/channel/get.json -// -// groupId=ug_m_gid_lw_1&page=1&limit=20 -// response:返回byte数组 -func (rc *RongCloud) UGGroupChannelGet(groupId string, page, limit int) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("page", strconv.Itoa(page)) - req.Param("limit", strconv.Itoa(limit)) - // http - return rc.do(req) -} - -type UGHisMsgQueryResp struct { - Code int `json:"code"` - Data []UGHisMsgQueryData `json:"data"` -} - -type UGHisMsgQueryData struct { - GroupId string `json:"groupId"` - BusChannel string `json:"busChannel"` - FromUserId string `json:"fromUserId"` - MsgUID string `json:"msgUID"` - MsgTime int64 `json:"msgTime"` - ObjectName string `json:"objectName"` - ConversionType int `json:"conversionType"` - Content string `json:"content"` - Expansion bool `json:"expansion"` - ExtraContent string `json:"extraContent"` -} - -type UGHisMsgIdQueryResp struct { - Code int `json:"code"` - Data []UGHisMsgIdQueryData `json:"data"` -} - -type UGHisMsgIdQueryData struct { - GroupId string `json:"groupId"` - BusChannel string `json:"busChannel"` - FromUserId string `json:"fromUserId"` - MsgUID string `json:"msgUID"` - MsgTime int64 `json:"msgTime"` - ObjectName string `json:"objectName"` - ConversionType int `json:"conversionType"` - Content string `json:"content"` - Expansion bool `json:"expansion"` - ExtraContent string `json:"extraContent"` -} - -// UGHisMsgIdQuery -// API 获取消息ID上下文历史消息 -// /ultragroup/hismsg/msgid/query.json -// param: groupId 必填 String 超级群Id -// param: busChannel 必填 String 频道Id -// param: msgUID 必填 string 查询指定的消息Id 上下 10 条消息时使用 -// param: prevNum 不是必填 string 默认 10 条(最大 50 条)即查询消息ID前面的 10 条消息, 当用户传 0 时,不查消息ID前面的数据了 -// param: lastNum 不是必填 string 默认 10 条(最大 50 条)即查询消息ID 后面的 10 条消息, 当用户传 0 时,不查消息ID后面的数据了 -func (rc *RongCloud) UGHisMsgIdQuery(groupId, busChannel, msgUID, prevNum, lastNum string) (UGHisMsgIdQueryResp, error) { - var ( - result = UGHisMsgIdQueryResp{} - ) - req := httplib.Post(rc.rongCloudURI + "/ultragroup/hismsg/msgid/query.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("msgUID", msgUID) - if len(prevNum) > 0 { - req.Param("prevNum", prevNum) - } - if len(lastNum) > 0 { - req.Param("lastNum", lastNum) - } - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UGHistoryQuery -// •接口: /ultragroup/hismsg/query.json -// •作用: 查询超级群历史消息 -// •限频: appKey 级别的 100 次/分钟 -// param: groupId 必填 String 超级群Id -// param: busChannel 必填 String 频道Id -// param: startTime 必填 int64 查询开始时间戳 -// param: endTime 必填 int64 查询结束时间戳,开始时间和结束时间最⻓跨度 14 天 -// param: fromUserId 不是必填 String 消息的发送者 Id , 有该参数只查该用戶发的群消息,否则查群全部历史消息 -// param: pageSize 不是必填 int 默认 20 条,最大100条 -// UGHisMsgQueryResp:返回数据结果集 startTime 100 { - size = 100 - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/hismsg/query.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("startTime", fmt.Sprintf("%v", startTime)) - req.Param("endTime", fmt.Sprintf("%v", endTime)) - if len(fromUserId) > 0 { - req.Param("fromUserId", fromUserId) - } - req.Param("pageSize", fmt.Sprintf("%v", size)) - // http - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err - -} - -// UGChannelPrivateUserGetObj : UGChannelPrivateUserGetResObj的返回值 -type UGChannelPrivateUserGetObj struct { - Code int `json:"code"` - Users []string `json:"users"` -} - -// UGChannelPrivateUserGetResObj :私有频道白名单用户-查询 /ultragroup/channel/private/users/get.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&page=1&pageSize=1000 -// response: UGChannelPrivateUserGetObj -func (rc *RongCloud) UGChannelPrivateUserGetResObj(groupId, busChannel, page, pageSize string) (UGChannelPrivateUserGetObj, error) { - var ( - result = UGChannelPrivateUserGetObj{} - ) - if len(groupId) == 0 { - return result, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return result, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("page", page) - req.Param("pageSize", pageSize) - // http - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UGChannelPrivateUserGet :私有频道白名单用户-查询 /ultragroup/channel/private/users/get.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&page=1&pageSize=1000 -// response: byte数组 -func (rc *RongCloud) UGChannelPrivateUserGet(groupId, busChannel, page, pageSize string) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return nil, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("page", page) - req.Param("pageSize", pageSize) - // http - return rc.do(req) -} - -type UGChannelPrivateUserDelObj struct { - Code int `json:"code"` -} - -// UGChannelPrivateUserDelResObj :私有频道白名单用户-删除 /ultragroup/channel/private/users/del.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&userIds=a%2Cb%2Cc -// response:UGChannelPrivateUserDelObj -func (rc *RongCloud) UGChannelPrivateUserDelResObj(groupId, busChannel, userIds string) (UGChannelPrivateUserDelObj, error) { - var ( - result = UGChannelPrivateUserDelObj{} - ) - - if len(groupId) == 0 { - return result, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return result, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(userIds) == 0 { - return result, RCErrorNewV2(1002, "param 'userIds' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/del.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userIds", userIds) - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UGChannelPrivateUserDel :私有频道白名单用户-删除 /ultragroup/channel/private/users/del.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&userIds=a%2Cb%2Cc -// response : byte数组 -func (rc *RongCloud) UGChannelPrivateUserDel(groupId, busChannel, userIds string) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - if len(busChannel) == 0 { - return nil, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(userIds) == 0 { - return nil, RCErrorNewV2(1002, "param 'userIds' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/del.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userIds", userIds) - // http - return rc.do(req) -} - -type UGChannelPrivateUserAddObj struct { - Code int `json:"code"` -} - -// UGChannelPrivateUserAddResObj :私有频道白名单用户-添加 /ultragroup/channel/private/users/add.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&userIds=a%2Cb%2Cc -// -// response :UGChannelPrivateUserAddObj -func (rc *RongCloud) UGChannelPrivateUserAddResObj(groupId, busChannel, userIds string) (UGChannelPrivateUserAddObj, error) { - var ( - result = UGChannelPrivateUserAddObj{} - ) - if len(groupId) == 0 { - return result, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return result, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(userIds) == 0 { - return result, RCErrorNewV2(1002, "param 'userIds' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/add.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userIds", userIds) - // http - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UGChannelPrivateUserAdd :私有频道白名单用户-添加 /ultragroup/channel/private/users/add.json -// -// groupId=ug_m_gid_lw_1&busChannel=channel001&userIds=a%2Cb%2Cc -func (rc *RongCloud) UGChannelPrivateUserAdd(groupId, busChannel, userIds string) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return nil, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(userIds) == 0 { - return nil, RCErrorNewV2(1002, "param 'userIds' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/private/users/add.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userIds", userIds) - // http - return rc.do(req) -} - -// UGGroupChannelCreate : 频道创建-支持设置频道类型/ultragroup/channel/create.json -// * -// groupId=ug_m_gid_lw_1&busChannel=channel001&type=0 -// -// response:byte数组 -// *// -func (rc *RongCloud) UGGroupChannelCreate(groupId, busChannel, t string) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return nil, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(t) == 0 { - return nil, RCErrorNewV2(1002, "param 'type' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/create.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("type", t) - // http - return rc.do(req) -} - -type UGGroupChannelChangeObj struct { - Code int `json:"code"` -} - -// UGGroupChannelChangeResObj : /ultragroup/channel/type/change 公私频道类型设置(切换) -// * -// -// @param: groupId -// @param: busChannel -// @param: type -// -// *// -func (rc *RongCloud) UGGroupChannelChangeResObj(groupId, busChannel, t string) (UGGroupChannelChangeObj, error) { - var ( - result = UGGroupChannelChangeObj{} - ) - if len(groupId) == 0 { - return result, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return result, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(t) == 0 { - return result, RCErrorNewV2(1002, "param 'type' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/type/change.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("type", t) - // http - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UGGroupChannelChange : /ultragroup/channel/type/change 公私频道类型设置(切换) -// * -// -// @param: groupId -// @param: busChannel -// @param: type -// -// *// -func (rc *RongCloud) UGGroupChannelChange(groupId, busChannel, t string) ([]byte, error) { - if len(groupId) == 0 { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if len(busChannel) == 0 { - return nil, RCErrorNewV2(1002, "param 'busChannel' is required") - } - - if len(t) == 0 { - return nil, RCErrorNewV2(1002, "param 'type' is required") - } - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/type/change.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("type", t) - // http - return rc.do(req) -} - -// 创建群组 -func (rc *RongCloud) UGGroupCreate(userId, groupId, groupName string) (err error, requestId string) { - if userId == "" { - return RCErrorNewV2(1002, "param 'userId' is required"), "" - } - - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - if groupName == "" { - return RCErrorNewV2(1002, "param 'groupName' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups", rc.rongCloudURI) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{"user_id": userId, - "group_id": groupId, - "group_name": groupName, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 解散群组 -func (rc *RongCloud) UGGroupDismiss(groupId string) (err error, requestId string) { - - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s", rc.rongCloudURI, groupId) - req := httplib.Delete(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 加入群组 -func (rc *RongCloud) UGGroupJoin(userId, groupId string) (err error, requestId string) { - if userId == "" { - return RCErrorNewV2(1002, "param 'userId' is required"), "" - } - - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/users/%s", rc.rongCloudURI, groupId, userId) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 退出群组 -func (rc *RongCloud) UGGroupQuit(userId, groupId string) (err error, requestId string) { - if userId == "" { - return RCErrorNewV2(1002, "param 'userId' is required"), "" - } - - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/users/%s", rc.rongCloudURI, groupId, userId) - req := httplib.Delete(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 刷新群组信息 -func (rc *RongCloud) UGGroupUpdate(groupId, groupName string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - if groupName == "" { - return RCErrorNewV2(1002, "param 'groupName' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s", rc.rongCloudURI, groupId) - req := httplib.Put(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "group_name": groupName, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 查询用户所在群组(P1) -func (rc *RongCloud) UGQueryUserGroups(userId string, page, size int) (groups []UGGroupInfo, err error, requestId string) { - if userId == "" { - return nil, RCErrorNewV2(1002, "param 'userId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/users/%s/groups", rc.rongCloudURI, userId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - req.Param("page", strconv.Itoa(page)) - req.Param("size", strconv.Itoa(size)) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return groups, err, requestId - } - - // 处理返回结果 - var respJson RespDataArray - if err := json.Unmarshal(respBody, &respJson); err != nil { - return groups, err, requestId - } - - if respJson.Data != nil { - if gs, ok := respJson.Data["groups"]; ok { - if gs != nil { - for _, v := range gs { - t := UGGroupInfo{GroupId: fmt.Sprint(v["group_id"]), - GroupName: fmt.Sprint(v["group_name"])} - groups = append(groups, t) - } - } - } - } - - return groups, err, requestId -} - -// 查询群成员(P1) -func (rc *RongCloud) UGQueryGroupUsers(groupId string, page, size int) (users []UGUserInfo, err error, requestId string) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/users", rc.rongCloudURI, groupId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - req.Param("page", strconv.Itoa(page)) - req.Param("size", strconv.Itoa(size)) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return users, err, requestId - } - - // 处理返回结果 - var respJson RespDataArray - if err := json.Unmarshal(respBody, &respJson); err != nil { - return users, err, requestId - } - - if respJson.Data != nil { - if gs, ok := respJson.Data["users"]; ok { - if gs != nil { - for _, v := range gs { - t := UGUserInfo{Id: fmt.Sprint(v["id"])} - users = append(users, t) - } - } - } - } - - return users, err, requestId -} - -// 消息发送 普通消息 -func (rc *RongCloud) UGGroupSend(msg UGMessage) (err error, requestId string) { - if msg.FromUserId == "" { - return RCErrorNewV2(1002, "Paramer 'FromUserId' is required"), "" - } - - if len(msg.ToGroupIds) == 0 { - return RCErrorNewV2(1002, "Paramer 'ToGroupIds' is required"), "" - } - - url := fmt.Sprintf("%s/v2/message/ultragroup/send", rc.rongCloudURI) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - _, err = req.JSONBody(msg) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 添加禁言成员 -func (rc *RongCloud) UGGroupMuteMembersAdd(groupId string, userIds []string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - if len(userIds) == 0 { - return RCErrorNewV2(1002, "Paramer 'userIds' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/muted-users", rc.rongCloudURI, groupId) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "user_ids": userIds, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 移除禁言成员 -func (rc *RongCloud) UGGroupMuteMembersRemove(groupId string, userIds []string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - if len(userIds) == 0 { - return RCErrorNewV2(1002, "Paramer 'userIds' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/muted-users", rc.rongCloudURI, groupId) - req := httplib.Delete(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "user_ids": userIds, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 获取禁言成员 -func (rc *RongCloud) UGGroupMuteMembersGetList(groupId string) (users []UGUserInfo, err error, requestId string) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/muted-users", rc.rongCloudURI, groupId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return users, err, requestId - } - - // 处理返回结果 - var respJson RespDataArray - if err := json.Unmarshal(respBody, &respJson); err != nil { - return users, err, requestId - } - - if respJson.Data != nil { - if gs, ok := respJson.Data["users"]; ok { - if gs != nil { - for _, v := range gs { - t := UGUserInfo{Id: fmt.Sprint(v["id"]), - MutedTime: fmt.Sprint(v["time"])} - users = append(users, t) - } - } - } - } - - return users, err, requestId -} - -// 设置全体成员禁言 -func (rc *RongCloud) UGGroupMuted(groupId string, status bool) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/muted-status", rc.rongCloudURI, groupId) - req := httplib.Put(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "status": status, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 获取群全体成员禁言状态 -func (rc *RongCloud) UGGroupMutedQuery(groupId string) (status bool, err error, requestId string) { - if groupId == "" { - return status, RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/muted-status", rc.rongCloudURI, groupId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return status, err, requestId - } - - // 处理返回结果 - var respJson RespDataKV - if err := json.Unmarshal(respBody, &respJson); err != nil { - return status, err, requestId - } - - if respJson.Data != nil { - if s, ok := respJson.Data["status"]; ok { - status, err = strconv.ParseBool(fmt.Sprint(s)) - } - } - - return status, err, requestId -} - -// 添加禁言白名单 -func (rc *RongCloud) UGGroupMutedWhitelistAdd(groupId string, userIds []string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - if len(userIds) == 0 { - return RCErrorNewV2(1002, "Paramer 'userIds' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/allowed-users", rc.rongCloudURI, groupId) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "user_ids": userIds, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 移除禁言白名单 -func (rc *RongCloud) UGGroupMutedWhitelistRemove(groupId string, userIds []string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "Paramer 'groupId' is required"), "" - } - - if len(userIds) == 0 { - return RCErrorNewV2(1002, "Paramer 'userIds' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/allowed-users", rc.rongCloudURI, groupId) - req := httplib.Delete(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // json body - postBody := map[string]interface{}{ - "user_ids": userIds, - } - _, err = req.JSONBody(postBody) - if err != nil { - return err, "" - } - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 获取禁言白名单 -func (rc *RongCloud) UGGroupMutedWhitelistQuery(groupId string) (users []UGUserInfo, err error, requestId string) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/allowed-users", rc.rongCloudURI, groupId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return users, err, requestId - } - - // 处理返回结果 - var respJson RespDataArray - if err := json.Unmarshal(respBody, &respJson); err != nil { - return users, err, requestId - } - - if respJson.Data != nil { - if gs, ok := respJson.Data["users"]; ok { - if gs != nil { - for _, v := range gs { - t := UGUserInfo{Id: fmt.Sprint(v["id"])} - users = append(users, t) - } - } - } - } - - return users, err, requestId -} - -// 创建群频道 -func (rc *RongCloud) UGChannelCreate(groupId, channelId string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - if channelId == "" { - return RCErrorNewV2(1002, "param 'channelId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/channels", rc.rongCloudURI) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - body := map[string]interface{}{ - "group_id": groupId, - "channel_id": channelId, - } - - if _, err = req.JSONBody(body); err != nil { - return err, "" - } - - if _, err = rc.doV2(req); err != nil { - return err, "" - } - - return nil, requestId -} - -// 删除群频道 -func (rc *RongCloud) UGChannelDelete(groupId, channelId string) (err error, requestId string) { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - if channelId == "" { - return RCErrorNewV2(1002, "param 'channelId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/channels/%s", rc.rongCloudURI, groupId, channelId) - req := httplib.Delete(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - // http - _, err = rc.doV2(req) - - return err, requestId -} - -// 查询群频道列表 -func (rc *RongCloud) UGChannelQuery(groupId string, page, size int) (channels []UGChannelInfo, err error, requestId string) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required"), "" - } - - url := fmt.Sprintf("%s/v2/ultragroups/%s/channels", rc.rongCloudURI, groupId) - req := httplib.Get(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - requestId = rc.fillHeaderV2(req) - - req.Param("page", strconv.Itoa(page)) - req.Param("limit", strconv.Itoa(size)) - - // http - respBody, err := rc.doV2(req) - if err != nil { - return channels, err, requestId - } - - // 处理返回结果 - var respJson RespDataArray - if err := json.Unmarshal(respBody, &respJson); err != nil { - return channels, err, requestId - } - - if respJson.Data != nil { - if gs, ok := respJson.Data["channel_list"]; ok { - if gs != nil { - for _, v := range gs { - t := UGChannelInfo{ChannelId: fmt.Sprint(v["channel_id"]), - CreateTime: fmt.Sprint(v["create_time"])} - channels = append(channels, t) - } - } - } - } - - return channels, err, requestId -} - -// UGMessageExpansionSet 设置扩展 -func (rc *RongCloud) UGMessageExpansionSet(groupId, userId, msgUID, busChannel string, extra map[string]string) error { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required") - } - - if userId == "" { - return RCErrorNewV2(1002, "param 'userId' is required") - } - - if msgUID == "" { - return RCErrorNewV2(1002, "param 'msgUID' is required") - } - - if extra == nil { - return RCErrorNewV2(1002, "param 'extra' is required") - } - - if len(extra) > 100 { - return RCErrorNewV2(1002, "param 'extra' is too long") - } - - encExtra, err := json.Marshal(extra) - if err != nil { - return err - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/message/expansion/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("groupId", groupId) - req.Param("extraKeyVal", string(encExtra)) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - if _, err = rc.doV2(req); err != nil { - return err - } - - return nil -} - -// UGMessageExpansionDelete 删除扩展 -func (rc *RongCloud) UGMessageExpansionDelete(groupId, userId, msgUID, busChannel string, keys ...string) error { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required") - } - - if userId == "" { - return RCErrorNewV2(1002, "param 'userId' is required") - } - - if msgUID == "" { - return RCErrorNewV2(1002, "param 'msgUID' is required") - } - - if klens := len(keys); klens <= 0 || klens > 100 { - return RCErrorNewV2(1002, "invalid param keys") - } - - encKeys, err := json.Marshal(keys) - if err != nil { - return err - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/message/expansion/delete." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("userId", userId) - req.Param("groupId", groupId) - req.Param("extraKey", string(encKeys)) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - if _, err = rc.doV2(req); err != nil { - return err - } - - return nil -} - -type UGMessageExpansionItem struct { - Key string `json:"key"` - Value string `json:"value"` - Timestamp int64 `json:"timestamp"` -} - -// UGMessageExpansionQuery 获取扩展信息 -func (rc *RongCloud) UGMessageExpansionQuery(groupId, msgUID, busChannel string) ([]UGMessageExpansionItem, error) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if msgUID == "" { - return nil, RCErrorNewV2(1002, "param 'msgUID' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/message/expansion/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("msgUID", msgUID) - req.Param("groupId", groupId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - body, err := rc.doV2(req) - - if err != nil { - return nil, err - } - - resp := struct { - Code int `json:"code"` - ExtraContent map[string]map[string]interface{} `json:"extraContent"` - }{} - if err = json.Unmarshal(body, &resp); err != nil { - return nil, err - } - - if resp.Code != 200 { - return nil, fmt.Errorf("Response error. code: %d", resp.Code) - } - - var data []UGMessageExpansionItem - for key, val := range resp.ExtraContent { - item := UGMessageExpansionItem{ - Key: key, - } - - if v, ok := val["v"]; ok { - item.Value = v.(string) - } - - if ts, ok := val["ts"]; ok { - item.Timestamp = int64(ts.(float64)) - } - - data = append(data, item) - } - - return data, nil -} - -type PushExt struct { - Title string `json:"title,omitempty"` - TemplateId string `json:"templateId,omitempty"` - ForceShowPushContent int `json:"forceShowPushContent,omitempty"` - PushConfigs []map[string]map[string]string `json:"pushConfigs,omitempty"` -} - -// UGMessagePublish 超级群消息发送 -// 文档:https://doc.rongcloud.cn/imserver/server/v1/message/msgsend/ultragroup -func (rc *RongCloud) UGMessagePublish(fromUserId, objectName, content, pushContent, pushData, isPersisted, isCounted, isMentioned, contentAvailable, busChannel, extraContent string, expansion, unreadCountFlag bool, pushExt *PushExt, toGroupIds ...string) error { - if len(fromUserId) == 0 { - return RCErrorNewV2(1002, "param 'fromUserId' is required") - } - - if len(objectName) == 0 { - return RCErrorNewV2(1002, "param 'objectName' is required") - } - - if len(content) == 0 { - return RCErrorNewV2(1002, "param 'content' is required") - } - - if groupLen := len(toGroupIds); groupLen <= 0 || groupLen > 3 { - return RCErrorNewV2(1002, "invalid 'toGroupIds'") - } - - req := httplib.Post(rc.rongCloudURI + "/message/ultragroup/publish." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - body := map[string]interface{}{ - "fromUserId": fromUserId, - "toGroupIds": toGroupIds, - "objectName": objectName, - "content": content, - "expansion": expansion, - } - - if pushContent != "" { - body["pushContent"] = pushContent - } - - if pushData != "" { - body["pushData"] = pushData - } - - if isPersisted != "" { - body["isPersisted"] = isPersisted - } - - if isMentioned != "" { - body["isMentioned"] = isMentioned - } - - if isMentioned != "1" { - body["unreadCountFlag"] = unreadCountFlag - } - - if contentAvailable != "" { - body["contentAvailable"] = contentAvailable - } - - if busChannel != "" { - body["busChannel"] = busChannel - } - - if extraContent != "" { - body["extraContent"] = extraContent - } - - body["isCounted"] = isCounted - if len(isCounted) == 0 || isCounted != "1" && isCounted != "0" { - body["isCounted"] = "1" - } - - if pushExt != nil { - encPushExt, e := json.Marshal(pushExt) - if e != nil { - return e - } - body["pushExt"] = string(encPushExt) - } - - var err error - req, err = req.JSONBody(body) - if err != nil { - return err - } - - if _, err = rc.doV2(req); err != nil { - return err - } - - return nil -} - -// UGMemberExists 查询用户是否在超级群中 -func (rc *RongCloud) UGMemberExists(groupId, userId string) (bool, error) { - if groupId == "" { - return false, RCErrorNewV2(1002, "param 'groupId' is required") - } - - if userId == "" { - return false, RCErrorNewV2(1002, "param 'userId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/member/exist." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userId", userId) - - body, err := rc.doV2(req) - if err != nil { - return false, err - } - - resp := struct { - Code int `json:"code"` - Status bool `json:"status"` - }{} - - if err = json.Unmarshal(body, &resp); err != nil { - return false, err - } - - if resp.Code != http.StatusOK { - return false, fmt.Errorf("Response error. code: %d", resp.Code) - } - - return resp.Status, nil -} - -// UGNotDisturbSet 设置群/频道默认免打扰接口 -func (rc *RongCloud) UGNotDisturbSet(groupId string, unPushLevel int, busChannel string) error { - if groupId == "" { - return RCErrorNewV2(1002, "param 'groupId' is required") - } - - if unPushLevel != UGUnPushLevelAllMessage && unPushLevel != UGUnPushLevelNotSet && unPushLevel != UGUnPushLevelAtMessage && - unPushLevel != UGUnPushLevelAtUser && unPushLevel != UGUnPushLevelAtAllGroupMembers && unPushLevel != UGUnPushLevelNotRecv { - return RCErrorNewV2(1002, "param 'unPushLevel' was wrong") - } - - var err error - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/notdisturb/set.json") - - req.Param("groupId", groupId) - req.Param("unpushLevel", strconv.Itoa(unPushLevel)) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - data, err := rc.doV2(req) - if err != nil { - return err - } - - resp := struct { - Code int `json:"code"` - }{} - if err = json.Unmarshal(data, &resp); err != nil { - return err - } - - if resp.Code != http.StatusOK { - return fmt.Errorf("Response error. code: %d", resp.Code) - } - - return nil -} - -type UGNotDisturbGetResponses struct { - GroupId string `json:"groupId"` - BusChannel string `json:"busChannel"` - UnPushLevel int `json:"unpushLevel"` -} - -func (rc *RongCloud) UGNotDisturbGet(groupId, busChannel string) (*UGNotDisturbGetResponses, error) { - if groupId == "" { - return nil, RCErrorNewV2(1002, "param 'groupId' is required") - } - - var err error - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/notdisturb/get.json") - - req.Param("groupId", groupId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - - rc.fillHeader(req) - - data, err := rc.doV2(req) - if err != nil { - return nil, err - } - - resp := struct { - Code int `json:"code"` - GroupId string `json:"groupId"` - BusChannel string `json:"busChannel"` - UnPushLevel int `json:"unpushLevel"` - }{} - if err = json.Unmarshal(data, &resp); err != nil { - return nil, err - } - - if resp.Code != http.StatusOK { - return nil, fmt.Errorf("Response error. code: %d", resp.Code) - } - - return &UGNotDisturbGetResponses{ - GroupId: resp.GroupId, - BusChannel: resp.BusChannel, - UnPushLevel: resp.UnPushLevel, - }, nil -} - -// UltraGroupCreate 创建超级群 -func (rc *RongCloud) UltraGroupCreate(userId, groupId, groupName string) error { - if userId == "" { - return RCErrorNew(1002, "param 'userId' is empty") - } - - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if groupName == "" { - return RCErrorNew(1002, "param 'groupName' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/create.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("userId", userId) - req.Param("groupId", groupId) - req.Param("groupName", groupName) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupDis 解散超级群 -func (rc *RongCloud) UltraGroupDis(groupId string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/dis.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupJoin 加入超级群 -func (rc *RongCloud) UltraGroupJoin(userId, groupId string) error { - if userId == "" { - return RCErrorNew(1002, "param 'userId' is empty") - } - - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/join.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("userId", userId) - req.Param("groupId", groupId) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupQuit 退出超级群 -func (rc *RongCloud) UltraGroupQuit(userId, groupId string) error { - if userId == "" { - return RCErrorNew(1002, "param 'userId' is empty") - } - - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/quit.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("userId", userId) - req.Param("groupId", groupId) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupRefresh 刷新超级群信息 -func (rc *RongCloud) UltraGroupRefresh(groupId, groupName string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if groupName == "" { - return RCErrorNew(1002, "param 'groupName' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/refresh.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("groupName", groupName) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupUserBannedAdd 添加禁言成员 -func (rc *RongCloud) UltraGroupUserBannedAdd(groupId, busChannel string, userIds ...string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if userIds == nil || len(userIds) <= 0 { - return RCErrorNew(1002, "param 'userIds' is empty") - } - - if len(userIds) > 20 { - return RCErrorNew(1002, "param 'userIds' is too long") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/userbanned/add.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupUserBannedDel 移除禁言成员 -func (rc *RongCloud) UltraGroupUserBannedDel(groupId, busChannel string, userIds ...string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if userIds == nil || len(userIds) <= 0 { - return RCErrorNew(1002, "param 'userIds' is empty") - } - - if len(userIds) > 20 { - return RCErrorNew(1002, "param 'userIds' is too long") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/userbanned/del.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -type UltraGroupUserBannedResponseItem struct { - Id string `json:"id"` -} - -// UltraGroupUserBannedGet 获取禁言成员 -func (rc *RongCloud) UltraGroupUserBannedGet(groupId, busChannel string, page, pageSize int) ([]UltraGroupUserBannedResponseItem, error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/userbanned/get.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - if page != 0 { - req.Param("page", strconv.Itoa(page)) - } - - if pageSize != 0 { - req.Param("pageSize", strconv.Itoa(pageSize)) - } - - resp, err := rc.do(req) - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - Users []UltraGroupUserBannedResponseItem `json:"users"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return nil, err - } - - if data.Code != 200 { - return nil, fmt.Errorf("response error. code: %d", data.Code) - } - - return data.Users, nil -} - -// UltraGroupGlobalBannedSet 设置超级群禁言状态 -func (rc *RongCloud) UltraGroupGlobalBannedSet(groupId, busChannel string, status bool) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/globalbanned/set.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("status", strconv.FormatBool(status)) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupGlobalBannedGet 查询超级群禁言状态 -func (rc *RongCloud) UltraGroupGlobalBannedGet(groupId, busChannel string) (bool, error) { - if groupId == "" { - return false, RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/globalbanned/get.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return false, err - } - - data := struct { - Code int `json:"code"` - Status bool `json:"status"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return false, err - } - - if data.Code != 200 { - return false, fmt.Errorf("response error. code: %d", data.Code) - } - - return data.Status, nil -} - -// UltraGroupBannedWhiteListAdd 添加禁言白名单 -func (rc *RongCloud) UltraGroupBannedWhiteListAdd(groupId, busChannel string, userIds ...string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if userIds == nil || len(userIds) <= 0 { - return RCErrorNew(1002, "param 'userIds' is empty") - } - - if len(userIds) > 20 { - return RCErrorNew(1002, "param 'userIds' is too long") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/banned/whitelist/add.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupBannedWhiteListDel 移除禁言白名单 -func (rc *RongCloud) UltraGroupBannedWhiteListDel(groupId, busChannel string, userIds ...string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if userIds == nil || len(userIds) <= 0 { - return RCErrorNew(1002, "param 'userIds' is empty") - } - - if len(userIds) > 20 { - return RCErrorNew(1002, "param 'userIds' is too long") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/banned/whitelist/del.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -type UltraGroupBannedWhiteListGetResponseItem struct { - Id string `json:"id"` -} - -// UltraGroupBannedWhiteListGet 获取禁言白名单 -func (rc *RongCloud) UltraGroupBannedWhiteListGet(groupId, busChannel string, page, pageSize int) ([]UltraGroupBannedWhiteListGetResponseItem, error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/banned/whitelist/get.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - - if busChannel != "" { - req.Param("busChannel", busChannel) - } - - if page != 0 { - req.Param("page", strconv.Itoa(page)) - } - - if pageSize != 0 { - req.Param("pageSize", strconv.Itoa(pageSize)) - } - - resp, err := rc.do(req) - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - Users []UltraGroupBannedWhiteListGetResponseItem `json:"users"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return nil, err - } - - if data.Code != 200 { - return nil, fmt.Errorf("response error. code: %d", data.Code) - } - - return data.Users, nil -} - -// UltraGroupChannelCreate 创建频道 -func (rc *RongCloud) UltraGroupChannelCreate(groupId, busChannel string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if busChannel == "" { - return RCErrorNew(1002, "param 'busChannel' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/create.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -// UltraGroupChannelDel 删除频道 -func (rc *RongCloud) UltraGroupChannelDel(groupId, busChannel string) error { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is empty") - } - - if busChannel == "" { - return RCErrorNew(1002, "param 'busChannel' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/del.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - - resp, err := rc.do(req) - if err != nil { - return err - } - - data := struct { - Code int `json:"code"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return err - } - - if data.Code != 200 { - return fmt.Errorf("response error. code: %d", data.Code) - } - - return nil -} - -type UltraGroupChannelGetResponseItem struct { - ChannelId string `json:"channelId"` - Type int `json:"type"` - CreateTime string `json:"createTime"` -} - -// UltraGroupChannelGet 查询频道列表 -// response:[]UltraGroupChannelGetResponseItem -func (rc *RongCloud) UltraGroupChannelGet(groupId string, page, limit int) ([]UltraGroupChannelGetResponseItem, error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is empty") - } - - req := httplib.Post(rc.rongCloudURI + "/ultragroup/channel/get.json") - - req.SetTimeout(rc.timeout*time.Second, rc.timeout*time.Second) - rc.fillHeader(req) - - req.Param("groupId", groupId) - - if page != 0 { - req.Param("page", strconv.Itoa(page)) - } - - if limit != 0 { - req.Param("limit", strconv.Itoa(limit)) - } - - resp, err := rc.do(req) - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - Channels []UltraGroupChannelGetResponseItem `json:"channelList"` - }{} - - if err = json.Unmarshal(resp, &data); err != nil { - return nil, err - } - - if data.Code != 200 { - return nil, fmt.Errorf("response error. code: %d", data.Code) - } - - return data.Channels, nil -} - -// UGUserGroupAdd 批量新建用户组 -func (rc *RongCloud) UGUserGroupAdd(groupId string, userGroups []UGUserGroupInfo) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if userGroups == nil || len(userGroups) < 1 { - return RCErrorNew(1002, "param 'userGroups' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/add.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - body := map[string]interface{}{ - "groupId": groupId, - "userGroups": userGroups, - } - - if _, err = req.JSONBody(body); err != nil { - return err - } - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGUserGroupDelete 批量删除用户组 -func (rc *RongCloud) UGUserGroupDelete(groupId string, userGroupIds []string) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if userGroupIds == nil || len(userGroupIds) < 1 { - return RCErrorNew(1002, "param 'userGroupIds' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/del.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userGroupIds", strings.Join(userGroupIds, ",")) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGUserGroupDelete 分页查询超级群下用户组信息 -func (rc *RongCloud) UGUserGroupQuery(groupId string, page, pageSize int) (userGroups []UGUserGroupInfo, err error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/query.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("page", strconv.Itoa(page)) - req.Param("pageSize", strconv.Itoa(pageSize)) - - respBody, err := rc.do(req) - - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - UserGroups []UGUserGroupInfo `json:"userGroups"` - }{} - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, err - } - - return data.UserGroups, nil -} - -// UGUserGroupUserAdd 用户组批量增加用户 -func (rc *RongCloud) UGUserGroupUserAdd(groupId, userGroupId string, userIds []string) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if userGroupId == "" { - return RCErrorNew(1002, "param 'userGroupId' is required") - } - - if userIds == nil || len(userIds) < 1 { - return RCErrorNew(1002, "param 'userIds' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/user/add.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userGroupId", userGroupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGUserGroupUserDelete 用户组批量移除用户 -func (rc *RongCloud) UGUserGroupUserDelete(groupId, userGroupId string, userIds []string) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if userGroupId == "" { - return RCErrorNew(1002, "param 'userGroupId' is required") - } - - if userIds == nil || len(userIds) < 1 { - return RCErrorNew(1002, "param 'userIds' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/user/del.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userGroupId", userGroupId) - req.Param("userIds", strings.Join(userIds, ",")) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGUserUserGroupQuery 查询用户在超级群下所属的用户组列表 -func (rc *RongCloud) UGUserUserGroupQuery(groupId, userId string, page, pageSize int) (userGroupIds []string, err error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is required") - } - - if userId == "" { - return nil, RCErrorNew(1002, "param 'userId' is required") - } - - url := fmt.Sprintf("%s/ultragroup/user/usergroup/query.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userId", userId) - req.Param("page", strconv.Itoa(page)) - req.Param("pageSize", strconv.Itoa(pageSize)) - - respBody, err := rc.do(req) - - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - UserGroupIds []string `json:"data"` - }{} - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, err - } - - return data.UserGroupIds, nil -} - -// UGChannelUserGroupBind 频道批量绑定用户组 -func (rc *RongCloud) UGChannelUserGroupBind(groupId, busChannel string, userGroupIds []string) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if busChannel == "" { - return RCErrorNew(1002, "param 'busChannel' is required") - } - - if userGroupIds == nil || len(userGroupIds) < 1 { - return RCErrorNew(1002, "param 'userGroupIds' is required") - } - - url := fmt.Sprintf("%s/ultragroup/channel/usergroup/bind.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userGroupIds", strings.Join(userGroupIds, ",")) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGChannelUserGroupUnbind 频道批量解绑用户组 -func (rc *RongCloud) UGChannelUserGroupUnbind(groupId, busChannel string, userGroupIds []string) (err error) { - if groupId == "" { - return RCErrorNew(1002, "param 'groupId' is required") - } - - if busChannel == "" { - return RCErrorNew(1002, "param 'busChannel' is required") - } - - if userGroupIds == nil || len(userGroupIds) < 1 { - return RCErrorNew(1002, "param 'userGroupIds' is required") - } - - url := fmt.Sprintf("%s/ultragroup/channel/usergroup/unbind.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("userGroupIds", strings.Join(userGroupIds, ",")) - - if _, err = rc.do(req); err != nil { - return err - } - - return nil -} - -// UGChannelUserGroupQuery 查询频道绑定的用户组列表 -func (rc *RongCloud) UGChannelUserGroupQuery(groupId, busChannel string, page, pageSize int) (userGroupIds []string, err error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is required") - } - - if busChannel == "" { - return nil, RCErrorNew(1002, "param 'busChannel' is required") - } - - url := fmt.Sprintf("%s/ultragroup/channel/usergroup/query.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("busChannel", busChannel) - req.Param("page", strconv.Itoa(page)) - req.Param("pageSize", strconv.Itoa(pageSize)) - - respBody, err := rc.do(req) - - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - UserGroupIds []string `json:"data"` - }{} - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, err - } - - return data.UserGroupIds, nil -} - -// UGUserGroupChannelQuery 查询用户组绑定的频道列表 -func (rc *RongCloud) UGUserGroupChannelQuery(groupId, userGroupId string, page, pageSize int) (busChannelIds []string, err error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is required") - } - - if userGroupId == "" { - return nil, RCErrorNew(1002, "param 'userGroupId' is required") - } - - url := fmt.Sprintf("%s/ultragroup/usergroup/channel/query.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userGroupId", userGroupId) - req.Param("page", strconv.Itoa(page)) - req.Param("pageSize", strconv.Itoa(pageSize)) - - respBody, err := rc.do(req) - - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - BusChannelIds []string `json:"data"` - }{} - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, err - } - - return data.BusChannelIds, nil -} - -// UGUserChannelQuery 查询用户所属的频道白名单列表 -func (rc *RongCloud) UGUserChannelQuery(groupId, userId string, page, pageSize int) (busChannelIds []string, err error) { - if groupId == "" { - return nil, RCErrorNew(1002, "param 'groupId' is required") - } - - if userId == "" { - return nil, RCErrorNew(1002, "param 'userId' is required") - } - - url := fmt.Sprintf("%s/ultragroup/user/channel/query.%s", rc.rongCloudURI, ReqType) - req := httplib.Post(url) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - req.Param("groupId", groupId) - req.Param("userId", userId) - req.Param("page", strconv.Itoa(page)) - req.Param("pageSize", strconv.Itoa(pageSize)) - - respBody, err := rc.do(req) - - if err != nil { - return nil, err - } - - data := struct { - Code int `json:"code"` - BusChannelIds []string `json:"data"` - }{} - - if err := json.Unmarshal(respBody, &data); err != nil { - return nil, err - } - - return data.BusChannelIds, nil -} diff --git a/sdk/ultragroup_test.go b/sdk/ultragroup_test.go deleted file mode 100644 index d9eab83..0000000 --- a/sdk/ultragroup_test.go +++ /dev/null @@ -1,694 +0,0 @@ -package sdk - -import ( - "os" - "testing" -) - -func TestRongCloud_UGHisMsgIdQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGHisMsgIdQuery( - "wxlGroup", - "wxlBusChannel", - "AAAA-BBBB-CCCC-DDDD", - "10", - "10") - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UltraGroupChannelGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UltraGroupChannelGet( - "ug_m_gid_lw_1", - 1, - 1, - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UGGroupChannelGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGGroupChannelGet( - "ug_m_gid_lw_1", - 001, - 1, - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -// go test -v -run TestRongCloud_UGHistoryQuery -func TestRongCloud_UGHistoryQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - result, err := rc.UGHistoryQuery("474", "2360", 1667491234000, 1668428009000, "275105", 0) - if err != nil { - t.Errorf("UGHistoryQuery err:%v", err) - return - } - t.Log("result is", result) - -} - -func TestRongCloud_UGChannelPrivateUserGetResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserGetResObj( - "ug_m_gid_lw_1", - "channel001", - "1", - "1", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UGChannelPrivateUserGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserGet( - "ug_m_gid_lw_1", - "channel001", - "1", - "1", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -func TestRongCloud_UGChannelPrivateUserDelResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserDelResObj( - "ug_m_gid_lw_1", - "channel001", - "0", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UGChannelPrivateUserDel(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserDel( - "ug_m_gid_lw_1", - "channel001", - "0", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -func TestRongCloud_UGChannelPrivateUserAddResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserAddResObj( - "ug_m_gid_lw_1", - "channel001", - "0", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UGChannelPrivateUserAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - res, err := rc.UGChannelPrivateUserAdd( - "ug_m_gid_lw_1", - "channel001", - "0", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -func TestRongCloud_UGGroupChannelCreate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UltraGroupCreate("1", "ug_m_gid_lw_1", "ug_m_gid_lw_1"); err != nil { - t.Errorf("UltraGroupCreate err:%v", err) - return - } - - res, err := rc.UGGroupChannelCreate( - "ug_m_gid_lw_1", - "channel001", - "0", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -func TestRongCloud_UGGroupChannelChangeResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - res, err := rc.UGGroupChannelChangeResObj( - "ug_m_gid_lw_1", - "channel001", - "1", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%+v", res) -} - -func TestRongCloud_UGGroupChannelChange(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - res, err := rc.UGGroupChannelChange( - "ug_m_gid_lw_1", - "channel001", - "1", - ) - if err != nil { - t.Errorf("err:%v", err) - return - } - t.Logf("res is:%v", string(res)) -} - -func Test_UGGroupUpdate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err, requestId := rc.UGGroupCreate( - "u02", - "rongcloud_group01", - "super", - ) - - t.Log(err) - t.Log(requestId) -} - -func Test_UGQueryUserGroups(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - groups, err, requestId := rc.UGQueryUserGroups("user001", 1, 20) - t.Log(requestId) - if err == nil { - t.Log(len(groups)) - for _, group := range groups { - t.Log(group.GroupId, " - ", group.GroupName) - } - } else { - t.Log(err) - } -} - -func Test_UGGroupSend(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - rcmsg := TXTMsg{ - Content: "hello", - Extra: "helloExtra", - } - - content, err := rcmsg.ToString() - if err != nil { - t.Log(err) - return - } - - var ugmsg UGMessage - ugmsg.FromUserId = "test1" - ugmsg.ToGroupIds = []string{"group1"} - ugmsg.ObjectName = "RC:TxtMsg" - ugmsg.Content = content - ugmsg.StoreFlag = true - - err, requestId := rc.UGGroupSend(ugmsg) - - t.Log(err) - t.Log(requestId) - -} - -func Test_UGMessageExpansionSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - m := map[string]string{} - m["k1"] = "v1" - m["k2"] = "v1" - m["k3"] = "v1" - - err := rc.UGMessageExpansionSet( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - m, - ) - - t.Log(err) - - err = rc.UGMessageExpansionSet( - "", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - m, - ) - - t.Log(err) - - err = rc.UGMessageExpansionSet( - "testExp0309", - "", - "BVET-SJMK-AT5B-ADFN", - "cc", - m, - ) - - t.Log(err) - - err = rc.UGMessageExpansionSet( - "testExp0309", - "ltZ1InfrF", - "", - "cc", - m, - ) - - t.Log(err) - - err = rc.UGMessageExpansionSet( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - nil, - ) - - t.Log(err) - - err = rc.UGMessageExpansionSet( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "", - m, - ) - - t.Log(err) -} - -func Test_UGMessageExpansionDelete(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.UGMessageExpansionDelete( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - "k1", "k2", - ) - t.Log(err) - - err = rc.UGMessageExpansionDelete( - "", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - "k1", "k2", - ) - t.Log(err) - - err = rc.UGMessageExpansionDelete( - "testExp0309", - "", - "BVET-SJMK-AT5B-ADFN", - "cc", - "k1", "k2", - ) - t.Log(err) - - err = rc.UGMessageExpansionDelete( - "testExp0309", - "ltZ1InfrF", - "", - "cc", - "k1", "k2", - ) - t.Log(err) - - err = rc.UGMessageExpansionDelete( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "cc", - "", - ) - t.Log(err) - - err = rc.UGMessageExpansionDelete( - "testExp0309", - "ltZ1InfrF", - "BVET-SJMK-AT5B-ADFN", - "", - "k1", "k2", - ) - t.Log(err) - -} - -func Test_UGMessageExpansionQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - data, requestId := rc.UGMessageExpansionQuery( - "testExp0309", - "BVET-SJMK-AT5B-ADFN", - "cc", - ) - - t.Log(data) - t.Log(requestId) -} - -func Test_UGMessagePublish(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.UGMessagePublish("aa", "RC:TxtMsg", "{\"content\":\"1234455667788-0309-1-test\"}", - "", "", "1", "", "0", "0", "", "{\"key1\":\"key1\"}", - false, false, &PushExt{ - Title: "you have a new message.", - TemplateId: "123456", - ForceShowPushContent: 0, - PushConfigs: []map[string]map[string]string{ - { - "HW": { - "channelId": "NotificationKanong", - }, - }, - { - "MI": { - "channelId": "rongcloud_kanong", - }, - }, - { - "OPPO": { - "channelId": "rc_notification_id", - }, - }, - { - "VIVO": { - "classification": "0", - }, - }, - { - "APNs": { - "thread-id": "1", - "apns-collapse-id": "1", - }, - }, - }, - }, "testExp0309") - - if err != nil { - t.Error(err) - return - } - t.Log("success") -} - -func Test_UGMemberExists(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - exists, err := rc.UGMemberExists("rongcloud_group01", "u01") - if err != nil { - t.Errorf("Failed to query member exists. err: %v", err) - return - } - - t.Logf("Exists: %t", exists) -} - -func Test_UGUserGroupAdd(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "groupId1" - userGroups := []UGUserGroupInfo{ - {UserGroupId: "id1"}, - {UserGroupId: "id2"}, - } - err := rc.UGUserGroupAdd(groupId, userGroups) - - t.Log(err) -} - -func Test_UGUserGroupDelete(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userGroups := []string{ - "roleId1", - "roleId2", - } - err := rc.UGUserGroupDelete(groupId, userGroups) - - t.Log(err) -} - -func Test_UGUserGroupQuery(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userGroups, err := rc.UGUserGroupQuery(groupId, 1, 10) - - t.Log(err) - t.Log(userGroups) -} - -func Test_UGUserGroupUserAdd(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userGroupId := "id" - userIds := []string{ - "user1", - "user2", - "user3", - } - err := rc.UGUserGroupUserAdd(groupId, userGroupId, userIds) - - t.Log(err) -} - -func Test_UGUserGroupUserDelete(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userGroupId := "id" - userIds := []string{ - "user1", - "user2", - "user3", - } - err := rc.UGUserGroupUserDelete(groupId, userGroupId, userIds) - - t.Log(err) -} - -func Test_UGUserUserGroupQuery(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userId := "userId" - userGroupIds, err := rc.UGUserUserGroupQuery(groupId, userId, 1, 10) - - t.Log(err) - t.Log(userGroupIds) -} - -func Test_UGChannelUserGroupBind(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - busChannel := "channelid" - userGroupIds := []string{ - "user1", - "user2", - "user3", - } - err := rc.UGChannelUserGroupBind(groupId, busChannel, userGroupIds) - - t.Log(err) -} - -func Test_UGChannelUserGroupUnbind(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - busChannel := "channelid" - userGroupIds := []string{ - "user1", - "user2", - "user3", - } - err := rc.UGChannelUserGroupUnbind(groupId, busChannel, userGroupIds) - - t.Log(err) -} - -func Test_UGChannelUserGroupQuery(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - busChannel := "buschannel1" - userGroupIds, err := rc.UGChannelUserGroupQuery(groupId, busChannel, 1, 10) - - t.Log(err) - t.Log(userGroupIds) -} - -func Test_UGUserGroupChannelQuery(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userGroupId := "userGroupId" - busChannelIds, err := rc.UGUserGroupChannelQuery(groupId, userGroupId, 1, 10) - - t.Log(err) - t.Log(busChannelIds) -} - -func Test_UGUserChannelQuery(t *testing.T) { - key := os.Getenv("APP_KEY") - secret := os.Getenv("APP_SECRET") - - rc := NewRongCloud(key, secret) - - groupId := "abc" - userId := "userId" - busChannelIds, err := rc.UGUserChannelQuery(groupId, userId, 1, 10) - - t.Log(err) - t.Log(busChannelIds) -} diff --git a/sdk/user.go b/sdk/user.go deleted file mode 100644 index 0704610..0000000 --- a/sdk/user.go +++ /dev/null @@ -1,983 +0,0 @@ -/* - * @Descripttion: - * @version: - * @Author: ran.ding - * @Date: 2019-09-02 18:29:55 - * @LastEditors: ran.ding - * @LastEditTime: 2019-09-10 11:22:38 - */ -package sdk - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" - "time" - - "github.com/astaxie/beego/httplib" -) - -// User 用户信息 返回信息 -type User struct { - Token string `json:"token"` - UserID string `json:"userId"` - BlockEndTime string `json:"blockEndTime,omitempty"` - Status string `json:"status,omitempty"` -} - -// BlockListResult 返回信息 -type BlockListResult struct { - Users []User `json:"users"` -} - -// BlacklistResult 返回信息 -type BlacklistResult struct { - Users []string `json:"users"` -} - -// Tag TagSet 参数 -type Tag struct { - UserID string `json:"userId"` // 用户 Id。(必传) - Tags []string `json:"tags"` // 用户标签,一个用户最多添加 20 个标签,每个 tag 最大不能超过 40 个字节,标签中不能包含特殊字符。(必传) -} - -// TagBatch TagBatchSet 参数 -type TagBatch struct { - UserIDs []string `json:"userIds"` // 用户 Id,一次最多支持 1000 个用户。(必传) - Tags []string `json:"tags"` // 用户标签,一个用户最多添加 20 个标签,每个 tag 最大不能超过 40 个字节,标签中不能包含特殊字符。(必传) -} - -// TagResult TagGet 返回值 -type TagResult struct { - *CodeResult - Result map[string][]string `json:"result"` // 用户所有的标签数组。 -} - -// WhiteList QueryWhiteList 返回数据 -type WhiteList struct { - Users []string `json:"users"` -} - -// UserBlockPushPeriodDelete 删除用户免打扰时段 /user/blockPushPeriod/delete.json -// * -// @param: userId 用户id,必传 -// -// *// -func (rc *RongCloud) UserBlockPushPeriodDelete(userId string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/blockPushPeriod/delete.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - _, err := rc.do(req) - if err != nil { - return err - } - return nil -} - -type PushPeriodGet struct { - Code int `json:"code"` - Data struct { - StartTime string `json:"startTime"` - Period int `json:"period"` - Level int `json:"unPushLevel"` - } -} - -// UserBlockPushPeriodGet UserBlockPushPeriodGet: 查用户免打扰时段 /user/blockPushPeriod/get.json -// * -// @param: userId 用户id,必传 -// -// response : PushPeriodGet -// -// *// -func (rc *RongCloud) UserBlockPushPeriodGet(userId string) (PushPeriodGet, error) { - data := PushPeriodGet{} - if len(userId) == 0 { - return data, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/blockPushPeriod/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - res, err := rc.do(req) - if err != nil { - return data, err - } - if err := json.Unmarshal(res, &data); err != nil { - return data, err - } - return data, nil -} - -// UserBlockPushPeriodSet :添加户免打扰时段 /user/blockPushPeriod/set.json -// * -// -// @param :userId 用户ID 必传 -// @param :startTime 开始时间(秒) 必传 -// @param :period 时段 (分钟) 必传 -// @param :level 免打扰级别 默认 1 不是必传 -// form表单 -// -// *// -func (rc *RongCloud) UserBlockPushPeriodSet(userId, startTime, period, level string) error { - if len(userId) <= 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(startTime) <= 0 { - return RCErrorNew(1002, "Paramer 'startTime' is required") - } - if len(period) <= 0 { - return RCErrorNew(1002, "Paramer 'period' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/blockPushPeriod/set.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("startTime", startTime) - req.Param("period", period) - if len(level) > 0 { - req.Param("level", level) - } else { - req.Param("level", strconv.Itoa(1)) - } - _, err := rc.do(req) - if err != nil { - return err - } - return nil -} - -// UserTokenExpireObj :的返回值定义 -type UserTokenExpireObj struct { - // 返回码,200 为正常 - Code int `json:"code"` -} - -// UserTokenExpireResObj /user/token/expire.json Token 失效 -// * -// -// @param: userId: 必传 需要设置 Token 失效的用户 ID,支持设置多个最多不超过 20 个 -// @param: time: 必传 过期时间戳精确到毫秒,该时间戳前用户获取的 Token 全部失效,使用时间戳之前的 Token 已经在连接中的用户不会立即失效,断开后无法进行连接。 -// response: UserTokenExpireObj -// 文档: https://doc.rongcloud.cn/imserver/server/v1/user/expire -// -// *// -func (rc *RongCloud) UserTokenExpireResObj(userId string, t int64) (UserTokenExpireObj, error) { - var result = UserTokenExpireObj{} - if len(userId) == 0 { - return result, RCErrorNew(1002, "Paramer 'userId' is required") - } - if t <= 0 { - return result, RCErrorNew(1002, "Paramer 'time' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/token/expire.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("time", fmt.Sprintf("%v", t)) - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UserTokenExpire /user/token/expire.json Token 失效 -// * -// -// @param: userId: 必传 需要设置 Token 失效的用户 ID,支持设置多个最多不超过 20 个 -// @param: time: 必传 过期时间戳精确到毫秒,该时间戳前用户获取的 Token 全部失效,使用时间戳之前的 Token 已经在连接中的用户不会立即失效,断开后无法进行连接。 -// response: byte数组 -// 文档 :https://doc.rongcloud.cn/imserver/server/v1/user/expire -// -// *// -func (rc *RongCloud) UserTokenExpire(userId string, t int64) ([]byte, error) { - if len(userId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'userId' is required") - } - if t <= 0 { - return nil, RCErrorNew(1002, "Paramer 'time' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/token/expire.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("time", fmt.Sprintf("%v", t)) - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// UserRemarksGetObj :UserRemarksGetResObj 的返回值 -type UserRemarksGetObj struct { - // 返回码,200 为正常。 - Code int `json:"code"` - - // 用户的备注名总数。 - Total int `json:"total"` - - // JSON 对象数组,包含用户 ID(id)和对应的备注名(remark)。单次最多返回 50 个用户备注名。 - Users []UserRemarksUsers `json:"users"` -} - -type UserRemarksUsers struct { - // 用户id - Id string `json:"id"` - - // 备注名字 - Remark string `json:"remark"` -} - -// UserRemarksGetResObj /user/remarks/get.json 查询用户级送备注名 -// * -// -// @param: userId :用户ID。 -// @param: page :页数,默认为第一页。 -// @param: size :每页条数,默认每页 50 条 -// response: UserRemarksGetObj -// 文档:https://doc.rongcloud.cn/imserver/server/v1/user/get-remark-for-push -// -// */ -func (rc *RongCloud) UserRemarksGetResObj(userId string, page, size int) (UserRemarksGetObj, error) { - var ( - result = UserRemarksGetObj{} - ) - if len(userId) == 0 { - return result, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/remarks/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("page", strconv.Itoa(page)) - req.Param("size", strconv.Itoa(size)) - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UserRemarksGet /user/remarks/get.json 查询用户级送备注名 -// * -// -// @param: userId :用户ID。 -// @param: page :页数,默认为第一页。 -// @param: size :每页条数,默认每页 50 条 -// -// response :byte数组 -// 文档:https://doc.rongcloud.cn/imserver/server/v1/user/get-remark-for-push -// */ -func (rc *RongCloud) UserRemarksGet(userId string, page, size int) ([]byte, error) { - if len(userId) == 0 { - return nil, RCErrorNew(1002, "Paramer 'userId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/remarks/get.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("page", strconv.Itoa(page)) - req.Param("size", strconv.Itoa(size)) - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// UserRemarksDel /user/remarks/del.json 删除用户级送备注名 -// * -// -// @param: userId :操作者用户ID。 -// @param: targetId:需要删除推送备注名的用户 ID -// -// */ -func (rc *RongCloud) UserRemarksDel(userId, targetId string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(targetId) == 0 { - return RCErrorNew(1002, "Paramer 'targetId' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/remarks/del.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("targetId", targetId) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// UserRemark :UserRemarksSet方法接收的参数 -type UserRemark struct { - // 目标用户 ID。单次最多设置 100 个 - Id string - - // 收到目标用户推送时显示的备注名。 - Remark string -} - -// UserRemarksSet /user/remarks/set.json -// * -// @param: userId:用户 ID。 -// @param: remarks:设置的目标用户推送备注名 JSON 字符串 -// -// */ -func (rc *RongCloud) UserRemarksSet(userId string, remarks []UserRemark) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(remarks) == 0 { - return RCErrorNew(1002, "Paramer 'remarks' is required") - } - remarkList, err := json.Marshal(remarks) - if err != nil { - return RCErrorNew(1002, "Marshal 'remarks' err") - } - req := httplib.Post(rc.rongCloudURI + "/user/remarks/set.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("remarks", string(remarkList)) - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// UserChatFbQueryListObj : 的返回结果 -type UserChatFbQueryListObj struct { - // 返回码,200 为正常。 - Code int `json:"code"` - - // 被禁言用户总数。 - Total int `json:"total"` - - // 被禁言用户数组。 - Users []string `json:"users"` -} - -// UserChatFbQueryListResObj * /user/chat/fb/querylist -// 查询禁言用户列表 -// @param: num :获取行数,默认为 100,最大支持 200 个 -// @param: offset :查询开始位置,默认为 0。 -// @param: t :会话类型,目前支持单聊会话 PERSON。 -// response: UserChatFbQueryListObj -// 文档: https://doc.rongcloud.cn/imserver/server/v1/user/ban -// */ -func (rc *RongCloud) UserChatFbQueryListResObj(num, offset int, t string) (UserChatFbQueryListObj, error) { - var ( - result = UserChatFbQueryListObj{} - ) - if num == 0 { - num = 100 - } - if len(t) == 0 { - return result, RCErrorNew(1002, "Paramer 'type' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/chat/fb/querylist.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("num", strconv.Itoa(num)) - req.Param("offset", strconv.Itoa(offset)) - req.Param("type", t) - res, err := rc.do(req) - if err != nil { - return result, err - } - if err := json.Unmarshal(res, &result); err != nil { - return result, err - } - return result, err -} - -// UserChatFbQueryList * /user/chat/fb/querylist -// 查询禁言用户列表 -// @param: num :获取行数,默认为 100,最大支持 200 个 -// @param: offset :查询开始位置,默认为 0。 -// @param: t :会话类型,目前支持单聊会话 PERSON。 -// response: 返回byte数组 -// https://doc.rongcloud.cn/imserver/server/v1/user/ban -// */ -func (rc *RongCloud) UserChatFbQueryList(num, offset int, t string) ([]byte, error) { - if num == 0 { - num = 100 - } - if len(t) == 0 { - return nil, RCErrorNew(1002, "Paramer 'type' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/chat/fb/querylist.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("num", strconv.Itoa(num)) - req.Param("offset", strconv.Itoa(offset)) - req.Param("type", t) - res, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return res, err -} - -// UserChatFbSet * -// 用户单聊禁言 -// @param: userId :被禁言用户 ID,支持批量设置,最多不超过 1000 个 -// @param: state :禁言状态,0 解除禁言、1 添加禁言 -// @param: type :会话类型,目前支持单聊会话 PERSON -// */ -func (rc *RongCloud) UserChatFbSet(userId string, state int, t string) error { - if len(userId) == 0 { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - if len(t) == 0 { - return RCErrorNew(1002, "Paramer 'type' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/chat/fb/set.json") - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - req.Param("state", fmt.Sprintf("%v", state)) - req.Param("type", t) - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: AddWhiteList - * @test: - * @msg: 添加用户到白名单(每秒限 100 次) - * @param string userId - * @param []string whiteList - * @return: error - */ -func (rc *RongCloud) AddWhiteList(userId string, whiteList []string) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if len(whiteList) == 0 { - return RCErrorNew(1002, "Paramer 'whiteList' cannot empty") - } - - if len(whiteList) > 20 { - return RCErrorNew(1002, "Length of paramer 'whiteList' must less than 20") - } - - req := httplib.Post(rc.rongCloudURI + "/user/whitelist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - for _, v := range whiteList { - req.Param("whiteUserId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: RemoveWhiteList - * @test: - * @msg: 移除白名单中用户(每秒限 100 次) - * @param string userId - * @param []string whiteList - * @return: error - */ -func (rc *RongCloud) RemoveWhiteList(userId string, whiteList []string) error { - if userId == "" { - return RCErrorNew(1002, "Paramer 'userId' is required") - } - - if len(whiteList) == 0 { - return RCErrorNew(1002, "Paramer 'whiteList' is required") - } - - if len(whiteList) > 20 { - return RCErrorNew(1002, "Length of paramer 'whiteList' must less than 20") - } - - req := httplib.Post(rc.rongCloudURI + "/user/whitelist/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - for _, v := range whiteList { - req.Param("whiteUserId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -/** - * @name: QueryWhiteList - * @test: - * @msg: 获取某用户白名单列表(每秒限100次) - * @param string userId - * @return: WhiteList error - */ -func (rc *RongCloud) QueryWhiteList(userId string) (WhiteList, error) { - if userId == "" { - return WhiteList{}, RCErrorNew(1002, "Paramer 'userId' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/whitelist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userId) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return WhiteList{}, err - } - - var whiteList WhiteList - if err := json.Unmarshal(resp, &whiteList); err != nil { - return WhiteList{}, err - } - return whiteList, nil -} - -// UserRegister 注册用户,生成用户在融云的唯一身份标识 Token -/* -*@param userID:用户 ID,最大长度 64 字节.是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户。 -*@param name:用户名称,最大长度 128 字节.用来在 Push 推送时显示用户的名称.用户名称,最大长度 128 字节.用来在 Push 推送时显示用户的名称。 -*@param portraitURI:用户头像 URI,最大长度 1024 字节.用来在 Push 推送时显示用户的头像。可以为空 -* -*@return User, error - */ -func (rc *RongCloud) UserRegister(userID, name, portraitURI string) (User, error) { - if userID == "" { - return User{}, RCErrorNew(1002, "Paramer 'userID' is required") - } - if name == "" { - return User{}, RCErrorNew(1002, "Paramer 'name' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/getToken." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userID) - req.Param("name", name) - if portraitURI != "" { - req.Param("portraitUri", portraitURI) - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return User{}, err - } - - var userResult User - if err := json.Unmarshal(resp, &userResult); err != nil { - return User{}, err - } - return userResult, nil -} - -// UserUpdate 修改用户信息 -/* -*@param userID:用户 ID,最大长度 64 字节.是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户。 -*@param name:用户名称,最大长度 128 字节。用来在 Push 推送时,显示用户的名称,刷新用户名称后 5 分钟内生效。(可选,提供即刷新,不提供忽略) -*@param portraitURI:用户头像 URI,最大长度 1024 字节。用来在 Push 推送时显示。(可选,提供即刷新,不提供忽略) -* -*@return error - */ -func (rc *RongCloud) UserUpdate(userID, name, portraitURI string) error { - if userID == "" { - return RCErrorNew(1002, "Paramer 'userID' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/refresh." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userID) - req.Param("name", name) - req.Param("portraitUri", portraitURI) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// BlockAdd 添加用户到黑名单 -/* -*@param id:用户 ID。 -*@param minute:封禁时长 1 - 1 * 30 * 24 * 60 分钟,最大值为 43200 分钟 -* -*@return error - */ -func (rc *RongCloud) BlockAdd(id string, minute uint64) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - if minute > 43200 { - return RCErrorNew(20004, "封禁时间不正确, 当前传入为 , 正确范围 1 - 1 * 30 * 24 * 60 分钟") - } - - req := httplib.Post(rc.rongCloudURI + "/user/block." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", id) - req.Param("minute", strconv.FormatUint(minute, 10)) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// BlockRemove 从黑名单中移除用户 -/* -*@param id:用户 ID。 -* -*@return error - */ -func (rc *RongCloud) BlockRemove(id string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - req := httplib.Post(rc.rongCloudURI + "/user/unblock." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", id) - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// BlockGetList 获取某用户的黑名单列表 -/* -*@return QueryBlockUserResult error - */ -func (rc *RongCloud) BlockGetList() (BlockListResult, error) { - req := httplib.Post(rc.rongCloudURI + "/user/block/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return BlockListResult{}, err - } - - var dat BlockListResult - if err := json.Unmarshal(resp, &dat); err != nil { - return BlockListResult{}, err - } - - return dat, nil -} - -// BlacklistAdd 添加用户到黑名单方法(每秒钟限 100 次) -/* -*@param id:用户 ID。 -*@param blacklist:被设置为黑名单的用户列表。 -* -*@return error - */ -func (rc *RongCloud) BlacklistAdd(id string, blacklist []string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - if len(blacklist) == 0 { - return RCErrorNew(1002, "Paramer 'blacklist' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/blacklist/add." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", id) - for _, v := range blacklist { - req.Param("blackUserId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// BlacklistRemove 从黑名单中移除用户方法(每秒钟限 100 次) -/* -*@param id:用户 ID。 -*@param blacklist:被移除黑名单列表。 -* -*@return error - */ -func (rc *RongCloud) BlacklistRemove(id string, blacklist []string) error { - if id == "" { - return RCErrorNew(1002, "Paramer 'id' is required") - } - if len(blacklist) == 0 { - return RCErrorNew(1002, "Paramer 'blacklist' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/blacklist/remove." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", id) - for _, v := range blacklist { - req.Param("blackUserId", v) - } - - _, err := rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// BlacklistGet 获取某用户的黑名单列表方法(每秒钟限 100 次) -/* -*@param id:用户 ID。 -* -*@return BlacklistResult error - */ -func (rc *RongCloud) BlacklistGet(id string) (BlacklistResult, error) { - if id == "" { - return BlacklistResult{}, RCErrorNew(1002, "Paramer 'id' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/blacklist/query." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", id) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return BlacklistResult{}, err - } - - var listResult BlacklistResult - if err := json.Unmarshal(resp, &listResult); err != nil { - return BlacklistResult{}, err - } - return listResult, nil -} - -// OnlineStatusCheck 检查用户在线状态 -/* -*@param userID:用户 ID,最大长度 64 字节.是用户在 App 中的唯一标识码,必须保证在同一个 App 内不重复,重复的用户 Id 将被当作是同一用户。 -* -*@return int, error - */ -func (rc *RongCloud) OnlineStatusCheck(userID string) (int, error) { - if userID == "" { - return -1, RCErrorNew(1002, "Paramer 'userID' is required") - } - - req := httplib.Post(rc.rongCloudURI + "/user/checkOnline." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", userID) - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return -1, err - } - var userResult User - if err := json.Unmarshal(resp, &userResult); err != nil { - return -1, err - } - status, _ := strconv.Atoi(userResult.Status) - return status, nil -} - -// TagSet 为应用中的用户添加标签,如果某用户已经添加了标签,再次对用户添加标签时将覆盖之前设置的标签内容。 -/* -*@param tag :标签 Tag 构造体。 -* -*@return error - */ -func (rc *RongCloud) TagSet(tag Tag) error { - req := httplib.Post(rc.rongCloudURI + "/user/tag/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req, err := req.JSONBody(tag) - if err != nil { - rc.urlError(err) - return err - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// TagBatchSet 为应用中的用户批量添加标签,如果某用户已经添加了标签,再次对用户添加标签时将覆盖之前设置的标签内容。 -/* -*@param t :标签 TagBatch 构造体。 -* -*@return error - */ -func (rc *RongCloud) TagBatchSet(tagBatch TagBatch) error { - req := httplib.Post(rc.rongCloudURI + "/user/tag/batch/set." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req, err := req.JSONBody(tagBatch) - if err != nil { - rc.urlError(err) - return err - } - - _, err = rc.do(req) - if err != nil { - rc.urlError(err) - } - return err -} - -// TagGet 查询用户所有标签功能,支持批量查询每次最多查询 50 个用户。 -/* -*@param userIds: 用户 ID。 -* -*@return error - */ -func (rc *RongCloud) TagGet(userIds []string) (TagResult, error) { - req := httplib.Post(rc.rongCloudURI + "/user/tags/get." + ReqType) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - for _, v := range userIds { - req.Param("userIds", v) - } - - resp, err := rc.do(req) - if err != nil { - rc.urlError(err) - return TagResult{}, err - } - - var tag TagResult - if err := json.Unmarshal(resp, &tag); err != nil { - return TagResult{}, err - } - return tag, nil - -} - -type UserDeactivateResponse struct { - Code int `json:"code"` - OperateId string `json:"operateId"` // 操作 ID,为当前操作的唯一标识。开通用户注销与激活状态回调后,回调请求正文中会携带此参数。 -} - -// UserDeactivate 注销用户 -// @param userIds []string 被注销用户 ID,最多一次 100 个 -// @return string, error -// official doc https://doc.rongcloud.cn/imserver/server/v1/user/deactivate -// 发起注销后,服务端会在 15 分钟内通过回调通知注销结果。 https://doc.rongcloud.cn/imserver/server/v1/user/callback-deactivation -func (rc *RongCloud) UserDeactivate(userIds []string) (*UserDeactivateResponse, error) { - req := httplib.Post(fmt.Sprintf("%s%s", rc.rongCloudURI, "/user/deactivate.json")) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", strings.Join(userIds, ",")) - body, err := rc.doV2(req) - if err != nil { - return nil, err - } - var userDeactivateResp UserDeactivateResponse - err = json.Unmarshal(body, &userDeactivateResp) - if err != nil { - return nil, err - } - return &userDeactivateResp, nil -} - -type UserDeactivateQueryResponse struct { - Code int `json:"code"` // 返回码,200 为正常 - Users []string `json:"users"` // 已注销的用户 ID 列表 -} - -// UserDeactivateQuery 查询已注销用户 -// @param pageNo 分页获取注销用户列表时的当前页数,默认 1,最小 1。 -// @param pageSize 分页获取注销用户列表时的每页行数,默认 50,最小 1,最大 50。 -// @return string, error -// official doc https://doc.rongcloud.cn/imserver/server/v1/user/query-deactivated-list -func (rc *RongCloud) UserDeactivateQuery(pageNo, pageSize int) (*UserDeactivateQueryResponse, error) { - req := httplib.Post(fmt.Sprintf("%s/%s", rc.rongCloudURI, "/user/deactivate/query.json")) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("pageNo", strconv.Itoa(pageNo)) - req.Param("pageSize", strconv.Itoa(pageSize)) - body, err := rc.doV2(req) - if err != nil { - return nil, err - } - var userDeactivateQueryResp UserDeactivateQueryResponse - err = json.Unmarshal(body, &userDeactivateQueryResp) - if err != nil { - return nil, err - } - return &userDeactivateQueryResp, nil -} - -type UserReactivateResponse struct { - Code int `json:"code"` // 返回码,200 为正常。每个用户 ID 操作结果通过用户注销与激活状态回调传递。 - OperateId string `json:"operateId"` // 操作 ID,为当前操作的唯一标识。开通用户注销与激活状态回调后,回调请求正文中会携带此参数。 -} - -// UserReactivate 重新激活注销用户 -// @param userIds []string 激活用户 ID,单次请求最多传入 100 个用户 ID。 -// @return string, error -// official doc https://doc.rongcloud.cn/imserver/server/v1/user/reactivate -// 重新激活用户请通过(https://doc.rongcloud.cn/imserver/server/v1/user/callback-deactivation)接口获取重新激活结果。重复调用此接口不会报错。 -func (rc *RongCloud) UserReactivate(userIds []string) (*UserReactivateResponse, error) { - req := httplib.Post(fmt.Sprintf("%s%s", rc.rongCloudURI, "/user/reactivate.json")) - req.SetTimeout(time.Second*rc.timeout, time.Second*rc.timeout) - rc.fillHeader(req) - req.Param("userId", strings.Join(userIds, ",")) - body, err := rc.doV2(req) - if err != nil { - return nil, err - } - var userReactivateResp UserReactivateResponse - err = json.Unmarshal(body, &userReactivateResp) - if err != nil { - return nil, err - } - return &userReactivateResp, nil -} diff --git a/sdk/user_test.go b/sdk/user_test.go deleted file mode 100644 index ba717b0..0000000 --- a/sdk/user_test.go +++ /dev/null @@ -1,423 +0,0 @@ -/* - * @Descripttion: - * @version: - * @Author: ran.ding - * @Date: 2019-09-02 18:29:55 - * @LastEditors: ran.ding - * @LastEditTime: 2019-09-10 12:14:41 - */ -package sdk - -import ( - "fmt" - "os" - "testing" -) - -func TestRongCloud_UserBlockPushPeriodDelete(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UserBlockPushPeriodDelete("u01"); err != nil { - t.Errorf("UserTokenExpire err:%v", err) - return - } - t.Log("suc") -} - -func TestRongCloud_UserBlockPushPeriodGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserBlockPushPeriodGet("u01"); err != nil { - t.Errorf("UserTokenExpire err:%v", err) - return - } else { - t.Log(fmt.Sprintf("suc %+v", res)) - } -} - -func TestRongCloud_UserBlockPushPeriodSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UserBlockPushPeriodSet("u01", "23:59:59", "120", ""); err != nil { - t.Errorf("UserTokenExpire err:%v", err) - return - } - t.Log("suc") -} - -func TestRongCloud_UserTokenExpireResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserTokenExpireResObj("u01", 1619469955344); err != nil { - t.Errorf("UserTokenExpire err:%v", err) - return - } else { - t.Logf("user remark get suc:%+v", res) - } -} - -func TestRongCloud_UserTokenExpire(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserTokenExpire("u01", 1619469955344); err != nil { - t.Errorf("UserTokenExpire err:%v", err) - return - } else { - t.Log("user remark get suc", string(res)) - } -} - -func TestRongCloud_UserRemarksGetResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserRemarksGetResObj("u01", 1, 1); err != nil { - t.Errorf("user remark get err:%v", err) - return - } else { - t.Logf("user remark get suc :%+v", res) - } -} - -func TestRongCloud_UserRemarksGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserRemarksGet("u01", 1, 1); err != nil { - t.Errorf("user remark get err:%v", err) - return - } else { - t.Log("user remark get suc", string(res)) - } -} - -func TestRongCloud_UserRemarksDel(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UserRemarksDel("u01", "qq"); err != nil { - t.Errorf("user remark del err:%v", err) - return - } - t.Log("user remark del suc") -} - -func TestRongCloud_UserRemarksSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UserRemarksSet("u01", []UserRemark{{ - Id: "u01", - Remark: "remark1", - }}); err != nil { - t.Errorf("user remark set err:%v", err) - return - } - t.Log("user remark set suc") -} - -func TestRongCloud_UserChatFbQueryListResObj(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserChatFbQueryListResObj(0, 0, "PERSON"); err != nil { - t.Errorf("user chat fb set err:%v", err) - return - } else { - t.Logf("user chat fb set suc:%+v", res) - } -} - -func TestRongCloud_UserChatFbQueryList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if res, err := rc.UserChatFbQueryList(0, 0, "PERSON"); err != nil { - t.Errorf("user chat fb set err:%v", err) - return - } else { - t.Log("user chat fb set suc", string(res)) - } -} - -func TestRongCloud_UserChatFbSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - if err := rc.UserChatFbSet("u01", 0, "PERSON"); err != nil { - t.Errorf("user chat fb set err:%v", err) - return - } - t.Log("user chat fb set suc") -} - -func TestQueryWhiteList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - _, err := rc.QueryWhiteList("123") - if err != nil { - t.Errorf("ERROR: %v", err) - } else { - t.Log("PASS") - } -} - -func TestRemoveWhiteList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - if err := rc.RemoveWhiteList("123", []string{"234", "456"}); err != nil { - t.Errorf("ERROR: %v", err) - } else { - t.Log("PASS") - } -} - -func TestAddWhiteList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - if err := rc.AddWhiteList("123", []string{"234", "345"}); err != nil { - t.Errorf("ERROR: %v", err) - } else { - t.Log("PASS") - } -} - -func TestRongCloud_UserRegister(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - rep, err := rc.UserRegister( - "1000014", - "1000014", - "https://img.theplace.cool/MTY1NjMxNDExNjQxMCMzMjAjcG5n.png&apiId=1", - ) - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_UserUpdate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - rep := rc.UserUpdate("7Szq13MKRVortoknTAk7W8", "7Szq13MKRVortoknTAk7W8", "http://rongcloud.cn/portrait.jpg") - t.Log(rep) -} - -func TestRongCloud_BlockAdd(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.BlockAdd( - "4kIvGJmETlYqDoVFgWdYdM", - 5, - ) - t.Log(err) -} - -func TestRongCloud_BlockGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - rep, err := rc.BlockGetList() - t.Log(err) - t.Log(rep) -} - -func TestRongCloud_BlockRemove(t *testing.T) { - - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.BlockRemove( - "4kIvGJmETlYqDoVFgWdYdM", - ) - t.Log(err) -} - -func TestRongCloud_BlacklistAdd(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.BlacklistAdd( - "4kIvGJmETlYqDoVFgWdYdM", - []string{"u01"}, - ) - - t.Log(err) -} - -func TestRongCloud_BlacklistGetList(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - req, err := rc.BlacklistGet( - "4kIvGJmETlYqDoVFgWdYdM", - ) - t.Log(err) - t.Log(req) -} - -func TestRongCloud_BlacklistRemove(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - err := rc.BlacklistRemove( - "4kIvGJmETlYqDoVFgWdYdM", - []string{"u01"}, - ) - t.Log(err) -} - -func TestRongCloud_OnlineStatusCheck(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - status, err := rc.OnlineStatusCheck("4kIvGJmETlYqDoVFgWdYdM") - t.Log(err) - t.Log(status) -} - -func TestRongCloud_TagSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.TagSet( - Tag{ - UserID: "u01", - Tags: []string{ - "男", - }, - }) - t.Log(err) -} - -func TestRongCloud_TagBatchSet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - err := rc.TagBatchSet( - TagBatch{ - UserIDs: []string{ - "u02", - "u03", - }, - Tags: []string{ - "男", - "bj", - }, - }) - t.Log(err) -} - -func TestRongCloud_TagGet(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - - result, err := rc.TagGet( - []string{ - "u01", - "u02", - "u03", - }, - ) - if err == nil { - for k, v := range result.Result { - t.Log(k) - for _, tag := range v { - t.Log(tag) - } - } - } - t.Log(err) -} - -func TestRongCloud_UserDeactivate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - // 注册用户测试 - result, err := rc.UserDeactivate( - []string{ - "u01", - "u02", - }) - if err != nil { - t.Fatalf("UserDeactivate fail: %s", err) - } - t.Logf("res: %+v", result) -} - -func TestRongCloud_UserDeactivateQuery(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - result, err := rc.UserDeactivateQuery(1, 50) - if err != nil { - t.Fatalf("UserDeactivateQuery fail: %s", err) - } - t.Logf("res: %+v", result) -} - -func TestRongCloud_UserReactivate(t *testing.T) { - rc := NewRongCloud( - os.Getenv("APP_KEY"), - os.Getenv("APP_SECRET"), - ) - result, err := rc.UserReactivate( - []string{ - "u01", - "u02", - }) - if err != nil { - t.Fatalf("UserReactivate fail: %s", err) - } - t.Logf("res: %+v", result) -} diff --git a/vendor/github.com/astaxie/beego/LICENSE b/vendor/github.com/astaxie/beego/LICENSE deleted file mode 100644 index 5dbd424..0000000 --- a/vendor/github.com/astaxie/beego/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2014 astaxie - -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. \ No newline at end of file diff --git a/vendor/github.com/astaxie/beego/httplib/README.md b/vendor/github.com/astaxie/beego/httplib/README.md deleted file mode 100644 index 97df8e6..0000000 --- a/vendor/github.com/astaxie/beego/httplib/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# httplib -httplib is an libs help you to curl remote url. - -# How to use? - -## GET -you can use Get to crawl data. - - import "github.com/astaxie/beego/httplib" - - str, err := httplib.Get("http://beego.me/").String() - if err != nil { - // error - } - fmt.Println(str) - -## POST -POST data to remote url - - req := httplib.Post("http://beego.me/") - req.Param("username","astaxie") - req.Param("password","123456") - str, err := req.String() - if err != nil { - // error - } - fmt.Println(str) - -## Set timeout - -The default timeout is `60` seconds, function prototype: - - SetTimeout(connectTimeout, readWriteTimeout time.Duration) - -Example: - - // GET - httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second) - - // POST - httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second) - - -## Debug - -If you want to debug the request info, set the debug on - - httplib.Get("http://beego.me/").Debug(true) - -## Set HTTP Basic Auth - - str, err := Get("http://beego.me/").SetBasicAuth("user", "passwd").String() - if err != nil { - // error - } - fmt.Println(str) - -## Set HTTPS - -If request url is https, You can set the client support TSL: - - httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) - -More info about the `tls.Config` please visit http://golang.org/pkg/crypto/tls/#Config - -## Set HTTP Version - -some servers need to specify the protocol version of HTTP - - httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1") - -## Set Cookie - -some http request need setcookie. So set it like this: - - cookie := &http.Cookie{} - cookie.Name = "username" - cookie.Value = "astaxie" - httplib.Get("http://beego.me/").SetCookie(cookie) - -## Upload file - -httplib support mutil file upload, use `req.PostFile()` - - req := httplib.Post("http://beego.me/") - req.Param("username","astaxie") - req.PostFile("uploadfile1", "httplib.pdf") - str, err := req.String() - if err != nil { - // error - } - fmt.Println(str) - - -See godoc for further documentation and examples. - -* [godoc.org/github.com/astaxie/beego/httplib](https://godoc.org/github.com/astaxie/beego/httplib) diff --git a/vendor/github.com/astaxie/beego/httplib/httplib.go b/vendor/github.com/astaxie/beego/httplib/httplib.go deleted file mode 100644 index 074cf66..0000000 --- a/vendor/github.com/astaxie/beego/httplib/httplib.go +++ /dev/null @@ -1,624 +0,0 @@ -// Copyright 2014 beego Author. 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 httplib is used as http.Client -// Usage: -// -// import "github.com/astaxie/beego/httplib" -// -// b := httplib.Post("http://beego.me/") -// b.Param("username","astaxie") -// b.Param("password","123456") -// b.PostFile("uploadfile1", "httplib.pdf") -// b.PostFile("uploadfile2", "httplib.txt") -// str, err := b.String() -// if err != nil { -// t.Fatal(err) -// } -// fmt.Println(str) -// -// more docs http://beego.me/docs/module/httplib.md -package httplib - -import ( - "bytes" - "compress/gzip" - "crypto/tls" - "encoding/json" - "encoding/xml" - "io" - "io/ioutil" - "log" - "mime/multipart" - "net" - "net/http" - "net/http/cookiejar" - "net/http/httputil" - "net/url" - "os" - "strings" - "sync" - "time" - "gopkg.in/yaml.v2" -) - -var defaultSetting = BeegoHTTPSettings{ - UserAgent: "beegoServer", - ConnectTimeout: 60 * time.Second, - ReadWriteTimeout: 60 * time.Second, - Gzip: true, - DumpBody: true, -} - -var defaultCookieJar http.CookieJar -var settingMutex sync.Mutex - -// createDefaultCookie creates a global cookiejar to store cookies. -func createDefaultCookie() { - settingMutex.Lock() - defer settingMutex.Unlock() - defaultCookieJar, _ = cookiejar.New(nil) -} - -// SetDefaultSetting Overwrite default settings -func SetDefaultSetting(setting BeegoHTTPSettings) { - settingMutex.Lock() - defer settingMutex.Unlock() - defaultSetting = setting -} - -// NewBeegoRequest return *BeegoHttpRequest with specific method -func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest { - var resp http.Response - u, err := url.Parse(rawurl) - if err != nil { - log.Println("Httplib:", err) - } - req := http.Request{ - URL: u, - Method: method, - Header: make(http.Header), - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - } - return &BeegoHTTPRequest{ - url: rawurl, - req: &req, - params: map[string][]string{}, - files: map[string]string{}, - setting: defaultSetting, - resp: &resp, - } -} - -// Get returns *BeegoHttpRequest with GET method. -func Get(url string) *BeegoHTTPRequest { - return NewBeegoRequest(url, "GET") -} - -// Post returns *BeegoHttpRequest with POST method. -func Post(url string) *BeegoHTTPRequest { - return NewBeegoRequest(url, "POST") -} - -// Put returns *BeegoHttpRequest with PUT method. -func Put(url string) *BeegoHTTPRequest { - return NewBeegoRequest(url, "PUT") -} - -// Delete returns *BeegoHttpRequest DELETE method. -func Delete(url string) *BeegoHTTPRequest { - return NewBeegoRequest(url, "DELETE") -} - -// Head returns *BeegoHttpRequest with HEAD method. -func Head(url string) *BeegoHTTPRequest { - return NewBeegoRequest(url, "HEAD") -} - -// BeegoHTTPSettings is the http.Client setting -type BeegoHTTPSettings struct { - ShowDebug bool - UserAgent string - ConnectTimeout time.Duration - ReadWriteTimeout time.Duration - TLSClientConfig *tls.Config - Proxy func(*http.Request) (*url.URL, error) - Transport http.RoundTripper - CheckRedirect func(req *http.Request, via []*http.Request) error - EnableCookie bool - Gzip bool - DumpBody bool - Retries int // if set to -1 means will retry forever -} - -// BeegoHTTPRequest provides more useful methods for requesting one url than http.Request. -type BeegoHTTPRequest struct { - url string - req *http.Request - params map[string][]string - files map[string]string - setting BeegoHTTPSettings - resp *http.Response - body []byte - dump []byte -} - -// GetRequest return the request object -func (b *BeegoHTTPRequest) GetRequest() *http.Request { - return b.req -} - -// Setting Change request settings -func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest { - b.setting = setting - return b -} - -// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password. -func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest { - b.req.SetBasicAuth(username, password) - return b -} - -// SetEnableCookie sets enable/disable cookiejar -func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest { - b.setting.EnableCookie = enable - return b -} - -// SetUserAgent sets User-Agent header field -func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest { - b.setting.UserAgent = useragent - return b -} - -// Debug sets show debug or not when executing request. -func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest { - b.setting.ShowDebug = isdebug - return b -} - -// Retries sets Retries times. -// default is 0 means no retried. -// -1 means retried forever. -// others means retried times. -func (b *BeegoHTTPRequest) Retries(times int) *BeegoHTTPRequest { - b.setting.Retries = times - return b -} - -// DumpBody setting whether need to Dump the Body. -func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest { - b.setting.DumpBody = isdump - return b -} - -// DumpRequest return the DumpRequest -func (b *BeegoHTTPRequest) DumpRequest() []byte { - return b.dump -} - -// SetTimeout sets connect time out and read-write time out for BeegoRequest. -func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHTTPRequest { - b.setting.ConnectTimeout = connectTimeout - b.setting.ReadWriteTimeout = readWriteTimeout - return b -} - -// SetTLSClientConfig sets tls connection configurations if visiting https url. -func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest { - b.setting.TLSClientConfig = config - return b -} - -// Header add header item string in request. -func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest { - b.req.Header.Set(key, value) - return b -} - -// SetHost set the request host -func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest { - b.req.Host = host - return b -} - -// SetProtocolVersion Set the protocol version for incoming requests. -// Client requests always use HTTP/1.1. -func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { - if len(vers) == 0 { - vers = "HTTP/1.1" - } - - major, minor, ok := http.ParseHTTPVersion(vers) - if ok { - b.req.Proto = vers - b.req.ProtoMajor = major - b.req.ProtoMinor = minor - } - - return b -} - -// SetCookie add cookie into request. -func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest { - b.req.Header.Add("Cookie", cookie.String()) - return b -} - -// SetTransport set the setting transport -func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest { - b.setting.Transport = transport - return b -} - -// SetProxy set the http proxy -// example: -// -// func(req *http.Request) (*url.URL, error) { -// u, _ := url.ParseRequestURI("http://127.0.0.1:8118") -// return u, nil -// } -func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHTTPRequest { - b.setting.Proxy = proxy - return b -} - -// SetCheckRedirect specifies the policy for handling redirects. -// -// If CheckRedirect is nil, the Client uses its default policy, -// which is to stop after 10 consecutive requests. -func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) *BeegoHTTPRequest { - b.setting.CheckRedirect = redirect - return b -} - -// Param adds query param in to request. -// params build query string as ?key1=value1&key2=value2... -func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { - if param, ok := b.params[key]; ok { - b.params[key] = append(param, value) - } else { - b.params[key] = []string{value} - } - return b -} - -// PostFile add a post file to the request -func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest { - b.files[formname] = filename - return b -} - -// Body adds request raw body. -// it supports string and []byte. -func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { - switch t := data.(type) { - case string: - bf := bytes.NewBufferString(t) - b.req.Body = ioutil.NopCloser(bf) - b.req.ContentLength = int64(len(t)) - case []byte: - bf := bytes.NewBuffer(t) - b.req.Body = ioutil.NopCloser(bf) - b.req.ContentLength = int64(len(t)) - } - return b -} - -// XMLBody adds request raw body encoding by XML. -func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { - if b.req.Body == nil && obj != nil { - byts, err := xml.Marshal(obj) - if err != nil { - return b, err - } - b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) - b.req.ContentLength = int64(len(byts)) - b.req.Header.Set("Content-Type", "application/xml") - } - return b, nil -} - -// YAMLBody adds request raw body encoding by YAML. -func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) { - if b.req.Body == nil && obj != nil { - byts, err := yaml.Marshal(obj) - if err != nil { - return b, err - } - b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) - b.req.ContentLength = int64(len(byts)) - b.req.Header.Set("Content-Type", "application/x+yaml") - } - return b, nil -} - -// JSONBody adds request raw body encoding by JSON. -func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) { - if b.req.Body == nil && obj != nil { - byts, err := json.Marshal(obj) - if err != nil { - return b, err - } - b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) - b.req.ContentLength = int64(len(byts)) - b.req.Header.Set("Content-Type", "application/json") - } - return b, nil -} - -func (b *BeegoHTTPRequest) buildURL(paramBody string) { - // build GET url with query string - if b.req.Method == "GET" && len(paramBody) > 0 { - if strings.Contains(b.url, "?") { - b.url += "&" + paramBody - } else { - b.url = b.url + "?" + paramBody - } - return - } - - // build POST/PUT/PATCH url and body - if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil { - // with files - if len(b.files) > 0 { - pr, pw := io.Pipe() - bodyWriter := multipart.NewWriter(pw) - go func() { - for formname, filename := range b.files { - fileWriter, err := bodyWriter.CreateFormFile(formname, filename) - if err != nil { - log.Println("Httplib:", err) - } - fh, err := os.Open(filename) - if err != nil { - log.Println("Httplib:", err) - } - //iocopy - _, err = io.Copy(fileWriter, fh) - fh.Close() - if err != nil { - log.Println("Httplib:", err) - } - } - for k, v := range b.params { - for _, vv := range v { - bodyWriter.WriteField(k, vv) - } - } - bodyWriter.Close() - pw.Close() - }() - b.Header("Content-Type", bodyWriter.FormDataContentType()) - b.req.Body = ioutil.NopCloser(pr) - return - } - - // with params - if len(paramBody) > 0 { - b.Header("Content-Type", "application/x-www-form-urlencoded") - b.Body(paramBody) - } - } -} - -func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) { - if b.resp.StatusCode != 0 { - return b.resp, nil - } - resp, err := b.DoRequest() - if err != nil { - return nil, err - } - b.resp = resp - return resp, nil -} - -// DoRequest will do the client.Do -func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { - var paramBody string - if len(b.params) > 0 { - var buf bytes.Buffer - for k, v := range b.params { - for _, vv := range v { - buf.WriteString(url.QueryEscape(k)) - buf.WriteByte('=') - buf.WriteString(url.QueryEscape(vv)) - buf.WriteByte('&') - } - } - paramBody = buf.String() - paramBody = paramBody[0 : len(paramBody)-1] - } - - b.buildURL(paramBody) - urlParsed, err := url.Parse(b.url) - if err != nil { - return nil, err - } - - b.req.URL = urlParsed - - trans := b.setting.Transport - - if trans == nil { - // create default transport - trans = &http.Transport{ - TLSClientConfig: b.setting.TLSClientConfig, - Proxy: b.setting.Proxy, - Dial: TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout), - MaxIdleConnsPerHost: 100, - } - } else { - // if b.transport is *http.Transport then set the settings. - if t, ok := trans.(*http.Transport); ok { - if t.TLSClientConfig == nil { - t.TLSClientConfig = b.setting.TLSClientConfig - } - if t.Proxy == nil { - t.Proxy = b.setting.Proxy - } - if t.Dial == nil { - t.Dial = TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout) - } - } - } - - var jar http.CookieJar - if b.setting.EnableCookie { - if defaultCookieJar == nil { - createDefaultCookie() - } - jar = defaultCookieJar - } - - client := &http.Client{ - Transport: trans, - Jar: jar, - } - - if b.setting.UserAgent != "" && b.req.Header.Get("User-Agent") == "" { - b.req.Header.Set("User-Agent", b.setting.UserAgent) - } - - if b.setting.CheckRedirect != nil { - client.CheckRedirect = b.setting.CheckRedirect - } - - if b.setting.ShowDebug { - dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody) - if err != nil { - log.Println(err.Error()) - } - b.dump = dump - } - // retries default value is 0, it will run once. - // retries equal to -1, it will run forever until success - // retries is setted, it will retries fixed times. - for i := 0; b.setting.Retries == -1 || i <= b.setting.Retries; i++ { - resp, err = client.Do(b.req) - if err == nil { - break - } - } - return resp, err -} - -// String returns the body string in response. -// it calls Response inner. -func (b *BeegoHTTPRequest) String() (string, error) { - data, err := b.Bytes() - if err != nil { - return "", err - } - - return string(data), nil -} - -// Bytes returns the body []byte in response. -// it calls Response inner. -func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { - if b.body != nil { - return b.body, nil - } - resp, err := b.getResponse() - if err != nil { - return nil, err - } - if resp.Body == nil { - return nil, nil - } - defer resp.Body.Close() - if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(resp.Body) - if err != nil { - return nil, err - } - b.body, err = ioutil.ReadAll(reader) - return b.body, err - } - b.body, err = ioutil.ReadAll(resp.Body) - return b.body, err -} - -// ToFile saves the body data in response to one file. -// it calls Response inner. -func (b *BeegoHTTPRequest) ToFile(filename string) error { - f, err := os.Create(filename) - if err != nil { - return err - } - defer f.Close() - - resp, err := b.getResponse() - if err != nil { - return err - } - if resp.Body == nil { - return nil - } - defer resp.Body.Close() - _, err = io.Copy(f, resp.Body) - return err -} - -// ToJSON returns the map that marshals from the body bytes as json in response . -// it calls Response inner. -func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { - data, err := b.Bytes() - if err != nil { - return err - } - return json.Unmarshal(data, v) -} - -// ToXML returns the map that marshals from the body bytes as xml in response . -// it calls Response inner. -func (b *BeegoHTTPRequest) ToXML(v interface{}) error { - data, err := b.Bytes() - if err != nil { - return err - } - return xml.Unmarshal(data, v) -} - -// ToYAML returns the map that marshals from the body bytes as yaml in response . -// it calls Response inner. -func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { - data, err := b.Bytes() - if err != nil { - return err - } - return yaml.Unmarshal(data, v) -} - -// Response executes request client gets response mannually. -func (b *BeegoHTTPRequest) Response() (*http.Response, error) { - return b.getResponse() -} - -// TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. -func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) { - return func(netw, addr string) (net.Conn, error) { - conn, err := net.DialTimeout(netw, addr, cTimeout) - if err != nil { - return nil, err - } - err = conn.SetDeadline(time.Now().Add(rwTimeout)) - return conn, err - } -} diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml deleted file mode 100644 index d8156a6..0000000 --- a/vendor/github.com/google/uuid/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.4.3 - - 1.5.3 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md deleted file mode 100644 index 04fdf09..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ /dev/null @@ -1,10 +0,0 @@ -# How to contribute - -We definitely welcome patches and contribution to this project! - -### Legal requirements - -In order to protect both you and ourselves, you will need to sign the -[Contributor License Agreement](https://cla.developers.google.com/clas). - -You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS deleted file mode 100644 index b4bb97f..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTORS +++ /dev/null @@ -1,9 +0,0 @@ -Paul Borman -bmatsuo -shawnps -theory -jboverfelt -dsymonds -cd1 -wallclockbuilder -dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE deleted file mode 100644 index 5dc6826..0000000 --- a/vendor/github.com/google/uuid/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009,2014 Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md deleted file mode 100644 index f765a46..0000000 --- a/vendor/github.com/google/uuid/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) -The uuid package generates and inspects UUIDs based on -[RFC 4122](http://tools.ietf.org/html/rfc4122) -and DCE 1.1: Authentication and Security Services. - -This package is based on the github.com/pborman/uuid package (previously named -code.google.com/p/go-uuid). It differs from these earlier packages in that -a UUID is a 16 byte array rather than a byte slice. One loss due to this -change is the ability to represent an invalid UUID (vs a NIL UUID). - -###### Install -`go get github.com/google/uuid` - -###### Documentation -[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) - -Full `go doc` style documentation for the package can be viewed online without -installing this package by using the GoDoc site here: -http://pkg.go.dev/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go deleted file mode 100644 index fa820b9..0000000 --- a/vendor/github.com/google/uuid/dce.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "fmt" - "os" -) - -// A Domain represents a Version 2 domain -type Domain byte - -// Domain constants for DCE Security (Version 2) UUIDs. -const ( - Person = Domain(0) - Group = Domain(1) - Org = Domain(2) -) - -// NewDCESecurity returns a DCE Security (Version 2) UUID. -// -// The domain should be one of Person, Group or Org. -// On a POSIX system the id should be the users UID for the Person -// domain and the users GID for the Group. The meaning of id for -// the domain Org or on non-POSIX systems is site defined. -// -// For a given domain/id pair the same token may be returned for up to -// 7 minutes and 10 seconds. -func NewDCESecurity(domain Domain, id uint32) (UUID, error) { - uuid, err := NewUUID() - if err == nil { - uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 - uuid[9] = byte(domain) - binary.BigEndian.PutUint32(uuid[0:], id) - } - return uuid, err -} - -// NewDCEPerson returns a DCE Security (Version 2) UUID in the person -// domain with the id returned by os.Getuid. -// -// NewDCESecurity(Person, uint32(os.Getuid())) -func NewDCEPerson() (UUID, error) { - return NewDCESecurity(Person, uint32(os.Getuid())) -} - -// NewDCEGroup returns a DCE Security (Version 2) UUID in the group -// domain with the id returned by os.Getgid. -// -// NewDCESecurity(Group, uint32(os.Getgid())) -func NewDCEGroup() (UUID, error) { - return NewDCESecurity(Group, uint32(os.Getgid())) -} - -// Domain returns the domain for a Version 2 UUID. Domains are only defined -// for Version 2 UUIDs. -func (uuid UUID) Domain() Domain { - return Domain(uuid[9]) -} - -// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 -// UUIDs. -func (uuid UUID) ID() uint32 { - return binary.BigEndian.Uint32(uuid[0:4]) -} - -func (d Domain) String() string { - switch d { - case Person: - return "Person" - case Group: - return "Group" - case Org: - return "Org" - } - return fmt.Sprintf("Domain%d", int(d)) -} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go deleted file mode 100644 index 5b8a4b9..0000000 --- a/vendor/github.com/google/uuid/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package uuid generates and inspects UUIDs. -// -// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security -// Services. -// -// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to -// maps or compared directly. -package uuid diff --git a/vendor/github.com/google/uuid/go.mod b/vendor/github.com/google/uuid/go.mod deleted file mode 100644 index fc84cd7..0000000 --- a/vendor/github.com/google/uuid/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/google/uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go deleted file mode 100644 index b404f4b..0000000 --- a/vendor/github.com/google/uuid/hash.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "crypto/md5" - "crypto/sha1" - "hash" -) - -// Well known namespace IDs and UUIDs -var ( - NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) - Nil UUID // empty UUID, all zeros -) - -// NewHash returns a new UUID derived from the hash of space concatenated with -// data generated by h. The hash should be at least 16 byte in length. The -// first 16 bytes of the hash are used to form the UUID. The version of the -// UUID will be the lower 4 bits of version. NewHash is used to implement -// NewMD5 and NewSHA1. -func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { - h.Reset() - h.Write(space[:]) //nolint:errcheck - h.Write(data) //nolint:errcheck - s := h.Sum(nil) - var uuid UUID - copy(uuid[:], s) - uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) - uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant - return uuid -} - -// NewMD5 returns a new MD5 (Version 3) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(md5.New(), space, data, 3) -func NewMD5(space UUID, data []byte) UUID { - return NewHash(md5.New(), space, data, 3) -} - -// NewSHA1 returns a new SHA1 (Version 5) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(sha1.New(), space, data, 5) -func NewSHA1(space UUID, data []byte) UUID { - return NewHash(sha1.New(), space, data, 5) -} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go deleted file mode 100644 index 14bd340..0000000 --- a/vendor/github.com/google/uuid/marshal.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "fmt" - -// MarshalText implements encoding.TextMarshaler. -func (uuid UUID) MarshalText() ([]byte, error) { - var js [36]byte - encodeHex(js[:], uuid) - return js[:], nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (uuid *UUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - return err - } - *uuid = id - return nil -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (uuid UUID) MarshalBinary() ([]byte, error) { - return uuid[:], nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (uuid *UUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(uuid[:], data) - return nil -} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go deleted file mode 100644 index d651a2b..0000000 --- a/vendor/github.com/google/uuid/node.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "sync" -) - -var ( - nodeMu sync.Mutex - ifname string // name of interface being used - nodeID [6]byte // hardware for version 1 UUIDs - zeroID [6]byte // nodeID with only 0's -) - -// NodeInterface returns the name of the interface from which the NodeID was -// derived. The interface "user" is returned if the NodeID was set by -// SetNodeID. -func NodeInterface() string { - defer nodeMu.Unlock() - nodeMu.Lock() - return ifname -} - -// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. -// If name is "" then the first usable interface found will be used or a random -// Node ID will be generated. If a named interface cannot be found then false -// is returned. -// -// SetNodeInterface never fails when name is "". -func SetNodeInterface(name string) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - return setNodeInterface(name) -} - -func setNodeInterface(name string) bool { - iname, addr := getHardwareInterface(name) // null implementation for js - if iname != "" && addr != nil { - ifname = iname - copy(nodeID[:], addr) - return true - } - - // We found no interfaces with a valid hardware address. If name - // does not specify a specific interface generate a random Node ID - // (section 4.1.6) - if name == "" { - ifname = "random" - randomBits(nodeID[:]) - return true - } - return false -} - -// NodeID returns a slice of a copy of the current Node ID, setting the Node ID -// if not already set. -func NodeID() []byte { - defer nodeMu.Unlock() - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - nid := nodeID - return nid[:] -} - -// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes -// of id are used. If id is less than 6 bytes then false is returned and the -// Node ID is not set. -func SetNodeID(id []byte) bool { - if len(id) < 6 { - return false - } - defer nodeMu.Unlock() - nodeMu.Lock() - copy(nodeID[:], id) - ifname = "user" - return true -} - -// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is -// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) NodeID() []byte { - var node [6]byte - copy(node[:], uuid[10:]) - return node[:] -} diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go deleted file mode 100644 index 24b78ed..0000000 --- a/vendor/github.com/google/uuid/node_js.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build js - -package uuid - -// getHardwareInterface returns nil values for the JS version of the code. -// This remvoves the "net" dependency, because it is not used in the browser. -// Using the "net" library inflates the size of the transpiled JS code by 673k bytes. -func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go deleted file mode 100644 index 0cbbcdd..0000000 --- a/vendor/github.com/google/uuid/node_net.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !js - -package uuid - -import "net" - -var interfaces []net.Interface // cached list of interfaces - -// getHardwareInterface returns the name and hardware address of interface name. -// If name is "" then the name and hardware address of one of the system's -// interfaces is returned. If no interfaces are found (name does not exist or -// there are no interfaces) then "", nil is returned. -// -// Only addresses of at least 6 bytes are returned. -func getHardwareInterface(name string) (string, []byte) { - if interfaces == nil { - var err error - interfaces, err = net.Interfaces() - if err != nil { - return "", nil - } - } - for _, ifs := range interfaces { - if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { - return ifs.Name, ifs.HardwareAddr - } - } - return "", nil -} diff --git a/vendor/github.com/google/uuid/null.go b/vendor/github.com/google/uuid/null.go deleted file mode 100644 index d7fcbf2..0000000 --- a/vendor/github.com/google/uuid/null.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2021 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "database/sql/driver" - "encoding/json" - "fmt" -) - -var jsonNull = []byte("null") - -// NullUUID represents a UUID that may be null. -// NullUUID implements the SQL driver.Scanner interface so -// it can be used as a scan destination: -// -// var u uuid.NullUUID -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) -// ... -// if u.Valid { -// // use u.UUID -// } else { -// // NULL value -// } -// -type NullUUID struct { - UUID UUID - Valid bool // Valid is true if UUID is not NULL -} - -// Scan implements the SQL driver.Scanner interface. -func (nu *NullUUID) Scan(value interface{}) error { - if value == nil { - nu.UUID, nu.Valid = Nil, false - return nil - } - - err := nu.UUID.Scan(value) - if err != nil { - nu.Valid = false - return err - } - - nu.Valid = true - return nil -} - -// Value implements the driver Valuer interface. -func (nu NullUUID) Value() (driver.Value, error) { - if !nu.Valid { - return nil, nil - } - // Delegate to UUID Value function - return nu.UUID.Value() -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (nu NullUUID) MarshalBinary() ([]byte, error) { - if nu.Valid { - return nu.UUID[:], nil - } - - return []byte(nil), nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (nu *NullUUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(nu.UUID[:], data) - nu.Valid = true - return nil -} - -// MarshalText implements encoding.TextMarshaler. -func (nu NullUUID) MarshalText() ([]byte, error) { - if nu.Valid { - return nu.UUID.MarshalText() - } - - return jsonNull, nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (nu *NullUUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - nu.Valid = false - return err - } - nu.UUID = id - nu.Valid = true - return nil -} - -// MarshalJSON implements json.Marshaler. -func (nu NullUUID) MarshalJSON() ([]byte, error) { - if nu.Valid { - return json.Marshal(nu.UUID) - } - - return jsonNull, nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (nu *NullUUID) UnmarshalJSON(data []byte) error { - if bytes.Equal(data, jsonNull) { - *nu = NullUUID{} - return nil // valid null UUID - } - err := json.Unmarshal(data, &nu.UUID) - nu.Valid = err == nil - return err -} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go deleted file mode 100644 index 2e02ec0..0000000 --- a/vendor/github.com/google/uuid/sql.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements sql.Scanner so UUIDs can be read from databases transparently. -// Currently, database types that map to string and []byte are supported. Please -// consult database-specific driver documentation for matching types. -func (uuid *UUID) Scan(src interface{}) error { - switch src := src.(type) { - case nil: - return nil - - case string: - // if an empty UUID comes from a table, we return a null UUID - if src == "" { - return nil - } - - // see Parse for required string format - u, err := Parse(src) - if err != nil { - return fmt.Errorf("Scan: %v", err) - } - - *uuid = u - - case []byte: - // if an empty UUID comes from a table, we return a null UUID - if len(src) == 0 { - return nil - } - - // assumes a simple slice of bytes if 16 bytes - // otherwise attempts to parse - if len(src) != 16 { - return uuid.Scan(string(src)) - } - copy((*uuid)[:], src) - - default: - return fmt.Errorf("Scan: unable to scan type %T into UUID", src) - } - - return nil -} - -// Value implements sql.Valuer so that UUIDs can be written to databases -// transparently. Currently, UUIDs map to strings. Please consult -// database-specific driver documentation for matching types. -func (uuid UUID) Value() (driver.Value, error) { - return uuid.String(), nil -} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go deleted file mode 100644 index e6ef06c..0000000 --- a/vendor/github.com/google/uuid/time.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "sync" - "time" -) - -// A Time represents a time as the number of 100's of nanoseconds since 15 Oct -// 1582. -type Time int64 - -const ( - lillian = 2299160 // Julian day of 15 Oct 1582 - unix = 2440587 // Julian day of 1 Jan 1970 - epoch = unix - lillian // Days between epochs - g1582 = epoch * 86400 // seconds between epochs - g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs -) - -var ( - timeMu sync.Mutex - lasttime uint64 // last time we returned - clockSeq uint16 // clock sequence for this run - - timeNow = time.Now // for testing -) - -// UnixTime converts t the number of seconds and nanoseconds using the Unix -// epoch of 1 Jan 1970. -func (t Time) UnixTime() (sec, nsec int64) { - sec = int64(t - g1582ns100) - nsec = (sec % 10000000) * 100 - sec /= 10000000 - return sec, nsec -} - -// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and -// clock sequence as well as adjusting the clock sequence as needed. An error -// is returned if the current time cannot be determined. -func GetTime() (Time, uint16, error) { - defer timeMu.Unlock() - timeMu.Lock() - return getTime() -} - -func getTime() (Time, uint16, error) { - t := timeNow() - - // If we don't have a clock sequence already, set one. - if clockSeq == 0 { - setClockSequence(-1) - } - now := uint64(t.UnixNano()/100) + g1582ns100 - - // If time has gone backwards with this clock sequence then we - // increment the clock sequence - if now <= lasttime { - clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 - } - lasttime = now - return Time(now), clockSeq, nil -} - -// ClockSequence returns the current clock sequence, generating one if not -// already set. The clock sequence is only used for Version 1 UUIDs. -// -// The uuid package does not use global static storage for the clock sequence or -// the last time a UUID was generated. Unless SetClockSequence is used, a new -// random clock sequence is generated the first time a clock sequence is -// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) -func ClockSequence() int { - defer timeMu.Unlock() - timeMu.Lock() - return clockSequence() -} - -func clockSequence() int { - if clockSeq == 0 { - setClockSequence(-1) - } - return int(clockSeq & 0x3fff) -} - -// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to -// -1 causes a new sequence to be generated. -func SetClockSequence(seq int) { - defer timeMu.Unlock() - timeMu.Lock() - setClockSequence(seq) -} - -func setClockSequence(seq int) { - if seq == -1 { - var b [2]byte - randomBits(b[:]) // clock sequence - seq = int(b[0])<<8 | int(b[1]) - } - oldSeq := clockSeq - clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant - if oldSeq != clockSeq { - lasttime = 0 - } -} - -// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. -func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) -} - -// ClockSequence returns the clock sequence encoded in uuid. -// The clock sequence is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) ClockSequence() int { - return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff -} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go deleted file mode 100644 index 5ea6c73..0000000 --- a/vendor/github.com/google/uuid/util.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// randomBits completely fills slice b with random data. -func randomBits(b []byte) { - if _, err := io.ReadFull(rander, b); err != nil { - panic(err.Error()) // rand should never fail - } -} - -// xvalues returns the value of a byte as a hexadecimal digit or 255. -var xvalues = [256]byte{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -} - -// xtob converts hex characters x1 and x2 into a byte. -func xtob(x1, x2 byte) (byte, bool) { - b1 := xvalues[x1] - b2 := xvalues[x2] - return (b1 << 4) | b2, b1 != 255 && b2 != 255 -} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go deleted file mode 100644 index a57207a..0000000 --- a/vendor/github.com/google/uuid/uuid.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2018 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "io" - "strings" - "sync" -) - -// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC -// 4122. -type UUID [16]byte - -// A Version represents a UUID's version. -type Version byte - -// A Variant represents a UUID's variant. -type Variant byte - -// Constants returned by Variant. -const ( - Invalid = Variant(iota) // Invalid UUID - RFC4122 // The variant specified in RFC4122 - Reserved // Reserved, NCS backward compatibility. - Microsoft // Reserved, Microsoft Corporation backward compatibility. - Future // Reserved for future definition. -) - -const randPoolSize = 16 * 16 - -var ( - rander = rand.Reader // random function - poolEnabled = false - poolMu sync.Mutex - poolPos = randPoolSize // protected with poolMu - pool [randPoolSize]byte // protected with poolMu -) - -type invalidLengthError struct{ len int } - -func (err invalidLengthError) Error() string { - return fmt.Sprintf("invalid UUID length: %d", err.len) -} - -// IsInvalidLengthError is matcher function for custom error invalidLengthError -func IsInvalidLengthError(err error) bool { - _, ok := err.(invalidLengthError) - return ok -} - -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. -func Parse(s string) (UUID, error) { - var uuid UUID - switch len(s) { - // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36: - - // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: - if strings.ToLower(s[:9]) != "urn:uuid:" { - return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - - // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - case 36 + 2: - s = s[1:] - - // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - case 32: - var ok bool - for i := range uuid { - uuid[i], ok = xtob(s[i*2], s[i*2+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(s)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34} { - v, ok := xtob(s[x], s[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// ParseBytes is like Parse, except it parses a byte slice instead of a string. -func ParseBytes(b []byte) (UUID, error) { - var uuid UUID - switch len(b) { - case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { - return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) - } - b = b[9:] - case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - b = b[1:] - case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - var ok bool - for i := 0; i < 32; i += 2 { - uuid[i/2], ok = xtob(b[i], b[i+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(b)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34} { - v, ok := xtob(b[x], b[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// MustParse is like Parse but panics if the string cannot be parsed. -// It simplifies safe initialization of global variables holding compiled UUIDs. -func MustParse(s string) UUID { - uuid, err := Parse(s) - if err != nil { - panic(`uuid: Parse(` + s + `): ` + err.Error()) - } - return uuid -} - -// FromBytes creates a new UUID from a byte slice. Returns an error if the slice -// does not have a length of 16. The bytes are copied from the slice. -func FromBytes(b []byte) (uuid UUID, err error) { - err = uuid.UnmarshalBinary(b) - return uuid, err -} - -// Must returns uuid if err is nil and panics otherwise. -func Must(uuid UUID, err error) UUID { - if err != nil { - panic(err) - } - return uuid -} - -// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// , or "" if uuid is invalid. -func (uuid UUID) String() string { - var buf [36]byte - encodeHex(buf[:], uuid) - return string(buf[:]) -} - -// URN returns the RFC 2141 URN form of uuid, -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. -func (uuid UUID) URN() string { - var buf [36 + 9]byte - copy(buf[:], "urn:uuid:") - encodeHex(buf[9:], uuid) - return string(buf[:]) -} - -func encodeHex(dst []byte, uuid UUID) { - hex.Encode(dst, uuid[:4]) - dst[8] = '-' - hex.Encode(dst[9:13], uuid[4:6]) - dst[13] = '-' - hex.Encode(dst[14:18], uuid[6:8]) - dst[18] = '-' - hex.Encode(dst[19:23], uuid[8:10]) - dst[23] = '-' - hex.Encode(dst[24:], uuid[10:]) -} - -// Variant returns the variant encoded in uuid. -func (uuid UUID) Variant() Variant { - switch { - case (uuid[8] & 0xc0) == 0x80: - return RFC4122 - case (uuid[8] & 0xe0) == 0xc0: - return Microsoft - case (uuid[8] & 0xe0) == 0xe0: - return Future - default: - return Reserved - } -} - -// Version returns the version of uuid. -func (uuid UUID) Version() Version { - return Version(uuid[6] >> 4) -} - -func (v Version) String() string { - if v > 15 { - return fmt.Sprintf("BAD_VERSION_%d", v) - } - return fmt.Sprintf("VERSION_%d", v) -} - -func (v Variant) String() string { - switch v { - case RFC4122: - return "RFC4122" - case Reserved: - return "Reserved" - case Microsoft: - return "Microsoft" - case Future: - return "Future" - case Invalid: - return "Invalid" - } - return fmt.Sprintf("BadVariant%d", int(v)) -} - -// SetRand sets the random number generator to r, which implements io.Reader. -// If r.Read returns an error when the package requests random data then -// a panic will be issued. -// -// Calling SetRand with nil sets the random number generator to the default -// generator. -func SetRand(r io.Reader) { - if r == nil { - rander = rand.Reader - return - } - rander = r -} - -// EnableRandPool enables internal randomness pool used for Random -// (Version 4) UUID generation. The pool contains random bytes read from -// the random number generator on demand in batches. Enabling the pool -// may improve the UUID generation throughput significantly. -// -// Since the pool is stored on the Go heap, this feature may be a bad fit -// for security sensitive applications. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func EnableRandPool() { - poolEnabled = true -} - -// DisableRandPool disables the randomness pool if it was previously -// enabled with EnableRandPool. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func DisableRandPool() { - poolEnabled = false - defer poolMu.Unlock() - poolMu.Lock() - poolPos = randPoolSize -} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go deleted file mode 100644 index 4631096..0000000 --- a/vendor/github.com/google/uuid/version1.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" -) - -// NewUUID returns a Version 1 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewUUID returns nil. If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewUUID returns nil and an error. -// -// In most cases, New should be used. -func NewUUID() (UUID, error) { - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - timeLow := uint32(now & 0xffffffff) - timeMid := uint16((now >> 32) & 0xffff) - timeHi := uint16((now >> 48) & 0x0fff) - timeHi |= 0x1000 // Version 1 - - binary.BigEndian.PutUint32(uuid[0:], timeLow) - binary.BigEndian.PutUint16(uuid[4:], timeMid) - binary.BigEndian.PutUint16(uuid[6:], timeHi) - binary.BigEndian.PutUint16(uuid[8:], seq) - - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - copy(uuid[10:], nodeID[:]) - nodeMu.Unlock() - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go deleted file mode 100644 index 7697802..0000000 --- a/vendor/github.com/google/uuid/version4.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "io" - -// New creates a new random UUID or panics. New is equivalent to -// the expression -// -// uuid.Must(uuid.NewRandom()) -func New() UUID { - return Must(NewRandom()) -} - -// NewString creates a new random UUID and returns it as a string or panics. -// NewString is equivalent to the expression -// -// uuid.New().String() -func NewString() string { - return Must(NewRandom()).String() -} - -// NewRandom returns a Random (Version 4) UUID. -// -// The strength of the UUIDs is based on the strength of the crypto/rand -// package. -// -// Uses the randomness pool if it was enabled with EnableRandPool. -// -// A note about uniqueness derived from the UUID Wikipedia entry: -// -// Randomly generated UUIDs have 122 random bits. One's annual risk of being -// hit by a meteorite is estimated to be one chance in 17 billion, that -// means the probability is about 0.00000000006 (6 × 10−11), -// equivalent to the odds of creating a few tens of trillions of UUIDs in a -// year and having one duplicate. -func NewRandom() (UUID, error) { - if !poolEnabled { - return NewRandomFromReader(rander) - } - return newRandomFromPool() -} - -// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. -func NewRandomFromReader(r io.Reader) (UUID, error) { - var uuid UUID - _, err := io.ReadFull(r, uuid[:]) - if err != nil { - return Nil, err - } - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} - -func newRandomFromPool() (UUID, error) { - var uuid UUID - poolMu.Lock() - if poolPos == randPoolSize { - _, err := io.ReadFull(rander, pool[:]) - if err != nil { - poolMu.Unlock() - return Nil, err - } - poolPos = 0 - } - copy(uuid[:], pool[poolPos:(poolPos+16)]) - poolPos += 16 - poolMu.Unlock() - - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} diff --git a/vendor/gopkg.in/yaml.v2/.travis.yml b/vendor/gopkg.in/yaml.v2/.travis.yml deleted file mode 100644 index 9f55693..0000000 --- a/vendor/gopkg.in/yaml.v2/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go - -go: - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - 1.9 - - tip - -go_import_path: gopkg.in/yaml.v2 diff --git a/vendor/gopkg.in/yaml.v2/LICENSE b/vendor/gopkg.in/yaml.v2/LICENSE deleted file mode 100644 index 8dada3e..0000000 --- a/vendor/gopkg.in/yaml.v2/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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 --git a/vendor/gopkg.in/yaml.v2/LICENSE.libyaml b/vendor/gopkg.in/yaml.v2/LICENSE.libyaml deleted file mode 100644 index 8da58fb..0000000 --- a/vendor/gopkg.in/yaml.v2/LICENSE.libyaml +++ /dev/null @@ -1,31 +0,0 @@ -The following files were ported to Go from C files of libyaml, and thus -are still covered by their original copyright and license: - - apic.go - emitterc.go - parserc.go - readerc.go - scannerc.go - writerc.go - yamlh.go - yamlprivateh.go - -Copyright (c) 2006 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/gopkg.in/yaml.v2/NOTICE b/vendor/gopkg.in/yaml.v2/NOTICE deleted file mode 100644 index 866d74a..0000000 --- a/vendor/gopkg.in/yaml.v2/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2011-2016 Canonical Ltd. - -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 --git a/vendor/gopkg.in/yaml.v2/README.md b/vendor/gopkg.in/yaml.v2/README.md deleted file mode 100644 index b50c6e8..0000000 --- a/vendor/gopkg.in/yaml.v2/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# YAML support for the Go language - -Introduction ------------- - -The yaml package enables Go programs to comfortably encode and decode YAML -values. It was developed within [Canonical](https://www.canonical.com) as -part of the [juju](https://juju.ubuntu.com) project, and is based on a -pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) -C library to parse and generate YAML data quickly and reliably. - -Compatibility -------------- - -The yaml package supports most of YAML 1.1 and 1.2, including support for -anchors, tags, map merging, etc. Multi-document unmarshalling is not yet -implemented, and base-60 floats from YAML 1.1 are purposefully not -supported since they're a poor design and are gone in YAML 1.2. - -Installation and usage ----------------------- - -The import path for the package is *gopkg.in/yaml.v2*. - -To install it, run: - - go get gopkg.in/yaml.v2 - -API documentation ------------------ - -If opened in a browser, the import path itself leads to the API documentation: - - * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) - -API stability -------------- - -The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). - - -License -------- - -The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. - - -Example -------- - -```Go -package main - -import ( - "fmt" - "log" - - "gopkg.in/yaml.v2" -) - -var data = ` -a: Easy! -b: - c: 2 - d: [3, 4] -` - -// Note: struct fields must be public in order for unmarshal to -// correctly populate the data. -type T struct { - A string - B struct { - RenamedC int `yaml:"c"` - D []int `yaml:",flow"` - } -} - -func main() { - t := T{} - - err := yaml.Unmarshal([]byte(data), &t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t:\n%v\n\n", t) - - d, err := yaml.Marshal(&t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t dump:\n%s\n\n", string(d)) - - m := make(map[interface{}]interface{}) - - err = yaml.Unmarshal([]byte(data), &m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m:\n%v\n\n", m) - - d, err = yaml.Marshal(&m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m dump:\n%s\n\n", string(d)) -} -``` - -This example will generate the following output: - -``` ---- t: -{Easy! {2 [3 4]}} - ---- t dump: -a: Easy! -b: - c: 2 - d: [3, 4] - - ---- m: -map[a:Easy! b:map[c:2 d:[3 4]]] - ---- m dump: -a: Easy! -b: - c: 2 - d: - - 3 - - 4 -``` - diff --git a/vendor/gopkg.in/yaml.v2/apic.go b/vendor/gopkg.in/yaml.v2/apic.go deleted file mode 100644 index 1f7e87e..0000000 --- a/vendor/gopkg.in/yaml.v2/apic.go +++ /dev/null @@ -1,739 +0,0 @@ -package yaml - -import ( - "io" -) - -func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { - //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) - - // Check if we can move the queue at the beginning of the buffer. - if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { - if parser.tokens_head != len(parser.tokens) { - copy(parser.tokens, parser.tokens[parser.tokens_head:]) - } - parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] - parser.tokens_head = 0 - } - parser.tokens = append(parser.tokens, *token) - if pos < 0 { - return - } - copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) - parser.tokens[parser.tokens_head+pos] = *token -} - -// Create a new parser object. -func yaml_parser_initialize(parser *yaml_parser_t) bool { - *parser = yaml_parser_t{ - raw_buffer: make([]byte, 0, input_raw_buffer_size), - buffer: make([]byte, 0, input_buffer_size), - } - return true -} - -// Destroy a parser object. -func yaml_parser_delete(parser *yaml_parser_t) { - *parser = yaml_parser_t{} -} - -// String read handler. -func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - if parser.input_pos == len(parser.input) { - return 0, io.EOF - } - n = copy(buffer, parser.input[parser.input_pos:]) - parser.input_pos += n - return n, nil -} - -// Reader read handler. -func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - return parser.input_reader.Read(buffer) -} - -// Set a string input. -func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_string_read_handler - parser.input = input - parser.input_pos = 0 -} - -// Set a file input. -func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_reader_read_handler - parser.input_reader = r -} - -// Set the source encoding. -func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { - if parser.encoding != yaml_ANY_ENCODING { - panic("must set the encoding only once") - } - parser.encoding = encoding -} - -// Create a new emitter object. -func yaml_emitter_initialize(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{ - buffer: make([]byte, output_buffer_size), - raw_buffer: make([]byte, 0, output_raw_buffer_size), - states: make([]yaml_emitter_state_t, 0, initial_stack_size), - events: make([]yaml_event_t, 0, initial_queue_size), - } -} - -// Destroy an emitter object. -func yaml_emitter_delete(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{} -} - -// String write handler. -func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - *emitter.output_buffer = append(*emitter.output_buffer, buffer...) - return nil -} - -// yaml_writer_write_handler uses emitter.output_writer to write the -// emitted text. -func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - _, err := emitter.output_writer.Write(buffer) - return err -} - -// Set a string output. -func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_string_write_handler - emitter.output_buffer = output_buffer -} - -// Set a file output. -func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_writer_write_handler - emitter.output_writer = w -} - -// Set the output encoding. -func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { - if emitter.encoding != yaml_ANY_ENCODING { - panic("must set the output encoding only once") - } - emitter.encoding = encoding -} - -// Set the canonical output style. -func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { - emitter.canonical = canonical -} - -//// Set the indentation increment. -func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { - if indent < 2 || indent > 9 { - indent = 2 - } - emitter.best_indent = indent -} - -// Set the preferred line width. -func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { - if width < 0 { - width = -1 - } - emitter.best_width = width -} - -// Set if unescaped non-ASCII characters are allowed. -func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { - emitter.unicode = unicode -} - -// Set the preferred line break character. -func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { - emitter.line_break = line_break -} - -///* -// * Destroy a token object. -// */ -// -//YAML_DECLARE(void) -//yaml_token_delete(yaml_token_t *token) -//{ -// assert(token); // Non-NULL token object expected. -// -// switch (token.type) -// { -// case YAML_TAG_DIRECTIVE_TOKEN: -// yaml_free(token.data.tag_directive.handle); -// yaml_free(token.data.tag_directive.prefix); -// break; -// -// case YAML_ALIAS_TOKEN: -// yaml_free(token.data.alias.value); -// break; -// -// case YAML_ANCHOR_TOKEN: -// yaml_free(token.data.anchor.value); -// break; -// -// case YAML_TAG_TOKEN: -// yaml_free(token.data.tag.handle); -// yaml_free(token.data.tag.suffix); -// break; -// -// case YAML_SCALAR_TOKEN: -// yaml_free(token.data.scalar.value); -// break; -// -// default: -// break; -// } -// -// memset(token, 0, sizeof(yaml_token_t)); -//} -// -///* -// * Check if a string is a valid UTF-8 sequence. -// * -// * Check 'reader.c' for more details on UTF-8 encoding. -// */ -// -//static int -//yaml_check_utf8(yaml_char_t *start, size_t length) -//{ -// yaml_char_t *end = start+length; -// yaml_char_t *pointer = start; -// -// while (pointer < end) { -// unsigned char octet; -// unsigned int width; -// unsigned int value; -// size_t k; -// -// octet = pointer[0]; -// width = (octet & 0x80) == 0x00 ? 1 : -// (octet & 0xE0) == 0xC0 ? 2 : -// (octet & 0xF0) == 0xE0 ? 3 : -// (octet & 0xF8) == 0xF0 ? 4 : 0; -// value = (octet & 0x80) == 0x00 ? octet & 0x7F : -// (octet & 0xE0) == 0xC0 ? octet & 0x1F : -// (octet & 0xF0) == 0xE0 ? octet & 0x0F : -// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; -// if (!width) return 0; -// if (pointer+width > end) return 0; -// for (k = 1; k < width; k ++) { -// octet = pointer[k]; -// if ((octet & 0xC0) != 0x80) return 0; -// value = (value << 6) + (octet & 0x3F); -// } -// if (!((width == 1) || -// (width == 2 && value >= 0x80) || -// (width == 3 && value >= 0x800) || -// (width == 4 && value >= 0x10000))) return 0; -// -// pointer += width; -// } -// -// return 1; -//} -// - -// Create STREAM-START. -func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - encoding: encoding, - } -} - -// Create STREAM-END. -func yaml_stream_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - } -} - -// Create DOCUMENT-START. -func yaml_document_start_event_initialize( - event *yaml_event_t, - version_directive *yaml_version_directive_t, - tag_directives []yaml_tag_directive_t, - implicit bool, -) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: implicit, - } -} - -// Create DOCUMENT-END. -func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - implicit: implicit, - } -} - -///* -// * Create ALIAS. -// */ -// -//YAML_DECLARE(int) -//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) -//{ -// mark yaml_mark_t = { 0, 0, 0 } -// anchor_copy *yaml_char_t = NULL -// -// assert(event) // Non-NULL event object is expected. -// assert(anchor) // Non-NULL anchor is expected. -// -// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 -// -// anchor_copy = yaml_strdup(anchor) -// if (!anchor_copy) -// return 0 -// -// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) -// -// return 1 -//} - -// Create SCALAR. -func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - anchor: anchor, - tag: tag, - value: value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-START. -func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-END. -func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - } - return true -} - -// Create MAPPING-START. -func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } -} - -// Create MAPPING-END. -func yaml_mapping_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - } -} - -// Destroy an event object. -func yaml_event_delete(event *yaml_event_t) { - *event = yaml_event_t{} -} - -///* -// * Create a document object. -// */ -// -//YAML_DECLARE(int) -//yaml_document_initialize(document *yaml_document_t, -// version_directive *yaml_version_directive_t, -// tag_directives_start *yaml_tag_directive_t, -// tag_directives_end *yaml_tag_directive_t, -// start_implicit int, end_implicit int) -//{ -// struct { -// error yaml_error_type_t -// } context -// struct { -// start *yaml_node_t -// end *yaml_node_t -// top *yaml_node_t -// } nodes = { NULL, NULL, NULL } -// version_directive_copy *yaml_version_directive_t = NULL -// struct { -// start *yaml_tag_directive_t -// end *yaml_tag_directive_t -// top *yaml_tag_directive_t -// } tag_directives_copy = { NULL, NULL, NULL } -// value yaml_tag_directive_t = { NULL, NULL } -// mark yaml_mark_t = { 0, 0, 0 } -// -// assert(document) // Non-NULL document object is expected. -// assert((tag_directives_start && tag_directives_end) || -// (tag_directives_start == tag_directives_end)) -// // Valid tag directives are expected. -// -// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error -// -// if (version_directive) { -// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) -// if (!version_directive_copy) goto error -// version_directive_copy.major = version_directive.major -// version_directive_copy.minor = version_directive.minor -// } -// -// if (tag_directives_start != tag_directives_end) { -// tag_directive *yaml_tag_directive_t -// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) -// goto error -// for (tag_directive = tag_directives_start -// tag_directive != tag_directives_end; tag_directive ++) { -// assert(tag_directive.handle) -// assert(tag_directive.prefix) -// if (!yaml_check_utf8(tag_directive.handle, -// strlen((char *)tag_directive.handle))) -// goto error -// if (!yaml_check_utf8(tag_directive.prefix, -// strlen((char *)tag_directive.prefix))) -// goto error -// value.handle = yaml_strdup(tag_directive.handle) -// value.prefix = yaml_strdup(tag_directive.prefix) -// if (!value.handle || !value.prefix) goto error -// if (!PUSH(&context, tag_directives_copy, value)) -// goto error -// value.handle = NULL -// value.prefix = NULL -// } -// } -// -// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, -// tag_directives_copy.start, tag_directives_copy.top, -// start_implicit, end_implicit, mark, mark) -// -// return 1 -// -//error: -// STACK_DEL(&context, nodes) -// yaml_free(version_directive_copy) -// while (!STACK_EMPTY(&context, tag_directives_copy)) { -// value yaml_tag_directive_t = POP(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// } -// STACK_DEL(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// -// return 0 -//} -// -///* -// * Destroy a document object. -// */ -// -//YAML_DECLARE(void) -//yaml_document_delete(document *yaml_document_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// tag_directive *yaml_tag_directive_t -// -// context.error = YAML_NO_ERROR // Eliminate a compiler warning. -// -// assert(document) // Non-NULL document object is expected. -// -// while (!STACK_EMPTY(&context, document.nodes)) { -// node yaml_node_t = POP(&context, document.nodes) -// yaml_free(node.tag) -// switch (node.type) { -// case YAML_SCALAR_NODE: -// yaml_free(node.data.scalar.value) -// break -// case YAML_SEQUENCE_NODE: -// STACK_DEL(&context, node.data.sequence.items) -// break -// case YAML_MAPPING_NODE: -// STACK_DEL(&context, node.data.mapping.pairs) -// break -// default: -// assert(0) // Should not happen. -// } -// } -// STACK_DEL(&context, document.nodes) -// -// yaml_free(document.version_directive) -// for (tag_directive = document.tag_directives.start -// tag_directive != document.tag_directives.end -// tag_directive++) { -// yaml_free(tag_directive.handle) -// yaml_free(tag_directive.prefix) -// } -// yaml_free(document.tag_directives.start) -// -// memset(document, 0, sizeof(yaml_document_t)) -//} -// -///** -// * Get a document node. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_node(document *yaml_document_t, index int) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (index > 0 && document.nodes.start + index <= document.nodes.top) { -// return document.nodes.start + index - 1 -// } -// return NULL -//} -// -///** -// * Get the root object. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_root_node(document *yaml_document_t) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (document.nodes.top != document.nodes.start) { -// return document.nodes.start -// } -// return NULL -//} -// -///* -// * Add a scalar node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_scalar(document *yaml_document_t, -// tag *yaml_char_t, value *yaml_char_t, length int, -// style yaml_scalar_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// value_copy *yaml_char_t = NULL -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// assert(value) // Non-NULL value is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (length < 0) { -// length = strlen((char *)value) -// } -// -// if (!yaml_check_utf8(value, length)) goto error -// value_copy = yaml_malloc(length+1) -// if (!value_copy) goto error -// memcpy(value_copy, value, length) -// value_copy[length] = '\0' -// -// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// yaml_free(tag_copy) -// yaml_free(value_copy) -// -// return 0 -//} -// -///* -// * Add a sequence node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_sequence(document *yaml_document_t, -// tag *yaml_char_t, style yaml_sequence_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_item_t -// end *yaml_node_item_t -// top *yaml_node_item_t -// } items = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error -// -// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, items) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Add a mapping node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_mapping(document *yaml_document_t, -// tag *yaml_char_t, style yaml_mapping_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_pair_t -// end *yaml_node_pair_t -// top *yaml_node_pair_t -// } pairs = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error -// -// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, pairs) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Append an item to a sequence node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_sequence_item(document *yaml_document_t, -// sequence int, item int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// assert(document) // Non-NULL document is required. -// assert(sequence > 0 -// && document.nodes.start + sequence <= document.nodes.top) -// // Valid sequence id is required. -// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) -// // A sequence node is required. -// assert(item > 0 && document.nodes.start + item <= document.nodes.top) -// // Valid item id is required. -// -// if (!PUSH(&context, -// document.nodes.start[sequence-1].data.sequence.items, item)) -// return 0 -// -// return 1 -//} -// -///* -// * Append a pair of a key and a value to a mapping node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_mapping_pair(document *yaml_document_t, -// mapping int, key int, value int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// pair yaml_node_pair_t -// -// assert(document) // Non-NULL document is required. -// assert(mapping > 0 -// && document.nodes.start + mapping <= document.nodes.top) -// // Valid mapping id is required. -// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) -// // A mapping node is required. -// assert(key > 0 && document.nodes.start + key <= document.nodes.top) -// // Valid key id is required. -// assert(value > 0 && document.nodes.start + value <= document.nodes.top) -// // Valid value id is required. -// -// pair.key = key -// pair.value = value -// -// if (!PUSH(&context, -// document.nodes.start[mapping-1].data.mapping.pairs, pair)) -// return 0 -// -// return 1 -//} -// -// diff --git a/vendor/gopkg.in/yaml.v2/decode.go b/vendor/gopkg.in/yaml.v2/decode.go deleted file mode 100644 index e4e56e2..0000000 --- a/vendor/gopkg.in/yaml.v2/decode.go +++ /dev/null @@ -1,775 +0,0 @@ -package yaml - -import ( - "encoding" - "encoding/base64" - "fmt" - "io" - "math" - "reflect" - "strconv" - "time" -) - -const ( - documentNode = 1 << iota - mappingNode - sequenceNode - scalarNode - aliasNode -) - -type node struct { - kind int - line, column int - tag string - // For an alias node, alias holds the resolved alias. - alias *node - value string - implicit bool - children []*node - anchors map[string]*node -} - -// ---------------------------------------------------------------------------- -// Parser, produces a node tree out of a libyaml event stream. - -type parser struct { - parser yaml_parser_t - event yaml_event_t - doc *node - doneInit bool -} - -func newParser(b []byte) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - if len(b) == 0 { - b = []byte{'\n'} - } - yaml_parser_set_input_string(&p.parser, b) - return &p -} - -func newParserFromReader(r io.Reader) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - yaml_parser_set_input_reader(&p.parser, r) - return &p -} - -func (p *parser) init() { - if p.doneInit { - return - } - p.expect(yaml_STREAM_START_EVENT) - p.doneInit = true -} - -func (p *parser) destroy() { - if p.event.typ != yaml_NO_EVENT { - yaml_event_delete(&p.event) - } - yaml_parser_delete(&p.parser) -} - -// expect consumes an event from the event stream and -// checks that it's of the expected type. -func (p *parser) expect(e yaml_event_type_t) { - if p.event.typ == yaml_NO_EVENT { - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - } - if p.event.typ == yaml_STREAM_END_EVENT { - failf("attempted to go past the end of stream; corrupted value?") - } - if p.event.typ != e { - p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) - p.fail() - } - yaml_event_delete(&p.event) - p.event.typ = yaml_NO_EVENT -} - -// peek peeks at the next event in the event stream, -// puts the results into p.event and returns the event type. -func (p *parser) peek() yaml_event_type_t { - if p.event.typ != yaml_NO_EVENT { - return p.event.typ - } - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - return p.event.typ -} - -func (p *parser) fail() { - var where string - var line int - if p.parser.problem_mark.line != 0 { - line = p.parser.problem_mark.line - // Scanner errors don't iterate line before returning error - if p.parser.error == yaml_SCANNER_ERROR { - line++ - } - } else if p.parser.context_mark.line != 0 { - line = p.parser.context_mark.line - } - if line != 0 { - where = "line " + strconv.Itoa(line) + ": " - } - var msg string - if len(p.parser.problem) > 0 { - msg = p.parser.problem - } else { - msg = "unknown problem parsing YAML content" - } - failf("%s%s", where, msg) -} - -func (p *parser) anchor(n *node, anchor []byte) { - if anchor != nil { - p.doc.anchors[string(anchor)] = n - } -} - -func (p *parser) parse() *node { - p.init() - switch p.peek() { - case yaml_SCALAR_EVENT: - return p.scalar() - case yaml_ALIAS_EVENT: - return p.alias() - case yaml_MAPPING_START_EVENT: - return p.mapping() - case yaml_SEQUENCE_START_EVENT: - return p.sequence() - case yaml_DOCUMENT_START_EVENT: - return p.document() - case yaml_STREAM_END_EVENT: - // Happens when attempting to decode an empty buffer. - return nil - default: - panic("attempted to parse unknown event: " + p.event.typ.String()) - } -} - -func (p *parser) node(kind int) *node { - return &node{ - kind: kind, - line: p.event.start_mark.line, - column: p.event.start_mark.column, - } -} - -func (p *parser) document() *node { - n := p.node(documentNode) - n.anchors = make(map[string]*node) - p.doc = n - p.expect(yaml_DOCUMENT_START_EVENT) - n.children = append(n.children, p.parse()) - p.expect(yaml_DOCUMENT_END_EVENT) - return n -} - -func (p *parser) alias() *node { - n := p.node(aliasNode) - n.value = string(p.event.anchor) - n.alias = p.doc.anchors[n.value] - if n.alias == nil { - failf("unknown anchor '%s' referenced", n.value) - } - p.expect(yaml_ALIAS_EVENT) - return n -} - -func (p *parser) scalar() *node { - n := p.node(scalarNode) - n.value = string(p.event.value) - n.tag = string(p.event.tag) - n.implicit = p.event.implicit - p.anchor(n, p.event.anchor) - p.expect(yaml_SCALAR_EVENT) - return n -} - -func (p *parser) sequence() *node { - n := p.node(sequenceNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_SEQUENCE_START_EVENT) - for p.peek() != yaml_SEQUENCE_END_EVENT { - n.children = append(n.children, p.parse()) - } - p.expect(yaml_SEQUENCE_END_EVENT) - return n -} - -func (p *parser) mapping() *node { - n := p.node(mappingNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_MAPPING_START_EVENT) - for p.peek() != yaml_MAPPING_END_EVENT { - n.children = append(n.children, p.parse(), p.parse()) - } - p.expect(yaml_MAPPING_END_EVENT) - return n -} - -// ---------------------------------------------------------------------------- -// Decoder, unmarshals a node into a provided value. - -type decoder struct { - doc *node - aliases map[*node]bool - mapType reflect.Type - terrors []string - strict bool -} - -var ( - mapItemType = reflect.TypeOf(MapItem{}) - durationType = reflect.TypeOf(time.Duration(0)) - defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) - ifaceType = defaultMapType.Elem() - timeType = reflect.TypeOf(time.Time{}) - ptrTimeType = reflect.TypeOf(&time.Time{}) -) - -func newDecoder(strict bool) *decoder { - d := &decoder{mapType: defaultMapType, strict: strict} - d.aliases = make(map[*node]bool) - return d -} - -func (d *decoder) terror(n *node, tag string, out reflect.Value) { - if n.tag != "" { - tag = n.tag - } - value := n.value - if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { - if len(value) > 10 { - value = " `" + value[:7] + "...`" - } else { - value = " `" + value + "`" - } - } - d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) -} - -func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { - terrlen := len(d.terrors) - err := u.UnmarshalYAML(func(v interface{}) (err error) { - defer handleErr(&err) - d.unmarshal(n, reflect.ValueOf(v)) - if len(d.terrors) > terrlen { - issues := d.terrors[terrlen:] - d.terrors = d.terrors[:terrlen] - return &TypeError{issues} - } - return nil - }) - if e, ok := err.(*TypeError); ok { - d.terrors = append(d.terrors, e.Errors...) - return false - } - if err != nil { - fail(err) - } - return true -} - -// d.prepare initializes and dereferences pointers and calls UnmarshalYAML -// if a value is found to implement it. -// It returns the initialized and dereferenced out value, whether -// unmarshalling was already done by UnmarshalYAML, and if so whether -// its types unmarshalled appropriately. -// -// If n holds a null value, prepare returns before doing anything. -func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { - if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { - return out, false, false - } - again := true - for again { - again = false - if out.Kind() == reflect.Ptr { - if out.IsNil() { - out.Set(reflect.New(out.Type().Elem())) - } - out = out.Elem() - again = true - } - if out.CanAddr() { - if u, ok := out.Addr().Interface().(Unmarshaler); ok { - good = d.callUnmarshaler(n, u) - return out, true, good - } - } - } - return out, false, false -} - -func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { - switch n.kind { - case documentNode: - return d.document(n, out) - case aliasNode: - return d.alias(n, out) - } - out, unmarshaled, good := d.prepare(n, out) - if unmarshaled { - return good - } - switch n.kind { - case scalarNode: - good = d.scalar(n, out) - case mappingNode: - good = d.mapping(n, out) - case sequenceNode: - good = d.sequence(n, out) - default: - panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) - } - return good -} - -func (d *decoder) document(n *node, out reflect.Value) (good bool) { - if len(n.children) == 1 { - d.doc = n - d.unmarshal(n.children[0], out) - return true - } - return false -} - -func (d *decoder) alias(n *node, out reflect.Value) (good bool) { - if d.aliases[n] { - // TODO this could actually be allowed in some circumstances. - failf("anchor '%s' value contains itself", n.value) - } - d.aliases[n] = true - good = d.unmarshal(n.alias, out) - delete(d.aliases, n) - return good -} - -var zeroValue reflect.Value - -func resetMap(out reflect.Value) { - for _, k := range out.MapKeys() { - out.SetMapIndex(k, zeroValue) - } -} - -func (d *decoder) scalar(n *node, out reflect.Value) bool { - var tag string - var resolved interface{} - if n.tag == "" && !n.implicit { - tag = yaml_STR_TAG - resolved = n.value - } else { - tag, resolved = resolve(n.tag, n.value) - if tag == yaml_BINARY_TAG { - data, err := base64.StdEncoding.DecodeString(resolved.(string)) - if err != nil { - failf("!!binary value contains invalid base64 data") - } - resolved = string(data) - } - } - if resolved == nil { - if out.Kind() == reflect.Map && !out.CanAddr() { - resetMap(out) - } else { - out.Set(reflect.Zero(out.Type())) - } - return true - } - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - // We've resolved to exactly the type we want, so use that. - out.Set(resolvedv) - return true - } - // Perhaps we can use the value as a TextUnmarshaler to - // set its value. - if out.CanAddr() { - u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) - if ok { - var text []byte - if tag == yaml_BINARY_TAG { - text = []byte(resolved.(string)) - } else { - // We let any value be unmarshaled into TextUnmarshaler. - // That might be more lax than we'd like, but the - // TextUnmarshaler itself should bowl out any dubious values. - text = []byte(n.value) - } - err := u.UnmarshalText(text) - if err != nil { - fail(err) - } - return true - } - } - switch out.Kind() { - case reflect.String: - if tag == yaml_BINARY_TAG { - out.SetString(resolved.(string)) - return true - } - if resolved != nil { - out.SetString(n.value) - return true - } - case reflect.Interface: - if resolved == nil { - out.Set(reflect.Zero(out.Type())) - } else if tag == yaml_TIMESTAMP_TAG { - // It looks like a timestamp but for backward compatibility - // reasons we set it as a string, so that code that unmarshals - // timestamp-like values into interface{} will continue to - // see a string and not a time.Time. - // TODO(v3) Drop this. - out.Set(reflect.ValueOf(n.value)) - } else { - out.Set(reflect.ValueOf(resolved)) - } - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch resolved := resolved.(type) { - case int: - if !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case int64: - if !out.OverflowInt(resolved) { - out.SetInt(resolved) - return true - } - case uint64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case float64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case string: - if out.Type() == durationType { - d, err := time.ParseDuration(resolved) - if err == nil { - out.SetInt(int64(d)) - return true - } - } - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch resolved := resolved.(type) { - case int: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case int64: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case uint64: - if !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case float64: - if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - } - case reflect.Bool: - switch resolved := resolved.(type) { - case bool: - out.SetBool(resolved) - return true - } - case reflect.Float32, reflect.Float64: - switch resolved := resolved.(type) { - case int: - out.SetFloat(float64(resolved)) - return true - case int64: - out.SetFloat(float64(resolved)) - return true - case uint64: - out.SetFloat(float64(resolved)) - return true - case float64: - out.SetFloat(resolved) - return true - } - case reflect.Struct: - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - out.Set(resolvedv) - return true - } - case reflect.Ptr: - if out.Type().Elem() == reflect.TypeOf(resolved) { - // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? - elem := reflect.New(out.Type().Elem()) - elem.Elem().Set(reflect.ValueOf(resolved)) - out.Set(elem) - return true - } - } - d.terror(n, tag, out) - return false -} - -func settableValueOf(i interface{}) reflect.Value { - v := reflect.ValueOf(i) - sv := reflect.New(v.Type()).Elem() - sv.Set(v) - return sv -} - -func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - l := len(n.children) - - var iface reflect.Value - switch out.Kind() { - case reflect.Slice: - out.Set(reflect.MakeSlice(out.Type(), l, l)) - case reflect.Array: - if l != out.Len() { - failf("invalid array: want %d elements but got %d", out.Len(), l) - } - case reflect.Interface: - // No type hints. Will have to use a generic sequence. - iface = out - out = settableValueOf(make([]interface{}, l)) - default: - d.terror(n, yaml_SEQ_TAG, out) - return false - } - et := out.Type().Elem() - - j := 0 - for i := 0; i < l; i++ { - e := reflect.New(et).Elem() - if ok := d.unmarshal(n.children[i], e); ok { - out.Index(j).Set(e) - j++ - } - } - if out.Kind() != reflect.Array { - out.Set(out.Slice(0, j)) - } - if iface.IsValid() { - iface.Set(out) - } - return true -} - -func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - switch out.Kind() { - case reflect.Struct: - return d.mappingStruct(n, out) - case reflect.Slice: - return d.mappingSlice(n, out) - case reflect.Map: - // okay - case reflect.Interface: - if d.mapType.Kind() == reflect.Map { - iface := out - out = reflect.MakeMap(d.mapType) - iface.Set(out) - } else { - slicev := reflect.New(d.mapType).Elem() - if !d.mappingSlice(n, slicev) { - return false - } - out.Set(slicev) - return true - } - default: - d.terror(n, yaml_MAP_TAG, out) - return false - } - outt := out.Type() - kt := outt.Key() - et := outt.Elem() - - mapType := d.mapType - if outt.Key() == ifaceType && outt.Elem() == ifaceType { - d.mapType = outt - } - - if out.IsNil() { - out.Set(reflect.MakeMap(outt)) - } - l := len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - k := reflect.New(kt).Elem() - if d.unmarshal(n.children[i], k) { - kkind := k.Kind() - if kkind == reflect.Interface { - kkind = k.Elem().Kind() - } - if kkind == reflect.Map || kkind == reflect.Slice { - failf("invalid map key: %#v", k.Interface()) - } - e := reflect.New(et).Elem() - if d.unmarshal(n.children[i+1], e) { - d.setMapIndex(n.children[i+1], out, k, e) - } - } - } - d.mapType = mapType - return true -} - -func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { - if d.strict && out.MapIndex(k) != zeroValue { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) - return - } - out.SetMapIndex(k, v) -} - -func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { - outt := out.Type() - if outt.Elem() != mapItemType { - d.terror(n, yaml_MAP_TAG, out) - return false - } - - mapType := d.mapType - d.mapType = outt - - var slice []MapItem - var l = len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - item := MapItem{} - k := reflect.ValueOf(&item.Key).Elem() - if d.unmarshal(n.children[i], k) { - v := reflect.ValueOf(&item.Value).Elem() - if d.unmarshal(n.children[i+1], v) { - slice = append(slice, item) - } - } - } - out.Set(reflect.ValueOf(slice)) - d.mapType = mapType - return true -} - -func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { - sinfo, err := getStructInfo(out.Type()) - if err != nil { - panic(err) - } - name := settableValueOf("") - l := len(n.children) - - var inlineMap reflect.Value - var elemType reflect.Type - if sinfo.InlineMap != -1 { - inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) - elemType = inlineMap.Type().Elem() - } - - var doneFields []bool - if d.strict { - doneFields = make([]bool, len(sinfo.FieldsList)) - } - for i := 0; i < l; i += 2 { - ni := n.children[i] - if isMerge(ni) { - d.merge(n.children[i+1], out) - continue - } - if !d.unmarshal(ni, name) { - continue - } - if info, ok := sinfo.FieldsMap[name.String()]; ok { - if d.strict { - if doneFields[info.Id] { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) - continue - } - doneFields[info.Id] = true - } - var field reflect.Value - if info.Inline == nil { - field = out.Field(info.Num) - } else { - field = out.FieldByIndex(info.Inline) - } - d.unmarshal(n.children[i+1], field) - } else if sinfo.InlineMap != -1 { - if inlineMap.IsNil() { - inlineMap.Set(reflect.MakeMap(inlineMap.Type())) - } - value := reflect.New(elemType).Elem() - d.unmarshal(n.children[i+1], value) - d.setMapIndex(n.children[i+1], inlineMap, name, value) - } else if d.strict { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) - } - } - return true -} - -func failWantMap() { - failf("map merge requires map or sequence of maps as the value") -} - -func (d *decoder) merge(n *node, out reflect.Value) { - switch n.kind { - case mappingNode: - d.unmarshal(n, out) - case aliasNode: - an, ok := d.doc.anchors[n.value] - if ok && an.kind != mappingNode { - failWantMap() - } - d.unmarshal(n, out) - case sequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.children) - 1; i >= 0; i-- { - ni := n.children[i] - if ni.kind == aliasNode { - an, ok := d.doc.anchors[ni.value] - if ok && an.kind != mappingNode { - failWantMap() - } - } else if ni.kind != mappingNode { - failWantMap() - } - d.unmarshal(ni, out) - } - default: - failWantMap() - } -} - -func isMerge(n *node) bool { - return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) -} diff --git a/vendor/gopkg.in/yaml.v2/emitterc.go b/vendor/gopkg.in/yaml.v2/emitterc.go deleted file mode 100644 index a1c2cc5..0000000 --- a/vendor/gopkg.in/yaml.v2/emitterc.go +++ /dev/null @@ -1,1685 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Flush the buffer if needed. -func flush(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) { - return yaml_emitter_flush(emitter) - } - return true -} - -// Put a character to the output buffer. -func put(emitter *yaml_emitter_t, value byte) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - emitter.buffer[emitter.buffer_pos] = value - emitter.buffer_pos++ - emitter.column++ - return true -} - -// Put a line break to the output buffer. -func put_break(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - switch emitter.line_break { - case yaml_CR_BREAK: - emitter.buffer[emitter.buffer_pos] = '\r' - emitter.buffer_pos += 1 - case yaml_LN_BREAK: - emitter.buffer[emitter.buffer_pos] = '\n' - emitter.buffer_pos += 1 - case yaml_CRLN_BREAK: - emitter.buffer[emitter.buffer_pos+0] = '\r' - emitter.buffer[emitter.buffer_pos+1] = '\n' - emitter.buffer_pos += 2 - default: - panic("unknown line break setting") - } - emitter.column = 0 - emitter.line++ - return true -} - -// Copy a character from a string into buffer. -func write(emitter *yaml_emitter_t, s []byte, i *int) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - p := emitter.buffer_pos - w := width(s[*i]) - switch w { - case 4: - emitter.buffer[p+3] = s[*i+3] - fallthrough - case 3: - emitter.buffer[p+2] = s[*i+2] - fallthrough - case 2: - emitter.buffer[p+1] = s[*i+1] - fallthrough - case 1: - emitter.buffer[p+0] = s[*i+0] - default: - panic("unknown character width") - } - emitter.column++ - emitter.buffer_pos += w - *i += w - return true -} - -// Write a whole string into buffer. -func write_all(emitter *yaml_emitter_t, s []byte) bool { - for i := 0; i < len(s); { - if !write(emitter, s, &i) { - return false - } - } - return true -} - -// Copy a line break character from a string into buffer. -func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { - if s[*i] == '\n' { - if !put_break(emitter) { - return false - } - *i++ - } else { - if !write(emitter, s, i) { - return false - } - emitter.column = 0 - emitter.line++ - } - return true -} - -// Set an emitter error and return false. -func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_EMITTER_ERROR - emitter.problem = problem - return false -} - -// Emit an event. -func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.events = append(emitter.events, *event) - for !yaml_emitter_need_more_events(emitter) { - event := &emitter.events[emitter.events_head] - if !yaml_emitter_analyze_event(emitter, event) { - return false - } - if !yaml_emitter_state_machine(emitter, event) { - return false - } - yaml_event_delete(event) - emitter.events_head++ - } - return true -} - -// Check if we need to accumulate more events before emitting. -// -// We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// -func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { - if emitter.events_head == len(emitter.events) { - return true - } - var accumulate int - switch emitter.events[emitter.events_head].typ { - case yaml_DOCUMENT_START_EVENT: - accumulate = 1 - break - case yaml_SEQUENCE_START_EVENT: - accumulate = 2 - break - case yaml_MAPPING_START_EVENT: - accumulate = 3 - break - default: - return false - } - if len(emitter.events)-emitter.events_head > accumulate { - return false - } - var level int - for i := emitter.events_head; i < len(emitter.events); i++ { - switch emitter.events[i].typ { - case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: - level++ - case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: - level-- - } - if level == 0 { - return false - } - } - return true -} - -// Append a directive to the directives stack. -func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { - for i := 0; i < len(emitter.tag_directives); i++ { - if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") - } - } - - // [Go] Do we actually need to copy this given garbage collection - // and the lack of deallocating destructors? - tag_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(tag_copy.handle, value.handle) - copy(tag_copy.prefix, value.prefix) - emitter.tag_directives = append(emitter.tag_directives, tag_copy) - return true -} - -// Increase the indentation level. -func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { - emitter.indents = append(emitter.indents, emitter.indent) - if emitter.indent < 0 { - if flow { - emitter.indent = emitter.best_indent - } else { - emitter.indent = 0 - } - } else if !indentless { - emitter.indent += emitter.best_indent - } - return true -} - -// State dispatcher. -func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { - switch emitter.state { - default: - case yaml_EMIT_STREAM_START_STATE: - return yaml_emitter_emit_stream_start(emitter, event) - - case yaml_EMIT_FIRST_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, true) - - case yaml_EMIT_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, false) - - case yaml_EMIT_DOCUMENT_CONTENT_STATE: - return yaml_emitter_emit_document_content(emitter, event) - - case yaml_EMIT_DOCUMENT_END_STATE: - return yaml_emitter_emit_document_end(emitter, event) - - case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, true) - - case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, false) - - case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, true) - - case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, false) - - case yaml_EMIT_END_STATE: - return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") - } - panic("invalid emitter state") -} - -// Expect STREAM-START. -func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_STREAM_START_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") - } - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = event.encoding - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = yaml_UTF8_ENCODING - } - } - if emitter.best_indent < 2 || emitter.best_indent > 9 { - emitter.best_indent = 2 - } - if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { - emitter.best_width = 80 - } - if emitter.best_width < 0 { - emitter.best_width = 1<<31 - 1 - } - if emitter.line_break == yaml_ANY_BREAK { - emitter.line_break = yaml_LN_BREAK - } - - emitter.indent = -1 - emitter.line = 0 - emitter.column = 0 - emitter.whitespace = true - emitter.indention = true - - if emitter.encoding != yaml_UTF8_ENCODING { - if !yaml_emitter_write_bom(emitter) { - return false - } - } - emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE - return true -} - -// Expect DOCUMENT-START or STREAM-END. -func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - - if event.typ == yaml_DOCUMENT_START_EVENT { - - if event.version_directive != nil { - if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { - return false - } - } - - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { - return false - } - if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { - return false - } - } - - for i := 0; i < len(default_tag_directives); i++ { - tag_directive := &default_tag_directives[i] - if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { - return false - } - } - - implicit := event.implicit - if !first || emitter.canonical { - implicit = false - } - - if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if event.version_directive != nil { - implicit = false - if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if len(event.tag_directives) > 0 { - implicit = false - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { - return false - } - if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - if yaml_emitter_check_empty_document(emitter) { - implicit = false - } - if !implicit { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { - return false - } - if emitter.canonical { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE - return true - } - - if event.typ == yaml_STREAM_END_EVENT { - if emitter.open_ended { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_END_STATE - return true - } - - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") -} - -// Expect the root node. -func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) - return yaml_emitter_emit_node(emitter, event, true, false, false, false) -} - -// Expect DOCUMENT-END. -func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_DOCUMENT_END_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !event.implicit { - // [Go] Allocate the slice elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_DOCUMENT_START_STATE - emitter.tag_directives = emitter.tag_directives[:0] - return true -} - -// Expect a flow item node. -func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a flow key node. -func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_MAPPING_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a flow value node. -func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block item node. -func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { - return false - } - } - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a block key node. -func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, false) { - return false - } - } - if event.typ == yaml_MAPPING_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block value node. -func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a node. -func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, - root bool, sequence bool, mapping bool, simple_key bool) bool { - - emitter.root_context = root - emitter.sequence_context = sequence - emitter.mapping_context = mapping - emitter.simple_key_context = simple_key - - switch event.typ { - case yaml_ALIAS_EVENT: - return yaml_emitter_emit_alias(emitter, event) - case yaml_SCALAR_EVENT: - return yaml_emitter_emit_scalar(emitter, event) - case yaml_SEQUENCE_START_EVENT: - return yaml_emitter_emit_sequence_start(emitter, event) - case yaml_MAPPING_START_EVENT: - return yaml_emitter_emit_mapping_start(emitter, event) - default: - return yaml_emitter_set_emitter_error(emitter, - fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) - } -} - -// Expect ALIAS. -func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SCALAR. -func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_select_scalar_style(emitter, event) { - return false - } - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - if !yaml_emitter_process_scalar(emitter) { - return false - } - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SEQUENCE-START. -func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || - yaml_emitter_check_empty_sequence(emitter) { - emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE - } - return true -} - -// Expect MAPPING-START. -func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || - yaml_emitter_check_empty_mapping(emitter) { - emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE - } - return true -} - -// Check if the document content is an empty scalar. -func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { - return false // [Go] Huh? -} - -// Check if the next events represent an empty sequence. -func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT -} - -// Check if the next events represent an empty mapping. -func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT -} - -// Check if the next node can be expressed as a simple key. -func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { - length := 0 - switch emitter.events[emitter.events_head].typ { - case yaml_ALIAS_EVENT: - length += len(emitter.anchor_data.anchor) - case yaml_SCALAR_EVENT: - if emitter.scalar_data.multiline { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) + - len(emitter.scalar_data.value) - case yaml_SEQUENCE_START_EVENT: - if !yaml_emitter_check_empty_sequence(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - case yaml_MAPPING_START_EVENT: - if !yaml_emitter_check_empty_mapping(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - default: - return false - } - return length <= 128 -} - -// Determine an acceptable scalar style. -func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 - if no_tag && !event.implicit && !event.quoted_implicit { - return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") - } - - style := event.scalar_style() - if style == yaml_ANY_SCALAR_STYLE { - style = yaml_PLAIN_SCALAR_STYLE - } - if emitter.canonical { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - if emitter.simple_key_context && emitter.scalar_data.multiline { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - - if style == yaml_PLAIN_SCALAR_STYLE { - if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || - emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if no_tag && !event.implicit { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { - if !emitter.scalar_data.single_quoted_allowed { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { - if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - - if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { - emitter.tag_data.handle = []byte{'!'} - } - emitter.scalar_data.style = style - return true -} - -// Write an anchor. -func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { - if emitter.anchor_data.anchor == nil { - return true - } - c := []byte{'&'} - if emitter.anchor_data.alias { - c[0] = '*' - } - if !yaml_emitter_write_indicator(emitter, c, true, false, false) { - return false - } - return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) -} - -// Write a tag. -func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { - if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { - return true - } - if len(emitter.tag_data.handle) > 0 { - if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { - return false - } - if len(emitter.tag_data.suffix) > 0 { - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - } - } else { - // [Go] Allocate these slices elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { - return false - } - } - return true -} - -// Write a scalar. -func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { - switch emitter.scalar_data.style { - case yaml_PLAIN_SCALAR_STYLE: - return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_SINGLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_DOUBLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_LITERAL_SCALAR_STYLE: - return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) - - case yaml_FOLDED_SCALAR_STYLE: - return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) - } - panic("unknown scalar style") -} - -// Check if a %YAML directive is valid. -func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { - if version_directive.major != 1 || version_directive.minor != 1 { - return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") - } - return true -} - -// Check if a %TAG directive is valid. -func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { - handle := tag_directive.handle - prefix := tag_directive.prefix - if len(handle) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") - } - if handle[0] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") - } - if handle[len(handle)-1] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") - } - for i := 1; i < len(handle)-1; i += width(handle[i]) { - if !is_alpha(handle, i) { - return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") - } - } - if len(prefix) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") - } - return true -} - -// Check if an anchor is valid. -func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { - if len(anchor) == 0 { - problem := "anchor value must not be empty" - if alias { - problem = "alias value must not be empty" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - for i := 0; i < len(anchor); i += width(anchor[i]) { - if !is_alpha(anchor, i) { - problem := "anchor value must contain alphanumerical characters only" - if alias { - problem = "alias value must contain alphanumerical characters only" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - } - emitter.anchor_data.anchor = anchor - emitter.anchor_data.alias = alias - return true -} - -// Check if a tag is valid. -func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { - if len(tag) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") - } - for i := 0; i < len(emitter.tag_directives); i++ { - tag_directive := &emitter.tag_directives[i] - if bytes.HasPrefix(tag, tag_directive.prefix) { - emitter.tag_data.handle = tag_directive.handle - emitter.tag_data.suffix = tag[len(tag_directive.prefix):] - return true - } - } - emitter.tag_data.suffix = tag - return true -} - -// Check if a scalar is valid. -func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { - var ( - block_indicators = false - flow_indicators = false - line_breaks = false - special_characters = false - - leading_space = false - leading_break = false - trailing_space = false - trailing_break = false - break_space = false - space_break = false - - preceded_by_whitespace = false - followed_by_whitespace = false - previous_space = false - previous_break = false - ) - - emitter.scalar_data.value = value - - if len(value) == 0 { - emitter.scalar_data.multiline = false - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = false - return true - } - - if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { - block_indicators = true - flow_indicators = true - } - - preceded_by_whitespace = true - for i, w := 0, 0; i < len(value); i += w { - w = width(value[i]) - followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) - - if i == 0 { - switch value[i] { - case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': - flow_indicators = true - block_indicators = true - case '?', ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '-': - if followed_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } else { - switch value[i] { - case ',', '?', '[', ']', '{', '}': - flow_indicators = true - case ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '#': - if preceded_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } - - if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { - special_characters = true - } - if is_space(value, i) { - if i == 0 { - leading_space = true - } - if i+width(value[i]) == len(value) { - trailing_space = true - } - if previous_break { - break_space = true - } - previous_space = true - previous_break = false - } else if is_break(value, i) { - line_breaks = true - if i == 0 { - leading_break = true - } - if i+width(value[i]) == len(value) { - trailing_break = true - } - if previous_space { - space_break = true - } - previous_space = false - previous_break = true - } else { - previous_space = false - previous_break = false - } - - // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. - preceded_by_whitespace = is_blankz(value, i) - } - - emitter.scalar_data.multiline = line_breaks - emitter.scalar_data.flow_plain_allowed = true - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = true - - if leading_space || leading_break || trailing_space || trailing_break { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if trailing_space { - emitter.scalar_data.block_allowed = false - } - if break_space { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - } - if space_break || special_characters { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - emitter.scalar_data.block_allowed = false - } - if line_breaks { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if flow_indicators { - emitter.scalar_data.flow_plain_allowed = false - } - if block_indicators { - emitter.scalar_data.block_plain_allowed = false - } - return true -} - -// Check if the event data is valid. -func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - emitter.anchor_data.anchor = nil - emitter.tag_data.handle = nil - emitter.tag_data.suffix = nil - emitter.scalar_data.value = nil - - switch event.typ { - case yaml_ALIAS_EVENT: - if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { - return false - } - - case yaml_SCALAR_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - if !yaml_emitter_analyze_scalar(emitter, event.value) { - return false - } - - case yaml_SEQUENCE_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - - case yaml_MAPPING_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - } - return true -} - -// Write the BOM character. -func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { - if !flush(emitter) { - return false - } - pos := emitter.buffer_pos - emitter.buffer[pos+0] = '\xEF' - emitter.buffer[pos+1] = '\xBB' - emitter.buffer[pos+2] = '\xBF' - emitter.buffer_pos += 3 - return true -} - -func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { - indent := emitter.indent - if indent < 0 { - indent = 0 - } - if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { - if !put_break(emitter) { - return false - } - } - for emitter.column < indent { - if !put(emitter, ' ') { - return false - } - } - emitter.whitespace = true - emitter.indention = true - return true -} - -func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, indicator) { - return false - } - emitter.whitespace = is_whitespace - emitter.indention = (emitter.indention && is_indention) - emitter.open_ended = false - return true -} - -func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - for i := 0; i < len(value); { - var must_write bool - switch value[i] { - case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': - must_write = true - default: - must_write = is_alpha(value, i) - } - if must_write { - if !write(emitter, value, &i) { - return false - } - } else { - w := width(value[i]) - for k := 0; k < w; k++ { - octet := value[i] - i++ - if !put(emitter, '%') { - return false - } - - c := octet >> 4 - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - - c = octet & 0x0f - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - } - } - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - - emitter.whitespace = false - emitter.indention = false - if emitter.root_context { - emitter.open_ended = true - } - - return true -} - -func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { - return false - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if value[i] == '\'' { - if !put(emitter, '\'') { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - spaces := false - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { - return false - } - - for i := 0; i < len(value); { - if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || - is_bom(value, i) || is_break(value, i) || - value[i] == '"' || value[i] == '\\' { - - octet := value[i] - - var w int - var v rune - switch { - case octet&0x80 == 0x00: - w, v = 1, rune(octet&0x7F) - case octet&0xE0 == 0xC0: - w, v = 2, rune(octet&0x1F) - case octet&0xF0 == 0xE0: - w, v = 3, rune(octet&0x0F) - case octet&0xF8 == 0xF0: - w, v = 4, rune(octet&0x07) - } - for k := 1; k < w; k++ { - octet = value[i+k] - v = (v << 6) + (rune(octet) & 0x3F) - } - i += w - - if !put(emitter, '\\') { - return false - } - - var ok bool - switch v { - case 0x00: - ok = put(emitter, '0') - case 0x07: - ok = put(emitter, 'a') - case 0x08: - ok = put(emitter, 'b') - case 0x09: - ok = put(emitter, 't') - case 0x0A: - ok = put(emitter, 'n') - case 0x0b: - ok = put(emitter, 'v') - case 0x0c: - ok = put(emitter, 'f') - case 0x0d: - ok = put(emitter, 'r') - case 0x1b: - ok = put(emitter, 'e') - case 0x22: - ok = put(emitter, '"') - case 0x5c: - ok = put(emitter, '\\') - case 0x85: - ok = put(emitter, 'N') - case 0xA0: - ok = put(emitter, '_') - case 0x2028: - ok = put(emitter, 'L') - case 0x2029: - ok = put(emitter, 'P') - default: - if v <= 0xFF { - ok = put(emitter, 'x') - w = 2 - } else if v <= 0xFFFF { - ok = put(emitter, 'u') - w = 4 - } else { - ok = put(emitter, 'U') - w = 8 - } - for k := (w - 1) * 4; ok && k >= 0; k -= 4 { - digit := byte((v >> uint(k)) & 0x0F) - if digit < 10 { - ok = put(emitter, digit+'0') - } else { - ok = put(emitter, digit+'A'-10) - } - } - } - if !ok { - return false - } - spaces = false - } else if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { - if !yaml_emitter_write_indent(emitter) { - return false - } - if is_space(value, i+1) { - if !put(emitter, '\\') { - return false - } - } - i += width(value[i]) - } else if !write(emitter, value, &i) { - return false - } - spaces = true - } else { - if !write(emitter, value, &i) { - return false - } - spaces = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { - if is_space(value, 0) || is_break(value, 0) { - indent_hint := []byte{'0' + byte(emitter.best_indent)} - if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { - return false - } - } - - emitter.open_ended = false - - var chomp_hint [1]byte - if len(value) == 0 { - chomp_hint[0] = '-' - } else { - i := len(value) - 1 - for value[i]&0xC0 == 0x80 { - i-- - } - if !is_break(value, i) { - chomp_hint[0] = '-' - } else if i == 0 { - chomp_hint[0] = '+' - emitter.open_ended = true - } else { - i-- - for value[i]&0xC0 == 0x80 { - i-- - } - if is_break(value, i) { - chomp_hint[0] = '+' - emitter.open_ended = true - } - } - } - if chomp_hint[0] != 0 { - if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { - return false - } - } - return true -} - -func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - breaks := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - breaks = false - } - } - - return true -} - -func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - - breaks := true - leading_spaces := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !breaks && !leading_spaces && value[i] == '\n' { - k := 0 - for is_break(value, k) { - k += width(value[k]) - } - if !is_blankz(value, k) { - if !put_break(emitter) { - return false - } - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - leading_spaces = is_blank(value, i) - } - if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - emitter.indention = false - breaks = false - } - } - return true -} diff --git a/vendor/gopkg.in/yaml.v2/encode.go b/vendor/gopkg.in/yaml.v2/encode.go deleted file mode 100644 index a14435e..0000000 --- a/vendor/gopkg.in/yaml.v2/encode.go +++ /dev/null @@ -1,362 +0,0 @@ -package yaml - -import ( - "encoding" - "fmt" - "io" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -type encoder struct { - emitter yaml_emitter_t - event yaml_event_t - out []byte - flow bool - // doneInit holds whether the initial stream_start_event has been - // emitted. - doneInit bool -} - -func newEncoder() *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_string(&e.emitter, &e.out) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func newEncoderWithWriter(w io.Writer) *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_writer(&e.emitter, w) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func (e *encoder) init() { - if e.doneInit { - return - } - yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) - e.emit() - e.doneInit = true -} - -func (e *encoder) finish() { - e.emitter.open_ended = false - yaml_stream_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) destroy() { - yaml_emitter_delete(&e.emitter) -} - -func (e *encoder) emit() { - // This will internally delete the e.event value. - e.must(yaml_emitter_emit(&e.emitter, &e.event)) -} - -func (e *encoder) must(ok bool) { - if !ok { - msg := e.emitter.problem - if msg == "" { - msg = "unknown problem generating YAML content" - } - failf("%s", msg) - } -} - -func (e *encoder) marshalDoc(tag string, in reflect.Value) { - e.init() - yaml_document_start_event_initialize(&e.event, nil, nil, true) - e.emit() - e.marshal(tag, in) - yaml_document_end_event_initialize(&e.event, true) - e.emit() -} - -func (e *encoder) marshal(tag string, in reflect.Value) { - if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { - e.nilv() - return - } - iface := in.Interface() - switch m := iface.(type) { - case time.Time, *time.Time: - // Although time.Time implements TextMarshaler, - // we don't want to treat it as a string for YAML - // purposes because YAML has special support for - // timestamps. - case Marshaler: - v, err := m.MarshalYAML() - if err != nil { - fail(err) - } - if v == nil { - e.nilv() - return - } - in = reflect.ValueOf(v) - case encoding.TextMarshaler: - text, err := m.MarshalText() - if err != nil { - fail(err) - } - in = reflect.ValueOf(string(text)) - case nil: - e.nilv() - return - } - switch in.Kind() { - case reflect.Interface: - e.marshal(tag, in.Elem()) - case reflect.Map: - e.mapv(tag, in) - case reflect.Ptr: - if in.Type() == ptrTimeType { - e.timev(tag, in.Elem()) - } else { - e.marshal(tag, in.Elem()) - } - case reflect.Struct: - if in.Type() == timeType { - e.timev(tag, in) - } else { - e.structv(tag, in) - } - case reflect.Slice, reflect.Array: - if in.Type().Elem() == mapItemType { - e.itemsv(tag, in) - } else { - e.slicev(tag, in) - } - case reflect.String: - e.stringv(tag, in) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if in.Type() == durationType { - e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) - } else { - e.intv(tag, in) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - e.uintv(tag, in) - case reflect.Float32, reflect.Float64: - e.floatv(tag, in) - case reflect.Bool: - e.boolv(tag, in) - default: - panic("cannot marshal type: " + in.Type().String()) - } -} - -func (e *encoder) mapv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - keys := keyList(in.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - e.marshal("", k) - e.marshal("", in.MapIndex(k)) - } - }) -} - -func (e *encoder) itemsv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) - for _, item := range slice { - e.marshal("", reflect.ValueOf(item.Key)) - e.marshal("", reflect.ValueOf(item.Value)) - } - }) -} - -func (e *encoder) structv(tag string, in reflect.Value) { - sinfo, err := getStructInfo(in.Type()) - if err != nil { - panic(err) - } - e.mappingv(tag, func() { - for _, info := range sinfo.FieldsList { - var value reflect.Value - if info.Inline == nil { - value = in.Field(info.Num) - } else { - value = in.FieldByIndex(info.Inline) - } - if info.OmitEmpty && isZero(value) { - continue - } - e.marshal("", reflect.ValueOf(info.Key)) - e.flow = info.Flow - e.marshal("", value) - } - if sinfo.InlineMap >= 0 { - m := in.Field(sinfo.InlineMap) - if m.Len() > 0 { - e.flow = false - keys := keyList(m.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - if _, found := sinfo.FieldsMap[k.String()]; found { - panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) - } - e.marshal("", k) - e.flow = false - e.marshal("", m.MapIndex(k)) - } - } - } - }) -} - -func (e *encoder) mappingv(tag string, f func()) { - implicit := tag == "" - style := yaml_BLOCK_MAPPING_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_MAPPING_STYLE - } - yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) - e.emit() - f() - yaml_mapping_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) slicev(tag string, in reflect.Value) { - implicit := tag == "" - style := yaml_BLOCK_SEQUENCE_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_SEQUENCE_STYLE - } - e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) - e.emit() - n := in.Len() - for i := 0; i < n; i++ { - e.marshal("", in.Index(i)) - } - e.must(yaml_sequence_end_event_initialize(&e.event)) - e.emit() -} - -// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. -// -// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported -// in YAML 1.2 and by this package, but these should be marshalled quoted for -// the time being for compatibility with other parsers. -func isBase60Float(s string) (result bool) { - // Fast path. - if s == "" { - return false - } - c := s[0] - if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { - return false - } - // Do the full match. - return base60float.MatchString(s) -} - -// From http://yaml.org/type/float.html, except the regular expression there -// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. -var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) - -func (e *encoder) stringv(tag string, in reflect.Value) { - var style yaml_scalar_style_t - s := in.String() - canUsePlain := true - switch { - case !utf8.ValidString(s): - if tag == yaml_BINARY_TAG { - failf("explicitly tagged !!binary data must be base64-encoded") - } - if tag != "" { - failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) - } - // It can't be encoded directly as YAML so use a binary tag - // and encode it as base64. - tag = yaml_BINARY_TAG - s = encodeBase64(s) - case tag == "": - // Check to see if it would resolve to a specific - // tag when encoded unquoted. If it doesn't, - // there's no need to quote it. - rtag, _ := resolve("", s) - canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) - } - // Note: it's possible for user code to emit invalid YAML - // if they explicitly specify a tag and a string containing - // text that's incompatible with that tag. - switch { - case strings.Contains(s, "\n"): - style = yaml_LITERAL_SCALAR_STYLE - case canUsePlain: - style = yaml_PLAIN_SCALAR_STYLE - default: - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - e.emitScalar(s, "", tag, style) -} - -func (e *encoder) boolv(tag string, in reflect.Value) { - var s string - if in.Bool() { - s = "true" - } else { - s = "false" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) intv(tag string, in reflect.Value) { - s := strconv.FormatInt(in.Int(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) uintv(tag string, in reflect.Value) { - s := strconv.FormatUint(in.Uint(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) timev(tag string, in reflect.Value) { - t := in.Interface().(time.Time) - s := t.Format(time.RFC3339Nano) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) floatv(tag string, in reflect.Value) { - // Issue #352: When formatting, use the precision of the underlying value - precision := 64 - if in.Kind() == reflect.Float32 { - precision = 32 - } - - s := strconv.FormatFloat(in.Float(), 'g', -1, precision) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) nilv() { - e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { - implicit := tag == "" - e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) - e.emit() -} diff --git a/vendor/gopkg.in/yaml.v2/go.mod b/vendor/gopkg.in/yaml.v2/go.mod deleted file mode 100644 index 1934e87..0000000 --- a/vendor/gopkg.in/yaml.v2/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module "gopkg.in/yaml.v2" - -require ( - "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 -) diff --git a/vendor/gopkg.in/yaml.v2/parserc.go b/vendor/gopkg.in/yaml.v2/parserc.go deleted file mode 100644 index 81d05df..0000000 --- a/vendor/gopkg.in/yaml.v2/parserc.go +++ /dev/null @@ -1,1095 +0,0 @@ -package yaml - -import ( - "bytes" -) - -// The parser implements the following grammar: -// -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// implicit_document ::= block_node DOCUMENT-END* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// block_node_or_indentless_sequence ::= -// ALIAS -// | properties (block_content | indentless_block_sequence)? -// | block_content -// | indentless_block_sequence -// block_node ::= ALIAS -// | properties block_content? -// | block_content -// flow_node ::= ALIAS -// | properties flow_content? -// | flow_content -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// block_content ::= block_collection | flow_collection | SCALAR -// flow_content ::= flow_collection | SCALAR -// block_collection ::= block_sequence | block_mapping -// flow_collection ::= flow_sequence | flow_mapping -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// block_mapping ::= BLOCK-MAPPING_START -// ((KEY block_node_or_indentless_sequence?)? -// (VALUE block_node_or_indentless_sequence?)?)* -// BLOCK-END -// flow_sequence ::= FLOW-SEQUENCE-START -// (flow_sequence_entry FLOW-ENTRY)* -// flow_sequence_entry? -// FLOW-SEQUENCE-END -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// flow_mapping ::= FLOW-MAPPING-START -// (flow_mapping_entry FLOW-ENTRY)* -// flow_mapping_entry? -// FLOW-MAPPING-END -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - -// Peek the next token in the token queue. -func peek_token(parser *yaml_parser_t) *yaml_token_t { - if parser.token_available || yaml_parser_fetch_more_tokens(parser) { - return &parser.tokens[parser.tokens_head] - } - return nil -} - -// Remove the next token from the queue (must be called after peek_token). -func skip_token(parser *yaml_parser_t) { - parser.token_available = false - parser.tokens_parsed++ - parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN - parser.tokens_head++ -} - -// Get the next event. -func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { - // Erase the event object. - *event = yaml_event_t{} - - // No events after the end of the stream or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { - return true - } - - // Generate the next event. - return yaml_parser_state_machine(parser, event) -} - -// Set parser error. -func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -// State dispatcher. -func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { - //trace("yaml_parser_state_machine", "state:", parser.state.String()) - - switch parser.state { - case yaml_PARSE_STREAM_START_STATE: - return yaml_parser_parse_stream_start(parser, event) - - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, true) - - case yaml_PARSE_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, false) - - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return yaml_parser_parse_document_content(parser, event) - - case yaml_PARSE_DOCUMENT_END_STATE: - return yaml_parser_parse_document_end(parser, event) - - case yaml_PARSE_BLOCK_NODE_STATE: - return yaml_parser_parse_node(parser, event, true, false) - - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return yaml_parser_parse_node(parser, event, true, true) - - case yaml_PARSE_FLOW_NODE_STATE: - return yaml_parser_parse_node(parser, event, false, false) - - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, true) - - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, false) - - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_indentless_sequence_entry(parser, event) - - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, true) - - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, false) - - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return yaml_parser_parse_block_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, true) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, false) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) - - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, true) - - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, true) - - default: - panic("invalid parser state") - } -} - -// Parse the production: -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ -func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_STREAM_START_TOKEN { - return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) - } - parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - encoding: token.encoding, - } - skip_token(parser) - return true -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// * -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* -func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { - - token := peek_token(parser) - if token == nil { - return false - } - - // Parse extra document end indicators. - if !implicit { - for token.typ == yaml_DOCUMENT_END_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && - token.typ != yaml_TAG_DIRECTIVE_TOKEN && - token.typ != yaml_DOCUMENT_START_TOKEN && - token.typ != yaml_STREAM_END_TOKEN { - // Parse an implicit document. - if !yaml_parser_process_directives(parser, nil, nil) { - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_BLOCK_NODE_STATE - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - } else if token.typ != yaml_STREAM_END_TOKEN { - // Parse an explicit document. - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - start_mark := token.start_mark - if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { - return false - } - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_DOCUMENT_START_TOKEN { - yaml_parser_set_parser_error(parser, - "did not find expected ", token.start_mark) - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE - end_mark := token.end_mark - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: false, - } - skip_token(parser) - - } else { - // Parse the stream end. - parser.state = yaml_PARSE_END_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - } - - return true -} - -// Parse the productions: -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** -// -func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || - token.typ == yaml_TAG_DIRECTIVE_TOKEN || - token.typ == yaml_DOCUMENT_START_TOKEN || - token.typ == yaml_DOCUMENT_END_TOKEN || - token.typ == yaml_STREAM_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - return yaml_parser_process_empty_scalar(parser, event, - token.start_mark) - } - return yaml_parser_parse_node(parser, event, true, false) -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// -func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - start_mark := token.start_mark - end_mark := token.start_mark - - implicit := true - if token.typ == yaml_DOCUMENT_END_TOKEN { - end_mark = token.end_mark - skip_token(parser) - implicit = false - } - - parser.tag_directives = parser.tag_directives[:0] - - parser.state = yaml_PARSE_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - start_mark: start_mark, - end_mark: end_mark, - implicit: implicit, - } - return true -} - -// Parse the productions: -// block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * -// block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * -// flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* -// block_content ::= block_collection | flow_collection | SCALAR -// ****** -// flow_content ::= flow_collection | SCALAR -// ****** -func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { - //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_ALIAS_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - *event = yaml_event_t{ - typ: yaml_ALIAS_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - anchor: token.value, - } - skip_token(parser) - return true - } - - start_mark := token.start_mark - end_mark := token.start_mark - - var tag_token bool - var tag_handle, tag_suffix, anchor []byte - var tag_mark yaml_mark_t - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - start_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } else if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - start_mark = token.start_mark - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - var tag []byte - if tag_token { - if len(tag_handle) == 0 { - tag = tag_suffix - tag_suffix = nil - } else { - for i := range parser.tag_directives { - if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { - tag = append([]byte(nil), parser.tag_directives[i].prefix...) - tag = append(tag, tag_suffix...) - break - } - } - if len(tag) == 0 { - yaml_parser_set_parser_error_context(parser, - "while parsing a node", start_mark, - "found undefined tag handle", tag_mark) - return false - } - } - } - - implicit := len(tag) == 0 - if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_SCALAR_TOKEN { - var plain_implicit, quoted_implicit bool - end_mark = token.end_mark - if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { - plain_implicit = true - } else if len(tag) == 0 { - quoted_implicit = true - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - value: token.value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(token.style), - } - skip_token(parser) - return true - } - if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { - // [Go] Some of the events below can be merged as they differ only on style. - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_FLOW_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), - } - return true - } - if len(anchor) > 0 || len(tag) > 0 { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - quoted_implicit: false, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true - } - - context := "while parsing a flow node" - if block { - context = "while parsing a block node" - } - yaml_parser_set_parser_error_context(parser, context, start_mark, - "did not find expected node content", token.start_mark) - return false -} - -// Parse the productions: -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* -// -func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } else { - parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } - if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block collection", context_mark, - "did not find expected '-' indicator", token.start_mark) -} - -// Parse the productions: -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * -func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && - token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? - } - return true -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* -// -// BLOCK-END -// ********* -// -func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_KEY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } else { - parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } else if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block mapping", context_mark, - "did not find expected key", token.start_mark) -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// -// -func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow sequence", context_mark, - "did not find expected ',' or ']'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - implicit: true, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - skip_token(parser) - return true - } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true -} - -// -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - mark := token.end_mark - skip_token(parser) - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? - } - return true -} - -// Parse the productions: -// flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * -// -func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow mapping", context_mark, - "did not find expected ',' or '}'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } else { - parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true -} - -// Parse the productions: -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// -func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { - token := peek_token(parser) - if token == nil { - return false - } - if empty { - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Generate an empty scalar event. -func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: mark, - end_mark: mark, - value: nil, // Empty - implicit: true, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true -} - -var default_tag_directives = []yaml_tag_directive_t{ - {[]byte("!"), []byte("!")}, - {[]byte("!!"), []byte("tag:yaml.org,2002:")}, -} - -// Parse directives. -func yaml_parser_process_directives(parser *yaml_parser_t, - version_directive_ref **yaml_version_directive_t, - tag_directives_ref *[]yaml_tag_directive_t) bool { - - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - - token := peek_token(parser) - if token == nil { - return false - } - - for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { - if version_directive != nil { - yaml_parser_set_parser_error(parser, - "found duplicate %YAML directive", token.start_mark) - return false - } - if token.major != 1 || token.minor != 1 { - yaml_parser_set_parser_error(parser, - "found incompatible YAML document", token.start_mark) - return false - } - version_directive = &yaml_version_directive_t{ - major: token.major, - minor: token.minor, - } - } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { - value := yaml_tag_directive_t{ - handle: token.value, - prefix: token.prefix, - } - if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { - return false - } - tag_directives = append(tag_directives, value) - } - - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - - for i := range default_tag_directives { - if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { - return false - } - } - - if version_directive_ref != nil { - *version_directive_ref = version_directive - } - if tag_directives_ref != nil { - *tag_directives_ref = tag_directives - } - return true -} - -// Append a tag directive to the directives stack. -func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { - for i := range parser.tag_directives { - if bytes.Equal(value.handle, parser.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) - } - } - - // [Go] I suspect the copy is unnecessary. This was likely done - // because there was no way to track ownership of the data. - value_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(value_copy.handle, value.handle) - copy(value_copy.prefix, value.prefix) - parser.tag_directives = append(parser.tag_directives, value_copy) - return true -} diff --git a/vendor/gopkg.in/yaml.v2/readerc.go b/vendor/gopkg.in/yaml.v2/readerc.go deleted file mode 100644 index 7c1f5fa..0000000 --- a/vendor/gopkg.in/yaml.v2/readerc.go +++ /dev/null @@ -1,412 +0,0 @@ -package yaml - -import ( - "io" -) - -// Set the reader error and return 0. -func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { - parser.error = yaml_READER_ERROR - parser.problem = problem - parser.problem_offset = offset - parser.problem_value = value - return false -} - -// Byte order marks. -const ( - bom_UTF8 = "\xef\xbb\xbf" - bom_UTF16LE = "\xff\xfe" - bom_UTF16BE = "\xfe\xff" -) - -// Determine the input stream encoding by checking the BOM symbol. If no BOM is -// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. -func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { - // Ensure that we had enough bytes in the raw buffer. - for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { - if !yaml_parser_update_raw_buffer(parser) { - return false - } - } - - // Determine the encoding. - buf := parser.raw_buffer - pos := parser.raw_buffer_pos - avail := len(buf) - pos - if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { - parser.encoding = yaml_UTF16LE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { - parser.encoding = yaml_UTF16BE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { - parser.encoding = yaml_UTF8_ENCODING - parser.raw_buffer_pos += 3 - parser.offset += 3 - } else { - parser.encoding = yaml_UTF8_ENCODING - } - return true -} - -// Update the raw buffer. -func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { - size_read := 0 - - // Return if the raw buffer is full. - if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { - return true - } - - // Return on EOF. - if parser.eof { - return true - } - - // Move the remaining bytes in the raw buffer to the beginning. - if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { - copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) - } - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] - parser.raw_buffer_pos = 0 - - // Call the read handler to fill the buffer. - size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] - if err == io.EOF { - parser.eof = true - } else if err != nil { - return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) - } - return true -} - -// Ensure that the buffer contains at least `length` characters. -// Return true on success, false on failure. -// -// The length is supposed to be significantly less that the buffer size. -func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { - if parser.read_handler == nil { - panic("read handler must be set") - } - - // [Go] This function was changed to guarantee the requested length size at EOF. - // The fact we need to do this is pretty awful, but the description above implies - // for that to be the case, and there are tests - - // If the EOF flag is set and the raw buffer is empty, do nothing. - if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { - // [Go] ACTUALLY! Read the documentation of this function above. - // This is just broken. To return true, we need to have the - // given length in the buffer. Not doing that means every single - // check that calls this function to make sure the buffer has a - // given length is Go) panicking; or C) accessing invalid memory. - //return true - } - - // Return if the buffer contains enough characters. - if parser.unread >= length { - return true - } - - // Determine the input encoding if it is not known yet. - if parser.encoding == yaml_ANY_ENCODING { - if !yaml_parser_determine_encoding(parser) { - return false - } - } - - // Move the unread characters to the beginning of the buffer. - buffer_len := len(parser.buffer) - if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { - copy(parser.buffer, parser.buffer[parser.buffer_pos:]) - buffer_len -= parser.buffer_pos - parser.buffer_pos = 0 - } else if parser.buffer_pos == buffer_len { - buffer_len = 0 - parser.buffer_pos = 0 - } - - // Open the whole buffer for writing, and cut it before returning. - parser.buffer = parser.buffer[:cap(parser.buffer)] - - // Fill the buffer until it has enough characters. - first := true - for parser.unread < length { - - // Fill the raw buffer if necessary. - if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { - if !yaml_parser_update_raw_buffer(parser) { - parser.buffer = parser.buffer[:buffer_len] - return false - } - } - first = false - - // Decode the raw buffer. - inner: - for parser.raw_buffer_pos != len(parser.raw_buffer) { - var value rune - var width int - - raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos - - // Decode the next character. - switch parser.encoding { - case yaml_UTF8_ENCODING: - // Decode a UTF-8 character. Check RFC 3629 - // (http://www.ietf.org/rfc/rfc3629.txt) for more details. - // - // The following table (taken from the RFC) is used for - // decoding. - // - // Char. number range | UTF-8 octet sequence - // (hexadecimal) | (binary) - // --------------------+------------------------------------ - // 0000 0000-0000 007F | 0xxxxxxx - // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // - // Additionally, the characters in the range 0xD800-0xDFFF - // are prohibited as they are reserved for use with UTF-16 - // surrogate pairs. - - // Determine the length of the UTF-8 sequence. - octet := parser.raw_buffer[parser.raw_buffer_pos] - switch { - case octet&0x80 == 0x00: - width = 1 - case octet&0xE0 == 0xC0: - width = 2 - case octet&0xF0 == 0xE0: - width = 3 - case octet&0xF8 == 0xF0: - width = 4 - default: - // The leading octet is invalid. - return yaml_parser_set_reader_error(parser, - "invalid leading UTF-8 octet", - parser.offset, int(octet)) - } - - // Check if the raw buffer contains an incomplete character. - if width > raw_unread { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-8 octet sequence", - parser.offset, -1) - } - break inner - } - - // Decode the leading octet. - switch { - case octet&0x80 == 0x00: - value = rune(octet & 0x7F) - case octet&0xE0 == 0xC0: - value = rune(octet & 0x1F) - case octet&0xF0 == 0xE0: - value = rune(octet & 0x0F) - case octet&0xF8 == 0xF0: - value = rune(octet & 0x07) - default: - value = 0 - } - - // Check and decode the trailing octets. - for k := 1; k < width; k++ { - octet = parser.raw_buffer[parser.raw_buffer_pos+k] - - // Check if the octet is valid. - if (octet & 0xC0) != 0x80 { - return yaml_parser_set_reader_error(parser, - "invalid trailing UTF-8 octet", - parser.offset+k, int(octet)) - } - - // Decode the octet. - value = (value << 6) + rune(octet&0x3F) - } - - // Check the length of the sequence against the value. - switch { - case width == 1: - case width == 2 && value >= 0x80: - case width == 3 && value >= 0x800: - case width == 4 && value >= 0x10000: - default: - return yaml_parser_set_reader_error(parser, - "invalid length of a UTF-8 sequence", - parser.offset, -1) - } - - // Check the range of the value. - if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { - return yaml_parser_set_reader_error(parser, - "invalid Unicode character", - parser.offset, int(value)) - } - - case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: - var low, high int - if parser.encoding == yaml_UTF16LE_ENCODING { - low, high = 0, 1 - } else { - low, high = 1, 0 - } - - // The UTF-16 encoding is not as simple as one might - // naively think. Check RFC 2781 - // (http://www.ietf.org/rfc/rfc2781.txt). - // - // Normally, two subsequent bytes describe a Unicode - // character. However a special technique (called a - // surrogate pair) is used for specifying character - // values larger than 0xFFFF. - // - // A surrogate pair consists of two pseudo-characters: - // high surrogate area (0xD800-0xDBFF) - // low surrogate area (0xDC00-0xDFFF) - // - // The following formulas are used for decoding - // and encoding characters using surrogate pairs: - // - // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) - // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) - // W1 = 110110yyyyyyyyyy - // W2 = 110111xxxxxxxxxx - // - // where U is the character value, W1 is the high surrogate - // area, W2 is the low surrogate area. - - // Check for incomplete UTF-16 character. - if raw_unread < 2 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 character", - parser.offset, -1) - } - break inner - } - - // Get the character. - value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) - - // Check for unexpected low surrogate area. - if value&0xFC00 == 0xDC00 { - return yaml_parser_set_reader_error(parser, - "unexpected low surrogate area", - parser.offset, int(value)) - } - - // Check for a high surrogate area. - if value&0xFC00 == 0xD800 { - width = 4 - - // Check for incomplete surrogate pair. - if raw_unread < 4 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 surrogate pair", - parser.offset, -1) - } - break inner - } - - // Get the next character. - value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) - - // Check for a low surrogate area. - if value2&0xFC00 != 0xDC00 { - return yaml_parser_set_reader_error(parser, - "expected low surrogate area", - parser.offset+2, int(value2)) - } - - // Generate the value of the surrogate pair. - value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) - } else { - width = 2 - } - - default: - panic("impossible") - } - - // Check if the character is in the allowed range: - // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) - // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) - // | [#x10000-#x10FFFF] (32 bit) - switch { - case value == 0x09: - case value == 0x0A: - case value == 0x0D: - case value >= 0x20 && value <= 0x7E: - case value == 0x85: - case value >= 0xA0 && value <= 0xD7FF: - case value >= 0xE000 && value <= 0xFFFD: - case value >= 0x10000 && value <= 0x10FFFF: - default: - return yaml_parser_set_reader_error(parser, - "control characters are not allowed", - parser.offset, int(value)) - } - - // Move the raw pointers. - parser.raw_buffer_pos += width - parser.offset += width - - // Finally put the character into the buffer. - if value <= 0x7F { - // 0000 0000-0000 007F . 0xxxxxxx - parser.buffer[buffer_len+0] = byte(value) - buffer_len += 1 - } else if value <= 0x7FF { - // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) - parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) - buffer_len += 2 - } else if value <= 0xFFFF { - // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) - buffer_len += 3 - } else { - // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) - buffer_len += 4 - } - - parser.unread++ - } - - // On EOF, put NUL into the buffer and return. - if parser.eof { - parser.buffer[buffer_len] = 0 - buffer_len++ - parser.unread++ - break - } - } - // [Go] Read the documentation of this function above. To return true, - // we need to have the given length in the buffer. Not doing that means - // every single check that calls this function to make sure the buffer - // has a given length is Go) panicking; or C) accessing invalid memory. - // This happens here due to the EOF above breaking early. - for buffer_len < length { - parser.buffer[buffer_len] = 0 - buffer_len++ - } - parser.buffer = parser.buffer[:buffer_len] - return true -} diff --git a/vendor/gopkg.in/yaml.v2/resolve.go b/vendor/gopkg.in/yaml.v2/resolve.go deleted file mode 100644 index 6c151db..0000000 --- a/vendor/gopkg.in/yaml.v2/resolve.go +++ /dev/null @@ -1,258 +0,0 @@ -package yaml - -import ( - "encoding/base64" - "math" - "regexp" - "strconv" - "strings" - "time" -) - -type resolveMapItem struct { - value interface{} - tag string -} - -var resolveTable = make([]byte, 256) -var resolveMap = make(map[string]resolveMapItem) - -func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, - {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, - {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, - {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, - {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, - {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, - {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, - {"<<", yaml_MERGE_TAG, []string{"<<"}}, - } - - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } -} - -const longTagPrefix = "tag:yaml.org,2002:" - -func shortTag(tag string) string { - // TODO This can easily be made faster and produce less garbage. - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag -} - -func longTag(tag string) string { - if strings.HasPrefix(tag, "!!") { - return longTagPrefix + tag[2:] - } - return tag -} - -func resolvableTag(tag string) bool { - switch tag { - case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: - return true - } - return false -} - -var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`) - -func resolve(tag string, in string) (rtag string, out interface{}) { - if !resolvableTag(tag) { - return tag, in - } - - defer func() { - switch tag { - case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: - return - case yaml_FLOAT_TAG: - if rtag == yaml_INT_TAG { - switch v := out.(type) { - case int64: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - case int: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - } - } - } - failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) - }() - - // Any data is accepted as a !!str or !!binary. - // Otherwise, the prefix is enough of a hint about what it might be. - hint := byte('N') - if in != "" { - hint = resolveTable[in[0]] - } - if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } - - // Base 60 floats are a bad idea, were dropped in YAML 1.2, and - // are purposefully unsupported here. They're still quoted on - // the way out for compatibility with other parser, though. - - switch hint { - case 'M': - // We've already checked the map above. - - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.ParseFloat(in, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - - case 'D', 'S': - // Int, float, or timestamp. - // Only try values as a timestamp if the value is unquoted or there's an explicit - // !!timestamp tag. - if tag == "" || tag == yaml_TIMESTAMP_TAG { - t, ok := parseTimestamp(in) - if ok { - return yaml_TIMESTAMP_TAG, t - } - } - - plain := strings.Replace(in, "_", "", -1) - intv, err := strconv.ParseInt(plain, 0, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain, 0, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - if yamlStyleFloat.MatchString(plain) { - floatv, err := strconv.ParseFloat(plain, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - } - if strings.HasPrefix(plain, "0b") { - intv, err := strconv.ParseInt(plain[2:], 2, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain[2:], 2, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) - if err == nil { - if true || intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - } - default: - panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") - } - } - return yaml_STR_TAG, in -} - -// encodeBase64 encodes s as base64 that is broken up into multiple lines -// as appropriate for the resulting length. -func encodeBase64(s string) string { - const lineLen = 70 - encLen := base64.StdEncoding.EncodedLen(len(s)) - lines := encLen/lineLen + 1 - buf := make([]byte, encLen*2+lines) - in := buf[0:encLen] - out := buf[encLen:] - base64.StdEncoding.Encode(in, []byte(s)) - k := 0 - for i := 0; i < len(in); i += lineLen { - j := i + lineLen - if j > len(in) { - j = len(in) - } - k += copy(out[k:], in[i:j]) - if lines > 1 { - out[k] = '\n' - k++ - } - } - return string(out[:k]) -} - -// This is a subset of the formats allowed by the regular expression -// defined at http://yaml.org/type/timestamp.html. -var allowedTimestampFormats = []string{ - "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. - "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". - "2006-1-2 15:4:5.999999999", // space separated with no time zone - "2006-1-2", // date only - // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" - // from the set of examples. -} - -// parseTimestamp parses s as a timestamp string and -// returns the timestamp and reports whether it succeeded. -// Timestamp formats are defined at http://yaml.org/type/timestamp.html -func parseTimestamp(s string) (time.Time, bool) { - // TODO write code to check all the formats supported by - // http://yaml.org/type/timestamp.html instead of using time.Parse. - - // Quick check: all date formats start with YYYY-. - i := 0 - for ; i < len(s); i++ { - if c := s[i]; c < '0' || c > '9' { - break - } - } - if i != 4 || i == len(s) || s[i] != '-' { - return time.Time{}, false - } - for _, format := range allowedTimestampFormats { - if t, err := time.Parse(format, s); err == nil { - return t, true - } - } - return time.Time{}, false -} diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go deleted file mode 100644 index 077fd1d..0000000 --- a/vendor/gopkg.in/yaml.v2/scannerc.go +++ /dev/null @@ -1,2696 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Introduction -// ************ -// -// The following notes assume that you are familiar with the YAML specification -// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in -// some cases we are less restrictive that it requires. -// -// The process of transforming a YAML stream into a sequence of events is -// divided on two steps: Scanning and Parsing. -// -// The Scanner transforms the input stream into a sequence of tokens, while the -// parser transform the sequence of tokens produced by the Scanner into a -// sequence of parsing events. -// -// The Scanner is rather clever and complicated. The Parser, on the contrary, -// is a straightforward implementation of a recursive-descendant parser (or, -// LL(1) parser, as it is usually called). -// -// Actually there are two issues of Scanning that might be called "clever", the -// rest is quite straightforward. The issues are "block collection start" and -// "simple keys". Both issues are explained below in details. -// -// Here the Scanning step is explained and implemented. We start with the list -// of all the tokens produced by the Scanner together with short descriptions. -// -// Now, tokens: -// -// STREAM-START(encoding) # The stream start. -// STREAM-END # The stream end. -// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. -// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. -// DOCUMENT-START # '---' -// DOCUMENT-END # '...' -// BLOCK-SEQUENCE-START # Indentation increase denoting a block -// BLOCK-MAPPING-START # sequence or a block mapping. -// BLOCK-END # Indentation decrease. -// FLOW-SEQUENCE-START # '[' -// FLOW-SEQUENCE-END # ']' -// BLOCK-SEQUENCE-START # '{' -// BLOCK-SEQUENCE-END # '}' -// BLOCK-ENTRY # '-' -// FLOW-ENTRY # ',' -// KEY # '?' or nothing (simple keys). -// VALUE # ':' -// ALIAS(anchor) # '*anchor' -// ANCHOR(anchor) # '&anchor' -// TAG(handle,suffix) # '!handle!suffix' -// SCALAR(value,style) # A scalar. -// -// The following two tokens are "virtual" tokens denoting the beginning and the -// end of the stream: -// -// STREAM-START(encoding) -// STREAM-END -// -// We pass the information about the input stream encoding with the -// STREAM-START token. -// -// The next two tokens are responsible for tags: -// -// VERSION-DIRECTIVE(major,minor) -// TAG-DIRECTIVE(handle,prefix) -// -// Example: -// -// %YAML 1.1 -// %TAG ! !foo -// %TAG !yaml! tag:yaml.org,2002: -// --- -// -// The correspoding sequence of tokens: -// -// STREAM-START(utf-8) -// VERSION-DIRECTIVE(1,1) -// TAG-DIRECTIVE("!","!foo") -// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") -// DOCUMENT-START -// STREAM-END -// -// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole -// line. -// -// The document start and end indicators are represented by: -// -// DOCUMENT-START -// DOCUMENT-END -// -// Note that if a YAML stream contains an implicit document (without '---' -// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be -// produced. -// -// In the following examples, we present whole documents together with the -// produced tokens. -// -// 1. An implicit document: -// -// 'a scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// STREAM-END -// -// 2. An explicit document: -// -// --- -// 'a scalar' -// ... -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// SCALAR("a scalar",single-quoted) -// DOCUMENT-END -// STREAM-END -// -// 3. Several documents in a stream: -// -// 'a scalar' -// --- -// 'another scalar' -// --- -// 'yet another scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// DOCUMENT-START -// SCALAR("another scalar",single-quoted) -// DOCUMENT-START -// SCALAR("yet another scalar",single-quoted) -// STREAM-END -// -// We have already introduced the SCALAR token above. The following tokens are -// used to describe aliases, anchors, tag, and scalars: -// -// ALIAS(anchor) -// ANCHOR(anchor) -// TAG(handle,suffix) -// SCALAR(value,style) -// -// The following series of examples illustrate the usage of these tokens: -// -// 1. A recursive sequence: -// -// &A [ *A ] -// -// Tokens: -// -// STREAM-START(utf-8) -// ANCHOR("A") -// FLOW-SEQUENCE-START -// ALIAS("A") -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A tagged scalar: -// -// !!float "3.14" # A good approximation. -// -// Tokens: -// -// STREAM-START(utf-8) -// TAG("!!","float") -// SCALAR("3.14",double-quoted) -// STREAM-END -// -// 3. Various scalar styles: -// -// --- # Implicit empty plain scalars do not produce tokens. -// --- a plain scalar -// --- 'a single-quoted scalar' -// --- "a double-quoted scalar" -// --- |- -// a literal scalar -// --- >- -// a folded -// scalar -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// DOCUMENT-START -// SCALAR("a plain scalar",plain) -// DOCUMENT-START -// SCALAR("a single-quoted scalar",single-quoted) -// DOCUMENT-START -// SCALAR("a double-quoted scalar",double-quoted) -// DOCUMENT-START -// SCALAR("a literal scalar",literal) -// DOCUMENT-START -// SCALAR("a folded scalar",folded) -// STREAM-END -// -// Now it's time to review collection-related tokens. We will start with -// flow collections: -// -// FLOW-SEQUENCE-START -// FLOW-SEQUENCE-END -// FLOW-MAPPING-START -// FLOW-MAPPING-END -// FLOW-ENTRY -// KEY -// VALUE -// -// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and -// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' -// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the -// indicators '?' and ':', which are used for denoting mapping keys and values, -// are represented by the KEY and VALUE tokens. -// -// The following examples show flow collections: -// -// 1. A flow sequence: -// -// [item 1, item 2, item 3] -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-SEQUENCE-START -// SCALAR("item 1",plain) -// FLOW-ENTRY -// SCALAR("item 2",plain) -// FLOW-ENTRY -// SCALAR("item 3",plain) -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A flow mapping: -// -// { -// a simple key: a value, # Note that the KEY token is produced. -// ? a complex key: another value, -// } -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// FLOW-ENTRY -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// FLOW-ENTRY -// FLOW-MAPPING-END -// STREAM-END -// -// A simple key is a key which is not denoted by the '?' indicator. Note that -// the Scanner still produce the KEY token whenever it encounters a simple key. -// -// For scanning block collections, the following tokens are used (note that we -// repeat KEY and VALUE here): -// -// BLOCK-SEQUENCE-START -// BLOCK-MAPPING-START -// BLOCK-END -// BLOCK-ENTRY -// KEY -// VALUE -// -// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation -// increase that precedes a block collection (cf. the INDENT token in Python). -// The token BLOCK-END denote indentation decrease that ends a block collection -// (cf. the DEDENT token in Python). However YAML has some syntax pecularities -// that makes detections of these tokens more complex. -// -// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators -// '-', '?', and ':' correspondingly. -// -// The following examples show how the tokens BLOCK-SEQUENCE-START, -// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: -// -// 1. Block sequences: -// -// - item 1 -// - item 2 -// - -// - item 3.1 -// - item 3.2 -// - -// key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 3.1",plain) -// BLOCK-ENTRY -// SCALAR("item 3.2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Block mappings: -// -// a simple key: a value # The KEY token is produced here. -// ? a complex key -// : another value -// a mapping: -// key 1: value 1 -// key 2: value 2 -// a sequence: -// - item 1 -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// KEY -// SCALAR("a mapping",plain) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML does not always require to start a new block collection from a new -// line. If the current line contains only '-', '?', and ':' indicators, a new -// block collection may start at the current line. The following examples -// illustrate this case: -// -// 1. Collections in a sequence: -// -// - - item 1 -// - item 2 -// - key 1: value 1 -// key 2: value 2 -// - ? complex key -// : complex value -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("complex key") -// VALUE -// SCALAR("complex value") -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Collections in a mapping: -// -// ? a sequence -// : - item 1 -// - item 2 -// ? a mapping -// : key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// KEY -// SCALAR("a mapping",plain) -// VALUE -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML also permits non-indented sequences if they are included into a block -// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: -// -// key: -// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key",plain) -// VALUE -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// - -// Ensure that the buffer contains the required number of characters. -// Return true on success, false on failure (reader error or memory error). -func cache(parser *yaml_parser_t, length int) bool { - // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) - return parser.unread >= length || yaml_parser_update_buffer(parser, length) -} - -// Advance the buffer pointer. -func skip(parser *yaml_parser_t) { - parser.mark.index++ - parser.mark.column++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) -} - -func skip_line(parser *yaml_parser_t) { - if is_crlf(parser.buffer, parser.buffer_pos) { - parser.mark.index += 2 - parser.mark.column = 0 - parser.mark.line++ - parser.unread -= 2 - parser.buffer_pos += 2 - } else if is_break(parser.buffer, parser.buffer_pos) { - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) - } -} - -// Copy a character to a string buffer and advance pointers. -func read(parser *yaml_parser_t, s []byte) []byte { - w := width(parser.buffer[parser.buffer_pos]) - if w == 0 { - panic("invalid character sequence") - } - if len(s) == 0 { - s = make([]byte, 0, 32) - } - if w == 1 && len(s)+w <= cap(s) { - s = s[:len(s)+1] - s[len(s)-1] = parser.buffer[parser.buffer_pos] - parser.buffer_pos++ - } else { - s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) - parser.buffer_pos += w - } - parser.mark.index++ - parser.mark.column++ - parser.unread-- - return s -} - -// Copy a line break character to a string buffer and advance pointers. -func read_line(parser *yaml_parser_t, s []byte) []byte { - buf := parser.buffer - pos := parser.buffer_pos - switch { - case buf[pos] == '\r' && buf[pos+1] == '\n': - // CR LF . LF - s = append(s, '\n') - parser.buffer_pos += 2 - parser.mark.index++ - parser.unread-- - case buf[pos] == '\r' || buf[pos] == '\n': - // CR|LF . LF - s = append(s, '\n') - parser.buffer_pos += 1 - case buf[pos] == '\xC2' && buf[pos+1] == '\x85': - // NEL . LF - s = append(s, '\n') - parser.buffer_pos += 2 - case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): - // LS|PS . LS|PS - s = append(s, buf[parser.buffer_pos:pos+3]...) - parser.buffer_pos += 3 - default: - return s - } - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - return s -} - -// Get the next token. -func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { - // Erase the token object. - *token = yaml_token_t{} // [Go] Is this necessary? - - // No tokens after STREAM-END or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR { - return true - } - - // Ensure that the tokens queue contains enough tokens. - if !parser.token_available { - if !yaml_parser_fetch_more_tokens(parser) { - return false - } - } - - // Fetch the next token from the queue. - *token = parser.tokens[parser.tokens_head] - parser.tokens_head++ - parser.tokens_parsed++ - parser.token_available = false - - if token.typ == yaml_STREAM_END_TOKEN { - parser.stream_end_produced = true - } - return true -} - -// Set the scanner error and return false. -func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { - parser.error = yaml_SCANNER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = parser.mark - return false -} - -func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { - context := "while parsing a tag" - if directive { - context = "while parsing a %TAG directive" - } - return yaml_parser_set_scanner_error(parser, context, context_mark, problem) -} - -func trace(args ...interface{}) func() { - pargs := append([]interface{}{"+++"}, args...) - fmt.Println(pargs...) - pargs = append([]interface{}{"---"}, args...) - return func() { fmt.Println(pargs...) } -} - -// Ensure that the tokens queue contains at least one token which can be -// returned to the Parser. -func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { - // While we need more tokens to fetch, do it. - for { - // Check if we really need to fetch more tokens. - need_more_tokens := false - - if parser.tokens_head == len(parser.tokens) { - // Queue is empty. - need_more_tokens = true - } else { - // Check if any potential simple key may occupy the head position. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - if simple_key.possible && simple_key.token_number == parser.tokens_parsed { - need_more_tokens = true - break - } - } - } - - // We are finished. - if !need_more_tokens { - break - } - // Fetch the next token. - if !yaml_parser_fetch_next_token(parser) { - return false - } - } - - parser.token_available = true - return true -} - -// The dispatcher for token fetchers. -func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { - // Ensure that the buffer is initialized. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we just started scanning. Fetch STREAM-START then. - if !parser.stream_start_produced { - return yaml_parser_fetch_stream_start(parser) - } - - // Eat whitespaces and comments until we reach the next token. - if !yaml_parser_scan_to_next_token(parser) { - return false - } - - // Remove obsolete potential simple keys. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - // Check the indentation level against the current column. - if !yaml_parser_unroll_indent(parser, parser.mark.column) { - return false - } - - // Ensure that the buffer contains at least 4 characters. 4 is the length - // of the longest indicators ('--- ' and '... '). - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - // Is it the end of the stream? - if is_z(parser.buffer, parser.buffer_pos) { - return yaml_parser_fetch_stream_end(parser) - } - - // Is it a directive? - if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { - return yaml_parser_fetch_directive(parser) - } - - buf := parser.buffer - pos := parser.buffer_pos - - // Is it the document start indicator? - if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) - } - - // Is it the document end indicator? - if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) - } - - // Is it the flow sequence start indicator? - if buf[pos] == '[' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) - } - - // Is it the flow mapping start indicator? - if parser.buffer[parser.buffer_pos] == '{' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) - } - - // Is it the flow sequence end indicator? - if parser.buffer[parser.buffer_pos] == ']' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_SEQUENCE_END_TOKEN) - } - - // Is it the flow mapping end indicator? - if parser.buffer[parser.buffer_pos] == '}' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_MAPPING_END_TOKEN) - } - - // Is it the flow entry indicator? - if parser.buffer[parser.buffer_pos] == ',' { - return yaml_parser_fetch_flow_entry(parser) - } - - // Is it the block entry indicator? - if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { - return yaml_parser_fetch_block_entry(parser) - } - - // Is it the key indicator? - if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_key(parser) - } - - // Is it the value indicator? - if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_value(parser) - } - - // Is it an alias? - if parser.buffer[parser.buffer_pos] == '*' { - return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) - } - - // Is it an anchor? - if parser.buffer[parser.buffer_pos] == '&' { - return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) - } - - // Is it a tag? - if parser.buffer[parser.buffer_pos] == '!' { - return yaml_parser_fetch_tag(parser) - } - - // Is it a literal scalar? - if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, true) - } - - // Is it a folded scalar? - if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, false) - } - - // Is it a single-quoted scalar? - if parser.buffer[parser.buffer_pos] == '\'' { - return yaml_parser_fetch_flow_scalar(parser, true) - } - - // Is it a double-quoted scalar? - if parser.buffer[parser.buffer_pos] == '"' { - return yaml_parser_fetch_flow_scalar(parser, false) - } - - // Is it a plain scalar? - // - // A plain scalar may start with any non-blank characters except - // - // '-', '?', ':', ',', '[', ']', '{', '}', - // '#', '&', '*', '!', '|', '>', '\'', '\"', - // '%', '@', '`'. - // - // In the block context (and, for the '-' indicator, in the flow context - // too), it may also start with the characters - // - // '-', '?', ':' - // - // if it is followed by a non-space character. - // - // The last rule is more restrictive than the specification requires. - // [Go] Make this logic more reasonable. - //switch parser.buffer[parser.buffer_pos] { - //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': - //} - if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || - parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || - parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || - (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level == 0 && - (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && - !is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_plain_scalar(parser) - } - - // If we don't determine the token type so far, it is an error. - return yaml_parser_set_scanner_error(parser, - "while scanning for the next token", parser.mark, - "found character that cannot start any token") -} - -// Check the list of potential simple keys and remove the positions that -// cannot contain simple keys anymore. -func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool { - // Check for a potential simple key for each flow level. - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - - // The specification requires that a simple key - // - // - is limited to a single line, - // - is shorter than 1024 characters. - if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) { - - // Check if the potential simple key to be removed is required. - if simple_key.required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key.mark, - "could not find expected ':'") - } - simple_key.possible = false - } - } - return true -} - -// Check if a simple key may start at the current position and add it if -// needed. -func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { - // A simple key is required at the current position if the scanner is in - // the block context and the current column coincides with the indentation - // level. - - required := parser.flow_level == 0 && parser.indent == parser.mark.column - - // - // If the current position may start a simple key, save it. - // - if parser.simple_key_allowed { - simple_key := yaml_simple_key_t{ - possible: true, - required: required, - token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), - } - simple_key.mark = parser.mark - - if !yaml_parser_remove_simple_key(parser) { - return false - } - parser.simple_keys[len(parser.simple_keys)-1] = simple_key - } - return true -} - -// Remove a potential simple key at the current flow level. -func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { - i := len(parser.simple_keys) - 1 - if parser.simple_keys[i].possible { - // If the key is required, it is an error. - if parser.simple_keys[i].required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", parser.simple_keys[i].mark, - "could not find expected ':'") - } - } - // Remove the key from the stack. - parser.simple_keys[i].possible = false - return true -} - -// Increase the flow level and resize the simple key list if needed. -func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { - // Reset the simple key on the next level. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // Increase the flow level. - parser.flow_level++ - return true -} - -// Decrease the flow level. -func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { - if parser.flow_level > 0 { - parser.flow_level-- - parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1] - } - return true -} - -// Push the current indentation level to the stack and set the new level -// the current column is greater than the indentation level. In this case, -// append or insert the specified token into the token queue. -func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - if parser.indent < column { - // Push the current indentation level to the stack and set the new - // indentation level. - parser.indents = append(parser.indents, parser.indent) - parser.indent = column - - // Create a token and insert it into the queue. - token := yaml_token_t{ - typ: typ, - start_mark: mark, - end_mark: mark, - } - if number > -1 { - number -= parser.tokens_parsed - } - yaml_insert_token(parser, number, &token) - } - return true -} - -// Pop indentation levels from the indents stack until the current level -// becomes less or equal to the column. For each indentation level, append -// the BLOCK-END token. -func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - // Loop through the indentation levels in the stack. - for parser.indent > column { - // Create a token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - - // Pop the indentation level. - parser.indent = parser.indents[len(parser.indents)-1] - parser.indents = parser.indents[:len(parser.indents)-1] - } - return true -} - -// Initialize the scanner and produce the STREAM-START token. -func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { - - // Set the initial indentation. - parser.indent = -1 - - // Initialize the simple key stack. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // A simple key is allowed at the beginning of the stream. - parser.simple_key_allowed = true - - // We have started. - parser.stream_start_produced = true - - // Create the STREAM-START token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_START_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - encoding: parser.encoding, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the STREAM-END token and shut down the scanner. -func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { - - // Force new line. - if parser.mark.column != 0 { - parser.mark.column = 0 - parser.mark.line++ - } - - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the STREAM-END token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. -func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. - token := yaml_token_t{} - if !yaml_parser_scan_directive(parser, &token) { - return false - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the DOCUMENT-START or DOCUMENT-END token. -func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Consume the token. - start_mark := parser.mark - - skip(parser) - skip(parser) - skip(parser) - - end_mark := parser.mark - - // Create the DOCUMENT-START or DOCUMENT-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. -func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // The indicators '[' and '{' may start a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // Increase the flow level. - if !yaml_parser_increase_flow_level(parser) { - return false - } - - // A simple key may follow the indicators '[' and '{'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. -func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset any potential simple key on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Decrease the flow level. - if !yaml_parser_decrease_flow_level(parser) { - return false - } - - // No simple keys after the indicators ']' and '}'. - parser.simple_key_allowed = false - - // Consume the token. - - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-ENTRY token. -func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after ','. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_FLOW_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the BLOCK-ENTRY token. -func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { - // Check if the scanner is in the block context. - if parser.flow_level == 0 { - // Check if we are allowed to start a new entry. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "block sequence entries are not allowed in this context") - } - // Add the BLOCK-SEQUENCE-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { - return false - } - } else { - // It is an error for the '-' indicator to occur in the flow context, - // but we let the Parser detect and report about it because the Parser - // is able to point to the context. - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '-'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the BLOCK-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the KEY token. -func yaml_parser_fetch_key(parser *yaml_parser_t) bool { - - // In the block context, additional checks are required. - if parser.flow_level == 0 { - // Check if we are allowed to start a new key (not nessesary simple). - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping keys are not allowed in this context") - } - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '?' in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the KEY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the VALUE token. -func yaml_parser_fetch_value(parser *yaml_parser_t) bool { - - simple_key := &parser.simple_keys[len(parser.simple_keys)-1] - - // Have we found a simple key? - if simple_key.possible { - // Create the KEY token and insert it into the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: simple_key.mark, - end_mark: simple_key.mark, - } - yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) - - // In the block context, we may need to add the BLOCK-MAPPING-START token. - if !yaml_parser_roll_indent(parser, simple_key.mark.column, - simple_key.token_number, - yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { - return false - } - - // Remove the simple key. - simple_key.possible = false - - // A simple key cannot follow another simple key. - parser.simple_key_allowed = false - - } else { - // The ':' indicator follows a complex key. - - // In the block context, extra checks are required. - if parser.flow_level == 0 { - - // Check if we are allowed to start a complex value. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping values are not allowed in this context") - } - - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Simple keys after ':' are allowed in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - } - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the VALUE token and append it to the queue. - token := yaml_token_t{ - typ: yaml_VALUE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the ALIAS or ANCHOR token. -func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // An anchor or an alias could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow an anchor or an alias. - parser.simple_key_allowed = false - - // Create the ALIAS or ANCHOR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_anchor(parser, &token, typ) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the TAG token. -func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { - // A tag could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a tag. - parser.simple_key_allowed = false - - // Create the TAG token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_tag(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. -func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { - // Remove any potential simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // A simple key may follow a block scalar. - parser.simple_key_allowed = true - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_block_scalar(parser, &token, literal) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. -func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_flow_scalar(parser, &token, single) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,plain) token. -func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_plain_scalar(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Eat whitespaces and comments until the next token is found. -func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { - - // Until the next token is not found. - for { - // Allow the BOM mark to start a line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { - skip(parser) - } - - // Eat whitespaces. - // Tabs are allowed: - // - in the flow context - // - in the block context, but not at the beginning of the line or - // after '-', '?', or ':' (complex value). - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Eat a comment until a line break. - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // If it is a line break, eat it. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - - // In the block context, a new line may start a simple key. - if parser.flow_level == 0 { - parser.simple_key_allowed = true - } - } else { - break // We have found a token. - } - } - - return true -} - -// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { - // Eat '%'. - start_mark := parser.mark - skip(parser) - - // Scan the directive name. - var name []byte - if !yaml_parser_scan_directive_name(parser, start_mark, &name) { - return false - } - - // Is it a YAML directive? - if bytes.Equal(name, []byte("YAML")) { - // Scan the VERSION directive value. - var major, minor int8 - if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { - return false - } - end_mark := parser.mark - - // Create a VERSION-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_VERSION_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - major: major, - minor: minor, - } - - // Is it a TAG directive? - } else if bytes.Equal(name, []byte("TAG")) { - // Scan the TAG directive value. - var handle, prefix []byte - if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { - return false - } - end_mark := parser.mark - - // Create a TAG-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_TAG_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - prefix: prefix, - } - - // Unknown directive. - } else { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unknown directive name") - return false - } - - // Eat the rest of the line including any comments. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - return true -} - -// Scan the directive name. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ -// -func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { - // Consume the directive name. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - var s []byte - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the name is empty. - if len(s) == 0 { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "could not find expected directive name") - return false - } - - // Check for an blank character after the name. - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unexpected non-alphabetical character") - return false - } - *name = s - return true -} - -// Scan the value of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ -func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the major version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { - return false - } - - // Eat '.'. - if parser.buffer[parser.buffer_pos] != '.' { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected digit or '.' character") - } - - skip(parser) - - // Consume the minor version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { - return false - } - return true -} - -const max_number_length = 2 - -// Scan the version number of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ -func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { - - // Repeat while the next character is digit. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var value, length int8 - for is_digit(parser.buffer, parser.buffer_pos) { - // Check if the number is too long. - length++ - if length > max_number_length { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "found extremely long version number") - } - value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the number was present. - if length == 0 { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected version number") - } - *number = value - return true -} - -// Scan the value of a TAG-DIRECTIVE token. -// -// Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { - var handle_value, prefix_value []byte - - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a handle. - if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { - return false - } - - // Expect a whitespace. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blank(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace") - return false - } - - // Eat whitespaces. - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a prefix. - if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { - return false - } - - // Expect a whitespace or line break. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace or line break") - return false - } - - *handle = handle_value - *prefix = prefix_value - return true -} - -func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { - var s []byte - - // Eat the indicator character. - start_mark := parser.mark - skip(parser) - - // Consume the value. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - end_mark := parser.mark - - /* - * Check if length of the anchor is greater than 0 and it is followed by - * a whitespace character or one of the indicators: - * - * '?', ':', ',', ']', '}', '%', '@', '`'. - */ - - if len(s) == 0 || - !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || - parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '`') { - context := "while scanning an alias" - if typ == yaml_ANCHOR_TOKEN { - context = "while scanning an anchor" - } - yaml_parser_set_scanner_error(parser, context, start_mark, - "did not find expected alphabetic or numeric character") - return false - } - - // Create a token. - *token = yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - value: s, - } - - return true -} - -/* - * Scan a TAG token. - */ - -func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { - var handle, suffix []byte - - start_mark := parser.mark - - // Check if the tag is in the canonical form. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - if parser.buffer[parser.buffer_pos+1] == '<' { - // Keep the handle as '' - - // Eat '!<' - skip(parser) - skip(parser) - - // Consume the tag value. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - - // Check for '>' and eat it. - if parser.buffer[parser.buffer_pos] != '>' { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find the expected '>'") - return false - } - - skip(parser) - } else { - // The tag has either the '!suffix' or the '!handle!suffix' form. - - // First, try to scan a handle. - if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { - return false - } - - // Check if it is, indeed, handle. - if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { - // Scan the suffix now. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - } else { - // It wasn't a handle after all. Scan the rest of the tag. - if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { - return false - } - - // Set the handle to '!'. - handle = []byte{'!'} - - // A special case: the '!' tag. Set the handle to '' and the - // suffix to '!'. - if len(suffix) == 0 { - handle, suffix = suffix, handle - } - } - } - - // Check the character which ends the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find expected whitespace or line break") - return false - } - - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_TAG_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - suffix: suffix, - } - return true -} - -// Scan a tag handle. -func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { - // Check the initial '!' character. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] != '!' { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - - var s []byte - - // Copy the '!' character. - s = read(parser, s) - - // Copy all subsequent alphabetical and numerical characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the trailing character is '!' and copy it. - if parser.buffer[parser.buffer_pos] == '!' { - s = read(parser, s) - } else { - // It's either the '!' tag or not really a tag handle. If it's a %TAG - // directive, it's an error. If it's a tag token, it must be a part of URI. - if directive && string(s) != "!" { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - } - - *handle = s - return true -} - -// Scan a tag. -func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { - //size_t length = head ? strlen((char *)head) : 0 - var s []byte - hasTag := len(head) > 0 - - // Copy the head if needed. - // - // Note that we don't copy the leading '!' character. - if len(head) > 1 { - s = append(s, head[1:]...) - } - - // Scan the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // The set of characters that may appear in URI is as follows: - // - // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', - // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', - // '%'. - // [Go] Convert this into more reasonable logic. - for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || - parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || - parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || - parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || - parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || - parser.buffer[parser.buffer_pos] == '%' { - // Check if it is a URI-escape sequence. - if parser.buffer[parser.buffer_pos] == '%' { - if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { - return false - } - } else { - s = read(parser, s) - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - hasTag = true - } - - if !hasTag { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected tag URI") - return false - } - *uri = s - return true -} - -// Decode an URI-escape sequence corresponding to a single UTF-8 character. -func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { - - // Decode the required number of characters. - w := 1024 - for w > 0 { - // Check for a URI-escaped octet. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - - if !(parser.buffer[parser.buffer_pos] == '%' && - is_hex(parser.buffer, parser.buffer_pos+1) && - is_hex(parser.buffer, parser.buffer_pos+2)) { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find URI escaped octet") - } - - // Get the octet. - octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) - - // If it is the leading octet, determine the length of the UTF-8 sequence. - if w == 1024 { - w = width(octet) - if w == 0 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect leading UTF-8 octet") - } - } else { - // Check if the trailing octet is correct. - if octet&0xC0 != 0x80 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect trailing UTF-8 octet") - } - } - - // Copy the octet and move the pointers. - *s = append(*s, octet) - skip(parser) - skip(parser) - skip(parser) - w-- - } - return true -} - -// Scan a block scalar. -func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { - // Eat the indicator '|' or '>'. - start_mark := parser.mark - skip(parser) - - // Scan the additional block scalar indicators. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check for a chomping indicator. - var chomping, increment int - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - // Set the chomping method and eat the indicator. - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - - // Check for an indentation indicator. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if is_digit(parser.buffer, parser.buffer_pos) { - // Check that the indentation is greater than 0. - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - - // Get the indentation level and eat the indicator. - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - } - - } else if is_digit(parser.buffer, parser.buffer_pos) { - // Do the same as above, but in the opposite order. - - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - } - } - - // Eat whitespaces and comments to the end of the line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - end_mark := parser.mark - - // Set the indentation level if it was specified. - var indent int - if increment > 0 { - if parser.indent >= 0 { - indent = parser.indent + increment - } else { - indent = increment - } - } - - // Scan the leading line breaks and determine the indentation level if needed. - var s, leading_break, trailing_breaks []byte - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - - // Scan the block scalar content. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var leading_blank, trailing_blank bool - for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { - // We are at the beginning of a non-empty line. - - // Is it a trailing whitespace? - trailing_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Check if we need to fold the leading line break. - if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { - // Do we need to join the lines by space? - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } - } else { - s = append(s, leading_break...) - } - leading_break = leading_break[:0] - - // Append the remaining line breaks. - s = append(s, trailing_breaks...) - trailing_breaks = trailing_breaks[:0] - - // Is it a leading whitespace? - leading_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Consume the current line. - for !is_breakz(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - leading_break = read_line(parser, leading_break) - - // Eat the following indentation spaces and line breaks. - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - } - - // Chomp the tail. - if chomping != -1 { - s = append(s, leading_break...) - } - if chomping == 1 { - s = append(s, trailing_breaks...) - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_LITERAL_SCALAR_STYLE, - } - if !literal { - token.style = yaml_FOLDED_SCALAR_STYLE - } - return true -} - -// Scan indentation spaces and line breaks for a block scalar. Determine the -// indentation level if needed. -func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { - *end_mark = parser.mark - - // Eat the indentation spaces and line breaks. - max_indent := 0 - for { - // Eat the indentation spaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.mark.column > max_indent { - max_indent = parser.mark.column - } - - // Check for a tab character messing the indentation. - if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { - return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found a tab character where an indentation space is expected") - } - - // Have we found a non-empty line? - if !is_break(parser.buffer, parser.buffer_pos) { - break - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - // [Go] Should really be returning breaks instead. - *breaks = read_line(parser, *breaks) - *end_mark = parser.mark - } - - // Determine the indentation level if needed. - if *indent == 0 { - *indent = max_indent - if *indent < parser.indent+1 { - *indent = parser.indent + 1 - } - if *indent < 1 { - *indent = 1 - } - } - return true -} - -// Scan a quoted scalar. -func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { - // Eat the left quote. - start_mark := parser.mark - skip(parser) - - // Consume the content of the quoted scalar. - var s, leading_break, trailing_breaks, whitespaces []byte - for { - // Check that there are no document indicators at the beginning of the line. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected document indicator") - return false - } - - // Check for EOF. - if is_z(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected end of stream") - return false - } - - // Consume non-blank characters. - leading_blanks := false - for !is_blankz(parser.buffer, parser.buffer_pos) { - if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { - // Is is an escaped single quote. - s = append(s, '\'') - skip(parser) - skip(parser) - - } else if single && parser.buffer[parser.buffer_pos] == '\'' { - // It is a right single quote. - break - } else if !single && parser.buffer[parser.buffer_pos] == '"' { - // It is a right double quote. - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { - // It is an escaped line break. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - skip(parser) - skip_line(parser) - leading_blanks = true - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' { - // It is an escape sequence. - code_length := 0 - - // Check the escape character. - switch parser.buffer[parser.buffer_pos+1] { - case '0': - s = append(s, 0) - case 'a': - s = append(s, '\x07') - case 'b': - s = append(s, '\x08') - case 't', '\t': - s = append(s, '\x09') - case 'n': - s = append(s, '\x0A') - case 'v': - s = append(s, '\x0B') - case 'f': - s = append(s, '\x0C') - case 'r': - s = append(s, '\x0D') - case 'e': - s = append(s, '\x1B') - case ' ': - s = append(s, '\x20') - case '"': - s = append(s, '"') - case '\'': - s = append(s, '\'') - case '\\': - s = append(s, '\\') - case 'N': // NEL (#x85) - s = append(s, '\xC2') - s = append(s, '\x85') - case '_': // #xA0 - s = append(s, '\xC2') - s = append(s, '\xA0') - case 'L': // LS (#x2028) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA8') - case 'P': // PS (#x2029) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA9') - case 'x': - code_length = 2 - case 'u': - code_length = 4 - case 'U': - code_length = 8 - default: - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found unknown escape character") - return false - } - - skip(parser) - skip(parser) - - // Consume an arbitrary escape code. - if code_length > 0 { - var value int - - // Scan the character value. - if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { - return false - } - for k := 0; k < code_length; k++ { - if !is_hex(parser.buffer, parser.buffer_pos+k) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "did not find expected hexdecimal number") - return false - } - value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) - } - - // Check the value and write the character. - if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found invalid Unicode character escape code") - return false - } - if value <= 0x7F { - s = append(s, byte(value)) - } else if value <= 0x7FF { - s = append(s, byte(0xC0+(value>>6))) - s = append(s, byte(0x80+(value&0x3F))) - } else if value <= 0xFFFF { - s = append(s, byte(0xE0+(value>>12))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } else { - s = append(s, byte(0xF0+(value>>18))) - s = append(s, byte(0x80+((value>>12)&0x3F))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } - - // Advance the pointer. - for k := 0; k < code_length; k++ { - skip(parser) - } - } - } else { - // It is a non-escaped non-blank character. - s = read(parser, s) - } - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we are at the end of the scalar. - if single { - if parser.buffer[parser.buffer_pos] == '\'' { - break - } - } else { - if parser.buffer[parser.buffer_pos] == '"' { - break - } - } - - // Consume blank characters. - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Join the whitespaces or fold line breaks. - if leading_blanks { - // Do we need to fold line breaks? - if len(leading_break) > 0 && leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Eat the right quote. - skip(parser) - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_SINGLE_QUOTED_SCALAR_STYLE, - } - if !single { - token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - return true -} - -// Scan a plain scalar. -func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { - - var s, leading_break, trailing_breaks, whitespaces []byte - var leading_blanks bool - var indent = parser.indent + 1 - - start_mark := parser.mark - end_mark := parser.mark - - // Consume the content of the plain scalar. - for { - // Check for a document indicator. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - break - } - - // Check for a comment. - if parser.buffer[parser.buffer_pos] == '#' { - break - } - - // Consume non-blank characters. - for !is_blankz(parser.buffer, parser.buffer_pos) { - - // Check for indicators that may end a plain scalar. - if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level > 0 && - (parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}')) { - break - } - - // Check if we need to join whitespaces and breaks. - if leading_blanks || len(whitespaces) > 0 { - if leading_blanks { - // Do we need to fold line breaks? - if leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - leading_blanks = false - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Copy the character. - s = read(parser, s) - - end_mark = parser.mark - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - // Is it the end? - if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { - break - } - - // Consume blank characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - - // Check for tab characters that abuse indentation. - if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found a tab character that violates indentation") - return false - } - - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check indentation level. - if parser.flow_level == 0 && parser.mark.column < indent { - break - } - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_PLAIN_SCALAR_STYLE, - } - - // Note that we change the 'simple_key_allowed' flag. - if leading_blanks { - parser.simple_key_allowed = true - } - return true -} diff --git a/vendor/gopkg.in/yaml.v2/sorter.go b/vendor/gopkg.in/yaml.v2/sorter.go deleted file mode 100644 index 4c45e66..0000000 --- a/vendor/gopkg.in/yaml.v2/sorter.go +++ /dev/null @@ -1,113 +0,0 @@ -package yaml - -import ( - "reflect" - "unicode" -) - -type keyList []reflect.Value - -func (l keyList) Len() int { return len(l) } -func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l keyList) Less(i, j int) bool { - a := l[i] - b := l[j] - ak := a.Kind() - bk := b.Kind() - for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { - a = a.Elem() - ak = a.Kind() - } - for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { - b = b.Elem() - bk = b.Kind() - } - af, aok := keyFloat(a) - bf, bok := keyFloat(b) - if aok && bok { - if af != bf { - return af < bf - } - if ak != bk { - return ak < bk - } - return numLess(a, b) - } - if ak != reflect.String || bk != reflect.String { - return ak < bk - } - ar, br := []rune(a.String()), []rune(b.String()) - for i := 0; i < len(ar) && i < len(br); i++ { - if ar[i] == br[i] { - continue - } - al := unicode.IsLetter(ar[i]) - bl := unicode.IsLetter(br[i]) - if al && bl { - return ar[i] < br[i] - } - if al || bl { - return bl - } - var ai, bi int - var an, bn int64 - if ar[i] == '0' || br[i] == '0' { - for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { - if ar[j] != '0' { - an = 1 - bn = 1 - break - } - } - } - for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { - an = an*10 + int64(ar[ai]-'0') - } - for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { - bn = bn*10 + int64(br[bi]-'0') - } - if an != bn { - return an < bn - } - if ai != bi { - return ai < bi - } - return ar[i] < br[i] - } - return len(ar) < len(br) -} - -// keyFloat returns a float value for v if it is a number/bool -// and whether it is a number/bool or not. -func keyFloat(v reflect.Value) (f float64, ok bool) { - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float64(v.Int()), true - case reflect.Float32, reflect.Float64: - return v.Float(), true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return float64(v.Uint()), true - case reflect.Bool: - if v.Bool() { - return 1, true - } - return 0, true - } - return 0, false -} - -// numLess returns whether a < b. -// a and b must necessarily have the same kind. -func numLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return a.Int() < b.Int() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Bool: - return !a.Bool() && b.Bool() - } - panic("not a number") -} diff --git a/vendor/gopkg.in/yaml.v2/writerc.go b/vendor/gopkg.in/yaml.v2/writerc.go deleted file mode 100644 index a2dde60..0000000 --- a/vendor/gopkg.in/yaml.v2/writerc.go +++ /dev/null @@ -1,26 +0,0 @@ -package yaml - -// Set the writer error and return false. -func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_WRITER_ERROR - emitter.problem = problem - return false -} - -// Flush the output buffer. -func yaml_emitter_flush(emitter *yaml_emitter_t) bool { - if emitter.write_handler == nil { - panic("write handler not set") - } - - // Check if the buffer is empty. - if emitter.buffer_pos == 0 { - return true - } - - if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { - return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) - } - emitter.buffer_pos = 0 - return true -} diff --git a/vendor/gopkg.in/yaml.v2/yaml.go b/vendor/gopkg.in/yaml.v2/yaml.go deleted file mode 100644 index de85aa4..0000000 --- a/vendor/gopkg.in/yaml.v2/yaml.go +++ /dev/null @@ -1,466 +0,0 @@ -// Package yaml implements YAML support for the Go language. -// -// Source code and other details for the project are available at GitHub: -// -// https://github.com/go-yaml/yaml -// -package yaml - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" -) - -// MapSlice encodes and decodes as a YAML map. -// The order of keys is preserved when encoding and decoding. -type MapSlice []MapItem - -// MapItem is an item in a MapSlice. -type MapItem struct { - Key, Value interface{} -} - -// The Unmarshaler interface may be implemented by types to customize their -// behavior when being unmarshaled from a YAML document. The UnmarshalYAML -// method receives a function that may be called to unmarshal the original -// YAML value into a field or variable. It is safe to call the unmarshal -// function parameter more than once if necessary. -type Unmarshaler interface { - UnmarshalYAML(unmarshal func(interface{}) error) error -} - -// The Marshaler interface may be implemented by types to customize their -// behavior when being marshaled into a YAML document. The returned value -// is marshaled in place of the original value implementing Marshaler. -// -// If an error is returned by MarshalYAML, the marshaling procedure stops -// and returns with the provided error. -type Marshaler interface { - MarshalYAML() (interface{}, error) -} - -// Unmarshal decodes the first document found within the in byte slice -// and assigns decoded values into the out value. -// -// Maps and pointers (to a struct, string, int, etc) are accepted as out -// values. If an internal pointer within a struct is not initialized, -// the yaml package will initialize it if necessary for unmarshalling -// the provided data. The out parameter must not be nil. -// -// The type of the decoded values should be compatible with the respective -// values in out. If one or more values cannot be decoded due to a type -// mismatches, decoding continues partially until the end of the YAML -// content, and a *yaml.TypeError is returned with details for all -// missed values. -// -// Struct fields are only unmarshalled if they are exported (have an -// upper case first letter), and are unmarshalled using the field name -// lowercased as the default key. Custom keys may be defined via the -// "yaml" name in the field tag: the content preceding the first comma -// is used as the key, and the following comma-separated options are -// used to tweak the marshalling process (see Marshal). -// Conflicting names result in a runtime error. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) -// -// See the documentation of Marshal for the format of tags and a list of -// supported tag options. -// -func Unmarshal(in []byte, out interface{}) (err error) { - return unmarshal(in, out, false) -} - -// UnmarshalStrict is like Unmarshal except that any fields that are found -// in the data that do not have corresponding struct members, or mapping -// keys that are duplicates, will result in -// an error. -func UnmarshalStrict(in []byte, out interface{}) (err error) { - return unmarshal(in, out, true) -} - -// A Decorder reads and decodes YAML values from an input stream. -type Decoder struct { - strict bool - parser *parser -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may read -// data from r beyond the YAML values requested. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{ - parser: newParserFromReader(r), - } -} - -// SetStrict sets whether strict decoding behaviour is enabled when -// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. -func (dec *Decoder) SetStrict(strict bool) { - dec.strict = strict -} - -// Decode reads the next YAML-encoded value from its input -// and stores it in the value pointed to by v. -// -// See the documentation for Unmarshal for details about the -// conversion of YAML into a Go value. -func (dec *Decoder) Decode(v interface{}) (err error) { - d := newDecoder(dec.strict) - defer handleErr(&err) - node := dec.parser.parse() - if node == nil { - return io.EOF - } - out := reflect.ValueOf(v) - if out.Kind() == reflect.Ptr && !out.IsNil() { - out = out.Elem() - } - d.unmarshal(node, out) - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -func unmarshal(in []byte, out interface{}, strict bool) (err error) { - defer handleErr(&err) - d := newDecoder(strict) - p := newParser(in) - defer p.destroy() - node := p.parse() - if node != nil { - v := reflect.ValueOf(out) - if v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - d.unmarshal(node, v) - } - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -// Marshal serializes the value provided into a YAML document. The structure -// of the generated document will reflect the structure of the value itself. -// Maps and pointers (to struct, string, int, etc) are accepted as the in value. -// -// Struct fields are only marshalled if they are exported (have an upper case -// first letter), and are marshalled using the field name lowercased as the -// default key. Custom keys may be defined via the "yaml" name in the field -// tag: the content preceding the first comma is used as the key, and the -// following comma-separated options are used to tweak the marshalling process. -// Conflicting names result in a runtime error. -// -// The field tag format accepted is: -// -// `(...) yaml:"[][,[,]]" (...)` -// -// The following flags are currently supported: -// -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. -// -// flow Marshal using a flow style (useful for structs, -// sequences and maps). -// -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. -// -// In addition, if the key is "-", the field is ignored. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// -func Marshal(in interface{}) (out []byte, err error) { - defer handleErr(&err) - e := newEncoder() - defer e.destroy() - e.marshalDoc("", reflect.ValueOf(in)) - e.finish() - out = e.out - return -} - -// An Encoder writes YAML values to an output stream. -type Encoder struct { - encoder *encoder -} - -// NewEncoder returns a new encoder that writes to w. -// The Encoder should be closed after use to flush all data -// to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - encoder: newEncoderWithWriter(w), - } -} - -// Encode writes the YAML encoding of v to the stream. -// If multiple items are encoded to the stream, the -// second and subsequent document will be preceded -// with a "---" document separator, but the first will not. -// -// See the documentation for Marshal for details about the conversion of Go -// values to YAML. -func (e *Encoder) Encode(v interface{}) (err error) { - defer handleErr(&err) - e.encoder.marshalDoc("", reflect.ValueOf(v)) - return nil -} - -// Close closes the encoder by writing any remaining data. -// It does not write a stream terminating string "...". -func (e *Encoder) Close() (err error) { - defer handleErr(&err) - e.encoder.finish() - return nil -} - -func handleErr(err *error) { - if v := recover(); v != nil { - if e, ok := v.(yamlError); ok { - *err = e.err - } else { - panic(v) - } - } -} - -type yamlError struct { - err error -} - -func fail(err error) { - panic(yamlError{err}) -} - -func failf(format string, args ...interface{}) { - panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) -} - -// A TypeError is returned by Unmarshal when one or more fields in -// the YAML document cannot be properly decoded into the requested -// types. When this error is returned, the value is still -// unmarshaled partially. -type TypeError struct { - Errors []string -} - -func (e *TypeError) Error() string { - return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -// The code in this section was copied from mgo/bson. - -// structInfo holds details for the serialization of fields of -// a given struct. -type structInfo struct { - FieldsMap map[string]fieldInfo - FieldsList []fieldInfo - - // InlineMap is the number of the field in the struct that - // contains an ,inline map, or -1 if there's none. - InlineMap int -} - -type fieldInfo struct { - Key string - Num int - OmitEmpty bool - Flow bool - // Id holds the unique field identifier, so we can cheaply - // check for field duplicates without maintaining an extra map. - Id int - - // Inline holds the field index if the field is part of an inlined struct. - Inline []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var fieldMapMutex sync.RWMutex - -func getStructInfo(st reflect.Type) (*structInfo, error) { - fieldMapMutex.RLock() - sinfo, found := structMap[st] - fieldMapMutex.RUnlock() - if found { - return sinfo, nil - } - - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, 0, n) - inlineMap := -1 - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" && !field.Anonymous { - continue // Private field - } - - info := fieldInfo{Num: i} - - tag := field.Tag.Get("yaml") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) - } - if tag == "-" { - continue - } - - inline := false - fields := strings.Split(tag, ",") - if len(fields) > 1 { - for _, flag := range fields[1:] { - switch flag { - case "omitempty": - info.OmitEmpty = true - case "flow": - info.Flow = true - case "inline": - inline = true - default: - return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) - } - } - tag = fields[0] - } - - if inline { - switch field.Type.Kind() { - case reflect.Map: - if inlineMap >= 0 { - return nil, errors.New("Multiple ,inline maps in struct " + st.String()) - } - if field.Type.Key() != reflect.TypeOf("") { - return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) - } - inlineMap = info.Num - case reflect.Struct: - sinfo, err := getStructInfo(field.Type) - if err != nil { - return nil, err - } - for _, finfo := range sinfo.FieldsList { - if _, found := fieldsMap[finfo.Key]; found { - msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - if finfo.Inline == nil { - finfo.Inline = []int{i, finfo.Num} - } else { - finfo.Inline = append([]int{i}, finfo.Inline...) - } - finfo.Id = len(fieldsList) - fieldsMap[finfo.Key] = finfo - fieldsList = append(fieldsList, finfo) - } - default: - //return nil, errors.New("Option ,inline needs a struct value or map field") - return nil, errors.New("Option ,inline needs a struct value field") - } - continue - } - - if tag != "" { - info.Key = tag - } else { - info.Key = strings.ToLower(field.Name) - } - - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - - info.Id = len(fieldsList) - fieldsList = append(fieldsList, info) - fieldsMap[info.Key] = info - } - - sinfo = &structInfo{ - FieldsMap: fieldsMap, - FieldsList: fieldsList, - InlineMap: inlineMap, - } - - fieldMapMutex.Lock() - structMap[st] = sinfo - fieldMapMutex.Unlock() - return sinfo, nil -} - -// IsZeroer is used to check whether an object is zero to -// determine whether it should be omitted when marshaling -// with the omitempty flag. One notable implementation -// is time.Time. -type IsZeroer interface { - IsZero() bool -} - -func isZero(v reflect.Value) bool { - kind := v.Kind() - if z, ok := v.Interface().(IsZeroer); ok { - if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { - return true - } - return z.IsZero() - } - switch kind { - case reflect.String: - return len(v.String()) == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflect.Slice: - return v.Len() == 0 - case reflect.Map: - return v.Len() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Struct: - vt := v.Type() - for i := v.NumField() - 1; i >= 0; i-- { - if vt.Field(i).PkgPath != "" { - continue // Private field - } - if !isZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go deleted file mode 100644 index e25cee5..0000000 --- a/vendor/gopkg.in/yaml.v2/yamlh.go +++ /dev/null @@ -1,738 +0,0 @@ -package yaml - -import ( - "fmt" - "io" -) - -// The version directive data. -type yaml_version_directive_t struct { - major int8 // The major version number. - minor int8 // The minor version number. -} - -// The tag directive data. -type yaml_tag_directive_t struct { - handle []byte // The tag handle. - prefix []byte // The tag prefix. -} - -type yaml_encoding_t int - -// The stream encoding. -const ( - // Let the parser choose the encoding. - yaml_ANY_ENCODING yaml_encoding_t = iota - - yaml_UTF8_ENCODING // The default UTF-8 encoding. - yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. - yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. -) - -type yaml_break_t int - -// Line break types. -const ( - // Let the parser choose the break type. - yaml_ANY_BREAK yaml_break_t = iota - - yaml_CR_BREAK // Use CR for line breaks (Mac style). - yaml_LN_BREAK // Use LN for line breaks (Unix style). - yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). -) - -type yaml_error_type_t int - -// Many bad things could happen with the parser and emitter. -const ( - // No error is produced. - yaml_NO_ERROR yaml_error_type_t = iota - - yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. - yaml_READER_ERROR // Cannot read or decode the input stream. - yaml_SCANNER_ERROR // Cannot scan the input stream. - yaml_PARSER_ERROR // Cannot parse the input stream. - yaml_COMPOSER_ERROR // Cannot compose a YAML document. - yaml_WRITER_ERROR // Cannot write to the output stream. - yaml_EMITTER_ERROR // Cannot emit a YAML stream. -) - -// The pointer position. -type yaml_mark_t struct { - index int // The position index. - line int // The position line. - column int // The position column. -} - -// Node Styles - -type yaml_style_t int8 - -type yaml_scalar_style_t yaml_style_t - -// Scalar styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota - - yaml_PLAIN_SCALAR_STYLE // The plain scalar style. - yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. - yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. - yaml_LITERAL_SCALAR_STYLE // The literal scalar style. - yaml_FOLDED_SCALAR_STYLE // The folded scalar style. -) - -type yaml_sequence_style_t yaml_style_t - -// Sequence styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota - - yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. - yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. -) - -type yaml_mapping_style_t yaml_style_t - -// Mapping styles. -const ( - // Let the emitter choose the style. - yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota - - yaml_BLOCK_MAPPING_STYLE // The block mapping style. - yaml_FLOW_MAPPING_STYLE // The flow mapping style. -) - -// Tokens - -type yaml_token_type_t int - -// Token types. -const ( - // An empty token. - yaml_NO_TOKEN yaml_token_type_t = iota - - yaml_STREAM_START_TOKEN // A STREAM-START token. - yaml_STREAM_END_TOKEN // A STREAM-END token. - - yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. - yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. - yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. - yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. - - yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. - yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. - yaml_BLOCK_END_TOKEN // A BLOCK-END token. - - yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. - yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. - yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. - yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. - - yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. - yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. - yaml_KEY_TOKEN // A KEY token. - yaml_VALUE_TOKEN // A VALUE token. - - yaml_ALIAS_TOKEN // An ALIAS token. - yaml_ANCHOR_TOKEN // An ANCHOR token. - yaml_TAG_TOKEN // A TAG token. - yaml_SCALAR_TOKEN // A SCALAR token. -) - -func (tt yaml_token_type_t) String() string { - switch tt { - case yaml_NO_TOKEN: - return "yaml_NO_TOKEN" - case yaml_STREAM_START_TOKEN: - return "yaml_STREAM_START_TOKEN" - case yaml_STREAM_END_TOKEN: - return "yaml_STREAM_END_TOKEN" - case yaml_VERSION_DIRECTIVE_TOKEN: - return "yaml_VERSION_DIRECTIVE_TOKEN" - case yaml_TAG_DIRECTIVE_TOKEN: - return "yaml_TAG_DIRECTIVE_TOKEN" - case yaml_DOCUMENT_START_TOKEN: - return "yaml_DOCUMENT_START_TOKEN" - case yaml_DOCUMENT_END_TOKEN: - return "yaml_DOCUMENT_END_TOKEN" - case yaml_BLOCK_SEQUENCE_START_TOKEN: - return "yaml_BLOCK_SEQUENCE_START_TOKEN" - case yaml_BLOCK_MAPPING_START_TOKEN: - return "yaml_BLOCK_MAPPING_START_TOKEN" - case yaml_BLOCK_END_TOKEN: - return "yaml_BLOCK_END_TOKEN" - case yaml_FLOW_SEQUENCE_START_TOKEN: - return "yaml_FLOW_SEQUENCE_START_TOKEN" - case yaml_FLOW_SEQUENCE_END_TOKEN: - return "yaml_FLOW_SEQUENCE_END_TOKEN" - case yaml_FLOW_MAPPING_START_TOKEN: - return "yaml_FLOW_MAPPING_START_TOKEN" - case yaml_FLOW_MAPPING_END_TOKEN: - return "yaml_FLOW_MAPPING_END_TOKEN" - case yaml_BLOCK_ENTRY_TOKEN: - return "yaml_BLOCK_ENTRY_TOKEN" - case yaml_FLOW_ENTRY_TOKEN: - return "yaml_FLOW_ENTRY_TOKEN" - case yaml_KEY_TOKEN: - return "yaml_KEY_TOKEN" - case yaml_VALUE_TOKEN: - return "yaml_VALUE_TOKEN" - case yaml_ALIAS_TOKEN: - return "yaml_ALIAS_TOKEN" - case yaml_ANCHOR_TOKEN: - return "yaml_ANCHOR_TOKEN" - case yaml_TAG_TOKEN: - return "yaml_TAG_TOKEN" - case yaml_SCALAR_TOKEN: - return "yaml_SCALAR_TOKEN" - } - return "" -} - -// The token structure. -type yaml_token_t struct { - // The token type. - typ yaml_token_type_t - - // The start/end of the token. - start_mark, end_mark yaml_mark_t - - // The stream encoding (for yaml_STREAM_START_TOKEN). - encoding yaml_encoding_t - - // The alias/anchor/scalar value or tag/tag directive handle - // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). - value []byte - - // The tag suffix (for yaml_TAG_TOKEN). - suffix []byte - - // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). - prefix []byte - - // The scalar style (for yaml_SCALAR_TOKEN). - style yaml_scalar_style_t - - // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). - major, minor int8 -} - -// Events - -type yaml_event_type_t int8 - -// Event types. -const ( - // An empty event. - yaml_NO_EVENT yaml_event_type_t = iota - - yaml_STREAM_START_EVENT // A STREAM-START event. - yaml_STREAM_END_EVENT // A STREAM-END event. - yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. - yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. - yaml_ALIAS_EVENT // An ALIAS event. - yaml_SCALAR_EVENT // A SCALAR event. - yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. - yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. - yaml_MAPPING_START_EVENT // A MAPPING-START event. - yaml_MAPPING_END_EVENT // A MAPPING-END event. -) - -var eventStrings = []string{ - yaml_NO_EVENT: "none", - yaml_STREAM_START_EVENT: "stream start", - yaml_STREAM_END_EVENT: "stream end", - yaml_DOCUMENT_START_EVENT: "document start", - yaml_DOCUMENT_END_EVENT: "document end", - yaml_ALIAS_EVENT: "alias", - yaml_SCALAR_EVENT: "scalar", - yaml_SEQUENCE_START_EVENT: "sequence start", - yaml_SEQUENCE_END_EVENT: "sequence end", - yaml_MAPPING_START_EVENT: "mapping start", - yaml_MAPPING_END_EVENT: "mapping end", -} - -func (e yaml_event_type_t) String() string { - if e < 0 || int(e) >= len(eventStrings) { - return fmt.Sprintf("unknown event %d", e) - } - return eventStrings[e] -} - -// The event structure. -type yaml_event_t struct { - - // The event type. - typ yaml_event_type_t - - // The start and end of the event. - start_mark, end_mark yaml_mark_t - - // The document encoding (for yaml_STREAM_START_EVENT). - encoding yaml_encoding_t - - // The version directive (for yaml_DOCUMENT_START_EVENT). - version_directive *yaml_version_directive_t - - // The list of tag directives (for yaml_DOCUMENT_START_EVENT). - tag_directives []yaml_tag_directive_t - - // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). - anchor []byte - - // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - tag []byte - - // The scalar value (for yaml_SCALAR_EVENT). - value []byte - - // Is the document start/end indicator implicit, or the tag optional? - // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). - implicit bool - - // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). - quoted_implicit bool - - // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - style yaml_style_t -} - -func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } -func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } -func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } - -// Nodes - -const ( - yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. - yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. - yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. - yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. - yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. - yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. - - yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. - yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. - - // Not in original libyaml. - yaml_BINARY_TAG = "tag:yaml.org,2002:binary" - yaml_MERGE_TAG = "tag:yaml.org,2002:merge" - - yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. - yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. - yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. -) - -type yaml_node_type_t int - -// Node types. -const ( - // An empty node. - yaml_NO_NODE yaml_node_type_t = iota - - yaml_SCALAR_NODE // A scalar node. - yaml_SEQUENCE_NODE // A sequence node. - yaml_MAPPING_NODE // A mapping node. -) - -// An element of a sequence node. -type yaml_node_item_t int - -// An element of a mapping node. -type yaml_node_pair_t struct { - key int // The key of the element. - value int // The value of the element. -} - -// The node structure. -type yaml_node_t struct { - typ yaml_node_type_t // The node type. - tag []byte // The node tag. - - // The node data. - - // The scalar parameters (for yaml_SCALAR_NODE). - scalar struct { - value []byte // The scalar value. - length int // The length of the scalar value. - style yaml_scalar_style_t // The scalar style. - } - - // The sequence parameters (for YAML_SEQUENCE_NODE). - sequence struct { - items_data []yaml_node_item_t // The stack of sequence items. - style yaml_sequence_style_t // The sequence style. - } - - // The mapping parameters (for yaml_MAPPING_NODE). - mapping struct { - pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). - pairs_start *yaml_node_pair_t // The beginning of the stack. - pairs_end *yaml_node_pair_t // The end of the stack. - pairs_top *yaml_node_pair_t // The top of the stack. - style yaml_mapping_style_t // The mapping style. - } - - start_mark yaml_mark_t // The beginning of the node. - end_mark yaml_mark_t // The end of the node. - -} - -// The document structure. -type yaml_document_t struct { - - // The document nodes. - nodes []yaml_node_t - - // The version directive. - version_directive *yaml_version_directive_t - - // The list of tag directives. - tag_directives_data []yaml_tag_directive_t - tag_directives_start int // The beginning of the tag directives list. - tag_directives_end int // The end of the tag directives list. - - start_implicit int // Is the document start indicator implicit? - end_implicit int // Is the document end indicator implicit? - - // The start/end of the document. - start_mark, end_mark yaml_mark_t -} - -// The prototype of a read handler. -// -// The read handler is called when the parser needs to read more bytes from the -// source. The handler should write not more than size bytes to the buffer. -// The number of written bytes should be set to the size_read variable. -// -// [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). -// [out] buffer The buffer to write the data from the source. -// [in] size The size of the buffer. -// [out] size_read The actual number of bytes read from the source. -// -// On success, the handler should return 1. If the handler failed, -// the returned value should be 0. On EOF, the handler should set the -// size_read to 0 and return 1. -type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) - -// This structure holds information about a potential simple key. -type yaml_simple_key_t struct { - possible bool // Is a simple key possible? - required bool // Is a simple key required? - token_number int // The number of the token. - mark yaml_mark_t // The position mark. -} - -// The states of the parser. -type yaml_parser_state_t int - -const ( - yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota - - yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. - yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. - yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. - yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. - yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. - yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. - yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. - yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. - yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. - yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. - yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. - yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. - yaml_PARSE_END_STATE // Expect nothing. -) - -func (ps yaml_parser_state_t) String() string { - switch ps { - case yaml_PARSE_STREAM_START_STATE: - return "yaml_PARSE_STREAM_START_STATE" - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_START_STATE: - return "yaml_PARSE_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return "yaml_PARSE_DOCUMENT_CONTENT_STATE" - case yaml_PARSE_DOCUMENT_END_STATE: - return "yaml_PARSE_DOCUMENT_END_STATE" - case yaml_PARSE_BLOCK_NODE_STATE: - return "yaml_PARSE_BLOCK_NODE_STATE" - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" - case yaml_PARSE_FLOW_NODE_STATE: - return "yaml_PARSE_FLOW_NODE_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" - case yaml_PARSE_END_STATE: - return "yaml_PARSE_END_STATE" - } - return "" -} - -// This structure holds aliases data. -type yaml_alias_data_t struct { - anchor []byte // The anchor. - index int // The node id. - mark yaml_mark_t // The anchor mark. -} - -// The parser structure. -// -// All members are internal. Manage the structure using the -// yaml_parser_ family of functions. -type yaml_parser_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - - problem string // Error description. - - // The byte about which the problem occurred. - problem_offset int - problem_value int - problem_mark yaml_mark_t - - // The error context. - context string - context_mark yaml_mark_t - - // Reader stuff - - read_handler yaml_read_handler_t // Read handler. - - input_reader io.Reader // File input data. - input []byte // String input data. - input_pos int - - eof bool // EOF flag - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - unread int // The number of unread characters in the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The input encoding. - - offset int // The offset of the current position (in bytes). - mark yaml_mark_t // The mark of the current position. - - // Scanner stuff - - stream_start_produced bool // Have we started to scan the input stream? - stream_end_produced bool // Have we reached the end of the input stream? - - flow_level int // The number of unclosed '[' and '{' indicators. - - tokens []yaml_token_t // The tokens queue. - tokens_head int // The head of the tokens queue. - tokens_parsed int // The number of tokens fetched from the queue. - token_available bool // Does the tokens queue contain a token ready for dequeueing. - - indent int // The current indentation level. - indents []int // The indentation levels stack. - - simple_key_allowed bool // May a simple key occur at the current position? - simple_keys []yaml_simple_key_t // The stack of simple keys. - - // Parser stuff - - state yaml_parser_state_t // The current parser state. - states []yaml_parser_state_t // The parser states stack. - marks []yaml_mark_t // The stack of marks. - tag_directives []yaml_tag_directive_t // The list of TAG directives. - - // Dumper stuff - - aliases []yaml_alias_data_t // The alias data. - - document *yaml_document_t // The currently parsed document. -} - -// Emitter Definitions - -// The prototype of a write handler. -// -// The write handler is called when the emitter needs to flush the accumulated -// characters to the output. The handler should write @a size bytes of the -// @a buffer to the output. -// -// @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). -// @param[in] buffer The buffer with bytes to be written. -// @param[in] size The size of the buffer. -// -// @returns On success, the handler should return @c 1. If the handler failed, -// the returned value should be @c 0. -// -type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error - -type yaml_emitter_state_t int - -// The emitter states. -const ( - // Expect STREAM-START. - yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota - - yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. - yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. - yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. - yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. - yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. - yaml_EMIT_END_STATE // Expect nothing. -) - -// The emitter structure. -// -// All members are internal. Manage the structure using the @c yaml_emitter_ -// family of functions. -type yaml_emitter_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - problem string // Error description. - - // Writer stuff - - write_handler yaml_write_handler_t // Write handler. - - output_buffer *[]byte // String output data. - output_writer io.Writer // File output data. - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The stream encoding. - - // Emitter stuff - - canonical bool // If the output is in the canonical style? - best_indent int // The number of indentation spaces. - best_width int // The preferred width of the output lines. - unicode bool // Allow unescaped non-ASCII characters? - line_break yaml_break_t // The preferred line break. - - state yaml_emitter_state_t // The current emitter state. - states []yaml_emitter_state_t // The stack of states. - - events []yaml_event_t // The event queue. - events_head int // The head of the event queue. - - indents []int // The stack of indentation levels. - - tag_directives []yaml_tag_directive_t // The list of tag directives. - - indent int // The current indentation level. - - flow_level int // The current flow level. - - root_context bool // Is it the document root context? - sequence_context bool // Is it a sequence context? - mapping_context bool // Is it a mapping context? - simple_key_context bool // Is it a simple mapping key context? - - line int // The current line. - column int // The current column. - whitespace bool // If the last character was a whitespace? - indention bool // If the last character was an indentation character (' ', '-', '?', ':')? - open_ended bool // If an explicit document end is required? - - // Anchor analysis. - anchor_data struct { - anchor []byte // The anchor value. - alias bool // Is it an alias? - } - - // Tag analysis. - tag_data struct { - handle []byte // The tag handle. - suffix []byte // The tag suffix. - } - - // Scalar analysis. - scalar_data struct { - value []byte // The scalar value. - multiline bool // Does the scalar contain line breaks? - flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? - block_plain_allowed bool // Can the scalar be expressed in the block plain style? - single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? - block_allowed bool // Can the scalar be expressed in the literal or folded styles? - style yaml_scalar_style_t // The output style. - } - - // Dumper stuff - - opened bool // If the stream was already opened? - closed bool // If the stream was already closed? - - // The information associated with the document nodes. - anchors *struct { - references int // The number of references. - anchor int // The anchor id. - serialized bool // If the node has been emitted? - } - - last_anchor_id int // The last assigned anchor id. - - document *yaml_document_t // The currently emitted document. -} diff --git a/vendor/gopkg.in/yaml.v2/yamlprivateh.go b/vendor/gopkg.in/yaml.v2/yamlprivateh.go deleted file mode 100644 index 8110ce3..0000000 --- a/vendor/gopkg.in/yaml.v2/yamlprivateh.go +++ /dev/null @@ -1,173 +0,0 @@ -package yaml - -const ( - // The size of the input raw buffer. - input_raw_buffer_size = 512 - - // The size of the input buffer. - // It should be possible to decode the whole raw buffer. - input_buffer_size = input_raw_buffer_size * 3 - - // The size of the output buffer. - output_buffer_size = 128 - - // The size of the output raw buffer. - // It should be possible to encode the whole output buffer. - output_raw_buffer_size = (output_buffer_size*2 + 2) - - // The size of other stacks and queues. - initial_stack_size = 16 - initial_queue_size = 16 - initial_string_size = 16 -) - -// Check if the character at the specified position is an alphabetical -// character, a digit, '_', or '-'. -func is_alpha(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' -} - -// Check if the character at the specified position is a digit. -func is_digit(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' -} - -// Get the value of a digit. -func as_digit(b []byte, i int) int { - return int(b[i]) - '0' -} - -// Check if the character at the specified position is a hex-digit. -func is_hex(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' -} - -// Get the value of a hex-digit. -func as_hex(b []byte, i int) int { - bi := b[i] - if bi >= 'A' && bi <= 'F' { - return int(bi) - 'A' + 10 - } - if bi >= 'a' && bi <= 'f' { - return int(bi) - 'a' + 10 - } - return int(bi) - '0' -} - -// Check if the character is ASCII. -func is_ascii(b []byte, i int) bool { - return b[i] <= 0x7F -} - -// Check if the character at the start of the buffer can be printed unescaped. -func is_printable(b []byte, i int) bool { - return ((b[i] == 0x0A) || // . == #x0A - (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E - (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF - (b[i] > 0xC2 && b[i] < 0xED) || - (b[i] == 0xED && b[i+1] < 0xA0) || - (b[i] == 0xEE) || - (b[i] == 0xEF && // #xE000 <= . <= #xFFFD - !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF - !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) -} - -// Check if the character at the specified position is NUL. -func is_z(b []byte, i int) bool { - return b[i] == 0x00 -} - -// Check if the beginning of the buffer is a BOM. -func is_bom(b []byte, i int) bool { - return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF -} - -// Check if the character at the specified position is space. -func is_space(b []byte, i int) bool { - return b[i] == ' ' -} - -// Check if the character at the specified position is tab. -func is_tab(b []byte, i int) bool { - return b[i] == '\t' -} - -// Check if the character at the specified position is blank (space or tab). -func is_blank(b []byte, i int) bool { - //return is_space(b, i) || is_tab(b, i) - return b[i] == ' ' || b[i] == '\t' -} - -// Check if the character at the specified position is a line break. -func is_break(b []byte, i int) bool { - return (b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) -} - -func is_crlf(b []byte, i int) bool { - return b[i] == '\r' && b[i+1] == '\n' -} - -// Check if the character is a line break or NUL. -func is_breakz(b []byte, i int) bool { - //return is_break(b, i) || is_z(b, i) - return ( // is_break: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - // is_z: - b[i] == 0) -} - -// Check if the character is a line break, space, or NUL. -func is_spacez(b []byte, i int) bool { - //return is_space(b, i) || is_breakz(b, i) - return ( // is_space: - b[i] == ' ' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Check if the character is a line break, space, tab, or NUL. -func is_blankz(b []byte, i int) bool { - //return is_blank(b, i) || is_breakz(b, i) - return ( // is_blank: - b[i] == ' ' || b[i] == '\t' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Determine the width of the character. -func width(b byte) int { - // Don't replace these by a switch without first - // confirming that it is being inlined. - if b&0x80 == 0x00 { - return 1 - } - if b&0xE0 == 0xC0 { - return 2 - } - if b&0xF0 == 0xE0 { - return 3 - } - if b&0xF8 == 0xF0 { - return 4 - } - return 0 - -} diff --git a/vendor/modules.txt b/vendor/modules.txt deleted file mode 100644 index 3ba8558..0000000 --- a/vendor/modules.txt +++ /dev/null @@ -1,6 +0,0 @@ -# github.com/astaxie/beego v1.12.0 -github.com/astaxie/beego/httplib -# github.com/google/uuid v1.3.0 -github.com/google/uuid -# gopkg.in/yaml.v2 v2.2.1 -gopkg.in/yaml.v2