serve hosts

This commit is contained in:
Arnas Udovic 2025-06-23 08:11:14 +03:00
parent a367666360
commit fd218bea53
3 changed files with 114 additions and 8 deletions

43
db.go
View file

@ -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
}

Binary file not shown.

79
main.go
View file

@ -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})
}