xasin-telegram 0.1.1.dev
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +41 -0
- data/lib/xasin/telegram/HTTPCore.rb +66 -0
- data/lib/xasin/telegram/MQTT_Adapter.rb +145 -0
- data/lib/xasin/telegram/SingleUser.rb +73 -0
- data/lib/xasin/telegram.rb +3 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '08a672d2bfc09cc9300f4079e89d575885db4d50'
|
4
|
+
data.tar.gz: c3cc7d5cc307f94739eb6d18ab6c8f69c7d088c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5dc1b8a37e4b39036a1bdcfa36ce98c533c0db87944074aae5464364cecf62d8afe9e56c9db39ac67e56990dcd1f87bd612934a3e66c076f734bb791b3599ca
|
7
|
+
data.tar.gz: 62cd7a35febfa417839088c9f0806c4a66086f53b1d21b1ed1e75f6e6e7f7ce98de360127f63488cb44f14cfb2094a779be76c2fc26f56edec441ba1e97ca755
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
# Xasin's simplifying Telegram gem
|
3
|
+
This gem is mainly meant for personal use.
|
4
|
+
Many of the existing Ruby gems for Telegram have all the functionality you want,
|
5
|
+
but also require a fairly complex setup, and good knowledge of the Telegram API.
|
6
|
+
|
7
|
+
My gem doesn't include all functionality, but aims to provide a somewhat simpler interface of
|
8
|
+
interaction with a small number (or just a single) of users.
|
9
|
+
I mainly use it for my own smart home system, to easily send and receive messages, but not much more.
|
10
|
+
|
11
|
+
## Single-User mode
|
12
|
+
The main element of this gem is the single user mode.
|
13
|
+
It discards messages of all users except one, and provides a simple "send" and "on_message" interface:
|
14
|
+
|
15
|
+
```Ruby
|
16
|
+
require 'xasin/telegram.rb'
|
17
|
+
|
18
|
+
# The HTTP "core" handles sending raw commands and getting updates, but not much more.
|
19
|
+
httpCore = Xasin::Telegram::HTTPCore.new(APIKEY);
|
20
|
+
|
21
|
+
# The SingleUser class handles the aforementioned sending/receiving of messages.
|
22
|
+
# Its first argument is the Chat-ID it should use, which is NOT the user ID
|
23
|
+
# To find it out you have to perform an update request to the Telegram API, send a message to your bot,
|
24
|
+
# and get the Chat_ID from there.
|
25
|
+
# I'm working on a better way >.>
|
26
|
+
singleUser = Xasin::Telegram::SingleUser.new(CHAT_ID, httpCore);
|
27
|
+
|
28
|
+
|
29
|
+
# From then, using the user is simple. Only text is required!
|
30
|
+
returned_id = singleUser.send_message(TEXT, **args);
|
31
|
+
|
32
|
+
# The ID that is returned can then be used to edit or delete the message:
|
33
|
+
singleUser.edit_message(returned_id, NEW_TEXT);
|
34
|
+
singleUser.delete_message(returned_id);
|
35
|
+
|
36
|
+
# And to receive messages:
|
37
|
+
singleUser.on_message do |message|
|
38
|
+
# Fetch the text from the message first!
|
39
|
+
text = message[:text];
|
40
|
+
end
|
41
|
+
```
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Xasin
|
6
|
+
module Telegram
|
7
|
+
class HTTPCore
|
8
|
+
def initialize(apikey)
|
9
|
+
@apikey = apikey;
|
10
|
+
|
11
|
+
@lastUpdateID = 0;
|
12
|
+
Thread.new do
|
13
|
+
receive_loop();
|
14
|
+
end.abort_on_exception = true
|
15
|
+
|
16
|
+
@receptors = Array.new();
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform_post(method, data = nil)
|
20
|
+
callAddress = URI "https://api.telegram.org/bot#{@apikey}/#{method}"
|
21
|
+
|
22
|
+
begin
|
23
|
+
if data
|
24
|
+
response = Net::HTTP.post_form(callAddress, data);
|
25
|
+
else
|
26
|
+
response = Net::HTTP.get callAddress
|
27
|
+
end
|
28
|
+
|
29
|
+
response = JSON.parse(response.body, symbolize_names: true);
|
30
|
+
rescue
|
31
|
+
sleep 0.5;
|
32
|
+
retry
|
33
|
+
end
|
34
|
+
|
35
|
+
return response;
|
36
|
+
end
|
37
|
+
|
38
|
+
def receive_loop()
|
39
|
+
loop do
|
40
|
+
begin
|
41
|
+
packet = perform_post("getUpdates", {timeout: 20, offset: @lastUpdateID + 1})
|
42
|
+
|
43
|
+
next unless packet[:ok];
|
44
|
+
next if packet[:result].length == 0;
|
45
|
+
|
46
|
+
packet[:result].each do |data|
|
47
|
+
hUpdateID = data[:update_id].to_i
|
48
|
+
@lastUpdateID = [hUpdateID, @lastUpdateID].max
|
49
|
+
|
50
|
+
@receptors.each do |r|
|
51
|
+
r.handle_packet(data);
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue
|
55
|
+
sleep 1
|
56
|
+
retry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def attach_receptor(receptorClass)
|
62
|
+
@receptors << receptorClass;
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
|
2
|
+
require 'mqtt/sub_handler'
|
3
|
+
|
4
|
+
module Xasin
|
5
|
+
module Telegram
|
6
|
+
module MQTT
|
7
|
+
class Server
|
8
|
+
attr_accessor :usernameList
|
9
|
+
|
10
|
+
def initialize(httpCore, mqtt)
|
11
|
+
if(httpCore.is_a? Telegram::HTTPCore)
|
12
|
+
@httpCore = httpCore;
|
13
|
+
else
|
14
|
+
@httpCore = Telegram::HTTPCore.new(httpCore);
|
15
|
+
end
|
16
|
+
@httpCore.attach_receptor(self);
|
17
|
+
|
18
|
+
@mqtt = mqtt;
|
19
|
+
|
20
|
+
# Hash {username => ChatID}
|
21
|
+
@usernameList = Hash.new();
|
22
|
+
# Hash {ChatID => {GroupID => MessageID}}
|
23
|
+
@groupIDList = Hash.new();
|
24
|
+
|
25
|
+
setup_mqtt();
|
26
|
+
end
|
27
|
+
|
28
|
+
# Processes messages received through MQTT
|
29
|
+
# It takes care of setting a few good defaults (like parse_mode),
|
30
|
+
# deletes any old messages of the same GroupID (if requested),
|
31
|
+
# and stores the new Message ID for later processing
|
32
|
+
# @param data [Hash] The raw "message" object received from the Telegram API
|
33
|
+
# @param uID [Integer,String] The user-id as received from the MQTT Wildcard.
|
34
|
+
# Can be a username defined in @usernameList
|
35
|
+
def _handle_send(data, uID)
|
36
|
+
# Resolve a saved Username to a User-ID
|
37
|
+
uID = @usernameList[uID] if(@usernameList.key? uID)
|
38
|
+
uID = uID.to_i;
|
39
|
+
|
40
|
+
begin
|
41
|
+
data = JSON.parse(data, symbolize_names: true);
|
42
|
+
rescue
|
43
|
+
# Allow for pure-text to be sent (easier on the ESPs)
|
44
|
+
data = {text: data}
|
45
|
+
end
|
46
|
+
|
47
|
+
data[:parse_mode] ||= "Markdown";
|
48
|
+
data[:chat_id] = uID;
|
49
|
+
|
50
|
+
reply = @httpCore.perform_post("sendMessage", data);
|
51
|
+
|
52
|
+
# Check if this message has a grouping ID
|
53
|
+
if(gID = data[:GID])
|
54
|
+
# If the message has the :single flag, delete the last one
|
55
|
+
if(data[:single])
|
56
|
+
_handle_delete(gID, uID);
|
57
|
+
end
|
58
|
+
|
59
|
+
# Save this grouping ID
|
60
|
+
@groupIDList[uID][gID] = reply[:result][:message_id];
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def _handle_edit(data, uID)
|
65
|
+
# Resolve a saved Username to a User-ID
|
66
|
+
uID = @usernameList[uID] if(@usernameList.key? uID)
|
67
|
+
uID = uID.to_i;
|
68
|
+
|
69
|
+
begin
|
70
|
+
data = JSON.parse(data, symbolize_names: true);
|
71
|
+
|
72
|
+
return unless data[:text];
|
73
|
+
# Fetch the target Message ID
|
74
|
+
return unless mID = @groupIDList[uID][data[:GID]]
|
75
|
+
|
76
|
+
# Send the POST request editing the message text
|
77
|
+
@httpCore.perform_post("editMessageText",
|
78
|
+
{ text: data[:text],
|
79
|
+
chat_id: uID,
|
80
|
+
message_id: mID});
|
81
|
+
rescue
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def _handle_delete(data, uID)
|
86
|
+
# Resolve a saved Username to a User-ID
|
87
|
+
uID = @usernameList[uID] if(@usernameList.key? uID)
|
88
|
+
uID = uID.to_i;
|
89
|
+
|
90
|
+
# Fetch the real message ID held by a grouping ID
|
91
|
+
return unless mID = @groupIDList[uID][data]
|
92
|
+
@groupIDList[uID].delete(data);
|
93
|
+
|
94
|
+
@httpCore.perform_post("deleteMessage", {chat_id: uID, message_id: mID});
|
95
|
+
end
|
96
|
+
|
97
|
+
def setup_mqtt()
|
98
|
+
@mqtt.subscribe_to "Telegram/+/Send" do |data, tSplit|
|
99
|
+
_handle_send(data, tSplit[0]);
|
100
|
+
end
|
101
|
+
|
102
|
+
@mqtt.subscribe_to "Telegram/+/Edit" do |data, tSplit|
|
103
|
+
_handle_edit(data, tSplit[0])
|
104
|
+
end
|
105
|
+
|
106
|
+
@mqtt.subscribe_to "Telegram/+/Delete" do |data, tSplit|
|
107
|
+
_handle_delete(data, tSplit[0])
|
108
|
+
end
|
109
|
+
|
110
|
+
@mqtt.subscribe_to "Telegram/+/Release" do |data, tSplit|
|
111
|
+
# Resolve a saved Username to a User-ID
|
112
|
+
uID = tSplit[0];
|
113
|
+
uID = @usernameList[uID] if(@usernameList.key? uID)
|
114
|
+
uID = uID.to_i;
|
115
|
+
|
116
|
+
# Delete the stored GID key
|
117
|
+
@groupIDList[uID].delete(data);
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def handle_packet(packet)
|
122
|
+
if(msg = packet[:message])
|
123
|
+
uID = msg[:chat][:id];
|
124
|
+
if(newUID = @usernameList.key(uID))
|
125
|
+
uID = newUID
|
126
|
+
end
|
127
|
+
|
128
|
+
data = Hash.new();
|
129
|
+
return unless(data[:text] = msg[:text])
|
130
|
+
|
131
|
+
if(replyMSG = msg[:reply_to_message])
|
132
|
+
data[:reply_GID] = @groupIDList[uID].key(replyMSG[:message_id]);
|
133
|
+
end
|
134
|
+
|
135
|
+
if(data[:reply_GID])
|
136
|
+
@mqtt.publish_to "Telegram/#{uID}/Reply", data;
|
137
|
+
else
|
138
|
+
@mqtt.publish_to "Telegram/#{uID}/Received", data;
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
require_relative "HTTPCore.rb"
|
3
|
+
|
4
|
+
module Xasin
|
5
|
+
module Telegram
|
6
|
+
class SingleUser
|
7
|
+
attr_reader :httpCore
|
8
|
+
|
9
|
+
def initialize(userChat, httpCore)
|
10
|
+
@httpCore = httpCore.is_a?(Telegram::HTTPCore) ? httpCore : HTTPCore.new(httpCore);
|
11
|
+
@httpCore.attach_receptor(self);
|
12
|
+
|
13
|
+
@userID = userChat;
|
14
|
+
|
15
|
+
@message_procs = Array.new();
|
16
|
+
@inlinebutton_procs = Array.new();
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle_packet(packet)
|
20
|
+
if(packet[:message]) then
|
21
|
+
return unless packet[:message][:chat][:id] == @userID;
|
22
|
+
|
23
|
+
@message_procs.each do |cb| cb.call(packet[:message]); end
|
24
|
+
packet[:has_been_handled] = true;
|
25
|
+
end
|
26
|
+
|
27
|
+
if(packet[:callback_query]) then
|
28
|
+
return unless packet[:callback_query][:message][:chat][:id] == @userID;
|
29
|
+
|
30
|
+
@inlinebutton_procs.each do |cb| cb.call(packet[:callback_query]); end
|
31
|
+
packet[:has_been_handled] = true;
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_message(text, **args)
|
36
|
+
args ||= Hash.new();
|
37
|
+
args[:text] = text;
|
38
|
+
|
39
|
+
args[:chat_id] = @userID;
|
40
|
+
args[:parse_mode] ||= "Markdown";
|
41
|
+
|
42
|
+
sent_message = @httpCore.perform_post("sendMessage", args);
|
43
|
+
|
44
|
+
return sent_message[:result][:message_id];
|
45
|
+
end
|
46
|
+
|
47
|
+
def edit_message(mID, text=nil, **args)
|
48
|
+
args[:chat_id] = @userID;
|
49
|
+
args[:message_id] = mID;
|
50
|
+
|
51
|
+
args[:parse_mode] ||= "Markdown";
|
52
|
+
|
53
|
+
if(text) then
|
54
|
+
args[:text] = text;
|
55
|
+
@httpCore.perform_post("editMessageText", args);
|
56
|
+
else
|
57
|
+
@httpCore.perform_post("editMessageReplyMarkup", args);
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_message(mID)
|
62
|
+
@httpCore.perform_post("deleteMessage", {chat_id: @userID, message_id: mID});
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_message(&block)
|
66
|
+
@message_procs << block;
|
67
|
+
end
|
68
|
+
def on_inlinebutton_press(&block)
|
69
|
+
@inlinebutton_procs << block;
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xasin-telegram
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1.dev
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Xasin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mqtt-sub_handler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Multi-Purpose Telegram gem. Mainly for personal use, but also used as
|
28
|
+
a Telegram to MQTT Bridge for IoT devices
|
29
|
+
email:
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- lib/xasin/telegram.rb
|
36
|
+
- lib/xasin/telegram/HTTPCore.rb
|
37
|
+
- lib/xasin/telegram/MQTT_Adapter.rb
|
38
|
+
- lib/xasin/telegram/SingleUser.rb
|
39
|
+
homepage: https://github.com/XasWorks/XasCode/tree/GEM_Telegram/Ruby/Telegram
|
40
|
+
licenses:
|
41
|
+
- GPL-3.0
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.3.1
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.6.14.1
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Xasin's Telegram gem
|
63
|
+
test_files: []
|