From fd218bea534742240b53ea38cf247e0bcba63d75 Mon Sep 17 00:00:00 2001 From: Arnas Udovic Date: Mon, 23 Jun 2025 08:11:14 +0300 Subject: [PATCH] serve hosts --- db.go | 43 ++++++++++++++++++++- instances-joinpeertube.db | Bin 1712128 -> 1712128 bytes main.go | 79 +++++++++++++++++++++++++++++++++++--- 3 files changed, 114 insertions(+), 8 deletions(-) diff --git a/db.go b/db.go index cbda5bd..78a3e33 100644 --- a/db.go +++ b/db.go @@ -18,6 +18,7 @@ package main import ( "database/sql" + "strconv" "time" _ "github.com/mattn/go-sqlite3" @@ -116,8 +117,8 @@ func addIndex(db *sql.DB, indexHost IndexHost) { db.Exec("INSERT INTO index_host (url, instance_url, last_fetched_at) VALUES (?, ?, '2000-01-01');", indexHost.Url, indexHost.InstanceUrl) } -func rejectHost(db *sql.DB, host string) { - db.Exec("UPDATE instances SET rejected = 1 WHERE url = ?", host) +func rejectHost(db *sql.DB, host string, reason string) { + db.Exec("UPDATE instances SET rejected = 1, reject_reason = ? WHERE url = ?", reason, host) } func getIndexHosts(db *sql.DB) []IndexHost { @@ -150,3 +151,41 @@ func addInstance(db *sql.DB, instance Instance) { db.Exec("INSERT INTO instances (url, data, created_at) VALUES (?, ?, ?);", instance.Url, instance.Data, instance.CreatedAt) } + +func getHosts(db *sql.DB, start int, count int, since string) ([]string, error) { + hosts := []string{} + query := "SELECT url FROM instances WHERE rejected = 0" + if since != "" { + query += " AND created_at > \"" + since + "\"" + } + rows, err := db.Query(query + " ORDER BY created_at DESC LIMIT ? OFFSET ?", count, start) + if err != nil { + return hosts, err + } + + for rows.Next() { + var host string + rows.Scan(&host) + hosts = append(hosts, host) + } + + return hosts, nil +} + +func getHostsTotal(db *sql.DB, since string) (int, error) { + total := "0" + query := "SELECT count(url) FROM instances WHERE rejected = 0" + if since != "" { + query += " AND created_at > \"" + since + "\"" + } + + row := db.QueryRow(query) + row.Scan(&total) + + totali, err := strconv.Atoi(total) + if err != nil { + return 0, err + } + + return totali, nil +} diff --git a/instances-joinpeertube.db b/instances-joinpeertube.db index 7a4da24d93a335f55753ad036cb669ac39f3a3a9..e4dd0b66b24a0b6f78a3d8a927b7e3393053ff13 100644 GIT binary patch delta 260 zcmZoTkkN1;V}dkq76Sw0A_!(+ny6vUn#G`(w_{_<0)CDjwmS?!nFX791a8PPDm6dV zZ-1)K2*gZ4%nZaVK+FonY(UHo#2i4(3B+7L%nigmK+Frod_c?(!~#Gp2*g4_EDXdV zKr9NxVn8gu{i(i$`~#LamOl*Bxh{y=Om`8Gtmpj0@`vRf%K?^_?Scl3JD8`-3kq;e z?-P+UVgWkMW}2v^LR9`~=0ZS4~3&V7-3t~3YT?8cSITx|~VY$b0fTd--paJ6!=IQc+0$kJk zL?n%--xHCP-F{a@QvEg;GxKBy9$$`c%#%T?TA8;`{w$d*!^I17J=a_YuDM$UnJn10 PDlkQ}Y@aJ7mCOnNP;OMM diff --git a/main.go b/main.go index 0e474ba..1febb6a 100644 --- a/main.go +++ b/main.go @@ -19,23 +19,36 @@ package main import ( "flag" "fmt" + "net/http" "net/url" + "regexp" + "strconv" "strings" "time" "github.com/gin-gonic/gin" ) +type HostColection struct { + Host string `json:"host"` +} +type HostsResponse struct { + Total int `json:"total"` + Data []HostColection `json:"data"` +} + func main() { var command string - var host string var url string var instanceUrl string + var host string + var reason string flag.StringVar(&command, "command", "", "Command to execute: index, reject, collect, serve") - flag.StringVar(&host, "host", "", "Host to reject") flag.StringVar(&url, "url", "", "Url to index hosts") flag.StringVar(&instanceUrl, "instance-url", "", "Url to fetch instance information") + flag.StringVar(&host, "host", "", "Host to reject") + flag.StringVar(&reason, "reject-reason", "", "Reject reason (optional)") flag.Parse() fmt.Println(command, host) @@ -44,9 +57,10 @@ func main() { case "index": index(url, instanceUrl) case "reject": - reject(host) + reject(host, reason) case "collect": collect() + case "serve": default: serve() } @@ -73,13 +87,13 @@ func index(url string, instanceUrl string) { } } -func reject(host string) { +func reject(host string, reason string) { host = formatHost(host) db := connectDB() defer db.Close() - rejectHost(db, host) + rejectHost(db, host, reason) fmt.Println(host, "rejected") } @@ -121,6 +135,9 @@ func collect() { } func serve() { + db := connectDB() + defer db.Close() + r := gin.Default() r.GET("/", func(c *gin.Context) { @@ -132,7 +149,53 @@ func serve() { }) r.GET("/instances/hosts", func(c *gin.Context) { - c.String(200, "pong") + start := c.DefaultQuery("start", "0") + count := c.DefaultQuery("count", "20") + since := c.DefaultQuery("since", "") + + if since != "" { + regex := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`) + if !regex.MatchString(since) { + generateErrorResponse(c, "since must be in YYYY-MM-DD format") + return + } + } + + starti, err := strconv.Atoi(start) + if err != nil { + generateErrorResponse(c, "start should be an integer") + return + } + + counti, err := strconv.Atoi(count) + if err != nil { + generateErrorResponse(c, "count should be an integer") + return + } + + hosts, err := getHosts(db, starti, counti, since) + if err != nil { + generateErrorResponse(c, "error getting hosts") + return + } + + total, err := getHostsTotal(db, since) + if err != nil { + generateErrorResponse(c, "error getting hosts") + return + } + + response := HostsResponse{ + Total: total, + } + + for _, host := range hosts { + response.Data = append(response.Data, HostColection{ + Host: host, + }) + } + + c.JSON(http.StatusOK, response) }) r.GET("/stats", func(c *gin.Context) { @@ -153,3 +216,7 @@ func formatHost(host string) string { return u.Host } + +func generateErrorResponse(c *gin.Context, err string) { + c.JSON(http.StatusBadRequest, gin.H{"error": err}) +}