github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/microblog/microblog.gno (about) 1 package microblog 2 3 import ( 4 "errors" 5 "sort" 6 "std" 7 "strings" 8 "time" 9 10 "gno.land/p/demo/avl" 11 "gno.land/p/demo/ufmt" 12 ) 13 14 var ( 15 ErrNotFound = errors.New("not found") 16 StatusNotFound = "404" 17 ) 18 19 type Microblog struct { 20 Title string 21 Prefix string // i.e. r/gnoland/blog: 22 Pages avl.Tree // author (string) -> Page 23 } 24 25 func NewMicroblog(title string, prefix string) (m *Microblog) { 26 return &Microblog{ 27 Title: title, 28 Prefix: prefix, 29 Pages: avl.Tree{}, 30 } 31 } 32 33 func (m *Microblog) GetPages() []*Page { 34 var ( 35 pages = make([]*Page, m.Pages.Size()) 36 index = 0 37 ) 38 39 m.Pages.Iterate("", "", func(key string, value interface{}) bool { 40 pages[index] = value.(*Page) 41 index++ 42 return false 43 }) 44 45 sort.Sort(byLastPosted(pages)) 46 47 return pages 48 } 49 50 func (m *Microblog) NewPost(text string) error { 51 author := std.GetOrigCaller() 52 _, found := m.Pages.Get(author.String()) 53 if !found { 54 // make a new page for the new author 55 m.Pages.Set(author.String(), &Page{ 56 Author: author, 57 CreatedAt: time.Now(), 58 }) 59 } 60 61 page, err := m.GetPage(author.String()) 62 if err != nil { 63 return err 64 } 65 return page.NewPost(text) 66 } 67 68 func (m *Microblog) GetPage(author string) (*Page, error) { 69 silo, found := m.Pages.Get(author) 70 if !found { 71 return nil, ErrNotFound 72 } 73 return silo.(*Page), nil 74 } 75 76 type Page struct { 77 ID int 78 Author std.Address 79 CreatedAt time.Time 80 LastPosted time.Time 81 Posts avl.Tree // time -> Post 82 } 83 84 // byLastPosted implements sort.Interface for []Page based on 85 // the LastPosted field. 86 type byLastPosted []*Page 87 88 func (a byLastPosted) Len() int { return len(a) } 89 func (a byLastPosted) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 90 func (a byLastPosted) Less(i, j int) bool { return a[i].LastPosted.After(a[j].LastPosted) } 91 92 func (p *Page) NewPost(text string) error { 93 now := time.Now() 94 p.LastPosted = now 95 p.Posts.Set(ufmt.Sprintf("%s%d", now.Format(time.RFC3339), p.Posts.Size()), &Post{ 96 ID: p.Posts.Size(), 97 Text: text, 98 CreatedAt: now, 99 }) 100 return nil 101 } 102 103 func (p *Page) GetPosts() []*Post { 104 posts := make([]*Post, p.Posts.Size()) 105 i := 0 106 p.Posts.ReverseIterate("", "", func(key string, value interface{}) bool { 107 postParsed := value.(*Post) 108 posts[i] = postParsed 109 i++ 110 return false 111 }) 112 return posts 113 } 114 115 // Post lists the specific update 116 type Post struct { 117 ID int 118 CreatedAt time.Time 119 Text string 120 } 121 122 func (p *Post) String() string { 123 return "> " + strings.ReplaceAll(p.Text, "\n", "\n>\n>") + "\n>\n> *" + p.CreatedAt.Format(time.RFC1123) + "*" 124 }