A community based topic aggregation platform built on atproto
1//go:build ignore
2
3package main
4
5import (
6 "database/sql"
7 "fmt"
8 "log"
9 "math/rand"
10 "time"
11
12 _ "github.com/lib/pq"
13)
14
15const (
16 postURI = "at://did:plc:hcuo3qx2lr7h7dquusbeobht/social.coves.community.post/3m56mowhbuk22"
17 postCID = "bafyreibml4midgt7ojq7dnabnku5ikzro4erfvdux6mmiqeat7pci2gy4u"
18 communityDID = "did:plc:hcuo3qx2lr7h7dquusbeobht"
19)
20
21type User struct {
22 DID string
23 Handle string
24 Name string
25}
26
27type Comment struct {
28 URI string
29 CID string
30 RKey string
31 DID string
32 RootURI string
33 RootCID string
34 ParentURI string
35 ParentCID string
36 Content string
37 CreatedAt time.Time
38}
39
40// Escalating conversation between two users
41var deepThreadConversation = []string{
42 "Wait, I just realized - if they both get suspended for this, their fantasy managers are SCREWED 😂",
43 "Bro imagine being in a league where you have BOTH Duren brothers and they both get suspended for fighting EACH OTHER",
44 "That's actually hilarious. 'Dear commissioner, my players got suspended for fighting... with each other'",
45 "The fantasy implications are wild. Do you get negative points for your players fighting your other players? 🤔",
46 "New fantasy category: Family Feuds. Duren brothers leading the league in FFD (Family Fight Disqualifications)",
47 "I'm dying 💀 FFD should absolutely be a stat. The Morris twins would've been unstoppable in that category",
48 "Don't forget the Plumlees! Those boys used to scrap in college practices. FFD Hall of Famers",
49 "Okay but serious question: has there EVER been brothers fighting each other in an NBA game before this? This has to be a first",
50 "I've been watching the NBA for 30 years and I can't think of a single time. This might genuinely be historic family beef",
51 "So we're witnessing NBA history right now. Not the good kind, but history nonetheless. Their mom is SO proud 😂",
52}
53
54var userHandles = []string{
55 "deep_thread_guy_1.bsky.social",
56 "deep_thread_guy_2.bsky.social",
57}
58
59func generateTID() string {
60 now := time.Now().UnixMicro()
61 return fmt.Sprintf("%d%04d", now, rand.Intn(10000))
62}
63
64func createUser(db *sql.DB, handle string, idx int) (*User, error) {
65 did := fmt.Sprintf("did:plc:deepthread%d%d", time.Now().Unix(), idx)
66 user := &User{
67 DID: did,
68 Handle: handle,
69 Name: handle,
70 }
71
72 query := `
73 INSERT INTO users (did, handle, pds_url, created_at, updated_at)
74 VALUES ($1, $2, $3, NOW(), NOW())
75 ON CONFLICT (did) DO NOTHING
76 `
77
78 _, err := db.Exec(query, user.DID, user.Handle, "http://localhost:3001")
79 if err != nil {
80 return nil, fmt.Errorf("failed to create user: %w", err)
81 }
82
83 log.Printf("Created user: %s (%s)", user.Handle, user.DID)
84 return user, nil
85}
86
87func createComment(db *sql.DB, user *User, content, parentURI, parentCID string, createdAt time.Time) (*Comment, error) {
88 rkey := generateTID()
89 uri := fmt.Sprintf("at://%s/social.coves.community.comment/%s", user.DID, rkey)
90 cid := fmt.Sprintf("bafy%s", rkey)
91
92 comment := &Comment{
93 URI: uri,
94 CID: cid,
95 RKey: rkey,
96 DID: user.DID,
97 RootURI: postURI,
98 RootCID: postCID,
99 ParentURI: parentURI,
100 ParentCID: parentCID,
101 Content: content,
102 CreatedAt: createdAt,
103 }
104
105 query := `
106 INSERT INTO comments (
107 uri, cid, rkey, commenter_did, root_uri, root_cid,
108 parent_uri, parent_cid, content, created_at, indexed_at
109 ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW())
110 ON CONFLICT (uri) DO NOTHING
111 RETURNING id
112 `
113
114 var id int64
115 err := db.QueryRow(query,
116 comment.URI, comment.CID, comment.RKey, comment.DID,
117 comment.RootURI, comment.RootCID, comment.ParentURI, comment.ParentCID,
118 comment.Content, comment.CreatedAt,
119 ).Scan(&id)
120 if err != nil {
121 return nil, fmt.Errorf("failed to create comment: %w", err)
122 }
123
124 log.Printf("Level %d: %s", getCurrentLevel(parentURI), content)
125 return comment, nil
126}
127
128func getCurrentLevel(parentURI string) int {
129 if parentURI == postURI {
130 return 1
131 }
132 // Count how many times we've nested (rough estimate)
133 return 2 // Will be incremented as we go
134}
135
136func updateCommentCount(db *sql.DB, parentURI string, isPost bool) error {
137 if isPost {
138 _, err := db.Exec(`
139 UPDATE posts
140 SET comment_count = comment_count + 1
141 WHERE uri = $1
142 `, parentURI)
143 return err
144 }
145
146 _, err := db.Exec(`
147 UPDATE comments
148 SET reply_count = reply_count + 1
149 WHERE uri = $1
150 `, parentURI)
151 return err
152}
153
154func main() {
155 dbURL := "postgres://dev_user:dev_password@localhost:5435/coves_dev?sslmode=disable"
156 db, err := sql.Open("postgres", dbURL)
157 if err != nil {
158 log.Fatalf("Failed to connect to database: %v", err)
159 }
160 defer db.Close()
161
162 if err := db.Ping(); err != nil {
163 log.Fatalf("Failed to ping database: %v", err)
164 }
165
166 log.Println("Connected to database successfully!")
167 log.Println("Creating 10-level deep comment thread...")
168
169 rand.Seed(time.Now().UnixNano())
170
171 // Create two users who will have the back-and-forth
172 user1, err := createUser(db, userHandles[0], 1)
173 if err != nil {
174 log.Fatalf("Failed to create user 1: %v", err)
175 }
176
177 user2, err := createUser(db, userHandles[1], 2)
178 if err != nil {
179 log.Fatalf("Failed to create user 2: %v", err)
180 }
181
182 baseTime := time.Now().Add(-30 * time.Minute)
183
184 // Create the 10-level deep thread
185 parentURI := postURI
186 parentCID := postCID
187 isPost := true
188
189 for i, content := range deepThreadConversation {
190 // Alternate between users
191 user := user1
192 if i%2 == 1 {
193 user = user2
194 }
195
196 createdAt := baseTime.Add(time.Duration(i*2) * time.Minute)
197
198 comment, err := createComment(db, user, content, parentURI, parentCID, createdAt)
199 if err != nil {
200 log.Fatalf("Failed to create comment at level %d: %v", i+1, err)
201 }
202
203 // Update parent's reply count
204 if err := updateCommentCount(db, parentURI, isPost); err != nil {
205 log.Printf("Warning: Failed to update comment count: %v", err)
206 }
207
208 // Set this comment as the parent for the next iteration
209 parentURI = comment.URI
210 parentCID = comment.CID
211 isPost = false
212
213 time.Sleep(10 * time.Millisecond)
214 }
215
216 log.Println("\n=== Summary ===")
217 log.Printf("Created 10-level deep comment thread")
218 log.Printf("Thread participants: %s and %s", user1.Handle, user2.Handle)
219 log.Println("Done! Check the NBACentral post for the deep thread.")
220}