rubirai 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/CI.yml +64 -0
  4. data/.github/workflows/docs.yml +32 -0
  5. data/.github/workflows/pull_request.yml +34 -0
  6. data/.gitignore +145 -0
  7. data/.rubocop.yml +41 -0
  8. data/.yardopts +7 -0
  9. data/Gemfile +19 -0
  10. data/LICENSE +661 -0
  11. data/README.md +24 -0
  12. data/Rakefile +16 -0
  13. data/examples/helper.rb +3 -0
  14. data/examples/listener_example.rb +25 -0
  15. data/examples/simple_example.rb +24 -0
  16. data/lib/rubirai.rb +66 -0
  17. data/lib/rubirai/auth.rb +73 -0
  18. data/lib/rubirai/errors.rb +26 -0
  19. data/lib/rubirai/event_recv.rb +83 -0
  20. data/lib/rubirai/event_resp.rb +129 -0
  21. data/lib/rubirai/events/bot_events.rb +53 -0
  22. data/lib/rubirai/events/event.rb +115 -0
  23. data/lib/rubirai/events/message_events.rb +77 -0
  24. data/lib/rubirai/events/request_events.rb +35 -0
  25. data/lib/rubirai/events/rubirai_events.rb +17 -0
  26. data/lib/rubirai/listener.rb +44 -0
  27. data/lib/rubirai/listing.rb +37 -0
  28. data/lib/rubirai/management.rb +200 -0
  29. data/lib/rubirai/message.rb +84 -0
  30. data/lib/rubirai/messages/message.rb +306 -0
  31. data/lib/rubirai/messages/message_chain.rb +119 -0
  32. data/lib/rubirai/multipart.rb +44 -0
  33. data/lib/rubirai/objects/group.rb +23 -0
  34. data/lib/rubirai/objects/info.rb +71 -0
  35. data/lib/rubirai/objects/user.rb +30 -0
  36. data/lib/rubirai/plugin_info.rb +19 -0
  37. data/lib/rubirai/retcode.rb +18 -0
  38. data/lib/rubirai/session.rb +26 -0
  39. data/lib/rubirai/utils.rb +62 -0
  40. data/lib/rubirai/version.rb +9 -0
  41. data/misc/common.css +11 -0
  42. data/rubirai.gemspec +24 -0
  43. data/spec/auth_spec.rb +118 -0
  44. data/spec/error_spec.rb +30 -0
  45. data/spec/events/event_spec.rb +78 -0
  46. data/spec/message_spec.rb +12 -0
  47. data/spec/messages/message_chain_spec.rb +32 -0
  48. data/spec/messages/message_spec.rb +171 -0
  49. data/spec/plugin_info_spec.rb +28 -0
  50. data/spec/rubirai_bot_spec.rb +45 -0
  51. data/spec/spec_helper.rb +31 -0
  52. data/spec/utils_spec.rb +70 -0
  53. metadata +121 -0
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/events/event'
4
+
5
+ module Rubirai
6
+ class BotEvent < Event
7
+ set_event nil, :qq
8
+ end
9
+
10
+ class BotOnlineEvent < BotEvent
11
+ set_event :BotOnlineEvent
12
+ end
13
+
14
+ class BotActiveOfflineEvent < BotEvent
15
+ set_event :BotOfflineEventActive
16
+ end
17
+
18
+ class BotForcedOfflineEvent < BotEvent
19
+ set_event :BotOfflineEventForce
20
+ end
21
+
22
+ class BotDroppedEvent < BotEvent
23
+ set_event :BotOfflineEventDropped
24
+ end
25
+
26
+ class BotReloginEvent < BotEvent
27
+ set_event :BotReloginEvent
28
+ end
29
+
30
+ class BotGroupPermissionChangedEvent < BotEvent
31
+ set_event :BotGroupPermissionChangeEvent, :origin, :new, :current, :group
32
+ end
33
+
34
+ class BotMutedEvent < BotEvent
35
+ set_event :BotMuteEvent, :duration_seconds, :operator
36
+ end
37
+
38
+ class BotUnmutedEvent < BotEvent
39
+ set_event :BotUnmuteEvent, :operator
40
+ end
41
+
42
+ class BotJoinGroupEvent < BotEvent
43
+ set_event :BotJoinGroupEvent, :group
44
+ end
45
+
46
+ class BotActiveLeaveEvent < BotEvent
47
+ set_event :BotLeaveEventActive, :group
48
+ end
49
+
50
+ class BotKickedEvent < BotEvent
51
+ set_event :BotLeaveEventKick, :group
52
+ end
53
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/objects/group'
4
+ require 'rubirai/utils'
5
+
6
+ module Rubirai
7
+ # @abstract
8
+ class Event
9
+ # @private
10
+ def self.gen_descendants
11
+ descs = ObjectSpace.each_object(Class).select do |klass|
12
+ klass < self
13
+ end
14
+
15
+ metaclass.instance_eval do
16
+ define_method(:descendants) do
17
+ descs
18
+ end
19
+ leaf_descs = descs.filter { |d| d.respond_to? :type }
20
+ all_types = leaf_descs.map(&:type)
21
+ define_method(:all_types) do
22
+ all_types
23
+ end
24
+ type_map = leaf_descs.to_h { |d| [d.type, d] }
25
+ define_method(:type_map) do
26
+ type_map
27
+ end
28
+ end
29
+
30
+ private_class_method :descendants
31
+ end
32
+
33
+ def self.type_to_klass(type)
34
+ # noinspection RubyResolve
35
+ type_map[type.to_sym]
36
+ end
37
+
38
+ def self.valid_type?(type)
39
+ # noinspection RubyResolve
40
+ all_types.include? type
41
+ end
42
+
43
+ def self.set_event(type, *attr_keys)
44
+ attr_reader(*attr_keys)
45
+
46
+ metaclass.instance_eval do
47
+ break if type.nil?
48
+ define_method(:type) do
49
+ type
50
+ end
51
+ end
52
+
53
+ class_eval do
54
+ define_method(:initialize) do |hash, bot = nil|
55
+ # noinspection RubySuperCallWithoutSuperclassInspection
56
+ super hash, bot
57
+ hash = hash.stringify_keys
58
+ attr_keys.each do |k|
59
+ k2 = k.to_s.snake_to_camel(lower: true)
60
+ val = hash[k2]
61
+ val = case k2
62
+ when 'group'
63
+ Group.new val, bot
64
+ when 'operator', 'member'
65
+ GroupUser.new val, bot
66
+ when 'sender'
67
+ if val.key? 'group'
68
+ GroupUser.new val, bot
69
+ else
70
+ User.new val, bot
71
+ end
72
+ when 'messageChain'
73
+ MessageChain.new bot, val
74
+ else
75
+ val
76
+ end
77
+ instance_variable_set("@#{k}", val)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def self.metaclass
84
+ class << self
85
+ self
86
+ end
87
+ end
88
+
89
+ private_class_method :metaclass
90
+
91
+ # @param hash [Hash]
92
+ # @param bot [Rubirai::Bot, nil]
93
+ def self.parse(hash, bot = nil)
94
+ hash = hash.stringify_keys
95
+ type_to_klass(hash['type']).new hash, bot
96
+ end
97
+
98
+ # @!attribute [r] bot
99
+ # @return [Bot]
100
+ # @!attribute [r] raw
101
+ # The raw hash representation of the event
102
+ # @return [Hash]
103
+ attr_reader :bot, :raw
104
+
105
+ def initialize(hash, bot = nil)
106
+ @raw = hash
107
+ @bot = bot
108
+ end
109
+ end
110
+ end
111
+
112
+ require_relative 'bot_events'
113
+ require_relative 'message_events'
114
+
115
+ Rubirai::Event.gen_descendants
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/events/event'
4
+
5
+ module Rubirai
6
+ # The base class for message events
7
+ # @abstract
8
+ class MessageEvent < Event
9
+ # @!attribute [r] message_chain
10
+ # @return [MessageChain] the message chain
11
+ set_event nil, :message_chain, :sender
12
+ end
13
+
14
+ # Friend message event
15
+ class FriendMessageEvent < MessageEvent
16
+ # @!method initialize(hash, bot = nil)
17
+ # @param hash [Hash]
18
+ # @param bot [Rubirai::Bot]
19
+ # @!attribute [r] sender
20
+ # @return [User] the sender
21
+ set_event :FriendMessage
22
+ end
23
+
24
+ # Group message event
25
+ class GroupMessageEvent < MessageEvent
26
+ # @!method initialize(hash, bot = nil)
27
+ # @param hash [Hash]
28
+ # @param bot [Rubirai::Bot]
29
+ # @!attribute [r] sender
30
+ # @return [GroupUser] the sender
31
+ set_event :GroupMessage
32
+ end
33
+
34
+ # Temp message event
35
+ class TempMessageEvent < MessageEvent
36
+ # @!method initialize(hash, bot = nil)
37
+ # @param hash [Hash]
38
+ # @param bot [Rubirai::Bot]
39
+ # @!attribute [r] sender
40
+ # @return [GroupUser] the sender
41
+ set_event :TempMessage
42
+ end
43
+
44
+ # The base class for recall events
45
+ # @abstract
46
+ class RecallEvent < Event
47
+ # @!attribute [r] author_id
48
+ # @return [Integer] the author's id
49
+ # @!attribute [r] message_id
50
+ # @return [Integer] the message id
51
+ # @!attribute [r] time
52
+ # @return [Integer] the time the message is sent
53
+ set_event nil, :author_id, :message_id, :time
54
+ end
55
+
56
+ # Group recall event
57
+ class GroupRecallEvent < RecallEvent
58
+ # @!method initialize(hash, bot = nil)
59
+ # @param hash [Hash]
60
+ # @param bot [Rubirai::Bot]
61
+ # @!attribute [r] group
62
+ # @return [Group] the group
63
+ # @!attribute [r] operator
64
+ # @return [GroupUser] the operator
65
+ set_event :GroupRecallEvent, :group, :operator
66
+ end
67
+
68
+ # Friend recall event
69
+ class FriendRecallEvent < RecallEvent
70
+ # @!method initialize(hash, bot = nil)
71
+ # @param hash [Hash]
72
+ # @param bot [Rubirai::Bot]
73
+ # @!attribute [r] operator
74
+ # @return [Integer] the operator id
75
+ set_event :FriendRecallEvent, :operator
76
+ end
77
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/events/event'
4
+
5
+ module Rubirai
6
+ class RequestEvent < Event
7
+ # @!attribute [r] event_id
8
+ # @return [Integer] the event id
9
+ # @!attribute [r] from_id
10
+ # @return [Integer] the id of the sender of the request
11
+ # @!attribute [r] group_id
12
+ # @return [Integer] the group where the request is from. 0 if not from group
13
+ # @!attribute [r] nick
14
+ # @return [String] the nickname of the sender of the request
15
+ # @!attribute [r] message
16
+ # @return [String] the message from the sender
17
+ set_event nil, :event_id, :from_id, :group_id, :nick, :message
18
+ end
19
+
20
+ class NewFriendRequestEvent < RequestEvent
21
+ set_event :NewFriendRequestEvent
22
+ end
23
+
24
+ class JoinGroupRequestEvent < RequestEvent
25
+ # @!attribute [r] group_name
26
+ # @return [String] the group name
27
+ set_event :MemberJoinRequestEvent, :group_name
28
+ end
29
+
30
+ class BotInvitedToGroupEvent < RequestEvent
31
+ # @!attribute [r] group_name
32
+ # @return [String] the group name
33
+ set_event :BotInvitedJoinGroupRequestEvent, :group_name
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/events/event'
4
+
5
+ module Rubirai
6
+ class RubiraiErrorEvent < Event
7
+ attr_reader :err
8
+
9
+ # An error event just for internal use
10
+ #
11
+ # @param err [RuntimeError] the error object
12
+ def initialize(err, bot = nil)
13
+ super nil, bot
14
+ @err = err
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+ require 'rubirai/events/rubirai_events'
5
+
6
+ module Rubirai
7
+ class Bot
8
+ def start_listen(interval, is_blocking: false, ignore_error: false)
9
+ raise RubiraiError, 'listener is already running' if @listener&.running?
10
+ @listener_stop_event = Concurrent::Event.new if is_blocking
11
+ bot = self
12
+ @listener = Concurrent::TimerTask.new(execution_interval: interval) do
13
+ loop do
14
+ events = fetch_message
15
+ events.each do |e|
16
+ @listener_funcs.each { |f| f.call e }
17
+ rescue RuntimeError => e
18
+ @listener_funcs.each { |f| f.call RubiraiErrorEvent.new(e, bot) unless ignore_error }
19
+ end
20
+ break if events.length < 10
21
+ rescue RuntimeError => e
22
+ @listener_funcs.each { |f| f.call RubiraiErrorEvent.new(e, bot) unless ignore_error }
23
+ break
24
+ end
25
+ end
26
+ @listener.execute
27
+ @listener_stop_event.wait if is_blocking
28
+ end
29
+
30
+ def add_listener(&listener_block)
31
+ @listener_funcs << listener_block
32
+ end
33
+
34
+ def clear_listener
35
+ @listener_funcs.clear
36
+ end
37
+
38
+ def stop_listen
39
+ @listener.shutdown
40
+ @listener_stop_event&.set
41
+ @listener_stop_event = nil
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/objects/user'
4
+ require 'rubirai/objects/group'
5
+
6
+ module Rubirai
7
+ class Bot
8
+ # Get friend list of the bot
9
+ # @return [Array<User>] list of friends
10
+ def friend_list
11
+ resp = call :get, '/friendList', params: {
12
+ sessionKey: @session
13
+ }
14
+ resp.map { |friend| User.new(friend, self) }
15
+ end
16
+
17
+ # Get group list of the bot
18
+ # @return [Array<Group>] list of groups
19
+ def group_list
20
+ resp = call :get, '/groupList', params: {
21
+ sessionKey: @session
22
+ }
23
+ resp.map { |group| Group.new(group, self) }
24
+ end
25
+
26
+ # Get member list of a group
27
+ # @param group_id [Integer, String] group id
28
+ # @return [Array<GroupUser>] list of members
29
+ def member_list(group_id)
30
+ resp = call :get, '/memberList', params: {
31
+ sessionKey: @session,
32
+ target: group_id
33
+ }
34
+ resp.map { |member| GroupUser.new(member, self) }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/objects/info'
4
+
5
+ module Rubirai
6
+ class Bot
7
+ # Mute a group member
8
+ #
9
+ # @param group_id [Integer] group id
10
+ # @param member_id [Integer] member id
11
+ # @param time [Integer] the mute time
12
+ def mute(group_id, member_id, time = 0)
13
+ call :post, '/mute', json: {
14
+ sessionKey: @session,
15
+ target: group_id,
16
+ memberId: member_id,
17
+ time: time
18
+ }
19
+ nil
20
+ end
21
+
22
+ # Unmute a group member
23
+ #
24
+ # @param group_id [Integer] group id
25
+ # @param member_id [Integer] member id
26
+ # @return [void]
27
+ def unmute(group_id, member_id)
28
+ call :post, '/unmute', json: {
29
+ sessionKey: @session,
30
+ target: group_id,
31
+ memberId: member_id
32
+ }
33
+ nil
34
+ end
35
+
36
+ # Kick a member from a group
37
+ #
38
+ # @param group_id [Integer] group id
39
+ # @param member_id [Integer] member id
40
+ # @param msg [String, nil] the message for the kicked
41
+ # @return [void]
42
+ def kick(group_id, member_id, msg = nil)
43
+ json = {
44
+ sessionKey: @session,
45
+ target: group_id,
46
+ memberId: member_id
47
+ }
48
+ json[:msg] = msg if msg
49
+ call :post, '/kick', json: json
50
+ nil
51
+ end
52
+
53
+ # Quit a group
54
+ #
55
+ # @param group_id [Integer] group id
56
+ # @return [void]
57
+ def quit(group_id)
58
+ call :post, '/quit', json: {
59
+ sessionKey: @session,
60
+ target: group_id
61
+ }
62
+ nil
63
+ end
64
+
65
+ # Mute all group
66
+ #
67
+ # @param group_id [Integer] group id
68
+ # @return [void]
69
+ def mute_all(group_id)
70
+ call :post, '/muteAll', json: {
71
+ sessionKey: @session,
72
+ target: group_id
73
+ }
74
+ nil
75
+ end
76
+
77
+ def unmute_all(group_id)
78
+ call :post, '/unmuteAll', json: {
79
+ sessionKey: @session,
80
+ target: group_id
81
+ }
82
+ nil
83
+ end
84
+
85
+ def get_group_config(group_id)
86
+ resp = call :get, '/groupConfig', params: {
87
+ sessionKey: @session,
88
+ target: group_id
89
+ }
90
+ GroupConfig.new resp, self
91
+ end
92
+
93
+ # Set group config
94
+ #
95
+ # @param group_id [Integer] group id
96
+ # @param config [GroupConfig, Hash{String => Object}] the configuration
97
+ # @return [void]
98
+ def set_group_config(group_id, config)
99
+ config.must_be! [GroupConfig, Hash], RubiraiError, 'must be GroupConfig or Hash'
100
+ config.stringify_keys! if config.is_a? Hash
101
+ config = config.to_h if config.is_a? GroupConfig
102
+ call :post, '/groupConfig', json: {
103
+ sessionKey: @session,
104
+ target: group_id,
105
+ config: config
106
+ }
107
+ nil
108
+ end
109
+
110
+ def get_member_info(group_id, member_id)
111
+ resp = call :get, '/memberInfo', params: {
112
+ sessionKey: @session,
113
+ target: group_id,
114
+ memberId: member_id
115
+ }
116
+ MemberInfo.new resp, self
117
+ end
118
+
119
+ def set_member_info(group_id, member_id, info)
120
+ info.must_be! [MemberInfo, Hash], RubiraiError, 'must be MemberInfo or Hash'
121
+ info.stringify_keys! if info.is_a? Hash
122
+ info = info.to_h if info.is_a? MemberInfo
123
+ call :post, '/memberInfo', json: {
124
+ sessionKey: @session,
125
+ target: group_id,
126
+ memberId: member_id,
127
+ info: info
128
+ }
129
+ nil
130
+ end
131
+
132
+ def get_group_file_list(group_id, dir = nil)
133
+ resp = call :get, '/groupFileList', params: {
134
+ sessionKey: @session,
135
+ target: group_id,
136
+ dir: dir
137
+ }.compact
138
+ resp.must_be! Array # assert resp is Array
139
+ resp.map { |f| GroupFileSimple.new(f, self) }
140
+ end
141
+
142
+ # Get the info about a group file
143
+ # @param group_id [Integer] the group id
144
+ # @param file_id [String] the file id, e.g. `/xxx-xxx-xxx-xxx`
145
+ def get_group_file_info(group_id, file_id)
146
+ resp = call :get, '/groupFileInfo', params: {
147
+ sessionKey: @session,
148
+ target: group_id,
149
+ id: file_id
150
+ }
151
+ GroupFile.new resp, self
152
+ end
153
+
154
+ def rename_group_file(group_id, file_id, new_name)
155
+ call :post, '/groupFileRename', json: {
156
+ sessionKey: @session,
157
+ target: group_id,
158
+ id: file_id,
159
+ rename: new_name
160
+ }
161
+ nil
162
+ end
163
+
164
+ def group_mkdir(group_id, dir)
165
+ call :post, '/groupMkdir', json: {
166
+ sessionKey: @session,
167
+ group: group_id,
168
+ dir: dir
169
+ }
170
+ nil
171
+ end
172
+
173
+ def group_file_mv(group_id, file_id, path)
174
+ call :post, '/groupFileMove', json: {
175
+ sessionKey: @session,
176
+ target: group_id,
177
+ id: file_id,
178
+ movePath: path
179
+ }
180
+ nil
181
+ end
182
+
183
+ def group_file_delete(group_id, file_id)
184
+ call :post, '/groupFileDelete', json: {
185
+ sessionKey: @session,
186
+ target: group_id,
187
+ id: file_id
188
+ }
189
+ nil
190
+ end
191
+
192
+ def group_set_essence(msg_id)
193
+ call :post, '/setEssence', json: {
194
+ sessionKey: @session,
195
+ target: msg_id
196
+ }
197
+ nil
198
+ end
199
+ end
200
+ end