GithubHelp home page GithubHelp logo

socketio's People

Contributors

ethanholz avatar njones 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

socketio's Issues

socket-io: Panic sent on closed channel

Hi,

I noticed that sometimes when my application (which implements the socketio server) is running for some time, I experience a panic which states the following:

panic: send on closed channel

goroutine 6198 [running]:
github.com/njones/socketio/transport.(*Transport).Receive.func1()
	.../go/pkg/mod/github.com/njones/[email protected]/transport/transport.go:154 +0x826
created by github.com/njones/socketio/transport.(*Transport).Receive
	.../go/pkg/mod/github.com/njones/[email protected]/transport/transport.go:111 +0x76


I use the ServerV4 with PollingTransport.

Is that a known issue?

Even when the application is idle, it happens sometimes and crashes the whole app.
How can I prevent this from happening?

engine-io: Add more EIO server integration tests

While the SIO server tests will cover most EIO server functionality, we currently have this much covered:

ok  	github.com/njones/socketio/engineio	0.004s	coverage: 2.3% of statements

Uhh, no comment.

[Project Update]: 2024 Working Hours

Hello github.com/njones/socketio users (and future users),

As my commit history and issue updates indicate, I took an unannounced break from the project over the past year due to burnout. I realize this is a very long time for many of you to wait for answers to questions and to bug fixes. I believe I've found a solution that can prioritize both my well-being and community contributions.

Moving forward, I'm implementing a new work schedule to ensure consistent progress while maintaining balance. I'll be working on the project for two months (starting January-February) followed by a one-month break (March). This pattern will continue throughout the year, providing me with the necessary breathers to keep up with everything and deliver my best work. I'll re-evaluate this plan Jan 2025 to see if it makes sense moving forward.

I understand that some questions, bug reports, and proposals have been waiting for answers for a while. I'm eager to address them as soon as possible.

I want to expressing my sincere gratitude for those that have continued passion and support for this project even through the break. Thank you for your patience and understanding. Let's make 2024 a fantastic year!

Nika

socket-io (client): Developing a SocketIO Client

Proposal: Adding a SocketIO Client

Author(s): Nika Jones (@njones)

Last updated: 2022-Aug-27

Abstract

The SocketIO library should have a client developed alongside the server. This will allow backend services developed in Go the ability to call any SocketIO server implementation.

Background

Although the general SocketIO client use case is from a browser, which can't natively run Go. However there are lots of situations where a backend service could use a client to talk to a SocketIO server.

Examples:

  • The server is forwarding chat messages or used as a bot for a chat service
  • Testing of a SocketIO service

Proposal

Create a Client object. (The zero defaults should be valid)

client = NewClient(options...) <*Client>

or

client = &Client{} 

Rationale

The simplest Client is one that can have .On and .Emit with a Dialer that can have any transport necessary.

Implementation

  1. Create the client object
  2. Flesh out the OnConnect, OnDisconnect, On and Emit handlers
  3. Make sure that a replacement Transport or Dialer works
  4. Test the client
  5. Release

Latest version at main branch doesn't allow clients to connect to multiple namespaces

Latest version at the main branch (12ccfd1) doesn't allow clients to connect to multiple namespaces.

To reproduce:

Client (Python):

requirements.txt

python-socketio
python-socketio[client]==4.6.1

main.py

import socketio

NAMESPACES = ["/channel"]
URL = "http://127.0.0.1:8003/"

sio = socketio.Client(logger=True, engineio_logger=True)

@sio.event
def connect():
    print('connection established')

@sio.event
def connect_error(data):
    print("The connection failed!")

@sio.event
def disconnect():
    print('disconnected from server')

sio.connect(URL,
    transports="websocket",
    namespaces=NAMESPACES)

sio.wait()

Server:

main.go

package main

import (
	"log"
	"net/http"
	"time"

	sio "github.com/njones/socketio"
	eio "github.com/njones/socketio/engineio"
	eiot "github.com/njones/socketio/engineio/transport"
)

func main() {
	port := "localhost:8003"

	server := sio.NewServerV2(
		eio.WithSessionShave(1*time.Millisecond),
		eio.WithPingInterval(5*time.Second),
		eio.WithPingTimeout(1*time.Minute),
		eio.WithMaxPayload(1000000),
		eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
	)

	// Root namespace
	server.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/ %s connected.", socket.ID().String())
		return nil
	})

	// Channel namespace
	channel := server.Of("/channel")
	channel.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/channel %s connected.", socket.ID().String())
		return nil
	})

	log.Printf("Serving port %s...\n", port)
	log.Fatal(http.ListenAndServe(port, server))
}

If you use v0.1.1 -- go get github.com/njones/[email protected], it works, it connects to "/" and "/channel".
But if you use the latest version -- go get github.com/njones/socketio@main, it doesn't work, it just connects to "/".

Let me know if you need anything else. Keep up the great work!

Private callback does not allow me to create interfaces

Hi! I'm currently trying to swap out go-socket.io with your library (because of the v4 compatibility), but I have problems due to the private structs and private callback typings.

When I want to create an interface for a Namespace / sio.inSocketV4 that's impossible, because I cannot make an On Method definition conforming to the private eventCallback interface definition, even if it matches the signature.

So I would propose to either expose interfaces (probably eventCallback would be good enough) to public or to not return private structs which can't be even embedded in self-defined data types.
But maybe there is already a solution to this which I didn't see yet.

WithPath option is not working

When defining a specific path on the server and the client, the connection is not established by the client.

Node client:

const io = require("socket.io-client");

const socket = io("http://localhost:8003/channel", {
    transports: ["websocket"],
    reconnection: true,
    autoConnect: true,
    pingInterval: 8000,
    pingTimeout: 10000,
    connectTimeout: 10000,
    query: {
        token: "token!",
    },
    path: "/testing/",
});

socket.on("connect", () => {
    console.log("Connected.");
});

socket.on("message", (msg) => {
    console.log("Message: ", msg)
})

socket.on("error", (error) => {
    console.log("Error: ", error);
});

socket.on("disconnect", (error) => {
    console.log("Disconnected: ", error);
});

socket.on("connect_error", (error) => {
    console.log("connect_error: ", error);
});

socket.connect();

Go server:

import (
	"log"
	"net/http"
	"time"

	sio "github.com/njones/socketio"
	eio "github.com/njones/socketio/engineio"
	eiot "github.com/njones/socketio/engineio/transport"
)

func main() {
	port := "localhost:8003"

	server := sio.NewServerV2(
                eio.WithPath("/testing/"),
		eio.WithSessionShave(1*time.Millisecond),
		eio.WithPingInterval(5*time.Second),
		eio.WithPingTimeout(1*time.Minute),
		eio.WithMaxPayload(1000000),
		eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
	)

	//////////////////////////////////////////////////
	// ROOT
	server.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/ %s connected.", socket.ID().String())
		log.Printf("/ token: %s", socket.Request().URL.Query().Get("token"))
		return nil
	})

	//////////////////////////////////////////////////
	// CHANNEL
	channel := server.Of("/channel")
	channel.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/channel %s connected.", socket.ID().String())
		log.Printf("/channel token: %s", socket.Request().URL.Query().Get("token"))
		return nil
	})

	//////////////////////////////////////////////////
	log.Printf("Serving port %s...\n", port)
	log.Fatal(http.ListenAndServe(port, server))
}

Accessing Socket Object from Event

Hello this library is really useful as it's the only library that is currently implementing latest from Socket.IO

I just would like to ask how can I access the SocketV4 object like I need the ID for example to check if that ID is part of a room, how do I get that information from an event trigger like so:

serverV4.Of("/myNamespace").On("myEvent", callback.FuncString(func(i string) {
     // access socketID of who triggered the event
})

Is there any way to do this?

v0.1.1 doesn't allow to connect to a specific namespace while using socket.io JS library

v0.1.1 doesn't allow to connect to a specific namespace while using socket.io JS library.

  1. Install socket.io-client npm install [email protected]
  2. Test script (test.js):
const io = require("socket.io-client");

const socket = io("http://localhost:8003/channel", {
    transports: ["websocket"],
    reconnection: true,
    autoConnect: true,
    pingInterval: 8000,
    pingTimeout: 10000,
    connectTimeout: 10000,
});

socket.on("connect", () => {
    console.log("Connected.");
});

socket.on("message", (msg) => {
    console.log("Message: ", msg)
})

socket.on("error", (error) => {
    console.log("Error: ", error);
});

socket.on("disconnect", (error) => {
    console.log("Disconnected: ", error);
});

socket.on("connect_error", (error) => {
    console.log("connect_error: ", error);
});

socket.connect();
  1. Execute running node test.js
  2. Socket.io server (Go):
package main

import (
	"log"
	"net/http"
	"time"

	sio "github.com/njones/socketio"
	eio "github.com/njones/socketio/engineio"
	eiot "github.com/njones/socketio/engineio/transport"
)

func main() {
	port := "localhost:8003"

	server := sio.NewServerV2(
		eio.WithSessionShave(1*time.Millisecond),
		eio.WithPingInterval(5*time.Second),
		eio.WithPingTimeout(1*time.Minute),
		eio.WithMaxPayload(1000000),
		eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
	)

	// Root namespace
	server.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/ %s connected.", socket.ID().String())
		return nil
	})

	// Channel namespace
	channel := server.Of("/channel")
	channel.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/channel %s connected.", socket.ID().String())
		return nil
	})

	log.Printf("Serving port %s...\n", port)
	log.Fatal(http.ListenAndServe(port, server))
}

socket-io: Closing Browser Tab and OnDisconnect Event

Upon exploring the library, I noticed that the OnDisconnect event does not trigger when closing the browser tab of an active socket connection.

However calling socket.disconnect() on client side triggers the OnDisconnect event.

On callback return map[string]interface{} empty

Hello. Thanks for the library
I can't sort out the callback for On (subscription events). In server. I received empty map[string]interface.
Can you help me this problem, maybe. thanks

I sending test message from Postman as JSON. Setting v4 or v3

Message
{
  "key": "value" 
}
Use code map
server.On("event", callback.Wrap{
  	Parameters: []ser.Serializable{ser.MapParam},
  	Func: func() interface{} {
  		return func(msg map[string]interface{}) error {
  			fmt.Println(msg)
  			return nil
  		}
  	},
  })

I getting empty map. map[]

if I set StrParam

Use code string
server.On("event", callback.Wrap{
  	Parameters: []ser.Serializable{ser. StrParam},
  	Func: func() interface{} {
  		return func(msg string) error {
  			fmt.Println(msg)
  			return nil
  		}
  	},
  })

then I getting string "map[key:value]"

Number of acknowledgement arguments needs to be equal to number of input arguments?

What I'm trying to achieve:
I'm setting up a socketio server in Go with this package, and using multiple .net clients to connect and communicate with each other. The .net client is not fully developed yet, so I'm using Postman v10.17 to test the connection with my server (which is running locally at the moment).
For my use-case, it's important that some events coming from one side are acknowledged by the other side, with additional arguments. To make it a bit less abstract, an example would be that the client emits an event with one or more arguments, the server processes these arguments, and returns some other arguments in an acknowledgement.

The issue
I'm just starting to learn about socketio so I'm not sure if this is the correct way to do this. The code below is how I get to return an acknowledgement from the Go server to Postman:

socket.On("test", callback.FuncAnyAck(func(i ...interface{}) []ser.Serializable {
	fmt.Printf("\nnumber of input arguments: %d", len(i))

	output := []ser.Serializable{}
	returnArgmunents := 2

	for i := 0; i < returnArgmunents; i++ {
		output = append(output, ser.String(fmt.Sprintf("return argument %d", i)))
	}

	return output
}))

The code above does the behavior that I expect when the number of input arguments is equal to the number of output arguments.

However, when I have more input arguments than output arguments, let's say three input vs. two output arguments, there are three arguments being returned instead of two, the last one being null.

And when I have less input arguments than output arguments, the program panics on the CallbackAck function in callback/callback.go:

runtime/debug.Stack()
	/usr/local/go/src/runtime/debug/stack.go:24 +0x7a
panic({0x111a2e0, 0xc000320048})
	/usr/local/go/src/runtime/panic.go:890 +0x267
github.com/njones/socketio/callback.FuncAnyAck.CallbackAck(0x11d6b30, {0xc00034c090, 0x1, 0x3})
	/go/pkg/mod/github.com/njones/[email protected]/callback/callback.go:33 +0x2b5

When I change callback/callback.go line 30 from

out := make([]interface{}, len(v))

to

out := make([]interface{}, len(slice))

it does work as expected. However I'm not sure if this is the correct way to go, or that I'm going to mess it up any further.
I've searched to find if the number of input and output arguments in an acknowledgement should be equal, but I couldn't find anything about it.

Am I on the right path here regarding ackowledgements? And if so, is the behavior described above correct or am I missing something?
Thanks in advance!

socket-io: Allocated memory isn't released under load test

Hi Nika!
So, I'm running some load tests here and noticed the server is not releasing allocated memory.

Here is what I found:

  1. After running the load test, I got around 5Gib of allocated memory that is not released even after GC execution.
    Screen Shot 2023-04-20 at 16 23 58

  2. Digging into pprof, I got:
    Screen Shot 2023-04-20 at 16 25 01

Screen Shot 2023-04-20 at 16 26 21

To reproduce the test:

  1. Install k6;
  2. Start the server go run main.go (code below);
  3. Run k6 load test script k6 run loadTest.js (code below);
  4. Run pprof:
$ go tool pprof http://localhost:8003/debug/pprof/heap

main.go

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"time"

	sio "github.com/njones/socketio"
	"github.com/njones/socketio/callback"
	eio "github.com/njones/socketio/engineio"
	ser "github.com/njones/socketio/serialize"
)

const (
	httpServerPort = ":8003"
)

func main() {
	var ruTimerQuitChan chan struct{}

	sioServer := sio.NewServerV2(
		sio.WithPath("/websocket/api/socket.io/"),
		eio.WithCors(eio.CORSorigin{"*"}),
		eio.WithSessionShave(1*time.Millisecond),
		eio.WithPingInterval(5*time.Second),
		eio.WithPingTimeout(1*time.Minute),
		eio.WithMaxPayload(1000000),
	)

	// /
	sioServer.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/ connected: %s", socket.ID().String())
		log.Printf("/ token: %s", socket.Request().URL.Query().Get("token"))
		return nil
	})

	// CHANNEL
	channel := sioServer.Of("/channel")
	channel.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/channel connected: %s", socket.ID().String())
		log.Printf("/channel token: %s", socket.Request().URL.Query().Get("token"))
		return nil
	})

	// CHAT
	chat := sioServer.Of("/chat")
	chat.OnConnect(func(socket *sio.SocketV2) error {
		log.Printf("/chat connected: %s", socket.ID().String())
		log.Printf("/chat token: %s", socket.Request().URL.Query().Get("token"))
		socket.On("join", callback.Wrap{
			Parameters: []ser.Serializable{ser.StrParam},
			Func: func() interface{} {
				return func(room string) error {
					log.Print("/chat join event")
					return nil
				}
			},
		})

		socket.On("leave", callback.Wrap{
			Parameters: []ser.Serializable{ser.StrParam},
			Func: func() interface{} {
				return func(room string) error {
					log.Print("/chat leave event")
					return nil
				}
			},
		})

		return nil
	})

	// Debug
	ruTicker := time.NewTicker(time.Second * 10)
	ruTimerQuitChan = make(chan struct{})
	go func() {
		for {
			select {
			case <-ruTicker.C:
				printMemStats()
			case <-ruTimerQuitChan:
				ruTicker.Stop()
				return
			}
		}
	}()

	defaultMux := http.NewServeMux()

	// Socket.io setup
	defaultMux.Handle("/", sioServer)

	// Pprof setup
	defaultMux.HandleFunc("/debug/pprof/", pprof.Index)

	sioHTTPServer := &http.Server{
		Addr:              httpServerPort,
		Handler:           defaultMux,
		ReadHeaderTimeout: 2 * time.Second,
	}

	// Start server
	log.Printf("Server running at %s.", httpServerPort)
	go func() {
		if err := sioHTTPServer.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt)
	<-stop
	close(ruTimerQuitChan)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := sioHTTPServer.Shutdown(ctx); err != nil {
		log.Fatal(err)
	}
}

func printMemStats() {
	var stats strings.Builder
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	stats.WriteString(fmt.Sprintf("Alloc=%vMiB; TotalAlloc=%v MiB; Sys=%vMiB; GoRoutines=%d; NumGC=%v",
		bToMb(m.Alloc),
		bToMb(m.TotalAlloc),
		bToMb(m.Sys),
		runtime.NumGoroutine(),
		m.NumGC))
	log.Print(stats.String())
}

func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}

loadTest.js

import { check, group, sleep } from 'k6';
import ws from 'k6/ws';

export const options = {
  thresholds: {
    http_req_failed: ['rate<0.50'],
    http_req_duration: ['p(90)<5000'],
  },
  stages: [
    { duration: '2m', target: 100 },
    { duration: '4m', target: 100 },
    { duration: '2m', target: 0 },
  ],
};

const nameSpaces = ['', 'channel', 'chat'];
const token = '01234567890123456789012345';
const url = 'ws://localhost:8003/websocket/api/socket.io/?token=' + token + '&EIO=3&transport=websocket';

export default function () {
  nameSpaces.forEach((nameSpace) => {
    group("Test '" + nameSpace + "'", function () {
      let response = ws.connect(url, {}, function (socket) {
        socket.on('open', function open() {
          if (nameSpace.length > 0) {
            socket.send('40/' + nameSpace);
          }

          if (nameSpace === 'chat') {
            sleep(1);
            socket.send('42/chat,["join","room-id"]');
            sleep(1);
            socket.send('42/chat,["leave","room-id"]');
          }

          sleep(1);
          socket.close();
        });
      });

      check(response, {
        'status is 101': (r) => r && r.status === 101,
      });
    });
  });
}

socket-io: How to work with namespaces?

Hello, I'm trying to use this package for different namespaces

Here's the working version using github.com/googollee/go-socket.io

func main() {
	server := socketio.NewServer(&engineio.Options{
		Transports: []transport.Transport{
			&polling.Transport{
				CheckOrigin: allowOriginFunc,
			},
			&websocket.Transport{
				CheckOrigin: allowOriginFunc,
			},
		},
	})
	
	server.OnConnect("/", func(s socketio.Conn) error {
		s.SetContext("")
		log.Println("connected:", s.ID())
		return nil
	})
	
	server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
		log.Println("notice:", msg)
		s.Emit("reply", "have "+msg)
	})
	
	server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string {
		log.Println("chat:", msg)
		s.SetContext(msg)
		return "recv " + msg
	})
	
	server.OnEvent("/", "bye", func(s socketio.Conn) string {
		last := s.Context().(string)
		s.Emit("bye", last)
		s.Close()
		return last
	})
	
	server.OnError("/", func(s socketio.Conn, e error) {
		log.Println("meet error:", e)
	})
	
	server.OnDisconnect("/", func(s socketio.Conn, reason string) {
		log.Println("closed", reason)
	})
	
	go func() {
		if err := server.Serve(); err != nil {
			log.Fatalf("socketio listen error: %s\n", err)
		}
	}()
	defer server.Close()
	
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("asset")))
	
	log.Println("Serving at http://localhost:8001...")
	log.Fatal(http.ListenAndServe(":8001", nil))
}

When I try to use this package I'm getting error. Not sure what might be the issue

func main() {
	port := ":8001"
	
	server := sio.NewServer(
		eio.WithPingInterval(300*1*time.Millisecond),
		eio.WithPingTimeout(200*1*time.Millisecond),
		eio.WithMaxPayload(1000000),
		eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
	)
	
	server.OnConnect(func(s *sio.SocketV4) error {
		log.Println("connected:", s.ID())
		s.Of("/").On("notice", CustomWrap(func(a string) error {
			return s.Emit("reply", seri.String("have "+a))
		}))
		s.Of("/").On("bye", CustomWrap(func(a string) error {
			return s.Emit("bye", seri.String(a))
		}))
		s.Of("/chat").On("msg", CustomWrap(func(a string) error {
			fmt.Println("msg", a)
			return nil
		}))
		return nil
	})
	
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("asset")))
	log.Printf("serving port %s...\n", port)
	log.Fatal(http.ListenAndServe(port, nil))
}

// Define a custom wrapper 
type CustomWrap func(string) error

// Define your callback
func (cc CustomWrap) Callback(data ...interface{}) error {
	a, aOK := data[0].(string)
	
	if !aOK {
		return fmt.Errorf("bad parameters")
	}
	
	return cc(a)
}

Error:

44{"message":"expected an []interface{} or []string, found []interface {}\t{"do":"eventPacket"}"}

index.html

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
    <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      var socket = io("http://127.0.0.1:8001", {transports: ["websocket"]});

      socket.on('reply', function(msg){
        $('#messages').append($('<li>').text(msg));
      });

      $('form').submit(function(){
        socket.emit('msg', $('#m').val(), function(data){
          $('#messages').append($('<li>').text('ACK CALLBACK: ' + data));
        });

        socket.emit('notice', $('#m').val());

        $('#m').val('');
        return false;
      });
    </script>
  </body>
</html>

Update ReadMe Example

This project looks really cool!
But the usage is not clear. The readme example does not compile. Even after adjusting it I could not get the server to run.

socket-io: Update the SocketID to work with a user defined prefix

Currently the SocketID has a generated prefix from one source. In order to allow custom prefixes the ID should contain two parts the ID and the Prefix. This way there can't be custom generators that can generate fake-able ID's in the system. The two parts could look like something as simple as:

type ID struct { prefix, id string } 

This needs to be threaded throughout the system, and must convert to a String() for logging and debugging.

socket-io: Do events on same socket support concurrency?

Hi,

It seems like concurrent handling of events on the same socket is not working.
If a specific client sends multiple events to the server, events are only handled if the previous event is completely finished.
This is not expected behavior and my implementation is not very complex.
Is this a bug? Or could it be that my own code is the culprit.

Thanks

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.