Implement LAST command

This commit is contained in:
ChronosX88 2022-02-05 19:19:43 +03:00
parent 1197ded1aa
commit 679c515ad1
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
5 changed files with 51 additions and 1 deletions

View File

@ -36,7 +36,7 @@
- :construction: Group and Article Selection
- :heavy_check_mark: `GROUP`
- :heavy_check_mark: `LISTGROUP`
- :x: `LAST`
- :heavy_check_mark: `LAST`
- :x: `NEXT`
- :construction: The LIST Commands
- :heavy_check_mark: `LIST ACTIVE`

View File

@ -173,6 +173,17 @@ func (sb *SQLiteBackend) GetArticleNumbers(g *models.Group, low, high int64) ([]
return numbers, nil
}
func (sb *SQLiteBackend) GetLastArticleByNum(g *models.Group, a *models.Article) (models.Article, error) {
var lastArticle models.Article
if err := sb.db.Get(&lastArticle, "SELECT articles.* FROM articles INNER JOIN articles_to_groups atg on atg.article_id = articles.id WHERE atg.article_number < ? AND atg.group_id = ? LIMIT 1", a.ArticleNumber, g.ID); err != nil {
return lastArticle, err
}
if err := sb.db.Get(&a.ArticleNumber, "SELECT article_number FROM articles_to_groups WHERE article_id = ?", a.ID); err != nil {
return lastArticle, err
}
return lastArticle, json.Unmarshal([]byte(a.HeaderRaw), &a.Header)
}
func (sb *SQLiteBackend) GetNewArticlesSince(timestamp int64) ([]string, error) {
var articleIds []string
return articleIds, sb.db.Select(&articleIds, "SELECT json_extract(articles.header, '$.Message-Id[0]') FROM articles WHERE created_at > datetime(?, 'unixepoch')", timestamp)

View File

@ -19,4 +19,5 @@ type StorageBackend interface {
GetArticleByNumber(g *models.Group, num int) (models.Article, error)
GetArticleNumbers(g *models.Group, low, high int64) ([]int64, error)
GetNewArticlesSince(timestamp int64) ([]string, error)
GetLastArticleByNum(g *models.Group, a *models.Article) (models.Article, error)
}

View File

@ -62,6 +62,7 @@ const (
CommandStat = "STAT"
CommandHelp = "HELP"
CommandNewNews = "NEWNEWS"
CommandLast = "LAST"
)
const (

View File

@ -42,6 +42,7 @@ func NewHandler(b backend.StorageBackend, serverDomain string) *Handler {
protocol.CommandStat: h.handleArticle,
protocol.CommandHelp: h.handleHelp,
protocol.CommandNewNews: h.handleNewNews,
protocol.CommandLast: h.handleLast,
}
h.serverDomain = serverDomain
return h
@ -626,6 +627,42 @@ func (h *Handler) handleNewNews(s *Session, command string, arguments []string,
return dw.Close()
}
func (h *Handler) handleLast(s *Session, command string, arguments []string, id uint) error {
s.tconn.StartResponse(id)
defer s.tconn.EndResponse(id)
if len(arguments) != 0 {
return s.tconn.PrintfLine(protocol.ErrSyntaxError.String())
}
if s.currentGroup == nil {
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 412, Message: "no newsgroup selected"}.String())
}
if s.currentArticle == nil {
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 420, Message: "No current article selected"}.String())
}
low, err := h.backend.GetGroupLowWaterMark(s.currentGroup)
if err != nil {
return err
}
if s.currentArticle.ArticleNumber == low {
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 422, Message: "No previous article to retrieve"}.String())
}
a, err := h.backend.GetLastArticleByNum(s.currentGroup, s.currentArticle)
if err != nil {
if err == sql.ErrNoRows {
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 422, Message: "No previous article to retrieve"}.String())
}
return err
}
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 223, Message: fmt.Sprintf("%d %s retrieved", a.ArticleNumber, a.Header.Get("Message-ID"))}.String())
}
func (h *Handler) Handle(s *Session, message string, id uint) error {
splittedMessage := strings.Split(message, " ")
for i, v := range splittedMessage {