commit 519acee1bbf60fee276fd734f7a8254edd803d06 from: Oliver Lowe date: Wed Mar 13 01:35:32 2024 UTC cmd/apserve: implement NodeInfo 2.0 commit - 345d2260d11d054c199c7a16e48ad84d0f068b35 commit + 519acee1bbf60fee276fd734f7a8254edd803d06 blob - c2b8a3a95b8c9a282efe093aa9f1f503c884a592 blob + 37d0c0a04d9f1e59c704a55ecb56882b4873608f --- cmd/apserve/listen.go +++ cmd/apserve/listen.go @@ -166,6 +166,9 @@ func main() { acceptFor: acceptFor, } http.HandleFunc("/.well-known/webfinger", serveWebFinger) + http.Handle("/.well-known/nodeinfo", http.RedirectHandler("/nodeinfo/2.0", http.StatusFound)) + http.HandleFunc("/nodeinfo/2.0", srv.serveNodeInfo) + http.HandleFunc("/nodeinfo/2.0.json", srv.serveNodeInfo) for _, u := range acceptFor { dataDir := path.Join(u.HomeDir, "apubtest") blob - ac03c54af0a01bb2af85fe72f457d19eb2639415 blob + e6d123b274247d1feb5641f79307e092063476eb --- cmd/apserve/user.go +++ cmd/apserve/user.go @@ -5,7 +5,9 @@ import ( "fmt" "log" "net/http" + "os" "os/user" + "path" "strings" "olowe.co/apub" @@ -57,3 +59,28 @@ func serveWebFinger(w http.ResponseWriter, req *http.R log.Printf("encode webfinger response: %v", err) } } + +func (srv *server) nodeInfo() (NodeInfo, error) { + var count int + for _, user := range srv.acceptFor { + dents, err := os.ReadDir(path.Join(user.HomeDir, "apubtest/outbox")) + if err != nil { + return NodeInfo{}, fmt.Errorf("count posts in outbox: %w", err) + } + count += len(dents) + } + return NewNodeInfo("apas", "0.0.1", len(srv.acceptFor), count), nil +} + +func (srv *server) serveNodeInfo(w http.ResponseWriter, req *http.Request) { + info, err := srv.nodeInfo() + if err != nil { + log.Println("serve nodeinfo:", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(info); err != nil { + log.Println("encode nodeinfo:", err) + } +} blob - /dev/null blob + 0211664170d948005bd9d409f76b56b30e1646ea (mode 644) --- /dev/null +++ cmd/apserve/nodeinfo.go @@ -0,0 +1,40 @@ +package apub + +// NodeInfo represents... +type NodeInfo struct { + Version string `json:"version"` + Software nodeSoftware `json:"software"` + Protocols []string `json:"protocols"` + Usage nodeUsage `json:"usage"` + OpenRegistrations bool `json:"openRegistration"` +} + +type nodeSoftware struct { + Name string `json:"name"` + Version string `json:"version"` +} + +type nodeUsage struct { + Users nodeUserCounts `json:"users"` + LocalPosts int `json:"localPosts"` + LocalComments int `json:"localComments"` +} + +type nodeUserCounts struct { + Total int `json:"total"` + ActiveHalfYear int `json:"activeHalfYear"` + ActiveMonth int `json:"activetMonth"` +} + +func NewNodeInfo(name, version string, users int, posts int) NodeInfo { + return NodeInfo{ + Version: "2.0", + Software: nodeSoftware{name, version}, + Protocols: []string{"activitypub"}, + Usage: nodeUsage{ + Users: nodeUserCounts{users, users, users}, + LocalPosts: posts, + }, + OpenRegistrations: false, + } +}