]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/news.go
Convert more bespoke methods to io.Reader/io.Writer interfaces
[rbdr/mobius] / hotline / news.go
index a9e5d723277281c819c4c8830fe53dd763184674..8e13a297ab212c114bdf79d3a4b2536b2e929e6f 100644 (file)
@@ -4,24 +4,33 @@ import (
        "bytes"
        "crypto/rand"
        "encoding/binary"
-       "log"
+       "io"
+       "slices"
        "sort"
-       "time"
 )
 
+const defaultNewsDateFormat = "Jan02 15:04" // Jun23 20:49
+
+const defaultNewsTemplate = `From %s (%s):
+
+%s
+
+__________________________________________________________`
+
 type ThreadedNews struct {
        Categories map[string]NewsCategoryListData15 `yaml:"Categories"`
 }
 
 type NewsCategoryListData15 struct {
-       Type     []byte                            `yaml:"Type"`     //Size 2 ; Bundle (2) or category (3)
+       Type     [2]byte `yaml:"Type"` // Size 2 ; Bundle (2) or category (3)
+       Count    []byte  // Article or SubCategory count Size 2
+       NameSize byte
        Name     string                            `yaml:"Name"`     //
        Articles map[uint32]*NewsArtData           `yaml:"Articles"` // Optional, if Type is Category
        SubCats  map[string]NewsCategoryListData15 `yaml:"SubCats"`
-       Count    []byte                            // Article or SubCategory count Size 2
+       GUID     []byte                            // Size 16
        AddSN    []byte                            // Size 4
        DeleteSN []byte                            // Size 4
-       GUID     []byte                            // Size 16
 }
 
 func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData {
@@ -29,11 +38,11 @@ func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData {
        var newsArtsPayload []byte
 
        for i, art := range newscat.Articles {
-               ID := make([]byte, 4)
-               binary.BigEndian.PutUint32(ID, i)
+               id := make([]byte, 4)
+               binary.BigEndian.PutUint32(id, i)
 
                newArt := NewsArtList{
-                       ID:          ID,
+                       ID:          id,
                        TimeStamp:   art.Date,
                        ParentID:    art.ParentArt,
                        Flags:       []byte{0, 0, 0, 0},
@@ -52,7 +61,8 @@ func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData {
        }
 
        nald := NewsArtListData{
-               ID:          []byte{0, 0, 0, 0},
+               ID:          [4]byte{0, 0, 0, 0},
+               Count:       len(newsArts),
                Name:        []byte{},
                Description: []byte{},
                NewsArtList: newsArtsPayload,
@@ -61,15 +71,15 @@ func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData {
        return nald
 }
 
-// NewsArtData repsents a single news article
+// NewsArtData represents single news article
 type NewsArtData struct {
        Title         string `yaml:"Title"`
        Poster        string `yaml:"Poster"`
-       Date          []byte `yaml:"Date"`             //size 8
-       PrevArt       []byte `yaml:"PrevArt"`          //size 4
-       NextArt       []byte `yaml:"NextArt"`          //size 4
-       ParentArt     []byte `yaml:"ParentArt"`        //size 4
-       FirstChildArt []byte `yaml:"FirstChildArtArt"` //size 4
+       Date          []byte `yaml:"Date"`             // size 8
+       PrevArt       []byte `yaml:"PrevArt"`          // size 4
+       NextArt       []byte `yaml:"NextArt"`          // size 4
+       ParentArt     []byte `yaml:"ParentArt"`        // size 4
+       FirstChildArt []byte `yaml:"FirstChildArtArt"` // size 4
        DataFlav      []byte `yaml:"DataFlav"`         // "text/plain"
        Data          string `yaml:"Data"`
 }
@@ -82,27 +92,33 @@ func (art *NewsArtData) DataSize() []byte {
 }
 
 type NewsArtListData struct {
-       ID          []byte `yaml:"ID"` // Size 4
-       Name        []byte `yaml:"Name"`
-       Description []byte `yaml:"Description"` // not used?
-       NewsArtList []byte // List of articles                  Optional (if article count > 0)
+       ID          [4]byte `yaml:"ID"` // Size 4
+       Name        []byte  `yaml:"Name"`
+       Description []byte  `yaml:"Description"` // not used?
+       NewsArtList []byte  // List of articles                 Optional (if article count > 0)
+       Count       int
 }
 
-func (nald *NewsArtListData) Payload() []byte {
+func (nald *NewsArtListData) Read(p []byte) (int, error) {
        count := make([]byte, 4)
-       binary.BigEndian.PutUint32(count, uint32(len(nald.NewsArtList)))
-
-       out := append(nald.ID, count...)
-       out = append(out, []byte{uint8(len(nald.Name))}...)
-       out = append(out, nald.Name...)
-       out = append(out, []byte{uint8(len(nald.Description))}...)
-       out = append(out, nald.Description...)
-       out = append(out, nald.NewsArtList...)
-
-       return out
-}
-
-// NewsArtList is a summarized ver sion of a NewArtData record for display in list view
+       binary.BigEndian.PutUint32(count, uint32(nald.Count))
+
+       return copy(
+                       p,
+                       slices.Concat(
+                               nald.ID[:],
+                               count,
+                               []byte{uint8(len(nald.Name))},
+                               nald.Name,
+                               []byte{uint8(len(nald.Description))},
+                               nald.Description,
+                               nald.NewsArtList,
+                       ),
+               ),
+               io.EOF
+}
+
+// NewsArtList is a summarized version of a NewArtData record for display in list view
 type NewsArtList struct {
        ID          []byte // Size 4
        TimeStamp   []byte // Year (2 bytes), milliseconds (2 bytes) and seconds (4 bytes)
@@ -154,18 +170,18 @@ type NewsFlavorList struct {
        // Article size 2
 }
 
-func (newscat *NewsCategoryListData15) Payload() []byte {
+func (newscat *NewsCategoryListData15) MarshalBinary() (data []byte, err error) {
        count := make([]byte, 2)
        binary.BigEndian.PutUint16(count, uint16(len(newscat.Articles)+len(newscat.SubCats)))
 
-       out := append(newscat.Type, count...)
+       out := append(newscat.Type[:], count...)
 
-       if bytes.Equal(newscat.Type, []byte{0, 3}) {
-               // Generate a random GUID
+       if bytes.Equal(newscat.Type[:], []byte{0, 3}) {
+               // Generate a random GUID // TODO: does this need to be random?
                b := make([]byte, 16)
                _, err := rand.Read(b)
                if err != nil {
-                       log.Fatal(err)
+                       return data, err
                }
 
                out = append(out, b...)                  // GUID
@@ -176,54 +192,14 @@ func (newscat *NewsCategoryListData15) Payload() []byte {
        out = append(out, newscat.nameLen()...)
        out = append(out, []byte(newscat.Name)...)
 
-       return out
-}
-
-// ReadNewsCategoryListData parses a byte slice into a NewsCategoryListData15 struct
-// For use on the client side
-func ReadNewsCategoryListData(payload []byte) NewsCategoryListData15 {
-       ncld := NewsCategoryListData15{
-               Type:  payload[0:2],
-               Count: payload[2:4],
-       }
-
-       if bytes.Equal(ncld.Type, []byte{0, 3}) {
-               ncld.GUID = payload[4:20]
-               ncld.AddSN = payload[20:24]
-               ncld.AddSN = payload[24:28]
-               ncld.Name = string(payload[29:])
-       } else {
-               ncld.Name = string(payload[5:])
-       }
-
-       return ncld
+       return out, err
 }
 
 func (newscat *NewsCategoryListData15) nameLen() []byte {
        return []byte{uint8(len(newscat.Name))}
 }
 
-type NewsPath struct {
-       Paths []string
-}
-
-func (np *NewsPath) Payload() []byte {
-       var out []byte
-
-       count := make([]byte, 2)
-       binary.BigEndian.PutUint16(count, uint16(len(np.Paths)))
-
-       out = append(out, count...)
-       for _, p := range np.Paths {
-               pLen := byte(len(p))
-               out = append(out, []byte{0, 0}...) // what is this?
-               out = append(out, pLen)
-               out = append(out, []byte(p)...)
-       }
-
-       return out
-}
-
+// TODO: re-implement as bufio.Scanner interface
 func ReadNewsPath(newsPath []byte) []string {
        if len(newsPath) == 0 {
                return []string{}
@@ -250,25 +226,3 @@ func (s *Server) GetNewsCatByPath(paths []string) map[string]NewsCategoryListDat
        }
        return cats
 }
-
-// News article date field contains this structure:
-// Year                                        2
-// Milliseconds        2 (seriously?)
-// Seconds                     4
-func NewsDate() []byte {
-       t := time.Now()
-       ms := []byte{0, 0}
-       seconds := []byte{0, 0, 0, 0}
-
-       year := []byte{0, 0}
-       binary.BigEndian.PutUint16(year, uint16(t.Year()))
-
-       yearStart := time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, time.Local)
-
-       binary.BigEndian.PutUint32(seconds, uint32(t.Sub(yearStart).Seconds()))
-
-       date := append(year, ms...)
-       date = append(date, seconds...)
-
-       return date
-}