Renamed files and libs
Added config file (config.yml) Changed logger implementation Correct Telegram session terminating
This commit is contained in:
parent
854b61ada0
commit
08540206f0
13
config.yml.example
Normal file
13
config.yml.example
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
telegram:
|
||||||
|
|
||||||
|
api_id: '17349'
|
||||||
|
api_hash: '344583e45741c457fe1862106095a5eb'
|
||||||
|
verbosity: 3
|
||||||
|
|
||||||
|
xmpp:
|
||||||
|
|
||||||
|
jid: 'zhabogram.localhost'
|
||||||
|
host: '127.0.0.1'
|
||||||
|
port: 8899
|
||||||
|
secret: 'password'
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
require 'logger'
|
|
||||||
|
|
||||||
class Logging
|
|
||||||
def self.log
|
|
||||||
if @logger.nil?
|
|
||||||
@logger = Logger.new STDOUT
|
|
||||||
@logger.level = Logger::DEBUG
|
|
||||||
@logger.datetime_format = '%Y-%m-%d %H:%M:%S '
|
|
||||||
end
|
|
||||||
@logger
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,15 +1,16 @@
|
||||||
require 'tdlib-ruby'
|
require 'tdlib-ruby'
|
||||||
|
|
||||||
|
|
||||||
class TelegramClient
|
class TelegramClient
|
||||||
|
|
||||||
# tdlib configuration, shared within all instances #
|
# tdlib configuration, shared within all instances #
|
||||||
def self.configure(params)
|
def self.configure(params)
|
||||||
TD.configure do |config|
|
TD.configure do |config|
|
||||||
config.lib_path = params[:lib_path] || 'lib/'
|
config.lib_path = params[:lib_path] || 'lib/'
|
||||||
config.client.api_id = params[:api_id] || 430850
|
config.client.api_id = params[:api_id] || '17349' # desktop telegram app
|
||||||
config.client.api_hash = params[:api_hash] || '3d3cfcbd30d0805f757c5fc521004861'
|
config.client.api_hash = params[:api_hash] || '344583e45741c457fe1862106095a5eb' # desktop telegram app
|
||||||
end
|
end
|
||||||
TD::Api.set_log_verbosity_level(params[:verbose] || 1)
|
TD::Api.set_log_verbosity_level(params[:verbosity] || 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
# instance initialization #
|
# instance initialization #
|
||||||
|
@ -17,65 +18,71 @@ class TelegramClient
|
||||||
|
|
||||||
@xmpp = xmpp
|
@xmpp = xmpp
|
||||||
@login = login
|
@login = login
|
||||||
|
@logger = Logger.new(STDOUT); @logger.progname = '[TelegramClient: %s/%s]' % [@xmpp.user_jid, @login]
|
||||||
|
|
||||||
Logging.log.info '[TelegramClient] [%s] Initializing..' % @login
|
@logger.info 'Spawning Telegram client instance..'
|
||||||
|
|
||||||
@client = TD::Client.new(database_directory: 'sessions/' + @login, files_directory: 'sessions/' + @login + '/files/') # create telegram client instance
|
@client = TD::Client.new(database_directory: 'sessions/' + @login, files_directory: 'sessions/' + @login + '/files/') # create telegram client instance
|
||||||
@client.on(TD::Types::Update::AuthorizationState) do |update| self.auth_handler(update) end # register auth update handler
|
@client.on(TD::Types::Update::AuthorizationState) do |update| self.auth_handler(update) end # register auth update handler
|
||||||
@client.on(TD::Types::Update::NewMessage) do |update| self.message_handler(update) end # register new message update handler
|
@client.on(TD::Types::Update::NewMessage) do |update| self.message_handler(update) end # register new message update handler
|
||||||
@client.connect #
|
@client.connect #
|
||||||
|
|
||||||
# we will check new messages in queue and auth data in forever loop #
|
# we will check new messages in queue and auth data in forever loop #
|
||||||
#begin
|
begin
|
||||||
loop do
|
loop do
|
||||||
self.process_outgoing_msg(@xmpp.message_queue.pop) unless @xmpp.message_queue.empty? # found something in message queue
|
self.process_outgoing_msg(@xmpp.message_queue.pop) unless @xmpp.message_queue.empty? # found something in message queue
|
||||||
self.process_auth(:code, @xmpp.tg_auth_data[:code]) unless @xmpp.tg_auth_data[:code].nil? # found code in auth queue
|
self.process_auth(:code, @xmpp.tg_auth_data[:code]) unless @xmpp.tg_auth_data[:code].nil? # found code in auth queue
|
||||||
self.process_auth(:password, @xmpp.tg_auth_data[:password]) unless @xmpp.tg_auth_data[:password].nil? # found 2fa password in auth queue
|
self.process_auth(:password, @xmpp.tg_auth_data[:password]) unless @xmpp.tg_auth_data[:password].nil? # found 2fa password in auth queue
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
end
|
end
|
||||||
#ensure
|
ensure
|
||||||
#Logging.log.info '[TelegramClient] Exitting gracefully...'
|
@logger.info 'Exitting gracefully...'
|
||||||
#@client.dispose
|
@client.dispose
|
||||||
#end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
## Callback handlers #####################
|
||||||
|
###########################################
|
||||||
|
|
||||||
# authorization handler #
|
# authorization handler #
|
||||||
def auth_handler(update)
|
def auth_handler(update)
|
||||||
Logging.log.debug '[TelegramClient] [%s] Authorization state changed: %s' % [@login, update.authorization_state]
|
@logger.debug 'Authorization state changed: %s' % update.authorization_state
|
||||||
case update.authorization_state
|
|
||||||
|
|
||||||
|
case update.authorization_state
|
||||||
# auth stage 0: specify login #
|
# auth stage 0: specify login #
|
||||||
when TD::Types::AuthorizationState::WaitPhoneNumber
|
when TD::Types::AuthorizationState::WaitPhoneNumber
|
||||||
Logging.log.debug '[TelegramClient] [%s] Logging in..' % @login
|
@logger.info 'Logging in..'
|
||||||
@client.set_authentication_phone_number(@login)
|
@client.set_authentication_phone_number(@login)
|
||||||
# auth stage 1: wait for authorization code #
|
# auth stage 1: wait for authorization code #
|
||||||
when TD::Types::AuthorizationState::WaitCode
|
when TD::Types::AuthorizationState::WaitCode
|
||||||
|
@logger.info 'Waiting for authorization code..'
|
||||||
@xmpp.send_message(nil, 'Please, enter authorization code via /code 12345')
|
@xmpp.send_message(nil, 'Please, enter authorization code via /code 12345')
|
||||||
Logging.log.debug '[TelegramClient] [%s] Waiting for Authorization code..' % @login
|
|
||||||
# auth stage 2: wait for 2fa passphrase #
|
# auth stage 2: wait for 2fa passphrase #
|
||||||
when TD::Types::AuthorizationState::WaitPassword
|
when TD::Types::AuthorizationState::WaitPassword
|
||||||
|
@logger.info 'Waiting for 2FA password..'
|
||||||
@xmpp.send_message(nil, 'Please, enter 2FA passphrase via /password 12345')
|
@xmpp.send_message(nil, 'Please, enter 2FA passphrase via /password 12345')
|
||||||
Logging.log.debug '[TelegramClient] [%s] Waiting for 2FA password..' % @login
|
|
||||||
# authorizatio successful #
|
# authorizatio successful #
|
||||||
when TD::Types::AuthorizationState::Ready
|
when TD::Types::AuthorizationState::Ready
|
||||||
|
@logger.info 'Authorization successful!'
|
||||||
@xmpp.send_message(nil, 'Authorization successful.')
|
@xmpp.send_message(nil, 'Authorization successful.')
|
||||||
Logging.log.debug '[TelegramClient] [%s] Authorization successful.' % @login
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# message from telegram network handler #
|
# message from telegram network handler #
|
||||||
def message_handler(update)
|
def message_handler(update)
|
||||||
Logging.log.debug '[TelegramClient] [%s] Got NewMessage update <%s>' % [@login, update.message]
|
@logger.info 'Got NewMessage update'
|
||||||
from = update.message.chat_id
|
from = update.message.chat_id
|
||||||
text = update.message.content.text.text
|
text = update.message.content.text.text
|
||||||
@xmpp.send_message(from, text) if not update.message.is_outgoing
|
@xmpp.send_message(from, text) if not update.message.is_outgoing
|
||||||
end
|
end
|
||||||
|
|
||||||
##################################################
|
###########################################
|
||||||
|
## LooP handlers #########################
|
||||||
|
###########################################
|
||||||
|
|
||||||
# processing authorization #
|
# processing authorization #
|
||||||
def process_auth(typ, data)
|
def process_auth(typ, data)
|
||||||
Logging.log.debug '[TelegramClient] [%s] Authorizing with <%s> in Telegram...' % [@login, typ.to_s]
|
@logger.info 'Check authorization :%s..' % typ.to_s
|
||||||
@client.check_authentication_code(data) if typ == :code
|
@client.check_authentication_code(data) if typ == :code
|
||||||
@client.check_authentication_password(data) if typ == :password
|
@client.check_authentication_password(data) if typ == :password
|
||||||
@xmpp.tg_auth = {} # unset it to prevent extracting 2fa password from memory
|
@xmpp.tg_auth = {} # unset it to prevent extracting 2fa password from memory
|
||||||
|
@ -83,8 +90,9 @@ class TelegramClient
|
||||||
|
|
||||||
# processing outgoing message from queue #
|
# processing outgoing message from queue #
|
||||||
def process_outgoing_msg(msg)
|
def process_outgoing_msg(msg)
|
||||||
Logging.log.debug '[TelegramClient] [%s] Sending message to user/chat <%s> within Telegram network..' % [@login, msg[:to]]
|
@logger.info 'Sending message to user/chat <%s> within Telegram network..' % msg[:to]
|
||||||
message = TD::Types::InputMessageContent::Text.new(:text => { :text => msg[:text], :entities => []}, :disable_web_page_preview => false, :clear_draft => false )
|
message = TD::Types::InputMessageContent::Text.new(:text => { :text => msg[:text], :entities => []}, :disable_web_page_preview => false, :clear_draft => false )
|
||||||
@client.send_message(msg[:to].to_i, message)
|
@client.send_message(msg[:to].to_i, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,46 +1,52 @@
|
||||||
require 'xmpp4r'
|
require 'xmpp4r'
|
||||||
|
|
||||||
|
### Some constants #########
|
||||||
|
::HELP_MESSAGE = "Unknown command. \n\n Please, use /login <phonenumber> to try log in. ☺"
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
## XMPP Transport Class #####
|
## XMPP Transport Class #####
|
||||||
#############################
|
#############################
|
||||||
class XMPPComponent
|
class XMPPComponent
|
||||||
attr_accessor :jid
|
def initialize()
|
||||||
|
@logger = Logger.new(STDOUT); @logger.progname = '[XMPPComponent]'
|
||||||
|
end
|
||||||
|
|
||||||
# transport initialization & connecting to XMPP server #
|
# transport initialization & connecting to XMPP server #
|
||||||
def connect(params) # :jid => transport_jid, :host => xmpp_server, :port => xmpp_component_port, :secret => xmpp_component_secret
|
def connect(params) # :jid => transport_jid, :host => xmpp_server, :port => xmpp_component_port, :secret => xmpp_component_secret
|
||||||
Logging.log.info '[XMPP] Connecting...'
|
@logger.info "Connecting.."
|
||||||
begin
|
begin
|
||||||
@@transport = Jabber::Component.new( params[:jid] )
|
@@transport = Jabber::Component.new( params[:jid] )
|
||||||
@@transport.connect( params[:host], params[:port] )
|
@@transport.connect( params[:host], params[:port] )
|
||||||
@@transport.auth( params[:secret] )
|
@@transport.auth( params[:secret] )
|
||||||
@@transport.add_message_callback do |msg| msg.first_element_text('body') ? self.message_handler(msg) : nil end
|
@@transport.add_message_callback do |msg| msg.first_element_text('body') ? self.message_handler(msg) : nil end
|
||||||
@sessions = {}
|
@sessions = {}
|
||||||
Logging.log.info '[XMPP] Connection established'
|
@logger.info "Connection established"
|
||||||
Thread.stop()
|
Thread.stop()
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
Logging.log.info '[XMPP] Connection failed (%s)' % e
|
@logger.info 'Connection failed: %s' % e
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# new message to XMPP component #
|
# new message to XMPP component #
|
||||||
def message_handler(msg)
|
def message_handler(msg)
|
||||||
Logging.log.debug '[XMPP] New message from [%s] to [%s]' % [msg.from, msg.to]
|
@logger.info 'New message from [%s] to [%s]' % [msg.from, msg.to]
|
||||||
|
|
||||||
return self.process_internal_command(msg.from.bare, msg.first_element_text('body') ) if msg.to == @@transport.jid # treat message as internal command if received as transport jid
|
return self.process_internal_command(msg.from.bare, msg.first_element_text('body') ) if msg.to == @@transport.jid # treat message as internal command if received as transport jid
|
||||||
return @sessions[msg.from.bare].queue_message(msg.to, msg.first_element_text('body')) if @sessions.key? msg.from.bare # queue message for processing session is active for jid from
|
return @sessions[msg.from.bare].queue_message(msg.to.to_s, msg.first_element_text('body')) if @sessions.key? msg.from.bare # queue message for processing session is active for jid from
|
||||||
end
|
end
|
||||||
|
|
||||||
# process internal /command #
|
# process internal /command #
|
||||||
def process_internal_command(jfrom, body)
|
def process_internal_command(jfrom, body)
|
||||||
case body.split[0] # /command argument = [command, argument]
|
case body.split[0] # /command argument = [command, argument]
|
||||||
when '/help' #
|
when '/login'
|
||||||
when '/login' # Create new session
|
# we will try to create new user session for JID <jfrom> and try to start telegram client for login <body.split[1]>
|
||||||
@sessions[jfrom] = XMPPSession.new(jfrom, body.split[1])
|
@sessions[jfrom] = XMPPSession.new(jfrom, body.split[1])
|
||||||
when '/code', '/password' # Enter auth code / 2fa password
|
when '/code', '/password'
|
||||||
@sessions[jfrom].enter_auth_data(body.split[0], body.split[1])
|
# we will pass auth data to user session if this session exists.
|
||||||
else # Unknown command
|
@sessions[jfrom].enter_auth_data(body.split[0][1..8], body.split[1]) if @sessions.key? jfrom
|
||||||
reply = Jabber::Message.new; reply.from, reply.to, reply.body, reply.type = @@transport.jid, jfrom, 'Unknown command', :chat
|
else # unknown command -- we will display sort of help message.
|
||||||
|
reply = Jabber::Message.new; reply.from, reply.to, reply.body, reply.type = @@transport.jid, jfrom, ::HELP_MESSAGE, :chat
|
||||||
@@transport.send(reply)
|
@@transport.send(reply)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,32 +61,31 @@ class XMPPSession < XMPPComponent
|
||||||
|
|
||||||
# start XMPP user session and Telegram client instance #
|
# start XMPP user session and Telegram client instance #
|
||||||
def initialize(jid, tg_login)
|
def initialize(jid, tg_login)
|
||||||
Logging.log.info "[XMPPSession] [%s] Starting Telegram session as [%s]" % [jid, tg_login]
|
@logger = Logger.new(STDOUT); @logger.progname = '[XMPPSession: %s/%s]' % [jid, tg_login]
|
||||||
|
@logger.info "Starting Telegram session"
|
||||||
@user_jid, @tg_login, @tg_auth_data, @message_queue = jid, tg_login, {code: nil, password: nil}, Queue.new()
|
@user_jid, @tg_login, @tg_auth_data, @message_queue = jid, tg_login, {code: nil, password: nil}, Queue.new()
|
||||||
@tg_thread = Thread.new{ TelegramClient.new(self, tg_login) }
|
@tg_client = Thread.new{ TelegramClient.new(self, tg_login) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# send message to XMPP #
|
# send message to XMPP #
|
||||||
def send_message(from = nil, body = '')
|
def send_message(from = nil, body = '')
|
||||||
Logging.log.info "[XMPPSession] [%s] Incoming message from Telegram network <- [%s].." % [@user_jid, from.to_s]
|
@logger.info "Incoming message from Telegram network <- %s" % from.to_s
|
||||||
puts 1
|
|
||||||
from = from.nil? ? @@transport.jid : from.to_s+'@'+@@transport.jid.to_s
|
from = from.nil? ? @@transport.jid : from.to_s+'@'+@@transport.jid.to_s
|
||||||
puts 2
|
|
||||||
reply = Jabber::Message.new; reply.from, reply.to, reply.body, reply.type = from, @user_jid, body, :chat
|
reply = Jabber::Message.new; reply.from, reply.to, reply.body, reply.type = from, @user_jid, body, :chat
|
||||||
puts reply
|
|
||||||
@@transport.send(reply)
|
@@transport.send(reply)
|
||||||
end
|
end
|
||||||
|
|
||||||
# queue message (we will share this queue within :message_queue to Telegram client thread) #
|
# queue message (we will share this queue within :message_queue to Telegram client thread) #
|
||||||
def queue_message(to, text = '')
|
def queue_message(to, text = '')
|
||||||
Logging.log.info "[XMPPSession] [%s] Queuying message to Telegram network -> [%s].." % [@user_jid, to]
|
@logger.info "Queuing message to be sent to Telegram network user -> " % to
|
||||||
@message_queue << {to: to.split('@')[0], text: text}
|
@message_queue << {to: to.split('@')[0], text: text}
|
||||||
|
puts @message_queue
|
||||||
end
|
end
|
||||||
|
|
||||||
# enter auth data (we will share this data within :tg_auth_data to Telegram client thread ) #
|
# enter auth data (we will share this data within :tg_auth_data to Telegram client thread ) #
|
||||||
def enter_auth_data(typ, data)
|
def enter_auth_data(typ, data)
|
||||||
Logging.log.info "[XMPPSession] [%s] Authorizing in Telegram with [%s]" % [@user_jid, typ]
|
logger.info "Authorizing in Telegram network with :%s" % typ
|
||||||
@tg_auth_data[typ[1..8].to_sym] = data
|
@tg_auth_data[typ.to_sym] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
7
main.rb
7
main.rb
|
@ -1,7 +0,0 @@
|
||||||
require_relative 'inc/logger'
|
|
||||||
require_relative 'inc/telegram'
|
|
||||||
require_relative 'inc/xmpp'
|
|
||||||
|
|
||||||
Logging.log.info '[MAIN] Starting Zhabogram v0.o1...'
|
|
||||||
TelegramClient.configure(verbose: 2)
|
|
||||||
XMPPComponent.new().connect(host: 'localhost', port: '8899', jid: 'tlgrm2.rxtx.us', secret: '')
|
|
12
zhabogram.rb
Normal file
12
zhabogram.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Some very important libraries'
|
||||||
|
require 'yaml'
|
||||||
|
require 'logger'
|
||||||
|
require_relative 'inc/telegramclient'
|
||||||
|
require_relative 'inc/xmppcomponent'
|
||||||
|
|
||||||
|
# Configuration file #
|
||||||
|
Config = YAML.load_file(File.dirname(__FILE__) + '/config.yml')
|
||||||
|
|
||||||
|
# Configure Telegram Client #
|
||||||
|
TelegramClient.configure(api_id: Config['telegram']['api_id'], api_hash: Config['telegram']['api_hash'], verbosity: Config['telegram']['verbosity'])
|
||||||
|
XMPPComponent.new().connect(host: Config['xmpp']['host'], port: Config['xmpp']['port'], jid: Config['xmpp']['jid'], secret: Config['xmpp']['secret'])
|
Reference in a new issue