Giter Site home page Giter Site logo

sse's Introduction

SSE - Server Sent Events Client/Server Library for Go

Synopsis

SSE is a client/server implementation for Server Sent Events for Golang.

Build status

  • Master: CircleCI  Master

Quick start

To install:

go get github.com/r3labs/sse/v2

To Test:

$ make deps
$ make test

Example Server

There are two parts of the server. It is comprised of the message scheduler and a http handler function. The messaging system is started when running:

func main() {
	server := sse.New()
}

To add a stream to this handler:

func main() {
	server := sse.New()
	server.CreateStream("messages")
}

This creates a new stream inside of the scheduler. Seeing as there are no consumers, publishing a message to this channel will do nothing. Clients can connect to this stream once the http handler is started by specifying stream as a url parameter, like so:

http://server/events?stream=messages

In order to start the http server:

func main() {
	server := sse.New()

	// Create a new Mux and set the handler
	mux := http.NewServeMux()
	mux.HandleFunc("/events", server.ServeHTTP)

	http.ListenAndServe(":8080", mux)
}

To publish messages to a stream:

func main() {
	server := sse.New()

	// Publish a payload to the stream
	server.Publish("messages", &sse.Event{
		Data: []byte("ping"),
	})
}

Please note there must be a stream with the name you specify and there must be subscribers to that stream

A way to detect disconnected clients:

func main() {
	server := sse.New()

	mux := http.NewServeMux()
	mux.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
		go func() {
			// Received Browser Disconnection
			<-r.Context().Done()
			println("The client is disconnected here")
			return
		}()

		server.ServeHTTP(w, r)
	})

	http.ListenAndServe(":8080", mux)
}

Example Client

The client exposes a way to connect to an SSE server. The client can also handle multiple events under the same url.

To create a new client:

func main() {
	client := sse.NewClient("http://server/events")
}

To subscribe to an event stream, please use the Subscribe function. This accepts the name of the stream and a handler function:

func main() {
	client := sse.NewClient("http://server/events")

	client.Subscribe("messages", func(msg *sse.Event) {
		// Got some data!
		fmt.Println(msg.Data)
	})
}

Please note that this function will block the current thread. You can run this function in a go routine.

If you wish to have events sent to a channel, you can use SubscribeChan:

func main() {
	events := make(chan *sse.Event)

	client := sse.NewClient("http://server/events")
	client.SubscribeChan("messages", events)
}

HTTP client parameters

To add additional parameters to the http client, such as disabling ssl verification for self signed certs, you can override the http client or update its options:

func main() {
	client := sse.NewClient("http://server/events")
	client.Connection.Transport =  &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
}

URL query parameters

To set custom query parameters on the client or disable the stream parameter altogether:

func main() {
	client := sse.NewClient("http://server/events?search=example")

	client.SubscribeRaw(func(msg *sse.Event) {
		// Got some data!
		fmt.Println(msg.Data)
	})
}

Contributing

Please read through our contributing guidelines. Included are directions for opening issues, coding standards, and notes on development.

Moreover, if your pull request contains patches or features, you must include relevant unit tests.

Versioning

For transparency into our release cycle and in striving to maintain backward compatibility, this project is maintained under the Semantic Versioning guidelines.

Copyright and License

Code and documentation copyright since 2015 r3labs.io authors.

Code released under the Mozilla Public License Version 2.0.

sse's People

Contributors

adieu avatar adriacidre avatar aozd4v avatar beornf avatar codewinch avatar djones6 avatar enverbisevac avatar florianl avatar frederikhors avatar gozjw avatar hermanbanken avatar jbrady42 avatar jbrawnjr avatar jeffreydwalter avatar jwalter1-quest avatar jzbyers avatar kataras avatar marigs avatar matthewrankin avatar merlinran avatar mikamiel avatar panapol-p avatar purehyperbole avatar repejota avatar tigerlee avatar wdscxsj avatar x avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sse's Issues

Feature Request: Let's implement a client.AutoReconnect() method on lost connections.

I think it would be a great addition to the library if we could implement an auto reconnecting feature for the Client.go

Right now the Client will actually keep trying to connect with the amount of attempts decided by the backoff.Retry() method, but only IF the Client has been started with an unreachable stream (server) from start and then it will stop when it has established a connection with the stream

But the Client will not try again in the same way if it loses the connection from a stream it already was connected to, because the readLoop() method will detect this condition err == io.EOF and return nill to the erChan and thereby killing of the backoff.Retry()

An very simple idea to a solution for this would be something like this:

var AutoReconnect = false //[NEW] default should be false
func (c *Client) readLoop(reader *EventStreamReader, outCh chan *Event, erChan chan error) {
for {
	// Read each new line and process the type of event
	event, err := reader.ReadEvent()
	if err != nil {
		if err == io.EOF {
			if !autoReconnect {   //[NEW]  Check if user has enabled autoReconnect
				erChan <- nil
				return
			}
		}

		// run user specified disconnect function
		if c.disconnectcb != nil {
			c.disconnectcb(c)
		}
		erChan <- err
		return
	}

	// If we get an error, ignore it.
	if msg, err := c.processEvent(event); err == nil {
		if len(msg.ID) > 0 {
			c.EventID = string(msg.ID)
		} else {
			msg.ID = []byte(c.EventID)
		}
		// Send downstream
		outCh <- msg
	}
  }
}

This works and I have tried it on a Live-server.

cErr is being shadowed in unit tests.

Hey, was just looking through the unit test code today and noticed some code like this:

var cErr error
go func(cErr error) {
    cErr = c.Subscribe("test", func(msg *Event) {
        if msg.Data != nil {
            events <- msg
            return
       }
    })
}(cErr)

I didn't actually come across this failing, so I'm assuming here (with a little testing to back up my assumption)
Since your go routine is being passed an error it is being passed by value (i.e., copied), so when you set it in the go routine, you are actually setting a copy, and not the original cErr.

Check out this go playground example: https://play.golang.org/p/T_36FPCr3ei

If you agree it's broken, I'll submit a PR real quick.

Cheers,
Jeff

How to detect if source get disconnected

Hi,
Is it possible to detect that source of sse stream got disconnected or something else bad happened to it?
And if it is possible, how to detect that source is offline?

parameter in stream URL and reconnects

Hi!

What would be the best way to support additional parameters that change their values quickly in stream's URL when re-connecting to the data source? For example in the WikiPedia's EventStream we have since=<timestamp> parameter for consuming events from specified timestamp and I want to use the timestamp of the last processed event on reconnects.

Client receives all previous sent events from server when restarting client. Is it correct behavior?

I have server program which sends events via SSE to the Client program.

Suppose that the Server program has sent forexample 40 events and the client program successfully received all 40 events, but when restarting the Client program (while not restarting the server) it gets all the previous 40 events at once again even though the server didn't send anything.

Is this a behavior that should exist or maybe defined in the SSE specifications? I find it odd

panic: client.cleanup() closing sse.Event channel causing panic.

Calling close(ch) in cleanup() causes a panic when SubscribeChan() on the same sse.Event object.

I'm not really sure what the "correct" way to handle this issue is... @purehyperbole any ideas?

The sample code from my last issue reproduces the problem:

package main

import (
    "log"

    "github.com/r3labs/sse"
)

const URL = "http://some.eventstream.url"

func main() {
    es := sse.NewClient(URL)
    events := make(chan *sse.Event)

    go func() {
        for {
            log.Println("HERE")
            go es.SubscribeChanRaw(events)
        }
    }()

    go func() {
        for {
            log.Println("HERE2")
            go es.SubscribeChanRaw(events)
        }
    }()

    done := make(chan interface{})

    <-done
}

SSE only sends the first line of a multi-line String

I have discovered a strange behavior. When sending a string with multiple lines, only the first line of that string is sent, the rest after a line-break doesn't gets sent. Is that an intended behavior to keep messages small?

Here is an example from my server side:

sseServer.AutoReplay = false
sseServer.BufferSize = 1024*30 //Increasing the BufferSize 30x more didn't help
sseServer.CreateStream(sseID)

sseServer.Publish(sseID, &sse.Event{
		Data: []byte("Hellloooooooooooooo\nWooooooooooooorld!!!"),
	})

From the client end:

err := sse.NewClient(sseURL).Subscribe("sseID", func(msg *sse.Event) {
	log.Println(string(msg.Data))
})

The received result in the Client side will be "Hellloooooooooooooo"

What about a real keep-alive ping avoiding timeout issues?

I'm using your amazing project on Heroku.

There is a timeout limit there: https://devcenter.heroku.com/articles/request-timeout#long-polling-and-streaming-responses:

If you’re sending a streaming response, such as with server-sent events, you’ll need to detect when the client has hung up, and make sure your app server closes the connection promptly. If the server keeps the connection open for 55 seconds without sending any data, you’ll see a request timeout.

I know in the WebSocket world there is the concept of Keep-Alive ping.

Why don't we add it too?

Example (pseudo code):

go func() { // goroutine to not block the main thread
  for { // infinite loop
    // From https://gist.github.com/akirattii/257d7efc8430c7e3fd0b4ec60fc7a768#file-sse-serverside-example-js-L44-L52
    each 50 seconds send this message to each client if no data has been sent in this interval: // interval is configurable of course
    ":\n\n" // means "comment"
  }
}

What do you think?

Feature: make an option to provide buffer size for client scanner

I'm trying to use client from this module and the problem I keep having is that the buffer is too small because server is sending events with data larger than max token size from bufio (MaxScanTokenSize).
I can also code this feature and make a PR but I'm not sure what's the best way to go about it. Would you be interested in adding this feature?

This library doesn't seem to follow the EventSource spec.

Hello, me again... I noticed that this library just reads a line and parses it, looking for a <field>: and then sends that as an event. This is not correct according to the EventSource spec.

Is there a reason you chose to implement this library in the current form, or were you trying to comply with the standard?

If so, I've made some changes to a local copy of your library to make it follow the standard (although it's not 100% yet) and would be happy to create a PR.

Here's a sample gist that demonstrates the issue: https://gist.github.com/jeffreydwalter/a01b14c51a6c0fc405278f49e0d99db2

Here's a fork that has my proposed changes (doesn't 100% follow the standard yet): jeffreydwalter@998bb67)

When I run the above gist, I get:

go run blah.go 
ID: 
EVENT: message
DATA: 
ERROR: 
ID: 
EVENT: 
DATA: {"status":"connected"}
ERROR: 
^Csignal: interrupt

What I would expect (according to how I understand the EventSource standard is that the Event should be like this:

$ go run blah.go 
ID: 
EVENT: message
DATA: {"status":"connected"}
ERROR: 

SSE client gets empty events out of nowhere

I have made an Windows program in Golang which uses SSE (the client part) and somehow the SSE client gets empty events out of nowhere. They don't originate from the server because I have checked the logs of both the Windows client program and the Server program.

I managed to log the SSE event data when I get these empty events and got the following:

2020/01/21 20:20:42 SSE EVENT DATA: []
2020/01/21 20:20:42 SSE EVENT ID: []
2020/01/21 20:20:42 SSE EVENT RETRY: []

The following code is the from the Client

func connectToSSE() {
	sseClient.ReconnectStrategy = getBackOff()
	err := sseClient.Subscribe("sseID", func(msg *sse.Event) {
		b, _ := base64.StdEncoding.DecodeString(string(msg.Data))
		go saveTodoFile(string(b))
	})

	if err != nil {
		log.Println("Error: couldn't subscribe to SSE:", err)
	}
}
func getBackOff() *backoff.ExponentialBackOff {
	var customBackOff = backoff.NewExponentialBackOff()
	customBackOff.MaxElapsedTime = 0            //try until forever time
	customBackOff.MaxInterval = 2 * time.Second //no more than 2 seconds till next retry
	customBackOff.Multiplier = 1                //Generate the same delay between retries
	return customBackOff
}

Feature: delete old messages in the eventlog after a custom interval

I'm using your amazing project for the first time (and I'm new to Go too).

I have a doubt.

If I don't use

sseServer.AutoReplay = false

each client (also the new ones) connects to a stream and gets all the messages from the past too.

My question is: is there a limit?

Example: a client connected at 09:00 and receives 100 messages. Another connects at 10:00 and receives the 100 messages too, plus the new ones that will arrive?

Do these messages remain in memory on the server?

If so, is there a way for this not to happen and to have a maximum time after which messages are deleted from memory?

Thanks for your commitment!

Remove hardcoded CORS headers

This is not a bug, but more like an enhancement.
Current CORS headers returned by http handler enforce "allow all" and there is no easy way to change that (except for writing a custom middleware which will wrap response with our custom one, which will discard those headers).
IMHO CORS is not part of SSE response and should be handled elsewhere - i.e. in middlewares.
This is probably a breaking change, as some clients might already expect those headers to be sent.

Why does readLoop() keeps getting "unexpected EOF" periodically?

I have run the Client in debug mode and put a break point here and noticed err is periodically getting unexpected EOF and thereby firing onDisconnect() everytime even when the Client has a active connection to the Server.

This will lead to unexpected behaviors, such as if anyone is trying to reconnect to the server inside onDisconnect(), which will lead to a crazy amount of TCP overflow of connections like in my case.

TCP leaks

Now one will ask why I don't let the ReconnectStrategy do the job for Reconnect, well that is because it won't reconnect if it first established a connection and then lost it, and the problem and solution for that is explained the link below.

I fixed it by avoiding setting onDisconnect() at all and by implementing this solution Feature Request: Let's implement a client.AutoReconnect() method on lost connections

Fun story: The TCP overflow of connections got entire internet of my home to crash a few times and It got me to contact my ISP provider to check for any anormalities :D

Connection leaks if the statusCode not equals with 200

Description

When I subscribes to a server, and it's returns me with status code 401, from the code we can see the req.Body didn't closed properly.

Workaround

Use a custom ResponseValidator like below can avoid at user side:

sseClient.ResponseValidator = func(c *sse.Client, resp *http.Response) error {
	if resp.StatusCode != 200 {
		resp.Body.Close()
		return fmt.Errorf("could not connect to stream: %s", http.StatusText(resp.StatusCode))
	}
	return nil
}

How to handle this error: "An existing connection was forcibly closed by the remote host"

I have an Windows .exe program written in Golang which use SSE to listen for events and write the SSE data strings into an .txt file.

When the computer goes into hibernation/sleep mode and an event is received from the server, I get this error:

read tcp 10.24.66.30:1824->52.56.35.14:8000: wsarecv: An existing connection was forcibly closed by the remote host.

How do I handle this and why did this error happend?

Decouple `stream` query parameter from Client module

Firstly thanks a lot for this library! It's really great to have a well-tested SSE library out there in the go ecosystem.

I understand that the Client module was originally written to work with your Server module, but I would imagine that there are a few of us out there that would like to use the Client with other servers, in my case, Facebook.

Would it be possible to refactor the Subscribe code so that one could submit optional flags for additional slugs / query params to extend the underlying url?

I would be happy to submit a PR for this.

Thanks

SubscribeChan is not working

As title, my go version is 1.8 darwin/amd64.
And if I just publish one msg, client cannot connect to the server. Is that normal?

Streaming unsupported

Hello,

I am trying to setup SSE for a progress bar but I am getting "Streaming unsupported!" in FireFox.

Client:

const source = new EventSource("http://localhost:1337/outlook/loading?stream=" + projectId, {withCredentials: true})
source.onmessage = e => console.log(e.data)

Server:

func (server *Server) Start() {
	server.ServerSentEvents = sse.New()

	server.Router.HandleFunc("/outlook/loading", server.ServerSentEvents.ServeHTTP)
}
go func() {
	server.ServerSentEvents.CreateStream(project.UUID)

	for percentage := range progressPercentageChannel {
		server.ServerSentEvents.Publish(project.UUID, &sse.Event{
			Data: []byte(fmt.Sprintf("%d%", percentage)),
		})
	}
}()

Examples ?

Would help.

Am thinking about using a MQ in the middle as well as using protocol buffers.

Also there is a good case for using this to allow golang channels to communicate over a network. It's a good match since golang channels require two endpoints as they are not bidirectional in the same way that SSE is not bidirectional.

Anyway if you have any example code etc or plans would be great to know

Example for client to reconnect?

Would some kind soul please show me how to setup the Client to reconnect if the server closes connection? I'm guessing it has something to do with Client.disconnectdb but I have no idea how to use this.

Is this what the TestClientChanReconnect method is testing? I see the httptest.Server closing connections but how did the client reconnect?

Multiple rows of data produce the wrong data format when processing event

Hi, when I listen to the Subscribtions event,I received the wrong data . It should be JSON format.
Is there something wrong in the func processEvent ? ( ps : client.go:287)
The origin data is as follow:

:
id: urn:uuid:04d6eadc-c270-406c-99c9-f6ce93499db6
data: {
data:   "@context": "https://mercure.rocks/",
data:   "id": "/.well-known/mercure/subscriptions/%2Fstarship%2Faa%2F%7Bevent%7D/urn%3Auuid%3A9605f26e-b6e7-4a36-a0cf-4126ef44647b",
data:   "type": "Subscription",
data:   "subscriber": "urn:uuid:9605f26e-b6e7-4a36-a0cf-4126ef44647b",
data:   "topic": "/starship/aa/{event}",
data:   "active": false,
data:   "payload": {
data:     "cluster_code": "aa"
data:   }
data: }

And the data I got is:

}  }    "cluster_code": "aa"  "payload": {  "active": false,  "topic": "/starship/aa/{event}",  "subscriber": "urn:uuid:9605f26e-b6e7-4a36-a0cf-4126ef44647b",  "type": "Subscription",  "id": "/.well-known/mercure/subscriptions/%2Fstarship%2Faa%2F%7Bevent%7D/urn%3Auuid%3A9605f26e-b6e7-4a36-a0cf-4126ef44647b",  "@context": "https://mercure.rocks/",{

panic: send on closed channel due to client.Unsubscribe()

panic: send on closed channel
goroutine 318 [running]:
github.com/r3labs/sse.(*Client).SubscribeChan.func1.1(0xc4200595c0, 0xc420160510, 0xc420177ce0, 0xc4200542c0)
        /a/src/github.com/r3labs/sse/client.go:105 +0xea
created by github.com/r3labs/sse.(*Client).SubscribeChan.func1
        /a/src/github.com/r3labs/sse/client.go:89 +0x203

This occurs in a busy stream, and the closed channel is because I called client.Unsubscribe() in the middle of another goroutine. What is the recommended way to call Unsubscribe to avoid this?

Alternatively we can also introduce some kind of locking between Unsubscribe and the select in client.go:100 to prevent this.

An empty event returns an error and is not sent downstream

Hello, thanks for the great library.

As the title says, empty messages are treated as errors and discarded.

https://github.com/r3labs/sse/blob/master/client.go#L290

SSE publishers provide "heartbeat" empty messages on a regular interval. My understanding is this is a common best practice. Since the library does not auto-reconnect, I have to monitor the health of the connection by receiving these heartbeats. This is not possible in the current implementation.

As per the event source spec, an empty message should still be dispatched and not treated as an error: https://html.spec.whatwg.org/multipage/server-sent-events.html#dispatchMessage

I propose making the change to call the downstream event handler with an empty message. Happy to open a PR.

Detect disconnected clients

Somethining I think we need ASAP is to detect clients disconnected both with eventSource.close() or without.

If I use this code:

func newSSEHandler(ssePingInterval time.Duration) *sse.Server {
	sseServer := sse.New()

	sseServer.AutoReplay = false

	sseServer.AutoStream = true

	go func() {
		for range time.Tick(ssePingInterval) {
			for i := range sseServer.Streams {
				println(i, "stream is still present...")
				sseServer.Publish(i, &sse.Event{Data: []byte("test")})
			}
		}
	}()

	return sseServer
}

even if my only client (a browser) closes the connection (with eventSource.close()), the server does not notice even after several minutes and does not close the stream.

panic: unsafe map write when calling client.SubscribeChan() multiple times (concurrently) with the same channel.

I know you probably wouldn't/shouldn't call SubscribeChan() with the same sse.Events channel multiple times from multiple go routines, but I encountered this issue while doing that. 😄

fatal error: concurrent map writes:

goroutine 378 [running]:
runtime.throw(0x13e593e, 0x15)
	/usr/local/go/src/runtime/panic.go:616 +0x81 fp=0xc42080ed20 sp=0xc42080ed00 pc=0x102c7c1
runtime.mapassign_fast64ptr(0x136d860, 0xc420095bf0, 0xc420432000, 0xc42078c300)
	/usr/local/go/src/runtime/hashmap_fast.go:688 +0x2fe fp=0xc42080ed68 sp=0xc42080ed20 pc=0x100d47e
github.com/jeffreydwalter/arlo-go/vendor/github.com/r3labs/sse.(*Client).SubscribeChan(0xc42034e4d0, 0x0, 0x0, 0xc420432000, 0x0, 0x0)
	arlo-go/vendor/github.com/r3labs/sse/client.go:99 +0xb2 fp=0xc42080edf0 sp=0xc42080ed68 pc=0x12f4672
github.com/jeffreydwalter/arlo-go/vendor/github.com/r3labs/sse.(*Client).SubscribeChanRaw(0xc42034e4d0, 0xc420432000, 0x1, 0xd)
	arlo-go/vendor/github.com/r3labs/sse/client.go:175 +0x3d fp=0xc42080ee30 sp=0xc42080edf0 pc=0x12f482d
github.com/jeffreydwalter/arlo-go.(*eventStream).listen.func2(0xc42034e540)
	/arlo-go/events_stream.go:113 +0x9b fp=0xc42080efd8 sp=0xc42080ee30 pc=0x130921b
runtime.goexit()
	/usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc42080efe0 sp=0xc42080efd8 pc=0x105a3b1
created by arlo-go.(*eventStream).listen
	arlo-go/events_stream.go:111 +0x9a

Here's a snippet that recreates the problem:

package main

import (
    "log"

    "github.com/r3labs/sse"
)

const URL = "http://some.eventstream.url"

func main() {
    es := sse.NewClient(URL)
    events := make(chan *sse.Event)

    go func() {
        for {
            log.Println("HERE")
            go es.SubscribeChanRaw(events)
        }
    }()

    go func() {
        for {
            log.Println("HERE2")
            go es.SubscribeChanRaw(events)
        }
    }()

    done := make(chan interface{})

    <-done
}

Version out of date.

Hello,

Looks like you merged some changes into master, but didn't rev the VERSION file nor tag those changes. Can you please do so, so I can use your package with go dep?

Thanks!

Question: connect state

Hey,

thank you for the great library - just want to ask how i can get informations about the connection progress - how i can retrieve errors when there is e.g. a non 200 status code? Is there something like a connection state?

Thank you!

Server is sending events with an empty data field, which violates the spec.

According to the spec:

When the user agent is required to dispatch the event, then the user agent must act as follows:

1. If the data buffer is an empty string, set the data buffer and the event name buffer to the empty string and abort these steps.

...steps 2-5 omitted for brevity and clarity.

6. Queue a task to dispatch the newly created event at the EventSource object.

In this case, the server should NOT send the message if the Data field is empty. The current code in http.go is sending a message in this case. See

sse/http.go

Lines 67 to 69 in f81257c

if len(ev.Data) > 0 {
fmt.Fprintf(w, "data: %s\n", ev.Data)
}

Fix circleci permissions

Using SSH Config Dir '/root/.ssh'
git version 2.30.2
Cloning git repository
Cloning into '.'...
Warning: Permanently added the RSA host key for IP address '140.82.112.3' to the list of known hosts.
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

exit status 128

Can we fix this? I think we should add a key in github settings.

client.Unsubscribe doesn't seem to do anything

If I call SubscribeChan, then immediately call Unsubscribe on my events channel I can still receive events as normal. I discovered this while implementing reconnection logic if a stream goes silent by calling Unsubscribe then SubscribeChan. After doing this I will receive duplicate events on my channel. If I repeat the process 10 more times, I will receive 10 duplicate events on the channel for each event that the server sends.

Reconnect with exponential backoff?

Hi all,

First of all, nice project. The API is nice and very intuitive.

That said, I'd like to propose a new feature where client.go Subscribe and SubscribeChan are capable of reconnecting indefinitely with exponential backoff.

The reason for this is because every http network is flaky. Connection is bound to be broken. So client should have a way to reliably reconnect.

What do you think?

CloseNotify() incompatible with the Labstack Echo v4:

CloseNotify() is deprecated in Go and completely removed in Echo 4 (from January 2019!)
https://pkg.go.dev/net/http#CloseNotifier

2021/07/15 12:30:48 http: panic serving 127.0.0.1:33340: interface conversion: *echo.Response is not http.CloseNotifier: missing method CloseNotify
goroutine 34 [running]:
net/http.(*conn).serve.func1
        /usr/lib/go/src/net/http/server.go:1824
panic(0xbff920, 0xc000384390)
        /usr/lib/go/src/runtime/panic.go:971
github.com/r3labs/sse/v2.(*Server).HTTPHandle
        ~/go/pkg/mod/github.com/r3labs/sse/[email protected]/http.go:61

Removing from http.go fixes it with no apparent loss of functionality (but not extensively tested yet):

    notify := w.(http.CloseNotifier).CloseNotify()                                                                                                       
    go func() {                                                                                                                                          
        <-notify                                                                                                                                         
        sub.close()                                                                                                                                      
    }()   

Version 4 of echo removed support for CloseNotify().. about 2.5 years ago: labstack/echo#1269

"It was already NOT working (not sending signals) as of 1.11, the functionality was gone already, we merely deleted the functions that exposed it. If everyone still rely on it they should migrate to using c.Request().Context().Done() instead."

CONTRIBUTING.md is missing

Hey,

I would like to adhere to your standards for contributing, but the file the README claims those guidelines are documented in is missing.

Cheers

Http endpoint doesn't return any response until first event is available on stream

Affects all releases and master branch.
Steps to reproduce:

  • Create event stream
  • Try to access it by id on http endpoint

Expected result:

  • Http response headers are sent immediatelly

Actual result:

  • Http client is stuck forever waiting for http response.

The problem seems to be that http handler does the first flush only after it receives first event. It can be fixed by calling flush just before entering event loop. PR follows

can't upgrade to version 2.0.0+

➜  go get github.com/r3labs/[email protected]
go: finding module for package gopkg.in/cenkalti/backoff.v1
go: found gopkg.in/cenkalti/backoff.v1 in gopkg.in/cenkalti/backoff.v1 v1.1.0

➜  go get github.com/r3labs/[email protected]
go get github.com/r3labs/[email protected]: github.com/r3labs/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2

I think this is because this project needs v2 in the import path.

Messages are received by "batch" in client

I notice that the messages are received by batches from my client (javascript).
Is this message buffersize for?

But I adjusted it and cant get "real-time". Please help :/

Update gopkg.in/yaml.v2 to v2.2.8+

Currently, the gopkg.in/yaml.v2 dependency is set at 2.2.2, which generates a GitHub Security Dependabot alert. This appears to have been resolved in gopkg.in/yaml.v2 v2.2.8.

cannot get respon server when project running on vps

why when running my project on vps, can not get a response from the server that I have subscribed to and there is no error or message from the library

whereas when I run it on a local run smoothly. Please help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.