Skip to content

What's new

2024-10-20 - Python SDK v1.0.0 released 🚀

We are excited to announce the release of the Realtime Pub/Sub SDK for Python v1.0.0. This release stabilizes the SDK API in a more user-friendly way for Python developers. The SDK provides a high-level abstraction for interacting with the Realtime Pub/Sub API, making it easier to integrate Realtime Pub/Sub into your Python applications.

Check out more: https://pypi.org/project/realtime-pubsub-client/

2024-10-19 - Introducing SDK for Go 🚀

We are excited to announce the release of the Realtime Pub/Sub SDK for Go. This SDK provides a high-level abstraction for interacting with the Realtime Pub/Sub API, making it easier to integrate Realtime Pub/Sub into your Go applications.

server.go
package main

import (
  "fmt"
  "github.com/backendstack21/realtime-pubsub-client-go"
  "github.com/joho/godotenv"
  "github.com/sirupsen/logrus"
  "os"
  "time"
)

func main() {
  logger := logrus.New()
  logger.SetFormatter(&logrus.JSONFormatter{})
  logger.SetOutput(os.Stdout)
  logger.SetLevel(logrus.InfoLevel)

  // Load environment variables from .env file
  if err := godotenv.Load(); err != nil {
    logger.Errorf("Error loading .env file")
  }

  appID := os.Getenv("APP_ID")
  accessToken := os.Getenv("ACCESS_TOKEN")

  // Create a URL provider function
  urlProvider := func() (string, error) {
    url := fmt.Sprintf("wss://genesis.r7.21no.de/apps/%s?access_token=%s", appID, accessToken)
    return url, nil
  }

  // Initialize the client with configuration

  client := realtime_pubsub.NewClient(realtime_pubsub.Config{
    Logger: logger,
    WebSocketOptions: realtime_pubsub.WebSocketOptions{
      URLProvider: urlProvider,
    },
  })

  client.On("secure/inbound.gettime", func(args ...interface{}) {
    logger.Infof("Responding to gettime request...")
    replyFunc := args[1].(realtime_pubsub.ReplyFunc)

    go func() {
      if err := replyFunc(map[string]interface{}{
        "time": time.Now().Format(time.RFC3339),
      }, "ok"); err != nil {
        logger.Errorf("Failed to reply to message: %v", err)
      }
    }()
  })

  client.On("secure/inbound.presence", func(args ...interface{}) {
    message := args[0].(realtime_pubsub.IncomingMessage)
    presence := message.DataAsPresenceMessage()

    if presence.Status() == "connected" {
      logger.Infof("Client %v connected with %v permissions...", presence.ConnectionId(), presence.Permissions())
    } else if presence.Status() == "disconnected" {
      logger.Infof("Client %v disconnected...", presence.ConnectionId())
    }
  })

  client.On("session.started", func(args ...interface{}) {
    err := client.SubscribeRemoteTopic("secure/inbound")
    if err != nil {
      logger.Errorf("Error subscribing to remote topic: %v", err)
    }
  })

  // Handle error events
  client.Connect()

  select {}
}
client.go
package main

import (
  "fmt"
  "github.com/backendstack21/realtime-pubsub-client-go"
  "github.com/sirupsen/logrus"
  "os"
  "time"

  "github.com/joho/godotenv"
)

func main() {
  done := make(chan bool)

  logger := logrus.New()
  logger.SetFormatter(&logrus.JSONFormatter{})
  logger.SetOutput(os.Stdout)
  logger.SetLevel(logrus.DebugLevel)

  // Load environment variables from .env file
  if err := godotenv.Load(); err != nil {
    logger.Errorf("Error loading .env file")
  }

  appID := os.Getenv("APP_ID")
  accessToken := os.Getenv("ACCESS_TOKEN")

  // Create a URL provider function
  urlProvider := func() (string, error) {
    url := fmt.Sprintf("wss://genesis.r7.21no.de/apps/%s?access_token=%s", appID, accessToken)
    return url, nil
  }

  // Initialize the client with configuration

  client := realtime_pubsub.NewClient(realtime_pubsub.Config{
    Logger: logger,
    WebSocketOptions: realtime_pubsub.WebSocketOptions{
      URLProvider: urlProvider,
    },
  })

  client.On("session.started", func(args ...interface{}) {
    go func() {
      // Publish a message to the "chat" topic
      waitFor, _ := client.Send("",
        realtime_pubsub.WithSendMessageType("gettime"),
      )

      // Wait for acknowledgment
      reply, err := waitFor.WaitForReply(500 * time.Millisecond)
      if err != nil {
        logger.Errorf("Error waiting for reply: %v", err)
      }

      // Print reply
      logger.Infof("Received date: %v\n", reply.DataAsMap()["time"])

      done <- true
    }()
  })

  // Handle error events
  client.Connect()

  select {
  case <-done:
  }
}

2024-10-07 - Introducing SDK for Python 🚀

We are excited to announce the release of the Realtime Pub/Sub SDK for Python. This SDK provides a high-level abstraction for interacting with the Realtime Pub/Sub API, making it easier to integrate Realtime Pub/Sub into your Python applications.

server.py
import os
import time
import logging
import asyncio

from dotenv import load_dotenv
from realtime_pubsub_client import RealtimeClient

# Load variables from .env into os.environ
load_dotenv()

# Configure logging
logging.basicConfig(level=logging.DEBUG)


async def main():
    async def get_url():
        # replace with your access token retrieval strategy
        access_token = os.environ.get('ACCESS_TOKEN')
        app_id = os.environ.get('APP_ID')

        # return the WebSocket URL with the access token
        return f"wss://genesis.r7.21no.de/apps/{app_id}?access_token={access_token}"

    config = {
        'logger': logging.getLogger('RealtimeClient'),
        'websocket_options': {
            'url_provider': get_url,
        }
    }
    client = RealtimeClient(config)

    # Connect to the WebSocket server
    await client.connect()
    client.logger.info('Connected to WebSocket server')

    # Define a message handler
    async def handle_session_started(message):
        await client.subscribe_remote_topic('secure/inbound')

    client.on('session.started', handle_session_started)

    async def handle_get_time(message, reply_fn):
        client.logger.info('Responding to gettime request...')
        await reply_fn({
            'time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
        }, status='ok')

    client.on('secure/inbound.gettime', handle_get_time)

    async def handle_presence(message, reply_fn):
        client.logger.info(f"Presence event received: {message}")
        if message['data']['payload']['status'] == 'connected':
            client.logger.info(f"Client {message['data']['client']['connectionId']} connected...")
        elif message['data']['payload']['status'] == 'disconnected':
            client.logger.info(f"Client {message['data']['client']['connectionId']} disconnected...")

    client.on('secure/inbound.presence', handle_presence)

    while client.ws and not client.ws.closed:
        await asyncio.sleep(1)


# Run the main coroutine
asyncio.run(main())
client.py
import os
import time
import logging
import asyncio

from dotenv import load_dotenv
from realtime_pubsub_client import RealtimeClient

# Load variables from .env into os.environ
load_dotenv()

# Configure logging
logging.basicConfig(level=logging.DEBUG)


async def main():
    async def get_url():
        # replace with your access token retrieval strategy
        access_token = os.environ.get('ACCESS_TOKEN')
        app_id = os.environ.get('APP_ID')

        # return the WebSocket URL with the access token
        return f"wss://genesis.r7.21no.de/apps/{app_id}?access_token={access_token}"

    config = {
        'logger': logging.getLogger('RealtimeClient'),
        'websocket_options': {
            'url_provider': get_url,
        }
    }
    client = RealtimeClient(config)

    # Connect to the WebSocket server
    await client.connect()

    # Define a message handler
    async def handle_session_started(message):
        client.logger.info('Requesting server time...')
        waiter = await client.send('', {
            'messageType': 'gettime'
        })

        response, = await waiter.wait_for_reply(timeout=5)
        client.logger.info(f"Server time: {response['data']['time']}")

        await client.disconnect()

    client.on('session.started', handle_session_started)

    while client.ws and not client.ws.closed:
        await asyncio.sleep(1)


# Run the main coroutine
asyncio.run(main())

2024-09-21 - Introducing SDK for JavaScript/TypeScript 🚀

We are excited to announce the release of the Realtime Pub/Sub SDK for JavaScript/TypeScript. This SDK provides a high-level abstraction for interacting with the Realtime Pub/Sub API, making it easier to integrate Realtime Pub/Sub into your JavaScript/TypeScript applications.

server.ts
import {
  ConnectionInfo,
  IncomingMessage, 
  ReplyFunction, 
  RealtimeClient
} from 'realtime-pubsub-client'

const client = new RealtimeClient({
  websocketOptions: {
    maxRetries: 10,
    urlProvider: async () => {
    return `wss://${CLUSTER_HOSTNAME}/apps/${APP_ID}?access_token=${ACCESS_TOKEN}`
    },
  },
})

client.on('session.started', async (info: ConnectionInfo) => {
  client.subscribeRemoteTopic('secure/inbound')
})

client.on('secure/inbound.gettime', async (_, reply: ReplyFunction) => {
  console.log('Responding to gettime request...')

  await reply({
    time: new Date().toISOString()
  }, 'ok').waitForAck()
})

client.on('secure/inbound.presence', async (message: IncomingMessage) => {
  if (message.data.payload.status === 'connected') {
    console.log(`Client ${message.data.client.connectionId} connected...`)
  } else if (message.data.payload.status === 'disconnected') {
    console.log(`Client ${message.data.client.connectionId} disconnected...`)
  }
})

client.connect()
client.ts
import {
  ConnectionInfo,
  IncomingMessage, 
  ReplyFunction, 
  RealtimeClient
} from 'realtime-pubsub-client'

const client = new RealtimeClient({
  websocketOptions: {
    maxRetries: 10,
    urlProvider: async () => {
    return `wss://${CLUSTER_HOSTNAME}/apps/${APP_ID}?access_token=${ACCESS_TOKEN}`
    },
  },
})

client.on('session.started', async (info: ConnectionInfo) => {
  // request time to server
  const [res] = await client
    .send('', {
      messageType: 'gettime',
    })
    .waitForReply()

  console.log('Server Time:', res as ResponseMessage)
})

client.connect()

2024-09-13 - Enabling apps icon costumization 🎨

We are excited to announce the latest enhancement to the Realtime Pub/Sub Console UI: the ability to customize your app icons. This new feature not only makes your apps more visually appealing but also improves usability and enhances the overall user experience.

Customizing your realtime application icon

2024-08-09 - Console UI enhancements and Max Age JWT Claim verification 🎨🔒

We are excited to announce the latest enhancements to the Realtime Pub/Sub Console UI. The new features include a more intuitive reporting navigation experience and connections by country map visualization.

Enhanced country map visualization

Additionally, we have added a new feature to the JWT verification process. The max_age claim can now be used to verify the maximum age of the token. This feature allows you to set a maximum age for the token and reject tokens that are older than the specified time.

Max Age JWT Claim verification support

2024-07-20 - Historical Egress Traffic chart added to Account page 📊📈

We are excited to announce the addition of the Historical Egress Traffic chart to the Account page. This new feature displays account-level egress traffic usage over a one-year period.

Historical Egress Traffic

2024-07-14 - General Availability with Free Plan 🚀💚🌟

We are thrilled to announce the general availability of Realtime Pub/Sub as a SaaS product. With this release we are also increasing the benefits of our free plan with up to 100KB/s per WebSocket client (inbound), allowing developers to build big from the beginning and without any cost.

Find out more about our Free plan in our pricing page.

With our Free plan, developers can build true realtime applications effortlessly.

Key Highlights

  • 🆓 Free Plan: Begin building realtime applications at no cost.
  • 📚 Enhanced Documentation: Comprehensive guides and tutorials to help you get started.
  • 📊 Administration Console: Monitor and manage your applications with ease.
  • 🔗 WebSocket and HTTP APIs: Simple and robust APIs for seamless integration. No libraries needed, no bullsh*t.

Further explore our documentation and demos to learn more about the features and capabilities of Realtime Pub/Sub.