khl 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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