implement basic telegram agent

This commit is contained in:
Tom König 2016-03-27 15:56:31 +02:00
parent 075545191a
commit adc1dee4fb
4 changed files with 232 additions and 11 deletions

23
Gemfile
View file

@ -25,17 +25,18 @@ end
# Optional libraries. To conserve RAM, comment out any that you don't need,
# then run `bundle` and commit the updated Gemfile and Gemfile.lock.
gem 'twilio-ruby', '~> 3.11.5' # TwilioAgent
gem 'ruby-growl', '~> 4.1.0' # GrowlAgent
gem 'net-ftp-list', '~> 3.2.8' # FtpsiteAgent
gem 'wunderground', '~> 1.2.0' # WeatherAgent
gem 'forecast_io', '~> 2.0.0' # WeatherAgent
gem 'rturk', '~> 2.12.1' # HumanTaskAgent
gem 'hipchat', '~> 1.2.0' # HipchatAgent
gem 'xmpp4r', '~> 0.5.6' # JabberAgent
gem 'mqtt' # MQTTAgent
gem 'slack-notifier', '~> 1.0.0' # SlackAgent
gem 'hypdf', '~> 1.0.7' # PDFInfoAgent
gem 'twilio-ruby', '~> 3.11.5' # TwilioAgent
gem 'ruby-growl', '~> 4.1.0' # GrowlAgent
gem 'net-ftp-list', '~> 3.2.8' # FtpsiteAgent
gem 'wunderground', '~> 1.2.0' # WeatherAgent
gem 'forecast_io', '~> 2.0.0' # WeatherAgent
gem 'rturk', '~> 2.12.1' # HumanTaskAgent
gem 'hipchat', '~> 1.2.0' # HipchatAgent
gem 'xmpp4r', '~> 0.5.6' # JabberAgent
gem 'mqtt' # MQTTAgent
gem 'slack-notifier', '~> 1.0.0' # SlackAgent
gem 'hypdf', '~> 1.0.7' # PDFInfoAgent
gem 'telegram-bot-ruby', '~> 0.4.1' # TelegramAgent
# Weibo Agents
gem 'weibo_2', github: 'cantino/weibo_2', branch: 'master'

View file

@ -112,6 +112,10 @@ GEM
multi_json (>= 1.0.0)
aws-sdk-core (2.2.15)
jmespath (~> 1.0)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
bcrypt (3.1.10)
better_errors (1.1.0)
coderay (>= 1.0.0)
@ -146,6 +150,8 @@ GEM
chronic (0.10.2)
cliver (0.3.2)
coderay (1.1.0)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.1.x)
@ -170,6 +176,8 @@ GEM
activesupport (>= 3.0, < 5.0)
delorean (2.1.0)
chronic
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (3.5.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
@ -225,6 +233,8 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.5)
gene_pool (1.4.1)
thread_safe
geokit (1.8.5)
multi_json (>= 1.3.2)
geokit-rails (2.0.1)
@ -281,6 +291,7 @@ GEM
hypdf (1.0.7)
httmultiparty (= 0.3.10)
i18n (0.7.0)
ice_nine (0.11.2)
jmespath (1.1.3)
jquery-rails (3.1.3)
railties (>= 3.0, < 5.0)
@ -371,6 +382,11 @@ GEM
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
orm_adapter (0.5.0)
persistent_http (1.0.6)
gene_pool (>= 1.3)
persistent_httparty (0.1.2)
httparty (~> 0.9)
persistent_http (< 2)
pg (0.18.3)
poltergeist (1.8.1)
capybara (~> 2.1)
@ -515,6 +531,10 @@ GEM
net-ssh (>= 2.8.0)
string-scrub (0.0.5)
systemu (2.6.4)
telegram-bot-ruby (0.4.1)
httmultiparty
persistent_httparty
virtus
term-ansicolor (1.3.0)
tins (~> 1.0)
therubyracer (0.12.2)
@ -559,6 +579,11 @@ GEM
macaddr (~> 1.0)
uuidtools (2.1.5)
vcr (2.9.2)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.4)
rack (>= 1.0)
webmock (1.17.4)
@ -664,6 +689,7 @@ DEPENDENCIES
spring (~> 1.6.3)
spring-commands-rspec (~> 1.0.4)
string-scrub
telegram-bot-ruby (~> 0.4.1)
therubyracer (~> 0.12.2)
tumblr_client!
twilio-ruby (~> 3.11.5)

View file

@ -0,0 +1,92 @@
require 'telegram/bot'
require 'open-uri'
require 'tempfile'
module Agents
class TelegramAgent < Agent
cannot_be_scheduled!
cannot_create_events!
no_bulk_receive!
gem_dependency_check { defined?(Telegram) }
description <<-MD
#{'# Include `telegram-bot-ruby` in your Gemfile to use this Agent!' if dependencies_missing?}
The Telegram Agent receives and collects events and sends them via [Telegram](https://telegram.org/).
It is assumed that events have either a `text`, `photo`, `audio`, `document` or `video` key. You can use the EventFormattingAgent if your event does not provide these keys.
The value of `text` key is sent as a plain text message.
The value of `photo`, `audio`, `document` and `video` keys should be an url which contents are sent to you according to the type.
**Setup**
1. obtain an `auth_token` by [creating a new bot](https://telegram.me/botfather).
2. [send a private message to your bot](https://telegram.me/YourHuginnBot)
3. obtain your private `chat_id` [from the recently started conversation](https://api.telegram.org/bot<auth_token>/getUpdates)
MD
def default_options
{
auth_token: 'xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
chat_id: 'xxxxxxxx'
}
end
def validate_options
errors.add(:base, 'auth_token is required') unless options['auth_token'].present?
errors.add(:base, 'chat_id is required') unless options['chat_id'].present?
end
def working?
received_event_without_error? && !recent_error_logs?
end
def receive(incoming_events)
incoming_events.each do |event|
receive_event event
end
end
private
TELEGRAM_FIELDS = {
text: :send_message,
photo: :send_photo,
audio: :send_audio,
document: :send_document,
video: :send_video
}.freeze
def receive_event(event)
TELEGRAM_FIELDS.each do |field, method|
payload = load_field event, field
next unless payload
send_telegram_message method, field => payload
end
end
def send_telegram_message(method, params)
params[:chat_id] = interpolated['chat_id']
Telegram::Bot::Client.run interpolated['auth_token'] do |bot|
bot.api.send method, params
end
end
def load_field(event, field)
payload = event.payload[field]
return false unless payload.present?
return payload if field == :text
load_file payload
end
def load_file(url)
file = Tempfile.new [File.basename(url), File.extname(url)]
file.binmode
file.write open(url).read
file.rewind
file
end
end
end

View file

@ -0,0 +1,102 @@
require 'rails_helper'
describe Agents::TelegramAgent do
before do
default_options = {
auth_token: 'xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
chat_id: 'xxxxxxxx'
}
@checker = Agents::TelegramAgent.new name: 'Telegram Tester', options: default_options
@checker.user = users(:bob)
@checker.save!
@sent_messages = []
stub_methods
end
def stub_methods
stub.any_instance_of(Agents::TelegramAgent).send_telegram_message do |method, params|
@sent_messages << { method => params }
end
stub.any_instance_of(Agents::TelegramAgent).load_file do |_url|
:stubbed_file
end
end
def event_with_payload(payload)
event = Event.new
event.agent = agents(:bob_weather_agent)
event.payload = payload
event.save!
event
end
describe 'validation' do
before do
expect(@checker).to be_valid
end
it 'should validate presence of of auth_token' do
@checker.options[:auth_token] = ''
expect(@checker).not_to be_valid
end
it 'should validate presence of of chat_id' do
@checker.options[:chat_id] = ''
expect(@checker).not_to be_valid
end
end
describe '#receive' do
it 'processes multiple events properly' do
event_0 = event_with_payload text: 'Looks like its going to rain'
event_1 = event_with_payload text: 'Another text message'
@checker.receive [event_0, event_1]
expect(@sent_messages).to eq([
{ send_message: { text: 'Looks like its going to rain' } },
{ send_message: { text: 'Another text message' } }
])
end
it 'accepts photo key and uses :send_photo to send the file' do
event = event_with_payload photo: 'https://example.com/image.png'
@checker.receive [event]
expect(@sent_messages).to eq([{ send_photo: { photo: :stubbed_file } }])
end
it 'accepts audio key and uses :send_audio to send the file' do
event = event_with_payload audio: 'https://example.com/sound.mp3'
@checker.receive [event]
expect(@sent_messages).to eq([{ send_audio: { audio: :stubbed_file } }])
end
it 'accepts document key and uses :send_document to send the file' do
event = event_with_payload document: 'https://example.com/document.pdf'
@checker.receive [event]
expect(@sent_messages).to eq([{ send_document: { document: :stubbed_file } }])
end
it 'accepts video key and uses :send_video to send the file' do
event = event_with_payload video: 'https://example.com/video.avi'
@checker.receive [event]
expect(@sent_messages).to eq([{ send_video: { video: :stubbed_file } }])
end
end
describe '#working?' do
it 'is not working without having received an event' do
expect(@checker).not_to be_working
end
it 'is working after receiving an event without error' do
@checker.last_receive_at = Time.now
expect(@checker).to be_working
end
end
end