gowebsocketstreamingmastodon

GO WebSocket to stream public Mastodon posts gives bad handshake


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)
}

Solution

  • 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)
    }
    

    enter image description here