KSbus is a zero configuration Eventbus written in Golang, it offer an easy way to share/synchronise data between your Golang servers or between you servers and browsers(JS client) , or simply between your GO and JS clients.
What's New:
- JoinCombinedServer, allow you to join a combined server, first you create a server, then you join the combined See More
- SendToServer, allow to send data from serverBus to serverBus See More
- Loadbalanced mode removed for the combinedServer, because it cannot work as i want it to work, Distributed mode will be the only way to synchronise your servers togethers
Any Go App can communicate with another Go Server or another Go Client.
CDN
JS client is written in Pure JS, so it can be used from any html page as aKSbus also handle distributed use cases using a CombinedServer
You don't know where you can use it ?, here is a simple use case example:
let's take a discord like application for example, if you goal is to broadcast message in realtime to all room members notifying them that a new user joined the room, you can do it using pooling of course, but it's not very efficient, you can use also any broker but it will be hard to subscribe from the browser or html directly
KSbus make it very easy, here is how:
Client side:
">
<script src="https://raw.githubusercontent.com/kamalshkeir/ksbus/master/JS/Bus.js">script> <script> let bus = new Bus("localhost:9313"); bus.autorestart=true; this.restartevery=5; bus.OnOpen = (e) => { let sub = bus.Subscribe("room-client",(data,subs) => { // show notification ... // you can use subs to unsubscribe subs.Unsubscribe(); }); // or you can unsubscribe from outside the handler using the returned sub sub.Unsubscribe(); } script>
Server side:
bus := ksbus.NewServer()
// whenever you register a new user to the room
bus.Publish("room-client",map[string]any{
....
})
bus.Run("localhost:9313")
Before Handlers
you can handle authentication or access to certain topics using toPython client will be added soon
Get Started
go get github.com/kamalshkeir/ksbus@latest
Internal Bus (No websockets, use channels to handle topic communications)
func New() *Bus
func (b *Bus) Subscribe(topic string, fn func(data map[string]any, ch Channel),name ...string) (ch Channel)
func (b *Bus) Unsubscribe(topic string,ch Channel)
func (b *Bus) Publish(topic string, data map[string]any)
func (b *Bus) RemoveTopic(topic string)
func (b *Bus) SendTo(name string, data map[string]any)
// in param and returned subscribe channel
func (ch Channel) Unsubscribe() Channel
Server Bus (use the internal bus and a websocket server)
func NewServer() *Server
func (s *Server) JoinCombinedServer(combinedAddr string,secure bool) // not tested yet
func (s *Server) SendToServer(addr string, data map[string]any, secure ...bool) // allow you to send data to another server, and listen for it using ksbus.BeforeServersData
func (s *Server) Subscribe(topic string, fn func(data map[string]any,ch Channel),name ...string) (ch Channel)
func (s *Server) Unsubscribe(topic string, ch Channel)
func (s *Server) Publish(topic string, data map[string]any)
func (s *Server) RemoveTopic(topic string)
func (s *Server) SendTo(name string, data map[string]any)
func (s *Server) Run(addr string)
func (s *Server) RunTLS(addr string, cert string, certKey string)
func (s *Server) RunAutoTLS(domainName string, subDomains ...string)
// param and returned subscribe channel
func (ch Channel) Unsubscribe() Channel
Example:
func main() {
bus := ksbus.NewServer()
bus.App.LocalTemplates("tempss") // load template folder to be used with c.HTML
bus.App.LocalStatics("assets","/assets/")
bus.App.GET("/",func(c *kmux.Context) {
c.Html("index.html",nil)
})
// if you specify a name 'go' to this subscription like below, you will receive data from any Publish on topic 'server' AND SendTo on 'server:go' name, so SendTo allow you to send not for all listeners on the topic, but the unique named one 'topic1:go'
bus.Subscribe("server",func(data map[string]any, ch ksbus.Channel) {
log.Println("server recv:",data)
},"go")
bus.App.GET("/pp",func(c *kmux.Context) {
bus.Publish("client",map[string]any{
"msg":"hello from server",
})
c.Text("ok")
})
bus.Run(":9313")
}
Client Bus GO
func NewClient(addr string, secure bool,path ...string) *Client
func (client *Client) Subscribe(topic string,handler func(data map[string]any,sub *ClientSubscription), name ...string) *ClientSubscription
func (client *Client) Unsubscribe(topic string)
func (client *Client) Publish(topic string, data map[string]any)
func (client *Client) RemoveTopic(topic string)
func (client *Client) SendTo(name string, data map[string]any)
func (client *Client) Run()
// param and returned subscription
func (subscribtion *ClientSubscription) Unsubscribe() (*ClientSubscription)
Example
func main() {
client,_ := ksbus.NewClient("localhost:9313",false)
// if you specify a name 'go' to this subscription like below, you will receive data from any Publish on topic 'topic1' AND any SendTo on 'topic1:go' name, so SendTo allow you to send not for all listeners on the topic, but the unique named one 'topic1:go'
client.Subscribe("topic1",func(data map[string]any, unsub *ksbus.ClientSubscription) {
fmt.Println("client recv",data)
},"go")
// this will only receive on Publish on topic 'topic2', because no name specified , so you can't send only for this one using SendTo
client.Subscribe("topic2",func(data map[string]any, unsub *ksbus.ClientSubscription) {
fmt.Println("client recv",data)
})
client.Run()
}
Client JS
you can find the client ws wrapper in the repos JS folder above
class Bus {
constructor(addr,path="/ws/bus",secure=false)
this.autorestart=false;
this.restartevery=10; // try reconnect every 10s if autorestart enabled
OnOpen(e)
Subscribe(topic,handler,name="")
Unsubscribe(topic,name="")
Publish(topic,data)
SendTo(name,data,topic="")
RemoveTopic(topic)