func HandleWebsocket(modules WebsocketModulesInterface) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		projectID := vars["project"]
		ctx := r.Context()
		socket, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			helpers.Logger.LogInfo(helpers.GetRequestID(ctx), "upgrade:", map[string]interface{}{"error": err})
			return
		}
		c := client.CreateWebsocketClient(socket)
		defer c.Close()
		realtime, err := modules.Realtime(projectID)
		if err != nil {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusBadRequest)
			_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
			return
		}
		defer realtime.RemoveClient(c.ClientID())
		go c.RoutineWrite(ctx)
		clientID := c.ClientID()
		c.Read(func(req *model.Message) bool {
			switch req.Type {
			case utils.TypeRealtimeSubscribe:
				data := new(model.RealtimeRequest)
				if err := mapstructure.Decode(req.Data, data); err != nil {
					_ = helpers.Logger.LogError(helpers.GetRequestID(ctx), "Unable to decode incoming subscription request", err, nil)
					res := model.RealtimeResponse{Ack: false, Error: err.Error()}
					c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
					return true
				}
				data.Project = projectID
				feedData, err := realtime.Subscribe(clientID, data, func(feed *model.FeedData) {
					c.Write(&model.Message{Type: utils.TypeRealtimeFeed, Data: feed})
				})
				if err != nil {
					_ = helpers.Logger.LogError(helpers.GetRequestID(ctx), "Unable to process incoming subscription request", err, nil)
					res := model.RealtimeResponse{Group: data.Group, ID: data.ID, Ack: false, Error: err.Error()}
					c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
					return true
				}
				res := model.RealtimeResponse{Group: data.Group, ID: data.ID, Ack: true, Docs: feedData}
				c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
			case utils.TypeRealtimeUnsubscribe:
				data := new(model.RealtimeRequest)
				if err := mapstructure.Decode(req.Data, data); err != nil {
					_ = helpers.Logger.LogError(helpers.GetRequestID(ctx), "Unable to decode incoming subscription request", err, nil)
					res := model.RealtimeResponse{Ack: false, Error: err.Error()}
					c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
					return true
				}
				data.Project = projectID
				if err := realtime.Unsubscribe(ctx, data, clientID); err != nil {
					res := model.RealtimeResponse{Group: data.Group, ID: data.ID, Ack: false}
					c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
				}
				res := model.RealtimeResponse{Group: data.Group, ID: data.ID, Ack: true}
				c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: res})
			default:
				c.Write(&model.Message{ID: req.ID, Type: req.Type, Data: map[string]string{"error": "Invalid message type"}})
			}
			return true
		})
	}
}
HandleWebsocket handles all websocket communications
package handlers
import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"
	"github.com/fatih/structs"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/graphql-go/graphql/language/ast"
	"github.com/graphql-go/graphql/language/parser"
	"github.com/graphql-go/graphql/language/source"
	"github.com/mitchellh/mapstructure"
	"github.com/segmentio/ksuid"
	"github.com/spaceuptech/helpers"
	"github.com/spaceuptech/space-cloud/gateway/model"
	"github.com/spaceuptech/space-cloud/gateway/modules"
	"github.com/spaceuptech/space-cloud/gateway/utils"
	"github.com/spaceuptech/space-cloud/gateway/utils/client"
	"github.com/spaceuptech/space-cloud/gateway/utils/graphql"
)
type WebsocketModulesInterface interface {
	Realtime(projectID string) (modules.RealtimeInterface, error)
	GraphQL(projectID string) (modules.GraphQLInterface, error)
}
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}