khl 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/README.md +53 -0
- data/lib/khl/http/asset.rb +19 -0
- data/lib/khl/http/badge.rb +20 -0
- data/lib/khl/http/base.rb +101 -0
- data/lib/khl/http/blacklist.rb +41 -0
- data/lib/khl/http/channel.rb +58 -0
- data/lib/khl/http/channel_role.rb +50 -0
- data/lib/khl/http/channel_user.rb +22 -0
- data/lib/khl/http/client.rb +78 -0
- data/lib/khl/http/direct_message.rb +85 -0
- data/lib/khl/http/game.rb +59 -0
- data/lib/khl/http/gateway.rb +19 -0
- data/lib/khl/http/guild.rb +70 -0
- data/lib/khl/http/guild_emoji.rb +46 -0
- data/lib/khl/http/guild_mute.rb +38 -0
- data/lib/khl/http/guild_role.rb +70 -0
- data/lib/khl/http/intimacy.rb +29 -0
- data/lib/khl/http/invite.rb +43 -0
- data/lib/khl/http/message.rb +92 -0
- data/lib/khl/http/response.rb +69 -0
- data/lib/khl/http/user.rb +32 -0
- data/lib/khl/http/user_chat.rb +42 -0
- data/lib/khl/version.rb +5 -0
- data/lib/khl/web_socket/client.rb +151 -0
- data/lib/khl/web_socket/message.rb +54 -0
- data/lib/khl.rb +6 -0
- metadata +108 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 服务器相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/guild
|
9
|
+
class Guild < Base
|
10
|
+
# 获取当前用户加入的服务器列表
|
11
|
+
# @param [Hash] options 可选参数
|
12
|
+
# @option options [Integer] :page 页数
|
13
|
+
# @option options [Integer] :page_size 每页数据数量
|
14
|
+
# @option options [String] :sort 代表排序的字段,比如 -id 代表 id 按 DESC 排序,id 代表 id 按 ASC 排序
|
15
|
+
# @return [KHL::HTTP::Response]
|
16
|
+
def list(options = {})
|
17
|
+
get(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
# 获取服务器详情
|
21
|
+
# @param [String] guild_id 服务器 ID
|
22
|
+
# @return [KHL::HTTP::Response]
|
23
|
+
def view(guild_id)
|
24
|
+
get(guild_id: guild_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
# 获取服务器中的用户列表
|
28
|
+
# @param [String] guild_id 服务器 ID
|
29
|
+
# @param [Hash] options 可选参数
|
30
|
+
# @option options [String] :channel_id 频道 ID
|
31
|
+
# @option options [String] :search 搜索关键字,在用户名或昵称中搜索
|
32
|
+
# @option options [Integer] :role_id 角色 ID,获取特定角色的用户列表
|
33
|
+
# @option options [Integer] :mobile_verified 只能为 0 或 1,0 是未认证,1 是已认证
|
34
|
+
# @option options [Integer] :active_time 根据活跃时间排序,0 是顺序排列,1 是倒序排列
|
35
|
+
# @option options [Integer] :joined_at 根据加入时间排序,0 是顺序排列,1 是倒序排列
|
36
|
+
# @option options [Integer] :page 页数
|
37
|
+
# @option options [Integer] :page_size 每页数据数量
|
38
|
+
# @option options [String] :filter_user_id 获取指定 ID 所属用户的信息
|
39
|
+
# @return [KHL::HTTP::Response]
|
40
|
+
def user_list(guild_id, options = {})
|
41
|
+
get(options.merge(guild_id: guild_id))
|
42
|
+
end
|
43
|
+
|
44
|
+
# 修改服务器中用户的昵称
|
45
|
+
# @param [String] guild_id 服务器 ID
|
46
|
+
# @param [Hash] options 可选参数
|
47
|
+
# @option options [String] :nickname 昵称,2-64 长度,不传则清空昵称
|
48
|
+
# @option options [String] :user_id 用户 ID,不传则修改当前登陆用户的昵称
|
49
|
+
# @return [KHL::HTTP::Response]
|
50
|
+
def nickname(guild_id, options = {})
|
51
|
+
post(options.merge(guild_id: guild_id))
|
52
|
+
end
|
53
|
+
|
54
|
+
# 离开服务器
|
55
|
+
# @param [String] guild_id 服务器 ID
|
56
|
+
# @return [KHL::HTTP::Response]
|
57
|
+
def leave(guild_id)
|
58
|
+
post(guild_id: guild_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
# 踢出服务器
|
62
|
+
# @param [String] guild_id 服务器 ID
|
63
|
+
# @param [String] target_id 用户 ID
|
64
|
+
# @return [KHL::HTTP::Response]
|
65
|
+
def kickout(guild_id, target_id)
|
66
|
+
post(guild_id: guild_id, target_id: target_id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 服务器表情相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/guild-emoji
|
9
|
+
class GuildEmoji < Base
|
10
|
+
# 获取服务器表情列表
|
11
|
+
# @param [String] guild_id 服务器 ID
|
12
|
+
# @param [Hash] options 可选参数
|
13
|
+
# @option options [Integer] :page 页数
|
14
|
+
# @option options [Integer] :page_size 每页数据数量
|
15
|
+
# @return [KHL::HTTP::Response]
|
16
|
+
def list(guild_id, options = {})
|
17
|
+
get(options.merge(guild_id: guild_id))
|
18
|
+
end
|
19
|
+
|
20
|
+
# 创建服务器表情
|
21
|
+
# @param [String] guild_id 服务器 ID
|
22
|
+
# @param [IO] emoji 表情文件。必须为 PNG 类型,大小不能超过 256 KB
|
23
|
+
# @param [Hash] options 可选参数
|
24
|
+
# @option options [String] :name 表情名。长度限制 2-32 字符,如果不写,则为随机字符串
|
25
|
+
# @return [KHL::HTTP::Response]
|
26
|
+
def create(guild_id, emoji, options = {})
|
27
|
+
post_file(options.merge(content_type: "multipart/form-data", guild_id: guild_id, emoji: emoji))
|
28
|
+
end
|
29
|
+
|
30
|
+
# 更新服务器表情
|
31
|
+
# @param [String] name 表情名。长度限制 2-32 字符,如果不写,则为随机字符串
|
32
|
+
# @param [String] id 表情 ID
|
33
|
+
# @return [KHL::HTTP::Response]
|
34
|
+
def update(name, id)
|
35
|
+
post(name: name, id: id)
|
36
|
+
end
|
37
|
+
|
38
|
+
# 删除服务器表情
|
39
|
+
# @param [String] id 表情 ID
|
40
|
+
# @return [KHL::HTTP::Response]
|
41
|
+
def delete(id)
|
42
|
+
post(id: id)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 服务器静音闭麦相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/guild
|
9
|
+
class GuildMute < Base
|
10
|
+
# 服务器静音闭麦列表
|
11
|
+
# @param [String] guild_id 服务器 ID
|
12
|
+
# @param [Hash] options 可选参数
|
13
|
+
# @option options [String] :return_type 返回格式,建议为 "detail", 其他情况仅作为兼容
|
14
|
+
# @return [KHL::HTTP::Response]
|
15
|
+
def list(guild_id, options = {})
|
16
|
+
get(options.merge(guild_id: guild_id))
|
17
|
+
end
|
18
|
+
|
19
|
+
# 添加服务器静音或闭麦
|
20
|
+
# @param [String] guild_id 服务器 ID
|
21
|
+
# @param [String] user_id 用户 ID
|
22
|
+
# @param [Integer] type 静音类型,1 代表麦克风闭麦,2 代表耳机静音
|
23
|
+
# @return [KHL::HTTP::Response]
|
24
|
+
def create(guild_id, user_id, type)
|
25
|
+
post(guild_id: guild_id, user_id: user_id, type: type)
|
26
|
+
end
|
27
|
+
|
28
|
+
# 删除服务器静音或闭麦
|
29
|
+
# @param [String] guild_id 服务器 ID
|
30
|
+
# @param [String] user_id 用户 ID
|
31
|
+
# @param [Integer] type 静音类型,1 代表麦克风闭麦,2 代表耳机静音
|
32
|
+
# @return [KHL::HTTP::Response]
|
33
|
+
def delete(guild_id, user_id, type)
|
34
|
+
post(guild_id: guild_id, user_id: user_id, type: type)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 服务器角色权限相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/guild-role
|
9
|
+
class GuildRole < Base
|
10
|
+
# 获取服务器角色列表
|
11
|
+
# @param [String] guild_id 服务器 ID
|
12
|
+
# @param [Hash] options 可选参数
|
13
|
+
# @option options [Integer] :page 页数
|
14
|
+
# @option options [Integer] :page_size 每页数据数量
|
15
|
+
# @return [KHL::HTTP::Response]
|
16
|
+
def list(guild_id, options = {})
|
17
|
+
get(options.merge(guild_id: guild_id))
|
18
|
+
end
|
19
|
+
|
20
|
+
# 创建服务器角色
|
21
|
+
# @param [String] guild_id 服务器 ID
|
22
|
+
# @param [Hash] options 可选参数
|
23
|
+
# @option options [String] :name 角色名称,如果不写,则为 "新角色"
|
24
|
+
# @return [KHL::HTTP::Response]
|
25
|
+
def create(guild_id, options = {})
|
26
|
+
post(options.merge(guild_id: guild_id))
|
27
|
+
end
|
28
|
+
|
29
|
+
# 更新服务器角色
|
30
|
+
# @param [String] guild_id 服务器 ID
|
31
|
+
# @param [Integer] role_id 角色 ID
|
32
|
+
# @param [Hash] options 可选参数
|
33
|
+
# @option options [String] :name 角色名称
|
34
|
+
# @option options [Integer] :color 颜色
|
35
|
+
# @option options [Integer] :hoist 只能为 0 或者 1,是否把该角色的用户在用户列表排到前面
|
36
|
+
# @option options [Integer] :mentionable 只能为 0 或者 1,该角色是否可以被提及
|
37
|
+
# @option options [Integer] :permissions 权限
|
38
|
+
# @return [KHL::HTTP::Response]
|
39
|
+
def update(guild_id, role_id, options = {})
|
40
|
+
post(options.merge(guild_id: guild_id, role_id: role_id))
|
41
|
+
end
|
42
|
+
|
43
|
+
# 删除服务器角色
|
44
|
+
# @param [String] guild_id 服务器 ID
|
45
|
+
# @param [Integer] role_id 角色 ID
|
46
|
+
# @return [KHL::HTTP::Response]
|
47
|
+
def delete(guild_id, role_id)
|
48
|
+
post(guild_id: guild_id, role_id: role_id)
|
49
|
+
end
|
50
|
+
|
51
|
+
# 赋予用户角色
|
52
|
+
# @param [String] guild_id 服务器 ID
|
53
|
+
# @param [String] user_id 用户 ID
|
54
|
+
# @param [Integer] role_id 角色 ID
|
55
|
+
# @return [KHL::HTTP::Response]
|
56
|
+
def grant(guild_id, user_id, role_id)
|
57
|
+
post(guild_id: guild_id, user_id: user_id, role_id: role_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# 删除用户角色
|
61
|
+
# @param [String] guild_id 服务器 ID
|
62
|
+
# @param [String] user_id 用户 ID
|
63
|
+
# @param [Integer] role_id 角色 ID
|
64
|
+
# @return [KHL::HTTP::Response]
|
65
|
+
def revoke(guild_id, user_id, role_id)
|
66
|
+
post(guild_id: guild_id, user_id: user_id, role_id: role_id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 亲密度相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/intimacy
|
9
|
+
class Intimacy < Base
|
10
|
+
# 获取用户亲密度
|
11
|
+
# @param [String] user_id 用户 ID
|
12
|
+
# @return [KHL::HTTP::Response]
|
13
|
+
def index(user_id)
|
14
|
+
get(user_id: user_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
# 更新用户亲密度
|
18
|
+
# @param [String] user_id 用户 ID
|
19
|
+
# @param [Hash] options 可选参数
|
20
|
+
# @option options [Integer] :score 亲密度,0-2200
|
21
|
+
# @option options [String] :social_info 机器人与用户的社交信息,500 字以内
|
22
|
+
# @option options [String] :img_id 表情 ID
|
23
|
+
# @return [KHL::HTTP::Response]
|
24
|
+
def update(user_id, options = {})
|
25
|
+
post(options.merge(user_id: user_id))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 邀请相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/invite
|
9
|
+
class Invite < Base
|
10
|
+
# 获取邀请列表
|
11
|
+
# @param [Hash] options 可选参数
|
12
|
+
# @option options [String] :guild_id 服务器 ID
|
13
|
+
# @option options [String] :channel_id 频道 ID
|
14
|
+
# @option options [Integer] :page 页数
|
15
|
+
# @option options [Integer] :page_size 每页数据数量
|
16
|
+
# @return [KHL::HTTP::Response]
|
17
|
+
def list(options = {})
|
18
|
+
get(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# 创建邀请链接
|
22
|
+
# @option options [String] :guild_id 服务器 ID
|
23
|
+
# @option options [String] :channel_id 频道 ID
|
24
|
+
# @option options [Integer] :duration 邀请链接有效时长(秒),默认 7 天。
|
25
|
+
# 可选值: 0(永不)、1800(0.5 小时)、3600(1 小时)、21600(6 小时)、43200(12小时)、86400(1 天)、604800(7 天)
|
26
|
+
# @option options [Integer] :setting_times 设置的次数,默认-1。可选值:-1(无限制)、1、5、10、25、50、100
|
27
|
+
# @return [KHL::HTTP::Response]
|
28
|
+
def create(options = {})
|
29
|
+
post(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# 删除邀请链接
|
33
|
+
# @param [String] url_code 邀请码
|
34
|
+
# @param [Hash] options 可选参数
|
35
|
+
# @option options [String] :guild_id 服务器 ID
|
36
|
+
# @option options [String] :channel_id 频道 ID
|
37
|
+
# @return [KHL::HTTP::Response]
|
38
|
+
def delete(url_code, options = {})
|
39
|
+
post(options.merge(url_code: url_code))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 频道消息相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/message
|
9
|
+
class Message < Base
|
10
|
+
# 获取频道聊天消息列表
|
11
|
+
# @note 此接口非标准分页,需要根据参考消息来查询相邻分页的消息
|
12
|
+
# @param [String] target_id 频道 ID
|
13
|
+
# @param [Hash] options 可选参数
|
14
|
+
# @option options [String] :msg_id 参考消息 ID,不传则查询最新消息
|
15
|
+
# @option options [Integer] :pin 只能为 0 或者 1,是否查询置顶消息。置顶消息只支持查询最新的消息
|
16
|
+
# @option options [String] :flag 查询模式,有三种模式可以选择 before、around、after。不传则默认查询最新的消息
|
17
|
+
# @option options [Integer] :page_size 当前分页消息数量,默认 50
|
18
|
+
# @return [KHL::HTTP::Response]
|
19
|
+
def list(target_id, options = {})
|
20
|
+
get(options.merge(target_id: target_id))
|
21
|
+
end
|
22
|
+
|
23
|
+
# 获取频道聊天消息详情
|
24
|
+
# @param [String] msg_id 消息 ID
|
25
|
+
# @return [KHL::HTTP::Response]
|
26
|
+
def view(msg_id)
|
27
|
+
get(msg_id: msg_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
# 发送频道聊天消息
|
31
|
+
# @note 此接口与频道相关接口下的 "发送频道聊天消息" 功能相同
|
32
|
+
# @warning 强列建议过滤掉机器人发送的消息,再进行回应。否则会很容易形成两个机器人循环自言自语导致发送量过大,进而导致机器人被封禁。如果确实需要机器人联动的情况,慎重进行处理,防止形成循环
|
33
|
+
# @param [String] target_id 频道 ID
|
34
|
+
# @param [String] content 消息内容
|
35
|
+
# @param [Hash] options 可选参数
|
36
|
+
# @option options [Integer] :type 消息类型,不传默认为 1,代表文本类型。9 代表 kmarkdown 消息,10 代表卡片消息
|
37
|
+
# @option options [String] :quote 回复某条消息的 msg_id
|
38
|
+
# @option options [String] :nonce 随机字符串,服务端不做处理,原样返回
|
39
|
+
# @option options [String] :temp_target_id 用户 ID,如果传了,代表该消息是临时消息,该消息不会存数据库,但是会在频道内只给该用户推送临时消息。用于在频道内针对用户的操作进行单独的回应通知等
|
40
|
+
# @return [KHL::HTTP::Response]
|
41
|
+
def create(target_id, content, options = {})
|
42
|
+
post(options.merge(target_id: target_id, content: content))
|
43
|
+
end
|
44
|
+
|
45
|
+
# 更新频道聊天消息
|
46
|
+
# @note 目前支持消息 type 为 9、10 的修改,即 KMarkdown 和 CardMessage
|
47
|
+
# @param [String] msg_id 消息 ID
|
48
|
+
# @param [String] content 消息内容
|
49
|
+
# @param [Hash] options 可选参数
|
50
|
+
# @option options [String] :quote 回复某条消息的 msg_id。如果为空,则代表删除回复,不传则无影响
|
51
|
+
# @option options [String] :temp_target_id 用户 ID,针对特定用户临时更新消息,必须是正常消息才能更新。与发送临时消息概念不同,但同样不保存数据库
|
52
|
+
# @return [KHL::HTTP::Response]
|
53
|
+
def update(msg_id, content, options = {})
|
54
|
+
post(options.merge(msg_id: msg_id, content: content))
|
55
|
+
end
|
56
|
+
|
57
|
+
# 删除频道聊天消息
|
58
|
+
# @note 普通用户只能删除自己的消息,有权限的用户可以删除权限范围内他人的消息
|
59
|
+
# @param [String] msg_id 消息 ID
|
60
|
+
# @return [KHL::HTTP::Response]
|
61
|
+
def delete(msg_id)
|
62
|
+
post(msg_id: msg_id)
|
63
|
+
end
|
64
|
+
|
65
|
+
# 获取频道消息某回应的用户列表
|
66
|
+
# @param [String] msg_id 频道消息 ID
|
67
|
+
# @param [String] emoji Emoji ID,可以为 GuilEmoji 或者 Emoji,注意:在 GET 中,应该进行 urlencode
|
68
|
+
# @return [KHL::HTTP::Response]
|
69
|
+
def reaction_list(msg_id, emoji)
|
70
|
+
get(msg_id: msg_id, emoji: emoji)
|
71
|
+
end
|
72
|
+
|
73
|
+
# 给某个消息添加回应
|
74
|
+
# @param [String] msg_id 频道消息 ID
|
75
|
+
# @param [String] emoji Emoji ID,可以为 GuilEmoji 或者 Emoji,注意:在 GET 中,应该进行 urlencode
|
76
|
+
# @return [KHL::HTTP::Response]
|
77
|
+
def add_reaction(msg_id, emoji)
|
78
|
+
post(msg_id: msg_id, emoji: emoji)
|
79
|
+
end
|
80
|
+
|
81
|
+
# 删除消息的某个回应
|
82
|
+
# @param [String] msg_id 频道消息 ID
|
83
|
+
# @param [String] emoji Emoji ID,可以为 GuilEmoji 或者 Emoji,注意:在 GET 中,应该进行 urlencode
|
84
|
+
# @param [Hash] options 可选参数
|
85
|
+
# @option options [String] :user_id 用户 ID, 如果不填则为自己的 ID。删除别人的回应需要有管理频道消息的权限
|
86
|
+
# @return [KHL::HTTP::Response]
|
87
|
+
def delete_reaction(msg_id, emoji, options = {})
|
88
|
+
post(options.merge(msg_id: msg_id, emoji: emoji))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KHL
|
4
|
+
module HTTP
|
5
|
+
class Response
|
6
|
+
attr_reader :http_code, :body
|
7
|
+
|
8
|
+
# @param [Net::HTTPResponse] raw_response The raw HTTP response
|
9
|
+
def initialize(raw_response)
|
10
|
+
@raw_response = raw_response
|
11
|
+
@http_code = raw_response.code.to_i
|
12
|
+
@body = JSON.parse(@raw_response.body)
|
13
|
+
end
|
14
|
+
|
15
|
+
def data
|
16
|
+
@body["data"]
|
17
|
+
end
|
18
|
+
|
19
|
+
# The code in the response body
|
20
|
+
def code
|
21
|
+
@body["code"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def max_request_limit
|
25
|
+
@raw_response["X-Rate-Limit-Limit"].to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def remain_request_limit
|
29
|
+
@raw_response["X-Rate-Limit-Remaining"].to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset_limit_time
|
33
|
+
@raw_response["X-Rate-Limit-Reset"].to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def limit_bucket
|
37
|
+
@raw_response["X-Rate-Limit-Bucket"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def limit?
|
41
|
+
@http_code == 429 || !@raw_response["X-Rate-Limit-Global"].nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
def success?
|
45
|
+
http_code == 200 && code.zero?
|
46
|
+
end
|
47
|
+
|
48
|
+
def error?
|
49
|
+
!success?
|
50
|
+
end
|
51
|
+
|
52
|
+
def message
|
53
|
+
@body["message"]
|
54
|
+
end
|
55
|
+
|
56
|
+
def page
|
57
|
+
data.dig("meta", "page") || 0
|
58
|
+
end
|
59
|
+
|
60
|
+
def page_size
|
61
|
+
data.dig("meta", "page_size") || 0
|
62
|
+
end
|
63
|
+
|
64
|
+
def page_total
|
65
|
+
data.dig("meta", "total") || 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 用户相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/user
|
9
|
+
class User < Base
|
10
|
+
# 获取当前用户信息
|
11
|
+
# @return [KHL::HTTP::Response]
|
12
|
+
def me
|
13
|
+
get
|
14
|
+
end
|
15
|
+
|
16
|
+
# 获取目标用户信息
|
17
|
+
# @param [String] user_id 用户 ID
|
18
|
+
# @param [Hash] options 可选参数
|
19
|
+
# @option options [String] :guild_id 服务器 ID
|
20
|
+
# @return [KHL::HTTP::Response]
|
21
|
+
def view(user_id, options = {})
|
22
|
+
get(options.merge(user_id: user_id))
|
23
|
+
end
|
24
|
+
|
25
|
+
# 下线机器人
|
26
|
+
# @return [KHL::HTTP::Response]
|
27
|
+
def offline
|
28
|
+
post
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module KHL
|
6
|
+
module HTTP
|
7
|
+
# 私信聊天会话相关接口
|
8
|
+
# https://developer.kaiheila.cn/doc/http/user-chat
|
9
|
+
class UserChat < Base
|
10
|
+
# 获取私信聊天会话列表
|
11
|
+
# @param [Hash] options 可选参数
|
12
|
+
# @option options [Integer] :page 页数
|
13
|
+
# @option options [Integer] :page_size 每页数据数量
|
14
|
+
# @return [KHL::HTTP::Response]
|
15
|
+
def list(options = {})
|
16
|
+
get(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# 获取私信聊天会话详情
|
20
|
+
# @param [String] chat_code 私聊会话 Code
|
21
|
+
# @return [KHL::HTTP::Response]
|
22
|
+
def view(chat_code)
|
23
|
+
get(chat_code: chat_code)
|
24
|
+
end
|
25
|
+
|
26
|
+
# 创建私信聊天会话
|
27
|
+
# @param [String] target_id 用户 ID
|
28
|
+
# @return [KHL::HTTP::Response]
|
29
|
+
def create(target_id)
|
30
|
+
post(target_id: target_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
# 删除私信聊天会话
|
34
|
+
# @note 只能删除自己的消息
|
35
|
+
# @param [String] target_id 用户 ID
|
36
|
+
# @return [KHL::HTTP::Response]
|
37
|
+
def delete(target_id)
|
38
|
+
post(target_id: target_id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/khl/version.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cgi"
|
4
|
+
require "eventmachine"
|
5
|
+
require "faye/websocket"
|
6
|
+
require "json"
|
7
|
+
require "uri"
|
8
|
+
require "zlib"
|
9
|
+
|
10
|
+
require_relative "message"
|
11
|
+
|
12
|
+
module KHL
|
13
|
+
module WebSocket
|
14
|
+
# Client for the KHL WebSocket API
|
15
|
+
# @example
|
16
|
+
# client = KHL::WebSocket.new(token: "bot_token")
|
17
|
+
# Thread.new { client.run }
|
18
|
+
# client.message.pop # Get message from queue
|
19
|
+
class Client
|
20
|
+
attr_reader :config, :url, :messages, :state
|
21
|
+
|
22
|
+
# @param config [String] :token Bot token
|
23
|
+
# @option config [String] :token_type Token type
|
24
|
+
# @option config [String] :language Language
|
25
|
+
# @option config [Boolean] :compress Compress
|
26
|
+
def initialize(config)
|
27
|
+
config[:compress] ||= false
|
28
|
+
|
29
|
+
@config = config
|
30
|
+
@http_gateway = HTTP::Gateway.new(config)
|
31
|
+
@url = gateway_url
|
32
|
+
@messages = Queue.new
|
33
|
+
@sn = 0
|
34
|
+
@state = :disconnected
|
35
|
+
@ping_signal = false
|
36
|
+
@resume_signal = false
|
37
|
+
@ws = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Only receive messages from the server
|
41
|
+
def run
|
42
|
+
EM.run {
|
43
|
+
Signal.trap("INT") { EventMachine.stop }
|
44
|
+
Signal.trap("TERM") { EventMachine.stop }
|
45
|
+
|
46
|
+
@ws = Faye::WebSocket::Client.new(gateway_url)
|
47
|
+
@state = :connecting
|
48
|
+
|
49
|
+
EventMachine.add_periodic_timer(30) do
|
50
|
+
EventMachine.add_timer(6) do
|
51
|
+
if @ping_signal
|
52
|
+
@state = :timeout
|
53
|
+
|
54
|
+
unless reconnect
|
55
|
+
unless resume
|
56
|
+
@state = :disconnected
|
57
|
+
EventMachine.stop
|
58
|
+
rerun
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Send ping message
|
65
|
+
@ws.send({s: 2, sn: @sn}.to_json)
|
66
|
+
@ping_signal = true
|
67
|
+
end
|
68
|
+
|
69
|
+
@ws.on :message do |event|
|
70
|
+
raw = config[:compress] ? Zlib::Inflate.inflate(event.data.pack("C*")) : event.data
|
71
|
+
msg = Message.parse(raw)
|
72
|
+
|
73
|
+
if msg.hello?
|
74
|
+
@state = :connected
|
75
|
+
elsif msg.pong?
|
76
|
+
@ping_signal = false
|
77
|
+
elsif msg.resume_ack?
|
78
|
+
@resume_signal = false
|
79
|
+
elsif msg.reconnect?
|
80
|
+
@state = :reconnecting
|
81
|
+
rerun
|
82
|
+
elsif msg.event?
|
83
|
+
messages << msg
|
84
|
+
@sn = msg.sn
|
85
|
+
end
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def gateway_url
|
93
|
+
response = @http_gateway.index
|
94
|
+
return nil unless response.success?
|
95
|
+
|
96
|
+
uri = URI(response.data["url"])
|
97
|
+
query = CGI.parse(uri.query)
|
98
|
+
query["compress"] = config[:compress] ? 1 : 0
|
99
|
+
uri.query = URI.encode_www_form(query)
|
100
|
+
uri.to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
def reconnect
|
104
|
+
@state = :reconnecting
|
105
|
+
@ping_signal = false
|
106
|
+
|
107
|
+
@ws.send({s: 2, sn: @sn}.to_json)
|
108
|
+
@ping_signal = true
|
109
|
+
sleep(2)
|
110
|
+
return true unless @ping_signal
|
111
|
+
|
112
|
+
@ws.send({s: 2, sn: @sn}.to_json)
|
113
|
+
@ping_signal = true
|
114
|
+
sleep(4)
|
115
|
+
return true unless @ping_signal
|
116
|
+
|
117
|
+
false
|
118
|
+
end
|
119
|
+
|
120
|
+
def resume
|
121
|
+
@state = :resuming
|
122
|
+
@resume_signal = false
|
123
|
+
|
124
|
+
@ws.send({s: 4, sn: @sn}.to_json)
|
125
|
+
@resume_signal = true
|
126
|
+
sleep(8)
|
127
|
+
return true unless @resume_signal
|
128
|
+
|
129
|
+
@ws.send({s: 4, sn: @sn}.to_json)
|
130
|
+
@resume_signal = true
|
131
|
+
sleep(16)
|
132
|
+
return true unless @resume_signal
|
133
|
+
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
def rerun
|
138
|
+
@url = gateway_url
|
139
|
+
@messages.clear
|
140
|
+
@sn = 0
|
141
|
+
@state = :disconnected
|
142
|
+
@ping_signal = false
|
143
|
+
@resume_signal = false
|
144
|
+
@ws = nil
|
145
|
+
|
146
|
+
EventMachine.stop
|
147
|
+
run
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|