1
0

libchat.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/env python3
  2. # -*- coding: UTF-8 -*-
  3. import sqlite3
  4. import os
  5. from datetime import datetime
  6. import time
  7. from collections import namedtuple
  8. SOURCE_ID = {'wechat': 0}
  9. NUM_FIELDS = 8
  10. ChatMsgBase = namedtuple('ChatMsgBase',
  11. ['source', 'time', 'sender', 'chatroom',
  12. 'text', 'image', 'sound', 'extra_data'])
  13. """ source: unicode,
  14. time: datetime,
  15. sender: unicode,
  16. chatroom: unicode,
  17. text: unicode,
  18. image: string,
  19. sound: string,
  20. extra_data: string
  21. """
  22. class ChatMsg(ChatMsgBase):
  23. def __repr__(self): # repr must return str?
  24. return "Msg@{}/{}-{}/{}/{}/{}/{}".format(
  25. self.time, self.sender.encode('utf-8'),
  26. self.chatroom.encode('utf-8'),
  27. self.text.encode('utf-8'), 'IMG' if self.image else '',
  28. 'AUD' if self.sound else '', self.extra_data)
  29. class SqliteLibChat(object):
  30. """ Interface for interacting with LibChat database"""
  31. def __init__(self, db_file):
  32. self.db_file = db_file
  33. exist = os.path.isfile(db_file)
  34. self.conn = sqlite3.connect(db_file)
  35. self.conn.text_factory = str # to allow use of raw-byte string
  36. self.c = self.conn.cursor()
  37. if not exist:
  38. self.create()
  39. def create(self):
  40. self.c.execute("""
  41. CREATE TABLE message (
  42. source SMALLINT,
  43. time TEXT,
  44. sender TEXT,
  45. chatroom TEXT,
  46. text TEXT,
  47. image COLLATE BINARY,
  48. sound COLLATE BINARY,
  49. extra_data COLLATE BINARY
  50. )
  51. """)
  52. self.conn.commit()
  53. def _add_msg(self, tp):
  54. assert isinstance(tp, ChatMsg)
  55. self.c.execute(
  56. """INSERT INTO message VALUES ({0})""".format(
  57. ','.join(['?']*NUM_FIELDS)), tp)
  58. def add_msgs(self, msgs):
  59. """ each message is a ChatMsg instance"""
  60. self.c = self.conn.cursor()
  61. for m in msgs:
  62. self._add_msg(SqliteLibChat.prefilter(m))
  63. self.conn.commit()
  64. @staticmethod
  65. def prefilter(msg):
  66. source = msg.source
  67. if isinstance(source, basestring):
  68. source = SOURCE_ID[source]
  69. tm = int(time.mktime(msg[1].timetuple()))
  70. return ChatMsg(source, tm, *msg[2:])
  71. @staticmethod
  72. def postfilter(msg):
  73. # source
  74. text = msg[4].decode('utf-8')
  75. time = datetime.fromtimestamp(int(msg[1]))
  76. return ChatMsg(msg[0], time, msg[2], msg[3],
  77. text=text, image=msg[5],
  78. sound=msg[6], extra_data=msg[7])
  79. def iterate_all_msg(self, predicate=None):
  80. """ predicate: a dict used as SELECT filter
  81. return a generator for all messages
  82. """
  83. if predicate is None:
  84. self.c.execute("SELECT * FROM message")
  85. else:
  86. self.c.execute("SELECT * FROM message WHERE {}".format(
  87. ' AND '.join(["{} = {}".format(k, v)
  88. for k, v in predicate.items()])))
  89. for row in self.c.fetchall():
  90. yield ChatMsg(*SqliteLibChat.postfilter(row))
  91. if __name__ == '__main__':
  92. db = SqliteLibChat(os.path.join(
  93. os.path.dirname(__file__), './message.db'))
  94. #msg = ChatMsg(-1, 1000, 'me', 'room', 'hello', '\x01\x02\x03', '', '')
  95. #db.add_msgs([msg])
  96. for k in db.iterate_all_msg():
  97. from IPython import embed; embed()
  98. print(k)