diff --git a/go.mod b/go.mod index 9f6cd63..43ef10f 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/gin-gonic/gin v1.7.7 + github.com/gorilla/websocket v1.5.0 // indirect github.com/joho/godotenv v1.4.0 github.com/mrz1836/go-sanitize v1.1.5 github.com/ulule/limiter/v3 v3.10.0 diff --git a/go.sum b/go.sum index 8f1cb05..38f7d7f 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/lib/socketmanager/socketmanager.go b/lib/socketmanager/socketmanager.go new file mode 100644 index 0000000..219ad37 --- /dev/null +++ b/lib/socketmanager/socketmanager.go @@ -0,0 +1,84 @@ +package socketmanager + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" +) + +var wsUpgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +type SocketMessage struct { + EventType string `json:"eventType"` + PadName string `json:"padName"` + Message map[string]interface{} `json:"message"` +} + +// Bind the websockets to the gin router +func BindSocket(router *gin.RouterGroup) { + + router.GET("/get", func(ctx *gin.Context) { + webSocketUpgrade(ctx.Writer, ctx.Request) + }) + +} + +func webSocketUpgrade(w http.ResponseWriter, r *http.Request) { + conn, err := wsUpgrader.Upgrade(w, r, nil) + if err != nil { + fmt.Printf("Failed to set websocket upgrade: %v\n", err) + return + } + + // Start listening to this socket + for { + // Try Read the JSON input from the socket + _, msg, err := conn.ReadMessage() + + // Check if a close request was sent + if errors.Is(err, websocket.ErrCloseSent) { + break + } + + if err != nil { + // There has been an error reading the message + fmt.Println("Failed to read from the socket") + // Skip this cycle + continue + } + + // Init the variable + var p SocketMessage + // Try and parse the json + err = json.Unmarshal([]byte(msg), &p) + if err != nil { + // There has been an error reading the message + fmt.Println("Failed to parse the JSON", err) + // Skip this cycle + continue + } + + // Pass the message to the proper handlers + + handleSocketMessage(p) + } +} + +// Handle the socket's message +func handleSocketMessage(msg SocketMessage) { + + // Check the type of message + fmt.Println(msg.EventType) + +} + +func BroadcastMessage(padName string, message string) { + +} diff --git a/main.go b/main.go index 6549a86..45a1e75 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "github.com/JustKato/FreePad/lib/controllers" "github.com/JustKato/FreePad/lib/objects" "github.com/JustKato/FreePad/lib/routes" + "github.com/JustKato/FreePad/lib/socketmanager" "github.com/gin-gonic/gin" "github.com/joho/godotenv" ) @@ -52,6 +53,9 @@ func main() { // Add Routes routes.HomeRoutes(router) + // Bind the Web Sockets + socketmanager.BindSocket(router.Group("/ws")) + router.Run(":8080") } diff --git a/static/js/ws.js b/static/js/ws.js new file mode 100644 index 0000000..f33ced3 --- /dev/null +++ b/static/js/ws.js @@ -0,0 +1,71 @@ +class PadSocket { + + ws = null; + padName = null; + state = null; + + /** + * Create a new PadSocket + * @param {string} padName The name of the pad + * @param {string} connUrl The URL to the websocket + */ + constructor(padName, connUrl = null) { + + // Check if a connection URL was mentioned + if ( connUrl == null ) { + // Try and connect to the local websocket + connUrl = `ws://` + window.location.host + "/ws/get"; + } + + // Connect to the websocket + const ws = new WebSocket(connUrl); + ws.onopen = () => { + this.state = 'active'; + } + + // Bind the onMessage function + ws.onmessage = this.handleMessage; + + // Assign the websocket + this.ws = ws; + // Assign the pad name + this.padName = padName; + } + + /** + * @description Send a message to the server + * @param {string} eventType The type of event, this can be anything really, it's just used for routing by the server + * @param {Object} message The message to send out to the server, this can only be of format string but JSON is parsed. + */ + sendMessage = (eventType, message) => { + + if ( this.state != 'active' ) { + throw new Error(`The websocket connection is not active`); + } + + // Check if the message is a string + if ( typeof message == 'string' ) { + // Convert the message into a map[string]interface{} + message = { + "message": message, + }; + } + + this.ws.send( JSON.stringify({ + eventType, + padName: this.padName, + message, + })) + + } + + handleMessage = ev => { + console.log(ev); + } + +} + +// wait for the whole window to load +window.addEventListener(`load`, e => { + window.socket = new PadSocket(padTitle); +}) \ No newline at end of file diff --git a/templates/pages/page.html b/templates/pages/page.html index a0b282d..7870dcf 100644 --- a/templates/pages/page.html +++ b/templates/pages/page.html @@ -209,6 +209,7 @@ {{ template "inc/theme-toggle.html" .}} +