I am trying to stream public posts from Mastodon in real-time using WebSockets and retrieving public posts using the API. However, I am encountering a issue bad handshake
error when using WebSocket.
How can I stream public posts from Mastodon in real-time using WebSocket? Are there additional configurations or steps I need to follow?
WebSocket URL
I started by using the following WebSocket URL to connect to the public timeline stream on mastodon.social:
wss://mastodon.social/api/v1/streaming/public
This results in the error:
websocket: bad handshake
websocat
Testing with websocat:
websocat wss://echo.websocket.org
This worked fine and returned messages.
Testing the public timeline via HTTP
I used the Mastodon HTTP API to retrieve public posts from the timeline, and it worked perfectly:
curl https://mastodon.social/api/v1/timelines/public
Go code:
package main
import (
"fmt"
"log"
"os"
"github.com/gorilla/websocket"
)
func streamPublicTimelineWebSocket(instanceURL string) {
// Updated Mastodon Streaming WebSocket API URL for public posts
url := fmt.Sprintf("wss://%s/api/v1/streaming/public", instanceURL)
// Create a WebSocket dialer to manage the connection
dialer := websocket.DefaultDialer
// Create a map for custom headers if necessary (e.g., User-Agent)
headers := map[string][]string{
"User-Agent": {"Mastodon Streamer Go"},
}
// Establish a WebSocket connection with custom headers
conn, _, err := dialer.Dial(url, headers)
if err != nil {
log.Fatalf("Failed to connect to Mastodon streaming WebSocket: %v", err)
os.Exit(1)
}
defer conn.Close()
log.Printf("Successfully connected to stream at: %s", url)
// Continuously read and process incoming WebSocket messages
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Fatalf("Error reading WebSocket message: %v", err)
}
// Print out the received message (which is a Mastodon post)
log.Printf("Received message: %s", msg)
}
}
func main() {
// Replace with your Mastodon instance URL (e.g., "streaming.mastodon.social")
instanceURL := "streaming.mastodon.social" // Updated to the correct WebSocket URL
// Start streaming the public timeline in real-time using WebSocket
log.Println("Starting streaming from Mastodon...")
streamPublicTimelineWebSocket(instanceURL)
}
you have to create a token in your account appearance->Development->new application. Copy de token and add the token to head.
package main
import (
"fmt"
"log"
"os"
"github.com/gorilla/websocket"
)
func streamPublicTimelineWebSocket(instanceURL string) {
// Updated Mastodon Streaming WebSocket API URL for public posts
url := fmt.Sprintf("wss://%s/api/v1/streaming/public", instanceURL)
// Create a WebSocket dialer to manage the connection
dialer := websocket.DefaultDialer
token := "you token"
// Create a map for custom headers if necessary (e.g., User-Agent)
headers := map[string][]string{
"User-Agent": {"Mastodon Streamer Go"},
"Authorization": {" Bearer " + token},
}
// Establish a WebSocket connection with custom headers
conn, _, err := dialer.Dial(url, headers)
if err != nil {
log.Fatalf("Failed to connect to Mastodon streaming WebSocket: %v", err)
os.Exit(1)
}
defer conn.Close()
log.Printf("Successfully connected to stream at: %s", url)
// Continuously read and process incoming WebSocket messages
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Fatalf("Error reading WebSocket message: %v", err)
}
// Print out the received message (which is a Mastodon post)
log.Printf("Received message: %s", msg)
}
}
func main() {
// Replace with your Mastodon instance URL (e.g., "streaming.mastodon.social")
instanceURL := "streaming.mastodon.social" // Updated to the correct WebSocket URL
// Start streaming the public timeline in real-time using WebSocket
log.Println("Starting streaming from Mastodon...")
streamPublicTimelineWebSocket(instanceURL)
}