From 08540206f01e7bf2e62b1958848a1f2903199bd0 Mon Sep 17 00:00:00 2001 From: annelin Date: Sat, 6 Apr 2019 10:29:48 +0300 Subject: [PATCH] Renamed files and libs Added config file (config.yml) Changed logger implementation Correct Telegram session terminating --- config.yml.example | 13 +++++++ inc/logger.rb | 12 ------- inc/{telegram.rb => telegramclient.rb} | 48 +++++++++++++++----------- inc/{xmpp.rb => xmppcomponent.rb} | 47 ++++++++++++++----------- main.rb | 7 ---- zhabogram.rb | 12 +++++++ 6 files changed, 79 insertions(+), 60 deletions(-) create mode 100644 config.yml.example delete mode 100644 inc/logger.rb rename inc/{telegram.rb => telegramclient.rb} (69%) rename inc/{xmpp.rb => xmppcomponent.rb} (59%) delete mode 100644 main.rb create mode 100644 zhabogram.rb diff --git a/config.yml.example b/config.yml.example new file mode 100644 index 0000000..99b0e6c --- /dev/null +++ b/config.yml.example @@ -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' + diff --git a/inc/logger.rb b/inc/logger.rb deleted file mode 100644 index 097438b..0000000 --- a/inc/logger.rb +++ /dev/null @@ -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 diff --git a/inc/telegram.rb b/inc/telegramclient.rb similarity index 69% rename from inc/telegram.rb rename to inc/telegramclient.rb index ac6ad47..a331b36 100644 --- a/inc/telegram.rb +++ b/inc/telegramclient.rb @@ -1,15 +1,16 @@ require 'tdlib-ruby' + class TelegramClient # tdlib configuration, shared within all instances # def self.configure(params) TD.configure do |config| config.lib_path = params[:lib_path] || 'lib/' - config.client.api_id = params[:api_id] || 430850 - config.client.api_hash = params[:api_hash] || '3d3cfcbd30d0805f757c5fc521004861' + config.client.api_id = params[:api_id] || '17349' # desktop telegram app + config.client.api_hash = params[:api_hash] || '344583e45741c457fe1862106095a5eb' # desktop telegram app end - TD::Api.set_log_verbosity_level(params[:verbose] || 1) + TD::Api.set_log_verbosity_level(params[:verbosity] || 1) end # instance initialization # @@ -17,65 +18,71 @@ class TelegramClient @xmpp = xmpp @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.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.connect # # we will check new messages in queue and auth data in forever loop # - #begin + begin loop do 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(:password, @xmpp.tg_auth_data[:password]) unless @xmpp.tg_auth_data[:password].nil? # found 2fa password in auth queue sleep 0.5 end - #ensure - #Logging.log.info '[TelegramClient] Exitting gracefully...' - #@client.dispose - #end + ensure + @logger.info 'Exitting gracefully...' + @client.dispose + end end + + ########################################### + ## Callback handlers ##################### + ########################################### # authorization handler # def auth_handler(update) - Logging.log.debug '[TelegramClient] [%s] Authorization state changed: %s' % [@login, update.authorization_state] - case update.authorization_state + @logger.debug 'Authorization state changed: %s' % update.authorization_state + case update.authorization_state # auth stage 0: specify login # when TD::Types::AuthorizationState::WaitPhoneNumber - Logging.log.debug '[TelegramClient] [%s] Logging in..' % @login + @logger.info 'Logging in..' @client.set_authentication_phone_number(@login) # auth stage 1: wait for authorization code # when TD::Types::AuthorizationState::WaitCode + @logger.info 'Waiting for authorization code..' @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 # when TD::Types::AuthorizationState::WaitPassword + @logger.info 'Waiting for 2FA password..' @xmpp.send_message(nil, 'Please, enter 2FA passphrase via /password 12345') - Logging.log.debug '[TelegramClient] [%s] Waiting for 2FA password..' % @login # authorizatio successful # when TD::Types::AuthorizationState::Ready + @logger.info 'Authorization successful!' @xmpp.send_message(nil, 'Authorization successful.') - Logging.log.debug '[TelegramClient] [%s] Authorization successful.' % @login end end # message from telegram network handler # 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 text = update.message.content.text.text @xmpp.send_message(from, text) if not update.message.is_outgoing end - ################################################## + ########################################### + ## LooP handlers ######################### + ########################################### # processing authorization # 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_password(data) if typ == :password @xmpp.tg_auth = {} # unset it to prevent extracting 2fa password from memory @@ -83,8 +90,9 @@ class TelegramClient # processing outgoing message from queue # 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 ) @client.send_message(msg[:to].to_i, message) end + end diff --git a/inc/xmpp.rb b/inc/xmppcomponent.rb similarity index 59% rename from inc/xmpp.rb rename to inc/xmppcomponent.rb index 69021dd..5aab3c9 100644 --- a/inc/xmpp.rb +++ b/inc/xmppcomponent.rb @@ -1,46 +1,52 @@ require 'xmpp4r' +### Some constants ######### +::HELP_MESSAGE = "Unknown command. \n\n Please, use /login to try log in. ☺" + ############################# ## XMPP Transport Class ##### ############################# class XMPPComponent - attr_accessor :jid + def initialize() + @logger = Logger.new(STDOUT); @logger.progname = '[XMPPComponent]' + end # transport initialization & connecting to XMPP server # 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 @@transport = Jabber::Component.new( params[:jid] ) @@transport.connect( params[:host], params[:port] ) @@transport.auth( params[:secret] ) @@transport.add_message_callback do |msg| msg.first_element_text('body') ? self.message_handler(msg) : nil end @sessions = {} - Logging.log.info '[XMPP] Connection established' + @logger.info "Connection established" Thread.stop() rescue Exception => e - Logging.log.info '[XMPP] Connection failed (%s)' % e + @logger.info 'Connection failed: %s' % e exit 1 end end # new message to XMPP component # 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 @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 # process internal /command # def process_internal_command(jfrom, body) case body.split[0] # /command argument = [command, argument] - when '/help' # - when '/login' # Create new session + when '/login' + # we will try to create new user session for JID and try to start telegram client for login @sessions[jfrom] = XMPPSession.new(jfrom, body.split[1]) - when '/code', '/password' # Enter auth code / 2fa password - @sessions[jfrom].enter_auth_data(body.split[0], body.split[1]) - else # Unknown command - reply = Jabber::Message.new; reply.from, reply.to, reply.body, reply.type = @@transport.jid, jfrom, 'Unknown command', :chat + when '/code', '/password' + # we will pass auth data to user session if this session exists. + @sessions[jfrom].enter_auth_data(body.split[0][1..8], body.split[1]) if @sessions.key? jfrom + 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) end end @@ -55,32 +61,31 @@ class XMPPSession < XMPPComponent # start XMPP user session and Telegram client instance # 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() - @tg_thread = Thread.new{ TelegramClient.new(self, tg_login) } + @tg_client = Thread.new{ TelegramClient.new(self, tg_login) } end # send message to XMPP # def send_message(from = nil, body = '') - Logging.log.info "[XMPPSession] [%s] Incoming message from Telegram network <- [%s].." % [@user_jid, from.to_s] - puts 1 + @logger.info "Incoming message from Telegram network <- %s" % from.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 - puts reply @@transport.send(reply) end # queue message (we will share this queue within :message_queue to Telegram client thread) # 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} + puts @message_queue end # enter auth data (we will share this data within :tg_auth_data to Telegram client thread ) # def enter_auth_data(typ, data) - Logging.log.info "[XMPPSession] [%s] Authorizing in Telegram with [%s]" % [@user_jid, typ] - @tg_auth_data[typ[1..8].to_sym] = data + logger.info "Authorizing in Telegram network with :%s" % typ + @tg_auth_data[typ.to_sym] = data end end diff --git a/main.rb b/main.rb deleted file mode 100644 index b5685e0..0000000 --- a/main.rb +++ /dev/null @@ -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: '') diff --git a/zhabogram.rb b/zhabogram.rb new file mode 100644 index 0000000..3200fca --- /dev/null +++ b/zhabogram.rb @@ -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'])