Release v0.3
[UPD] more correct way to handle user/chat/auth updates [UPD] removed successful login message, using presence instead [NEW] config option `content_upload_prefix` that says which url prefixes will be treated as media and uploaded as file to telegram [NEW] processing self outgoing messages that sent via another telegram instance [NEW] added gif animations, locations, video, chat events support [NEW] control commands implemented: /s/old/new (edit), /d (delete), /info @username, /add @username or uid, /join invite.link or id, /invite @username, /kick @username, /ban @username [hours], /block, /unblock, /leave, /delete
This commit is contained in:
parent
c4f2e9d4b8
commit
33677f5289
|
@ -9,6 +9,7 @@ telegram:
|
||||||
loglevel: 0
|
loglevel: 0
|
||||||
content_path: '/var/www/tg_media'
|
content_path: '/var/www/tg_media'
|
||||||
content_link: 'https://localhost/tg_media'
|
content_link: 'https://localhost/tg_media'
|
||||||
|
content_upload_prefix: 'https://localhost/upload'
|
||||||
|
|
||||||
xmpp:
|
xmpp:
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class TelegramClient
|
||||||
@@loglevel = params['loglevel'] || Logger::DEBUG
|
@@loglevel = params['loglevel'] || Logger::DEBUG
|
||||||
@@content_path = params['content_path'] || '/tmp'
|
@@content_path = params['content_path'] || '/tmp'
|
||||||
@@content_link = params['content_link'] || 'https://localhost/tg_media'
|
@@content_link = params['content_link'] || 'https://localhost/tg_media'
|
||||||
@@content_size_limit = params["content_size_limit"] || 100 * 1024 * 1024
|
@@content_upload_prefix = params["content_upload_prefix"] || 'https://localhost/upload/'
|
||||||
TD.configure do |config|
|
TD.configure do |config|
|
||||||
config.lib_path = params['path'] || 'lib/' # we hope it's here
|
config.lib_path = params['path'] || 'lib/' # we hope it's here
|
||||||
config.client.api_id = params['api_id'] || '17349' # desktop telegram app
|
config.client.api_id = params['api_id'] || '17349' # desktop telegram app
|
||||||
|
@ -40,6 +40,7 @@ class TelegramClient
|
||||||
@client.on(TD::Types::Update::DeleteMessages) do |update| self.message_deleted_handler(update) end # register msg del handler
|
@client.on(TD::Types::Update::DeleteMessages) do |update| self.message_deleted_handler(update) end # register msg del handler
|
||||||
@client.on(TD::Types::Update::File) do |update| self.file_handler(update) end # register file handler
|
@client.on(TD::Types::Update::File) do |update| self.file_handler(update) end # register file handler
|
||||||
@client.on(TD::Types::Update::NewChat) do |update| self.new_chat_handler(update) end # register new chat handler
|
@client.on(TD::Types::Update::NewChat) do |update| self.new_chat_handler(update) end # register new chat handler
|
||||||
|
@client.on(TD::Types::Update::User) do |update| self.user_handler(update) end # new user update?
|
||||||
@client.on(TD::Types::Update::UserStatus) do |update| self.status_update_handler(update) end # register status handler
|
@client.on(TD::Types::Update::UserStatus) do |update| self.status_update_handler(update) end # register status handler
|
||||||
@client.connect #
|
@client.connect #
|
||||||
|
|
||||||
|
@ -47,8 +48,7 @@ class TelegramClient
|
||||||
begin
|
begin
|
||||||
while not @xmpp.online? === false do
|
while not @xmpp.online? === false 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(@xmpp.auth_data.shift) unless @xmpp.auth_data.empty? # found something 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.1
|
sleep 0.1
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
|
@ -84,7 +84,8 @@ class TelegramClient
|
||||||
when TD::Types::AuthorizationState::Ready
|
when TD::Types::AuthorizationState::Ready
|
||||||
@logger.info 'Authorization successful!'
|
@logger.info 'Authorization successful!'
|
||||||
@xmpp.online!
|
@xmpp.online!
|
||||||
@client.get_chats(limit=9999).then { |chats| chats.chat_ids.each do |chat_id| self.process_chat_info(chat_id) end }.wait
|
@client.get_me().then { |user| @me = user }.wait
|
||||||
|
@client.get_chats(limit=9999).wait
|
||||||
@logger.info "Contact list updating finished"
|
@logger.info "Contact list updating finished"
|
||||||
self.sync_roster()
|
self.sync_roster()
|
||||||
when TD::Types::AuthorizationState::Closed
|
when TD::Types::AuthorizationState::Closed
|
||||||
|
@ -98,24 +99,58 @@ class TelegramClient
|
||||||
@logger.debug 'Got NewMessage update'
|
@logger.debug 'Got NewMessage update'
|
||||||
@logger.debug update.message.to_json
|
@logger.debug update.message.to_json
|
||||||
|
|
||||||
return if update.message.is_outgoing # ignore outgoing
|
return if not @cache[:chats].key? update.message.chat_id # we do not know about this chat, ignore it
|
||||||
return if not @cache[:chats].key? update.message.chat_id
|
return if update.message.is_outgoing and update.message.sending_state.instance_of? TD::Types::MessageSendingState::Pending # ignore self outgoing messages
|
||||||
|
|
||||||
# media? #
|
# media? #
|
||||||
content = nil
|
file = nil
|
||||||
@logger.debug update.message.content.to_json
|
text = ''
|
||||||
case update.message.content # content = [content, name, mime]
|
case update.message.content
|
||||||
when TD::Types::MessageContent::Photo then content = [update.message.content.photo.sizes[-1].photo, update.message.content.photo.id.to_s + '.jpg', 'image/jpeg']
|
when TD::Types::MessageContent::Photo # photos
|
||||||
when TD::Types::MessageContent::Sticker then content = [update.message.content.sticker.sticker, update.message.content.sticker.emoji.to_s + '.webp', 'image/webp']
|
file = update.message.content.photo.sizes[-1].photo
|
||||||
when TD::Types::MessageContent::Audio then content = [update.message.content.audio.audio, update.message.content.audio.file_name.to_s, update.message.content.audio.mime_type.to_s]
|
text = "%s.jpg (image/jpeg), %d bytes | %s | %s" % [update.message.content.photo.id.to_s, file.size.to_i, self.format_content_link(file.remote.id, 'image.jpg'), update.message.content.caption.text.to_s]
|
||||||
when TD::Types::MessageContent::Document then content = [update.message.content.document.document, update.message.content.document.file_name.to_s, update.message.content.document.mime_type.to_s]
|
when TD::Types::MessageContent::Animation # "gif" (mp4) animations
|
||||||
|
file = update.message.content.animation.animation
|
||||||
|
text = "gif: %s | %s" % [update.message.content.animation.file_name, self.format_content_link(file.remote.id, 'video.mp4')]
|
||||||
|
when TD::Types::MessageContent::Sticker # stickers
|
||||||
|
file = update.message.content.sticker.sticker
|
||||||
|
text = "sticker: %s | %s" % [update.message.content.sticker.emoji.to_s, self.format_content_link(file.remote.id, 'sticker.webp')]
|
||||||
|
when TD::Types::MessageContent::Audio # music files
|
||||||
|
file = update.message.content.audio.audio
|
||||||
|
text = "%s (%s), %d bytes | %s | %s" % [update.message.content.audio.file_name.to_s, update.message.content.audio.mime_type.to_s, file.size.to_i, self.format_content_link(file.remote.id, update.message.content.audio.file_name.to_s), update.message.content.caption.text.to_s]
|
||||||
|
when TD::Types::MessageContent::Video # video files
|
||||||
|
file = update.message.content.video.video
|
||||||
|
text = "%s (%s), %d bytes | %s | %s" % [update.message.content.video.file_name.to_s, update.message.content.video.mime_type.to_s, file.size.to_i, self.format_content_link(file.remote.id, update.message.content.video.file_name.to_s), update.message.content.caption.text.to_s]
|
||||||
|
when TD::Types::MessageContent::VoiceNote # voice messages
|
||||||
|
file = update.message.content.voice_note.voice
|
||||||
|
text = "voice message (%i s.) | %s" % [update.message.content.voice_note.duration, self.format_content_link(file.remote.id, 'voice.oga')]
|
||||||
|
when TD::Types::MessageContent::Document # documents
|
||||||
|
file = update.message.content.document.document
|
||||||
|
text = "%s (%s), %d bytes | %s | %s" % [update.message.content.document.file_name.to_s, update.message.content.document.mime_type.to_s, file.size.to_i, self.format_content_link(file.remote.id, update.message.content.document.file_name.to_s), update.message.content.caption.text.to_s]
|
||||||
|
when TD::Types::MessageContent::ChatJoinByLink # joined member
|
||||||
|
text = "joined"
|
||||||
|
when TD::Types::MessageContent::ChatAddMembers # add members
|
||||||
|
text = "added "
|
||||||
|
update.message.content.member_user_ids.each do |member| text = text + self.format_username(member) + ' ' end
|
||||||
|
when TD::Types::MessageContent::ChatDeleteMember # kicked member
|
||||||
|
text = "removed %s" % self.format_username(update.message.content.user_id)
|
||||||
|
when TD::Types::MessageContent::PinMessage # pinned message
|
||||||
|
@client.get_message(update.message.chat_id, update.message.content.message_id).then { |message| text = "pinned message: %s" % message.content.text.text.to_s }.wait
|
||||||
|
when TD::Types::MessageContent::ChatChangeTitle # changed chat title
|
||||||
|
text = "chat title set to: %s" % update.message.content.title.to_s
|
||||||
|
when TD::Types::MessageContent::Location # location
|
||||||
|
location = "%s,%s" % [update.message.content.location.latitude.to_s, update.message.content.location.longitude.to_s]
|
||||||
|
text = "coordinates: %s | https://www.google.com/maps/search/%s/" % [location, location]
|
||||||
|
when TD::Types::MessageContent::Text # plain text
|
||||||
|
text = update.message.content.text.text.to_s
|
||||||
|
else
|
||||||
|
text = "unknown message type %s" % update.message.content.class
|
||||||
end
|
end
|
||||||
@client.download_file(content[0].id) if content # download it if already not
|
@client.download_file(file.id) if file # download it if already not
|
||||||
|
|
||||||
# formatting...
|
# forwards, replies and message id..
|
||||||
text = (content.nil?) ? update.message.content.text.text.to_s : update.message.content.caption.text.to_s
|
text = "[Forward from %s] %s" % [self.format_username(update.message.forward_info.sender_user_id), text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd from user
|
||||||
text = "[%s (%s), %d bytes] | %s | %s" % [content[1], content[2], content[0].size.to_i, self.format_content_link(content[0].remote.id, content[1]), text] if content # content format
|
text = "[Forward from channel %s (%s)] %s" % [update.message.forward_info.chat_id.to_s, update.message.forward_info.author_signature.to_s, text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedPost # fwd from chat
|
||||||
text = "[FWD From %s] %s" % [self.format_username(update.message.forward_info.sender_user_id), text] if update.message.forward_info.instance_of? TD::Types::MessageForwardInfo::MessageForwardedFromUser # fwd
|
|
||||||
text = "[Reply to MSG %s] %s" % [update.message.reply_to_message_id.to_s, text] if update.message.reply_to_message_id.to_i != 0 # reply
|
text = "[Reply to MSG %s] %s" % [update.message.reply_to_message_id.to_s, text] if update.message.reply_to_message_id.to_i != 0 # reply
|
||||||
text = "[MSG %s] [%s] %s" % [update.message.id.to_s, self.format_username(update.message.sender_user_id), text] # username/id
|
text = "[MSG %s] [%s] %s" % [update.message.id.to_s, self.format_username(update.message.sender_user_id), text] # username/id
|
||||||
|
|
||||||
|
@ -131,6 +166,13 @@ class TelegramClient
|
||||||
self.process_chat_info(update.chat.id)
|
self.process_chat_info(update.chat.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# user -- something changed in user data #
|
||||||
|
def user_handler(update)
|
||||||
|
@logger.debug 'Got User update'
|
||||||
|
@logger.debug update.to_json
|
||||||
|
self.process_user_info(update.user.id)
|
||||||
|
end
|
||||||
|
|
||||||
# edited msg #
|
# edited msg #
|
||||||
def message_edited_handler(update)
|
def message_edited_handler(update)
|
||||||
@logger.debug 'Got MessageEdited update'
|
@logger.debug 'Got MessageEdited update'
|
||||||
|
@ -166,8 +208,8 @@ class TelegramClient
|
||||||
def status_update_handler(update)
|
def status_update_handler(update)
|
||||||
@logger.debug 'Got new StatusUpdate'
|
@logger.debug 'Got new StatusUpdate'
|
||||||
@logger.debug update.to_json
|
@logger.debug update.to_json
|
||||||
presence, message = self.format_status(update.status)
|
return if update.user_id == @me.id # ignore self statuses
|
||||||
@xmpp.presence_update(update.user_id.to_s, presence, message)
|
self.process_status_update(update.user_id, update.status)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,11 +218,80 @@ class TelegramClient
|
||||||
###########################################
|
###########################################
|
||||||
|
|
||||||
# processing authorization #
|
# processing authorization #
|
||||||
def process_auth(typ, data)
|
def process_auth(auth_data)
|
||||||
@logger.debug 'check_authorization :%s..' % typ.to_s
|
@logger.debug 'check_authorization :%s..' % auth_data[0]
|
||||||
@client.check_authentication_code(data) if typ == :code
|
@client.check_authentication_code(auth_data[1]) if auth_data[0] == :code
|
||||||
@client.check_authentication_password(data) if typ == :password
|
@client.check_authentication_password(auth_data[1]) if auth_data[0] == :password
|
||||||
@xmpp.tg_auth_data = {}
|
end
|
||||||
|
|
||||||
|
# /command #
|
||||||
|
def process_command(chat_id, text)
|
||||||
|
splitted = text.split # splitted[0] = command, splitted[1] = argument
|
||||||
|
splitted = ['/sed', text[3..-1]] if text[0..2] == '/s/' # sed-like edit
|
||||||
|
resolved = nil; response = nil
|
||||||
|
|
||||||
|
# if second argument starts with @, try to resolve it
|
||||||
|
@client.search_public_chat(splitted[1][1..-1]).then {|chat| resolved = chat}.wait if splitted[1] and splitted[1][0] == '@'
|
||||||
|
|
||||||
|
case splitted[0]
|
||||||
|
when '/info' # retrieve some information by link, @username or username
|
||||||
|
response = "Contact id: %s\nContact name: %s\nContact type: %s" % [resolved.id.to_s, resolved.title.to_s, resolved.type.class.to_s] if resolved
|
||||||
|
when '/add' # open new private chat by its id
|
||||||
|
chat = (resolved) ? resolved.id : splitted[1].to_i
|
||||||
|
@client.create_private_chat(chat).wait
|
||||||
|
self.process_chat_info(chat)
|
||||||
|
when '/join' # join group/supergroup by invite link or by id
|
||||||
|
chat = splitted[1]
|
||||||
|
chat.start_with? "http" ? @client.join_chat_by_invite_link(chat).wait : @client.join_chat(chat.to_i).wait
|
||||||
|
when '/invite' # invite user to chat
|
||||||
|
@client.add_chat_member(chat_id, response.id).wait if resolved
|
||||||
|
when '/kick' # removes user from chat
|
||||||
|
@client.set_chat_member_status(chat_id, response.id, TD::Types::ChatMemberStatus::Left.new()).wait if resolved
|
||||||
|
when '/ban' # removes user from chat. argument = hours to ban.
|
||||||
|
until_date = (splitted[1]) ? Time.now.getutc.to_i + splitted[1].to_i * 3600 : 0
|
||||||
|
@client.set_chat_member_status(chat_id, response.id, TD::Types::ChatMemberStatus::Banned.new(banned_until_date: until_date)).wait if resolved
|
||||||
|
when '/block' # add user to blacklist
|
||||||
|
@client.block_user(chat_id)
|
||||||
|
when '/unblock' # add user to blacklist
|
||||||
|
@client.unblock_user(chat_id)
|
||||||
|
when '/leave', '/delete' # delete / leave chat
|
||||||
|
@client.close_chat(chat_id).wait
|
||||||
|
@client.leave_chat(chat_id).wait
|
||||||
|
@client.delete_chat_history(chat_id, true).wait
|
||||||
|
@xmpp.presence_update(chat_id, :unsubscribed)
|
||||||
|
@xmpp.presence_update(chat_id, :unavailable)
|
||||||
|
@cache[:chats].delete(chat_id)
|
||||||
|
when '/sed' # sed-like edit
|
||||||
|
sed = splitted[1].split('/')
|
||||||
|
@client.search_chat_messages(chat_id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs|
|
||||||
|
original = msgs.messages[0].content.text.text.to_s
|
||||||
|
edited = (sed[0] != '' ) ? original.gsub(Regexp.new(sed[0]), sed[1]) : sed[1]
|
||||||
|
@client.edit_message_text(chat_id, msgs.messages[0].id, TD::Types::InputMessageContent::Text.new(:text => { :text => edited, :entities => []}, :disable_web_page_preview => false, :clear_draft => true )) if edited != original
|
||||||
|
}.wait
|
||||||
|
when '/d' # delete last message
|
||||||
|
@client.search_chat_messages(chat_id, 0, 1, sender_user_id: @me.id, filter: TD::Types::SearchMessagesFilter::Empty.new).then {|msgs|
|
||||||
|
@client.delete_messages(chat_id, [msgs.messages[0].id], true)
|
||||||
|
}.wait
|
||||||
|
else
|
||||||
|
response = 'Unknown command.
|
||||||
|
|
||||||
|
/s/mitsake/mistake/ — Edit last message
|
||||||
|
/d — Delete last message
|
||||||
|
|
||||||
|
/info @username — Search public chat or user
|
||||||
|
/add @username or id — Creates conversation with specified user
|
||||||
|
/join chat_link or id — Joins chat by its link or id
|
||||||
|
/invite @username — Invites @username to current chat
|
||||||
|
/kick @username — Removes @username from current chat
|
||||||
|
/ban @username [hours] — Bans @username in current chat for [hours] hrs or forever if [hours] not specified
|
||||||
|
/block — Blacklists current user
|
||||||
|
/unblock — Removes current user from blacklist
|
||||||
|
/leave — Leave current chat
|
||||||
|
/delete — Delete current chat
|
||||||
|
'
|
||||||
|
end
|
||||||
|
|
||||||
|
@xmpp.send_message(chat_id, response) if response
|
||||||
end
|
end
|
||||||
|
|
||||||
# processing outgoing message from queue #
|
# processing outgoing message from queue #
|
||||||
|
@ -188,23 +299,26 @@ class TelegramClient
|
||||||
@logger.debug 'Sending message to user/chat <%s> within Telegram network..' % msg[:to]
|
@logger.debug 'Sending message to user/chat <%s> within Telegram network..' % msg[:to]
|
||||||
chat_id, text, reply_to = msg[:to].to_i, msg[:text], 0
|
chat_id, text, reply_to = msg[:to].to_i, msg[:text], 0
|
||||||
|
|
||||||
|
# processing /commands #
|
||||||
|
return self.process_command(chat_id, text) if text[0] == '/'
|
||||||
|
|
||||||
# handling replies #
|
# handling replies #
|
||||||
if msg[:text][0] == '>' then
|
if text[0] == '>' then
|
||||||
splitted = msg[:text].split("\n")
|
splitted = text.split("\n")
|
||||||
reply_to, reply_text = splitted[0].scan(/\d/)[0] || 0
|
reply_to = splitted[0].scan(/\d/).join('') || 0
|
||||||
text = splitted.drop(1).join("\n") if reply_to != 0
|
text = splitted.drop(1).join("\n") if reply_to != 0
|
||||||
end
|
end
|
||||||
|
|
||||||
# handle commands... (todo) #
|
# handling files received from xmpp #
|
||||||
#
|
if text.start_with? @@content_upload_prefix then
|
||||||
|
message = TD::Types::InputMessageContent::Document.new(document: TD::Types::InputFile::Remote.new(id: text), caption: { :text => '', :entities => []})
|
||||||
|
else
|
||||||
|
message = TD::Types::InputMessageContent::Text.new(:text => { :text => text, :entities => []}, :disable_web_page_preview => false, :clear_draft => true )
|
||||||
|
end
|
||||||
|
|
||||||
# mark all messages within this chat as read #
|
# send message and mark chat as read #
|
||||||
@client.view_messages(chat_id, [@cache[:unread_msg][chat_id]], force_read: true) if @cache[:unread_msg][chat_id]
|
|
||||||
@cache[:unread_msg][chat_id] = nil
|
|
||||||
|
|
||||||
# send message #
|
|
||||||
message = TD::Types::InputMessageContent::Text.new(:text => { :text => text, :entities => []}, :disable_web_page_preview => true, :clear_draft => false )
|
|
||||||
@client.send_message(chat_id, message, reply_to_message_id: reply_to)
|
@client.send_message(chat_id, message, reply_to_message_id: reply_to)
|
||||||
|
@client.view_messages(chat_id, [@cache[:unread_msg].delete(chat_id)], force_read: true) if @cache[:unread_msg][chat_id]
|
||||||
end
|
end
|
||||||
|
|
||||||
# update users information and save it to cache #
|
# update users information and save it to cache #
|
||||||
|
@ -220,48 +334,48 @@ class TelegramClient
|
||||||
# send to roster #
|
# send to roster #
|
||||||
if @cache[:chats].key? chat_id
|
if @cache[:chats].key? chat_id
|
||||||
@logger.debug "Sending presence to roster.."
|
@logger.debug "Sending presence to roster.."
|
||||||
@xmpp.subscription_req(chat_id.to_s, @cache[:chats][chat_id].title.to_s) # send subscription request
|
@xmpp.presence_update(chat_id.to_s, :subscribe, nil, nil, @cache[:chats][chat_id].title.to_s) # send subscription request
|
||||||
case @cache[:chats][chat_id].type # determine status / presence
|
@xmpp.presence_update(chat_id.to_s, nil, :chat, nil, @cache[:chats][chat_id].title.to_s) if chat_id < 0 # send :chat status if its group/supergroup
|
||||||
when TD::Types::ChatType::BasicGroup, TD::Types::ChatType::Supergroup then presence, status = :chat, @cache[:chats][chat_id].title.to_s
|
|
||||||
when TD::Types::ChatType::Private then presence, status = self.format_status(@cache[:users][chat_id].status)
|
|
||||||
end
|
|
||||||
@xmpp.presence_update(chat_id.to_s, presence, status) # send presence
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# update user info #
|
# update user info in cache and sync status to roster if needed #
|
||||||
def process_user_info(user_id)
|
def process_user_info(user_id)
|
||||||
@logger.debug 'Updating user id %s..' % user_id.to_s
|
@logger.debug 'Updating user id %s..' % user_id.to_s
|
||||||
@client.get_user(user_id).then { |user| @cache[:users][user_id] = user }.wait
|
@client.get_user(user_id).then { |user|
|
||||||
|
@cache[:users][user_id] = user # add to cache
|
||||||
|
self.process_status_update(user_id, user.status) # status update
|
||||||
|
}.wait
|
||||||
|
end
|
||||||
|
|
||||||
|
# convert telegram status to XMPP one
|
||||||
|
def process_status_update(user_id, status)
|
||||||
|
@logger.debug "Processing status update for user id %s.." % user_id.to_s
|
||||||
|
xmpp_show, xmpp_status = nil, ''
|
||||||
|
case status
|
||||||
|
when TD::Types::UserStatus::Online
|
||||||
|
xmpp_show = nil
|
||||||
|
xmpp_status = "Online"
|
||||||
|
when TD::Types::UserStatus::Offline
|
||||||
|
xmpp_show = (Time.now.getutc.to_i - status.was_online.to_i < 3600) ? :away : :xa
|
||||||
|
xmpp_status = DateTime.strptime(status.was_online.to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y")
|
||||||
|
when TD::Types::UserStatus::Recently
|
||||||
|
xmpp_show = :dnd
|
||||||
|
xmpp_status = "Last seen recently"
|
||||||
|
when TD::Types::UserStatus::LastWeek
|
||||||
|
xmpp_show = :unavailable
|
||||||
|
xmpp_status = "Last seen last week"
|
||||||
|
when TD::Types::UserStatus::LastMonth
|
||||||
|
xmpp_show = :unavailable
|
||||||
|
xmpp_status = "Last seen last month"
|
||||||
|
end
|
||||||
|
@xmpp.presence_update(user_id.to_s, nil, xmpp_show, xmpp_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
## Format functions #######################
|
## Format functions #######################
|
||||||
###########################################
|
###########################################
|
||||||
|
|
||||||
# convert telegram status to XMPP one
|
|
||||||
def format_status(status)
|
|
||||||
presence, message = nil, ''
|
|
||||||
case status
|
|
||||||
when TD::Types::UserStatus::Online
|
|
||||||
presence = nil
|
|
||||||
message = "Online"
|
|
||||||
when TD::Types::UserStatus::Offline
|
|
||||||
presence = (Time.now.getutc.to_i - status.was_online.to_i < 3600) ? :away : :xa
|
|
||||||
message = DateTime.strptime(status.was_online.to_s,'%s').strftime("Last seen at %H:%M %d/%m/%Y")
|
|
||||||
when TD::Types::UserStatus::Recently
|
|
||||||
presence = :dnd
|
|
||||||
message = "Last seen recently"
|
|
||||||
when TD::Types::UserStatus::LastWeek
|
|
||||||
presence = :unavailable
|
|
||||||
message = "Last seen last week"
|
|
||||||
when TD::Types::UserStatus::LastMonth
|
|
||||||
presence = :unavailable
|
|
||||||
message = "Last seen last month"
|
|
||||||
end
|
|
||||||
return presence, message
|
|
||||||
end
|
|
||||||
|
|
||||||
# format tg user name #
|
# format tg user name #
|
||||||
def format_username(user_id)
|
def format_username(user_id)
|
||||||
if not @cache[:users].key? user_id then self.process_user_info(user_id) end
|
if not @cache[:users].key? user_id then self.process_user_info(user_id) end
|
||||||
|
|
|
@ -1,16 +1,6 @@
|
||||||
require 'xmpp4r'
|
|
||||||
require 'sqlite3'
|
require 'sqlite3'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
require 'xmpp4r'
|
||||||
#
|
|
||||||
# todo: #
|
|
||||||
#
|
|
||||||
# last message edit / delete
|
|
||||||
# join chat / add contact / get information by link/id/@username
|
|
||||||
# chat admin commands (kick, invite, ban, etc.)
|
|
||||||
# sending files
|
|
||||||
# vcards
|
|
||||||
#
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
### Some constants #########
|
### Some constants #########
|
||||||
|
@ -69,7 +59,7 @@ class XMPPComponent
|
||||||
@@transport.auth( @config[:secret] )
|
@@transport.auth( @config[: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
|
||||||
@@transport.add_presence_callback do |presence| self.presence_handler(presence) end
|
@@transport.add_presence_callback do |presence| self.presence_handler(presence) end
|
||||||
# @@transport.add_iq_callback do |iq| self.iq_handler(iq) end
|
#@@transport.add_iq_callback do |iq| self.iq_handler(iq) end
|
||||||
@logger.info "Connection established"
|
@logger.info "Connection established"
|
||||||
self.load_db()
|
self.load_db()
|
||||||
@logger.info 'Found %s sessions in database.' % @sessions.count
|
@logger.info 'Found %s sessions in database.' % @sessions.count
|
||||||
|
@ -152,14 +142,14 @@ end
|
||||||
## XMPP Session Class #######
|
## XMPP Session Class #######
|
||||||
#############################
|
#############################
|
||||||
class XMPPSession < XMPPComponent
|
class XMPPSession < XMPPComponent
|
||||||
attr_reader :user_jid, :tg_login, :message_queue
|
attr_reader :user_jid, :tg_login
|
||||||
attr_accessor :online, :tg_auth_data
|
attr_accessor :online, :message_queue, :auth_data
|
||||||
|
|
||||||
# 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)
|
||||||
@logger = Logger.new(STDOUT); @logger.level = @@loglevel; @logger.progname = '[XMPPSession: %s/%s]' % [jid, tg_login] # init logger
|
@logger = Logger.new(STDOUT); @logger.level = @@loglevel; @logger.progname = '[XMPPSession: %s/%s]' % [jid, tg_login] # init logger
|
||||||
@logger.info "Initializing new session.."
|
@logger.info "Initializing new session.."
|
||||||
@user_jid, @tg_login, @tg_auth_data, @message_queue = jid, tg_login, {code: nil, password: nil}, Queue.new() # init class variables
|
@user_jid, @tg_login, @auth_data, @message_queue = jid, tg_login, Hash.new(), Queue.new() # init class variables
|
||||||
end
|
end
|
||||||
|
|
||||||
# connect to tg #
|
# connect to tg #
|
||||||
|
@ -185,27 +175,16 @@ class XMPPSession < XMPPComponent
|
||||||
@@transport.send(reply)
|
@@transport.send(reply)
|
||||||
end
|
end
|
||||||
|
|
||||||
# subscription request to current user via XMPP #
|
|
||||||
def subscription_req(from, nickname = nil)
|
|
||||||
@logger.debug "Subscription request from %s.." %from.to_s
|
|
||||||
req = Jabber::Presence.new()
|
|
||||||
req.from = from.nil? ? @@transport.jid : from.to_s+'@'+@@transport.jid.to_s # presence <from>
|
|
||||||
req.to = @user_jid # presence <to>
|
|
||||||
req.type = :subscribe
|
|
||||||
req.add_element('nick', {'xmlns' => 'http://jabber.org/protocol/nick'} ).add_text(nickname) unless nickname.nil?
|
|
||||||
@logger.debug req
|
|
||||||
@@transport.send(req)
|
|
||||||
end
|
|
||||||
|
|
||||||
# presence update #
|
# presence update #
|
||||||
def presence_update(from, status, message, type = nil)
|
def presence_update(from, type = nil, show = nil, status = nil, nickname = nil)
|
||||||
@logger.debug "Presence update request from %s.." %from.to_s
|
@logger.debug "Presence update request from %s.." %from.to_s
|
||||||
req = Jabber::Presence.new()
|
req = Jabber::Presence.new()
|
||||||
req.from = from.nil? ? @@transport.jid : from.to_s+'@'+@@transport.jid.to_s # presence <from>
|
req.from = from.nil? ? @@transport.jid : from.to_s+'@'+@@transport.jid.to_s # presence <from>
|
||||||
req.to = @user_jid # presence <to>
|
req.to = @user_jid # presence <to>
|
||||||
req.show = status unless status.nil? # presence <show>
|
|
||||||
req.type = type unless type.nil? # pres. type
|
req.type = type unless type.nil? # pres. type
|
||||||
req.status = message # presence message
|
req.show = show unless show.nil? # presence <show>
|
||||||
|
req.status = status unless status.nil? # presence message
|
||||||
|
req.add_element('nick', {'xmlns' => 'http://jabber.org/protocol/nick'} ).add_text(nickname) unless nickname.nil? # nickname
|
||||||
@logger.debug req
|
@logger.debug req
|
||||||
@@transport.send(req)
|
@@transport.send(req)
|
||||||
end
|
end
|
||||||
|
@ -218,16 +197,16 @@ class XMPPSession < XMPPComponent
|
||||||
@message_queue << {to: to.split('@')[0], text: text}
|
@message_queue << {to: to.split('@')[0], text: text}
|
||||||
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 :auth_data {} to Telegram client thread ) #
|
||||||
def enter_auth_data(typ, data)
|
def enter_auth_data(typ, data)
|
||||||
@logger.info "Authenticating in Telegram network with :%s" % typ
|
@logger.info "Authenticating in Telegram network with :%s" % typ
|
||||||
@tg_auth_data[typ.to_sym] = data
|
@auth_data[typ.to_sym] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
|
|
||||||
# session status #
|
# session status #
|
||||||
def online?() @online end
|
def online?() @online end
|
||||||
def online!() @logger.info "Connection established"; @online = true; self.subscription_req(nil); self.presence_update(nil, nil, "Logged in as " + @tg_login.to_s) end
|
def online!() @logger.info "Connection established"; @online = true; self.presence_update(nil, :subscribe); self.presence_update(nil, nil, nil, "Logged in as " + @tg_login.to_s) end
|
||||||
def offline!() @online = false; self.presence_update(nil, nil, "Logged out", :unavailable); end
|
def offline!() @online = false; self.presence_update(nil, :unavailable, nil, "Logged out"); end
|
||||||
end
|
end
|
||||||
|
|
Reference in a new issue