Skip to content

v0.13.0

Compare
Choose a tag to compare
@FZambia FZambia released this 30 Oct 18:36
· 352 commits to master since this release
47dfbae

This release solves two important issues from v1.0.0 library milestone. It has API changes, though as always it's possible to implement the same as before, and adapting new version should be pretty straightforward.

  • #163 Provide a way to add concurrent processing of protocol commands. Before this change protocol commands could only be processed one by one. The obvious drawback in this case is that one slow RPC could result into stopping other requests from being processed thus affecting overall latency. This required changing client handler API and use asynchronous callback style API for returning replies from event handlers. This approach while not being very idiomatic allows using whatever concurrency strategy developer wants without losing the possibility to control event order.
  • #161 Eliminating ChannelOptionsFunc – now all channel options can be provided when calling Publish operation (history size and TTL) or by returning from event handlers inside SubscribeReply (enabling channel presence, join/leave messages, recovery in a channel). This means that channel options can now be controlled per-connection (not only per channel as before). For example if you need admin connection to subscribe to channel but not participate in channel presence – you are able to not enable presence for that connection.
  • Server-side subscriptions now set over Subscriptions map (instead of Channels). Again – subscribe options can be set with per-connection resolution.
  • Change signature of Publish method in Broker interface – method now accepts []byte data instead of *Publication.
  • Function options for Unsubbscribe and Disconnect methods now have boolean argument.
  • History functional option WithNoLimit removed – use WithLimit(centrifuge.NoLimit) instead.
  • Config option ClientUserConnectionLimit renamed to UserConnectionLimit. If UserConnectionLimit set then now connection will be disconnected with DisconnectConnectionLimit instead of returning a LimitExceeded error.

Since API changes are pretty big, let's look at example program and how to adapt it from v0.12.0 to v0.13.0.

The program based on v0.12.0 API:

package main

import (
	"context"

	"github.com/centrifugal/centrifuge"
)

func main() {
	cfg := centrifuge.DefaultConfig
	cfg.ChannelOptionsFunc = func(channel string) (centrifuge.ChannelOptions, bool, error) {
		return centrifuge.ChannelOptions{
			Presence:        true,
			JoinLeave:       true,
			HistorySize:     100,
			HistoryLifetime: 300,
			HistoryRecover:  true,
		}, true, nil
	}

	node, _ := centrifuge.New(cfg)

	node.OnConnecting(func(ctx context.Context, e centrifuge.ConnectEvent) (centrifuge.ConnectReply, error) {
		return centrifuge.ConnectReply{
			Credentials: &centrifuge.Credentials{UserID: "42"},
			// Subscribe to a server-side channel.
			Channels: []string{"news"},
		}, nil
	})

	node.OnConnect(func(c *centrifuge.Client) {
		println("client connected")
	})

	node.OnSubscribe(func(c *centrifuge.Client, e centrifuge.SubscribeEvent) (centrifuge.SubscribeReply, error) {
		return centrifuge.SubscribeReply{}, nil
	})

	node.OnPublish(func(c *centrifuge.Client, e centrifuge.PublishEvent) (centrifuge.PublishReply, error) {
		return centrifuge.PublishReply{}, nil
	})

	node.OnDisconnect(func(c *centrifuge.Client, e centrifuge.DisconnectEvent) {
		println("client disconnected")
	})

	_ = node.Run()
}

With v0.13.0 the same program becomes:

package main

import (
	"context"
	"time"

	"github.com/centrifugal/centrifuge"
)

func main() {
	node, _ := centrifuge.New(centrifuge.DefaultConfig)

	node.OnConnecting(func(ctx context.Context, e centrifuge.ConnectEvent) (centrifuge.ConnectReply, error) {
		return centrifuge.ConnectReply{
			Credentials: &centrifuge.Credentials{UserID: "42"},
			// Subscribe to a server-side channel.
			Subscriptions: map[string]centrifuge.SubscribeOptions{
				"news": {Presence: true, JoinLeave: true, Recover: true},
			},
		}, nil
	})

	node.OnConnect(func(client *centrifuge.Client) {
		println("client connected")

		client.OnSubscribe(func(e centrifuge.SubscribeEvent, cb centrifuge.SubscribeCallback) {
			cb(centrifuge.SubscribeReply{
				Options: centrifuge.SubscribeOptions{
					Presence:  true,
					JoinLeave: true,
					Recover:   true,
				},
			}, nil)
		})

		client.OnPublish(func(e centrifuge.PublishEvent, cb centrifuge.PublishCallback) {
			// BTW you can publish here explicitly using node.Publish method – see Result
			// field of PublishReply and chat_json example.
			cb(centrifuge.PublishReply{
				Options: centrifuge.PublishOptions{
					HistorySize: 100,
					HistoryTTL:  5 * time.Minute,
				},
			}, nil)
		})

		client.OnDisconnect(func(e centrifuge.DisconnectEvent) {
			println("client disconnected")
		})
	})

	_ = node.Run()
}

As you can see there are three important changes:

  1. You should now set up event handlers inside node.OnConnect closure
  2. Event handlers now have callback argument that you should call with corresponding Reply as soon as you have it
  3. For server-side subscriptions you should now return Subscriptions field in ConnectReply which is map[string]SubscribeOptions instead of []string slice.

See new example that demonstrates concurrency using bounded semaphore.

Note that every feature enabled for a channel increases resource usage on a server. You should only enable presence, recovery, join/leave features and maintaining history in channels where this is necessary.

See also updated Tips and tricks section in a README – it now contains information about connection life cycle and event handler concurrency.