telegram-rb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +42 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +14 -0
- data/example.rb +28 -0
- data/lib/telegram.rb +3 -0
- data/lib/telegram/api.rb +115 -0
- data/lib/telegram/callback.rb +29 -0
- data/lib/telegram/client.rb +148 -0
- data/lib/telegram/connection.rb +73 -0
- data/lib/telegram/connection_pool.rb +37 -0
- data/lib/telegram/events.rb +117 -0
- data/lib/telegram/logger.rb +29 -0
- data/lib/telegram/models.rb +167 -0
- data/lib/telegram/version.rb +4 -0
- data/telegram-rb.gemspec +17 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5eca42b752465bba38de5c76c31efdc2782c402f
|
4
|
+
data.tar.gz: 4dc3258d4b4d17c4b245320e3eb37e1f6458bb91
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd11d9f7e7db37260933db545884a9306f54317fd727d24dbdb6fc9007f78b2181dc8d4eb0d89275d6fec334bb6c69e491f8f8bd218735417f8af82470ddc818
|
7
|
+
data.tar.gz: c3572018df7cba228ec57c5d6f82c133efcaf5aad283e31112ec0bd8e52069e0c5fe2ff36eaf0ed8b9ef8699174bd16808bfcbe802cff8d7e80616b1858e0522
|
data/.gitignore
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/vendor/bundle
|
26
|
+
/lib/bundler/man/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
# Gemfile.lock
|
31
|
+
# .ruby-version
|
32
|
+
# .ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
36
|
+
|
37
|
+
# OS X
|
38
|
+
.DS_Store
|
39
|
+
|
40
|
+
# Telegram
|
41
|
+
telegram-cli
|
42
|
+
tg-server.pub
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 SuHun Han
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Telegram API for Ruby!
|
2
|
+
|
3
|
+
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ssut/telegram-rb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
4
|
+
|
5
|
+
[![Code Climate](https://codeclimate.com/github/ssut/telegram-rb/badges/gpa.svg)](https://codeclimate.com/github/ssut/telegram-rb)
|
6
|
+
|
7
|
+
A Ruby wrapper that communicates with the [Telegram-CLI](https://github.com/vysheng/tg).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
### Requirements
|
12
|
+
|
13
|
+
* You need to install the [Telegram-CLI](https://github.com/vysheng/tg) first.
|
14
|
+
|
data/example.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.join(File.dirname(__FILE__), 'lib')
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
|
5
|
+
require 'eventmachine'
|
6
|
+
require 'telegram'
|
7
|
+
|
8
|
+
EM.run do
|
9
|
+
telegram = Telegram::Client.new do |cfg|
|
10
|
+
cfg.daemon = './telegram-cli'
|
11
|
+
cfg.key = '/Users/ssut/tmp/tg/tg-server.pub'
|
12
|
+
end
|
13
|
+
|
14
|
+
telegram.connect do
|
15
|
+
puts telegram.profile
|
16
|
+
telegram.contacts.each do |contact|
|
17
|
+
puts contact
|
18
|
+
end
|
19
|
+
telegram.chats.each do |chat|
|
20
|
+
puts chat
|
21
|
+
end
|
22
|
+
|
23
|
+
telegram.on[Telegram::EventType::RECEIVE_MESSAGE] = Proc.new { |ev|
|
24
|
+
|
25
|
+
}
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/telegram.rb
ADDED
data/lib/telegram/api.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module Telegram
|
2
|
+
class API
|
3
|
+
def update!(&cb)
|
4
|
+
done = false
|
5
|
+
EM.synchrony do
|
6
|
+
multi = EM::Synchrony::Multi.new
|
7
|
+
multi.add :profile, update_profile!
|
8
|
+
multi.add :contacts, update_contacts!
|
9
|
+
multi.add :chats, update_chats!
|
10
|
+
multi.perform
|
11
|
+
done = true
|
12
|
+
end
|
13
|
+
|
14
|
+
check_done = Proc.new {
|
15
|
+
if done
|
16
|
+
@starts_at = Time.now
|
17
|
+
cb.call unless cb.nil?
|
18
|
+
logger.info("Successfully loaded all information")
|
19
|
+
else
|
20
|
+
EM.next_tick(&check_done)
|
21
|
+
end
|
22
|
+
}
|
23
|
+
EM.add_timer(0, &check_done)
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_profile!
|
27
|
+
assert!
|
28
|
+
callback = Callback.new
|
29
|
+
@profile = nil
|
30
|
+
@connection.communicate('get_self') do |success, data|
|
31
|
+
if success
|
32
|
+
callback.trigger(:success)
|
33
|
+
contact = TelegramContact.pick_or_new(self, data)
|
34
|
+
@contacts << contact unless self.contacts.include?(contact)
|
35
|
+
@profile = contact
|
36
|
+
else
|
37
|
+
raise "Couldn't fetch the user profile."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
callback
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_contacts!
|
44
|
+
assert!
|
45
|
+
callback = Callback.new
|
46
|
+
@contacts = []
|
47
|
+
@connection.communicate('contact_list') do |success, data|
|
48
|
+
if success and data.class == Array
|
49
|
+
callback.trigger(:success)
|
50
|
+
data.each { |contact|
|
51
|
+
contact = TelegramContact.pick_or_new(self, contact)
|
52
|
+
@contacts << contact unless self.contacts.include?(contact)
|
53
|
+
}
|
54
|
+
else
|
55
|
+
raise "Couldn't fetch the contact list."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
callback
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_chats!
|
62
|
+
assert!
|
63
|
+
callback = Callback.new
|
64
|
+
collected = 0
|
65
|
+
|
66
|
+
collect_done = Proc.new { |id, data, count|
|
67
|
+
collected += 1
|
68
|
+
@chats << TelegramChat.new(self, data)
|
69
|
+
callback.trigger(:success) if collected == count
|
70
|
+
}
|
71
|
+
collect = Proc.new { |id, count|
|
72
|
+
@connection.communicate(['chat_info', "chat\##{id}"]) do |success, data|
|
73
|
+
collect_done.call(id, data, count) if success
|
74
|
+
end
|
75
|
+
}
|
76
|
+
|
77
|
+
@chats = []
|
78
|
+
@connection.communicate('dialog_list') do |success, data|
|
79
|
+
if success and data.class == Array
|
80
|
+
chatsize = data.count { |chat| chat['type'] == 'chat' }
|
81
|
+
data.each { |chat|
|
82
|
+
if chat['type'] == 'chat'
|
83
|
+
collect.call(chat['id'], chatsize)
|
84
|
+
elsif chat['type'] == 'user'
|
85
|
+
@chats << TelegramChat.new(self, chat)
|
86
|
+
end
|
87
|
+
}
|
88
|
+
else
|
89
|
+
raise "Couldn't fetch the dialog(chat) list."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
callback
|
93
|
+
end
|
94
|
+
|
95
|
+
def msg(target, text, &callback)
|
96
|
+
assert!
|
97
|
+
@connection.communicate(['msg', target, text], &callback)
|
98
|
+
end
|
99
|
+
|
100
|
+
def chat_add_user(chat, user, &callback)
|
101
|
+
assert!
|
102
|
+
@connection.communicate(['chat_add_user', chat.to_tg, user.to_tg], &callback)
|
103
|
+
end
|
104
|
+
|
105
|
+
def chat_del_user(chat, user, &callback)
|
106
|
+
assert!
|
107
|
+
@connection.communicate(['chat_del_user', chat.to_tg, user.to_tg], &callback)
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
def assert!
|
112
|
+
raise "It appears that the connection to the telegram-cli is disconnected." unless connected?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Telegram
|
2
|
+
class Callback
|
3
|
+
attr_reader :data
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@success = nil
|
7
|
+
@fail = nil
|
8
|
+
@data = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def callback(&cb)
|
12
|
+
@success = cb
|
13
|
+
end
|
14
|
+
|
15
|
+
def errback(&cb)
|
16
|
+
@fail = cb
|
17
|
+
end
|
18
|
+
|
19
|
+
def trigger(type = :success, data = nil)
|
20
|
+
@data = data
|
21
|
+
case type
|
22
|
+
when :success
|
23
|
+
@success.call
|
24
|
+
when :fail
|
25
|
+
@fail.call
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'eventmachine'
|
3
|
+
require "em-synchrony"
|
4
|
+
require 'em-synchrony/fiber_iterator'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'oj'
|
7
|
+
require 'shellwords'
|
8
|
+
require 'date'
|
9
|
+
|
10
|
+
require 'telegram/logger'
|
11
|
+
require 'telegram/connection'
|
12
|
+
require 'telegram/connection_pool'
|
13
|
+
require 'telegram/callback'
|
14
|
+
require 'telegram/api'
|
15
|
+
require 'telegram/models'
|
16
|
+
require 'telegram/events'
|
17
|
+
|
18
|
+
module Telegram
|
19
|
+
class Client < API
|
20
|
+
include Logging
|
21
|
+
|
22
|
+
attr_reader :connection
|
23
|
+
|
24
|
+
attr_reader :profile
|
25
|
+
attr_reader :contacts
|
26
|
+
attr_reader :chats
|
27
|
+
|
28
|
+
attr_accessor :on
|
29
|
+
|
30
|
+
def initialize(&b)
|
31
|
+
@config = OpenStruct.new(:daemon => 'bin/telegram', :key => 'tg-server.pub', :sock => 'tg.sock', :size => 5)
|
32
|
+
yield @config
|
33
|
+
@connected = 0
|
34
|
+
@stdout = nil
|
35
|
+
@connect_callback = nil
|
36
|
+
@on = {}
|
37
|
+
|
38
|
+
@profile = nil
|
39
|
+
@contacts = []
|
40
|
+
@chats = []
|
41
|
+
@starts_at = nil
|
42
|
+
@events = EM::Queue.new
|
43
|
+
|
44
|
+
logger.info("Initialized")
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute
|
48
|
+
command = "'#{@config.daemon}' -Ck '#{@config.key}' -I -WS '#{@config.sock}' --json"
|
49
|
+
@stdout = IO.popen(command)
|
50
|
+
loop do
|
51
|
+
if t = @stdout.readline then
|
52
|
+
break if t.include?('I: config')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
proc {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def poll
|
59
|
+
data = ''
|
60
|
+
logger.info("Start polling for events")
|
61
|
+
loop do
|
62
|
+
begin
|
63
|
+
byte = @stdout.read_nonblock 1
|
64
|
+
rescue IO::WaitReadable
|
65
|
+
IO.select([@stdout])
|
66
|
+
retry
|
67
|
+
rescue EOFError
|
68
|
+
logger.error("EOFError occurred during the polling")
|
69
|
+
return
|
70
|
+
end
|
71
|
+
data << byte unless @starts_at.nil?
|
72
|
+
if byte.include?("\n")
|
73
|
+
begin
|
74
|
+
brace = data.index('{')
|
75
|
+
data = data[brace..-2]
|
76
|
+
data = Oj.load(data)
|
77
|
+
@events << data
|
78
|
+
rescue
|
79
|
+
end
|
80
|
+
data = ''
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def process_data
|
86
|
+
process = Proc.new { |data|
|
87
|
+
begin
|
88
|
+
type = case data['event']
|
89
|
+
when 'message'
|
90
|
+
if data['from']['id'] != @profile.id
|
91
|
+
EventType::RECEIVE_MESSAGE
|
92
|
+
else
|
93
|
+
EventType::SEND_MESSAGE
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
action = data.has_key?('action') ? case data['action']
|
98
|
+
when 'chat_add_user'
|
99
|
+
ActionType::CHAT_ADD_USER
|
100
|
+
else
|
101
|
+
ActionType::UNKNOWN_ACTION
|
102
|
+
end : ActionType::NO_ACTION
|
103
|
+
|
104
|
+
event = Event.new(self, type, action, data)
|
105
|
+
@on[type].call(event) if @on.has_key?(type)
|
106
|
+
rescue Exception => e
|
107
|
+
logger.error("Error occurred during the processing: #{data}\n #{e.inspect} #{e.backtrace}")
|
108
|
+
end
|
109
|
+
@events.pop(&process)
|
110
|
+
}
|
111
|
+
@events.pop(&process)
|
112
|
+
end
|
113
|
+
|
114
|
+
def connect(&block)
|
115
|
+
logger.info("Trying to start telegram-cli and then connect")
|
116
|
+
@connect_callback = block
|
117
|
+
process_data
|
118
|
+
EM.defer(execute, create_pool)
|
119
|
+
end
|
120
|
+
|
121
|
+
def create_pool
|
122
|
+
@connection = ConnectionPool.new(@config.size) do
|
123
|
+
client = EM.connect_unix_domain(@config.sock, Connection)
|
124
|
+
client.on_connect = self.method(:on_connect)
|
125
|
+
client.on_disconnect = self.method(:on_disconnect)
|
126
|
+
client
|
127
|
+
end
|
128
|
+
proc {}
|
129
|
+
end
|
130
|
+
|
131
|
+
def on_connect
|
132
|
+
@connected += 1
|
133
|
+
if connected?
|
134
|
+
logger.info("Successfully connected to the Telegram CLI")
|
135
|
+
EM.defer(&method(:poll))
|
136
|
+
update!(&@connect_callback)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def on_disconnect
|
141
|
+
@connected -= 1
|
142
|
+
end
|
143
|
+
|
144
|
+
def connected?
|
145
|
+
@connected == @config.size
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Telegram
|
2
|
+
class Connection < EM::Connection
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
@connected = false
|
6
|
+
@on_connect = nil
|
7
|
+
@on_disconnect = nil
|
8
|
+
@callback = nil
|
9
|
+
@available = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def available?
|
13
|
+
@available
|
14
|
+
end
|
15
|
+
|
16
|
+
def communicate(*messages, &callback)
|
17
|
+
@available = false
|
18
|
+
@callback = callback
|
19
|
+
messages = messages.each_with_index.map { |m, i|
|
20
|
+
if i > 0
|
21
|
+
m = "\"#{m}\""
|
22
|
+
end
|
23
|
+
m
|
24
|
+
}.join(' ') << "\n"
|
25
|
+
send_data(messages)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_connect=(block)
|
29
|
+
@on_connect = block
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_disconnect=(block)
|
33
|
+
@on_disconnect = block
|
34
|
+
end
|
35
|
+
|
36
|
+
# @api private
|
37
|
+
def connection_completed
|
38
|
+
@connected = true
|
39
|
+
@on_connect.call unless @on_connect.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
def unbind
|
43
|
+
@connected = false
|
44
|
+
@on_disconnect.call unless @on_disconnect.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def connected?
|
48
|
+
@connected
|
49
|
+
end
|
50
|
+
|
51
|
+
def receive_data(data)
|
52
|
+
begin
|
53
|
+
result = _receive_data(data)
|
54
|
+
rescue
|
55
|
+
result = nil
|
56
|
+
end
|
57
|
+
@callback.call(!result.nil?, result) unless @callback.nil?
|
58
|
+
@callback = nil
|
59
|
+
@available = true
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
def _receive_data(data)
|
64
|
+
if data[0..6] == 'ANSWER '
|
65
|
+
lf = data.index("\n") + 1
|
66
|
+
lflf = data.index("\n\n", lf) - 1
|
67
|
+
data = data[lf..lflf]
|
68
|
+
data = Oj.load(data)
|
69
|
+
end
|
70
|
+
data
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Telegram
|
2
|
+
class ConnectionPool < Array
|
3
|
+
include Logging
|
4
|
+
|
5
|
+
attr_reader :size
|
6
|
+
|
7
|
+
def initialize(size=10, &block)
|
8
|
+
size.times do
|
9
|
+
self << block.call if block_given?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def communicate(*messages, &block)
|
14
|
+
begin
|
15
|
+
acquire do |conn|
|
16
|
+
conn.communicate(*messages, &block)
|
17
|
+
end
|
18
|
+
rescue Exception => e
|
19
|
+
logger.error("Error occurred during the communicating: #{e.inspect} #{e.backtrace}")
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def acquire(&callback)
|
25
|
+
acq = Proc.new {
|
26
|
+
conn = self.find { |conn| conn.available? }
|
27
|
+
if not conn.nil? and conn.connected?
|
28
|
+
callback.call(conn)
|
29
|
+
else
|
30
|
+
logger.warning("Failed to acquire available connection, retry after 0.1 second")
|
31
|
+
EM.add_timer(0.1, &acq)
|
32
|
+
end
|
33
|
+
}
|
34
|
+
EM.add_timer(0, &acq)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Telegram
|
2
|
+
module EventType
|
3
|
+
UNKNOWN_EVENT = -1
|
4
|
+
SERVICE = 0
|
5
|
+
RECEIVE_MESSAGE = 1
|
6
|
+
SEND_MESSAGE = 2
|
7
|
+
ONLINE_STATUS = 3
|
8
|
+
end
|
9
|
+
|
10
|
+
module ActionType
|
11
|
+
UNKNOWN_ACTION = -1
|
12
|
+
NO_ACTION = 0
|
13
|
+
CHAT_ADD_USER = 1
|
14
|
+
CHAT_DEL_USER = 2
|
15
|
+
CHAT_RENAME = 3
|
16
|
+
end
|
17
|
+
|
18
|
+
class Message < Struct.new(:text, :type, :from, :from_type, :raw_from, :to, :to_type, :raw_to); end
|
19
|
+
|
20
|
+
class Event
|
21
|
+
# @return [Number]
|
22
|
+
attr_reader :id
|
23
|
+
|
24
|
+
# @return [EventType]
|
25
|
+
attr_reader :event
|
26
|
+
|
27
|
+
# @return [ActionType]
|
28
|
+
attr_reader :action
|
29
|
+
|
30
|
+
# @return [Time]
|
31
|
+
attr_reader :time
|
32
|
+
|
33
|
+
# @return [Message]
|
34
|
+
attr_reader :message
|
35
|
+
|
36
|
+
# @return [TelegramMessage]
|
37
|
+
attr_reader :tgmessage
|
38
|
+
|
39
|
+
def initialize(client, event = EventType::UNKNOWN_EVENT, action = ActionType::NO_ACTION, data = {})
|
40
|
+
@client = client
|
41
|
+
@message = nil
|
42
|
+
@tgmessage = nil
|
43
|
+
@raw_data = data
|
44
|
+
@time = nil
|
45
|
+
|
46
|
+
@event = event
|
47
|
+
@action = action
|
48
|
+
|
49
|
+
@time = Time.at(data['date'].to_i) if data.has_key?('date')
|
50
|
+
@time = DateTime.strptime(data['when'], "%Y-%m-%d %H:%M:%S") if @time.nil? and data.has_key?('when')
|
51
|
+
|
52
|
+
case event
|
53
|
+
when EventType::SERVICE
|
54
|
+
foramt_service
|
55
|
+
when EventType::RECEIVE_MESSAGE, EventType::SEND_MESSAGE
|
56
|
+
format_message
|
57
|
+
@tgmessage = TelegramMessage.new(@client, self)
|
58
|
+
when EventType::ONLINE_STATUS
|
59
|
+
foramt_status
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def format_service
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def format_message
|
68
|
+
message = Message.new
|
69
|
+
message.text = @raw_data['text']
|
70
|
+
message.type = @raw_data.has_key?('media') ? @raw_data['media']['type'] : 'text'
|
71
|
+
message.raw_from = @raw_data['from']['id']
|
72
|
+
message.from_type = @raw_data['from']['type']
|
73
|
+
message.raw_to = @raw_data['to']['id']
|
74
|
+
message.to_type = @raw_data['to']['type']
|
75
|
+
|
76
|
+
from = @client.contacts.find { |c| c.id == message.raw_from }
|
77
|
+
to = @client.contacts.find { |c| c.id == message.raw_to }
|
78
|
+
to = @client.chats.find { |c| c.id == message.raw_to } if to.nil?
|
79
|
+
|
80
|
+
message.from = from
|
81
|
+
message.to = to
|
82
|
+
|
83
|
+
@message = message
|
84
|
+
|
85
|
+
if @message.from.nil?
|
86
|
+
user = @raw_data['from']
|
87
|
+
user = TelegramContact.pick_or_new(@client, user)
|
88
|
+
@client.contacts << user unless @client.contacts.include?(user)
|
89
|
+
@message.from = user
|
90
|
+
end
|
91
|
+
|
92
|
+
if @message.to.nil?
|
93
|
+
type = @raw_data['to']['type']
|
94
|
+
if type == 'chat'
|
95
|
+
chat = @raw_data['to']
|
96
|
+
chat = TelegramChat.pick_or_new(@client, chat)
|
97
|
+
@client.chats << chat unless @client.chats.include?(chat)
|
98
|
+
@message.from = chat
|
99
|
+
elsif type == 'user'
|
100
|
+
user = @raw_data['to']
|
101
|
+
user = TelegramContact.pick_or_new(@client, user)
|
102
|
+
@client.contacts << user unless @client.contacts.include?(user)
|
103
|
+
@message.to = user
|
104
|
+
elsif type == 'encr_chat'
|
105
|
+
chat = @raw_data['to']
|
106
|
+
chat = TelegramChat.pick_or_new(@client, chat)
|
107
|
+
@client.chats << chat unless @client.chats.include?(chat)
|
108
|
+
@message.to = chat
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_s
|
114
|
+
"<Event Type=#{@event} Action=#{@action} Time=#{@time} Message=#{@message}>"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Telegram
|
4
|
+
module Logging
|
5
|
+
def logger
|
6
|
+
@logger ||= Logging.logger_for(self.class.name)
|
7
|
+
end
|
8
|
+
|
9
|
+
@loggers = {}
|
10
|
+
class << self
|
11
|
+
def logger_for(klass)
|
12
|
+
@loggers[klass] ||= configure_logger_for(klass)
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure_logger_for(klass)
|
16
|
+
logger = Logger.new(STDOUT)
|
17
|
+
logger.progname = klass
|
18
|
+
logger.level = Logger::DEBUG
|
19
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
20
|
+
date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
21
|
+
blanks = severity.size == 4 ? ' ' : ' '
|
22
|
+
"[#{date_format}] #{severity}#{blanks}(#{progname}): #{msg}\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
logger
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Telegram
|
2
|
+
class TelegramBase
|
3
|
+
attr_reader :client
|
4
|
+
attr_reader :id
|
5
|
+
|
6
|
+
def send_message(text, refer)
|
7
|
+
target = case @type
|
8
|
+
when 'encr_chat'
|
9
|
+
"#{@title}"
|
10
|
+
else
|
11
|
+
to_tg
|
12
|
+
end
|
13
|
+
@client.msg(target, text)
|
14
|
+
end
|
15
|
+
|
16
|
+
def send_sticker()
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_image(path, refer, &callback)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def send_image_url(url, refer, &callback)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class TelegramChat < TelegramBase
|
30
|
+
attr_reader :name
|
31
|
+
attr_reader :members
|
32
|
+
attr_reader :type
|
33
|
+
|
34
|
+
def self.pick_or_new(client, chat)
|
35
|
+
ct = client.chats.find { |c| c.id == chat['id'] }
|
36
|
+
return ct unless ct.nil?
|
37
|
+
TelegramChat.new(client, chat)
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(client, chat)
|
41
|
+
@client = client
|
42
|
+
@chat = chat
|
43
|
+
|
44
|
+
@id = chat['id']
|
45
|
+
@title = chat.has_key?('title') ? chat['title'] : chat['print_name']
|
46
|
+
@type = chat['type']
|
47
|
+
|
48
|
+
@members = []
|
49
|
+
if chat.has_key?('members')
|
50
|
+
chat['members'].each { |user|
|
51
|
+
@members << TelegramContact.pick_or_new(client, user)
|
52
|
+
}
|
53
|
+
elsif @type == 'user' and chat['user']
|
54
|
+
@members << TelegramContact.pick_or_new(client, chat)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def leave!
|
59
|
+
@client.chat_del_user(self, @client.profile)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_tg
|
63
|
+
"#{@type}\##{@id}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
"<TelegramChat #{@title}(#{@type}\##{@id}) members=#{@members.size}>"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class TelegramContact < TelegramBase
|
72
|
+
attr_reader :name
|
73
|
+
attr_reader :phone
|
74
|
+
attr_reader :type
|
75
|
+
|
76
|
+
def self.pick_or_new(client, contact)
|
77
|
+
ct = client.contacts.find { |c| c.id == contact['id'] }
|
78
|
+
return ct unless ct.nil?
|
79
|
+
TelegramContact.new(client, contact)
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize(client, contact)
|
83
|
+
@client = client
|
84
|
+
@contact = contact
|
85
|
+
|
86
|
+
@id = contact['id']
|
87
|
+
@type = 'user'
|
88
|
+
@username = contact.has_key?('username') ? contact['username'] : ''
|
89
|
+
@name = contact['print_name']
|
90
|
+
@phone = contact.has_key?('phone') ? contact['phone'] : ''
|
91
|
+
|
92
|
+
@client.contacts << self unless @client.contacts.include?(self)
|
93
|
+
end
|
94
|
+
|
95
|
+
def chats
|
96
|
+
@client.chats.select { |c| c.member.include?(self) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_tg
|
100
|
+
"#{@type}\##{@id}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s
|
104
|
+
"<TelegramContact #{@name}(#{@id}) username=#{@username}>"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class TelegramMessage
|
109
|
+
# @return [Telegram]
|
110
|
+
attr_reader :client
|
111
|
+
|
112
|
+
# @return [String]
|
113
|
+
attr_reader :raw
|
114
|
+
|
115
|
+
# @return [Integer]
|
116
|
+
attr_reader :id
|
117
|
+
|
118
|
+
# @return [Time]
|
119
|
+
attr_reader :time
|
120
|
+
|
121
|
+
# @return [TelegramContact] The user who sent this message
|
122
|
+
attr_reader :user
|
123
|
+
|
124
|
+
# targets to send a message
|
125
|
+
attr_reader :raw_target
|
126
|
+
attr_reader :target
|
127
|
+
|
128
|
+
# @return [TelegramChat]
|
129
|
+
attr_reader :chat
|
130
|
+
|
131
|
+
def initialize(client, event)
|
132
|
+
@event = event
|
133
|
+
|
134
|
+
@id = event.id
|
135
|
+
@raw = event.message.text
|
136
|
+
@time = event.time
|
137
|
+
@content_type = event.message.type
|
138
|
+
|
139
|
+
@raw_sender = event.message.raw_from
|
140
|
+
@raw_receiver = event.message.raw_to
|
141
|
+
|
142
|
+
@user = @sender = event.message.from
|
143
|
+
@receiver = event.message.to
|
144
|
+
|
145
|
+
@target = case @receiver.type
|
146
|
+
when 'user'
|
147
|
+
@sender
|
148
|
+
when 'chat', 'encr_chat'
|
149
|
+
@receiver
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def reply_user(type, content)
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
def reply(type, content, target=nil, &cb)
|
158
|
+
target = @target if target.nil?
|
159
|
+
if type == :text
|
160
|
+
target.send_message(content, self)
|
161
|
+
elsif type == :sticker
|
162
|
+
elsif type == :image
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/telegram-rb.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
lib = File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
require 'telegram/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.date = Date.today.to_s
|
8
|
+
s.name = 'telegram-rb'
|
9
|
+
s.version = Telegram::VERSION
|
10
|
+
s.licenses = ['MIT']
|
11
|
+
s.summary = 'A Ruby wrapper that communicates with the telegram-cli.'
|
12
|
+
s.description = "A Ruby wrapper that communicates with the telegram-cli."
|
13
|
+
s.authors = ["SuHun Han (ssut)"]
|
14
|
+
s.email = 'ssut@ssut.me'
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.homepage = 'https://github.com/ssut/telegram-rb'
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: telegram-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- SuHun Han (ssut)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A Ruby wrapper that communicates with the telegram-cli.
|
14
|
+
email: ssut@ssut.me
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- ".gitignore"
|
20
|
+
- Gemfile
|
21
|
+
- LICENSE
|
22
|
+
- README.md
|
23
|
+
- example.rb
|
24
|
+
- lib/telegram.rb
|
25
|
+
- lib/telegram/api.rb
|
26
|
+
- lib/telegram/callback.rb
|
27
|
+
- lib/telegram/client.rb
|
28
|
+
- lib/telegram/connection.rb
|
29
|
+
- lib/telegram/connection_pool.rb
|
30
|
+
- lib/telegram/events.rb
|
31
|
+
- lib/telegram/logger.rb
|
32
|
+
- lib/telegram/models.rb
|
33
|
+
- lib/telegram/version.rb
|
34
|
+
- telegram-rb.gemspec
|
35
|
+
homepage: https://github.com/ssut/telegram-rb
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.4.5
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: A Ruby wrapper that communicates with the telegram-cli.
|
59
|
+
test_files: []
|