10 type ThreadedNews struct {
11 Categories map[string]NewsCategoryListData15 `yaml:"Categories"`
14 type NewsCategoryListData15 struct {
15 Type []byte `yaml:"Type"` // Size 2 ; Bundle (2) or category (3)
16 Count []byte // Article or SubCategory count Size 2
18 Name string `yaml:"Name"` //
19 Articles map[uint32]*NewsArtData `yaml:"Articles"` // Optional, if Type is Category
20 SubCats map[string]NewsCategoryListData15 `yaml:"SubCats"`
21 GUID []byte // Size 16
22 AddSN []byte // Size 4
23 DeleteSN []byte // Size 4
26 func (newscat *NewsCategoryListData15) GetNewsArtListData() NewsArtListData {
27 var newsArts []NewsArtList
28 var newsArtsPayload []byte
30 for i, art := range newscat.Articles {
32 binary.BigEndian.PutUint32(ID, i)
34 newArt := NewsArtList{
37 ParentID: art.ParentArt,
38 Flags: []byte{0, 0, 0, 0},
39 FlavorCount: []byte{0, 0},
40 Title: []byte(art.Title),
41 Poster: []byte(art.Poster),
42 ArticleSize: art.DataSize(),
44 newsArts = append(newsArts, newArt)
47 sort.Sort(byID(newsArts))
49 for _, v := range newsArts {
50 newsArtsPayload = append(newsArtsPayload, v.Payload()...)
53 nald := NewsArtListData{
54 ID: []byte{0, 0, 0, 0},
56 Description: []byte{},
57 NewsArtList: newsArtsPayload,
63 // NewsArtData represents single news article
64 type NewsArtData struct {
65 Title string `yaml:"Title"`
66 Poster string `yaml:"Poster"`
67 Date []byte `yaml:"Date"` // size 8
68 PrevArt []byte `yaml:"PrevArt"` // size 4
69 NextArt []byte `yaml:"NextArt"` // size 4
70 ParentArt []byte `yaml:"ParentArt"` // size 4
71 FirstChildArt []byte `yaml:"FirstChildArtArt"` // size 4
72 DataFlav []byte `yaml:"DataFlav"` // "text/plain"
73 Data string `yaml:"Data"`
76 func (art *NewsArtData) DataSize() []byte {
77 dataLen := make([]byte, 2)
78 binary.BigEndian.PutUint16(dataLen, uint16(len(art.Data)))
83 type NewsArtListData struct {
84 ID []byte `yaml:"ID"` // Size 4
85 Name []byte `yaml:"Name"`
86 Description []byte `yaml:"Description"` // not used?
87 NewsArtList []byte // List of articles Optional (if article count > 0)
90 func (nald *NewsArtListData) Payload() []byte {
91 count := make([]byte, 4)
92 binary.BigEndian.PutUint32(count, uint32(len(nald.NewsArtList)))
94 out := append(nald.ID, count...)
95 out = append(out, []byte{uint8(len(nald.Name))}...)
96 out = append(out, nald.Name...)
97 out = append(out, []byte{uint8(len(nald.Description))}...)
98 out = append(out, nald.Description...)
99 out = append(out, nald.NewsArtList...)
104 // NewsArtList is a summarized version of a NewArtData record for display in list view
105 type NewsArtList struct {
107 TimeStamp []byte // Year (2 bytes), milliseconds (2 bytes) and seconds (4 bytes)
108 ParentID []byte // Size 4
109 Flags []byte // Size 4
110 FlavorCount []byte // Size 2
112 Title []byte // string
114 // Poster Poster string
116 FlavorList []NewsFlavorList
117 // Flavor list… Optional (if flavor count > 0)
118 ArticleSize []byte // Size 2
121 type byID []NewsArtList
123 func (s byID) Len() int {
126 func (s byID) Swap(i, j int) {
127 s[i], s[j] = s[j], s[i]
129 func (s byID) Less(i, j int) bool {
130 return binary.BigEndian.Uint32(s[i].ID) < binary.BigEndian.Uint32(s[j].ID)
133 func (nal *NewsArtList) Payload() []byte {
134 out := append(nal.ID, nal.TimeStamp...)
135 out = append(out, nal.ParentID...)
136 out = append(out, nal.Flags...)
138 out = append(out, []byte{0, 1}...)
140 out = append(out, []byte{uint8(len(nal.Title))}...)
141 out = append(out, nal.Title...)
142 out = append(out, []byte{uint8(len(nal.Poster))}...)
143 out = append(out, nal.Poster...)
144 out = append(out, []byte{0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e}...) // TODO: wat?
145 out = append(out, nal.ArticleSize...)
150 type NewsFlavorList struct {
152 // Flavor text size MIME type string
156 func (newscat *NewsCategoryListData15) MarshalBinary() (data []byte, err error) {
157 count := make([]byte, 2)
158 binary.BigEndian.PutUint16(count, uint16(len(newscat.Articles)+len(newscat.SubCats)))
160 out := append(newscat.Type, count...)
162 if bytes.Equal(newscat.Type, []byte{0, 3}) {
163 // Generate a random GUID // TODO: does this need to be random?
164 b := make([]byte, 16)
165 _, err := rand.Read(b)
170 out = append(out, b...) // GUID
171 out = append(out, []byte{0, 0, 0, 1}...) // Add SN (TODO: not sure what this is)
172 out = append(out, []byte{0, 0, 0, 2}...) // Delete SN (TODO: not sure what this is)
175 out = append(out, newscat.nameLen()...)
176 out = append(out, []byte(newscat.Name)...)
181 // ReadNewsCategoryListData parses a byte slice into a NewsCategoryListData15 struct
182 // For use on the client side
183 func ReadNewsCategoryListData(payload []byte) NewsCategoryListData15 {
184 ncld := NewsCategoryListData15{
189 if bytes.Equal(ncld.Type, []byte{0, 3}) {
190 ncld.GUID = payload[4:20]
191 ncld.AddSN = payload[20:24]
192 ncld.AddSN = payload[24:28]
193 ncld.Name = string(payload[29:])
195 ncld.Name = string(payload[5:])
201 func (newscat *NewsCategoryListData15) nameLen() []byte {
202 return []byte{uint8(len(newscat.Name))}
205 // TODO: re-implement as bufio.Scanner interface
206 func ReadNewsPath(newsPath []byte) []string {
207 if len(newsPath) == 0 {
210 pathCount := binary.BigEndian.Uint16(newsPath[0:2])
212 pathData := newsPath[2:]
215 for i := uint16(0); i < pathCount; i++ {
216 pathLen := pathData[2]
217 paths = append(paths, string(pathData[3:3+pathLen]))
219 pathData = pathData[pathLen+3:]
225 func (s *Server) GetNewsCatByPath(paths []string) map[string]NewsCategoryListData15 {
226 cats := s.ThreadedNews.Categories
227 for _, path := range paths {
228 cats = cats[path].SubCats