rubirai 0.0.2
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/.github/dependabot.yml +11 -0
- data/.github/workflows/CI.yml +64 -0
- data/.github/workflows/docs.yml +32 -0
- data/.github/workflows/pull_request.yml +34 -0
- data/.gitignore +145 -0
- data/.rubocop.yml +41 -0
- data/.yardopts +7 -0
- data/Gemfile +19 -0
- data/LICENSE +661 -0
- data/README.md +24 -0
- data/Rakefile +16 -0
- data/examples/helper.rb +3 -0
- data/examples/listener_example.rb +25 -0
- data/examples/simple_example.rb +24 -0
- data/lib/rubirai.rb +66 -0
- data/lib/rubirai/auth.rb +73 -0
- data/lib/rubirai/errors.rb +26 -0
- data/lib/rubirai/event_recv.rb +83 -0
- data/lib/rubirai/event_resp.rb +129 -0
- data/lib/rubirai/events/bot_events.rb +53 -0
- data/lib/rubirai/events/event.rb +115 -0
- data/lib/rubirai/events/message_events.rb +77 -0
- data/lib/rubirai/events/request_events.rb +35 -0
- data/lib/rubirai/events/rubirai_events.rb +17 -0
- data/lib/rubirai/listener.rb +44 -0
- data/lib/rubirai/listing.rb +37 -0
- data/lib/rubirai/management.rb +200 -0
- data/lib/rubirai/message.rb +84 -0
- data/lib/rubirai/messages/message.rb +306 -0
- data/lib/rubirai/messages/message_chain.rb +119 -0
- data/lib/rubirai/multipart.rb +44 -0
- data/lib/rubirai/objects/group.rb +23 -0
- data/lib/rubirai/objects/info.rb +71 -0
- data/lib/rubirai/objects/user.rb +30 -0
- data/lib/rubirai/plugin_info.rb +19 -0
- data/lib/rubirai/retcode.rb +18 -0
- data/lib/rubirai/session.rb +26 -0
- data/lib/rubirai/utils.rb +62 -0
- data/lib/rubirai/version.rb +9 -0
- data/misc/common.css +11 -0
- data/rubirai.gemspec +24 -0
- data/spec/auth_spec.rb +118 -0
- data/spec/error_spec.rb +30 -0
- data/spec/events/event_spec.rb +78 -0
- data/spec/message_spec.rb +12 -0
- data/spec/messages/message_chain_spec.rb +32 -0
- data/spec/messages/message_spec.rb +171 -0
- data/spec/plugin_info_spec.rb +28 -0
- data/spec/rubirai_bot_spec.rb +45 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/utils_spec.rb +70 -0
- metadata +121 -0
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Rubirai
|
2
|
+
[](https://github.com/Shimogawa/rubirai/actions/workflows/CI.yml)
|
3
|
+
[](https://codecov.io/gh/Shimogawa/rubirai)
|
4
|
+
[](https://codeclimate.com/github/Shimogawa/rubirai/maintainability)
|
5
|
+
[](http://inch-ci.org/github/shimogawa/rubirai)
|
6
|
+
[](https://app.fossa.com/projects/git%2Bgithub.com%2FShimogawa%2Frubirai?ref=badge_shield)
|
7
|
+
|
8
|
+
|
9
|
+
A light-weight Mirai QQ bot http interface lib for Ruby.
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
require 'rubirai'
|
15
|
+
# assuming your mirai http api address and port
|
16
|
+
# are 127.0.0.1 and 8080
|
17
|
+
bot = Rubirai::Bot.new('127.0.0.1', '8080')
|
18
|
+
# qq and auth key
|
19
|
+
bot.login 1145141919, 'ikisugi_key'
|
20
|
+
```
|
21
|
+
|
22
|
+
|
23
|
+
## License
|
24
|
+
[](https://app.fossa.com/projects/git%2Bgithub.com%2FShimogawa%2Frubirai?ref=badge_large)
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
+
t.rspec_opts = %w[
|
6
|
+
--force-color
|
7
|
+
--format progress
|
8
|
+
--require ./spec/spec_helper.rb
|
9
|
+
]
|
10
|
+
t.pattern = 'spec/**/*_spec.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rubocop/rake_task'
|
14
|
+
RuboCop::RakeTask.new(:rubocop)
|
15
|
+
|
16
|
+
task default: %i[spec rubocop]
|
data/examples/helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require 'rubirai'
|
5
|
+
|
6
|
+
bot = Rubirai::Bot.new '127.0.0.1', 8080
|
7
|
+
|
8
|
+
puts 'Enter qq: '
|
9
|
+
qq = gets.chomp
|
10
|
+
puts 'Enter auth key: '
|
11
|
+
auth = gets.chomp
|
12
|
+
|
13
|
+
bot.login(qq, auth)
|
14
|
+
puts 'Login successful.'
|
15
|
+
|
16
|
+
bot.add_listener do |event|
|
17
|
+
puts "#{event.class} -> #{event.raw}"
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
bot.start_listen 0.5, is_blocking: true, ignore_error: false
|
22
|
+
rescue Interrupt
|
23
|
+
bot.logout
|
24
|
+
puts 'Bye'
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require 'rubirai'
|
5
|
+
|
6
|
+
bot = Rubirai::Bot.new '127.0.0.1', 8080
|
7
|
+
|
8
|
+
puts 'Enter qq: '
|
9
|
+
qq = gets.chomp
|
10
|
+
puts 'Enter auth key: '
|
11
|
+
auth = gets.chomp
|
12
|
+
|
13
|
+
bot.login(qq, auth)
|
14
|
+
|
15
|
+
puts 'Login successful. Enter qq to send message to:'
|
16
|
+
target = gets.chomp
|
17
|
+
|
18
|
+
bot.send_friend_msg(
|
19
|
+
target,
|
20
|
+
'hello', ' world!',
|
21
|
+
Rubirai::ImageMessage(url: 'https://i0.hdslb.com/bfs/album/67fc4e6b417d9c68ef98ba71d5e79505bbad97a1.png')
|
22
|
+
)
|
23
|
+
|
24
|
+
bot.logout
|
data/lib/rubirai.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/errors'
|
4
|
+
require 'rubirai/utils'
|
5
|
+
|
6
|
+
# Rubirai is a library for connecting Mirai http api.
|
7
|
+
module Rubirai
|
8
|
+
require 'http'
|
9
|
+
|
10
|
+
# Bot represents a QQ bot at mirai side. All functions are API calls to the http plugin.
|
11
|
+
class Bot
|
12
|
+
# @!attribute [r] base_uri
|
13
|
+
# @return [String] the base uri of mirai-api-http which the bot will send messages to
|
14
|
+
# @!attribute [r] session
|
15
|
+
# @return [String] the session key
|
16
|
+
# @!attribute [r] qq
|
17
|
+
# @return [String, Integer] the qq of the bot
|
18
|
+
attr_reader :base_uri, :session, :qq
|
19
|
+
|
20
|
+
# Initializes the bot
|
21
|
+
#
|
22
|
+
# @param host [String] the host (IP or domain)
|
23
|
+
# @param port [String, Integer, nil] the port number (default is 80 for http)
|
24
|
+
def initialize(host, port = nil)
|
25
|
+
@base_uri = "http://#{host}#{":#{port}" if port}"
|
26
|
+
@listener_funcs = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def gen_uri(path)
|
30
|
+
URI.join(base_uri, path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.ensure_type_in(type, *types)
|
34
|
+
types = types.map { |x| x.to_s.downcase }
|
35
|
+
type.to_s.downcase.must_be_one_of! types, RubiraiError, "not valid type: should be one of #{types}"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def call(method, path, **kwargs)
|
41
|
+
return unless %i[get post].include?(method) && HTTP.respond_to?(method)
|
42
|
+
|
43
|
+
resp = HTTP.send method, gen_uri(path), kwargs
|
44
|
+
raise(HttpResponseError, resp.code) unless resp.status.success?
|
45
|
+
|
46
|
+
body = JSON.parse(resp.body)
|
47
|
+
if (body.is_a? Hash) && (body.include? 'code') && (body['code'] != 0)
|
48
|
+
raise MiraiError.new(body['code'], body['msg'] || body['errorMessage'])
|
49
|
+
end
|
50
|
+
|
51
|
+
body
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require 'rubirai/auth'
|
57
|
+
require 'rubirai/event_recv'
|
58
|
+
require 'rubirai/listener'
|
59
|
+
require 'rubirai/listing'
|
60
|
+
require 'rubirai/management'
|
61
|
+
require 'rubirai/message'
|
62
|
+
require 'rubirai/multipart'
|
63
|
+
require 'rubirai/plugin_info'
|
64
|
+
require 'rubirai/retcode'
|
65
|
+
require 'rubirai/session'
|
66
|
+
require 'rubirai/version'
|
data/lib/rubirai/auth.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rubirai
|
4
|
+
class Bot
|
5
|
+
# Start authentication. Will store the session.
|
6
|
+
# @param auth_key [String] the auth key defined in config file
|
7
|
+
# @return [String] the session key which will also be stored in the bot
|
8
|
+
def auth(auth_key)
|
9
|
+
v = call :post, '/auth', json: { "authKey": auth_key }
|
10
|
+
@session = v['session']
|
11
|
+
end
|
12
|
+
|
13
|
+
# Verify and start a session. Also bind the session to a bot with the qq id.
|
14
|
+
# @param qq [String, Integer] qq id
|
15
|
+
# @param session [String, nil] the session key. Set to `nil` will use the saved credentials.
|
16
|
+
# @return [void]
|
17
|
+
def verify(qq, session = nil)
|
18
|
+
check qq, session
|
19
|
+
|
20
|
+
call :post, '/verify', json: { "sessionKey": @session || session, "qq": qq.to_i }
|
21
|
+
@session = session if session
|
22
|
+
@qq = qq
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Release a session.
|
27
|
+
# Only fill in the arguments when you want to control another bot on the same Mirai process.
|
28
|
+
# @param qq [String, Integer, nil] qq id. Set to `nil` will use the logged in bot id.
|
29
|
+
# @param session [String, nil] the session key. Set to `nil` will use the logged in credentials.
|
30
|
+
# @return [void]
|
31
|
+
def release(qq = nil, session = nil)
|
32
|
+
qq ||= @qq
|
33
|
+
raise RubiraiError, "not same qq: #{qq} and #{@qq}" if qq != @qq
|
34
|
+
check qq, session
|
35
|
+
|
36
|
+
call :post, '/release', json: { "sessionKey": @session || session, "qq": qq.to_i }
|
37
|
+
@session = nil
|
38
|
+
@qq = nil
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Log you in.
|
43
|
+
#
|
44
|
+
# @param qq [String, Integer] qq id
|
45
|
+
# @param auth_key [String] the auth key set in the settings file for mirai-api-http.
|
46
|
+
# @return [void]
|
47
|
+
# @see #auth
|
48
|
+
# @see #verify
|
49
|
+
def login(qq, auth_key)
|
50
|
+
auth auth_key
|
51
|
+
verify qq
|
52
|
+
end
|
53
|
+
|
54
|
+
alias connect login
|
55
|
+
|
56
|
+
# Log you out.
|
57
|
+
#
|
58
|
+
# @return [void]
|
59
|
+
# @see #release
|
60
|
+
def logout
|
61
|
+
release
|
62
|
+
end
|
63
|
+
|
64
|
+
alias disconnect logout
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def check(qq, session = nil)
|
69
|
+
raise RubiraiError, 'Wrong format for qq' unless qq.to_i.to_s == qq.to_s
|
70
|
+
raise RubiraiError, 'No session provided' unless @session || session
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/retcode'
|
4
|
+
|
5
|
+
module Rubirai
|
6
|
+
# Represent all Rubirai errors
|
7
|
+
class RubiraiError < RuntimeError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Http response error
|
11
|
+
class HttpResponseError < RubiraiError
|
12
|
+
def initialize(code)
|
13
|
+
super "Http Error: #{code}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Mirai error
|
18
|
+
class MiraiError < RubiraiError
|
19
|
+
def initialize(code, msg = nil)
|
20
|
+
raise(RubiraiError, 'invalid mirai error code') unless Rubirai::RETURN_CODE.key? code
|
21
|
+
str = +"Mirai error: #{code} - #{Rubirai::RETURN_CODE[code]}"
|
22
|
+
str << "\n#{msg}" if msg
|
23
|
+
super str
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/events/event'
|
4
|
+
|
5
|
+
module Rubirai
|
6
|
+
class Bot
|
7
|
+
# Fetch `count` number of oldest events.
|
8
|
+
# @param count [Integer] the number of events to fetch
|
9
|
+
# @return [Array<Event>] the event objects.
|
10
|
+
def fetch_message(count = 10)
|
11
|
+
get_events '/fetchMessage', count
|
12
|
+
end
|
13
|
+
|
14
|
+
alias fetch_messages fetch_message
|
15
|
+
alias fetch_event fetch_message
|
16
|
+
alias fetch_events fetch_message
|
17
|
+
|
18
|
+
# Fetch `count` number of latest events.
|
19
|
+
# @param count [Integer] the number of events to fetch
|
20
|
+
# @return [Array<Event>] the event objects
|
21
|
+
def fetch_latest_message(count = 10)
|
22
|
+
get_events '/fetchLatestMessage', count
|
23
|
+
end
|
24
|
+
|
25
|
+
alias fetch_latest_messages fetch_latest_message
|
26
|
+
alias fetch_latest_event fetch_latest_message
|
27
|
+
alias fetch_latest_events fetch_latest_message
|
28
|
+
|
29
|
+
# Peek `count` number of oldest events. (Will not delete from cache)
|
30
|
+
# @param count [Integer] the number of events to peek
|
31
|
+
# @return [Array<Event>] the event objects
|
32
|
+
def peek_message(count = 10)
|
33
|
+
get_events '/peekMessage', count
|
34
|
+
end
|
35
|
+
|
36
|
+
alias peek_messages peek_message
|
37
|
+
alias peek_event peek_message
|
38
|
+
alias peek_events peek_message
|
39
|
+
|
40
|
+
# Peek `count` number of latest events. (Will not delete from cache)
|
41
|
+
# @param count [Integer] the number of events to peek
|
42
|
+
# @return [Array<Event>] the event objects
|
43
|
+
def peek_latest_message(count = 10)
|
44
|
+
get_events '/peekLatestMessage', count
|
45
|
+
end
|
46
|
+
|
47
|
+
alias peek_latest_messages peek_latest_message
|
48
|
+
alias peek_latest_event peek_latest_message
|
49
|
+
alias peek_latest_events peek_latest_message
|
50
|
+
|
51
|
+
# Get a message event from message id
|
52
|
+
# @param msg_id [Integer] message id
|
53
|
+
# @return [Event] the event object
|
54
|
+
def message_from_id(msg_id)
|
55
|
+
resp = call :get, '/messageFromId', params: {
|
56
|
+
sessionKey: @session,
|
57
|
+
id: msg_id
|
58
|
+
}
|
59
|
+
Event.parse resp['data'], self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the number of cached messages in mirai-http-api
|
63
|
+
# @return [Integer] the number of cached messages
|
64
|
+
def count_cached_message
|
65
|
+
resp = call :get, '/countMessage', params: {
|
66
|
+
sessionKey: @session
|
67
|
+
}
|
68
|
+
resp['data']
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def get_events(path, count)
|
74
|
+
resp = call :get, path, params: {
|
75
|
+
sessionKey: @session,
|
76
|
+
count: count
|
77
|
+
}
|
78
|
+
resp['data'].map do |event|
|
79
|
+
Event.parse event, self
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/events/event'
|
4
|
+
|
5
|
+
module Rubirai
|
6
|
+
# Operations for responding to friend requests.
|
7
|
+
# Only use the values defined in this module to respond to friend requests.
|
8
|
+
module FriendRequestOperation
|
9
|
+
# Approve the request
|
10
|
+
APPROVE = 0
|
11
|
+
|
12
|
+
# Deny the request
|
13
|
+
DENY = 1
|
14
|
+
|
15
|
+
# Deny and blacklist the sender of the request
|
16
|
+
DENY_AND_BLACKLIST = 2
|
17
|
+
end
|
18
|
+
|
19
|
+
# Operations for responding to group join requests.
|
20
|
+
# Only use the values defined in this module to respond to group join requests.
|
21
|
+
module JoinGroupRequestOperation
|
22
|
+
APPROVE = 0
|
23
|
+
DENY = 1
|
24
|
+
IGNORE = 2
|
25
|
+
DENY_AND_BLACKLIST = 3
|
26
|
+
IGNORE_AND_BLACKLIST = 4
|
27
|
+
end
|
28
|
+
|
29
|
+
# Operations for responding to group invite requests.
|
30
|
+
# Only use the values defined in this module to respond to group invite requests.
|
31
|
+
module GroupInviteRequestOperation
|
32
|
+
APPROVE = 0
|
33
|
+
DENY = 1
|
34
|
+
end
|
35
|
+
|
36
|
+
class Bot
|
37
|
+
# Respond to new friend request (raw)
|
38
|
+
#
|
39
|
+
# @param event_id [Integer] the event id
|
40
|
+
# @param from_id [Integer] id of the requester
|
41
|
+
# @param operation [Integer] see {FriendRequestOperation}.
|
42
|
+
# @param group_id [Integer] the group where the request is from. 0 if not from group.
|
43
|
+
# @param message [String] the message to reply
|
44
|
+
# @return [void]
|
45
|
+
def respond_to_new_friend_request(event_id, from_id, operation, group_id = 0, message = '')
|
46
|
+
call :post, '/resp/newFriendRequestEvent', json: {
|
47
|
+
sessionKey: @session,
|
48
|
+
eventId: event_id,
|
49
|
+
fromId: from_id,
|
50
|
+
groupId: group_id,
|
51
|
+
operate: operation,
|
52
|
+
message: message
|
53
|
+
}
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# Respond to join group request (raw)
|
58
|
+
#
|
59
|
+
# @param event_id [Integer] the event id
|
60
|
+
# @param from_id [Integer] id of the requester
|
61
|
+
# @param operation [Integer] see {JoinGroupRequestOperation}
|
62
|
+
# @param group_id [Integer] the group where the request is from. 0 if not from group.
|
63
|
+
# @param message [String] the message to reply
|
64
|
+
# @return [void]
|
65
|
+
def respond_to_member_join(event_id, from_id, group_id, operation, message = '')
|
66
|
+
call :post, '/resp/memberJoinRequestEvent', json: {
|
67
|
+
sessionKey: @session,
|
68
|
+
eventId: event_id,
|
69
|
+
fromId: from_id,
|
70
|
+
groupId: group_id,
|
71
|
+
operate: operation,
|
72
|
+
message: message
|
73
|
+
}
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def respond_to_group_invite(event_id, from_id, group_id, operation, message = '')
|
78
|
+
call :post, '/resp/botInvitedJoinGroupRequestEvent', json: {
|
79
|
+
sessionKey: @session,
|
80
|
+
eventId: event_id,
|
81
|
+
fromId: from_id,
|
82
|
+
groupId: group_id,
|
83
|
+
operate: operation,
|
84
|
+
message: message
|
85
|
+
}
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class RequestEvent
|
91
|
+
# @abstract
|
92
|
+
def respond(operation, message)
|
93
|
+
raise NotImplementedError
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class NewFriendRequestEvent
|
98
|
+
# Respond to the friend request.
|
99
|
+
#
|
100
|
+
# @param operation [Integer] see {FriendRequestOperation}
|
101
|
+
# @param message [String] the message to reply
|
102
|
+
# @return [void]
|
103
|
+
def respond(operation, message = '')
|
104
|
+
@bot.respond_to_new_friend_request @event_id, @from_id, operation, @group_id, message
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class JoinGroupRequestEvent
|
109
|
+
# Respond to the friend request.
|
110
|
+
#
|
111
|
+
# @param operation [Integer] see {JoinGroupRequestOperation}
|
112
|
+
# @param message [String] the message to reply
|
113
|
+
# @return [void]
|
114
|
+
def respond(operation, message = '')
|
115
|
+
@bot.respond_to_member_join @event_id, @from_id, @group_id, operation, message
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class BotInvitedToGroupEvent
|
120
|
+
# Respond to the group invitation.
|
121
|
+
#
|
122
|
+
# @param operation [Integer] see {GroupInviteRequestOperation}
|
123
|
+
# @param message [String] the message to reply
|
124
|
+
# @return [void]
|
125
|
+
def respond(operation, message = '')
|
126
|
+
@bot.respond_to_group_invite @event_id, @from_id, @group_id, operation, message
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|