commit - 345d2260d11d054c199c7a16e48ad84d0f068b35
commit + 519acee1bbf60fee276fd734f7a8254edd803d06
blob - c2b8a3a95b8c9a282efe093aa9f1f503c884a592
blob + 37d0c0a04d9f1e59c704a55ecb56882b4873608f
--- cmd/apserve/listen.go
+++ cmd/apserve/listen.go
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
"fmt"
"log"
"net/http"
+ "os"
"os/user"
+ "path"
"strings"
"olowe.co/apub"
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
+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,
+ }
+}