SDL2 only returns first registered UserEvent - events

I register three events via SDL_RegisterEvents. However, SDL_PollEvent() only returns events of the first type and swallows the others.
This is my code (it's Go, but I don't think that's relevant here):
package main
import (
"github.com/veandco/go-sdl2/sdl"
"log"
)
func main() {
if err := sdl.Init(sdl.INIT_VIDEO | sdl.INIT_EVENTS); err != nil {
panic(err)
}
defer sdl.Quit()
evt1 := sdl.RegisterEvents(3)
evt2 := evt1 + 1
evt3 := evt1 + 2
sdl.PushEvent(&sdl.UserEvent{Type: evt1})
sdl.PushEvent(&sdl.UserEvent{Type: evt2})
sdl.PushEvent(&sdl.UserEvent{Type: evt3})
sdl.PushEvent(&sdl.UserEvent{Type: evt1})
event := sdl.WaitEvent()
for ; event != nil; event = sdl.PollEvent() {
userEvent, ok := event.(*sdl.UserEvent)
if ok {
switch (userEvent.Type) {
case evt1:
log.Println("got evt1")
case evt2:
log.Println("got evt2")
case evt3:
log.Println("got evt3")
}
}
}
}
This is the output:
2019/08/04 20:10:26 got evt1
2019/08/04 20:10:26 got evt1
So both evt1 events that I pushed got polled, but evt2 and evt3 I pushed in between vanished. I tried calling sdl.RegisterEvents(1) three times instead for registering the events, but the result is the same.
What am I doing wrong?

It only is because of go binding, specifically the line https://github.com/veandco/go-sdl2/blob/24851c1f2d98dcac2a68223a24e6f799fc921f1e/sdl/events.go#L1035 (type conversion only triggered on SDL_USEREVENT, which matches only with first registered event; anything else is reported as "CommonEvent", losing all extra data you may have passed) . You probably should report a bug to developer of said binding.

Related

Handle multiple errors from a single channel

I have some trouble with go routines and channels regarding error handling.
Firstly I have a function that listen for messages (in a infinite for loop):
func main() {
messageChannel := make(chan messageHandler.MessageInfo)
for {
if token := client.Subscribe("#", 0, func(client MQTT.Client, msg MQTT.Message) {
go messageHandler.DecodeMessage(msg, messageChannel)
select {
case messageInfo := <-messageChannel:
//Handle
}
}); token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
}
}
}
But in the DecodeMessage function, there could arise multiple errors.
func DecodeMessage(msg mqtt.Message, c1 chan MessageInfo) {
//do something, might result in error
//do another thing, might result in error
c1 <- MessageInfo{...}
}
Normally I would just return from the function. But seems a bit trickier with routines. I've looked at this post, but if both errors would occur, I would only see the last error message.
Example:
func DecodeMessage(msg mqtt.Message, c1 chan MessageInfo) {
var returnError error
if err != nil {
returnError = err
}
if err != nil {
returnError = err
}
c1 <- MessageInfo{
Error: returnError,
...
}
}
Should I have an array of some sort and append all errors? Is it bad practice to have multiple errors in one routine?
The best thing, for me, is that the routine would exit on an error and return that error like it would do "normally". Is that possible?
I'll start by saying that having to go through all the error checks for a function before returning even if they fail is a bit of a code smell. It might mean that you have something weird going on and there may be a better way to accomplish what you're trying to do.
However, assuming that you've boiled down your problem to this, then I see two options, depending on how the errors have to be handled.
If the errors can be handled one-by-one and don't really rely on each other, then you can just create an error channel and send them back one by one as you encounter the errors. See the following working example:
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
errCh := make(chan error)
go HandleErrorsSerially("bad error", errCh)
for err := range errCh {
fmt.Printf("Found error serially: %v\n", err)
}
}
func HandleErrorsSerially(msg string, errCh chan<- error) {
if strings.Contains(msg, "error") {
errCh <- errors.New("message contained string 'error'")
}
if strings.Contains(msg, "bad") {
errCh <- errors.New("message contained string 'bad'")
}
close(errCh)
}
Alternatively, if you need to have a view of all the errors that occurred all at once (because two errors happening simultaneously may indicate some special circumstances) then you'd have to append them all to an array and then pass them through a channel. See the following working example:
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
errArrCh := make(chan []error)
go HandleErrorsTogether("bad error", errArrCh)
errArr := <-errArrCh
fmt.Printf("Found the following errors together: %v\n", errArr)
}
func HandleErrorsTogether(msg string, errArrCh chan<- []error) {
errArr := make([]error, 0)
if strings.Contains(msg, "error") {
errArr = append(errArr, errors.New("message contained string 'error'"))
}
if strings.Contains(msg, "bad") {
errArr = append(errArr, errors.New("message contained string 'bad'"))
}
errArrCh <- errArr
close(errArrCh)
}
I can see cases where it's useful to return multiple errors, such as when you are parsing messages and there are multiple bad fields and you need to summarise these back to a client.
I think the best approach is to use a package like hashicorp's multierror which allows multiple errors to be collected with formatting in a structure type that implements error interface and so can still be sent on a chan error. The receive side can then either process as just a standard error or extract the information on each individual error.
The multierror documentation is pretty good, just read through the examples on the github page.
The best thing, for me, is that the routine would exit on an error and
return that error like it would do "normally".
Of course, you can, and get last error or all error are both pretty strange.
Get last error is unhelpful for debugging, compare with getting first error.
Get all error is same if the first error will cause the following failure, the following error message is unhelpful; Another situation is these errors do not have the association, I think this means you have to sperate they into different concurrency part for better controlling.
Ok, now back to original problem. Consider the code:
func foo(errTo chan error) {
defer close(errTo)
v, err := CouldFailOne()
if err != nil {
errTo <- err
return // Yp, just stop this routine, let it join back to Invoker
}
v2, err := CloudFailTwo()
if err != nil {
errTo <- err
return
}
// As the previous error handle until end of the function
}
If you want to return value from this kind of function. Just use a channel, and send the value into it only no error raise. I think this style will be more clear and like return style, just became using a channel to return the error.

Golang listenUDP multiple ports blocking with BigTable connection

I'm creating a simple udp client that listens on multiple ports and saves the request to bigtable.
It's essential to listen on different ports before you ask.
Everything was working nicely until I included bigtable. After doing so, the listeners block completely.
My stripped down code, without bigtable, looks like this:
func flow(port string) {
protocol := "udp"
udpAddr, err := net.ResolveUDPAddr(protocol, "0.0.0.0:"+port)
if err != nil {
fmt.Println("Wrong Address")
return
}
udpConn, err := net.ListenUDP(protocol, udpAddr)
if err != nil {
fmt.Println(err)
}
defer udpConn.Close()
for {
Publish(udpConn, port)
}
}
func main() {
fmt.Print("Starting server.........")
for i := *Start; i <= *End; i++ {
x := strconv.Itoa(i)
go flow(x)
}
}
This works fine however, as soon as I add the following for bigtable, the whole thing blocks. If I remove the go routine that creates the listener (which means I can't listen on multiple ports) it works.
func createBigTable() {
ctx := context.Background()
client, err := bigtable.NewClient(ctx, *ProjectID, *Instance)
if err != nil {
log.Fatal("Bigtable NewClient:", err)
}
Table = client.Open("x")
}
I managed to get it working by adding a query in the createBigTable func but the program still blocks later on.
I have no idea if this is an issue with bigtable, grpc or just the way I'm doing it.
Would really appreciate some advise about how to fix.
--- UPDATE ---
I've discovered the issue isn't just with BigTable - I also have the same issue when I call gcloud pubsub.
--- UPDATE 2 ---
createBigtable is called in the init function (BEFORE THE MAIN FUNCTION):
func init() {
createBigTable
}
--- Update 3 ---
Output from sigquit can be found here:
https://pastebin.com/fzixqmiA
In your playground example, you're using for {} to keep the server running for forever.
This seems to deprive the goroutines from ever getting to run.
Try using e.g. a WaitGroup to yield control from the main() routine and let the flow() routines handle the incoming UDP packets.
import (
...
"sync"
...
)
...
func main() {
fmt.Print("Starting server.")
for i := *Start; i <= *End; i++ {
x := strconv.Itoa(i)
go flow(x)
}
var wg sync.WaitGroup
wg.Add(1)
wg.Wait()
}

How do I check the type of an error?

I want to check the error type from a function I call to see if it was caused by a deadlineExceededError but I don't see a way to reference it. I suppose I can always check against the .Error() string but I've been told that's frowned upon.
Also it's set to 2 microseconds for debugging purposes, I realize it should be changed to time.Minute
Godoc for the function in question: https://godoc.org/github.com/moby/moby/client#Client.ContainerStart
//if the container fails to start after 2 minutes then we should timeout
ctx, cancel := context.WithTimeout(ctx, 2*time.Microsecond)
defer cancel()
// Do the actual start
if err := myClient.ContainerStart(ctx, containerName, types.ContainerStartOptions{}); err != nil {
fmt.Printf("%v\n", err) //prints: 'context deadline exceeded'
fmt.Printf("%T\n", err) //prints: 'context.deadlineExceededError'
switch e := err.(type) {
case //how do I check for deadlineExceededError:
//print that it timed out here
}
return err
}
The context package exposes this value as a variable.
You can compare err == context.DeadlineExceeded.
However, as argued by Dave Cheney, you should probably use an interface instead.
Specifically net.Error or interface { Timeout() bool } will work as a type.

How is recwatch supposed to work?

I'm trying to get recwatch to work. I'm confused by its interface, though. Yes, I can make a watcher and add folders to it, but there does not seem to be a way to start an event loop that will allow me to receive notifications.
In the original code, there was a Run receiver for just this purpose.
Am I missing something?
The watcher starts emitting events as soon as it is created. All that's required is to read them from RecursiveWatcher.Watcher.Events. Example:
package main
import (
"fmt"
"github.com/xyproto/recwatch"
)
func main() {
w, err := recwatch.NewRecursiveWatcher("sample_dir")
if err != nil {
panic(err)
}
for {
select {
case event := <-w.Events:
fmt.Printf("Event: %s\n", event)
case event := <-w.Errors:
fmt.Printf("Error: %s\n", event)
}
}
}

How to handle HTTP timeout errors and accessing status codes in golang

I have some code (see below) written in Go which is supposed to "fan-out" HTTP requests, and collate/aggregate the details back.
I'm new to golang and so expect me to be a nOOb and my knowledge to be limited
The output of the program is currently something like:
{
"Status":"success",
"Components":[
{"Id":"foo","Status":200,"Body":"..."},
{"Id":"bar","Status":200,"Body":"..."},
{"Id":"baz","Status":404,"Body":"..."},
...
]
}
There is a local server running that is purposely slow (sleeps for 5 seconds and then returns a response). But I have other sites listed (see code below) that sometime trigger an error as well (if they error, then that's fine).
The problem I have at the moment is how best to handle these errors, and specifically the "timeout" related errors; in that I'm not sure how to recognise if a failure is a timeout or some other error?
At the moment I get a blanket error back all the time:
Get http://localhost:8080/pugs: read tcp 127.0.0.1:8080: use of closed network connection
Where http://localhost:8080/pugs will generally be the url that failed (hopefully by timeout!). But as you can see from the code (below), I'm not sure how to determine the error code is related to a timeout nor how to access the status code of the response (I'm currently just blanket setting it to 404 but obviously that's not right - if the server was to error I'd expect something like a 500 status code and obviously I'd like to reflect that in the aggregated response I send back).
The full code can be seen below. Any help appreciated.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"
)
type Component struct {
Id string `json:"id"`
Url string `json:"url"`
}
type ComponentsList struct {
Components []Component `json:"components"`
}
type ComponentResponse struct {
Id string
Status int
Body string
}
type Result struct {
Status string
Components []ComponentResponse
}
var overallStatus string = "success"
func main() {
var cr []ComponentResponse
var c ComponentsList
b := []byte(`{"components":[{"id":"local","url":"http://localhost:8080/pugs"},{"id":"google","url":"http://google.com/"},{"id":"integralist","url":"http://integralist.co.uk/"},{"id":"sloooow","url":"http://stevesouders.com/cuzillion/?c0=hj1hfff30_5_f&t=1439194716962"}]}`)
json.Unmarshal(b, &c)
var wg sync.WaitGroup
timeout := time.Duration(1 * time.Second)
client := http.Client{
Timeout: timeout,
}
for i, v := range c.Components {
wg.Add(1)
go func(i int, v Component) {
defer wg.Done()
resp, err := client.Get(v.Url)
if err != nil {
fmt.Printf("Problem getting the response: %s\n", err)
cr = append(cr, ComponentResponse{
v.Id,
404,
err.Error(),
})
} else {
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Problem reading the body: %s\n", err)
}
cr = append(cr, ComponentResponse{
v.Id,
resp.StatusCode,
string(contents),
})
}
}(i, v)
}
wg.Wait()
j, err := json.Marshal(Result{overallStatus, cr})
if err != nil {
fmt.Printf("Problem converting to JSON: %s\n", err)
return
}
fmt.Println(string(j))
}
If you want to fan out then aggregate results and you want specific timeout behavior the net/http package isn't giving you, then you may want to use goroutines and channels.
I just watched this video today and it will walk you through exactly those scenarios using the concurrency features of Go. Plus, the speaker Rob Pike is quite the authority -- he explains it much better than I could.
https://www.youtube.com/watch?v=f6kdp27TYZs
I am adding this for completes, as the correct answer was provided by Dave C in the comments of the accepted answer.
We can try to cast the error to a net.Error and check if it is a timeout.
resp, err := client.Get(url)
if err != nil {
// if there is an error check if its a timeout error
if e, ok := err.(net.Error); ok && e.Timeout() {
// handle timeout
return
}
// otherwise handle other types of error
}
The Go 1.5 release solved this issue by being more specific about the type of error it has handled.
So if you see this example https://github.com/Integralist/Go-Requester/blob/master/requester.go#L38 you'll see that I'm able to apply a regex pattern to the error message to decipher if the error was indeed a timeout or not
status := checkError(err.Error())
func checkError(msg string) int {
timeout, _ := regexp.MatchString("Timeout", msg)
if timeout {
return 408
}
return 500
}

Resources