Gotta commit somethin' :X
This commit is contained in:
parent
277c4c0aab
commit
9a4febca5c
2 changed files with 146 additions and 4 deletions
|
@ -1,10 +1,21 @@
|
|||
import enum
|
||||
|
||||
from nntp.tiny.db import Database
|
||||
from nntp.tiny.newsgroup import Newsgroup
|
||||
|
||||
class ServerCapability(enum.Flag):
|
||||
NONE = 0
|
||||
AUTH = enum.auto()
|
||||
POST = enum.auto()
|
||||
|
||||
class Server():
|
||||
def __init_(self):
|
||||
self.capabilities = NNTPServerCapability.NONE
|
||||
def __init_(self, db: Database):
|
||||
self.db = db
|
||||
self.capabilities = ServerCapability.NONE
|
||||
self.newsgroups = dict()
|
||||
|
||||
self._init_groups()
|
||||
|
||||
def _init_newsgroups(self):
|
||||
for newsgroup in self.db.query(Newsgroup).each():
|
||||
self.newsgroups[newsgroup.name.casefold()] = newsgroup
|
||||
|
|
|
@ -2,8 +2,12 @@ import enum
|
|||
import socket
|
||||
import re
|
||||
|
||||
from nntp.tiny.server import Server, ServerCapability
|
||||
from nntp.tiny.response import Response
|
||||
from typing import Optional
|
||||
|
||||
from nntp.tiny.server import Server, ServerCapability
|
||||
from nntp.tiny.response import Response, ResponseCode
|
||||
from nntp.tiny.newsgroup import Newsgroup
|
||||
from nntp.tiny.message import Message
|
||||
|
||||
class SessionState(enum.Flag):
|
||||
NONE = 0
|
||||
|
@ -12,6 +16,70 @@ class SessionState(enum.Flag):
|
|||
|
||||
from nntp.tiny.buffer import LineBuffer, BufferOverflow
|
||||
|
||||
class MessageRange():
|
||||
__slots__ = 'id', 'min', 'max',
|
||||
|
||||
RE_NUM = re.compile('^(\d+)$')
|
||||
RE_RANGE = re.compile('^(\d+)-(\d+)$')
|
||||
RE_RANGE_LOWER = re.compile('^(\d+$)-$')
|
||||
RE_RANGE_UPPER = re.compile('^-(\d+$)$')
|
||||
|
||||
def __init__(self):
|
||||
self.id: int = None
|
||||
self.min: int = None
|
||||
self.max: int = None
|
||||
|
||||
def __str__(self):
|
||||
if self.id is not None:
|
||||
return str(self.id)
|
||||
|
||||
if self.min is not None and self.max is None:
|
||||
return "%d-" % (self.min)
|
||||
elif self.min is not None and self.max is not None:
|
||||
return "%d-%d" % (self.min, self.max)
|
||||
elif self.min is None and self.max is not None:
|
||||
return "-%d" % (self.max)
|
||||
|
||||
return "?"
|
||||
|
||||
def __dict__(self):
|
||||
if self.id is not None:
|
||||
return {'id': self.id}
|
||||
|
||||
if self.min is not None and self.max is None:
|
||||
return { 'min(id)': self.min }
|
||||
elif self.min is not None and self.max is not None:
|
||||
return { 'min(id)': self.min, 'max(id)': self.max }
|
||||
elif self.min is None and self.max is not None:
|
||||
return { 'max(id)': self.max }
|
||||
|
||||
@staticmethod
|
||||
def parse(r: str):
|
||||
match = __class__.RE_NUM.match(r)
|
||||
if match:
|
||||
obj = __class__()
|
||||
obj.id = match[1]
|
||||
return obj
|
||||
|
||||
match = __class__.RE_RANGE.match(r)
|
||||
if match:
|
||||
obj = __class__()
|
||||
obj.min = match[1]
|
||||
obj.max = match[2]
|
||||
return obj
|
||||
|
||||
match = __class__.RE_RANGE_LOWER.match(r)
|
||||
if match:
|
||||
obj = __class__()
|
||||
obj.min = match[1]
|
||||
return obj
|
||||
|
||||
match = __class__.RE_RANGE_UPPER.match(r)
|
||||
if match:
|
||||
obj = __class__()
|
||||
obj.max = match[1]
|
||||
return obj
|
||||
|
||||
class Session():
|
||||
RE_SPLIT = re.compile(r'\s+')
|
||||
|
||||
|
@ -36,6 +104,8 @@ class Session():
|
|||
self.sock: socket.socket = sock
|
||||
self.buf: LineBuffer = LineBuffer()
|
||||
|
||||
self.newsgroup: Optional[Newsgroup] = None
|
||||
|
||||
def readline(self):
|
||||
return self.buf.readline(self.sock)
|
||||
|
||||
|
@ -64,6 +134,67 @@ class Session():
|
|||
|
||||
self.end()
|
||||
|
||||
def _cmd_group(self, name: str):
|
||||
if name not in self.server.newsgroups:
|
||||
return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_FOUND)
|
||||
|
||||
newsgroup = self.server.newsgroups[name]
|
||||
|
||||
sql = """
|
||||
select
|
||||
count(id),
|
||||
min(id),
|
||||
max(id)
|
||||
from
|
||||
newsgroup_message
|
||||
where
|
||||
newsgroup_id = ?
|
||||
"""
|
||||
|
||||
cr = self.server.db.execute(sql, (newsgroup.id))
|
||||
row = cr.fetchone()
|
||||
|
||||
text = "%d %d %d %s" % (
|
||||
row[0],
|
||||
row[1],
|
||||
row[2],
|
||||
newsgroup.name
|
||||
)
|
||||
|
||||
self.respond(ResponseCode.NNTP_GROUP_LISTING, text)
|
||||
|
||||
self.newsgroup = newsgroup
|
||||
|
||||
return
|
||||
|
||||
|
||||
def _cmd_listgroup(self, *args):
|
||||
newsgroup = self.newsgroup
|
||||
|
||||
if len(args) == 0 and newsgroup is None:
|
||||
return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_SELECTED)
|
||||
elif len(args) > 0:
|
||||
newsgroup = self.server.newsgroups.get(args[0])
|
||||
|
||||
if newsgroup is None:
|
||||
return self.respond(ResponseCode.NNTP_NEWSGROUP_NOT_FOUND)
|
||||
|
||||
values = {
|
||||
'newsgroup_id': newsgroup.id
|
||||
}
|
||||
|
||||
if len(args) > 1:
|
||||
msgrange = MessageRange.parse(args[1])z
|
||||
|
||||
values.update(dict(msgrange))
|
||||
|
||||
cr = self.server.db.query(Message, values)
|
||||
|
||||
for message in cr.each():
|
||||
self.print(str(message.id))
|
||||
|
||||
return self.end()
|
||||
|
||||
def handle(self):
|
||||
line = self.readline()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue