util.gno
3.70 Kb · 150 lines
1package social
2
3import (
4 "strconv"
5 "strings"
6
7 "gno.land/p/nt/avl/v0"
8 "gno.land/p/nt/ufmt/v0"
9 "gno.land/r/sys/users"
10)
11
12//----------------------------------------
13// private utility methods
14
15// Get the UserPosts for the user.
16func getUserPosts(userAddr address) *UserPosts {
17 userPosts, exists := gUserPostsByAddress.Get(userAddr.String())
18 if !exists {
19 return nil
20 }
21
22 return userPosts.(*UserPosts)
23}
24
25// Get the UserPosts for the userAddr. If not found, add a new UserPosts to
26// gUserPostsByAddress and update gUserAddressByName with the username.
27// (The caller usually has already called usernameOf to get the username, but if
28// it is "" then this will get it.)
29func getOrCreateUserPosts(userAddr address, username string) *UserPosts {
30 userPosts := getUserPosts(userAddr)
31 if userPosts != nil {
32 return userPosts
33 }
34
35 if username == "" {
36 username = usernameOf(userAddr)
37 }
38 if username == "" {
39 username = userAddr.String()
40 }
41
42 userPosts = newUserPosts(gRealmPath+":"+username, userAddr)
43 gUserPostsByAddress.Set(userAddr.String(), userPosts)
44 gUserAddressByName.Set(username, userAddr)
45
46 return userPosts
47}
48
49func padZero(u64 uint64, length int) string {
50 str := strconv.Itoa(int(u64))
51 if len(str) >= length {
52 return str
53 } else {
54 return strings.Repeat("0", length-len(str)) + str
55 }
56}
57
58func postIDKey(pid PostID) string {
59 return padZero(uint64(pid), 10)
60}
61
62func reactionKey(reaction Reaction) string {
63 return strconv.Itoa(int(reaction))
64}
65
66// If reactions has an value for the given reaction, then return it.
67// Otherwise, add the reaction key to reactions, set the value to an empty avl.Tree and return it.
68func getOrCreateReactionValue(reactions *avl.Tree, reaction Reaction) *avl.Tree {
69 key := reactionKey(reaction)
70 valueI, exists := reactions.Get(key)
71 if exists {
72 return valueI.(*avl.Tree)
73 } else {
74 value := avl.NewTree()
75 reactions.Set(key, value)
76 return value
77 }
78}
79
80// listByteStringKeysByPrefix returns up to maxResults keys from tree that start
81// with the given prefix, treating keys as byte strings (not Unicode runes).
82// Inlined from gno.land/p/jefft0/avlhelpers which is not yet deployed.
83func listByteStringKeysByPrefix(tree avl.ITree, prefix string, maxResults int) []string {
84 result := []string{}
85 end := ""
86 n := len(prefix)
87 for n > 0 {
88 if ascii := int(prefix[n-1]); ascii < 0xff {
89 end = prefix[0:n-1] + string(ascii+1)
90 break
91 }
92 n--
93 }
94 tree.Iterate(prefix, end, func(key string, value any) bool {
95 result = append(result, key)
96 return len(result) >= maxResults
97 })
98 return result
99}
100
101func indentBody(indent string, body string) string {
102 lines := strings.Split(body, "\n")
103 res := ""
104 for i, line := range lines {
105 if i > 0 {
106 res += "\n"
107 }
108 res += indent + line
109 }
110 return res
111}
112
113// NOTE: length must be greater than 3.
114func summaryOf(str string, length int) string {
115 lines := strings.SplitN(str, "\n", 2)
116 line := lines[0]
117 if len(line) > length {
118 line = line[:(length-3)] + "..."
119 } else if len(lines) > 1 {
120 // len(line) <= 80
121 line = line + "..."
122 }
123 return line
124}
125
126func displayAddressMD(addr address) string {
127 user := users.ResolveAddress(addr)
128 if user == nil {
129 return "[" + addr.String() + "](/r/gnoland/users/v1:" + addr.String() + ")"
130 } else {
131 return "[@" + user.Name() + "](" + gRealmPath + ":" + user.Name() + ")"
132 }
133}
134
135func usernameOf(addr address) string {
136 user := users.ResolveAddress(addr)
137 if user == nil {
138 return ""
139 } else {
140 return user.Name()
141 }
142}
143
144// Return the User info as a JSON string.
145// (This is a temporary utility until gno.land supports returning structured data directly.)
146func marshalJsonUser(user *users.UserData) string {
147 return ufmt.Sprintf(
148 "{\"address\": \"%s\", \"name\": \"%s\", \"deleted\": %t}",
149 user.Addr().String(), user.Name(), user.IsDeleted())
150}