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