How to make a websocket client wait util the server is running? - websocket

I want to create a websocket client that waits until the server is running. If the connection is closed by the server it should reconnect.
What I tried does not work and my code exits with a runtime error:
panic: runtime error: invalid memory address or nil pointer dereference
func run() {
origin := "http://localhost:8080/"
url := "ws://localhost:8080/ws"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
fmt.Println("Connection fails, is being re-connection")
main()
}
if _, err := ws.Write([]byte("something")); err != nil {
log.Fatal(err)
}
}

Your example looks like a code snippet. It's difficult to say why you're getting that error without seeing all the code. As were pointed out in the comments to your post, you can't call main() again from your code and including the line numbers from the panic report would be helpful as well.
Usually minimizing your program to a minimal case that anyone can run and reproduce the error is the fastest way to get help. I've reconstructed yours for you in such fashion. Hopefully you can use it to fix your own code.
package main
import (
"websocket"
"fmt"
"log"
"time"
)
func main() {
origin := "http://localhost:8080/"
url := "ws://localhost:8080/ws"
var err error
var ws *websocket.Conn
for {
ws, err = websocket.Dial(url, "", origin)
if err != nil {
fmt.Println("Connection fails, is being re-connection")
time.Sleep(1*time.Second)
continue
}
break
}
if _, err := ws.Write([]byte("something")); err != nil {
log.Fatal(err)
}
}
To run this, just copy it into a file called main.go on your system and then run:
go run main.go

Related

Testing NATS-streaming in Kubernetes with minimal effort

I wanted to test a very basic application for NATS-streaming on Kubernetes. To do so, I followed the commands from the official NATS-docs.
It basically comes down to running
kubectl apply -f https://raw.githubusercontent.com/nats-io/k8s/master/nats-server/single-server-nats.yml
kubectl apply -f https://raw.githubusercontent.com/nats-io/k8s/master/nats-streaming-server/single-server-stan.yml
in a terminal with access to the cluster (it's a kind-cluster in my case).
I used stan.go as the NATS-streaming-client. Here is the code I tried to connect to the NATS-streaming-server:
package main
import stan "github.com/nats-io/stan.go"
func main() {
sc, err := stan.Connect("stan", "test-client")
if err != nil {
panic(err)
}
if err := sc.Publish("test-subject", []byte("This is a test-message!")); err != nil {
panic(err)
}
}
and this is the error I'm getting:
panic: nats: no servers available for connection
goroutine 1 [running]:
main.main()
/Users/thilt/tmp/main.go:9 +0x15d
exit status 2
so I think another name was used for the cluster or something. If I use the provided example with nats-box from the docs.nats-link above, it also doesn't work! Where did I go wrong here?
I will happily provide more information, if needed.
There is a great example in stan.go docs:
// Connect to NATS
nc, err := nats.Connect(URL, opts...)
if err != nil {
log.Fatal(err)
}
defer nc.Close()
sc, err := stan.Connect(clusterID, clientID, stan.NatsConn(nc))
if err != nil {
log.Fatalf("Can't connect: %v.\nMake sure a NATS Streaming Server is running at: %s", err, URL)
}
defer sc.Close()
Your error happens because by default stan connects to localhost address (source code):
// DefaultNatsURL is the default URL the client connects to
DefaultNatsURL = "nats://127.0.0.1:4222"
Notice that povided above example overwrite this default connection.
Stan source code is short and easy to analyze. I really recommend you to try to analyze it and figure out what it does.
Now let's put it all together; here is a working example:
package main
import (
nats "github.com/nats-io/nats.go"
stan "github.com/nats-io/stan.go"
)
func main() {
// Create a NATS connection
nc, err := nats.Connect("nats://nats:4222")
if err != nil {
panic(err)
}
// Then pass it to the stan.Connect() call.
sc, err := stan.Connect("stan", "me", stan.NatsConn(nc))
if err != nil {
panic(err)
}
if err := sc.Publish("test-subject", []byte("This is a test-message!")); err != nil {
panic(err)
}
}

Closing amqp.Channel when consumer is failed is not responding

I use https://github.com/NeowayLabs/wabbit/
When amqp.Channel is closing after wrong try channel.Consume, we have a not listened chan and function is not responding.
My code:
package main
import (
"fmt"
"github.com/NeowayLabs/wabbit"
"github.com/NeowayLabs/wabbit/amqptest"
"github.com/NeowayLabs/wabbit/amqptest/server"
)
func someFunc(amqpURL string) error {
conn, err := amqptest.Dial(amqpURL)
defer conn.Close()
channel, err := conn.Channel()
defer channel.Close()
consumer, err := channel.Consume(
"queue",
"consumer",
wabbit.Option{},
)
if err != nil {
return err // err = "Unknown queue 'queue'", but we never response it
}
fmt.Println(<-consumer)
return nil
}
func main() {
amqpURL := "127.0.0.1:32773"
fakeServer := server.NewServer(amqpURL)
err := fakeServer.Start()
defer fakeServer.Stop()
err = someFunc(amqpURL)
if err != nil {
panic(err)
}
fmt.Println("Happy end")
}
someFunc never responding with error, but I want to handle consumer errors.
someFunc never responds with an error because it gets hung up in the defer code.
When someFunc gets to the return err line, then it tries to run the defer statements that you set up in the beginning of the function. The first one that it tries is defer channel.Close().
The problem seems to be with this block in the wabbit library: https://github.com/NeowayLabs/wabbit/blob/d8bc549279ecd80204a8a83a868a14fdd81d1a1b/amqptest/server/channel.go#L315-L317
I think, although I am not sure, that writing to the consumer.done channel is a blocking operation because the channel is not buffered and does not have a receiver. See this: https://gobyexample.com/non-blocking-channel-operations for more information.
I commented that block of code out when running this locally and found that the rest of the code ran as you expected that it would, finally resulting in a panic: Unknown queue 'queue'

Catch stdErr output in golang

I have written a go program to monitor some MySQL databases.
In the following example, I simply display "Connection Success!" when the connection is successful or "Connection Error:" followed by the error message in case of failure.
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
err := mysqlConnect()
if err != nil {
fmt.Println("Connection Error:", err)
} else {
fmt.Println("Connection Success!")
}
}
func mysqlConnect() error {
db, err := sql.Open("mysql", "myuser:mypwd#tcp(10.2.0.3:3306)/mysql")
if err != nil {
return err
}
defer db.Close()
err = db.Ping()
if err != nil {
return err
}
return nil
}
This works as expected, but in some cases, some error message appears while executing db.Ping() and is displayed to stdErr:
For example:
$ go run main.go
[mysql] 2019/07/22 18:01:59 auth.go:293: unknown auth plugin:dialog
Connection Error: this authentication plugin is not supported
The last line is my expected message, but the previous line is displayed when calling db.Ping().
I would like to catch/hide this message [mysql] 2019/07/22 18:01:59 auth.go:293: unknown auth plugin:dialog, as I already gets a clean error message that I can handle as I wish (displaying it or not).
How can I prevent such an error message from appearing (in code I mean, not at the calling time)?
As the comment by #tkausi suggests, you ought to set a custom logger for the go-sql-driver package with https://godoc.org/github.com/go-sql-driver/mysql#SetLogger
Your custom logger can then do whatever makes sense for your application, including "swallowing" these logging statements and not displaying anything in case of no errors.
To answer the question's title, you can capture os.Stderr with something like this:
func doPrint() {
fmt.Fprintf(os.Stderr, "output")
}
func main() {
old := os.Stderr
r, w, _ := os.Pipe()
os.Stderr = w
doPrint()
w.Close()
var buf bytes.Buffer
io.Copy(&buf, r)
os.Stderr = old
fmt.Println("Captured:", buf.String())
}

Panic: runtime error: invalid memory address or nil pointer dereference only on the GAE

I am working on the golang app using gin framework. Basically it just fetch the data from firestore as JSON.
Localy it works perfectly but when I deploy it to the GAE (gcloud app deploy) there is no error during deployment but when access the page it does not work and in the logs provide an error: "panic: runtime error: invalid memory address or nil pointer dereference"
package listcollections
import (
"fmt"
"log"
"net/http"
"cloud.google.com/go/firestore"
"github.com/gin-gonic/gin"
"google.golang.org/api/iterator"
"google.golang.org/appengine"
)
func main() {
}
//GetListCollections function
func GetListCollections(c *gin.Context) {
var coll []string
ctx := appengine.NewContext(c.Request)
projectID := "XXX"
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
iter := client.Collection("collection").Documents(ctx)
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
fmt.Println("ERROR")
}
coll = append(coll, doc.Data()["Title"].(string))
}
c.JSON(http.StatusOK, gin.H{
"collections": coll,
})
}
As no one has any clue where it did happen?
From Analysing your code, the only possibility which I can think off is that your
itr variable is empty.
You might need to change the check for error part and add Panic instead of just printing the error and keep runing
if err != nil {
panic("ERROR")
}

How to test main function in gin application?

How can I test func main? Like this:
func main(){
Engine := GetEngine() // returns gin router with handlers atttached
Engine.Run(":8080")
}
It has only 2 lines but I'd like to have them covered.
TestMain' is reserved for test preparation, does that mean testing main was not planned by language creators?
I can move the contents to another function mainReal but it seems to be some over engineering?
How to test gin has started well? Can I launch main in separate goroutine, check reply and stop it?
Thanks.
P.S. Possible duplicate is not precise duplicate because it is dedicated not to testing of func main() itself, but rather ideas to move in outside and so contains different issue and approach.
Solution.
You may test function main() from package main the same way, just do not name it TestMain. I launch it as a separate goroutine, than try to connect to it and perform any request.
I decided to connect to auxilary handler which should respond with a simple json {"status": "ok"}.
In my case:
func TestMainExecution(t *testing.T) {
go main()
resp, err := http.Get("http://127.0.0.1:8080/checkHealth")
if err != nil {
t.Fatalf("Cannot make get: %v\n", err)
}
bodySb, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Error reading body: %v\n", err)
}
body := string(bodySb)
fmt.Printf("Body: %v\n", body)
var decodedResponse interface{}
err = json.Unmarshal(bodySb, &decodedResponse)
if err != nil {
t.Fatalf("Cannot decode response <%p> from server. Err: %v", bodySb, err)
}
assert.Equal(t, map[string]interface{}{"status": "ok"}, decodedResponse,
"Should return status:ok")
}

Resources