All Projects → AndrewBurian → Eventsource

AndrewBurian / Eventsource

SSE Swiss Army Knife for Go

Programming Languages

go
31211 projects - #10 most used programming language
golang
3204 projects

Labels

Projects that are alternatives of or similar to Eventsource

http-event-stream
📡 Modern spec-compliant Server Sent Events stream implementation.
Stars: ✭ 16 (-44.83%)
Mutual labels:  sse
Libxsmm
Library for specialized dense and sparse matrix operations, and deep learning primitives.
Stars: ✭ 518 (+1686.21%)
Mutual labels:  sse
Golang Sse Todo
golang server sent events (sse) example
Stars: ✭ 23 (-20.69%)
Mutual labels:  sse
Std Simd
std::experimental::simd for GCC [ISO/IEC TS 19570:2018]
Stars: ✭ 275 (+848.28%)
Mutual labels:  sse
Klein
P(R*_{3, 0, 1}) specialized SIMD Geometric Algebra Library
Stars: ✭ 463 (+1496.55%)
Mutual labels:  sse
Fastnoisesimd
C++ SIMD Noise Library
Stars: ✭ 542 (+1768.97%)
Mutual labels:  sse
go-sse
Server-Sent Events for Go
Stars: ✭ 106 (+265.52%)
Mutual labels:  sse
Opensse
Open Sketch Search Engine- 3D object retrieval based on sketch image as input
Stars: ✭ 883 (+2944.83%)
Mutual labels:  sse
Swell
Swell: API development tool that enables developers to test endpoints served over streaming technologies including Server-Sent Events (SSE), WebSockets, HTTP2, GraphQL, and gRPC.
Stars: ✭ 517 (+1682.76%)
Mutual labels:  sse
Cglm
📽 Highly Optimized Graphics Math (glm) for C
Stars: ✭ 887 (+2958.62%)
Mutual labels:  sse
Sse2neon
A translator from Intel SSE intrinsics to Arm/Aarch64 NEON implementation
Stars: ✭ 316 (+989.66%)
Mutual labels:  sse
Atmosphere
Realtime Client Server Framework for the JVM, supporting WebSockets with Cross-Browser Fallbacks
Stars: ✭ 3,552 (+12148.28%)
Mutual labels:  sse
Agoo
A High Performance HTTP Server for Ruby
Stars: ✭ 679 (+2241.38%)
Mutual labels:  sse
Spring Boot Demo
Spring Boot & Spring Cloud & Spring Security Demo Case(Spring学习示例实战项目)
Stars: ✭ 255 (+779.31%)
Mutual labels:  sse
Directxmath
DirectXMath is an all inline SIMD C++ linear algebra library for use in games and graphics apps
Stars: ✭ 859 (+2862.07%)
Mutual labels:  sse
sseclient
Pure-Python Server Side Events (SSE) client
Stars: ✭ 85 (+193.1%)
Mutual labels:  sse
Eventsource
EventSource client for Node.js and Browser (polyfill)
Stars: ✭ 541 (+1765.52%)
Mutual labels:  sse
Libsimdpp
Portable header-only C++ low level SIMD library
Stars: ✭ 914 (+3051.72%)
Mutual labels:  sse
Quadray Engine
Realtime raytracer using SIMD on ARM, MIPS, PPC and x86
Stars: ✭ 13 (-55.17%)
Mutual labels:  sse
Iodine
iodine - HTTP / WebSockets Server for Ruby with Pub/Sub support
Stars: ✭ 720 (+2382.76%)
Mutual labels:  sse

EventSource

Swiss Army Knife for SSE in Golang

Semantic Versioning

This library is module-ready and versioned symantically. master branch tracks the latest unstable work, and the vN branches track stable releases.

Up and running in 30 seconds

So you want to publish events to client that connect to your server?

func main() {
	stream := eventsource.NewStream()

	go func(s *eventsource.Stream) {
		for {
			time.Sleep(time.Second)
			stream.Broadcast(eventsource.DataEvent("tick"))
		}
	}(stream)
	http.ListenAndServe(":8080", stream)
}

The Stream object implements an http.Handler for you so it can be registered directly to a server. Broadcast events to it and it'll forward them to every client that's connected to it.

DataEvent is shorthand for creating a new *Event object and assigning Data() to it

More control on the Stream

You got it! What do you need?

Multiplexing / Topics / Rooms / Channels

We call them "topics" but the gist is the same. All Clients always receive Broadcast events, but you can Publish events to a specific topic, and then only clients that have Subscribed to that topic will receive the event.

stream.Subscribe("weather", myClient)
stream.Publish("weather", weatherUpdateEvent)
stream.Broadcast(tornadoWarningEvent)

You can also just create multiple Stream objects much to the same effect, then only use Broadcast. Streams are cheap and run no background routines, so this is a valid pattern.

weatherStream := eventstream.NewStream()
lotteryStream := eventstream.NewStream()

weatherStream.Register(clientPlanningHikes)
lotteryStream.Register(soonToBePoorClient)

lotteryStream.Broadcast(everyoneLosesEvent)

Auto subscribe certain routes to topics

Stream implements an http.Handler but by default just registers clients for broadcasts.

Use TopicHandler to create another handler for that stream that will subscribe clients to topics as well as broadcasts.

stream := eventsource.NewStream()
catsHandler := stream.TopicHandler([]string{"cat"})

http.ListenAndServe(":8080", catsHandler)

Subscribe/Unsubscribe

Use the stream's Register, Subscribe, Remove, Unsubscribe, and CloseTopic functions to control which clients are registered where.

Tell me when clients connect

Register a callback for the Stream to invoke every time a new client connects with Stream.ClientConnectHook. It'll give you a handle to the resulting Client and the http request that created it, letting you do whatever you please.

stream := eventsource.NewStream()
stream.ClientConnectHook(func(r *http.Requset, c *eventsource.Client){
  fmt.Println("Recieved connection from", r.Host)
  fmt.Println("Hate that guy")
  stream.Remove(c)
  c.Shutdown()
})

The callback will be on the same goroutine as the incoming web request that created it, but the Client is live and functioning so it'll start receiving broadcasts and publications immediately before your callback has returned.

Client Send Errors

If you want to know about errors that occurring when the Stream tries to Send to individual clients (which will generally be disconnects), use the Stream.Errors to create a channel that will deliver them as they happen. The error stream is buffered, but if errors are created faster than they are produced, overflow to the buffer is silently discarded.

Graceful shutdown

The stream's Shutdown command will unsubscribe and disconnect all connected clients. However the Stream itself is not running any background routines, and may continue to register new clients if it's still registered as an http handler.

Get out of my way

Fine! The Stream object is entirely convenience. It runs no background routines and does no special handling. It just adds the topics abstraction and calls NewClient for you when it's connected to. Feel free not to use it.

More control of the Client

You betcha.

Create my own clients

Clients have to be created off an http.ResponseWriter that supports the http.Flusher and http.CloseNotifier interfaces. When creating a client, callers can optionally also pass the original http.Request being served, which helps determine which headers are appropriate to send in response.

NewClient does kick off a background routine to handle sending events, so constructing an object literal will not work. This is done because it's assumed you will likely be calling NewClient on an http handler routine, and will likely not be doing any interesting work on that routine.

func ServeHTTP(w http.ResponseWriter, r *http.Request) {
  client := eventsource.NewClient(w, r)
  if client == nil {
    http.Error(...)
    return
  }

  client.Wait()
}

Letting the http handler routine that created the Client return may cause the underlying connection to be closed by the server. Since NewClient does not block, use Wait to block until the client is shutdown.

Shutdown the client

The client's Shutdown function terminates the background routine and marks the client as closed. It does not actually sever the connection. It does unblock any routines waiting on Wait, which assuming the main http handler routine was waiting there, will cause the connection to close as it returns.

Attempts to Send events to a client after it has been shutdown will result in an error

More control of Events

Events are the most critical part of the library, and are the most versatile.

Write my own events from scratch

Events implement the io.ReadWriter interface so that data can be written to it from practically any source. However the Write interface does not write an entire event in wire format. It writes the provided buffer into data: sections in the resulting event.

ev := &eventsource.Event{}
io.WriteString(ev, "This is an event! How exciting.")

fmt.Fprintf(ev, "This is the %d time I've had to update this readme...", 42)

If you'd like to write bytes exactly as you'd like them to be written to the wire, use the WriteRaw function.

Read on the other hand, does return the event as it would have been written to the wire.

Deep copy an event

You can use Read and WriteRaw to create a perfect deep copy, however since this writes to the underlying data buffer and not to the "assembly area", any calls to Data, ID, Type etc will clobber the buffer and not give you the expected result.

evData, _ := ioutil.ReadAll(oldEvent) // full wire format
newEvent.Write(evData)                // ... smushed into the `data:` section. Not what you wanted

io.Copy(newEvent, oldEvent)           // still not what you wanted

newEvent.WriteRaw(evData)             // that will work
newEvent.AppendData("Moar")           // ... and you ruined it

Use Clone to create a perfect deep copy that survives further mutation. Though this is less efficient in memory.

Create events more easily

Since you will probably be creating more than just a few events, the EventFactory interface and a couple helper factories and functions have been provided to speed things up.

// Create events of the same type
typeFact := &eventsource.EventTypeFactory{
  Type: "message",
}

// then with incrementing ID's
idFact := &eventsource.EventIdFactory{
  Next:    0,
  NewFact: typeFact,
}

// then generate as many events as you want with
// type: message, and an ID that increments
ev := idFact.New()
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].