WIP: working on printing paged outbox

master
Michael Demetriou 2019-09-11 21:17:21 +03:00
parent 47dfecbeb3
commit 29ad8059ba
3 changed files with 112 additions and 52 deletions

View File

@ -482,7 +482,7 @@ func (a *Actor) appendToOutbox(iri string) (err error) {
// create outbox file if it doesn't exist // create outbox file if it doesn't exist
var outbox *os.File var outbox *os.File
outboxFilePath := storage + slash + "actors" + slash + a.name + slash + "outbox" outboxFilePath := storage + slash + "actors" + slash + a.name + slash + "outbox.txt"
outbox, err = os.OpenFile(outboxFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) outbox, err = os.OpenFile(outboxFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
log.Info("Cannot create or open outbox file") log.Info("Cannot create or open outbox file")
@ -491,7 +491,7 @@ func (a *Actor) appendToOutbox(iri string) (err error) {
} }
defer outbox.Close() defer outbox.Close()
outbox.Write([]byte(iri)) outbox.Write([]byte(iri + "\n"))
return nil return nil
} }

View File

@ -82,68 +82,79 @@ func Serve() {
var outboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { var outboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/activity+json; charset=utf-8") w.Header().Set("content-type", "application/activity+json; charset=utf-8")
username := mux.Vars(r)["actor"] // get the needed actor from the muxer (url variable {actor} below) pageStr := r.URL.Query().Get("page") // get the page from the query string as string
actor, err := LoadActor(username) // load the actor from disk username := mux.Vars(r)["actor"] // get the needed actor from the muxer (url variable {actor} below)
if err != nil { // either actor requested has illegal characters or actor, err := LoadActor(username) // load the actor from disk
if err != nil { // either actor requested has illegal characters or
log.Info("Can't load local actor") // we don't have such actor log.Info("Can't load local actor") // we don't have such actor
fmt.Fprintf(w, "404 - page not found") fmt.Fprintf(w, "404 - page not found")
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
var response string var response []byte
if r.URL.Query().Get("page") == "" { if pageStr == "" {
//TODO fix total items //TODO fix total items
response = `{ response = []byte(`{
"@context" : "https://www.w3.org/ns/activitystreams", "@context" : "https://www.w3.org/ns/activitystreams",
"first" : "` + baseURL + actor.name + `/outbox?page=true", "first" : "` + baseURL + actor.name + `/outbox?page=true",
"id" : "` + baseURL + actor.name + `/outbox", "id" : "` + baseURL + actor.name + `/outbox",
"last" : "` + baseURL + actor.name + `/outbox?min_id=0&page=true", "last" : "` + baseURL + actor.name + `/outbox?min_id=0&page=1",
"totalItems" : 10, "totalItems" : 10,
"type" : "OrderedCollection" "type" : "OrderedCollection"
}` }`)
} else { } else {
content := "Hello, World!" page, err := strconv.Atoi(pageStr) // get page number from query string
id := "asfdasdf" if err != nil {
response = ` log.Info("Page number not a number, assuming 1")
{ page = 1
"@context" : "https://www.w3.org/ns/activitystreams", }
"id" : "` + baseURL + actor.name + `/outbox?min_id=0&page=true", postsPerPage := 100
"next" : "` + baseURL + actor.name + `/outbox?max_id=99524642494530460&page=true", filename := storage + slash + "actors" + slash + actor.name + slash + "outbox.txt"
"orderedItems" :[ lines, err := ReadLines(filename, (page-1)*postsPerPage, page*(postsPerPage+1)-1)
{ if err != nil {
"actor" : "https://` + baseURL + actor.name + `", log.Info("Can't read outbox file")
"cc" : [ log.Info(err)
"https://` + baseURL + actor.name + `/followers" return
], }
"id" : "https://` + baseURL + actor.name + `/` + id + `", responseMap := make(map[string]interface{})
"object" : { responseMap["@context"] = context()
"attributedTo" : "https://` + baseURL + actor.name + `", responseMap["id"] = baseURL + actor.name + "/outbox?page=" + pageStr
"cc" : [ totalLines, err := lineCounter(filename)
"https://` + baseURL + actor.name + `/followers" if err != nil {
], log.Info("The file was deleted? It was okay a few lines above. Wtf?")
"content" : "` + content + `", log.Info(err)
"id" : "https://` + baseURL + actor.name + `/` + id + `", return
"inReplyTo" : null, }
"published" : "2019-08-26T16:25:26Z", if page*postsPerPage < totalLines {
"to" : [ responseMap["next"] = baseURL + actor.name + "/outbox?page=" + strconv.Itoa(page+1)
"https://www.w3.org/ns/activitystreams#Public" }
], if page > 1 {
"type" : "Note", responseMap["prev"] = baseURL + actor.name + "/outbox?page=" + strconv.Itoa(page-1)
"url" : "https://` + baseURL + actor.name + `/` + id + `" }
}, responseMap["partOf"] = baseURL + actor.name + "/outbox"
"published" : "2019-08-26T16:25:26Z", responseMap["type"] = "OrderedCollectionPage"
"to" : [
"https://www.w3.org/ns/activitystreams#Public" orderedItems := make(map[string]interface{})
],
"type" : "Create" for item := range lines {
} // read the line
], // parse the hash
"partOf" : "` + baseURL + actor.name + `/outbox", // build the filename
"prev" : "` + baseURL + actor.name + `/outbox?min_id=99982453036184436&page=true", // open the file
"type" : "OrderedCollectionPage" // unmarshal
}` // append to orderedItems
}
responseMap["orderedItems"] = orderedItems
response, err = json.Marshal(responseMap)
if err != nil {
log.Info("can't marshal map to json")
log.Info(err)
return
}
} }
w.Write([]byte(response)) w.Write(response)
} }
var inboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { var inboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
@ -200,7 +211,6 @@ func Serve() {
accept["object"] = activity accept["object"] = activity
accept["type"] = "Accept" accept["type"] = "Accept"
if err != nil { if err != nil {
log.Info("Couldn't retrieve remote actor info, maybe server is down?") log.Info("Couldn't retrieve remote actor info, maybe server is down?")
log.Info(err) log.Info(err)

View File

@ -1,7 +1,11 @@
package activityserve package activityserve
import ( import (
"bufio"
"io"
"net/http" "net/http"
"os"
// "net/url" // "net/url"
"bytes" "bytes"
"encoding/json" "encoding/json"
@ -50,3 +54,49 @@ func FormatHeaders(header http.Header) string {
func context() [1]string { func context() [1]string {
return [1]string{"https://www.w3.org/ns/activitystreams"} return [1]string{"https://www.w3.org/ns/activitystreams"}
} }
// ReadLines reads specific lines from a file and returns them as
// an array of strings
func ReadLines(filename string, from, to int) (lines []string, err error) {
lines = make([]string, to-from)
reader, err := os.Open(filename)
if err != nil {
log.Info("could not read file")
log.Info(err)
return
}
sc := bufio.NewScanner(reader)
line := 0
for sc.Scan() {
line++
if line >= from && line <= to {
lines = append(lines, sc.Text())
}
}
return lines, nil
}
func lineCounter(filename string) (int, error) {
r, err := os.Open(filename)
if err != nil {
log.Info("could not read file")
log.Info(err)
return 0, nil
}
buf := make([]byte, 32*1024)
count := 0
lineSep := []byte{'\n'}
for {
c, err := r.Read(buf)
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
return count, nil
case err != nil:
return count, err
}
}
}