backend for xcvr appview

idk probably good enough to try and break things now

+793 -80
+6 -4
migrations/005_initimages.up.sql
··· 1 - CREATE TABLE medias ( 2 uri TEXT PRIMARY KEY, 3 did TEXT NOT NULL, 4 signet_uri TEXT NOT NULL, 5 FOREIGN KEY (signet_uri) REFERENCES signets(uri) ON DELETE CASCADE, 6 - media_cid TEXT, 7 - media_mime TEXT, 8 alt TEXT, 9 nick TEXT NOT NULL, 10 color INTEGER CHECK (color BETWEEN 0 AND 16777215), 11 cid TEXT NOT NULL, ··· 13 indexed_at TIMESTAMPTZ NOT NULL DEFAULT now() 14 ); 15 16 - CREATE INDEX ON medias (signet_uri);
··· 1 + CREATE TABLE iamges ( 2 uri TEXT PRIMARY KEY, 3 did TEXT NOT NULL, 4 signet_uri TEXT NOT NULL, 5 FOREIGN KEY (signet_uri) REFERENCES signets(uri) ON DELETE CASCADE, 6 + blob_cid TEXT, 7 + blob_mime TEXT, 8 alt TEXT, 9 + height INTEGER, 10 + width INTEGER, 11 nick TEXT NOT NULL, 12 color INTEGER CHECK (color BETWEEN 0 AND 16777215), 13 cid TEXT NOT NULL, ··· 15 indexed_at TIMESTAMPTZ NOT NULL DEFAULT now() 16 ); 17 18 + CREATE INDEX ON images (signet_uri);
+4 -1
server/gen/main.go
··· 10 lex.ProfileRecord{}, 11 lex.ChannelRecord{}, 12 lex.MessageRecord{}, 13 - lex.SignetRecord{}); err != nil { 14 panic(err) 15 } 16 }
··· 10 lex.ProfileRecord{}, 11 lex.ChannelRecord{}, 12 lex.MessageRecord{}, 13 + lex.SignetRecord{}, 14 + lex.AspectRatio{}, 15 + lex.Image{}, 16 + lex.MediaRecord{}); err != nil { 17 panic(err) 18 } 19 }
-2
server/go.sum
··· 117 github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= 118 github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 119 github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 120 - github.com/rachel-mp4/lrcd v0.0.0-20250906202657-38adb092ac1a h1:AWXrdTM1ew/J6mup1xBKkmg/nC6xx6BkL4wT6INdAWI= 121 - github.com/rachel-mp4/lrcd v0.0.0-20250906202657-38adb092ac1a/go.mod h1:aWUVglSyrLf2RGpQdqTucX498b434yWBFJkD6Yzr0OE= 122 github.com/rachel-mp4/lrcd v0.0.1 h1:9d5if0HJ/+TLKdupd7Zu9dISA5fF3QRtI/yr+gYVqXM= 123 github.com/rachel-mp4/lrcd v0.0.1/go.mod h1:aWUVglSyrLf2RGpQdqTucX498b434yWBFJkD6Yzr0OE= 124 github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c h1:t33xVlfSwvB80nj1jroRXUaq/RTgjWwD4l7p/ISatUQ=
··· 117 github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= 118 github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 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/lrcproto v0.0.0-20250905154858-2ddb78e31d0c h1:t33xVlfSwvB80nj1jroRXUaq/RTgjWwD4l7p/ISatUQ=
+28 -16
server/internal/db/lexicon.go
··· 293 uri, 294 did, 295 signet_uri, 296 - image_cid, 297 - image_mime, 298 alt, 299 nick, 300 color, 301 cid, 302 posted_at 303 ) VALUES ( 304 - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 305 ) ON CONFLICT (uri) DO NOTHING`, 306 image.URI, 307 image.DID, 308 image.SignetURI, 309 - image.ImageCID, 310 - image.ImageMIME, 311 image.Alt, 312 image.Nick, 313 image.Color, 314 image.CID, ··· 320 } 321 322 func (s *Store) UpdateImage(image *types.Image, ctx context.Context) error { 323 - _, err := s.pool.Exec(ctx, `INSERT INTO medias ( 324 uri, 325 did, 326 signet_uri, 327 - image_cid, 328 - image_mime, 329 alt, 330 nick, 331 color, 332 cid, 333 posted_at 334 ) VALUES ( 335 - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 336 )`, 337 image.URI, 338 image.DID, 339 image.SignetURI, 340 - image.ImageCID, 341 - image.ImageMIME, 342 image.Alt, 343 image.Nick, 344 image.Color, 345 image.CID, ··· 351 } 352 353 func (s *Store) DeleteImage(uri string, ctx context.Context) error { 354 - _, err := s.pool.Exec(ctx, `DELETE from medias m WHERE m.uri = $1`, uri) 355 if err != nil { 356 return errors.New("bep bep bop: " + err.Error()) 357 } ··· 362 row := s.pool.QueryRow(ctx, `SELECT FROM medias ( 363 did, 364 signet_uri, 365 - media_cid, 366 - media_mime, 367 alt, 368 nick, 369 color, 370 cid, ··· 373 var image types.Image 374 err := row.Scan(&image.DID, 375 &image.SignetURI, 376 - &image.ImageCID, 377 - &image.ImageMIME, 378 &image.Alt, 379 &image.Nick, 380 &image.Color, 381 &image.CID,
··· 293 uri, 294 did, 295 signet_uri, 296 + blob_cid, 297 + blob_mime, 298 alt, 299 + height, 300 + width, 301 nick, 302 color, 303 cid, 304 posted_at 305 ) VALUES ( 306 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 307 ) ON CONFLICT (uri) DO NOTHING`, 308 image.URI, 309 image.DID, 310 image.SignetURI, 311 + image.BlobCID, 312 + image.BlobMIME, 313 image.Alt, 314 + image.Height, 315 + image.Width, 316 image.Nick, 317 image.Color, 318 image.CID, ··· 324 } 325 326 func (s *Store) UpdateImage(image *types.Image, ctx context.Context) error { 327 + _, err := s.pool.Exec(ctx, `INSERT INTO images ( 328 uri, 329 did, 330 signet_uri, 331 + blob_cid, 332 + blob_mime, 333 alt, 334 + height, 335 + width, 336 nick, 337 color, 338 cid, 339 posted_at 340 ) VALUES ( 341 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 342 )`, 343 image.URI, 344 image.DID, 345 image.SignetURI, 346 + image.BlobCID, 347 + image.BlobMIME, 348 image.Alt, 349 + image.Height, 350 + image.Width, 351 image.Nick, 352 image.Color, 353 image.CID, ··· 359 } 360 361 func (s *Store) DeleteImage(uri string, ctx context.Context) error { 362 + _, err := s.pool.Exec(ctx, `DELETE from images i WHERE i.uri = $1`, uri) 363 if err != nil { 364 return errors.New("bep bep bop: " + err.Error()) 365 } ··· 370 row := s.pool.QueryRow(ctx, `SELECT FROM medias ( 371 did, 372 signet_uri, 373 + blob_cid, 374 + blob_mime, 375 alt, 376 + height, 377 + width, 378 nick, 379 color, 380 cid, ··· 383 var image types.Image 384 err := row.Scan(&image.DID, 385 &image.SignetURI, 386 + &image.BlobCID, 387 + &image.BlobMIME, 388 &image.Alt, 389 + &image.Height, 390 + &image.Width, 391 &image.Nick, 392 &image.Color, 393 &image.CID,
-1
server/internal/handler/handler.go
··· 34 mux.HandleFunc("POST /lrc/image", h.oauthMiddleware(h.uploadImage)) 35 mux.HandleFunc("POST /lrc/media", h.oauthMiddleware(h.postMedia)) 36 // mux.HandleFunc("GET /lrc/image", h.getImage) 37 - mux.HandleFunc("POST /lrc/imagePub", h.oauthMiddleware(h.postImagePub)) 38 mux.HandleFunc("POST /lrc/mymessage", h.postMyMessage) 39 // xcvr handlers 40 mux.HandleFunc("POST /xcvr/profile", h.oauthMiddleware(h.postProfile))
··· 34 mux.HandleFunc("POST /lrc/image", h.oauthMiddleware(h.uploadImage)) 35 mux.HandleFunc("POST /lrc/media", h.oauthMiddleware(h.postMedia)) 36 // mux.HandleFunc("GET /lrc/image", h.getImage) 37 mux.HandleFunc("POST /lrc/mymessage", h.postMyMessage) 38 // xcvr handlers 39 mux.HandleFunc("POST /xcvr/profile", h.oauthMiddleware(h.postProfile))
+6 -5
server/internal/handler/lrcHandlers.go
··· 181 h.badRequest(w, err) 182 return 183 } 184 - h.rm.PostMedia(cs, mr, r.Context()) 185 } 186 187 func parseMediaRequest(r *http.Request) (*types.ParseMediaRequest, error) { ··· 225 // func syncGetBlob(did string, cid *string) { 226 // //TODO: impl 227 // } 228 - 229 - func (h *Handler) postImagePub(cs *atoauth.ClientSession, w http.ResponseWriter, r *http.Request) { 230 - 231 - }
··· 181 h.badRequest(w, err) 182 return 183 } 184 + err = h.rm.PostMedia(cs, mr, r.Context()) 185 + if err != nil { 186 + h.serverError(w, errors.New("failing to post the media :c")) 187 + return 188 + } 189 + w.Write(nil) 190 } 191 192 func parseMediaRequest(r *http.Request) (*types.ParseMediaRequest, error) { ··· 230 // func syncGetBlob(did string, cid *string) { 231 // //TODO: impl 232 // }
+736 -36
server/internal/lex/lexicons_cbor.go
··· 969 return err 970 } 971 972 - // t.Author (string) (string) 973 - if len("nick") > 8192 { 974 - return xerrors.Errorf("Value in field \"nick\" was too long") 975 - } 976 - 977 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("nick"))); err != nil { 978 - return err 979 - } 980 - if _, err := cw.WriteString(string("nick")); err != nil { 981 - return err 982 - } 983 - 984 - if len(t.AuthorHandle) > 8192 { 985 - return xerrors.Errorf("Value in field t.Author was too long") 986 - } 987 - 988 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.AuthorHandle))); err != nil { 989 - return err 990 - } 991 - if _, err := cw.WriteString(string(t.AuthorHandle)); err != nil { 992 - return err 993 - } 994 - 995 // t.LexiconTypeID (string) (string) 996 if len("$type") > 8192 { 997 return xerrors.Errorf("Value in field \"$type\" was too long") ··· 1081 if _, err := cw.WriteString(string(t.ChannelURI)); err != nil { 1082 return err 1083 } 1084 return nil 1085 } 1086 ··· 1109 1110 n := extra 1111 1112 - nameBuf := make([]byte, 10) 1113 for i := uint64(0); i < n; i++ { 1114 nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1115 if err != nil { ··· 1125 } 1126 1127 switch string(nameBuf[:nameLen]) { 1128 - // t.Author (string) (string) 1129 - case "authorHandle": 1130 - 1131 - { 1132 - sval, err := cbg.ReadStringWithMax(cr, 8192) 1133 - if err != nil { 1134 - return err 1135 - } 1136 - 1137 - t.AuthorHandle = string(sval) 1138 - } 1139 - // t.LexiconTypeID (string) (string) 1140 case "$type": 1141 1142 { ··· 1193 } 1194 1195 t.ChannelURI = string(sval) 1196 } 1197 1198 default:
··· 969 return err 970 } 971 972 // t.LexiconTypeID (string) (string) 973 if len("$type") > 8192 { 974 return xerrors.Errorf("Value in field \"$type\" was too long") ··· 1058 if _, err := cw.WriteString(string(t.ChannelURI)); err != nil { 1059 return err 1060 } 1061 + 1062 + // t.AuthorHandle (string) (string) 1063 + if len("authorHandle") > 8192 { 1064 + return xerrors.Errorf("Value in field \"authorHandle\" was too long") 1065 + } 1066 + 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 + } 1073 + 1074 + if len(t.AuthorHandle) > 8192 { 1075 + return xerrors.Errorf("Value in field t.AuthorHandle was too long") 1076 + } 1077 + 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 1083 + } 1084 return nil 1085 } 1086 ··· 1109 1110 n := extra 1111 1112 + nameBuf := make([]byte, 12) 1113 for i := uint64(0); i < n; i++ { 1114 nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1115 if err != nil { ··· 1125 } 1126 1127 switch string(nameBuf[:nameLen]) { 1128 + // t.LexiconTypeID (string) (string) 1129 case "$type": 1130 1131 { ··· 1182 } 1183 1184 t.ChannelURI = string(sval) 1185 + } 1186 + // t.AuthorHandle (string) (string) 1187 + case "authorHandle": 1188 + 1189 + { 1190 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1191 + if err != nil { 1192 + return err 1193 + } 1194 + 1195 + t.AuthorHandle = string(sval) 1196 + } 1197 + 1198 + default: 1199 + // Field doesn't exist on this type, so ignore it 1200 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 1201 + return err 1202 + } 1203 + } 1204 + } 1205 + 1206 + return nil 1207 + } 1208 + func (t *AspectRatio) MarshalCBOR(w io.Writer) error { 1209 + if t == nil { 1210 + _, err := w.Write(cbg.CborNull) 1211 + return err 1212 + } 1213 + 1214 + cw := cbg.NewCborWriter(w) 1215 + 1216 + if _, err := cw.Write([]byte{162}); err != nil { 1217 + return err 1218 + } 1219 + 1220 + // t.Width (int64) (int64) 1221 + if len("width") > 8192 { 1222 + return xerrors.Errorf("Value in field \"width\" was too long") 1223 + } 1224 + 1225 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("width"))); err != nil { 1226 + return err 1227 + } 1228 + if _, err := cw.WriteString(string("width")); err != nil { 1229 + return err 1230 + } 1231 + 1232 + if t.Width >= 0 { 1233 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Width)); err != nil { 1234 + return err 1235 + } 1236 + } else { 1237 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Width-1)); err != nil { 1238 + return err 1239 + } 1240 + } 1241 + 1242 + // t.Height (int64) (int64) 1243 + if len("height") > 8192 { 1244 + return xerrors.Errorf("Value in field \"height\" was too long") 1245 + } 1246 + 1247 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("height"))); err != nil { 1248 + return err 1249 + } 1250 + if _, err := cw.WriteString(string("height")); err != nil { 1251 + return err 1252 + } 1253 + 1254 + if t.Height >= 0 { 1255 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Height)); err != nil { 1256 + return err 1257 + } 1258 + } else { 1259 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Height-1)); err != nil { 1260 + return err 1261 + } 1262 + } 1263 + 1264 + return nil 1265 + } 1266 + 1267 + func (t *AspectRatio) UnmarshalCBOR(r io.Reader) (err error) { 1268 + *t = AspectRatio{} 1269 + 1270 + cr := cbg.NewCborReader(r) 1271 + 1272 + maj, extra, err := cr.ReadHeader() 1273 + if err != nil { 1274 + return err 1275 + } 1276 + defer func() { 1277 + if err == io.EOF { 1278 + err = io.ErrUnexpectedEOF 1279 + } 1280 + }() 1281 + 1282 + if maj != cbg.MajMap { 1283 + return fmt.Errorf("cbor input should be of type map") 1284 + } 1285 + 1286 + if extra > cbg.MaxLength { 1287 + return fmt.Errorf("AspectRatio: map struct too large (%d)", extra) 1288 + } 1289 + 1290 + n := extra 1291 + 1292 + nameBuf := make([]byte, 6) 1293 + for i := uint64(0); i < n; i++ { 1294 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1295 + if err != nil { 1296 + return err 1297 + } 1298 + 1299 + if !ok { 1300 + // Field doesn't exist on this type, so ignore it 1301 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 1302 + return err 1303 + } 1304 + continue 1305 + } 1306 + 1307 + switch string(nameBuf[:nameLen]) { 1308 + // t.Width (int64) (int64) 1309 + case "width": 1310 + { 1311 + maj, extra, err := cr.ReadHeader() 1312 + if err != nil { 1313 + return err 1314 + } 1315 + var extraI int64 1316 + switch maj { 1317 + case cbg.MajUnsignedInt: 1318 + extraI = int64(extra) 1319 + if extraI < 0 { 1320 + return fmt.Errorf("int64 positive overflow") 1321 + } 1322 + case cbg.MajNegativeInt: 1323 + extraI = int64(extra) 1324 + if extraI < 0 { 1325 + return fmt.Errorf("int64 negative overflow") 1326 + } 1327 + extraI = -1 - extraI 1328 + default: 1329 + return fmt.Errorf("wrong type for int64 field: %d", maj) 1330 + } 1331 + 1332 + t.Width = int64(extraI) 1333 + } 1334 + // t.Height (int64) (int64) 1335 + case "height": 1336 + { 1337 + maj, extra, err := cr.ReadHeader() 1338 + if err != nil { 1339 + return err 1340 + } 1341 + var extraI int64 1342 + switch maj { 1343 + case cbg.MajUnsignedInt: 1344 + extraI = int64(extra) 1345 + if extraI < 0 { 1346 + return fmt.Errorf("int64 positive overflow") 1347 + } 1348 + case cbg.MajNegativeInt: 1349 + extraI = int64(extra) 1350 + if extraI < 0 { 1351 + return fmt.Errorf("int64 negative overflow") 1352 + } 1353 + extraI = -1 - extraI 1354 + default: 1355 + return fmt.Errorf("wrong type for int64 field: %d", maj) 1356 + } 1357 + 1358 + t.Height = int64(extraI) 1359 + } 1360 + 1361 + default: 1362 + // Field doesn't exist on this type, so ignore it 1363 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 1364 + return err 1365 + } 1366 + } 1367 + } 1368 + 1369 + return nil 1370 + } 1371 + func (t *Image) MarshalCBOR(w io.Writer) error { 1372 + if t == nil { 1373 + _, err := w.Write(cbg.CborNull) 1374 + return err 1375 + } 1376 + 1377 + cw := cbg.NewCborWriter(w) 1378 + fieldCount := 4 1379 + 1380 + if t.AspectRatio == nil { 1381 + fieldCount-- 1382 + } 1383 + 1384 + if t.Blob == nil { 1385 + fieldCount-- 1386 + } 1387 + 1388 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 1389 + return err 1390 + } 1391 + 1392 + // t.Alt (string) (string) 1393 + if len("alt") > 8192 { 1394 + return xerrors.Errorf("Value in field \"alt\" was too long") 1395 + } 1396 + 1397 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("alt"))); err != nil { 1398 + return err 1399 + } 1400 + if _, err := cw.WriteString(string("alt")); err != nil { 1401 + return err 1402 + } 1403 + 1404 + if len(t.Alt) > 8192 { 1405 + return xerrors.Errorf("Value in field t.Alt was too long") 1406 + } 1407 + 1408 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Alt))); err != nil { 1409 + return err 1410 + } 1411 + if _, err := cw.WriteString(string(t.Alt)); err != nil { 1412 + return err 1413 + } 1414 + 1415 + // t.Blob (util.BlobSchema) (struct) 1416 + if t.Blob != nil { 1417 + 1418 + if len("blob") > 8192 { 1419 + return xerrors.Errorf("Value in field \"blob\" was too long") 1420 + } 1421 + 1422 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("blob"))); err != nil { 1423 + return err 1424 + } 1425 + if _, err := cw.WriteString(string("blob")); err != nil { 1426 + return err 1427 + } 1428 + 1429 + if err := t.Blob.MarshalCBOR(cw); err != nil { 1430 + return err 1431 + } 1432 + } 1433 + 1434 + // t.LexiconTypeID (string) (string) 1435 + if len("$type") > 8192 { 1436 + return xerrors.Errorf("Value in field \"$type\" was too long") 1437 + } 1438 + 1439 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 1440 + return err 1441 + } 1442 + if _, err := cw.WriteString(string("$type")); err != nil { 1443 + return err 1444 + } 1445 + 1446 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.lrc.image"))); err != nil { 1447 + return err 1448 + } 1449 + if _, err := cw.WriteString(string("org.xcvr.lrc.image")); err != nil { 1450 + return err 1451 + } 1452 + 1453 + // t.AspectRatio (lex.AspectRatio) (struct) 1454 + if t.AspectRatio != nil { 1455 + 1456 + if len("aspectRatio") > 8192 { 1457 + return xerrors.Errorf("Value in field \"aspectRatio\" was too long") 1458 + } 1459 + 1460 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("aspectRatio"))); err != nil { 1461 + return err 1462 + } 1463 + if _, err := cw.WriteString(string("aspectRatio")); err != nil { 1464 + return err 1465 + } 1466 + 1467 + if err := t.AspectRatio.MarshalCBOR(cw); err != nil { 1468 + return err 1469 + } 1470 + } 1471 + return nil 1472 + } 1473 + 1474 + func (t *Image) UnmarshalCBOR(r io.Reader) (err error) { 1475 + *t = Image{} 1476 + 1477 + cr := cbg.NewCborReader(r) 1478 + 1479 + maj, extra, err := cr.ReadHeader() 1480 + if err != nil { 1481 + return err 1482 + } 1483 + defer func() { 1484 + if err == io.EOF { 1485 + err = io.ErrUnexpectedEOF 1486 + } 1487 + }() 1488 + 1489 + if maj != cbg.MajMap { 1490 + return fmt.Errorf("cbor input should be of type map") 1491 + } 1492 + 1493 + if extra > cbg.MaxLength { 1494 + return fmt.Errorf("Image: map struct too large (%d)", extra) 1495 + } 1496 + 1497 + n := extra 1498 + 1499 + nameBuf := make([]byte, 11) 1500 + for i := uint64(0); i < n; i++ { 1501 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1502 + if err != nil { 1503 + return err 1504 + } 1505 + 1506 + if !ok { 1507 + // Field doesn't exist on this type, so ignore it 1508 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 1509 + return err 1510 + } 1511 + continue 1512 + } 1513 + 1514 + switch string(nameBuf[:nameLen]) { 1515 + // t.Alt (string) (string) 1516 + case "alt": 1517 + 1518 + { 1519 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1520 + if err != nil { 1521 + return err 1522 + } 1523 + 1524 + t.Alt = string(sval) 1525 + } 1526 + // t.Blob (util.BlobSchema) (struct) 1527 + case "blob": 1528 + 1529 + { 1530 + 1531 + b, err := cr.ReadByte() 1532 + if err != nil { 1533 + return err 1534 + } 1535 + if b != cbg.CborNull[0] { 1536 + if err := cr.UnreadByte(); err != nil { 1537 + return err 1538 + } 1539 + t.Blob = new(util.BlobSchema) 1540 + if err := t.Blob.UnmarshalCBOR(cr); err != nil { 1541 + return xerrors.Errorf("unmarshaling t.Blob pointer: %w", err) 1542 + } 1543 + } 1544 + 1545 + } 1546 + // t.LexiconTypeID (string) (string) 1547 + case "$type": 1548 + 1549 + { 1550 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1551 + if err != nil { 1552 + return err 1553 + } 1554 + 1555 + t.LexiconTypeID = string(sval) 1556 + } 1557 + // t.AspectRatio (lex.AspectRatio) (struct) 1558 + case "aspectRatio": 1559 + 1560 + { 1561 + 1562 + b, err := cr.ReadByte() 1563 + if err != nil { 1564 + return err 1565 + } 1566 + if b != cbg.CborNull[0] { 1567 + if err := cr.UnreadByte(); err != nil { 1568 + return err 1569 + } 1570 + t.AspectRatio = new(AspectRatio) 1571 + if err := t.AspectRatio.UnmarshalCBOR(cr); err != nil { 1572 + return xerrors.Errorf("unmarshaling t.AspectRatio pointer: %w", err) 1573 + } 1574 + } 1575 + 1576 + } 1577 + 1578 + default: 1579 + // Field doesn't exist on this type, so ignore it 1580 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 1581 + return err 1582 + } 1583 + } 1584 + } 1585 + 1586 + return nil 1587 + } 1588 + func (t *MediaRecord) MarshalCBOR(w io.Writer) error { 1589 + if t == nil { 1590 + _, err := w.Write(cbg.CborNull) 1591 + return err 1592 + } 1593 + 1594 + cw := cbg.NewCborWriter(w) 1595 + fieldCount := 6 1596 + 1597 + if t.Image == nil { 1598 + fieldCount-- 1599 + } 1600 + 1601 + if t.Nick == nil { 1602 + fieldCount-- 1603 + } 1604 + 1605 + if t.Color == nil { 1606 + fieldCount-- 1607 + } 1608 + 1609 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 1610 + return err 1611 + } 1612 + 1613 + // t.Nick (string) (string) 1614 + if t.Nick != nil { 1615 + 1616 + if len("nick") > 8192 { 1617 + return xerrors.Errorf("Value in field \"nick\" was too long") 1618 + } 1619 + 1620 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("nick"))); err != nil { 1621 + return err 1622 + } 1623 + if _, err := cw.WriteString(string("nick")); err != nil { 1624 + return err 1625 + } 1626 + 1627 + if t.Nick == nil { 1628 + if _, err := cw.Write(cbg.CborNull); err != nil { 1629 + return err 1630 + } 1631 + } else { 1632 + if len(*t.Nick) > 8192 { 1633 + return xerrors.Errorf("Value in field t.Nick was too long") 1634 + } 1635 + 1636 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.Nick))); err != nil { 1637 + return err 1638 + } 1639 + if _, err := cw.WriteString(string(*t.Nick)); err != nil { 1640 + return err 1641 + } 1642 + } 1643 + } 1644 + 1645 + // t.LexiconTypeID (string) (string) 1646 + if len("$type") > 8192 { 1647 + return xerrors.Errorf("Value in field \"$type\" was too long") 1648 + } 1649 + 1650 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 1651 + return err 1652 + } 1653 + if _, err := cw.WriteString(string("$type")); err != nil { 1654 + return err 1655 + } 1656 + 1657 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.lrc.media"))); err != nil { 1658 + return err 1659 + } 1660 + if _, err := cw.WriteString(string("org.xcvr.lrc.media")); err != nil { 1661 + return err 1662 + } 1663 + 1664 + // t.Color (uint64) (uint64) 1665 + if t.Color != nil { 1666 + 1667 + if len("color") > 8192 { 1668 + return xerrors.Errorf("Value in field \"color\" was too long") 1669 + } 1670 + 1671 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("color"))); err != nil { 1672 + return err 1673 + } 1674 + if _, err := cw.WriteString(string("color")); err != nil { 1675 + return err 1676 + } 1677 + 1678 + if t.Color == nil { 1679 + if _, err := cw.Write(cbg.CborNull); err != nil { 1680 + return err 1681 + } 1682 + } else { 1683 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(*t.Color)); err != nil { 1684 + return err 1685 + } 1686 + } 1687 + 1688 + } 1689 + 1690 + // t.Image (lex.Image) (struct) 1691 + if t.Image != nil { 1692 + 1693 + if len("image") > 8192 { 1694 + return xerrors.Errorf("Value in field \"image\" was too long") 1695 + } 1696 + 1697 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("image"))); err != nil { 1698 + return err 1699 + } 1700 + if _, err := cw.WriteString(string("image")); err != nil { 1701 + return err 1702 + } 1703 + 1704 + if err := t.Image.MarshalCBOR(cw); err != nil { 1705 + return err 1706 + } 1707 + } 1708 + 1709 + // t.PostedAt (string) (string) 1710 + if len("postedAt") > 8192 { 1711 + return xerrors.Errorf("Value in field \"postedAt\" was too long") 1712 + } 1713 + 1714 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("postedAt"))); err != nil { 1715 + return err 1716 + } 1717 + if _, err := cw.WriteString(string("postedAt")); err != nil { 1718 + return err 1719 + } 1720 + 1721 + if len(t.PostedAt) > 8192 { 1722 + return xerrors.Errorf("Value in field t.PostedAt was too long") 1723 + } 1724 + 1725 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.PostedAt))); err != nil { 1726 + return err 1727 + } 1728 + if _, err := cw.WriteString(string(t.PostedAt)); err != nil { 1729 + return err 1730 + } 1731 + 1732 + // t.SignetURI (string) (string) 1733 + if len("signetURI") > 8192 { 1734 + return xerrors.Errorf("Value in field \"signetURI\" was too long") 1735 + } 1736 + 1737 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("signetURI"))); err != nil { 1738 + return err 1739 + } 1740 + if _, err := cw.WriteString(string("signetURI")); err != nil { 1741 + return err 1742 + } 1743 + 1744 + if len(t.SignetURI) > 8192 { 1745 + return xerrors.Errorf("Value in field t.SignetURI was too long") 1746 + } 1747 + 1748 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.SignetURI))); err != nil { 1749 + return err 1750 + } 1751 + if _, err := cw.WriteString(string(t.SignetURI)); err != nil { 1752 + return err 1753 + } 1754 + return nil 1755 + } 1756 + 1757 + func (t *MediaRecord) UnmarshalCBOR(r io.Reader) (err error) { 1758 + *t = MediaRecord{} 1759 + 1760 + cr := cbg.NewCborReader(r) 1761 + 1762 + maj, extra, err := cr.ReadHeader() 1763 + if err != nil { 1764 + return err 1765 + } 1766 + defer func() { 1767 + if err == io.EOF { 1768 + err = io.ErrUnexpectedEOF 1769 + } 1770 + }() 1771 + 1772 + if maj != cbg.MajMap { 1773 + return fmt.Errorf("cbor input should be of type map") 1774 + } 1775 + 1776 + if extra > cbg.MaxLength { 1777 + return fmt.Errorf("MediaRecord: map struct too large (%d)", extra) 1778 + } 1779 + 1780 + n := extra 1781 + 1782 + nameBuf := make([]byte, 9) 1783 + for i := uint64(0); i < n; i++ { 1784 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1785 + if err != nil { 1786 + return err 1787 + } 1788 + 1789 + if !ok { 1790 + // Field doesn't exist on this type, so ignore it 1791 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 1792 + return err 1793 + } 1794 + continue 1795 + } 1796 + 1797 + switch string(nameBuf[:nameLen]) { 1798 + // t.Nick (string) (string) 1799 + case "nick": 1800 + 1801 + { 1802 + b, err := cr.ReadByte() 1803 + if err != nil { 1804 + return err 1805 + } 1806 + if b != cbg.CborNull[0] { 1807 + if err := cr.UnreadByte(); err != nil { 1808 + return err 1809 + } 1810 + 1811 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1812 + if err != nil { 1813 + return err 1814 + } 1815 + 1816 + t.Nick = (*string)(&sval) 1817 + } 1818 + } 1819 + // t.LexiconTypeID (string) (string) 1820 + case "$type": 1821 + 1822 + { 1823 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1824 + if err != nil { 1825 + return err 1826 + } 1827 + 1828 + t.LexiconTypeID = string(sval) 1829 + } 1830 + // t.Color (uint64) (uint64) 1831 + case "color": 1832 + 1833 + { 1834 + 1835 + b, err := cr.ReadByte() 1836 + if err != nil { 1837 + return err 1838 + } 1839 + if b != cbg.CborNull[0] { 1840 + if err := cr.UnreadByte(); err != nil { 1841 + return err 1842 + } 1843 + maj, extra, err = cr.ReadHeader() 1844 + if err != nil { 1845 + return err 1846 + } 1847 + if maj != cbg.MajUnsignedInt { 1848 + return fmt.Errorf("wrong type for uint64 field") 1849 + } 1850 + typed := uint64(extra) 1851 + t.Color = &typed 1852 + } 1853 + 1854 + } 1855 + // t.Image (lex.Image) (struct) 1856 + case "image": 1857 + 1858 + { 1859 + 1860 + b, err := cr.ReadByte() 1861 + if err != nil { 1862 + return err 1863 + } 1864 + if b != cbg.CborNull[0] { 1865 + if err := cr.UnreadByte(); err != nil { 1866 + return err 1867 + } 1868 + t.Image = new(Image) 1869 + if err := t.Image.UnmarshalCBOR(cr); err != nil { 1870 + return xerrors.Errorf("unmarshaling t.Image pointer: %w", err) 1871 + } 1872 + } 1873 + 1874 + } 1875 + // t.PostedAt (string) (string) 1876 + case "postedAt": 1877 + 1878 + { 1879 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1880 + if err != nil { 1881 + return err 1882 + } 1883 + 1884 + t.PostedAt = string(sval) 1885 + } 1886 + // t.SignetURI (string) (string) 1887 + case "signetURI": 1888 + 1889 + { 1890 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1891 + if err != nil { 1892 + return err 1893 + } 1894 + 1895 + t.SignetURI = string(sval) 1896 } 1897 1898 default:
+2 -6
server/internal/lex/types.go
··· 48 type MediaRecord struct { 49 LexiconTypeID string `json:"$type,const=org.xcvr.lrc.media" cborgen:"$type,const=org.xcvr.lrc.media"` 50 SignetURI string `json:"signetURI" cborgen:"signetURI"` 51 - Media Media `json:"media" cborgen:"media"` 52 Nick *string `json:"nick,omitempty" cborgen:"nick,omitempty"` 53 Color *uint64 `json:"color,omitempty" cborgen:"color,omitempty"` 54 PostedAt string `json:"postedAt" cborgen:"postedAt"` 55 } 56 57 - type Media struct { 58 - Image *Image 59 - } 60 - 61 type Image struct { 62 LexiconTypeID string `json:"$type,const=org.xcvr.lrc.image" cborgen:"$type,const=org.xcvr.lrc.image"` 63 Alt string `json:"alt" cborgen:"alt"` 64 AspectRatio *AspectRatio `json:"aspectRatio,omitempty" cborgen:"aspectRatio,omitempty"` 65 - Image *util.BlobSchema `json:"image,omitempty" cborgen:"image,omitempty"` 66 } 67 68 type AspectRatio struct {
··· 48 type MediaRecord struct { 49 LexiconTypeID string `json:"$type,const=org.xcvr.lrc.media" cborgen:"$type,const=org.xcvr.lrc.media"` 50 SignetURI string `json:"signetURI" cborgen:"signetURI"` 51 + Image *Image `json:"image,omitempty" cborgen:"image,omitempty"` 52 Nick *string `json:"nick,omitempty" cborgen:"nick,omitempty"` 53 Color *uint64 `json:"color,omitempty" cborgen:"color,omitempty"` 54 PostedAt string `json:"postedAt" cborgen:"postedAt"` 55 } 56 57 type Image struct { 58 LexiconTypeID string `json:"$type,const=org.xcvr.lrc.image" cborgen:"$type,const=org.xcvr.lrc.image"` 59 Alt string `json:"alt" cborgen:"alt"` 60 AspectRatio *AspectRatio `json:"aspectRatio,omitempty" cborgen:"aspectRatio,omitempty"` 61 + Blob *util.BlobSchema `json:"blob,omitempty" cborgen:"blob,omitempty"` 62 } 63 64 type AspectRatio struct {
+7 -7
server/internal/recordmanager/media.go
··· 51 cnum := uint64(*cptr) 52 imr.Color = &cnum 53 } 54 - imr.Media.Image = mr.Image 55 nowsyn := syntax.DatetimeNow() 56 imr.PostedAt = nowsyn.String() 57 nt := nowsyn.Time() ··· 68 img.URI = uri 69 img.DID = cs.Data.AccountDID.String() 70 img.SignetURI = imr.SignetURI 71 - if imr.Media.Image != nil { 72 - img.Alt = imr.Media.Image.Alt 73 - if imr.Media.Image.Image != nil { 74 - img.ImageMIME = &imr.Media.Image.Image.MimeType 75 - icid := imr.Media.Image.Image.Ref.String() 76 - img.ImageCID = &icid 77 } 78 } 79 img.Nick = imr.Nick
··· 51 cnum := uint64(*cptr) 52 imr.Color = &cnum 53 } 54 + imr.Image = mr.Image 55 nowsyn := syntax.DatetimeNow() 56 imr.PostedAt = nowsyn.String() 57 nt := nowsyn.Time() ··· 68 img.URI = uri 69 img.DID = cs.Data.AccountDID.String() 70 img.SignetURI = imr.SignetURI 71 + if imr.Image != nil { 72 + img.Alt = imr.Image.Alt 73 + if imr.Image.Blob != nil { 74 + img.BlobMIME = &imr.Image.Blob.MimeType 75 + icid := imr.Image.Blob.Ref.String() 76 + img.BlobCID = &icid 77 } 78 } 79 img.Nick = imr.Nick
+4 -2
server/internal/types/lexicons.go
··· 215 URI string 216 DID string 217 SignetURI string 218 - ImageCID *string 219 - ImageMIME *string 220 Alt string 221 Nick *string 222 Color *uint32 223 CID string 224 PostedAt time.Time 225 IndexedAt time.Time 226 }
··· 215 URI string 216 DID string 217 SignetURI string 218 + BlobCID *string 219 + BlobMIME *string 220 Alt string 221 Nick *string 222 Color *uint32 223 CID string 224 + Width *int64 225 + Height *int64 226 PostedAt time.Time 227 IndexedAt time.Time 228 }