tangled
alpha
login
or
join now
graham.systems
/
statusphere-react
forked from
samuel.fm/statusphere-react
0
fork
atom
the statusphere demo reworked into a vite/react app in a monorepo
0
fork
atom
overview
issues
pulls
pipelines
add cursor
samuel.fm
1 year ago
1693111a
f931711a
+51
-3
3 changed files
expand all
collapse all
unified
split
packages
appview
src
db.ts
index.ts
ingester.ts
+19
packages/appview/src/db.ts
···
13
status: Status
14
auth_session: AuthSession
15
auth_state: AuthState
0
16
}
17
18
export type Status = {
···
33
state: AuthStateJson
34
}
35
0
0
0
0
0
36
type AuthStateJson = string
37
38
type AuthSessionJson = string
···
44
const migrationProvider: MigrationProvider = {
45
async getMigrations() {
46
return migrations
0
0
0
0
0
0
0
0
0
0
0
0
0
47
},
48
}
49
···
13
status: Status
14
auth_session: AuthSession
15
auth_state: AuthState
16
+
cursor: Cursor
17
}
18
19
export type Status = {
···
34
state: AuthStateJson
35
}
36
37
+
export type Cursor = {
38
+
id: number
39
+
seq: number
40
+
}
41
+
42
type AuthStateJson = string
43
44
type AuthSessionJson = string
···
50
const migrationProvider: MigrationProvider = {
51
async getMigrations() {
52
return migrations
53
+
},
54
+
}
55
+
56
+
migrations['002'] = {
57
+
async up(db: Kysely<unknown>) {
58
+
await db.schema
59
+
.createTable('cursor')
60
+
.addColumn('id', 'integer', (col) => col.primaryKey())
61
+
.addColumn('seq', 'integer', (col) => col.notNull())
62
+
.execute()
63
+
},
64
+
async down(db: Kysely<unknown>) {
65
+
await db.schema.dropTable('cursor').execute()
66
},
67
}
68
+1
-1
packages/appview/src/index.ts
···
47
// Create the atproto utilities
48
const oauthClient = await createClient(db)
49
const baseIdResolver = createIdResolver()
50
-
const ingester = createIngester(db, baseIdResolver)
51
const resolver = createBidirectionalResolver(baseIdResolver)
52
const ctx = {
53
db,
···
47
// Create the atproto utilities
48
const oauthClient = await createClient(db)
49
const baseIdResolver = createIdResolver()
50
+
const ingester = await createIngester(db, baseIdResolver)
51
const resolver = createBidirectionalResolver(baseIdResolver)
52
const ctx = {
53
db,
+31
-2
packages/appview/src/ingester.ts
···
1
import { IdResolver } from '@atproto/identity'
2
-
import { Firehose, type Event } from '@atproto/sync'
3
import { XyzStatusphereStatus } from '@statusphere/lexicon'
4
import pino from 'pino'
5
6
import type { Database } from '#/db'
7
8
-
export function createIngester(db: Database, idResolver: IdResolver) {
9
const logger = pino({ name: 'firehose ingestion' })
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
10
return new Firehose({
11
idResolver,
0
12
handleEvent: async (evt: Event) => {
13
// Watch for write events
14
if (evt.event === 'create' || evt.event === 'update') {
···
1
import { IdResolver } from '@atproto/identity'
2
+
import { Firehose, MemoryRunner, type Event } from '@atproto/sync'
3
import { XyzStatusphereStatus } from '@statusphere/lexicon'
4
import pino from 'pino'
5
6
import type { Database } from '#/db'
7
8
+
export async function createIngester(db: Database, idResolver: IdResolver) {
9
const logger = pino({ name: 'firehose ingestion' })
10
+
11
+
const cursor = await db
12
+
.selectFrom('cursor')
13
+
.where('id', '=', 1)
14
+
.select('seq')
15
+
.executeTakeFirst()
16
+
17
+
logger.info(`start cursor: ${cursor?.seq}`)
18
+
19
+
// For throttling cursor writes
20
+
let lastCursorWrite = 0
21
+
22
+
const runner = new MemoryRunner({
23
+
startCursor: cursor?.seq || undefined,
24
+
setCursor: async (seq) => {
25
+
const now = Date.now()
26
+
27
+
if (now - lastCursorWrite >= 10000) {
28
+
lastCursorWrite = now
29
+
await db
30
+
.updateTable('cursor')
31
+
.set({ seq })
32
+
.where('id', '=', 1)
33
+
.execute()
34
+
}
35
+
},
36
+
})
37
+
38
return new Firehose({
39
idResolver,
40
+
runner,
41
handleEvent: async (evt: Event) => {
42
// Watch for write events
43
if (evt.event === 'create' || evt.event === 'update') {