From afdf8a014236452e098ab1266c9a9315824f8103 Mon Sep 17 00:00:00 2001 From: Julio Capote Date: Mon, 19 Dec 2022 10:41:43 -0500 Subject: url helpers, cgi response format --- README | 7 ------- README.md | 26 ++++++++++++++++++++++++++ TODO | 2 +- http/server.go | 2 ++ main.go | 4 +++- resources/outbox.go | 21 +++++++++------------ resources/profile.go | 9 +++------ sample-cgi-handler.sh | 13 +++++++++++-- urls/urls.go | 34 ++++++++++++++++++++++++++++++++++ 9 files changed, 89 insertions(+), 29 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100644 urls/urls.go diff --git a/README b/README deleted file mode 100644 index 2b1f7db..0000000 --- a/README +++ /dev/null @@ -1,7 +0,0 @@ -# Communique - -Communique aims to be an activitypub platform that abstracts outboxes/inboxes away from -handler implementations. - -1) handlers are defined in a config file -2) these are read into the registry which allows lookup by name or by fqdn \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c2dcd0 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Communique + +Communique aims to be an activitypub platform that abstracts outboxes/inboxes away from +handler implementations. + +1) handlers are defined in a config file +2) these are read into the registry which allows lookup by name or by fqdn + + +# CGI + +Communique uses CGI as the API between itself and your scripts. These scripts are only run **internally** and are never executed from a TCP request. + +## Response API + +Your CGI script MUST emit a valid CGI response. + +Your CGI script reponse MUST be of content type `application/activity+json`. + +Your CGI script reponse MUST be an `OrderedCollection` of ActivityStream `Object`s. + +See `sample-cgi-handler.sh` for an example + +## Processing + +Communique will iterate through this collection of objects and add them to the outbox for the handler for that script, if they have not been posted in the last hour. **(TODO make the dedupe window configurable)** \ No newline at end of file diff --git a/TODO b/TODO index 0cf7355..8c3610f 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ * CGI response API - * Array of activitystream Note's? + *DONE Array of activitystream Note's? * dedup * outbox pagination * badger GC https://dgraph.io/docs/badger/get-started/#garbage-collection diff --git a/http/server.go b/http/server.go index 5d0a689..b3d3c9b 100644 --- a/http/server.go +++ b/http/server.go @@ -39,6 +39,7 @@ func (s *Server) Start(zapWriter io.Writer) { actorParam := c.Param("actor") resource, _ := s.registry.Profile(actorParam) if resource != nil { + c.Writer.Header().Set("Content-Type", "application/activity+json") c.JSON(http.StatusOK, resource) } else { c.JSON(http.StatusNotFound, nil) @@ -68,6 +69,7 @@ func (s *Server) Start(zapWriter io.Writer) { resource, _ = s.registry.Outbox(actorParam) } if resource != nil { + c.Writer.Header().Set("Content-Type", "application/activity+json") c.JSON(http.StatusOK, resource) } else { c.JSON(http.StatusNotFound, nil) diff --git a/main.go b/main.go index fe2bb30..aa92f9f 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,9 @@ func main() { log.Debugf("Loaded TOML Config: %+v", cfg) // DB - db, err := badger.Open(badger.DefaultOptions(cfg.DbPath)) + dbOpts := badger.DefaultOptions(cfg.DbPath) + // dbOpts.Logger = log // TODO needs to adapt Warningf to Warnf + db, err := badger.Open(dbOpts) if err != nil { log.Fatal(err) } diff --git a/resources/outbox.go b/resources/outbox.go index 4dd022b..93bed92 100644 --- a/resources/outbox.go +++ b/resources/outbox.go @@ -1,23 +1,20 @@ package resources import ( - "fmt" - "net/url" - "path" - + "git.capotej.com/capotej/communique/urls" "github.com/dgraph-io/badger/v3" "github.com/go-fed/activity/streams" ) func RenderOutboxPage(name, domain string, db *badger.DB) (map[string]interface{}, error) { - id, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox") + "?page=true") + id, err := urls.UrlOutboxPage(name, domain) if err != nil { - return nil, fmt.Errorf("could not partse url: %w", err) + return nil, err } - partOf, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox")) + partOf, err := urls.UrlOutbox(name, domain) if err != nil { - return nil, fmt.Errorf("could not partse url: %w", err) + return nil, err } oc := streams.NewActivityStreamsOrderedCollectionPage() @@ -69,15 +66,15 @@ func RenderOutboxPage(name, domain string, db *badger.DB) (map[string]interface{ } func RenderOutbox(name, domain string, db *badger.DB) (map[string]interface{}, error) { - id, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox") + "?page=true") + id, err := urls.UrlOutbox(name, domain) if err != nil { - return nil, fmt.Errorf("could not partse url: %w", err) + return nil, err } - first, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox") + "?page=true") + first, err := urls.UrlOutboxPage(name, domain) if err != nil { - return nil, fmt.Errorf("could not partse url: %w", err) + return nil, err } oc := streams.NewActivityStreamsOrderedCollection() diff --git a/resources/profile.go b/resources/profile.go index b62a9c5..971b11c 100644 --- a/resources/profile.go +++ b/resources/profile.go @@ -1,17 +1,14 @@ package resources import ( - "fmt" - "net/url" - "path" - + "git.capotej.com/capotej/communique/urls" "github.com/go-fed/activity/streams" ) func RenderProfile(name, domain string) (map[string]interface{}, error) { - u, err := url.Parse(path.Join("https://", domain, "actors", name, "inbox")) + u, err := urls.UrlInbox(name, domain) if err != nil { - return nil, fmt.Errorf("could not partse url: %w", err) + return nil, err } inb := streams.NewActivityStreamsInboxProperty() diff --git a/sample-cgi-handler.sh b/sample-cgi-handler.sh index afd4ada..7cef511 100755 --- a/sample-cgi-handler.sh +++ b/sample-cgi-handler.sh @@ -1,5 +1,14 @@ #!/bin/bash -echo "Content-type: text/plain" +echo "Content-type: application/activity+json" echo "" -echo "This is a random value from bash: $RANDOM on $(date)" +echo '{ + "@context": "https://www.w3.org/ns/activitystreams", + "type": "OrderedCollection", + "totalItems": 1, + "items": [ + { + "type": "Note", + "content": "hi" + }, + ]}' exit 0 diff --git a/urls/urls.go b/urls/urls.go new file mode 100644 index 0000000..5f563a7 --- /dev/null +++ b/urls/urls.go @@ -0,0 +1,34 @@ +package urls + +import ( + "fmt" + "net/url" + "path" +) + +func UrlInbox(name, domain string) (*url.URL, error) { + u, err := url.Parse(path.Join("https://", domain, "actors", name, "inbox")) + if err != nil { + return nil, fmt.Errorf("could not build inbox url: %w", err) + } + return u, nil +} + +func UrlOutbox(name, domain string) (*url.URL, error) { + u, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox")) + if err != nil { + return nil, fmt.Errorf("could not build outbox url: %w", err) + } + return u, nil +} + +func UrlOutboxPage(name, domain string) (*url.URL, error) { + u, err := UrlOutbox(name, domain) + if err != nil { + return nil, fmt.Errorf("could not build outbox page url: %w", err) + } + q := u.Query() + q.Set("page", "true") + u.RawQuery = q.Encode() + return u, nil +} -- cgit v1.2.3