Add thread support
This commit is contained in:
parent
e49948777d
commit
4ebfcd27f1
229
server.go
229
server.go
|
@ -38,6 +38,11 @@ type Account struct {
|
|||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type Thread struct {
|
||||
Ancestors []Blog `json:"ancestors"`
|
||||
Descendants []Blog `json:"descendants"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
config := getConfig()
|
||||
|
||||
|
@ -150,8 +155,10 @@ func handleConn(conn *tls.Conn, baseURL, title, home_message string) {
|
|||
return
|
||||
}
|
||||
|
||||
// skip first '/'
|
||||
path = path[1:]
|
||||
|
||||
// home
|
||||
if path == "" {
|
||||
_, err = fmt.Fprintf(conn, "20 text/gemini\r\n# " + title + "\n\n" + home_message)
|
||||
if err != nil {
|
||||
|
@ -161,21 +168,54 @@ func handleConn(conn *tls.Conn, baseURL, title, home_message string) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = strconv.ParseUint(path, 10, 64)
|
||||
if err != nil {
|
||||
log.Println("invalid request: %s", err)
|
||||
_, err = fmt.Fprintf(conn, "59 Can't parse request\r\n")
|
||||
// profile
|
||||
if strings.HasPrefix(path, "profile/") {
|
||||
// skip prefix
|
||||
path = path[8:]
|
||||
_, err = strconv.ParseUint(path, 10, 64)
|
||||
if err != nil {
|
||||
log.Println("send error: %s", err)
|
||||
log.Println("invalid request: %s", err)
|
||||
_, err = fmt.Fprintf(conn, "59 Can't parse request\r\n")
|
||||
if err != nil {
|
||||
log.Println("send error: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Received request for account " + path)
|
||||
|
||||
printProfile(conn, baseURL, path)
|
||||
} /* thread */ else if strings.HasPrefix(path, "thread/") {
|
||||
// skip prefix
|
||||
path = path[7:]
|
||||
|
||||
_, err = strconv.ParseUint(path, 10, 64)
|
||||
if err != nil {
|
||||
log.Println("invalid request: %s", err)
|
||||
_, err = fmt.Fprintf(conn, "59 Can't parse request\r\n")
|
||||
if err != nil {
|
||||
log.Println("send error: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Received request for thread " + path)
|
||||
|
||||
printThread(conn, baseURL, path)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(conn, "59 Invalid request\r\n")
|
||||
if err != nil {
|
||||
log.Println("send: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Received request for account " + path)
|
||||
|
||||
account, err := getAccount(baseURL, path)
|
||||
blogs := getBlog(baseURL, path)
|
||||
func printProfile(conn *tls.Conn, baseURL, profileID string) {
|
||||
account, err := getAccount(baseURL, profileID)
|
||||
blogs := getBlog(baseURL, profileID)
|
||||
|
||||
if err != nil || blogs == nil {
|
||||
_, err = fmt.Fprintf(conn, "40 Remote mastodon instance failed\r\n")
|
||||
|
@ -195,27 +235,7 @@ func handleConn(conn *tls.Conn, baseURL, title, home_message string) {
|
|||
for _, blog := range blogs {
|
||||
date := "\n```\n* Posted at " + blog.Date + " *\n```\n"
|
||||
|
||||
text := blog.Content + "\n"
|
||||
text = strings.ReplaceAll(text, "<p>", "")
|
||||
text = strings.ReplaceAll(text, "</p>", "\n\n")
|
||||
text = strings.ReplaceAll(text, "<br />", "\n")
|
||||
text = strings.ReplaceAll(text, "</a>", "")
|
||||
text = strings.ReplaceAll(text, "</span>", "")
|
||||
regexString := "<a( [^>]*)?>"
|
||||
regex, err := regexp.Compile(regexString)
|
||||
if err != nil {
|
||||
log.Println("regex: %s", err)
|
||||
return
|
||||
}
|
||||
text = regex.ReplaceAllLiteralString(text, "")
|
||||
regexString = "<span( [^>]*)?>"
|
||||
regex, err = regexp.Compile(regexString)
|
||||
if err != nil {
|
||||
log.Println("regex: %s", err)
|
||||
return
|
||||
}
|
||||
text = regex.ReplaceAllLiteralString(text, "")
|
||||
text = html.UnescapeString(text)
|
||||
text := removeHTMLTags(blog.Content) + "\n"
|
||||
|
||||
_, err = fmt.Fprintf(conn, date + text)
|
||||
if err != nil {
|
||||
|
@ -231,6 +251,91 @@ func handleConn(conn *tls.Conn, baseURL, title, home_message string) {
|
|||
}
|
||||
}
|
||||
|
||||
func printThread(conn *tls.Conn, baseURL, tootID string) {
|
||||
originalToot, err := getToot(baseURL, tootID)
|
||||
if err != nil {
|
||||
_, err = fmt.Fprintf(conn, "40 Remote mastodon instance failed\r\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
thread, err := getThread(baseURL, tootID)
|
||||
if err != nil {
|
||||
_, err = fmt.Fprintf(conn, "40 Remote mastodon instance failed\r\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Print header
|
||||
_, err = fmt.Fprintf(conn, "20 text/gemini\r\n# Ancestors\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Print each anscestor
|
||||
for _, toot := range thread.Ancestors {
|
||||
_, err = fmt.Fprintf(conn, "\n```\n* Posted on " + toot.Date + " *\n```\n" + removeHTMLTags(toot.Content) + "\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Print original toot
|
||||
_, err = fmt.Fprintf(conn, "\n# Toot\n\n```\n* Posted on " + originalToot.Date + " *\n```\n" + removeHTMLTags(originalToot.Content) + "\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Print each descendant
|
||||
_, err = fmt.Fprintf(conn, "\n# Descendants\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
for _, toot := range thread.Descendants {
|
||||
_, err = fmt.Fprintf(conn, "\n```\n* Posted on " + toot.Date + " *\n```\n" + removeHTMLTags(toot.Content) + "\n")
|
||||
if err != nil {
|
||||
log.Println("handleConn: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeHTMLTags(content string) string {
|
||||
text := strings.ReplaceAll(content, "<p>", "")
|
||||
text = strings.ReplaceAll(text, "</p>", "\n\n")
|
||||
text = strings.ReplaceAll(text, "<br />", "\n")
|
||||
text = strings.ReplaceAll(text, "<br>", "\n")
|
||||
text = strings.ReplaceAll(text, "</a>", "")
|
||||
text = strings.ReplaceAll(text, "</span>", "")
|
||||
regexString := "<a( [^>]*)?>"
|
||||
regex, err := regexp.Compile(regexString)
|
||||
if err != nil {
|
||||
log.Println("regex: %s", err)
|
||||
return ""
|
||||
}
|
||||
text = regex.ReplaceAllLiteralString(text, "")
|
||||
regexString = "<span( [^>]*)?>"
|
||||
regex, err = regexp.Compile(regexString)
|
||||
if err != nil {
|
||||
log.Println("regex: %s", err)
|
||||
return ""
|
||||
}
|
||||
text = regex.ReplaceAllLiteralString(text, "")
|
||||
text = html.UnescapeString(text)
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
func getBlog(baseURL, account string) []Blog {
|
||||
if baseURL == "" || account == "" {
|
||||
log.Println("baseURL or account is empty")
|
||||
|
@ -291,3 +396,65 @@ func getAccount(baseURL, accountId string) (Account, error) {
|
|||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func getToot(baseURL, tootId string) (Blog, error) {
|
||||
if baseURL == "" || tootId == "" {
|
||||
log.Println("baseURL or tootID is empty")
|
||||
return Blog{}, fmt.Errorf("baseURL or tootID is empty")
|
||||
}
|
||||
|
||||
resp, err := http.Get(baseURL + "/api/v1/statuses/" + tootId)
|
||||
if err != nil {
|
||||
log.Println("Mastodon API request: %s", err)
|
||||
return Blog{}, fmt.Errorf("API request failed")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.Println("Mastodon API response: %s", resp.Status)
|
||||
return Blog{}, fmt.Errorf("API response is not 200")
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("Mastodon response body: %s", err)
|
||||
return Blog{}, fmt.Errorf("Failed to read response")
|
||||
}
|
||||
|
||||
var toot Blog
|
||||
json.Unmarshal(body, &toot)
|
||||
|
||||
return toot, nil
|
||||
}
|
||||
|
||||
func getThread(baseURL, tootId string) (Thread, error) {
|
||||
if baseURL == "" || tootId == "" {
|
||||
log.Println("baseURL or tootID is empty")
|
||||
return Thread{}, fmt.Errorf("baseURL or tootID is empty")
|
||||
}
|
||||
|
||||
resp, err := http.Get(baseURL + "/api/v1/statuses/" + tootId + "/context")
|
||||
if err != nil {
|
||||
log.Println("Mastodon API request: %s", err)
|
||||
return Thread{}, fmt.Errorf("API request failed")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.Println("Mastodon API response: %s", resp.Status)
|
||||
return Thread{}, fmt.Errorf("API response is not 200")
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("Mastodon response body: %s", err)
|
||||
return Thread{}, fmt.Errorf("Failed to read response")
|
||||
}
|
||||
|
||||
var thread Thread
|
||||
json.Unmarshal(body, &thread)
|
||||
|
||||
return thread, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue