You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

120 lines
4.6 KiB

  1. #! /usr/bin/env python3
  2. """
  3. meli - sample plugin
  4. Copyright 2019 Manos Pitsidianakis
  5. This file is part of meli.
  6. meli is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. meli is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with meli. If not, see <http://www.gnu.org/licenses/>.
  16. """
  17. import sys
  18. import time
  19. import subprocess
  20. import msgpack
  21. import nntplib
  22. import libmeliapi
  23. import itertools
  24. def chunks(iterable, n):
  25. while True:
  26. try:
  27. yield itertools.chain((next(iterable),), itertools.islice(iterable, n-1))
  28. except:
  29. break
  30. class NNTPClient(libmeliapi.Client):
  31. def __init__(self, stream_address, server_address, newsgroup):
  32. super().__init__(stream_address)
  33. self.bytes_cache = {}
  34. self.conn = nntplib.NNTP(server_address)
  35. self.newsgroup = newsgroup
  36. def backend_req(self, req):
  37. print("[nntp-plugin]: backend_req = ", req, flush=True, file=sys.stderr)
  38. if req.data == b'is_online':
  39. self.ok_send(None)
  40. elif req.data == b'get':
  41. resp, count, first, last, name = self.conn.group(self.newsgroup)
  42. print('Group', name, 'has', count, 'articles, range', first, 'to', last, flush=True, file=sys.stderr)
  43. resp, overviews = self.conn.over((0, last))
  44. for chunk in chunks(iter(reversed(overviews)), 100):
  45. ret = []
  46. for id, over in chunk:
  47. #print(id, nntplib.decode_header(over['subject']), flush=True, file=sys.stderr)
  48. env = {}
  49. env["hash"] = id
  50. env["subject"] = nntplib.decode_header(over["subject"])
  51. env["from"] = nntplib.decode_header(over["from"])
  52. env["date"] = nntplib.decode_header(over["date"])
  53. env["message_id"] = nntplib.decode_header(over["message-id"])
  54. env["references"] = nntplib.decode_header(over["references"])
  55. try:
  56. env["to"] = nntplib.decode_header(over["to"])
  57. except KeyError:
  58. env["to"] = self.newsgroup
  59. ret.append(env)
  60. print("ret len = ", len(ret), flush=True,file=sys.stderr)
  61. self.ok_send(ret)
  62. self.ok_send(None)
  63. def backend_op_req(self, req):
  64. print("[nntp-plugin]: backend_op_req = ", req, flush=True, file=sys.stderr)
  65. if req.data == b'as_bytes':
  66. _hash = self.read()
  67. print("[nntp-plugin]: hash = ", _hash, flush=True, file=sys.stderr)
  68. self.ack()
  69. try:
  70. try:
  71. self.ok_send(self.bytes_cache[_hash])
  72. except KeyError:
  73. resp, info = self.conn.article(_hash)
  74. #print(_id, " line0 = ", str(info.lines[0], 'utf-8', 'ignore'))
  75. elem = b'\n'.join(info.lines)
  76. self.bytes_cache[_hash] = str(elem, 'utf-8', 'ignore')
  77. self.ok_send(self.bytes_cache[_hash])
  78. except Exception as e:
  79. self.err_send(str(e))
  80. if __name__ == "__main__":
  81. import importlib
  82. importlib.reload(libmeliapi)
  83. stream_address = './soworkfile'
  84. server_address = 'news.gmane.org'
  85. newsgroup = 'gmane.comp.python.committers'
  86. client = NNTPClient(stream_address, server_address, newsgroup)
  87. client.connect()
  88. #client.setblocking(True)
  89. try:
  90. while True:
  91. req = client.read()
  92. if req is None:
  93. time.sleep(0.15)
  94. continue
  95. #client.setblocking(True)
  96. client.ack()
  97. print("[nntp-plugin]: ", "req: ", req, flush=True, file=sys.stderr)
  98. sys.stderr.flush()
  99. if isinstance(req, msgpack.ExtType):
  100. if req.code == client.backend_fn_type:
  101. client.backend_req(req)
  102. elif req.code == client.backend_op_fn_type:
  103. client.backend_op_req(req)
  104. print("[nntp-plugin]: ", req, flush=True, file=sys.stderr)
  105. #client.setblocking(True)
  106. time.sleep(0.15)
  107. except:
  108. raise RuntimeError("Something bad happened")