How to isolate a close 1006 (abnormal closure): unexpected EOF - go

I've been trying to subscribe to this API feed: https://www.cryptofacilities.com/resources/hc/en-us/articles/360000578294-Fills
Whenever I try to subscribe, it looks like I'm able to send the payload with WRITEJSON, but what I receive from my Read method is
websocket: close 1006 (abnormal closure): unexpected EOF.
The full terminal message is:
2019/08/04 22:20:31 recv: {"event":"info","version":1}
2019/08/04 22:20:31 recv: {"event":"subscribed","feed":"heartbeat"}
2019/08/04 22:20:31 recv: {"event":"challenge","message":"c6e55c07-d07a-4560-9283-be75ee458433"}
^C2019/08/04 22:21:50 interrupt
2019/08/04 22:21:50 write close: write tcp 192.168.1.6:49624->104.16.51.17:443: write: broken pipe
I understand from here that the status code means that my client closed the connection. I'm unable to track down this problem.
I've tried running race detection, turning off firewall (I have a Mac, and tried to turn off the antivirus - found out it's built in. Would this be worth pursuing?) increasing the handshake timeout, handling the error with a close frame, a different OS, increasing the buffer size, and max message size. A lot of it in reference to this post:
https://github.com/gorilla/websocket/issues/321
This is my client:
package websocket
import (
"crypto/hmac"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
var addr = "wss://www.cryptofacilities.com/ws/v1"
var Wait = 50000 * time.Second
var MaxMessageSize int64 = 100000
//WebSocket connection struct to pass into other methods
type WebSocket struct {
Conn *websocket.Conn
}
//Message represents the public server push messages
type Message struct {
Event string
Feed string
Message interface{}
}
type ChallengeSub struct {
Event string `json:"event"`
Message string `json:"message"`
}
type HeartBeat struct {
Event string
Message string
}
type FillSubscribe struct {
Event string `json:"event"`
Feed string `json:"feed"`
APIKey string `json:"api_key"`
OriginalChallenge string `json:"original_challenge"`
SignedChallenge string `json:"signed_challenge"`
}
//OpenWebSocket Connects to kraken API and returns a connection
func OpenWebSocket() (*WebSocket, error) {
conn, response, err := websocket.DefaultDialer.Dial(addr, nil)
if err != nil {
return nil, err
}
if response.StatusCode != http.StatusSwitchingProtocols {
return nil, fmt.Errorf("failed to upgrade protocol to websocket")
}
return &WebSocket{Conn: conn}, nil
}
//HeartBeat subscribes to the pingpong feed to keep the connection alive
func (c *WebSocket) HeartBeat() error {
ping := map[string]interface{}{
"event": "subscribe",
"feed": "heartbeat",
}
c.Conn.SetWriteDeadline(time.Now().Add(Wait))
err := c.Conn.WriteJSON(ping)
return err
}
func (c *WebSocket) Next() ([]byte, error) {
_, payload, err := c.Conn.ReadMessage()
return payload, err
}
//Challenge requests the UUID from kraken API for auth handshake
func (c *WebSocket) Challenge() error {
challengeRequest := map[string]interface{}{
"event": "challenge",
"api_key": "rhsqfT66dxTF7g2O7/t5Cluubjw4MlEz1UoBrZBjf8JocQ/q49j9rH9m",
}
c.Conn.SetWriteDeadline(time.Now().Add(Wait))
err := c.Conn.WriteJSON(challengeRequest)
if err != nil {
log.Println("write:", err)
return err
}
return err
}
func (c *WebSocket) Decode(payload []byte) (string, string) { //Decode takes in a connection and reference to Message struct
var msg json.RawMessage
env := Message{
Message: &msg,
}
if err := json.Unmarshal([]byte(payload), &env); err != nil {
log.Fatal(err)
}
switch env.Event {
case "challenge":
var s ChallengeSub
if err := json.Unmarshal(msg, &s.Message); err != nil {
log.Fatal(err)
}
message, signed := c.Signature(s.Message)
c.FillSubscribe(message, signed)
return message, signed
case "info":
{
fmt.Println("Connected:", env.Event)
}
case "subscribed":
{
fmt.Println("Connected to Heartbeat")
}
default:
switch env.Feed {
case "heartbeat":
fmt.Println("Live")
}
}
return "No messages to Decode...", ""
}
func (c *WebSocket) Signature(message string) (string, string) {
secret64, _ := base64.StdEncoding.DecodeString("rhsqfT66dxTF7g2O7/t5Cluubjw4MlEz1UoBrZBjf8JocQ/q49j9rH9m")
hash := sha256.New()
hash.Write([]byte(message))
challenge256 := hash.Sum(nil)
hmacHash := hmac.New(sha512.New, secret64)
hmacHash.Write(challenge256)
secretChallenge := hmacHash.Sum(nil)
signed := base64.StdEncoding.EncodeToString(secretChallenge)
return message, signed
}
//FillSubscribe populates message struct and sends out the JSON message
func (c *WebSocket) FillSubscribe(challenge string, signed string) error {
fillMessage := map[string]interface{}{
"event": "subscribe",
"feed": "fills",
"api_key": "rhsqfT66dxTF7g2O7/t5Cluubjw4MlEz1UoBrZBjf8JocQ/q49j9rH9m",
"original_challenge": challenge,
"signed_challenge": signed,
}
c.Conn.SetWriteDeadline(time.Now().Add(Wait))
err := c.Conn.WriteJSON(fillMessage)
if err != nil {
log.Println("write:", err)
return err
}
return err
}
Here is my main program:
package main
import (
"fmt"
"log"
"github.com/Mjavala/KrakenAPI/websocket"
)
var message string
var signed string
func main() {
ws, err := websocket.OpenWebSocket()
if err != nil {
log.Fatal(err)
}
ws.HeartBeat()
ws.Challenge()
fmt.Println(message, signed)
for {
// We first read in a raw message. An error here is a socket level
// error.
payload, err := ws.Next()
if err != nil {
log.Fatalf("socket error: %+v\n", err)
}
log.Printf("recv: %s", payload)
message, signed = ws.Decode(payload)
if err != nil {
log.Fatalf("decode error: %+v\n", err)
}
}
}
I believe that even if the API Keys are wrong a return message should still be sent, as per the API; but instead I get that 1006 close frame.
I'm new to WebSockets. I'm able to get the challenge messaged and heartbeat subscription from the API, the problem is specific to the fill subscription.
Also if anyone wants to replicate this, I can give the full code/Git link.

Related

Is it possible to send email from localhost?

My goal is to create a SMTP server to send an email from noreply#myname.com containing OTP.
The problem is, I code on my personal computer. Therefore, no public address or domain, yet. I tried to send email to myname#gmail.com, but I can't find it on the spam, or the inbox folders.
What I've did:
run the go-smtp server. $ go run cmd/server/main.go
run the go-smtp client. $ go run cmd/client/main.go
The go-smtp server output
(base) jason#Jasons-Mac-mini server % go run main.go
2022/09/23 13:35:38 Starting server at :1025
2022/09/23 13:56:06 Mail from: test#localhost
2022/09/23 13:56:06 Rcpt to: // email redacted for stackoverflow
2022/09/23 13:56:06 Data: This is the email body
The go-smtp client output
(base) jason#Jasons-Mac-mini client % go run main.go
2022/09/23 13:56:06 Mail sent! time elapsed: 1.988625ms
cmd/client/main.go
package main
import (
"fmt"
"log"
"time"
"github.com/emersion/go-smtp"
)
func main() {
start := time.Now()
// Connect to the remote SMTP server.
c, err := smtp.Dial("localhost:1025")
if err != nil {
log.Fatal(err)
}
// Set the sender and recipient first
if err := c.Mail("test#localhost", nil); err != nil {
log.Fatal(err)
}
if err := c.Rcpt("jasonong713#gmail.com"); err != nil {
log.Fatal(err)
}
// Send the email body.
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
_, err = fmt.Fprintf(wc, "This is the email body")
if err != nil {
log.Fatal(err)
}
err = wc.Close()
if err != nil {
log.Fatal(err)
}
// Send the QUIT command and close the connection.
err = c.Quit()
if err != nil {
log.Fatal(err)
}
log.Println("Mail sent! time elapsed:", time.Since(start))
}
cmd/server/main.go
package main
import (
"log"
"time"
"github.com/emersion/go-smtp"
"github.com/godataid/sendemail"
)
func main() {
be := &sendemail.Backend{}
s := smtp.NewServer(be)
s.Addr = ":1025"
s.Domain = "localhost"
s.ReadTimeout = 10 * time.Second
s.WriteTimeout = 10 * time.Second
s.MaxMessageBytes = 1024 * 1024
s.MaxRecipients = 50
s.AllowInsecureAuth = true
log.Println("Starting server at", s.Addr)
if err := s.ListenAndServe(); err != nil {
log.Fatalln(err)
}
}
backend.go
package sendemail
import "github.com/emersion/go-smtp"
type Backend struct{}
// Authenticate a user. Return smtp.ErrAuthUnsupported if you don't want to
// support this.
func (be *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
return nil, smtp.ErrAuthUnsupported
}
// Called if the client attempts to send mail without logging in first.
// Return smtp.ErrAuthRequired if you don't want to support this.
func (be *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
return &Session{}, nil
}
session.go
package sendemail
import (
"io"
"log"
"github.com/emersion/go-smtp"
)
type Session struct{}
// Discard currently processed message.
func (s *Session) Reset() {}
// Free all resources associated with session.
func (s *Session) Logout() error {
return nil
}
// Set return path for currently processed message.
func (s *Session) Mail(from string, opts smtp.MailOptions) error {
log.Println("Mail from:", from)
return nil
}
// Add recipient for currently processed message.
func (s *Session) Rcpt(to string) error {
log.Println("Rcpt to:", to)
return nil
}
// Set currently processed message contents and send it.
func (s *Session) Data(r io.Reader) error {
if b, err := io.ReadAll(r); err != nil {
return err
} else {
log.Println("Data:", string(b))
}
return nil
}

Trying to send a message from websocket inside the same port

I'm writing a chat using WebSocket with gorilla https://github.com/gorilla/websocket
It's working. But now I need to send a message from a consumer of rabbitMQ that I created. The idea is to be a Bot that answers some questions.
The problem is. That I don't know how to send a message without been using a WebSocket dial request which doesn't work, it giver this error.
dial:websocket: bad handshake
Should I create an separated go main with a different port so I can send the message? Or is it possible to do it inside the same main package?
This is the websocket code
package socket
import (
"chatGo/src/domain/message"
"chatGo/src/domain/message/repository"
"chatGo/src/infrastructure/queue"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/novalagung/gubrak/v2"
"log"
"net/http"
"strings"
)
const messageNewUser = "New User"
const messageChat = "Chat"
const messageLeave = "Leave"
const maxMessageSize = 1024 * 1024 // 1kb
var connections = make([]*webSocketConnection, 0)
type payload struct {
Message string
}
type response struct {
From string
Type string
Message string
}
type webSocketConnection struct {
*websocket.Conn
Username string
}
func Execute(c *gin.Context, db repository.GormDB, qBroker *queue.Broker) {
upgrader := websocket.Upgrader{
ReadBufferSize: maxMessageSize,
WriteBufferSize: maxMessageSize,
}
currentGorillaConn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
http.Error(c.Writer, "Could not open websocket connection", http.StatusBadRequest)
}
username := c.Query("username")
currentConn := webSocketConnection{Conn: currentGorillaConn, Username: username}
connections = append(connections, &currentConn)
go handleIO(&currentConn, db, qBroker)
}
func handleIO(currentConn *webSocketConnection, db repository.GormDB, qBroker *queue.Broker) {
defer func() {
if r := recover(); r != nil {
log.Println("ERROR", fmt.Sprintf("%v", r))
}
}()
messageEntitiy := message.NewMessage(currentConn.Username, messageNewUser, "")
broadcastMessage(currentConn, messageEntitiy)
messageStr := fmt.Sprintf("User %s: connected", currentConn.Username)
messageEntitiy = message.NewMessage(currentConn.Username, messageNewUser, messageStr)
db.Create(messageEntitiy)
for {
payload := payload{}
err := currentConn.ReadJSON(&payload)
if err != nil {
if strings.Contains(err.Error(), "websocket: close") {
messageEntitiy := message.NewMessage(currentConn.Username, messageLeave, "")
broadcastMessage(currentConn, messageEntitiy)
ejectConnection(currentConn)
messageStr := fmt.Sprintf("User %s: disconnect", currentConn.Username)
messageEntitiy = message.NewMessage(currentConn.Username, messageLeave, messageStr)
db.Create(messageEntitiy)
return
}
log.Println("ERROR", err.Error())
continue
}
trimStr := strings.TrimSpace(payload.Message)
splitStr := strings.Split(trimStr, "=")
if splitStr[0] == "/stock" {
_ = qBroker.PublishMessage("bot-send", splitStr[1])
} else {
messageEntitiy := message.NewMessage(currentConn.Username, messageChat, payload.Message)
db.Create(messageEntitiy)
}
broadcastMessage(currentConn, messageEntitiy)
}
}
func ejectConnection(currentConn *webSocketConnection) {
filtered := gubrak.From(connections).Reject(func(each *webSocketConnection) bool {
return each == currentConn
}).Result()
connections = filtered.([]*webSocketConnection)
}
func broadcastMessage(currentConn *webSocketConnection, message message.Message) {
for _, eachConn := range connections {
if eachConn == currentConn {
continue
}
eachConn.WriteJSON(response{
From: currentConn.Username,
Type: message.Kind,
Message: message.Message,
})
}
}
I tried this code to send an message using dial
var addr = flag.String("addr", "localhost:8081", "http service address")
test2 := func(msg string) {
u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
err = c.WriteMessage(websocket.TextMessage, []byte(msg))
if err != nil {
log.Println("write:", err)
return
}
Edit 1:
It was missing the handler. I fixed this with the correct handler.
But now If I send I get this error
u := url.URL{Scheme: "ws", Host: *addr, Path: "/socket/ws?username=Bot"}
ERROR invalid character 'T' looking for beginning of value
But my idea would be to send with and Query param, but when I do a get a bad handshake 404
u := url.URL{Scheme: "ws", Host: *addr, Path: "/socket/ws?username=Bot"}
dial:websocket: bad handshake 404

Go websocket test acting strange

So basically I'm writing a go test for my chat application and for some reason the if I write Test_saveMessage function in the top of this file my tests go through and they work fine, however if I write the Test_InitRouter in the top of this file - my server opens and the test doesn't finish. As if it would be listening for more requests. Does anyone know the reason of why this could be happening? Here is the that does not work code:
package messenger
import (
"fmt"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"net/http/httptest"
"strings"
"testing"
)
var testMessage = Message{
Username: "Name",
Message: "Test message"}
//Tests InitRouter both sending and receiving messages
func Test_InitRouter(t *testing.T) {
var receivedMessage Message
//Create test server with the InitRouter handler
s := httptest.NewServer(InitRouter())
defer s.Close()
// Convert URL from http to ws
u := "ws" + strings.TrimPrefix(s.URL, "http")
fmt.Println(u)
// Connect to the test server
ws, _, err := websocket.DefaultDialer.Dial(u, nil)
if err != nil {
t.Fatalf("%v", err)
}
defer ws.Close()
//Send message to the server read received message and see if it's the same
if err != ws.WriteJSON(testMessage) {
t.Fatalf("%v", err)
}
err = ws.ReadJSON(&receivedMessage)
if err != nil {
t.Fatalf("%v", err)
}
if receivedMessage != testMessage {
t.Fatalf("%v", err)
}
}
//Test for the saveMessage function
func Test_saveMessage(t *testing.T) {
saveMessage(testMessage)
assert.Equal(t, 1, len(messages), "Expected to have 1 message")
}
As soon as I move the Test_saveMessage function to the top it starts working properly.
Here is the code for the handler:
package messenger
import (
"fmt"
"github.com/go-chi/chi"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
"net/http"
)
func InitRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", GetWebsocket)
return r
}
var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan Message) // broadcast channel
var messages = []Message{}
func GetWebsocket(w http.ResponseWriter, r *http.Request) {
// Upgrade initial GET request to a websocket
upgrader := websocket.Upgrader{}
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Error(err)
}
// Close the connection when the function returns
defer ws.Close()
// Register our new client and send him the chat history
clients[ws] = true
serveInitialMessages(ws)
//initialize message sending logic
sendMessages(ws)
}
// Sends messages from a particular websocket to the channel
func sendMessages(ws *websocket.Conn){
for {
var msg Message
// Read in a new message as JSON and map it to a Message object
err := ws.ReadJSON(&msg)
if err != nil {
log.Info(err)
delete(clients, ws)
break
}
// Send the newly received message to the broadcast channel
broadcast <- msg
saveMessage(msg)
}
}
func HandleMessages() {
for {
// Grab the next message from the broadcast channel
msg := <-broadcast
fmt.Println(msg)
// Send it out to every client that is currently connected
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("error: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
func saveMessage(m Message) {
if len(messages) >= 50 {
messages = messages[1:]
}
messages = append(messages, m)
}
func serveInitialMessages(ws *websocket.Conn) {
for _, m := range messages {
err := ws.WriteJSON(m)
if err != nil {
log.Error(err)
}
}
}

rpc.ServerCodec Still Serving?

I was performing some RPC tests, and stumbled across a problem I can't seem to solve. In my testing I create three separate RPC servers, all of which I try to close and shutdown. However upon performing my last test (TestRpcCodecServerClientComm), it seems my client connection is connecting to the first RPC server I started (I know this because I at some point attached IDs to the RPCHandlers), even though I attempted everything I could to make sure it was shutdown. Though the code is not there I have attempted to inspect every single error I could, but that did not bring about anything.
rpc.go
package rbot
import (
"io"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func RpcCodecClientWithPort(port string) (rpc.ClientCodec, error) {
conn, err := net.Dial("tcp", "localhost:"+port)
if err != nil {
return nil, err
}
return jsonrpc.NewClientCodec(conn), nil
}
func RpcCodecServer(conn io.ReadWriteCloser) rpc.ServerCodec {
return jsonrpc.NewServerCodec(conn)
}
rpc_test.go
package rbot
import (
"errors"
"fmt"
"net"
"net/rpc"
"testing"
)
type RPCHandler struct {
RPCServer net.Listener
conn rpc.ServerCodec
done chan bool
TestPort string
stop bool
GotRPC bool
}
func (r *RPCHandler) SetupTest() {
r.stop = false
r.GotRPC = false
r.done = make(chan bool)
r.TestPort = "5556"
}
// TODO: Create separate function to handle erroring
func (r *RPCHandler) CreateRPCServer() error {
rpc.RegisterName("TestMaster", TestAPI{r})
var err error
r.RPCServer, err = net.Listen("tcp", ":"+r.TestPort)
if err != nil {
return err
}
go func() {
for {
conn, err := r.RPCServer.Accept()
if err != nil || r.stop {
r.done <- true
return
}
r.conn = RpcCodecServer(conn)
rpc.ServeCodec(r.conn)
}
}()
return nil
}
func (r *RPCHandler) CloseRPCServer() error {
r.stop = true
if r.conn != nil {
err := r.conn.Close()
if err != nil {
fmt.Println(err)
}
}
err := r.RPCServer.Close()
<-r.done
return err
}
type TestAPI struct {
t *RPCHandler
}
func (tapi TestAPI) Send(msg string, result *string) error {
if msg == "Got RPC?" {
tapi.t.GotRPC = true
return nil
}
return errors.New("Didn't receive right message")
}
// Check if we can create and close an RPC server successfully using the RPC server codec.
func TestRpcCodecServer(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
err := r.CreateRPCServer()
if err != nil {
t.Fatalf("Could not create rpc server! %s:", err.Error())
}
err = r.CloseRPCServer()
if err != nil {
t.Fatalf("Could not close RPC server! %s:", err.Error())
}
}
// Check if we can create a client without erroring.
func TestRpcCodecClientWithPortt(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
r.CreateRPCServer()
defer r.CloseRPCServer()
RPCClient, err := RpcCodecClientWithPort(r.TestPort)
defer RPCClient.Close()
if err != nil {
t.Fatalf("Could not create an RPC client! %s:", err.Error())
}
}
// Let's double check and make sure our server and client can speak to each other
func TestRpcCodecServerClientComm(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
r.CreateRPCServer()
defer r.CloseRPCServer()
RPCCodec, _ := RpcCodecClientWithPort(r.TestPort)
RPCClient := rpc.NewClientWithCodec(RPCCodec)
defer RPCClient.Close()
var result string
err := RPCClient.Call("TestMaster.Send", "Got RPC?", &result)
if err != nil {
t.Fatalf("Error while trying to send RPC message: %s", err.Error())
}
if !r.GotRPC {
t.Fatalf("Could not send correct message over RPC")
}
}
Not sure if I'm just mishandling the connection or something of the like, any help would be much appreciated.
For the Record The RPC api does receive the correct string message
While not the source of your problems, your test configuration has a few race conditions which you should take care of before they cause problems. Always check for issues with the -race option. You should also let the OS allocate the port so you don't run into conflicts. See for example how httptest.Server works.
Your failure here is that you're not creating a new rpc.Server for each test, you're reusing the rpc.DefaultServer. The first call to CreateRPCServer registers a TestAPI under the name TestMaster. Each subsequent call uses the already registered instance.
If you create a new rpc.Server each time you setup the test and register a new TestAPI, the final test will pass.
srv := rpc.NewServer()
srv.RegisterName("TestMaster", testAPI)
...
// and then use srv to handle the new connection
srv.ServeCodec(RpcCodecServer(conn))

Go WebSocket server: Use of closed network connection

I'm working on a websocket server and for some reason it outputs:
"WSARecv tcp 127.0.0.1:8080: Use of closed network connection."
I don't know why it says that because I haven't closed the connection at any point in time.
Below are some source code files of the server. If needed, the full source code is here on GitHub.
connection.go
package net
import (
"log"
"golang.org/x/net/websocket"
pnet "kekocity/misc/packet"
"kekocity/interfaces"
)
type Connection struct {
socket *websocket.Conn
txChan chan pnet.INetMessageWriter
rxChan chan pnet.INetMessageReader
user interfaces.IUser
}
func NewConnection(_socket *websocket.Conn) *Connection {
// The pointer allow us to modify connection struct from outside
connection := &Connection{
socket: _socket,
txChan: make(chan pnet.INetMessageWriter),
rxChan: make(chan pnet.INetMessageReader),
}
go connection.ReceivePoller()
go connection.SendPoller()
return connection
}
func (c *Connection) AssignToUser(_user interfaces.IUser) {
if _user == nil {
panic("net.connection: the user interface can not be nil!")
return
}
c.user = _user
_user.SetNetworkChans(c.rxChan, c.txChan)
}
/*
* ReceivePoller and SendPoller starts listening when the first packet is verified and the new connection is started
*/
func (c *Connection) ReceivePoller() {
for {
packet := pnet.NewPacket()
var buffer []uint8
err := websocket.Message.Receive(c.socket, &buffer)
if err == nil {
copy(packet.Buffer[0:len(buffer)], buffer[0:len(buffer)])
c.parsePacket(packet)
} else {
println(err.Error())
break
}
}
}
func (c *Connection) SendPoller() {
for {
// Read messages from transmit channel
message := <-c.txChan
if message == nil {
log.Println("SenPoller", "The message is nil, break the loop")
break
}
// Convert netmessage to packet
packet := message.WritePacket()
packet.SetHeader()
// Create byte buffer
buffer := packet.GetBuffer()
data := buffer[0:packet.GetMsgSize()]
// Send bytes off to the internetz
websocket.Message.Send(c.socket, data)
}
}
func (c *Connection) parsePacket(_packet pnet.IPacket) {
log.Println("net.connection:", "Received new packet!")
}
func (c *Connection) Close() {
// Close channels
close(c.txChan)
close(c.rxChan)
// Close the socket
c.socket.Close()
c.user = nil
}
server.go
package net
// <imports>
import (
"log"
"fmt"
"net/http"
"golang.org/x/net/websocket"
pnet "kekocity/misc/packet"
cmap "kekocity/misc/concurrentmap"
"kekocity/data/helpers"
"kekocity/net/message"
)
var server *Server
type Server struct {
port int
connectedUsers *cmap.ConcurrentMap
}
func init() {
server = newServer()
}
func newServer() *Server {
return &Server{
port: 8080,
connectedUsers: cmap.New(),
}
}
func Listen(_port int) {
server.port = _port
log.Printf("Listening for connections on port %d!", _port)
http.Handle("/ws", websocket.Handler(clientConnection))
err := http.ListenAndServe(fmt.Sprintf(":%d", _port), nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}
func clientConnection(clientsock *websocket.Conn) {
packet := pnet.NewPacket()
buffer := make([]uint8, pnet.PACKET_MAXSIZE)
recv, err := clientsock.Read(buffer)
if err == nil {
copy(packet.Buffer[0:recv], buffer[0:recv])
parseFirstMessage(clientsock, packet)
} else {
if err.Error() != "EOF" {
log.Println("net.server", "Client connection error:", err.Error())
}
}
}
func parseFirstMessage(_conn *websocket.Conn, _packet *pnet.Packet) {
_message := _packet.ToString()
// If the first packet length is < 1 close the socket
if len(_message) < 1 {
_conn.Close()
return
}
// Create the connection
connection := NewConnection(_conn)
// Authentication wrapper
authPacket := &message.AuthMessage{}
user, err := helpers.AuthHelper.AuthenticateUsingCredentials(_message)
if err != nil {
log.Fatal("Invalid credentials!")
authPacket.Status = "error"
} else {
// Need to check if its already logged
authPacket.Status = "success"
connection.AssignToUser(user)
connection.txChan <- authPacket
return
}
// Send bad auth message and close
connection.txChan <- authPacket
connection.Close()
}
Full source code: github
The context in the request is canceled right after the handler finishes.
serverHandler{c.server}.ServeHTTP(w, w.req)
w.cancelCtx()
This is the reason why your context. In this diagram, you can find how the context is created in the server.Serve method.
It is described in more detail in the blog post: HTTP context livetime.
In the websocket, the situation is very similar. The context is closed just after the handler finishes.
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
rwc, buf, err := w.(http.Hijacker).Hijack()
if err != nil {
panic("Hijack failed: " + err.Error())
}
// The server should abort the WebSocket connection if it finds
// the client did not send a handshake that matches with protocol
// specification.
defer rwc.Close() // <- here! It's executed when the s.Handler(conn) exites
conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
if err != nil {
return
}
if conn == nil {
panic("unexpected nil conn")
}
s.Handler(conn)
}
To fix that, you can create a new context from context.Background(), add some timeouts if needed and use it instead.

Resources