Skip to content

Commit

Permalink
Adding Chat Api in backend
Browse files Browse the repository at this point in the history
  • Loading branch information
p-shubh committed May 16, 2024
1 parent 9fe7505 commit 30890d6
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 1 deletion.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "main.go"
}
]
}
2 changes: 2 additions & 0 deletions Router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package router

import (
"fmt"
realtimechat "hack/real_time_chat"
voyagerrouting "hack/voyagerRouting"
"time"

Expand Down Expand Up @@ -53,6 +54,7 @@ func ApplyRoutes(r *gin.RouterGroup) {
fmt.Println("---------------------------------------------------------------------------------------------------------------------------------------")

voyagerrouting.VoyagerApplyRoutes(v1)
realtimechat.RealTimeVoyagerApplyRoutes(v1)
// suiRouter.SuiApplyRoutes(v1)
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ require (
github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/static v1.1.2
github.com/gin-gonic/gin v1.10.0
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.0
github.com/joho/godotenv v1.5.1
github.com/overseedio/realtime-go v0.0.0
gorm.io/driver/postgres v1.5.7
gorm.io/gorm v1.25.10
)
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
Expand Down Expand Up @@ -64,6 +68,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/overseedio/realtime-go v0.0.0 h1:WHP0lRBWxCWEmDzMoMer3yB26X1gp9xvWCd8w6L1icQ=
github.com/overseedio/realtime-go v0.0.0/go.mod h1:2pcz14UcMk1/e+JxorOm0nSaxR+fRwN6msynYsLHccQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
32 changes: 32 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat</title>
</head>
<body>
<input type="text" id="username" placeholder="Enter your username">
<input type="text" id="message" placeholder="Enter your message">
<button onclick="sendMessage()">Send</button>
<div id="chat"></div>

<script>
const socket = new WebSocket('ws://localhost:6060/v1.0/voyager_web_socket/ws');

socket.onmessage = function(event) {
const message = JSON.parse(event.data);
const chat = document.getElementById('chat');
chat.innerHTML += `<p><strong>${message.username}:</strong> ${message.content}</p>`;
};

function sendMessage() {
const username = document.getElementById('username').value;
const content = document.getElementById('message').value;
const message = { username, content };

socket.send(JSON.stringify(message));
}
</script>
</body>
</html>
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
router "hack/Router"
realtimechat "hack/real_time_chat"
"log"
"os"

Expand All @@ -16,5 +17,8 @@ func main() {
log.Printf("Error in reading the config file : %v\n", err)
}
}

realtimechat.RealtimeChatVoigerConnection()

router.HandleRequest()
}
237 changes: 237 additions & 0 deletions real_time_chat/real.time.chat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
package realtimechat

import (
"fmt"
dbflow "hack/dbFlow"
"log"
"net/http"
"os"
"sync"
"time"

"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/gorilla/websocket"
realtimego "github.com/overseedio/realtime-go"
)

// func handleConnections(c *gin.Context) {
// ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
// if err != nil {
// log.Println(err)
// return
// }
// defer ws.Close()
// clients[ws] = true

// for {
// var msg Message
// err := ws.ReadJSON(&msg)
// if err != nil {
// log.Printf("error: %v", err)
// delete(clients, ws)
// break
// }
// broadcast <- msg
// }
// }

// func subscribeToRealtime() {
// client := supabase.NewClient(os.Getenv("SUPABASE_PROJECT_URL"), os.Getenv("SUPABASE_ANON_KEY"), nil)
// rtClient, err := realtime.NewClient(client)
// if err != nil {
// log.Fatalf("Error creating Realtime client: %v", err)
// }

// rtClient.On("postgres_changes", map[string]string{
// "schema": "public",
// "table": "messages",
// "event": "*",
// }, func(payload realtime.Payload) {
// log.Printf("Realtime message: %v", payload)

// msg := Message{
// ID: payload.New["id"].(string),
// Content: payload.New["content"].(string),
// Username: payload.New["username"].(string),
// CreatedAt: payload.New["created_at"].(string),
// }

// broadcast <- msg
// })

// err = rtClient.Start()
// if err != nil {
// log.Fatalf("Error starting Realtime client: %v", err)
// }
// }

// func handleMessages() {
// db, dbClose := dbflow.ConnectHackDatabase()
// defer dbClose.Close()
// for {
// msg := <-broadcast

// for client := range clients {
// err := client.WriteJSON(msg)
// if err != nil {
// log.Printf("error: %v", err)
// client.Close()
// delete(clients, client)
// }
// }

// db.Create(&msg)
// }
// }

// Message represents a chat message
// type Message struct {
// ID uint `json:"id" gorm:"primaryKey"`
// Content string `json:"content"`
// Username string `json:"username"`
// CreatedAt time.Time `json:"created_at"`
// }

// var db *gorm.DB
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan VoyagerRandomeMessages)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var mutex = &sync.Mutex{}

func RealtimeChatVoigerConnection() {
var ENDPOINT = os.Getenv("SUPABASE_PROJECT_URL")
var API_KEY = os.Getenv("SUPABASE_ANON_KEY")
var RLS_TOKEN = os.Getenv("SUPABASE_RLS_TOKEN")

c, err := realtimego.NewClient(ENDPOINT, API_KEY, realtimego.WithUserToken(RLS_TOKEN))
if err != nil {
log.Fatal(err)
}

err = c.Connect()
if err != nil {
log.Fatal(err)
}

dbName := os.Getenv("SUPABASE_DB_NAME")
schema := os.Getenv("SCHEMA")
table := os.Getenv("TABLE")
ch, err := c.Channel(realtimego.WithTable(&dbName, &schema, &table))
if err != nil {
log.Fatal(err)
}

ch.OnInsert = func(m realtimego.Message) {
log.Println("***ON INSERT....", m)
}
ch.OnDelete = func(m realtimego.Message) {
log.Println("***ON DELETE....", m)
}
ch.OnUpdate = func(m realtimego.Message) {
log.Println("***ON UPDATE....", m)
}

err = ch.Subscribe()
if err != nil {
log.Fatal(err)
}
}

func RealTimeVoyagerApplyRoutes(p *gin.RouterGroup) {
r := p.Group("/voyager_web_socket/")
{
r.POST("/messages", CreateMessage)
r.GET("/messages", GetMessages)
r.GET("/ws", HandleWebSocket)
go HandleMessages()
}
}

func HandleWebSocket(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Printf("WebSocket upgrade error: %v", err)
return
}
db, dbClose := dbflow.ConnectHackDatabase()
defer dbClose.Close()
defer conn.Close()

mutex.Lock()
clients[conn] = true
mutex.Unlock()

for {
var message VoyagerRandomeMessages
err := conn.ReadJSON(&message)
if err != nil {
log.Printf("WebSocket read error: %v", err)
mutex.Lock()
delete(clients, conn)
mutex.Unlock()
break
}

// Save the received message to the database
message.CreatedAt = time.Now()
message.ID = uuid.New()
if err := db.Create(&message).Error; err != nil {
log.Printf("Database insert error: %v", err)
continue
}

// Broadcast the message to other clients
broadcast <- message

}
}

func HandleMessages() {
for {
message := <-broadcast
mutex.Lock()
for client := range clients {
err := client.WriteJSON(message)
if err != nil {
log.Printf("WebSocket error: %v", err)
client.Close()
delete(clients, client)
}
}
mutex.Unlock()
}
}

func CreateMessage(c *gin.Context) {
db, dbClose := dbflow.ConnectHackDatabase()
defer dbClose.Close()
var message VoyagerRandomeMessages
message.ID = uuid.New()
fmt.Println("message.ID = ", message.ID)
if err := c.ShouldBindJSON(&message); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
message.CreatedAt = time.Now()
if err := db.Create(&message).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, message)
}

func GetMessages(c *gin.Context) {
db, dbClose := dbflow.ConnectHackDatabase()
defer dbClose.Close()
var messages []VoyagerRandomeMessages
if err := db.Find(&messages).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, messages)
}
15 changes: 15 additions & 0 deletions real_time_chat/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package realtimechat

import (
"time"

"github.com/google/uuid"
)

type VoyagerRandomeMessages struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primary_key;"`
UserId int `json:"userId" gorm:"type:integer"`
Content string `json:"content"`
Username string `json:"username"`
CreatedAt time.Time `json:"created_at"`
}
2 changes: 1 addition & 1 deletion voyagerRouting/voyager.routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func VoyagerApplyRoutes(p *gin.RouterGroup) {
r := p.Group("voyager")
r := p.Group("/voyager")
{
// GET API for people listing according to interest or location

Expand Down

0 comments on commit 30890d6

Please sign in to comment.