[READ ONLY MIRROR] Spark Social AppView Server github.com/sprksocial/server
atproto deno hono lexicon
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

ingest look record

+119 -1
+3 -1
services/ingester/src/db/connection.ts
··· 8 8 profileSchema, 9 9 audioSchema, 10 10 repostSchema, 11 - musicSchema 11 + musicSchema, 12 + lookSchema, 12 13 } from './models.js' 13 14 import { env } from '../utils/env.js' 14 15 import { pino } from 'pino' ··· 29 30 Audio: this.connection.model('Audio', audioSchema), 30 31 Repost: this.connection.model('Repost', repostSchema), 31 32 Music: this.connection.model('Music', musicSchema), 33 + Look: this.connection.model('Look', lookSchema), 32 34 } 33 35 } 34 36
+26
services/ingester/src/db/models.ts
··· 22 22 cid: { type: String, required: true }, 23 23 }) 24 24 25 + export interface LookDocument extends Document { 26 + uri: string 27 + subject: string 28 + subjectCid: string 29 + authorDid: string 30 + authorHandle: string 31 + createdAt: string 32 + indexedAt: string 33 + cid: string 34 + } 35 + 36 + export const lookSchema = new Schema<LookDocument>({ 37 + uri: { type: String, required: true, unique: true, index: true }, 38 + subject: { type: String, required: true, index: true }, 39 + subjectCid: { type: String, required: true }, 40 + authorDid: { type: String, required: true, index: true }, 41 + authorHandle: { type: String, required: true }, 42 + createdAt: { type: String, required: true }, 43 + indexedAt: { type: String, required: true }, 44 + cid: { type: String, required: true }, 45 + }) 46 + 25 47 export interface FollowDocument extends Document { 26 48 uri: string 27 49 subject: string ··· 277 299 repostSchema.index({ authorDid: 1, createdAt: -1 }) 278 300 repostSchema.index({ 'subject.uri': 1, createdAt: -1 }) 279 301 302 + lookSchema.index({ authorDid: 1, createdAt: -1 }) 303 + lookSchema.index({ 'subject.uri': 1, createdAt: -1 }) 304 + 280 305 musicSchema.index({ authorDid: 1, createdAt: -1 }) 281 306 musicSchema.index({ tags: 1, createdAt: -1 }) 282 307 ··· 289 314 Audio: Model<AudioDocument> 290 315 Repost: Model<RepostDocument> 291 316 Music: Model<MusicDocument> 317 + Look: Model<LookDocument> 292 318 }
+6
services/ingester/src/handlers/index.ts
··· 9 9 import { handleAudioEvent } from './audio-handler.js' 10 10 import { handleRepostEvent } from './repost-handler.js' 11 11 import { handleMusicEvent } from './music-handler.js' 12 + import { handleLookEvent } from './look-handler.js' 12 13 13 14 const logger = pino({ name: 'event-handler' }) 14 15 ··· 52 53 53 54 if (evt.collection === 'so.sprk.feed.music') { 54 55 await handleMusicEvent(evt, db) 56 + return 57 + } 58 + 59 + if (evt.collection === 'so.sprk.feed.look') { 60 + await handleLookEvent(evt, db) 55 61 return 56 62 } 57 63
+84
services/ingester/src/handlers/look-handler.ts
··· 1 + import { pino } from 'pino' 2 + import { Database } from '../db/connection.js' 3 + import type { NormalizedEvent } from '../types/events.js' 4 + 5 + const logger = pino({ name: 'look-handler' }) 6 + 7 + export async function handleLookEvent(evt: NormalizedEvent, db: Database): Promise<void> { 8 + if (evt.collection !== 'so.sprk.feed.look') { 9 + return 10 + } 11 + 12 + if (evt.event === 'create' || evt.event === 'update') { 13 + await handleCreateOrUpdate(evt, db) 14 + return 15 + } 16 + 17 + if (evt.event === 'delete') { 18 + await handleDelete(evt, db) 19 + return 20 + } 21 + } 22 + 23 + async function handleCreateOrUpdate(evt: NormalizedEvent, db: Database): Promise<void> { 24 + const now = new Date() 25 + const record = evt.record 26 + 27 + if (!record) { 28 + logger.warn({ uri: evt.uri }, 'Look event missing record data') 29 + return 30 + } 31 + 32 + logger.info({ 33 + did: evt.did, 34 + handle: evt.handle, 35 + collection: evt.collection, 36 + uri: evt.uri, 37 + }, 'Processing look event') 38 + 39 + try { 40 + const lookData = { 41 + uri: evt.uri, 42 + subject: { 43 + uri: record.subject.uri, 44 + cid: record.subject.cid 45 + }, 46 + authorDid: evt.did, 47 + authorHandle: evt.handle || 'unknown', 48 + createdAt: record.createdAt, 49 + indexedAt: now.toISOString(), 50 + cid: evt.commit.cid 51 + } 52 + 53 + await db.models.Look.findOneAndUpdate( 54 + { uri: evt.uri }, 55 + lookData, 56 + { upsert: true, new: true } 57 + ) 58 + 59 + logger.info( 60 + { uri: evt.uri }, 61 + 'Successfully saved look to database' 62 + ) 63 + } catch (error) { 64 + logger.error( 65 + { error, uri: evt.uri }, 66 + 'Failed to save look to database' 67 + ) 68 + } 69 + } 70 + 71 + async function handleDelete(evt: NormalizedEvent, db: Database): Promise<void> { 72 + try { 73 + const result = await db.models.Look.deleteOne({ uri: evt.uri }) 74 + 75 + if (result.deletedCount > 0) { 76 + logger.info({ uri: evt.uri }, 'Successfully removed look from database') 77 + return 78 + } 79 + 80 + logger.warn({ uri: evt.uri }, 'Look not found in database for deletion') 81 + } catch (error) { 82 + logger.error({ error, uri: evt.uri }, 'Failed to delete look from database') 83 + } 84 + }