Implement thread pruning based on bumped_at

This commit is contained in:
Dominic Ferrando
2025-04-21 14:00:10 -04:00
parent 997d65707c
commit 80a0a5eb89
4 changed files with 88 additions and 14 deletions
+72
View File
@@ -2,10 +2,15 @@ package database
import ( import (
"database/sql" "database/sql"
"os"
"path"
"github.com/dominicf2001/comfychan/internal/util"
) )
type Queryer interface { type Queryer interface {
Exec(query string, args ...any) (sql.Result, error) Exec(query string, args ...any) (sql.Result, error)
Query(query string, args ...any) (*sql.Rows, error)
QueryRow(query string, args ...any) *sql.Row QueryRow(query string, args ...any) *sql.Row
} }
@@ -149,6 +154,33 @@ func PutThread(db *sql.DB, boardSlug string, subject string, body string, mediaP
return err return err
} }
row := tx.QueryRow("SELECT COUNT(*) FROM threads WHERE board_slug = ?", boardSlug)
var threadCount int
if err = row.Scan(&threadCount); err != nil {
return err
}
if threadCount > util.MAX_THREAD_COUNT {
row := tx.QueryRow(`
SELECT id FROM threads
WHERE id = (
SELECT id FROM threads
WHERE board_slug = ?
ORDER BY bumped_at ASC
LIMIT 1)`, boardSlug)
var pruneThreadId int
err := row.Scan(&pruneThreadId)
if err != nil {
return err
}
if err := DeleteThread(tx, pruneThreadId); err != nil {
return err
}
}
if err = tx.Commit(); err != nil { if err = tx.Commit(); err != nil {
return err return err
} }
@@ -187,3 +219,43 @@ func PutPost(db Queryer, boardSlug string, threadId int, body string, mediaPath
return nil return nil
} }
func DeleteThread(db Queryer, threadId int) error {
// cleanup images
rows, err := db.Query(`
SELECT media_path
FROM posts
WHERE thread_id = ?`, threadId)
if err != nil {
return err
}
defer rows.Close()
var pruneMediaPaths []string
for rows.Next() {
var pruneMediaPath string
if err := rows.Scan(&pruneMediaPath); err != nil {
return err
}
pruneMediaPaths = append(pruneMediaPaths, pruneMediaPath)
}
for _, pruneMediaPath := range pruneMediaPaths {
if err := os.Remove(path.Join(util.POST_IMG_FULL_PATH, pruneMediaPath)); err != nil && !os.IsNotExist(err) {
return err
}
if err := os.Remove(path.Join(util.POST_IMG_THUMB_PATH, pruneMediaPath)); err != nil && !os.IsNotExist(err) {
return err
}
}
// delete thread
_, err = db.Exec(`
DELETE FROM threads
WHERE id = ?`, threadId)
if err != nil {
return err
}
return nil
}
+6 -4
View File
@@ -17,11 +17,13 @@ var (
var CooldownMutex sync.Mutex var CooldownMutex sync.Mutex
// const POST_COOLDOWN = 15 * time.Second const POST_COOLDOWN = 15 * time.Second
const POST_COOLDOWN = 0 * time.Second
// const THREAD_COOLDOWN = 2 * time.Minute // const POST_COOLDOWN = 0 * time.Second
const THREAD_COOLDOWN = 0 * time.Minute
const THREAD_COOLDOWN = 2 * time.Minute
// const THREAD_COOLDOWN = 0 * time.Minute
func IsOnCooldown(ip string, m map[string]time.Time, duration time.Duration) bool { func IsOnCooldown(ip string, m map[string]time.Time, duration time.Duration) bool {
CooldownMutex.Lock() CooldownMutex.Lock()
+1 -9
View File
@@ -13,13 +13,13 @@ import (
"strings" "strings"
"github.com/disintegration/imaging" "github.com/disintegration/imaging"
"github.com/dominicf2001/comfychan/internal/database"
) )
// 10 MB memory limit // 10 MB memory limit
const FILE_MEM_LIMIT int64 = 10 << 20 const FILE_MEM_LIMIT int64 = 10 << 20
const POST_IMG_FULL_PATH = "web/static/img/posts/full" const POST_IMG_FULL_PATH = "web/static/img/posts/full"
const POST_IMG_THUMB_PATH = "web/static/img/posts/thumb" const POST_IMG_THUMB_PATH = "web/static/img/posts/thumb"
const MAX_THREAD_COUNT = 50
func EnrichPost(body string) string { func EnrichPost(body string) string {
var b strings.Builder var b strings.Builder
@@ -105,14 +105,6 @@ func SavePostFile(file *multipart.File, filename string) error {
return nil return nil
} }
func SumUniquePostIps(posts []database.Post) int {
uniqueIpHashes := map[string]bool{}
for _, post := range posts {
uniqueIpHashes[post.IpHash] = true
}
return len(uniqueIpHashes)
}
type PostImageInfo struct { type PostImageInfo struct {
Size int64 Size int64
Height int Height int
+9 -1
View File
@@ -30,6 +30,14 @@ func disableCacheInDevMode(next http.Handler) http.Handler {
}) })
} }
func SumUniquePostIps(posts []database.Post) int {
uniqueIpHashes := map[string]bool{}
for _, post := range posts {
uniqueIpHashes[post.IpHash] = true
}
return len(uniqueIpHashes)
}
func main() { func main() {
// ----------------- // -----------------
// SETUP // SETUP
@@ -244,7 +252,7 @@ func main() {
ThreadURL: fmt.Sprintf("/%s/threads/%d", slug, thread.Id), ThreadURL: fmt.Sprintf("/%s/threads/%d", slug, thread.Id),
MediaPath: op.MediaPath, MediaPath: op.MediaPath,
ReplyCount: len(posts), ReplyCount: len(posts),
IpCount: util.SumUniquePostIps(posts), IpCount: SumUniquePostIps(posts),
}) })
} }