more thoughts
This commit is contained in:
parent
dce1006228
commit
836a54599b
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
config.json
|
config.json
|
||||||
|
/friend
|
||||||
|
91
handlers.go
91
handlers.go
@ -7,38 +7,99 @@ import (
|
|||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type APIError struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we only have the single username to worry about, we just wrap everything up here
|
||||||
|
func UserExistsMiddleware(user string, h http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := chi.URLParam(r, "user")
|
||||||
|
if userID != user {
|
||||||
|
RespondJSON(w, APIError{Error: "account not found"}, http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RespondJSON(w http.ResponseWriter, content any, statuscode int) {
|
||||||
|
b, err := json.Marshal(content)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(statuscode)
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
func WebFingerHandler(wf *Webfinger) http.HandlerFunc {
|
func WebFingerHandler(wf *Webfinger) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
requestedResource := r.URL.Query().Get("resource")
|
requestedResource := r.URL.Query().Get("resource")
|
||||||
res, err := wf.FingerResource(requestedResource)
|
res, err := wf.FingerResource(requestedResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
RespondJSON(w, APIError{Error: "account not found"}, http.StatusNotFound)
|
||||||
w.Write([]byte(`{"error": "account not found"}`))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(res)
|
RespondJSON(w, res, http.StatusOK)
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProfileHandler(pp *ProfileProvider) http.HandlerFunc {
|
func ProfileHandler(pp *ProfileProvider) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
userID := chi.URLParam(r, "user")
|
res, err := pp.Get()
|
||||||
res, err := pp.Get(userID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
RespondJSON(w, APIError{Error: "account not found"}, http.StatusNotFound)
|
||||||
w.Write([]byte(`{"error": "account not found"}`))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(res)
|
RespondJSON(w, res, http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// client retrieves messages for user
|
||||||
|
func GetInboxHandler(streams *InMemoryStreams) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
stream, err := streams.GetActivitiesToUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
RespondJSON(w, APIError{Error: err.Error()}, http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write(b)
|
RespondJSON(w, stream, http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle incoming activities for user
|
||||||
|
func PostInboxHandler(streams *InMemoryStreams) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := streams.AddActivityToUser()
|
||||||
|
if err != nil {
|
||||||
|
RespondJSON(w, APIError{Error: err.Error()}, http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RespondJSON(w, nil, http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// other servers/clients read a user's activities
|
||||||
|
func GetOutboxHandler(streams *InMemoryStreams) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
stream, err := streams.GetActivitiesFromUser()
|
||||||
|
if err != nil {
|
||||||
|
RespondJSON(w, APIError{Error: err.Error()}, http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RespondJSON(w, stream, http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// client adds new activity for user
|
||||||
|
func PostOutboxHandler(streams *InMemoryStreams) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := streams.AddActivityFromUser()
|
||||||
|
if err != nil {
|
||||||
|
RespondJSON(w, APIError{Error: err.Error()}, http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RespondJSON(w, nil, http.StatusOK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
main.go
16
main.go
@ -8,18 +8,28 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
wf, err := NewWebfinger("dma", "hello.yetaga.in")
|
// this will be configurable in the future obviously
|
||||||
|
username := "dma"
|
||||||
|
domain := "hello.yetaga.in"
|
||||||
|
|
||||||
|
wf, err := NewWebfinger(username, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
pp, err := NewProfileProvider("hello.yetaga.in")
|
pp, err := NewProfileProvider(username, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
st := &InMemoryStreams{}
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
r.Get("/.well-known/webfinger", WebFingerHandler(wf))
|
r.Get("/.well-known/webfinger", WebFingerHandler(wf))
|
||||||
r.Get("/users/{user}", ProfileHandler(pp))
|
r.Get("/users/{user}", UserExistsMiddleware(username, ProfileHandler(pp)))
|
||||||
|
r.Get("/users/{user}/inbox", UserExistsMiddleware(username, GetInboxHandler(st)))
|
||||||
|
r.Post("/users/{user}/inbox", UserExistsMiddleware(username, PostInboxHandler(st)))
|
||||||
|
r.Get("/users/{user}/outbox", UserExistsMiddleware(username, GetOutboxHandler(st)))
|
||||||
|
r.Post("/users/{user}/outbox", UserExistsMiddleware(username, PostOutboxHandler(st)))
|
||||||
|
r.Post("/inbox", PostInboxHandler(st)) // "shared" inbox
|
||||||
|
|
||||||
log.Println("listening on http://0.0.0.0:8008")
|
log.Println("listening on http://0.0.0.0:8008")
|
||||||
err = http.ListenAndServe(":8008", r)
|
err = http.ListenAndServe(":8008", r)
|
||||||
|
14
profile.go
14
profile.go
@ -13,7 +13,7 @@ type Actor struct {
|
|||||||
PublicKey PublicKey `json:"publicKey,omitempty"`
|
PublicKey PublicKey `json:"publicKey,omitempty"`
|
||||||
|
|
||||||
Inbox string `json:"inbox,omitempty"`
|
Inbox string `json:"inbox,omitempty"`
|
||||||
Outbox string `json:"outbo,omitempty"`
|
Outbox string `json:"outbox,omitempty"`
|
||||||
Followers string `json:"followers,omitempty"`
|
Followers string `json:"followers,omitempty"`
|
||||||
Following string `json:"following,omitempty"`
|
Following string `json:"following,omitempty"`
|
||||||
|
|
||||||
@ -36,22 +36,24 @@ type PublicKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProfileProvider struct {
|
type ProfileProvider struct {
|
||||||
|
username string
|
||||||
domain string
|
domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProfileProvider(domain string) (*ProfileProvider, error) {
|
func NewProfileProvider(username, domain string) (*ProfileProvider, error) {
|
||||||
return &ProfileProvider{
|
return &ProfileProvider{
|
||||||
|
username: username,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *ProfileProvider) Get(userID string) (*Actor, error) {
|
func (pp *ProfileProvider) Get() (*Actor, error) {
|
||||||
userRoot := fmt.Sprintf("https://%s/users/%s", pp.domain, userID)
|
userRoot := fmt.Sprintf("https://%s/users/%s", pp.domain, pp.username)
|
||||||
return &Actor{
|
return &Actor{
|
||||||
ID: userRoot,
|
ID: userRoot,
|
||||||
Type: "Person",
|
Type: "Person",
|
||||||
URL: fmt.Sprintf("https://%s/@%s", pp.domain, userID),
|
URL: fmt.Sprintf("https://%s/@%s", pp.domain, pp.username),
|
||||||
Name: userID,
|
Name: pp.username,
|
||||||
Inbox: userRoot + "/inbox",
|
Inbox: userRoot + "/inbox",
|
||||||
Outbox: userRoot + "/outbox",
|
Outbox: userRoot + "/outbox",
|
||||||
Followers: userRoot + "/followers",
|
Followers: userRoot + "/followers",
|
||||||
|
36
streams.go
36
streams.go
@ -1,6 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Stream struct {
|
type Stream struct {
|
||||||
Context string `json:"@context"`
|
Context string `json:"@context"`
|
||||||
@ -27,12 +30,33 @@ type Object struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Streams struct{}
|
type InMemoryStreams struct {
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Streams) Inbox()
|
// view activities from other people directed to out user
|
||||||
|
func (s *InMemoryStreams) GetActivitiesToUser() (*Stream, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Streams) Outbox()
|
// view activities created by our user
|
||||||
|
func (s *InMemoryStreams) GetActivitiesFromUser() (*Stream, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Streams) Followers()
|
// insert activities from other people directed to our user
|
||||||
|
func (s *InMemoryStreams) AddActivityToUser() error {
|
||||||
|
return fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Streams) Followed()
|
// insert activities from our user to be dispatched
|
||||||
|
func (s *InMemoryStreams) AddActivityFromUser() error {
|
||||||
|
return fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InMemoryStreams) Followers() (*Stream, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InMemoryStreams) Followed() (*Stream, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user