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.
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KHL
4
+ VERSION = "1.0.0"
5
+ end
@@ -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