Skip to content

cvanloo/gowebmention

Repository files navigation

Webmention library and service implementation in Go

This package can be used either as a standalone application or included as a library in your own projects.

go get github.com/cvanloo/gowebmention

Import it:

import webmention "github.com/cvanloo/gowebmention"

Send webmentions

go build cmd/mentioner/main.go -o mentioner
./mentioner <source> <target> [<targets>...]

Use as a library

Sending webmentions can be done through a WebMentionSender.

sender := webmention.NewSender()
sender.Update(source, pastMentions, currentMentions)
// source: the url for which you want to send mentions
// pastMentions: if you have sent mentions for the same url before, this list should include all targets mentioned the last time
//               otherwise you can leave the list empty or nil
// currentMentions: all targets that the source is currently mentioning

If you are sending updates for a now deleted source, it is your responsibility to ensure that the source is returning 410 Gone, optionally returning a tombstone representation of the old source as the response body.

Also note that the library does not persist anything. It is on you to remember pastMentions.

To receive webmentions setup an http endpoint and get the processing goroutine going. Also register one or more notifiers, with your custom logic describing how to react to a mention.

receiver := webmention.NewReceiver(
  webmention.WithNotifier(
    // your custom handlers
    LogMentions,
    SaveMentionsToDB,
    NotifyOnMatrix,
    NotifyByEMail,
  ),
)

// goroutine asynchronously validates and processes received webmentions
// webmentions that pass validation are passed on to the listeners
go receiver.ProcessMentions()

http.Handle("/api/webmention", receiver) // register webmention endpoint
http.ListenAndServe(":8080", nil)

For a more comprehensive example, including how to cleanly shutdown the receiver, look at the example implementation.

Notifiers need to implement the Notifier interface, which defines a single Receive method.

type MentionLogger struct{}
func (MentionLogger) Receive(mention webmention.Mention) {
  slog.Info("received mention", "mention", mention)
}
var LogMentions MentionLogger

Run as a service

Sending Webmentions

Mentioner can be run as a daemon to listen for commands on a socket.

cd cmd/mentioner
go build .
sudo cp mentioner /usr/local/bin/
sudo cp mentioner.service mentioner.socket /etc/systemd/system/
sudo systemctl start mentioner.socket

Something managing a source, eg., a blogging software, can send a command through the socket, instructing the Sender to send out webmentions.

socat - UNIX-CONNECT:/var/run/mentioner.socket
{"mentions":[{"source":"https://example.com/blog.html","past_targets":[],"current_targets":["https://example.com/some_other_blog.html"]}]}

A command has the following JSON structure:

{
  "mentions": [
    {
      "source": "<source 1 url>",
      "past_targets": [
        "<target 1 url>",
        "<target 2 url>",
        "<target ... url>"
      ],
      "current_targets": [
        "<target 1 url>",
        "<target 2 url>",
        "<target ... url>"
      ]
    },
    {
      "source": "<source 2 url>",
      "past_targets": [],
      "current_targets": []
    }
  ]
}

For each of the sources, the past and current targets will be mentioned.

The daemon responds for each mention with whether it was successful or not:

{
  "statuses": [
    {
      "source": "<source 1 url>",
      "error": ""
    }
  ],
  "error": ""
}

An empty error string indicates success.

Receiving Webmentions

Mentionee is a daemon that listens to incoming Webmentions.

cd cmd/mentionee
go build .
sudo cp mentionee /usr/local/bin/
sudo cp mentionee.service /etc/systemd/system/
sudo systemctl start mentionee.service

Since it listens on a local port (per default :8080), you can configure your web server to forward requests to it.

location = /api/webmention {
	proxy_pass http://localhost:8080;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Don't forget to advertise your Webmention endpoint!

One way is by sending Link headers:

location ~* \.html$ {
	expires 30d;
	add_header Cache-Control public;
	add_header Link "</api/webmention>; rel=webmention";
}

Another options is to add a <link> to your blog posts:

<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="webmention" href="/api/webmention"> <!-- << advertise webmention endpoint here << -->
  </head>
  <body>
    <!-- Some super exciting blog post... -->
  </body>
</html>

About

Webmention library for Go

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages