From e8aa350c53acc6046401e5c5242199a064a577a1 Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Wed, 26 Jan 2022 00:29:30 +0300 Subject: [PATCH] Implement NEWGROUPS command --- README.md | 2 +- internal/backend/sqlite/sqlite.go | 5 ++ internal/backend/storage_backend.go | 1 + internal/protocol/constants.go | 2 + internal/server/handler.go | 74 +++++++++++++++++++++++++++-- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0567513..044bbaa 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ - :x: `IHAVE` - :x: `LAST` - :x: `LISTGROUP` -- :x: `NEWGROUPS` +- :heavy_check_mark: `NEWGROUPS` - :x: `NEWNEWS` - :x: `NEXT` - :x: `OVER` diff --git a/internal/backend/sqlite/sqlite.go b/internal/backend/sqlite/sqlite.go index cdfb3e5..b07c414 100644 --- a/internal/backend/sqlite/sqlite.go +++ b/internal/backend/sqlite/sqlite.go @@ -88,3 +88,8 @@ func (sb *SQLiteBackend) GetGroup(groupName string) (models.Group, error) { var group models.Group return group, sb.db.Get(&group, "SELECT * FROM groups WHERE group_name = ?", groupName) } + +func (sb *SQLiteBackend) GetNewGroupsSince(timestamp int64) ([]models.Group, error) { + var groups []models.Group + return groups, sb.db.Select(&groups, "SELECT * FROM groups WHERE created_at > ?", timestamp) +} diff --git a/internal/backend/storage_backend.go b/internal/backend/storage_backend.go index 3a01bac..112aa5b 100644 --- a/internal/backend/storage_backend.go +++ b/internal/backend/storage_backend.go @@ -10,6 +10,7 @@ type StorageBackend interface { ListGroups() ([]models.Group, error) ListGroupsByPattern(pattern string) ([]models.Group, error) GetGroup(groupName string) (models.Group, error) + GetNewGroupsSince(timestamp int64) ([]models.Group, error) GetArticlesCount(g models.Group) (int, error) GetGroupLowWaterMark(g models.Group) (int, error) GetGroupHighWaterMark(g models.Group) (int, error) diff --git a/internal/protocol/constants.go b/internal/protocol/constants.go index 49a7f52..015f0cd 100644 --- a/internal/protocol/constants.go +++ b/internal/protocol/constants.go @@ -12,6 +12,7 @@ const ( CommandMode = "MODE" CommandList = "LIST" CommandGroup = "GROUP" + CommandNewGroups = "NEWGROUPS" ) const ( @@ -34,6 +35,7 @@ const ( MessageUnknownCommand = "500 Unknown command" MessageErrorHappened = "403 Failed to process command:" MessageListOfNewsgroupsFollows = "215 list of newsgroups follows" + MessageNewGroupsListOfNewsgroupsFollows = "231 list of new newsgroups follows" MessageSyntaxError = "501 Syntax Error" MessageNoSuchGroup = "411 No such newsgroup" ) diff --git a/internal/server/handler.go b/internal/server/handler.go index 7fb3260..2143567 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -25,6 +25,7 @@ func NewHandler(b backend.StorageBackend) *Handler { protocol.CommandList: h.handleList, protocol.CommandMode: h.handleModeReader, protocol.CommandGroup: h.handleGroup, + protocol.CommandNewGroups: h.handleNewGroups, } return h } @@ -157,19 +158,20 @@ func (h *Handler) handleGroup(s *Session, arguments []string, id uint) error { if err != nil { if err == sql.ErrNoRows { return s.tconn.PrintfLine(protocol.MessageNoSuchGroup) + } else { + return err } - return err } highWaterMark, err := h.backend.GetGroupHighWaterMark(g) - if err != nil { + if err != nil && err != sql.ErrNoRows { return err } lowWaterMark, err := h.backend.GetGroupLowWaterMark(g) - if err != nil { + if err != nil && err != sql.ErrNoRows { return err } articlesCount, err := h.backend.GetArticlesCount(g) - if err != nil { + if err != nil && err != sql.ErrNoRows { return err } @@ -178,6 +180,70 @@ func (h *Handler) handleGroup(s *Session, arguments []string, id uint) error { return s.tconn.PrintfLine("211 %d %d %d %s", articlesCount, lowWaterMark, highWaterMark, g.GroupName) } +func (h *Handler) handleNewGroups(s *Session, arguments []string, id uint) error { + s.tconn.StartResponse(id) + defer s.tconn.EndResponse(id) + + if len(arguments) < 2 || len(arguments) > 3 { + return s.tconn.PrintfLine(protocol.MessageSyntaxError) + } + + dateString := arguments[0] + " " + arguments[1] + //isGMT := false + //if len(arguments) == 3 { + // isGMT = true + //} + + var date time.Time + + var err error + if len(dateString) == 15 { + date, err = time.Parse("20060102 150405", dateString) + if err != nil { + return err + } + } else if len(dateString) == 13 { + date, err = time.Parse("060102 150405", dateString) + if err != nil { + return err + } + } else { + return s.tconn.PrintfLine(protocol.MessageSyntaxError) + } + + g, err := h.backend.GetNewGroupsSince(date.Unix()) + if err != nil { + return err + } + + var sb strings.Builder + + sb.Write([]byte(protocol.MessageListOfNewsgroupsFollows + protocol.CRLF)) + for _, v := range g { + // TODO set actual post permission status + c, err := h.backend.GetArticlesCount(v) + if err != nil { + return err + } + if c > 0 { + highWaterMark, err := h.backend.GetGroupHighWaterMark(v) + if err != nil { + return err + } + lowWaterMark, err := h.backend.GetGroupLowWaterMark(v) + if err != nil { + return err + } + sb.Write([]byte(fmt.Sprintf("%s %d %d n"+protocol.CRLF, v.GroupName, highWaterMark, lowWaterMark))) + } else { + sb.Write([]byte(fmt.Sprintf("%s 0 1 n"+protocol.CRLF, v.GroupName))) + } + } + sb.Write([]byte(protocol.MultilineEnding)) + + return s.tconn.PrintfLine(sb.String()) +} + func (h *Handler) Handle(s *Session, message string, id uint) error { splittedMessage := strings.Split(message, " ") for i, v := range splittedMessage {