telegram-rb 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 +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
|
+
[](https://gitter.im/ssut/telegram-rb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
4
|
+
|
5
|
+
[](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: []
|