Implement thread pruning based on bumped_at
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
@@ -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),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user