Added basic chat buffer. Creates chats automatically when someone sends you a message
This commit is contained in:
parent
9291b3957b
commit
65fb61425b
@ -255,3 +255,37 @@ class empty(object):
|
||||
output.speak(_(u"This buffer doesn't support getting more items."))
|
||||
|
||||
def remove_buffer(self, mandatory=False): return False
|
||||
|
||||
class chatBuffer(baseBuffer):
|
||||
|
||||
def create_tab(self, parent):
|
||||
self.tab = home.chatTab(parent)
|
||||
|
||||
def connect_events(self):
|
||||
widgetUtils.connect_event(self.tab.send, widgetUtils.BUTTON_PRESSED, self.send_chat_to_user)
|
||||
|
||||
def get_items(self, show_nextpage=False):
|
||||
retrieved = True # Control variable for handling unauthorised/connection errors.
|
||||
try:
|
||||
num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs)
|
||||
except VkAPIMethodError as err:
|
||||
print(u"Error {0}: {1}".format(err.code, err.message))
|
||||
retrieved = err.code
|
||||
return retrieved
|
||||
if show_nextpage == False:
|
||||
if self.tab.list.get_count() > 0 and num > 0:
|
||||
print "inserting a value"
|
||||
v = [i for i in self.session.db[self.name]["items"][:num]]
|
||||
v.reverse()
|
||||
[self.insert(i, True) for i in v]
|
||||
else:
|
||||
[self.insert(i) for i in self.session.db[self.name]["items"][:num]]
|
||||
else:
|
||||
if num > 0:
|
||||
[self.insert(i, False) for i in self.session.db[self.name]["items"][:num]]
|
||||
return retrieved
|
||||
|
||||
def send_chat_to_user(self, *args, **kwargs):
|
||||
text = self.tab.text.GetValue()
|
||||
if text == "": return
|
||||
response = self.session.vk.client.messages.send(user_id=self.kwargs["user_id"], message=text)
|
||||
|
22
src/controller/longpoolthread.py
Normal file
22
src/controller/longpoolthread.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import threading
|
||||
from vk import longpool
|
||||
from pubsub import pub
|
||||
|
||||
class worker(threading.Thread):
|
||||
def __init__(self, session):
|
||||
super(worker, self).__init__()
|
||||
self.session = session
|
||||
self.l = longpool.LongPoll(self.session.vk.client)
|
||||
|
||||
def run(self):
|
||||
while self.session.is_logged == True:
|
||||
p = self.l.check()
|
||||
for i in p:
|
||||
print i.message_id, i.flags, i.from_id, i.user_id, i.mask, i.byself, i.message_flags
|
||||
# if i.flags == 4 or i.flags == 51 or i.flags == 49:
|
||||
if i.text != None and i.from_id != None and i.flags != None and i.message_flags != None:
|
||||
print i.message_id, i.flags, i.from_id, i.user_id, i.mask, i.byself, i.message_flags
|
||||
# if i.from_id != None:
|
||||
print "ordering sent stuff"
|
||||
pub.sendMessage("order-sent-message", obj=i)
|
@ -10,6 +10,7 @@ import player
|
||||
import posts
|
||||
import webbrowser
|
||||
import logging
|
||||
import longpoolthread
|
||||
from pubsub import pub
|
||||
from mysc.repeating_timer import RepeatingTimer
|
||||
from mysc.thread_utils import call_threaded
|
||||
@ -75,6 +76,9 @@ class Controller(object):
|
||||
r_audio = buffers.audioBuffer(parent=self.window.tb, name="recommended_audio", composefunc="compose_audio", session=self.session, endpoint="getRecommendations", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"])
|
||||
self.buffers.append(r_audio)
|
||||
self.window.insert_buffer(r_audio.tab, _(u"Recommendations"), self.window.search("audios"))
|
||||
chats = buffers.empty(parent=self.window.tb, name="chats")
|
||||
self.buffers.append(chats)
|
||||
self.window.add_buffer(chats.tab, _(u"Chats"))
|
||||
timelines = buffers.empty(parent=self.window.tb, name="timelines")
|
||||
self.buffers.append(timelines)
|
||||
self.window.add_buffer(timelines.tab, _(u"Timelines"))
|
||||
@ -97,6 +101,7 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.changelog, menuitem=self.window.changelog)
|
||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.configuration, menuitem=self.window.settings_dialog)
|
||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.new_timeline, menuitem=self.window.timeline)
|
||||
pub.subscribe(self.get_chat, "order-sent-message")
|
||||
|
||||
def disconnect_events(self):
|
||||
log.debug("Disconnecting some events...")
|
||||
@ -116,6 +121,8 @@ class Controller(object):
|
||||
self.window.change_status(_(u"Loading items for {0}").format(i.name,))
|
||||
i.get_items()
|
||||
self.window.change_status(_(u"Ready"))
|
||||
self.longpool = longpoolthread.worker(self.session)
|
||||
self.longpool.start()
|
||||
|
||||
def in_post(self, buffer):
|
||||
buffer = self.search(buffer)
|
||||
@ -242,4 +249,64 @@ class Controller(object):
|
||||
del buffer
|
||||
commonMessages.show_error_code(answer)
|
||||
return
|
||||
self.window.insert_buffer(buffer.tab, name_, position)
|
||||
self.window.insert_buffer(buffer.tab, name_, position)
|
||||
|
||||
def new_chat(self, *args, **kwargs):
|
||||
b = self.get_current_buffer()
|
||||
if not hasattr(b, "get_users"):
|
||||
b = self.search("home_timeline")
|
||||
d = []
|
||||
for i in self.session.db["users"]:
|
||||
d.append((i, self.session.get_user_name(i)))
|
||||
for i in self.session.db["groups"]:
|
||||
d.append((-i, self.session.get_user_name(-i)))
|
||||
a = timeline.timelineDialog([i[1] for i in d])
|
||||
if a.get_response() == widgetUtils.OK:
|
||||
user = a.get_user()
|
||||
buffertype = a.get_buffer_type()
|
||||
user_id = ""
|
||||
for i in d:
|
||||
if i[1] == user:
|
||||
user_id = i[0]
|
||||
if user_id == None:
|
||||
commonMessages.no_user_exist()
|
||||
return
|
||||
buffer = buffers.chatBuffer(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="compose_message", session=self.session, count=200, user_id=user_id, rev=1)
|
||||
self.buffers.append(buffer)
|
||||
self.window.insert_buffer(buffer.tab, _(u"Chat with {0}").format(self.session.get_user_name(user_id,)), self.window.search("chats"))
|
||||
buffer.get_items()
|
||||
|
||||
def search_chat_buffer(self, user_id):
|
||||
for i in self.buffers:
|
||||
if "_messages" in i.name:
|
||||
if i.kwargs.has_key("user_id") and i.kwargs["user_id"] == user_id: return i
|
||||
return None
|
||||
|
||||
def chat_from_id(self, user_id):
|
||||
buffer = buffers.chatBuffer(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="compose_message", session=self.session, count=200, user_id=user_id, rev=1)
|
||||
self.buffers.append(buffer)
|
||||
self.window.insert_buffer(buffer.tab, _(u"Chat with {0}").format(self.session.get_user_name(user_id,)), self.window.search("chats"))
|
||||
buffer.get_items()
|
||||
return True
|
||||
|
||||
def get_chat(self, obj=None):
|
||||
""" Searches or creates a chat buffer with the id of the user that is sending or receiving a message.
|
||||
obj vk.longpool.event: an event wich defines some data from the vk's longpool server."""
|
||||
# Set user_id to the id of the friend wich is receiving or sending the message.
|
||||
obj.user_id = obj.from_id
|
||||
buffer = self.search_chat_buffer(obj.user_id)
|
||||
if buffer == None:
|
||||
wx.CallAfter(self.chat_from_id, obj.user_id)
|
||||
return
|
||||
# If the chat already exists, let's create a dictionary wich will contains data of the received message.
|
||||
message = {"id": obj.message_id, "user_id": obj.user_id, "date": obj.timestamp, "body": obj.text, "attachments": obj.attachments}
|
||||
# If outbox it's true, it means that message["from_id"] should be the current user. If not, the obj.user_id should be taken.
|
||||
if obj.message_flags.has_key("outbox") == True:
|
||||
message["from_id"] = self.session.user_id
|
||||
else:
|
||||
message["from_id"] = obj.from_id
|
||||
data = [message]
|
||||
# Let's add this to the buffer.
|
||||
# ToDo: Clean this code and test how is the database working with this set to True.
|
||||
num = self.session.order_buffer(buffer.name, data, True)
|
||||
buffer.insert(self.session.db[buffer.name]["items"][-1], False)
|
||||
|
@ -101,6 +101,13 @@ def compose_new(status, session):
|
||||
if status["type"] != "post": print status
|
||||
return [user, message, created_at]
|
||||
|
||||
def compose_message(message, session):
|
||||
user = session.get_user_name(message["from_id"])
|
||||
original_date = arrow.get(message["date"])
|
||||
created_at = original_date.format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
||||
body = message["body"]
|
||||
return [u"{2}, {0} {1}".format(body, created_at, user)]
|
||||
|
||||
def compose_status(status, session):
|
||||
user = session.get_user_name(status["from_id"])
|
||||
if status.has_key("copy_history"):
|
||||
@ -141,7 +148,7 @@ class vkSession(object):
|
||||
self.db[name]["items"] = []
|
||||
first_addition = True
|
||||
for i in data:
|
||||
if i.has_key("type") and (i["type"] == "wall_photo" or i["type"] == "photo_tag"):
|
||||
if i.has_key("type") and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo"):
|
||||
log.debug("Skipping unsupported item... %r" % (i,))
|
||||
continue
|
||||
if find_item(self.db[name]["items"], i) == False:
|
||||
@ -240,6 +247,14 @@ class vkSession(object):
|
||||
num = self.order_buffer(name, data, show_nextpage)
|
||||
return num
|
||||
|
||||
def get_messages(self, name="", *args, **kwargs):
|
||||
data = self.vk.client.messages.getHistory(*args, **kwargs)
|
||||
if data != None:
|
||||
print data
|
||||
num = self.order_buffer(name, data["items"], False)
|
||||
return num
|
||||
|
||||
|
||||
def get_user_name(self, user_id):
|
||||
if user_id > 0:
|
||||
if self.db["users"].has_key(user_id):
|
||||
|
152
src/vk/longpool.py
Normal file
152
src/vk/longpool.py
Normal file
@ -0,0 +1,152 @@
|
||||
# encoding: utf-8
|
||||
import requests
|
||||
|
||||
class LongPoll(object):
|
||||
def __init__(self, vk, wait=25, use_ssl=True, mode=34):
|
||||
self.vk = vk
|
||||
self.wait = wait
|
||||
self.use_ssl = use_ssl
|
||||
self.mode = mode
|
||||
self.get_longpoll_server()
|
||||
self.url = 'https' if use_ssl else 'http'
|
||||
self.url += '://' + self.server
|
||||
|
||||
def get_longpoll_server(self, update_ts=True):
|
||||
values = {
|
||||
'use_ssl': '1' if self.use_ssl else '0',
|
||||
'need_pts': '1'
|
||||
}
|
||||
response = self.vk.messages.getLongPollServer(**values)
|
||||
self.key = response['key']
|
||||
self.server = response['server']
|
||||
if update_ts:
|
||||
self.ts = response['ts']
|
||||
self.pts = response['pts']
|
||||
|
||||
def check(self):
|
||||
values = {
|
||||
'act': 'a_check',
|
||||
'key': self.key,
|
||||
'ts': self.ts,
|
||||
'wait': self.wait,
|
||||
'mode': self.mode
|
||||
}
|
||||
response = requests.get(self.url, params=values,
|
||||
timeout=self.wait + 10).json()
|
||||
events = []
|
||||
|
||||
if 'failed' not in response:
|
||||
self.ts = response['ts']
|
||||
self.pts = response['pts']
|
||||
|
||||
for raw_event in response['updates']:
|
||||
events.append(Event(raw_event))
|
||||
# http://vk.com/dev/using_longpoll
|
||||
else:
|
||||
self.get_longpoll_server(update_ts=False)
|
||||
|
||||
return events
|
||||
|
||||
|
||||
CHAT_START_ID = int(2E9)
|
||||
|
||||
EVENT_TYPES = {
|
||||
0: 'message_delete',
|
||||
1: 'message_flags_replace',
|
||||
2: 'message_flags_put',
|
||||
3: 'message_flags_reset',
|
||||
4: 'message_new',
|
||||
|
||||
8: 'user_online',
|
||||
9: 'user_offline',
|
||||
|
||||
51: 'chat_new',
|
||||
61: 'user_typing',
|
||||
62: 'user_typing_in_chat',
|
||||
|
||||
70: 'user_call',
|
||||
}
|
||||
|
||||
ASSOCIATIVES = {
|
||||
0: ['message_id'],
|
||||
1: ['message_id', 'flags'],
|
||||
2: ['message_id', 'mask', 'user_id'],
|
||||
3: ['message_id', 'mask', 'user_id', 'timestamp', 'subject',
|
||||
'text', 'attachments'],
|
||||
4: ['message_id', 'flags', 'from_id', 'timestamp', 'subject',
|
||||
'text', 'attachments'],
|
||||
|
||||
8: ['user_id', 'flags'],
|
||||
9: ['user_id', 'flags'],
|
||||
|
||||
51: ['chat_id', 'byself'],
|
||||
61: ['user_id', 'flags'],
|
||||
62: ['user_id', 'chat_id'],
|
||||
|
||||
70: ['user_id', 'call_id'],
|
||||
}
|
||||
|
||||
MESSAGE_FLAGS = [
|
||||
'unread', 'outbox', 'replied', 'important', 'chat', 'friends', 'spam',
|
||||
'deleted', 'fixed', 'media'
|
||||
]
|
||||
|
||||
|
||||
class Event(object):
|
||||
def __init__(self, raw):
|
||||
self.raw = raw
|
||||
|
||||
self.message_id = None
|
||||
self.flags = None
|
||||
self.mask = None
|
||||
self.user_id = None
|
||||
self.from_id = None
|
||||
self.timestamp = None
|
||||
self.subject = None
|
||||
self.text = None
|
||||
self.attachments = None
|
||||
self.call_id = None
|
||||
self.chat_id = None
|
||||
self.byself = None
|
||||
|
||||
cmd = raw[0]
|
||||
|
||||
self.message_flags = {}
|
||||
self.type = EVENT_TYPES.get(cmd)
|
||||
self._list_to_attr(raw[1:], ASSOCIATIVES.get(cmd))
|
||||
|
||||
if cmd == 4:
|
||||
self._parse_message_flags()
|
||||
self.text = self.text.replace('<br>', '\n')
|
||||
|
||||
if self.from_id > CHAT_START_ID:
|
||||
self.chat_id = self.from_id - CHAT_START_ID
|
||||
self.from_id = self.attachments['from']
|
||||
elif cmd in [2, 3]:
|
||||
if self.user_id > CHAT_START_ID:
|
||||
self.chat_id = self.user_id - CHAT_START_ID
|
||||
self.user_id = None
|
||||
elif cmd in [8, 9]:
|
||||
self.user_id = abs(self.user_id)
|
||||
|
||||
def _parse_message_flags(self):
|
||||
x = 1
|
||||
for i in MESSAGE_FLAGS:
|
||||
|
||||
if self.flags & x:
|
||||
self.message_flags.update({i: True})
|
||||
|
||||
x *= 2
|
||||
|
||||
def _list_to_attr(self, l, associative):
|
||||
if not associative:
|
||||
return
|
||||
|
||||
for i in range(len(l)):
|
||||
try:
|
||||
name = associative[i]
|
||||
except IndexError:
|
||||
return True
|
||||
|
||||
value = l[i]
|
||||
self.__setattr__(name, value)
|
@ -114,3 +114,28 @@ class empty(wx.Panel):
|
||||
self.name = name
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
class chatTab(wx.Panel):
|
||||
|
||||
def __init__(self, parent):
|
||||
super(chatTab, self).__init__(parent=parent)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(self.create_controls())
|
||||
self.send = wx.Button(self, -1, _(u"Send"))
|
||||
sizer.Add(self.send, 0, wx.ALL, 5)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
def create_controls(self):
|
||||
lbl1 = wx.StaticText(self, wx.NewId(), _(u"History"))
|
||||
self.list = widgetUtils.list(self, *[_(u"post")], style=wx.LC_REPORT)
|
||||
self.list.set_windows_size(0, 190)
|
||||
# self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
box.Add(lbl1, 0, wx.ALL, 5)
|
||||
box.Add(self.list.list, 0, wx.ALL, 5)
|
||||
lbl2 = wx.StaticText(self, -1, _(u"Write a message"))
|
||||
self.text = wx.TextCtrl(self, -1)
|
||||
box.Add(lbl2, 0, wx.ALL, 20)
|
||||
box.Add(self.text, 0, wx.ALL, 5)
|
||||
return box
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user