backend for xcvr appview

i wanna see what breaks

+4 -3
lexicons/org/xcvr/notes.lex
··· 54 54 title: string, bytes<=640, chars<=64 55 55 topic?: string, bytes<=2560, chars<=256 56 56 createdAt: string 57 - host: handle 57 + host: did 58 58 59 59 sub: record 60 60 channelUri: uri 61 61 62 62 channelView?: def 63 63 uri: uri 64 - host: handle 64 + host: did 65 65 creator: org.xcvr.actor.profileView 66 66 title: string, bytes<=640, chars<=64 67 67 topic?: string, bytes<=2560, chars<=256 ··· 88 88 signet: record 89 89 channelURI: uri 90 90 lrcID: int, [0 4294967295] 91 - author: string 91 + author: did 92 + authorHandle?: string 92 93 startedAt?: date 93 94 94 95 media: record
+3
migrations/007_addauthor.down.sql
··· 1 + UPDATE signets SET author_handle = '' WHERE author_handle IS NULL; 2 + ALTER TABLE signets ALTER COLUMN author_handle SET NOT NULL; 3 + ALTER TABLE signets DROP COLUMN author;
+2
migrations/007_addauthor.up.sql
··· 1 + ALTER TABLE signets ADD COLUMN author TEXT NOT NULL; 2 + ALTER TABLE signets ALTER COLUMN author_handle DROP NOT NULL;
+1
migrations/008_updatexcvrdid.down.sql
··· 1 + UPDATE did_handles SET did = 'did:plc:mqt7hthieqzpa3mwqwggbqei' WHERE handle = 'xcvr.org';
+1
migrations/008_updatexcvrdid.up.sql
··· 1 + UPDATE did_handles SET did = 'did:web:xcvr.org' WHERE handle = 'xcvr.org';
+2 -2
server/go.mod
··· 10 10 github.com/ipfs/go-cid v0.4.1 11 11 github.com/jackc/pgx/v5 v5.7.4 12 12 github.com/joho/godotenv v1.5.1 13 - github.com/rachel-mp4/lrcd v0.1.1 14 - github.com/rachel-mp4/lrcproto v1.2.0 13 + github.com/rachel-mp4/lrcd v0.2.3 14 + github.com/rachel-mp4/lrcproto v1.2.1 15 15 github.com/rivo/uniseg v0.4.7 16 16 github.com/whyrusleeping/cbor-gen v0.3.1 17 17 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
+6 -14
server/go.sum
··· 24 24 github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= 25 25 github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 26 26 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 27 - github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 28 - github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 27 + github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 28 + github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 29 29 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 30 30 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 31 31 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= ··· 117 117 github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= 118 118 github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 119 119 github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 120 - github.com/rachel-mp4/lrcd v0.0.1 h1:9d5if0HJ/+TLKdupd7Zu9dISA5fF3QRtI/yr+gYVqXM= 121 - github.com/rachel-mp4/lrcd v0.0.1/go.mod h1:aWUVglSyrLf2RGpQdqTucX498b434yWBFJkD6Yzr0OE= 122 - github.com/rachel-mp4/lrcd v0.1.0 h1:iW3ux8otqo+9tYpP2Bsxu5VgbhP324Mjy0vOBf3M39Q= 123 - github.com/rachel-mp4/lrcd v0.1.0/go.mod h1:CyBPWmy94oQ0sTOj24VJjxWoZ9zSnqCKQ/qlR+vhtVE= 124 - github.com/rachel-mp4/lrcd v0.1.1 h1:2AXK61+pnL71ZqINLnxNfKqX/F0hUw+REFbBFZOjJcY= 125 - github.com/rachel-mp4/lrcd v0.1.1/go.mod h1:CyBPWmy94oQ0sTOj24VJjxWoZ9zSnqCKQ/qlR+vhtVE= 126 - github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c h1:t33xVlfSwvB80nj1jroRXUaq/RTgjWwD4l7p/ISatUQ= 127 - github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 128 - github.com/rachel-mp4/lrcproto v1.2.0 h1:nZI80WQKO6yKgX0O5H6OO1cM/tiJqugs0p52KCoIDOw= 129 - github.com/rachel-mp4/lrcproto v1.2.0/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 120 + github.com/rachel-mp4/lrcd v0.2.3 h1:HT3UjFn2ZK2zpFkS8U7KU1+I9kMA/oBF2FVWd7x0TkM= 121 + github.com/rachel-mp4/lrcd v0.2.3/go.mod h1:CyBPWmy94oQ0sTOj24VJjxWoZ9zSnqCKQ/qlR+vhtVE= 122 + github.com/rachel-mp4/lrcproto v1.2.1 h1:oKP/4u8JaRzV9vY/BUn24VTrsN7pgty0S4AP8hWc/JI= 123 + github.com/rachel-mp4/lrcproto v1.2.1/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 130 124 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 131 125 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 132 126 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= ··· 170 164 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 171 165 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= 172 166 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 173 - google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= 174 - google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 175 167 google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= 176 168 google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 177 169 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+196 -1
server/internal/db/db.go
··· 6 6 "fmt" 7 7 "os" 8 8 "rvcx/internal/atputils" 9 + "rvcx/internal/lex" 9 10 "rvcx/internal/types" 10 11 "time" 11 12 ··· 55 56 return did, nil 56 57 } 57 58 59 + func (s *Store) FullResolveHandle(hdl string, ctx context.Context) (string, error) { 60 + did, err := s.ResolveHandle(hdl, ctx) 61 + if err == nil { 62 + return did, nil 63 + } 64 + did, err = atputils.TryLookupHandle(ctx, hdl) 65 + if err != nil { 66 + return "", errors.New("couldn't resolve: " + err.Error()) 67 + } 68 + s.StoreDidHandle(did, hdl, ctx) 69 + return did, nil 70 + } 71 + 58 72 func (s *Store) ResolveDid(did string, ctx context.Context) (string, error) { 59 73 row := s.pool.QueryRow(ctx, `SELECT h.handle FROM did_handles h WHERE h.did = $1`, did) 60 74 var handle string ··· 101 115 return 102 116 } 103 117 118 + func (s *Store) GetHistory(channelURI string, limit int, cursor *int, ctx context.Context) ([]types.SignedItemView, error) { 119 + queryFmt := ` 120 + SELECT 121 + 'message' AS content_type, 122 + m.uri, 123 + m.did, 124 + dh.handle, 125 + p.display_name, 126 + p.status, 127 + p.color, 128 + p.avatar_cid, 129 + p.default_nick, 130 + m.body, 131 + NULL AS blob_cid, 132 + NULL AS blob_mime, 133 + NULL AS alt, 134 + NULL AS height, 135 + NULL AS width, 136 + m.nick, 137 + m.color, 138 + s.uri, 139 + s.issuer_did, 140 + s.channel_uri, 141 + s.message_id, 142 + s.author, 143 + s.author_handle, 144 + s.started_at, 145 + m.posted_at 146 + FROM signets s 147 + JOIN messages m ON s.uri = m.signet_uri 148 + JOIN did_handles dh ON m.did = dh.did 149 + JOIN profiles p ON m.did = p.did 150 + WHERE s.channel_uri = $2 AND m.did = s.author %s 151 + 152 + UNION ALL 153 + 154 + SELECT 155 + 'image' AS content_type, 156 + i.uri, 157 + i.did, 158 + dh.handle, 159 + p.display_name, 160 + p.status, 161 + p.color, 162 + p.avatar_cid, 163 + p.default_nick, 164 + NULL AS body, 165 + i.blob_cid, 166 + i.blob_mime, 167 + i.alt, 168 + i.height, 169 + i.width, 170 + i.nick, 171 + i.color, 172 + s.uri, 173 + s.issuer_did, 174 + s.channel_uri, 175 + s.message_id, 176 + s.author, 177 + s.author_handle, 178 + s.started_at, 179 + i.posted_at 180 + FROM signets s 181 + JOIN images i ON s.uri = i.signet_uri 182 + JOIN did_handles dh ON i.did = dh.did 183 + JOIN profiles p ON i.did = p.did 184 + WHERE s.channel_uri = $2 AND i.did = s.author %s 185 + 186 + ORDER BY message_id DESC 187 + LIMIT $1 188 + ` 189 + var query string 190 + if cursor != nil { 191 + query = fmt.Sprintf(queryFmt, "AND s.message_id < $3", "AND s.message_id < $3") 192 + return s.evalGetItems(query, ctx, limit, *cursor) 193 + } else { 194 + query = fmt.Sprintf(queryFmt, "", "") 195 + return s.evalGetItems(query, ctx, limit) 196 + } 197 + } 198 + func (s *Store) evalGetItems(query string, ctx context.Context, limit int, params ...any) ([]types.SignedItemView, error) { 199 + args := []any{limit} 200 + args = append(args, params...) 201 + rows, err := s.pool.Query(ctx, query, args...) 202 + if err != nil { 203 + return nil, err 204 + } 205 + defer rows.Close() 206 + var items = make([]types.SignedItemView, 0) 207 + for rows.Next() { 208 + var t string 209 + var p types.ProfileView 210 + var uri string 211 + var body string 212 + var image types.Image 213 + var nick string 214 + var color uint32 215 + var s types.SignetView 216 + var time time.Time 217 + 218 + err := rows.Scan( 219 + &t, 220 + &uri, 221 + &p.DID, 222 + &p.Handle, 223 + &p.DisplayName, 224 + &p.Status, 225 + &p.Color, 226 + &p.Avatar, 227 + &p.DefaultNick, 228 + &body, 229 + &image.BlobCID, 230 + &image.BlobMIME, 231 + &image.Alt, 232 + &image.Height, 233 + &image.Width, 234 + 235 + &nick, 236 + &color, 237 + 238 + &s.URI, 239 + &s.Issuer, 240 + &s.ChannelURI, 241 + &s.LrcId, 242 + &s.Author, 243 + &s.AuthorHandle, 244 + &s.StartedAt, 245 + &time, 246 + ) 247 + if err != nil { 248 + return nil, err 249 + } 250 + if t == "message" { 251 + var msg types.SignedMessageView 252 + msg.Body = body 253 + if nick != "" { 254 + msg.Nick = &nick 255 + } 256 + if color != 0 { 257 + msg.Color = &color 258 + } 259 + msg.Author = p 260 + msg.Signet = s 261 + msg.PostedAt = time 262 + msg.URI = uri 263 + 264 + items = append(items, msg) 265 + } else if t == "image" { 266 + var img types.SignedMediaView 267 + var imgview types.ImageView 268 + if image.Height != nil && image.Width != nil { 269 + var aspect lex.AspectRatio 270 + aspect.Width = *image.Width 271 + aspect.Height = *image.Height 272 + imgview.AspectRatio = &aspect 273 + } 274 + imgview.Alt = image.Alt 275 + base := os.Getenv("MY_IDENTITY") 276 + src := fmt.Sprintf("https://%s/xrpc/org.xcvr.lrc.getImage?uri=%s", base, uri) 277 + imgview.Src = &src 278 + img.Image = &imgview 279 + if nick != "" { 280 + img.Nick = &nick 281 + } 282 + if color != 0 { 283 + img.Color = &color 284 + } 285 + img.Author = p 286 + img.Signet = s 287 + img.PostedAt = time 288 + img.URI = uri 289 + 290 + items = append(items, img) 291 + } else { 292 + return nil, errors.New("recieved strange type t: " + t) 293 + } 294 + } 295 + return items, nil 296 + 297 + } 298 + 104 299 func (s *Store) GetMessages(channelURI string, limit int, cursor *int, ctx context.Context) ([]types.SignedMessageView, error) { 105 300 queryFmt := ` 106 301 SELECT ··· 168 363 &msg.Color, 169 364 170 365 &msg.Signet.URI, 171 - &msg.Signet.IssuerHandle, 366 + &msg.Signet.Issuer, 172 367 &msg.Signet.ChannelURI, 173 368 &msg.Signet.LrcId, 174 369 &msg.Signet.AuthorHandle,
+18 -5
server/internal/db/lexicon.go
··· 220 220 return 221 221 } 222 222 223 + // QuerySignetHandle takes a uri an queries the appropriate signet's handle. 224 + // Deprecated: i should QuerySignetDid instead 223 225 func (s *Store) QuerySignetHandle(uri string, ctx context.Context) (string, error) { 224 226 row := s.pool.QueryRow(ctx, `SELECT s.author_handle FROM signets s WHERE s.uri = $1`, uri) 225 227 var handle string ··· 228 230 return "", errors.New("BOBOBOBOBOBOL " + err.Error()) 229 231 } 230 232 return handle, nil 233 + } 234 + func (s *Store) QuerySignetDid(uri string, ctx context.Context) (string, error) { 235 + row := s.pool.QueryRow(ctx, `SELECT s.author FROM signets s WHERE s.uri = $1`, uri) 236 + var did string 237 + err := row.Scan(&did) 238 + if err != nil { 239 + return "", errors.New("BOBOBOBOBOBOL " + err.Error()) 240 + } 241 + return did, nil 231 242 } 232 243 233 244 func (s *Store) QuerySignetChannelIdNum(uri string, ctx context.Context) (channelUri string, messageID uint32, err error) { ··· 254 265 INSERT INTO signets ( 255 266 uri, 256 267 issuer_did, 268 + author, 257 269 author_handle, 258 270 channel_uri, 259 271 message_id, 260 272 cid, 261 273 started_at 262 274 ) VALUES ( 263 - $1, $2, $3, $4, $5, $6, $7 275 + $1, $2, $3, $4, $5, $6, $7, $8 264 276 ) ON CONFLICT (uri) DO NOTHING 265 - `, signet.URI, signet.IssuerDID, signet.AuthorHandle, signet.ChannelURI, signet.MessageID, signet.CID, signet.StartedAt) 277 + `, signet.URI, signet.IssuerDID, signet.Author, signet.AuthorHandle, signet.ChannelURI, signet.MessageID, signet.CID, signet.StartedAt) 266 278 if err != nil { 267 279 err = errors.New("SOMETHING BAD HAPPENED: " + err.Error()) 268 280 return ··· 276 288 INSERT INTO signets ( 277 289 uri, 278 290 issuer_did, 279 - AuthorHandle, 291 + author, 292 + author_handle, 280 293 channel_uri, 281 294 message_id, 282 295 cid, 283 296 started_at 284 297 ) VALUES ( 285 - $1, $2, $3, $4, $5, $6, $7 298 + $1, $2, $3, $4, $5, $6, $7, $8 286 299 ) 287 - `, signet.URI, signet.IssuerDID, signet.AuthorHandle, signet.ChannelURI, signet.MessageID, signet.CID, signet.StartedAt) 300 + `, signet.URI, signet.IssuerDID, signet.Author, signet.AuthorHandle, signet.ChannelURI, signet.MessageID, signet.CID, signet.StartedAt) 288 301 if err != nil { 289 302 err = errors.New("SOMETHING BAD HAPPENED: " + err.Error()) 290 303 }
+1
server/internal/handler/handler.go
··· 42 42 mux.HandleFunc("GET /xrpc/org.xcvr.feed.getChannels", h.WithCORS(h.getChannels)) 43 43 mux.HandleFunc("GET /xrpc/org.xcvr.feed.getChannel", h.WithCORS(h.getChannel)) 44 44 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getMessages", h.WithCORS(h.getMessages)) 45 + mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getHistory", h.WithCORS(h.getHistory)) 45 46 mux.HandleFunc("GET /xrpc/org.xcvr.lrc.getImage", h.WithCORS(h.getImage)) 46 47 mux.HandleFunc("GET /xrpc/org.xcvr.actor.resolveChannel", h.WithCORS(h.resolveChannel)) 47 48 mux.HandleFunc("GET /xrpc/org.xcvr.actor.getProfileView", h.WithCORS(h.getProfileView))
+55
server/internal/handler/lexiconHandlers.go
··· 88 88 encoder.Encode(gmo) 89 89 } 90 90 91 + func (h *Handler) getHistory(w http.ResponseWriter, r *http.Request) { 92 + limitstr := r.URL.Query().Get("limit") 93 + limit := 50 94 + if limitstr != "" { 95 + l, err := strconv.Atoi(limitstr) 96 + if err == nil { 97 + limit = max(min(l, 100), 1) 98 + } 99 + } 100 + cursorstr := r.URL.Query().Get("cursor") 101 + var cursor *int 102 + if cursorstr != "" { 103 + c, err := strconv.Atoi(cursorstr) 104 + if err == nil { 105 + cursor = &c 106 + } 107 + } 108 + channelURI := r.URL.Query().Get("channelURI") 109 + items, err := h.db.GetHistory(channelURI, limit, cursor, r.Context()) 110 + if err != nil { 111 + h.serverError(w, errors.New("something went south: "+err.Error())) 112 + return 113 + } 114 + if len(items) != 0 { 115 + var signet types.SignetView 116 + smv := items[len(items)-1] 117 + if smv.IsMedia() { 118 + media, _ := smv.ToSignedMediaView() 119 + signet = media.Signet 120 + } else if smv.IsMessage() { 121 + message, _ := smv.ToSignedMessageView() 122 + signet = message.Signet 123 + } else { 124 + h.serverError(w, errors.New("last item is invalid Signed Item")) 125 + return 126 + } 127 + if int(signet.LrcId) > 2 { 128 + cursor := strconv.Itoa(int(signet.LrcId)) 129 + w.Header().Set("Content-Type", "application/json") 130 + jsitems, err := types.MarshalItems(items) 131 + if err != nil { 132 + h.serverError(w, err) 133 + } 134 + fmt.Fprintf(w, "{\"items\": %s, \"cursor\": %s}", jsitems, cursor) 135 + return 136 + } 137 + } 138 + w.Header().Set("Content-Type", "application/json") 139 + jsitems, err := types.MarshalItems(items) 140 + if err != nil { 141 + h.serverError(w, err) 142 + } 143 + fmt.Fprintf(w, "{\"items\": %s}", jsitems) 144 + } 145 + 91 146 func (h *Handler) resolveChannel(w http.ResponseWriter, r *http.Request) { 92 147 handle := r.URL.Query().Get("handle") 93 148 did := r.URL.Query().Get("did")
+77 -20
server/internal/lex/lexicons_cbor.go
··· 959 959 } 960 960 961 961 cw := cbg.NewCborWriter(w) 962 - fieldCount := 5 962 + fieldCount := 6 963 + 964 + if t.AuthorHandle == nil { 965 + fieldCount-- 966 + } 963 967 964 968 if t.StartedAt == nil { 965 969 fieldCount-- ··· 1004 1008 return err 1005 1009 } 1006 1010 1011 + // t.Author (string) (string) 1012 + if len("author") > 8192 { 1013 + return xerrors.Errorf("Value in field \"author\" was too long") 1014 + } 1015 + 1016 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("author"))); err != nil { 1017 + return err 1018 + } 1019 + if _, err := cw.WriteString(string("author")); err != nil { 1020 + return err 1021 + } 1022 + 1023 + if len(t.Author) > 8192 { 1024 + return xerrors.Errorf("Value in field t.Author was too long") 1025 + } 1026 + 1027 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Author))); err != nil { 1028 + return err 1029 + } 1030 + if _, err := cw.WriteString(string(t.Author)); err != nil { 1031 + return err 1032 + } 1033 + 1007 1034 // t.StartedAt (string) (string) 1008 1035 if t.StartedAt != nil { 1009 1036 ··· 1060 1087 } 1061 1088 1062 1089 // t.AuthorHandle (string) (string) 1063 - if len("authorHandle") > 8192 { 1064 - return xerrors.Errorf("Value in field \"authorHandle\" was too long") 1065 - } 1090 + if t.AuthorHandle != nil { 1066 1091 1067 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("authorHandle"))); err != nil { 1068 - return err 1069 - } 1070 - if _, err := cw.WriteString(string("authorHandle")); err != nil { 1071 - return err 1072 - } 1092 + if len("authorHandle") > 8192 { 1093 + return xerrors.Errorf("Value in field \"authorHandle\" was too long") 1094 + } 1095 + 1096 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("authorHandle"))); err != nil { 1097 + return err 1098 + } 1099 + if _, err := cw.WriteString(string("authorHandle")); err != nil { 1100 + return err 1101 + } 1073 1102 1074 - if len(t.AuthorHandle) > 8192 { 1075 - return xerrors.Errorf("Value in field t.AuthorHandle was too long") 1076 - } 1103 + if t.AuthorHandle == nil { 1104 + if _, err := cw.Write(cbg.CborNull); err != nil { 1105 + return err 1106 + } 1107 + } else { 1108 + if len(*t.AuthorHandle) > 8192 { 1109 + return xerrors.Errorf("Value in field t.AuthorHandle was too long") 1110 + } 1077 1111 1078 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.AuthorHandle))); err != nil { 1079 - return err 1080 - } 1081 - if _, err := cw.WriteString(string(t.AuthorHandle)); err != nil { 1082 - return err 1112 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.AuthorHandle))); err != nil { 1113 + return err 1114 + } 1115 + if _, err := cw.WriteString(string(*t.AuthorHandle)); err != nil { 1116 + return err 1117 + } 1118 + } 1083 1119 } 1084 1120 return nil 1085 1121 } ··· 1151 1187 t.LRCID = uint64(extra) 1152 1188 1153 1189 } 1190 + // t.Author (string) (string) 1191 + case "author": 1192 + 1193 + { 1194 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1195 + if err != nil { 1196 + return err 1197 + } 1198 + 1199 + t.Author = string(sval) 1200 + } 1154 1201 // t.StartedAt (string) (string) 1155 1202 case "startedAt": 1156 1203 ··· 1187 1234 case "authorHandle": 1188 1235 1189 1236 { 1190 - sval, err := cbg.ReadStringWithMax(cr, 8192) 1237 + b, err := cr.ReadByte() 1191 1238 if err != nil { 1192 1239 return err 1193 1240 } 1241 + if b != cbg.CborNull[0] { 1242 + if err := cr.UnreadByte(); err != nil { 1243 + return err 1244 + } 1194 1245 1195 - t.AuthorHandle = string(sval) 1246 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1247 + if err != nil { 1248 + return err 1249 + } 1250 + 1251 + t.AuthorHandle = (*string)(&sval) 1252 + } 1196 1253 } 1197 1254 1198 1255 default:
+2 -1
server/internal/lex/types.go
··· 41 41 LexiconTypeID string `json:"$type,const=org.xcvr.lrc.signet" cborgen:"$type,const=org.xcvr.lrc.signet"` 42 42 ChannelURI string `json:"channelURI" cborgen:"channelURI"` 43 43 LRCID uint64 `json:"lrcID" cborgen:"lrcID"` 44 - AuthorHandle string `json:"authorHandle" cborgen:"authorHandle"` 44 + Author string `json:"author" cborgen:"author"` 45 + AuthorHandle *string `json:"authorHandle,omitempty" cborgen:"authorHandle,omitempty"` 45 46 StartedAt *string `json:"startedAt,omitempty" cborgen:"startedAt,omitempty"` 46 47 } 47 48
+20 -8
server/internal/model/channel.go
··· 34 34 welcome string 35 35 server *lrcd.Server 36 36 lastID uint32 37 - initChan <-chan lrcpb.Event_Init 38 - mediainitChan <-chan lrcpb.Event_Mediainit 37 + initChan <-chan lrcd.InitChanMsg 38 + mediainitChan <-chan lrcd.MediaInitChanMsg 39 39 ctx context.Context 40 40 cancel func() 41 41 ··· 164 164 m.logger.Deprintln("i think the server should exist, so i'm making it") 165 165 var err error 166 166 lastID := cm.lastID 167 - initChan := make(chan lrcpb.Event_Init, 100) 168 - mediainitChan := make(chan lrcpb.Event_Mediainit, 100) 167 + initChan := make(chan lrcd.InitChanMsg, 100) 168 + mediainitChan := make(chan lrcd.MediaInitChanMsg, 100) 169 169 170 170 server, err := lrcd.NewServer( 171 + lrcd.WithResolver(func(externalID string, ctx context.Context) *string { 172 + did, err := m.store.FullResolveHandle(externalID, ctx) 173 + if err != nil { 174 + select { 175 + case <-ctx.Done(): 176 + return nil 177 + default: 178 + return &did 179 + } 180 + } 181 + return &did 182 + }), 171 183 lrcd.WithWelcome(cm.welcome), 172 184 lrcd.WithLogging(os.Stdout, true), 173 185 lrcd.WithInitialID(lastID), ··· 230 242 cm.logger.Println("this is a weird case!") 231 243 return 232 244 } 233 - err := m.rm.PostSignet(e, cm.uri, context.Background()) 245 + err := m.rm.PostSignet(e.ResolvedId, e.Init, cm.uri, context.Background()) 234 246 if err != nil { 235 247 m.logger.Println("error posting signet: " + err.Error()) 236 248 } ··· 241 253 } 242 254 e := lrcpb.Event_Init{ 243 255 Init: &lrcpb.Init{ 244 - Id: me.Mediainit.Id, 245 - ExternalID: me.Mediainit.ExternalID, 256 + Id: me.Mediainit.Mediainit.Id, 257 + ExternalID: me.Mediainit.Mediainit.ExternalID, 246 258 }, 247 259 } 248 - err := m.rm.PostSignet(e, cm.uri, context.Background()) 260 + err := m.rm.PostSignet(me.ResolvedId, e, cm.uri, context.Background()) 249 261 if err != nil { 250 262 m.logger.Println("error posting signet: " + err.Error()) 251 263 }
+1 -1
server/internal/model/channelLexiconStream.go
··· 104 104 } 105 105 sv := types.SignetView{ 106 106 URI: s.URI, 107 - IssuerHandle: ihandle, 107 + Issuer: s.IssuerDID, 108 108 ChannelURI: s.ChannelURI, 109 109 LrcId: s.MessageID, 110 110 AuthorHandle: s.AuthorHandle,
+14 -7
server/internal/recordmanager/signet.go
··· 11 11 "time" 12 12 ) 13 13 14 - func (rm *RecordManager) PostSignet(e lrcpb.Event_Init, uri string, ctx context.Context) error { 15 - lsr, now, err := rm.validateSignet(e, uri) 14 + func (rm *RecordManager) PostSignet(resolvedId *string, e lrcpb.Event_Init, uri string, ctx context.Context) error { 15 + lsr, now, err := rm.validateSignet(resolvedId, e, uri, ctx) 16 16 if err != nil { 17 17 return errors.New("failed to validate signet: " + err.Error()) 18 18 } ··· 71 71 return rm.db.UpdateSignet(s, ctx) 72 72 } 73 73 74 - func (rm *RecordManager) validateSignet(e lrcpb.Event_Init, uri string) (*lex.SignetRecord, *time.Time, error) { 74 + func (rm *RecordManager) validateSignet(resolvedId *string, e lrcpb.Event_Init, uri string, ctx context.Context) (*lex.SignetRecord, *time.Time, error) { 75 75 signet := lex.SignetRecord{} 76 76 handle := e.Init.ExternalID 77 - if handle == nil { 78 - h := "" 79 - handle = &h 77 + if resolvedId == nil { 78 + if handle != nil { 79 + did, _ := rm.db.FullResolveHandle(*handle, ctx) 80 + signet.Author = did 81 + } else { 82 + signet.Author = "" 83 + } 84 + } else { 85 + signet.Author = *resolvedId 80 86 } 81 - signet.AuthorHandle = *handle 87 + signet.AuthorHandle = handle 82 88 if e.Init.Id == nil { 83 89 return nil, nil, errors.New("ID should not be nil") 84 90 } ··· 103 109 sr := types.Signet{ 104 110 URI: recorduri, 105 111 IssuerDID: atputils.GetMyDid(), 112 + Author: lsr.Author, 106 113 AuthorHandle: lsr.AuthorHandle, 107 114 ChannelURI: lsr.ChannelURI, 108 115 MessageID: id,
+80 -3
server/internal/types/lexicons.go
··· 1 1 package types 2 2 3 3 import ( 4 + "bytes" 4 5 "encoding/json" 6 + "errors" 5 7 "rvcx/internal/lex" 6 8 "time" 7 9 ) ··· 111 113 type Signet struct { 112 114 URI string 113 115 IssuerDID string 114 - AuthorHandle string 116 + Author string 117 + AuthorHandle *string 115 118 ChannelURI string 116 119 MessageID uint32 117 120 CID string ··· 122 125 type SignetView struct { 123 126 Type string `json:"$type,const=org.xcvr.lrc.defs#signetView"` 124 127 URI string `json:"uri"` 125 - IssuerHandle string `json:"issuerHandle"` 128 + Issuer string `json:"issuer"` 126 129 ChannelURI string `json:"channelURI"` 127 130 LrcId uint32 `json:"lrcID"` 128 - AuthorHandle string `json:"authorHandle"` 131 + Author string `json:"author"` 132 + AuthorHandle *string `json:"authorHandle,omitempty"` 129 133 StartedAt time.Time `json:"startedAt"` 130 134 } 131 135 ··· 286 290 Alias: (*Alias)(&m), 287 291 }) 288 292 } 293 + 294 + type SignedItemView interface { 295 + IsMedia() bool 296 + IsMessage() bool 297 + ToSignedMessageView() (*SignedMessageView, error) 298 + ToSignedMediaView() (*SignedMediaView, error) 299 + } 300 + 301 + func MarshalItems(items []SignedItemView) ([]byte, error) { 302 + bb := make([][]byte, 2*len(items)+1) 303 + bb[0] = []byte("[") 304 + for i, item := range items { 305 + if i != 0 { 306 + bb[2*i] = []byte(",") 307 + } 308 + if item.IsMedia() { 309 + smv, err := item.ToSignedMediaView() 310 + if err != nil { 311 + return nil, err 312 + } 313 + b, err := smv.MarshalJSON() 314 + if err != nil { 315 + return nil, err 316 + } 317 + bb[2*i+1] = b 318 + } else if item.IsMessage() { 319 + smv, err := item.ToSignedMessageView() 320 + if err != nil { 321 + return nil, err 322 + } 323 + b, err := smv.MarshalJSON() 324 + if err != nil { 325 + return nil, err 326 + } 327 + bb[2*i+1] = b 328 + } else { 329 + return nil, errors.New("item is neither media nor message") 330 + } 331 + } 332 + bb[2*len(items)] = []byte("]") 333 + return bytes.Join(bb, nil), nil 334 + } 335 + 336 + func (s SignedMediaView) IsMedia() bool { 337 + return true 338 + } 339 + 340 + func (s SignedMessageView) IsMedia() bool { 341 + return false 342 + } 343 + 344 + func (s SignedMediaView) IsMessage() bool { 345 + return false 346 + } 347 + 348 + func (s SignedMessageView) IsMessage() bool { 349 + return true 350 + } 351 + 352 + func (s SignedMediaView) ToSignedMessageView() (*SignedMessageView, error) { 353 + return nil, errors.New("i am not a message") 354 + } 355 + 356 + func (s SignedMessageView) ToSignedMediaView() (*SignedMediaView, error) { 357 + return nil, errors.New("i am not a media") 358 + } 359 + func (s SignedMessageView) ToSignedMessageView() (*SignedMessageView, error) { 360 + return &s, nil 361 + } 362 + 363 + func (s SignedMediaView) ToSignedMediaView() (*SignedMediaView, error) { 364 + return &s, nil 365 + }