xasin-telegram 0.1.1.dev
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/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: []
|