scherzma / Skunk

P2P Tor Chat App
GNU General Public License v3.0
4 stars 0 forks source link

Implement Concurrent Connection Handling, Switch to Gorilla Websockets, and Introduce Heartbeat Mechanism #20

Closed JavaHammes closed 5 months ago

JavaHammes commented 5 months ago

This pull request introduces several significant enhancements. Below is a summary of the key changes included:

1. Concurrent Connection Handling:

We've implemented a new feature that enables the application to handle multiple connections concurrently.

To manage multiple connections concurrently, the Peer structure includes a readConns map to keep track of active websocket connections for reading, indexed by the remote address. mapRWLock (sync.RWMutex) ensures thread-safe access to the readConns map, allowing for concurrent reads and writes to the map without data races.

3. Switch from Nhooyr to Gorilla Websockets:

After a comprehensive evaluation, we've decided to transition our websocket library from nhooyr to gorilla/websocket. This decision was driven by gorilla/websocket's widespread adoption, active maintenance, and its alignment with our project's needs. The switch has involved updating the websocket initialization, message handling, and closure processes to be compatible with the gorilla/websocket API.

4. Heartbeat Mechanism:

To further improve the reliability of our websocket connections, we've introduced a heartbeat mechanism. This feature periodically sends ping messages to each active connection to determine its status. If a connection fails to respond within a predefined timeout, it is considered stale and is gracefully closed. This mechanism helps in promptly detecting and handling broken connections.

func (p *Peer) startHeartbeat() {
    ticker := time.NewTicker(heartbeatInterval)
    go func() {
        for {
            select {
                case <-ticker.C:
                    p.sendHeartbeatToAll()
                case <-p.quitch:
                    ticker.Stop()
                    return
            }
        }
    }()
}

5. Comprehensive Testing:

Ensuring the reliability of these new features and changes, we've added a suite of tests that cover the most important functionalities.

The testing code covers various scenarios, including initializing peers, listening for connections, establishing connections between peers, setting write connections, sending and receiving messages, and shutting down peers. Special test cases like sending different types of messages (TestPeerWriteMessage) and handling peer shutdown (TestPeerShutdown) ensure comprehensive coverage. These tests validate not just the individual functionalities but also the integration and interaction between different components, ensuring that the system works as a whole.

Closes #13