2021-04-07 17:31:23 +02:00
|
|
|
|
2021-04-09 18:04:04 +02:00
|
|
|
package recv
|
2021-04-07 17:31:23 +02:00
|
|
|
|
|
|
|
import (
|
2021-04-09 10:12:14 +02:00
|
|
|
"encoding/json"
|
2021-04-09 18:04:04 +02:00
|
|
|
"brainbaking.com/go-jamming/app/mf"
|
|
|
|
"brainbaking.com/go-jamming/common"
|
|
|
|
"brainbaking.com/go-jamming/rest"
|
2021-04-09 10:12:14 +02:00
|
|
|
"io/fs"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
2021-04-07 17:31:23 +02:00
|
|
|
|
|
|
|
"github.com/rs/zerolog/log"
|
2021-04-08 12:50:15 +02:00
|
|
|
"willnorris.com/go/microformats"
|
2021-04-07 17:31:23 +02:00
|
|
|
)
|
|
|
|
|
2021-04-08 16:37:04 +02:00
|
|
|
|
2021-04-08 09:54:47 +02:00
|
|
|
// used as a "class" to iject dependencies, just to be able to test. Do NOT like htis.
|
|
|
|
// Is there a better way? e.g. in validate, I just pass rest.Client as an arg. Not great either.
|
2021-04-09 12:40:37 +02:00
|
|
|
type Receiver struct {
|
|
|
|
RestClient rest.Client
|
|
|
|
Conf *common.Config
|
2021-04-08 09:54:47 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) Receive(wm mf.Mention) {
|
2021-04-09 12:40:37 +02:00
|
|
|
log.Info().Str("Webmention", wm.String()).Msg("OK: looks valid")
|
|
|
|
body, geterr := recv.RestClient.GetBody(wm.Source)
|
2021-04-07 17:31:23 +02:00
|
|
|
|
|
|
|
if geterr != nil {
|
2021-04-09 12:40:37 +02:00
|
|
|
log.Warn().Str("source", wm.Source).Msg(" ABORT: invalid url")
|
2021-04-08 09:54:47 +02:00
|
|
|
recv.deletePossibleOlderWebmention(wm)
|
2021-04-07 17:31:23 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-08 09:54:47 +02:00
|
|
|
recv.processSourceBody(body, wm)
|
2021-04-07 17:31:23 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) deletePossibleOlderWebmention(wm mf.Mention) {
|
|
|
|
os.Remove(wm.AsPath(recv.Conf))
|
2021-04-07 17:31:23 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 16:37:04 +02:00
|
|
|
func getHEntry(data *microformats.Data) *microformats.Microformat {
|
|
|
|
for _, itm := range data.Items {
|
|
|
|
if common.Includes(itm.Type, "h-entry") {
|
|
|
|
return itm
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) processSourceBody(body string, wm mf.Mention) {
|
2021-04-09 12:40:37 +02:00
|
|
|
if !strings.Contains(body, wm.Target) {
|
|
|
|
log.Warn().Str("target", wm.Target).Msg("ABORT: no mention of target found in html src of source!")
|
2021-04-08 12:50:15 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
data := microformats.Parse(strings.NewReader(body), wm.SourceUrl())
|
2021-04-09 12:40:37 +02:00
|
|
|
indieweb := recv.convertBodyToIndiewebData(body, wm, getHEntry(data))
|
|
|
|
|
|
|
|
recv.saveWebmentionToDisk(wm, indieweb)
|
2021-04-09 14:21:25 +02:00
|
|
|
log.Info().Str("file", wm.AsPath(recv.Conf)).Msg("OK: Webmention processed.")
|
2021-04-09 12:40:37 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) convertBodyToIndiewebData(body string, wm mf.Mention, hEntry *microformats.Microformat) *mf.IndiewebData {
|
2021-04-08 16:37:04 +02:00
|
|
|
if hEntry == nil {
|
2021-04-09 12:40:37 +02:00
|
|
|
return recv.parseBodyAsNonIndiewebSite(body, wm)
|
2021-04-08 16:37:04 +02:00
|
|
|
}
|
2021-04-09 12:40:37 +02:00
|
|
|
return recv.parseBodyAsIndiewebSite(hEntry, wm)
|
2021-04-08 16:37:04 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) saveWebmentionToDisk(wm mf.Mention, indieweb *mf.IndiewebData) {
|
2021-04-09 10:12:14 +02:00
|
|
|
jsonData, jsonErr := json.Marshal(indieweb)
|
|
|
|
if jsonErr != nil {
|
2021-04-09 12:40:37 +02:00
|
|
|
log.Err(jsonErr).Msg("Unable to serialize Webmention into JSON")
|
2021-04-09 10:12:14 +02:00
|
|
|
}
|
2021-04-09 14:21:25 +02:00
|
|
|
err := ioutil.WriteFile(wm.AsPath(recv.Conf), jsonData, fs.ModePerm)
|
2021-04-09 10:12:14 +02:00
|
|
|
if err != nil {
|
2021-04-09 12:40:37 +02:00
|
|
|
log.Err(err).Msg("Unable to save Webmention to disk")
|
2021-04-09 10:12:14 +02:00
|
|
|
}
|
2021-04-08 16:37:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO I'm smelling very unstable code, apply https://golang.org/doc/effective_go#recover here?
|
|
|
|
// see https://github.com/willnorris/microformats/blob/main/microformats.go
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) parseBodyAsIndiewebSite(hEntry *microformats.Microformat, wm mf.Mention) *mf.IndiewebData {
|
|
|
|
name := mf.Str(hEntry, "name")
|
|
|
|
pic := mf.Str(mf.Prop(hEntry, "author"), "photo")
|
|
|
|
mfType := mf.DetermineType(hEntry)
|
2021-04-08 16:37:04 +02:00
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
return &mf.IndiewebData{
|
2021-04-09 10:12:14 +02:00
|
|
|
Name: name,
|
2021-04-09 14:21:25 +02:00
|
|
|
Author: mf.IndiewebAuthor{
|
|
|
|
Name: mf.DetermineAuthorName(hEntry),
|
2021-04-09 10:12:14 +02:00
|
|
|
Picture: pic,
|
2021-04-08 16:37:04 +02:00
|
|
|
},
|
2021-04-09 14:21:25 +02:00
|
|
|
Content: mf.DetermineContent(hEntry),
|
|
|
|
Url: mf.DetermineUrl(hEntry, wm.Source),
|
|
|
|
Published: mf.DeterminePublishedDate(hEntry, recv.Conf.UtcOffset),
|
2021-04-09 12:40:37 +02:00
|
|
|
Source: wm.Source,
|
|
|
|
Target: wm.Target,
|
2021-04-09 10:12:14 +02:00
|
|
|
IndiewebType: mfType,
|
2021-04-08 16:37:04 +02:00
|
|
|
}
|
2021-04-09 10:12:14 +02:00
|
|
|
}
|
|
|
|
|
2021-04-09 14:21:25 +02:00
|
|
|
func (recv *Receiver) parseBodyAsNonIndiewebSite(body string, wm mf.Mention) *mf.IndiewebData {
|
2021-04-09 10:12:14 +02:00
|
|
|
r := regexp.MustCompile(`<title>(.*?)<\/title>`)
|
|
|
|
titleMatch := r.FindStringSubmatch(body)
|
2021-04-09 12:40:37 +02:00
|
|
|
title := wm.Source
|
2021-04-09 10:12:14 +02:00
|
|
|
if titleMatch != nil {
|
|
|
|
title = titleMatch[1]
|
|
|
|
}
|
2021-04-09 14:21:25 +02:00
|
|
|
return &mf.IndiewebData{
|
|
|
|
Author: mf.IndiewebAuthor{
|
2021-04-09 12:40:37 +02:00
|
|
|
Name: wm.Source,
|
2021-04-09 10:12:14 +02:00
|
|
|
},
|
|
|
|
Name: title,
|
|
|
|
Content: title,
|
2021-04-09 14:21:25 +02:00
|
|
|
Published: mf.PublishedNow(recv.Conf.UtcOffset),
|
2021-04-09 12:40:37 +02:00
|
|
|
Url: wm.Source,
|
2021-04-09 10:12:14 +02:00
|
|
|
IndiewebType: "mention",
|
2021-04-09 12:40:37 +02:00
|
|
|
Source: wm.Source,
|
|
|
|
Target: wm.Target,
|
2021-04-09 10:12:14 +02:00
|
|
|
}
|
2021-04-07 17:31:23 +02:00
|
|
|
}
|