vk_longpoll_bot 0.0.2 → 0.1.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 +4 -4
- data/.gitignore +8 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +25 -0
- data/README.md +37 -5
- data/Rakefile +10 -24
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/audio_bot/main.rb +42 -0
- data/examples/chat_bot/main.rb +29 -0
- data/examples/command_bot/main.rb +37 -0
- data/lib/vk_longpoll_bot.rb +11 -6
- data/lib/vk_longpoll_bot/bot.rb +88 -52
- data/lib/vk_longpoll_bot/constants.rb +4 -1
- data/lib/vk_longpoll_bot/events.rb +65 -14
- data/lib/vk_longpoll_bot/exceptions.rb +16 -1
- data/lib/vk_longpoll_bot/request.rb +27 -5
- data/lib/vk_longpoll_bot/utility.rb +12 -3
- data/lib/vk_longpoll_bot/version.rb +7 -0
- data/vk_longpoll_bot.gemspec +36 -16
- metadata +56 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f6b0cfc136c4a32241d516da8a4a93ddca2233cfbe78110585191c891d7f7f37
|
|
4
|
+
data.tar.gz: ea9f81876c642fd066bfce3eb548b28979812f5296cfa52106db311f519db628
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7338044936b97bceb6f0d293f9d81b4f39634a268ae336177eb4c44c2bb43defcbf976e0b467edee2f12f12be5df1a662789737e7b1a1750e0ff124e1201209
|
|
7
|
+
data.tar.gz: 1943ef424b8aa3c9c0836aa1f3a56f663f89bd5b026cd38a816a3db6154175c7ebec82da48a360eb819bff702c0def6582822f6b753eb6306f18eaa801c08282
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
vk_longpoll_bot (0.1.0)
|
|
5
|
+
json (~> 2.2.0)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
json (2.2.0)
|
|
11
|
+
minitest (5.12.0)
|
|
12
|
+
rake (10.5.0)
|
|
13
|
+
|
|
14
|
+
PLATFORMS
|
|
15
|
+
x64-mingw32
|
|
16
|
+
|
|
17
|
+
DEPENDENCIES
|
|
18
|
+
bundler (~> 2.0)
|
|
19
|
+
json (~> 2.2)
|
|
20
|
+
minitest (~> 5.0)
|
|
21
|
+
rake (~> 10.0)
|
|
22
|
+
vk_longpoll_bot!
|
|
23
|
+
|
|
24
|
+
BUNDLED WITH
|
|
25
|
+
2.0.2
|
data/README.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
# VkLongpollBot
|
|
2
|
+
|
|
3
|
+
This small gem provides interface to work with VK API and create simple longpoll bot for group.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'vk_longpoll_bot'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install vk_longpoll_bot
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
You can find usage examples in `example` folder.
|
|
24
|
+
|
|
25
|
+
## Development
|
|
26
|
+
|
|
27
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
28
|
+
|
|
29
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
30
|
+
|
|
31
|
+
## Contributing
|
|
32
|
+
|
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fizvlad/vk-longpoll-bot-rb.
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
desc "Build and install gem"
|
|
14
|
-
task :install_local => :build do
|
|
15
|
-
puts `gem install ./#{GEM_NAME}-*.gem`
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
desc "Setup SSL certificate"
|
|
19
|
-
task :setup_ssl do
|
|
20
|
-
print "Path to SSL certificate (leave empty if there is no troubles with SSL):"
|
|
21
|
-
ssl_cert_path = STDIN.gets.chomp
|
|
22
|
-
puts
|
|
23
|
-
ENV["SSL_CERT_FILE"] = ssl_cert_path
|
|
24
|
-
end
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
|
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
|
5
|
+
t.libs << "test"
|
|
6
|
+
t.libs << "lib"
|
|
7
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
task :default => :test
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "vk_longpoll_bot"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
2
|
+
|
|
3
|
+
require "vk_music" # See https://rubygems.org/gems/vk_music
|
|
4
|
+
|
|
5
|
+
require "vk_longpoll_bot"
|
|
6
|
+
include VkLongpollBot
|
|
7
|
+
|
|
8
|
+
bot = Bot.new(ARGV[0], ARGV[1])
|
|
9
|
+
|
|
10
|
+
bot.on_start { puts "Starting bot." }
|
|
11
|
+
bot.on_finish { puts "Finishing bot." }
|
|
12
|
+
|
|
13
|
+
bot.on(subtype: "message_new") do |event|
|
|
14
|
+
next unless event["attachments"] && event["body"].chomp == "id"
|
|
15
|
+
reply = []
|
|
16
|
+
event["attachments"].each do |att|
|
|
17
|
+
if att["type"] == "audio"
|
|
18
|
+
audio = VkMusic::Audio.new(
|
|
19
|
+
artist: att["audio"]["artist"],
|
|
20
|
+
id: att["audio"]["id"],
|
|
21
|
+
owner_id: att["audio"]["owner_id"],
|
|
22
|
+
title: att["audio"]["title"],
|
|
23
|
+
url: att["audio"]["url"],
|
|
24
|
+
duration: att["audio"]["duration"]
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
puts audio
|
|
28
|
+
reply << "#{audio.owner_id}_#{audio.id}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
bot.send_message(event["user_id"], reply.join("\n")) unless reply.empty?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
bot.on(subtype: "message_new") do |event|
|
|
36
|
+
if event["body"].chomp == "stop"
|
|
37
|
+
bot.send_message(event["user_id"], "Shutting down")
|
|
38
|
+
bot.stop
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
bot.run
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
2
|
+
|
|
3
|
+
require "vk_longpoll_bot"
|
|
4
|
+
include VkLongpollBot
|
|
5
|
+
|
|
6
|
+
bot = Bot.new(ARGV[0], ARGV[1])
|
|
7
|
+
|
|
8
|
+
bot.on_start { puts "Starting bot." }
|
|
9
|
+
bot.on_finish { puts "Finishing bot." }
|
|
10
|
+
|
|
11
|
+
bot.on(subtype: "message_typing_state") do |event|
|
|
12
|
+
puts "#{event["from_id"]} is typing message"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
bot.on(subtype: "message_new") do |event|
|
|
16
|
+
puts "Got message from #{event["user_id"]}: #{event["body"]}"
|
|
17
|
+
bot.send_message(event["user_id"], "I got your message")
|
|
18
|
+
|
|
19
|
+
if event["attachments"]
|
|
20
|
+
puts "And it got attachments! #{event["attachments"]}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if event["body"].chomp == "stop"
|
|
24
|
+
bot.send_message(event["user_id"], "Shutting down")
|
|
25
|
+
bot.stop
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
bot.run
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
2
|
+
|
|
3
|
+
require "vk_longpoll_bot"
|
|
4
|
+
include VkLongpollBot
|
|
5
|
+
|
|
6
|
+
PREFIX = ">"
|
|
7
|
+
|
|
8
|
+
bot = Bot.new(ARGV[0], ARGV[1], api_version: "5.74")
|
|
9
|
+
|
|
10
|
+
bot.on_start do
|
|
11
|
+
puts "Starting bot."
|
|
12
|
+
bot.enable_online
|
|
13
|
+
end
|
|
14
|
+
bot.on_finish do
|
|
15
|
+
puts "Finishing bot."
|
|
16
|
+
bot.disable_online
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
bot.on(subtype: "message_new") do |event|
|
|
20
|
+
puts "Got message from #{event["user_id"]}: #{event["body"].chomp}"
|
|
21
|
+
next unless event["body"].start_with?(PREFIX)
|
|
22
|
+
command = event["body"].chomp.sub(PREFIX, "")
|
|
23
|
+
|
|
24
|
+
case command
|
|
25
|
+
when "help"
|
|
26
|
+
bot.send_message(event["user_id"], "Available commands: \n* help - show this message\n* answer - answer message\n* exit, stop - shut down")
|
|
27
|
+
when "answer"
|
|
28
|
+
bot.send_message(event["user_id"], "Answering")
|
|
29
|
+
when "exit", "stop"
|
|
30
|
+
bot.send_message(event["user_id"], "Shutting down")
|
|
31
|
+
bot.stop
|
|
32
|
+
else
|
|
33
|
+
bot.send_message(event["user_id"], "Unknwon command")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
bot.run
|
data/lib/vk_longpoll_bot.rb
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
require "vk_longpoll_bot/utility"
|
|
2
|
+
require "vk_longpoll_bot/constants"
|
|
3
|
+
require "vk_longpoll_bot/exceptions"
|
|
4
|
+
require "vk_longpoll_bot/request"
|
|
5
|
+
require "vk_longpoll_bot/bot"
|
|
6
|
+
require "vk_longpoll_bot/events"
|
|
7
|
+
require "vk_longpoll_bot/version"
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Main module.
|
|
11
|
+
module VkLongpollBot; end
|
data/lib/vk_longpoll_bot/bot.rb
CHANGED
|
@@ -1,96 +1,139 @@
|
|
|
1
1
|
module VkLongpollBot
|
|
2
2
|
|
|
3
|
+
##
|
|
3
4
|
# Main class, which contains all the methods of bot.
|
|
4
5
|
class Bot
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
##
|
|
8
|
+
# @return [Integer] group ID.
|
|
9
|
+
attr_reader :id
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# @return [Hash<Symbol, Array<EventListener>>] hash with listeners for each of event type.
|
|
13
|
+
attr_reader :event_listeners
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
##
|
|
16
|
+
# Initialize bot. This method don't start longpoll session.
|
|
17
|
+
#
|
|
18
|
+
# @param access_token [String] group access token.
|
|
19
|
+
# @param group_id [Integer] group of associated ID.
|
|
20
|
+
# @param options [Hash]
|
|
10
21
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
def initialize(access_token, id, options = {})
|
|
22
|
+
# @option options [Gem::Version, String] api_version (VK_API_URL_BASE) version of VK API.
|
|
23
|
+
# @option options [Integer] longpoll_wait longpoll (LONGPOLL_STANDART_WAIT) requests timeout.
|
|
24
|
+
def initialize(access_token, group_id, options = {})
|
|
15
25
|
@event_listeners = Hash.new { |hash, key| hash[key] = Array.new }
|
|
16
26
|
@on_start = []
|
|
17
27
|
@on_finish = []
|
|
18
28
|
|
|
19
|
-
@access_token = access_token
|
|
20
|
-
@id =
|
|
29
|
+
@access_token = access_token.to_s
|
|
30
|
+
@id = group_id.to_i
|
|
21
31
|
|
|
22
32
|
@api_version = options[:api_version] || VK_API_CURRENT_VERSION
|
|
23
33
|
@longpoll_wait = options[:longpoll_wait] || LONGPOLL_STANDART_WAIT
|
|
24
34
|
|
|
25
35
|
@longpoll = {}
|
|
26
|
-
|
|
27
|
-
# TODO
|
|
28
36
|
end
|
|
29
37
|
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
# =========================================================================
|
|
38
|
+
##
|
|
39
|
+
# @! group API methods
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
##
|
|
42
|
+
# Call for API method.
|
|
43
|
+
#
|
|
44
|
+
# @param method_name ["String"] name of requested method. See https://vk.com/dev/methods
|
|
45
|
+
#
|
|
46
|
+
# @return [Hash]
|
|
35
47
|
def api(method_name, parameters = {})
|
|
36
48
|
Request.api(method_name, parameters, @access_token, @api_version)
|
|
37
49
|
end
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
##
|
|
52
|
+
# Send text message.
|
|
53
|
+
#
|
|
54
|
+
# @param target [Integer] ID of receiver.
|
|
55
|
+
# @param content [String] text of message.
|
|
56
|
+
# @param options [Hash] additional options which must be sent with request.
|
|
57
|
+
# Options +user_id+, +message+ and +random_id+ will be overwritten
|
|
58
|
+
#
|
|
59
|
+
# @return [Hash]
|
|
60
|
+
def send_message(target, content, options = {})
|
|
41
61
|
target_id = target.to_i
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
forced_options = {
|
|
63
|
+
user_id: target_id,
|
|
64
|
+
message: content,
|
|
65
|
+
random_id: Utility.random_id(target_id)
|
|
66
|
+
}
|
|
67
|
+
api("messages.send", options.merge(forced_options))
|
|
44
68
|
end
|
|
45
69
|
|
|
70
|
+
##
|
|
46
71
|
# Enable group online status
|
|
47
|
-
|
|
72
|
+
#
|
|
73
|
+
# @return [nil]
|
|
74
|
+
def enable_online
|
|
48
75
|
begin
|
|
49
|
-
api("groups.enableOnline", group_id:
|
|
76
|
+
api("groups.enableOnline", group_id: @id)
|
|
50
77
|
rescue
|
|
51
78
|
# Online is already enabled
|
|
52
79
|
end
|
|
80
|
+
nil
|
|
53
81
|
end
|
|
54
82
|
|
|
83
|
+
##
|
|
55
84
|
# Disable group online status
|
|
56
|
-
|
|
85
|
+
#
|
|
86
|
+
# @return [nil]
|
|
87
|
+
def disable_online
|
|
57
88
|
begin
|
|
58
|
-
api("groups.disableOnline", group_id:
|
|
89
|
+
api("groups.disableOnline", group_id: @id)
|
|
59
90
|
rescue
|
|
60
91
|
# Online is already disabled
|
|
61
92
|
end
|
|
93
|
+
nil
|
|
62
94
|
end
|
|
63
95
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
96
|
+
##
|
|
97
|
+
# @!endgroup
|
|
98
|
+
|
|
99
|
+
##
|
|
100
|
+
# @!group Events
|
|
69
101
|
|
|
70
|
-
|
|
102
|
+
##
|
|
103
|
+
# Add new event listener.
|
|
104
|
+
#
|
|
105
|
+
# @param options [Hash]
|
|
106
|
+
#
|
|
107
|
+
# @option options [String] subtype
|
|
108
|
+
#
|
|
109
|
+
# @yieldparam event [Event]
|
|
71
110
|
#
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
111
|
+
# @return [nil]
|
|
112
|
+
def on(options, &block)
|
|
113
|
+
raise ArgumentError.new("Got subtype #{options[:subtype]} of class #{options[:subtype].class}") unless String === options[:subtype] && Events.valid_subtype?(options[:subtype])
|
|
114
|
+
@event_listeners[options[:subtype]] << Events::EventListener.new(options, &block)
|
|
115
|
+
nil
|
|
77
116
|
end
|
|
78
117
|
|
|
118
|
+
##
|
|
79
119
|
# Add code to be executed right after bot starts.
|
|
80
120
|
def on_start(&block)
|
|
81
121
|
@on_start << block
|
|
82
122
|
end
|
|
83
123
|
|
|
124
|
+
##
|
|
84
125
|
# Add code to be executed right after bot finishes.
|
|
85
126
|
def on_finish(&block)
|
|
86
127
|
@on_finish << block
|
|
87
128
|
end
|
|
129
|
+
|
|
130
|
+
##
|
|
131
|
+
# @!endgroup
|
|
88
132
|
|
|
89
|
-
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
# Start bot. This methods freeze current thread until <tt>stop</tt> called.
|
|
133
|
+
##
|
|
134
|
+
# Start bot. This methods freeze current thread until {Bot#stop} method is called.
|
|
135
|
+
#
|
|
136
|
+
# @return [void]
|
|
94
137
|
def run
|
|
95
138
|
@on_start.each(&:call)
|
|
96
139
|
|
|
@@ -100,18 +143,16 @@ module VkLongpollBot
|
|
|
100
143
|
@on_finish.each(&:call)
|
|
101
144
|
end
|
|
102
145
|
|
|
146
|
+
##
|
|
103
147
|
# Stop bot.
|
|
148
|
+
#
|
|
149
|
+
# @return [void]
|
|
104
150
|
def stop
|
|
105
151
|
@finish_flag = true
|
|
106
152
|
end
|
|
107
153
|
|
|
108
|
-
# =========================================================================
|
|
109
|
-
private
|
|
110
|
-
# =========================================================================
|
|
111
154
|
|
|
112
|
-
|
|
113
|
-
# LONGPOLL
|
|
114
|
-
# =========================================================================
|
|
155
|
+
private
|
|
115
156
|
|
|
116
157
|
# Request longpoll data.
|
|
117
158
|
def init_longpoll
|
|
@@ -121,14 +162,13 @@ module VkLongpollBot
|
|
|
121
162
|
@longpoll[:ts] = lp["ts"]
|
|
122
163
|
end
|
|
123
164
|
|
|
124
|
-
# Start longpoll. Requires
|
|
165
|
+
# Start longpoll. Requires +init_longpoll+ to be run first.
|
|
125
166
|
def run_longpoll
|
|
126
167
|
@finish_flag = false # Setting up flag for loop
|
|
127
168
|
|
|
128
169
|
until @finish_flag
|
|
129
|
-
response = Request.longpoll(@longpoll[:server], @longpoll[:key], @longpoll[:ts], @longpoll_wait)
|
|
170
|
+
response = Request.longpoll(@longpoll[:server], @longpoll[:key], @longpoll[:ts], @longpoll_wait)
|
|
130
171
|
if response["failed"]
|
|
131
|
-
# Error happened
|
|
132
172
|
Utility.warn "Longpoll failed with code #{response["failed"]}. This must be solvable. Keep running..."
|
|
133
173
|
case response["failed"]
|
|
134
174
|
when 1
|
|
@@ -150,10 +190,6 @@ module VkLongpollBot
|
|
|
150
190
|
end
|
|
151
191
|
end
|
|
152
192
|
end
|
|
153
|
-
|
|
154
|
-
# =========================================================================
|
|
155
|
-
# EVENTS
|
|
156
|
-
# =========================================================================
|
|
157
193
|
|
|
158
194
|
# Handle update from longpoll.
|
|
159
195
|
def update_handler(update)
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
module VkLongpollBot
|
|
2
2
|
|
|
3
|
+
##
|
|
3
4
|
# Base of URL to API.
|
|
4
5
|
VK_API_URL_BASE = "https://api.vk.com"
|
|
5
6
|
|
|
7
|
+
##
|
|
6
8
|
# It's recommended to use last version of VK API.
|
|
7
9
|
VK_API_CURRENT_VERSION = Gem::Version.new("5.101")
|
|
8
10
|
|
|
11
|
+
##
|
|
9
12
|
# Longpoll requests timeout.
|
|
10
13
|
LONGPOLL_STANDART_WAIT = 25
|
|
11
14
|
|
|
12
|
-
end
|
|
15
|
+
end
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
module VkLongpollBot
|
|
2
2
|
|
|
3
|
+
##
|
|
3
4
|
# Everything related to longpoll events.
|
|
4
5
|
module Events
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
##
|
|
8
|
+
# All the types and subtypes of events.
|
|
7
9
|
TYPES = {
|
|
8
10
|
message: %w{message_new message_reply message_edit message_typing_state message_allow message_deny},
|
|
9
11
|
photo: %w{photo_new photo_comment_new photo_comment_edit photo_comment_restore photo_comment_delete},
|
|
10
12
|
audio: %w{audio_new},
|
|
11
|
-
video: %w{video_new video_comment_new video_comment_restore video_comment_delete},
|
|
13
|
+
video: %w{video_new video_comment_new video_comment_edit video_comment_restore video_comment_delete},
|
|
12
14
|
wall: %w{wall_post_new wall_repost wall_reply_new wall_reply_edit wall_reply_restore wall_reply_delete},
|
|
13
15
|
board: %w{board_post_new board_post_edit board_post_restore board_post_delete},
|
|
14
16
|
market: %w{market_comment_new market_comment_edit market_comment_restore market_comment_delete},
|
|
@@ -19,16 +21,41 @@ module VkLongpollBot
|
|
|
19
21
|
app: %w{app_payload}
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
##
|
|
25
|
+
# Check whether subtype is correct.
|
|
26
|
+
#
|
|
27
|
+
# @param subtype [String]
|
|
22
28
|
def self.valid_subtype?(subtype)
|
|
23
29
|
TYPES.values.any? { |arr| arr.include?(subtype) }
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
##
|
|
33
|
+
# Class containing data received from longpoll. Provides easy access to it's data.
|
|
27
34
|
class Event
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
##
|
|
37
|
+
# @return [String] subtype of event.
|
|
38
|
+
attr_reader :subtype
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# @return [Integer] ID of group which received event.
|
|
42
|
+
attr_reader :group_id
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# @return [Hash] hash with updates data.
|
|
46
|
+
attr_reader :data
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# @return [Bot] longpoll bot which received event.
|
|
50
|
+
attr_reader :bot
|
|
30
51
|
|
|
31
|
-
|
|
52
|
+
##
|
|
53
|
+
# New event. Initialize from fields of update json and bot which got this event.
|
|
54
|
+
#
|
|
55
|
+
# @param subtype [String]
|
|
56
|
+
# @param data [Hash] +update+ array entry.
|
|
57
|
+
# @param group_id [Integer]
|
|
58
|
+
# @param bot [Bot]
|
|
32
59
|
def initialize(subtype, data, group_id, bot)
|
|
33
60
|
@subtype = subtype.to_s
|
|
34
61
|
@data = data
|
|
@@ -36,37 +63,61 @@ module VkLongpollBot
|
|
|
36
63
|
@bot = bot
|
|
37
64
|
end
|
|
38
65
|
|
|
66
|
+
##
|
|
39
67
|
# Provides access to fields of update data.
|
|
68
|
+
#
|
|
69
|
+
# @param arg [String] hash key.
|
|
70
|
+
#
|
|
71
|
+
# @return [Object]
|
|
40
72
|
def [](arg)
|
|
41
73
|
@data[arg.to_s]
|
|
42
74
|
end
|
|
43
|
-
|
|
44
|
-
# TODO
|
|
45
75
|
|
|
46
76
|
end
|
|
47
77
|
|
|
48
78
|
# NOTE: It might be better to create separate class for each event but there's lot of them and they don't have good hierarchy.
|
|
49
79
|
|
|
80
|
+
##
|
|
50
81
|
# Class containing block to run on some event.
|
|
51
82
|
class EventListener
|
|
52
83
|
|
|
84
|
+
##
|
|
85
|
+
# @return [String] subtype of this listener.
|
|
53
86
|
attr_reader :subtype
|
|
54
87
|
|
|
55
|
-
|
|
56
|
-
|
|
88
|
+
##
|
|
89
|
+
# Initialize new listener
|
|
90
|
+
#
|
|
91
|
+
# @param options[Hash]
|
|
92
|
+
#
|
|
93
|
+
# @option options [String] subtype
|
|
94
|
+
#
|
|
95
|
+
# @yieldparam event [Event]
|
|
96
|
+
def initialize(options, &block)
|
|
97
|
+
@subtype = options[:subtype]
|
|
57
98
|
@block = block
|
|
58
|
-
|
|
59
|
-
# TODO
|
|
60
99
|
end
|
|
61
100
|
|
|
101
|
+
##
|
|
102
|
+
# Calls block with given event as argument.
|
|
103
|
+
#
|
|
104
|
+
# @param event [Event]
|
|
105
|
+
#
|
|
106
|
+
# @return [void]
|
|
62
107
|
def call(event)
|
|
63
108
|
@block.call(event)
|
|
64
109
|
end
|
|
65
110
|
|
|
66
|
-
# TODO
|
|
67
|
-
|
|
68
111
|
end
|
|
69
112
|
|
|
70
113
|
end
|
|
71
114
|
|
|
72
|
-
|
|
115
|
+
##
|
|
116
|
+
# Alias for {Events::Event} class
|
|
117
|
+
Event = Events::Event
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Alias for {Events::EventListener} class
|
|
121
|
+
EventListener = Events::EventListener
|
|
122
|
+
|
|
123
|
+
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
module VkLongpollBot
|
|
2
2
|
|
|
3
|
+
##
|
|
3
4
|
# Custom exceptions.
|
|
4
5
|
module Exceptions
|
|
5
6
|
|
|
7
|
+
##
|
|
6
8
|
# All of the error codes descriptions. Source: https://vk.com/dev/errors
|
|
7
9
|
CODES = {
|
|
8
10
|
1 => "Произошла неизвестная ошибка.",
|
|
@@ -54,35 +56,48 @@ module VkLongpollBot
|
|
|
54
56
|
940 => "Слишком много постов в сообщении."
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
##
|
|
57
60
|
# Something wrong with response from vk.com.
|
|
58
61
|
class ResponseError < RuntimeError
|
|
59
62
|
end
|
|
60
63
|
|
|
64
|
+
##
|
|
61
65
|
# API error. Must have some code and description.
|
|
62
66
|
class APIError < ResponseError
|
|
63
67
|
|
|
64
68
|
attr_reader :error
|
|
65
69
|
|
|
70
|
+
##
|
|
71
|
+
# Create new instance.
|
|
72
|
+
#
|
|
73
|
+
# @param error [Hash] response hash which contains "error" key.
|
|
66
74
|
def initialize(error)
|
|
67
75
|
@error = error["error"]
|
|
68
76
|
super("#{code}: #{included_message}")
|
|
69
77
|
end
|
|
70
78
|
|
|
79
|
+
##
|
|
80
|
+
# @return [Integer]
|
|
71
81
|
def code
|
|
72
82
|
@error["error_code"]
|
|
73
83
|
end
|
|
74
84
|
|
|
85
|
+
##
|
|
86
|
+
# @return [String] attached error description.
|
|
75
87
|
def included_message
|
|
76
88
|
@error["error_msg"]
|
|
77
89
|
end
|
|
78
90
|
|
|
91
|
+
##
|
|
92
|
+
# @return [String] error description from API documentation.
|
|
79
93
|
def description
|
|
80
94
|
CODES[code]
|
|
81
95
|
end
|
|
82
96
|
|
|
83
97
|
end
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
##
|
|
100
|
+
# Something wrong with longpoll response.
|
|
86
101
|
class LongpollError < ResponseError
|
|
87
102
|
end
|
|
88
103
|
|
|
@@ -3,16 +3,30 @@ require "json"
|
|
|
3
3
|
|
|
4
4
|
module VkLongpollBot
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
##
|
|
7
|
+
# Some functions to send HTTP requests.
|
|
7
8
|
module Request
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
##
|
|
11
|
+
# Regular GET HTTP request to given URI.
|
|
12
|
+
#
|
|
13
|
+
# @param url [String]
|
|
14
|
+
#
|
|
15
|
+
# @return [String]
|
|
10
16
|
def self.to(url)
|
|
11
17
|
uri = URI(url.to_s)
|
|
12
18
|
Net::HTTP.get(uri)
|
|
13
19
|
end
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
##
|
|
22
|
+
# GET request to VK API.
|
|
23
|
+
#
|
|
24
|
+
# @param method_name [String, Symbol]
|
|
25
|
+
# @param parameters [Hash]
|
|
26
|
+
# @param access_token [String]
|
|
27
|
+
# @param v [Gem::Version, String] VK API version.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash]
|
|
16
30
|
def self.api(method_name, parameters, access_token, v = VK_API_CURRENT_VERSION)
|
|
17
31
|
response = JSON.parse self.to("#{VK_API_URL_BASE}/method/#{method_name}?access_token=#{access_token}&v=#{v.to_s}&#{URI.encode_www_form(parameters)}")
|
|
18
32
|
if response["response"]
|
|
@@ -24,11 +38,19 @@ module VkLongpollBot
|
|
|
24
38
|
end
|
|
25
39
|
end
|
|
26
40
|
|
|
27
|
-
|
|
41
|
+
##
|
|
42
|
+
# GET request to longpoll server.
|
|
43
|
+
#
|
|
44
|
+
# @param server [String] server address.
|
|
45
|
+
# @param key [String] secret session key.
|
|
46
|
+
# @param ts [Integer] index of last event.
|
|
47
|
+
# @param wait [Integer] size of request timeout in seconds.
|
|
48
|
+
#
|
|
49
|
+
# @return [Hash] hash with timestamp of last event and array of updates.
|
|
28
50
|
def self.longpoll(server, key, ts, wait = LONGPOLL_STANDART_WAIT)
|
|
29
51
|
JSON.parse self.to("#{server}?act=a_check&key=#{key}&ts=#{ts}&wait=#{wait}")
|
|
30
52
|
end
|
|
31
53
|
|
|
32
54
|
end
|
|
33
55
|
|
|
34
|
-
end
|
|
56
|
+
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
module VkLongpollBot
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
##
|
|
4
|
+
# Some utility methods.
|
|
4
5
|
module Utility
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
##
|
|
8
|
+
# Log warning message.
|
|
7
9
|
def self.warn(msg)
|
|
8
10
|
if defined?(Warning.warn)
|
|
9
11
|
Warning.warn msg
|
|
@@ -12,7 +14,14 @@ module VkLongpollBot
|
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
##
|
|
18
|
+
# Generate +random_id+ for message.
|
|
19
|
+
#
|
|
20
|
+
# This method generates random numerical ID based on current time, receiver ID and random salt.
|
|
21
|
+
#
|
|
22
|
+
# @param target_id [Integer] ID of message receiver.
|
|
23
|
+
#
|
|
24
|
+
# @return [Integer]
|
|
16
25
|
def self.random_id(target_id)
|
|
17
26
|
(rand(1000) * target_id * Time.now.to_f * 1000).to_i % 2**32
|
|
18
27
|
end
|
data/vk_longpoll_bot.gemspec
CHANGED
|
@@ -1,16 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require "vk_longpoll_bot/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "vk_longpoll_bot"
|
|
7
|
+
spec.version = VkLongpollBot::VERSION
|
|
8
|
+
spec.authors = ["Fizvlad"]
|
|
9
|
+
spec.email = ["fizvlad@mail.ru"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Provides interface to create simple VK longpoll bot"
|
|
12
|
+
spec.description = "Library to work with VK API and create simple longpoll bot for group."
|
|
13
|
+
spec.homepage = "https://github.com/fizvlad/vk-longpoll-bot-rb"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.required_ruby_version = ">=2.3.1"
|
|
17
|
+
|
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/fizvlad/vk-longpoll-bot-rb"
|
|
20
|
+
spec.metadata["changelog_uri"] = "https://github.com/fizvlad/vk-longpoll-bot-rb/releases"
|
|
21
|
+
|
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
24
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
26
|
+
end
|
|
27
|
+
spec.bindir = "exe"
|
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
29
|
+
spec.require_paths = ["lib"]
|
|
30
|
+
|
|
31
|
+
spec.add_runtime_dependency "json", "~> 2.2.0"
|
|
32
|
+
|
|
33
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
35
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
36
|
+
end
|
metadata
CHANGED
|
@@ -1,52 +1,90 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vk_longpoll_bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Fizvlad
|
|
8
8
|
autorequire:
|
|
9
|
-
bindir:
|
|
9
|
+
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-09-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: json
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 2.2.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 2.2.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: bundler
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.
|
|
34
|
-
type: :
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '10.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '10.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: minitest
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '5.0'
|
|
62
|
+
type: :development
|
|
35
63
|
prerelease: false
|
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
65
|
requirements:
|
|
38
66
|
- - "~>"
|
|
39
67
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
68
|
+
version: '5.0'
|
|
41
69
|
description: Library to work with VK API and create simple longpoll bot for group.
|
|
42
|
-
email:
|
|
70
|
+
email:
|
|
71
|
+
- fizvlad@mail.ru
|
|
43
72
|
executables: []
|
|
44
73
|
extensions: []
|
|
45
74
|
extra_rdoc_files: []
|
|
46
75
|
files:
|
|
76
|
+
- ".gitignore"
|
|
77
|
+
- ".travis.yml"
|
|
78
|
+
- Gemfile
|
|
79
|
+
- Gemfile.lock
|
|
47
80
|
- LICENSE
|
|
48
81
|
- README.md
|
|
49
82
|
- Rakefile
|
|
83
|
+
- bin/console
|
|
84
|
+
- bin/setup
|
|
85
|
+
- examples/audio_bot/main.rb
|
|
86
|
+
- examples/chat_bot/main.rb
|
|
87
|
+
- examples/command_bot/main.rb
|
|
50
88
|
- lib/vk_longpoll_bot.rb
|
|
51
89
|
- lib/vk_longpoll_bot/bot.rb
|
|
52
90
|
- lib/vk_longpoll_bot/constants.rb
|
|
@@ -54,11 +92,15 @@ files:
|
|
|
54
92
|
- lib/vk_longpoll_bot/exceptions.rb
|
|
55
93
|
- lib/vk_longpoll_bot/request.rb
|
|
56
94
|
- lib/vk_longpoll_bot/utility.rb
|
|
95
|
+
- lib/vk_longpoll_bot/version.rb
|
|
57
96
|
- vk_longpoll_bot.gemspec
|
|
58
97
|
homepage: https://github.com/fizvlad/vk-longpoll-bot-rb
|
|
59
98
|
licenses:
|
|
60
99
|
- MIT
|
|
61
|
-
metadata:
|
|
100
|
+
metadata:
|
|
101
|
+
homepage_uri: https://github.com/fizvlad/vk-longpoll-bot-rb
|
|
102
|
+
source_code_uri: https://github.com/fizvlad/vk-longpoll-bot-rb
|
|
103
|
+
changelog_uri: https://github.com/fizvlad/vk-longpoll-bot-rb/releases
|
|
62
104
|
post_install_message:
|
|
63
105
|
rdoc_options: []
|
|
64
106
|
require_paths:
|
|
@@ -74,8 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
74
116
|
- !ruby/object:Gem::Version
|
|
75
117
|
version: '0'
|
|
76
118
|
requirements: []
|
|
77
|
-
|
|
78
|
-
rubygems_version: 2.7.6.2
|
|
119
|
+
rubygems_version: 3.0.4
|
|
79
120
|
signing_key:
|
|
80
121
|
specification_version: 4
|
|
81
122
|
summary: Provides interface to create simple VK longpoll bot
|