Compare commits
5 Commits
76755b69bf
...
06a2c55da5
Author | SHA1 | Date | |
---|---|---|---|
06a2c55da5 | |||
02098bd2cc | |||
d5ae19a0a4 | |||
ecd996e21e | |||
623e9e1ad5 |
49
api/auth.go
49
api/auth.go
@ -4,14 +4,17 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/config"
|
"git.tek.govt.hu/dowerx/chat/server/config"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/controller"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SESSION_COOKIE string = "session"
|
const (
|
||||||
|
SESSION_COOKIE string = "session"
|
||||||
|
USER_ID string = "user_id"
|
||||||
|
)
|
||||||
|
|
||||||
func isLoggedIn(c *gin.Context) {
|
func isLoggedIn(c *gin.Context) {
|
||||||
token, err := c.Cookie(SESSION_COOKIE)
|
token, err := c.Cookie(SESSION_COOKIE)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": "missing token",
|
"error": "missing token",
|
||||||
@ -20,7 +23,15 @@ func isLoggedIn(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id, authErr := authController.IsLoggedIn(token)
|
||||||
|
if authErr != nil {
|
||||||
|
sendError(c, authErr)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Set(SESSION_COOKIE, token)
|
c.Set(SESSION_COOKIE, token)
|
||||||
|
c.Set(USER_ID, id)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,13 +50,7 @@ func register(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authController, err := controller.MakeAuthController()
|
err := authController.Register(transaction.Username, transaction.Password, transaction.RepeatPassword)
|
||||||
if err != nil {
|
|
||||||
sendError(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = authController.Register(transaction.Username, transaction.Password, transaction.RepeatPassword)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(c, err)
|
sendError(c, err)
|
||||||
return
|
return
|
||||||
@ -69,19 +74,13 @@ func login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authController, err := controller.MakeAuthController()
|
|
||||||
if err != nil {
|
|
||||||
sendError(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := authController.Login(transaction.Username, transaction.Password)
|
token, err := authController.Login(transaction.Username, transaction.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(c, err)
|
sendError(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetCookie(SESSION_COOKIE, token, config.GetConfig().API.TokenLife, "", "", false, false)
|
c.SetCookie(SESSION_COOKIE, token, config.GetConfig().API.TokenLife, "/", "", false, false)
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "sucessful login",
|
"message": "sucessful login",
|
||||||
"session": token,
|
"session": token,
|
||||||
@ -89,34 +88,22 @@ func login(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func logout(c *gin.Context) {
|
func logout(c *gin.Context) {
|
||||||
authController, err := controller.MakeAuthController()
|
|
||||||
if err != nil {
|
|
||||||
sendError(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token, _ := c.Get(SESSION_COOKIE) // must exist after isLoggedIn
|
token, _ := c.Get(SESSION_COOKIE) // must exist after isLoggedIn
|
||||||
err = authController.Logout(token.(string))
|
err := authController.Logout(token.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(c, err)
|
sendError(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetCookie(SESSION_COOKIE, "", 0, "", "", false, false)
|
c.SetCookie(SESSION_COOKIE, "", 0, "/", "", false, false)
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "sucessful logout",
|
"message": "sucessful logout",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func bump(c *gin.Context) {
|
func bump(c *gin.Context) {
|
||||||
authController, err := controller.MakeAuthController()
|
|
||||||
if err != nil {
|
|
||||||
sendError(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token, _ := c.Get(SESSION_COOKIE)
|
token, _ := c.Get(SESSION_COOKIE)
|
||||||
if err = authController.Bump(token.(string)); err != nil {
|
if err := authController.Bump(token.(string)); err != nil {
|
||||||
sendError(c, err)
|
sendError(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
112
api/chat.go
Normal file
112
api/chat.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CHANNEL_ID string = "id"
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{
|
||||||
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 1024,
|
||||||
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
|
}
|
||||||
|
|
||||||
|
func listAvailableChannels(c *gin.Context) {
|
||||||
|
token, _ := c.Get(SESSION_COOKIE)
|
||||||
|
|
||||||
|
channels, err := chatController.ListAvailableChannels(token.(string))
|
||||||
|
if err != nil {
|
||||||
|
sendError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "channels listed",
|
||||||
|
"channels": channels,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessages(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param(CHANNEL_ID))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "invalid channel id",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
messages, msgErr := chatController.GetMessages(id)
|
||||||
|
if msgErr != nil {
|
||||||
|
sendError(c, msgErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "messages listed",
|
||||||
|
"messages": messages,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendMessage(c *gin.Context) {
|
||||||
|
token, _ := c.Get(SESSION_COOKIE)
|
||||||
|
|
||||||
|
message := model.Message{}
|
||||||
|
if err := c.Bind(&message); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := chatController.SendMessage(token.(string), message.Channel, message.Content)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
sendError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "message sent",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToChannel(c *gin.Context) {
|
||||||
|
// TODO: check if the user has right to subscribe to the given channel
|
||||||
|
id, err := strconv.Atoi(c.Param(CHANNEL_ID))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "invalid channel id",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
messages, chanErr := chatController.SubscribeToChannel(c, id)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg := <-messages:
|
||||||
|
if err := conn.WriteJSON(msg); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case err := <-chanErr:
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,12 +4,75 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/controller"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/dao"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var userController controller.UserController
|
||||||
|
var chatController controller.ChatController
|
||||||
|
var authController controller.AuthController
|
||||||
|
|
||||||
|
func initControlles() *util.ChatError {
|
||||||
|
userDAO, err := dao.GetUserDAO()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channelDAO, err := dao.GetChannelDAO()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionDAO, err := dao.GetSessionDAO()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
messageDAO, err := dao.GetMessageDAO()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
notifcationDAO, err := dao.GetNotificationDAO()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userController = controller.MakeUserController(userDAO)
|
||||||
|
authController = controller.MakeAuthController(userDAO, sessionDAO)
|
||||||
|
chatController = controller.MakeChatController(
|
||||||
|
channelDAO,
|
||||||
|
sessionDAO,
|
||||||
|
messageDAO,
|
||||||
|
notifcationDAO,
|
||||||
|
userDAO)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func Listen(address string, base string) error {
|
func Listen(address string, base string) error {
|
||||||
|
if err := initControlles(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
|
if gin.DebugMode == "debug" {
|
||||||
|
router.Use(func(c *gin.Context) {
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization")
|
||||||
|
if c.Request.Method == "OPTIONS" {
|
||||||
|
c.AbortWithStatus(204)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
api := router.Group(base)
|
api := router.Group(base)
|
||||||
|
|
||||||
auth := api.Group("auth")
|
auth := api.Group("auth")
|
||||||
@ -22,6 +85,13 @@ func Listen(address string, base string) error {
|
|||||||
user.Use(isLoggedIn)
|
user.Use(isLoggedIn)
|
||||||
user.GET("info/:username", userInfo)
|
user.GET("info/:username", userInfo)
|
||||||
|
|
||||||
|
chat := api.Group("chat")
|
||||||
|
chat.Use(isLoggedIn)
|
||||||
|
chat.GET("channels", listAvailableChannels)
|
||||||
|
chat.GET("messages/:id", getMessages)
|
||||||
|
chat.POST("send", sendMessage)
|
||||||
|
chat.GET("subscribe/:id", subscribeToChannel)
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Addr: address,
|
Addr: address,
|
||||||
Handler: router,
|
Handler: router,
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/controller"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,13 +11,6 @@ const USERNAME_PARAM string = "username"
|
|||||||
func userInfo(c *gin.Context) {
|
func userInfo(c *gin.Context) {
|
||||||
username := c.Param(USERNAME_PARAM)
|
username := c.Param(USERNAME_PARAM)
|
||||||
|
|
||||||
userController, err := controller.MakeUserController()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
sendError(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := userController.GetUser(username)
|
user, err := userController.GetUser(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(c, err)
|
sendError(c, err)
|
||||||
|
@ -6,16 +6,14 @@ import (
|
|||||||
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/config"
|
"git.tek.govt.hu/dowerx/chat/server/config"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/dao"
|
"git.tek.govt.hu/dowerx/chat/server/dao"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/dao/postgres"
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/dao/valkey"
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/model"
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/util"
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthController struct {
|
type AuthController struct {
|
||||||
UserDAO dao.IUserDAO
|
userDAO dao.IUserDAO
|
||||||
SessionDAO dao.ISessionDAO
|
sessionDAO dao.ISessionDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -25,6 +23,14 @@ const (
|
|||||||
TOKEN_LENGTH int = 32
|
TOKEN_LENGTH int = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c AuthController) IsLoggedIn(token string) (int, *util.ChatError) {
|
||||||
|
id, err := c.sessionDAO.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
err = &util.ChatError{Message: "", Code: util.NOT_LOGGED_IN}
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c AuthController) Register(username string, password string, repeatPassword string) *util.ChatError {
|
func (c AuthController) Register(username string, password string, repeatPassword string) *util.ChatError {
|
||||||
if len(username) < MIN_USERNAME_LENGTH {
|
if len(username) < MIN_USERNAME_LENGTH {
|
||||||
return &util.ChatError{Message: "", Code: util.USERNAME_TOO_SHORT}
|
return &util.ChatError{Message: "", Code: util.USERNAME_TOO_SHORT}
|
||||||
@ -44,7 +50,7 @@ func (c AuthController) Register(username string, password string, repeatPasswor
|
|||||||
return util.MakeError(err, util.GENERAL_ERROR)
|
return util.MakeError(err, util.GENERAL_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.UserDAO.Create(model.User{
|
return c.userDAO.Create(model.User{
|
||||||
Username: username,
|
Username: username,
|
||||||
PasswordHash: string(hash),
|
PasswordHash: string(hash),
|
||||||
})
|
})
|
||||||
@ -61,7 +67,7 @@ func generateToken(length int) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c AuthController) Login(username string, password string) (string, *util.ChatError) {
|
func (c AuthController) Login(username string, password string) (string, *util.ChatError) {
|
||||||
user, err := c.UserDAO.Read(model.User{Username: username})
|
user, err := c.userDAO.Read(model.User{Username: username})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -75,12 +81,12 @@ func (c AuthController) Login(username string, password string) (string, *util.C
|
|||||||
return "", util.MakeError(err, util.GENERAL_ERROR)
|
return "", util.MakeError(err, util.GENERAL_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.SessionDAO.DeleteAllByID(user.ID)
|
err = c.sessionDAO.DeleteAllByID(user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.SessionDAO.Set(token, user.ID)
|
err = c.sessionDAO.Set(token, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -89,30 +95,14 @@ func (c AuthController) Login(username string, password string) (string, *util.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c AuthController) Logout(token string) *util.ChatError {
|
func (c AuthController) Logout(token string) *util.ChatError {
|
||||||
return c.SessionDAO.Delete(token)
|
return c.sessionDAO.Delete(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AuthController) Bump(token string) *util.ChatError {
|
func (c AuthController) Bump(token string) *util.ChatError {
|
||||||
return c.SessionDAO.Bump(token, config.GetConfig().API.TokenLife)
|
return c.sessionDAO.Bump(token, config.GetConfig().API.TokenLife)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeAuthController() (AuthController, *util.ChatError) {
|
func MakeAuthController(userDAO dao.IUserDAO, sessionDAO dao.ISessionDAO) AuthController {
|
||||||
controller := AuthController{}
|
controller := AuthController{userDAO: userDAO, sessionDAO: sessionDAO}
|
||||||
|
return controller
|
||||||
userDAO := postgres.UserDAOPG{}
|
|
||||||
err := userDAO.Init()
|
|
||||||
if err != nil {
|
|
||||||
return controller, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionDAO := valkey.SessionDAOVK{}
|
|
||||||
err = sessionDAO.Init()
|
|
||||||
if err != nil {
|
|
||||||
return controller, err
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.UserDAO = userDAO
|
|
||||||
controller.SessionDAO = sessionDAO
|
|
||||||
|
|
||||||
return controller, nil
|
|
||||||
}
|
}
|
||||||
|
80
controller/ChatController.go
Normal file
80
controller/ChatController.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/dao"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatController struct {
|
||||||
|
channelDAO dao.IChannelDAO
|
||||||
|
sessionDAO dao.ISessionDAO
|
||||||
|
messageDAO dao.IMessageDAO
|
||||||
|
notifcationDAO dao.INotificationDAO
|
||||||
|
userDAO dao.IUserDAO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChatController) ListAvailableChannels(token string) ([]model.Channel, *util.ChatError) {
|
||||||
|
userID, err := c.sessionDAO.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.channelDAO.ListAvailableChannels(userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChatController) GetMessages(channel int) ([]model.Message, *util.ChatError) {
|
||||||
|
return c.messageDAO.List(model.Channel{ID: channel})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChatController) SendMessage(token string, channel int, content string) *util.ChatError {
|
||||||
|
sender_id, err := c.sessionDAO.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := c.userDAO.Read(model.User{ID: sender_id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if user has right to send message in the given channel
|
||||||
|
|
||||||
|
message := model.Message{
|
||||||
|
SenderID: user.ID,
|
||||||
|
SenderName: user.Username,
|
||||||
|
Channel: channel,
|
||||||
|
Time: time.Now().UTC(),
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
|
||||||
|
message.ID, err = c.messageDAO.Create(message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.notifcationDAO.SendMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChatController) SubscribeToChannel(ctx context.Context, id int) (<-chan model.Message, <-chan *util.ChatError) {
|
||||||
|
return c.notifcationDAO.SubscribeToChannel(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeChatController(
|
||||||
|
channelDAO dao.IChannelDAO,
|
||||||
|
sessionDAO dao.ISessionDAO,
|
||||||
|
messageDAO dao.IMessageDAO,
|
||||||
|
notificationDAO dao.INotificationDAO,
|
||||||
|
userDAO dao.IUserDAO) ChatController {
|
||||||
|
controller := ChatController{
|
||||||
|
channelDAO: channelDAO,
|
||||||
|
sessionDAO: sessionDAO,
|
||||||
|
messageDAO: messageDAO,
|
||||||
|
notifcationDAO: notificationDAO,
|
||||||
|
userDAO: userDAO,
|
||||||
|
}
|
||||||
|
return controller
|
||||||
|
}
|
@ -2,29 +2,19 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.tek.govt.hu/dowerx/chat/server/dao"
|
"git.tek.govt.hu/dowerx/chat/server/dao"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/dao/postgres"
|
|
||||||
"git.tek.govt.hu/dowerx/chat/server/model"
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
"git.tek.govt.hu/dowerx/chat/server/util"
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserController struct {
|
type UserController struct {
|
||||||
UserDAO dao.IUserDAO
|
userDAO dao.IUserDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c UserController) GetUser(username string) (model.User, *util.ChatError) {
|
func (c UserController) GetUser(username string) (model.User, *util.ChatError) {
|
||||||
return c.UserDAO.Read(model.User{Username: username})
|
return c.userDAO.Read(model.User{Username: username})
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeUserController() (UserController, *util.ChatError) {
|
func MakeUserController(userDAO dao.IUserDAO) UserController {
|
||||||
controller := UserController{}
|
controller := UserController{userDAO: userDAO}
|
||||||
|
return controller
|
||||||
userDAO := postgres.UserDAOPG{}
|
|
||||||
err := userDAO.Init()
|
|
||||||
if err != nil {
|
|
||||||
return controller, err
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.UserDAO = userDAO
|
|
||||||
|
|
||||||
return controller, nil
|
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var userDAO IUserDAO
|
var userDAO IUserDAO
|
||||||
|
var channelDAO IChannelDAO
|
||||||
var sessionDAO ISessionDAO
|
var sessionDAO ISessionDAO
|
||||||
|
var messageDAO IMessageDAO
|
||||||
|
var notifcationDAO INotificationDAO
|
||||||
|
|
||||||
func GetUserDAO() (IUserDAO, *util.ChatError) {
|
func GetUserDAO() (IUserDAO, *util.ChatError) {
|
||||||
if !userDAO.Ready() {
|
if userDAO == nil {
|
||||||
dao, err := postgres.MakeUserDAO()
|
dao, err := postgres.MakeUserDAO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return userDAO, err
|
return userDAO, err
|
||||||
@ -22,9 +25,35 @@ func GetUserDAO() (IUserDAO, *util.ChatError) {
|
|||||||
return userDAO, nil
|
return userDAO, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetChannelDAO() (IChannelDAO, *util.ChatError) {
|
||||||
|
if channelDAO == nil {
|
||||||
|
dao, err := postgres.MakeChannelDAO()
|
||||||
|
if err != nil {
|
||||||
|
return channelDAO, err
|
||||||
|
}
|
||||||
|
|
||||||
|
channelDAO = dao
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelDAO, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMessageDAO() (IMessageDAO, *util.ChatError) {
|
||||||
|
if messageDAO == nil {
|
||||||
|
dao, err := postgres.MakeMessageDAO()
|
||||||
|
if err != nil {
|
||||||
|
return messageDAO, err
|
||||||
|
}
|
||||||
|
|
||||||
|
messageDAO = dao
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageDAO, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetSessionDAO() (ISessionDAO, *util.ChatError) {
|
func GetSessionDAO() (ISessionDAO, *util.ChatError) {
|
||||||
if !sessionDAO.Ready() {
|
if sessionDAO == nil {
|
||||||
dao, err := valkey.MakeUserDAO()
|
dao, err := valkey.MakeSessionDAO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sessionDAO, err
|
return sessionDAO, err
|
||||||
}
|
}
|
||||||
@ -34,3 +63,16 @@ func GetSessionDAO() (ISessionDAO, *util.ChatError) {
|
|||||||
|
|
||||||
return sessionDAO, nil
|
return sessionDAO, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetNotificationDAO() (INotificationDAO, *util.ChatError) {
|
||||||
|
if notifcationDAO == nil {
|
||||||
|
dao, err := valkey.MakeNotificationDAO()
|
||||||
|
if err != nil {
|
||||||
|
return notifcationDAO, err
|
||||||
|
}
|
||||||
|
|
||||||
|
notifcationDAO = dao
|
||||||
|
}
|
||||||
|
|
||||||
|
return notifcationDAO, nil
|
||||||
|
}
|
||||||
|
15
dao/IChannelDAO.go
Normal file
15
dao/IChannelDAO.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IChannelDAO interface {
|
||||||
|
Create(channel model.Channel) *util.ChatError
|
||||||
|
Read(channel model.Channel) (model.Channel, *util.ChatError)
|
||||||
|
List() ([]model.Channel, *util.ChatError)
|
||||||
|
ListAvailableChannels(userID int) ([]model.Channel, *util.ChatError)
|
||||||
|
Update(channel model.Channel) *util.ChatError
|
||||||
|
Delete(id int) *util.ChatError
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
type IDAO interface {
|
|
||||||
Ready() bool
|
|
||||||
}
|
|
14
dao/IMessageDAO.go
Normal file
14
dao/IMessageDAO.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IMessageDAO interface {
|
||||||
|
Create(message model.Message) (int, *util.ChatError)
|
||||||
|
Read(id int) (model.Message, *util.ChatError)
|
||||||
|
List(channel model.Channel) ([]model.Message, *util.ChatError)
|
||||||
|
Update(message model.Message) *util.ChatError
|
||||||
|
Delete(id int) *util.ChatError
|
||||||
|
}
|
13
dao/INotificationDAO.go
Normal file
13
dao/INotificationDAO.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type INotificationDAO interface {
|
||||||
|
SendMessage(message model.Message) *util.ChatError
|
||||||
|
SubscribeToChannel(ctx context.Context, id int) (<-chan model.Message, <-chan *util.ChatError)
|
||||||
|
}
|
@ -3,7 +3,6 @@ package dao
|
|||||||
import "git.tek.govt.hu/dowerx/chat/server/util"
|
import "git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
|
||||||
type ISessionDAO interface {
|
type ISessionDAO interface {
|
||||||
IDAO
|
|
||||||
Set(token string, id int) *util.ChatError
|
Set(token string, id int) *util.ChatError
|
||||||
Get(token string) (int, *util.ChatError)
|
Get(token string) (int, *util.ChatError)
|
||||||
Delete(token string) *util.ChatError
|
Delete(token string) *util.ChatError
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IUserDAO interface {
|
type IUserDAO interface {
|
||||||
IDAO
|
|
||||||
Create(user model.User) *util.ChatError
|
Create(user model.User) *util.ChatError
|
||||||
Read(user model.User) (model.User, *util.ChatError)
|
Read(user model.User) (model.User, *util.ChatError)
|
||||||
List() ([]model.User, *util.ChatError)
|
List() ([]model.User, *util.ChatError)
|
||||||
|
107
dao/postgres/ChannelDAO.go
Normal file
107
dao/postgres/ChannelDAO.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChannelDAOPG struct {
|
||||||
|
pgDAO
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new channel
|
||||||
|
func (d ChannelDAOPG) Create(channel model.Channel) *util.ChatError {
|
||||||
|
_, err := d.db.NamedExec(`call add_channel(:name, :description)`, &channel)
|
||||||
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read returns a channel by ID
|
||||||
|
func (d ChannelDAOPG) Read(channel model.Channel) (model.Channel, *util.ChatError) {
|
||||||
|
var rows *sqlx.Rows
|
||||||
|
var err error
|
||||||
|
rows, err = d.db.NamedQuery(`select * from "channel" where "id" = :id`, &channel)
|
||||||
|
if err != nil {
|
||||||
|
return channel, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return channel, &util.ChatError{Message: "", Code: util.NOT_FOUND}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.StructScan(&channel)
|
||||||
|
return channel, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all channels
|
||||||
|
func (d ChannelDAOPG) List() ([]model.Channel, *util.ChatError) {
|
||||||
|
rows, err := d.db.Queryx(`select * from "channel" order by "name"`)
|
||||||
|
if err != nil {
|
||||||
|
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
channels := make([]model.Channel, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
channel := model.Channel{}
|
||||||
|
|
||||||
|
err = rows.StructScan(&channel)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
channels = append(channels, channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAvailableChannels returns channels that the given user has access to
|
||||||
|
func (d ChannelDAOPG) ListAvailableChannels(userID int) ([]model.Channel, *util.ChatError) {
|
||||||
|
rows, err := d.db.Queryx(`select "channel_id" as "id", "channel_name" as "name", "channel_description" as "description" from "user_rigths_per_channel" where "user_id" = $1 order by "id"`, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
channels := make([]model.Channel, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
channel := model.Channel{}
|
||||||
|
|
||||||
|
err = rows.StructScan(&channel)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
channels = append(channels, channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update sets all the fields of the Channel with the given ID
|
||||||
|
func (d ChannelDAOPG) Update(channel model.Channel) *util.ChatError {
|
||||||
|
_, err := d.db.NamedExec(`update "channel" set "name" = :name, "description" = :description where "id" = :id`, &channel)
|
||||||
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a channel by ID
|
||||||
|
func (d ChannelDAOPG) Delete(id int) *util.ChatError {
|
||||||
|
var err error
|
||||||
|
_, err = d.db.NamedExec(`delete from "channel" where "id" = $1`, id)
|
||||||
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeChannelDAO() (ChannelDAOPG, *util.ChatError) {
|
||||||
|
dao := ChannelDAOPG{}
|
||||||
|
conn, err := getDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return dao, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dao.db = conn
|
||||||
|
return dao, nil
|
||||||
|
}
|
126
dao/postgres/MessageDAO.go
Normal file
126
dao/postgres/MessageDAO.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MessageDAO struct {
|
||||||
|
pgDAO
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new message
|
||||||
|
func (d MessageDAO) Create(message model.Message) (int, *util.ChatError) {
|
||||||
|
rows, err := d.db.NamedQuery(`insert into "message" ("sender_id", "channel_id", "time", "content") values (:sender_id, :channel_id, :time, :content) returning "id"`, &message)
|
||||||
|
if err != nil {
|
||||||
|
return 0, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return 0, &util.ChatError{Message: "failed to insert new message", Code: util.DATABASE_QUERY_FAULT}
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
if rows.Scan(&id) != nil {
|
||||||
|
return 0, &util.ChatError{Message: "failed to return new message id", Code: util.DATABASE_QUERY_FAULT}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(id), util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read returns a message by ID
|
||||||
|
func (d MessageDAO) Read(id int) (model.Message, *util.ChatError) {
|
||||||
|
message := model.Message{}
|
||||||
|
|
||||||
|
var rows *sqlx.Rows
|
||||||
|
var err error
|
||||||
|
rows, err = d.db.NamedQuery(`select * from "message" where "id" = $1`, id)
|
||||||
|
if err != nil {
|
||||||
|
return message, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return message, &util.ChatError{Message: "", Code: util.NOT_FOUND}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.StructScan(&message)
|
||||||
|
return message, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all messages in channel by ID or name
|
||||||
|
func (d MessageDAO) List(channel model.Channel) ([]model.Message, *util.ChatError) {
|
||||||
|
var rows *sqlx.Rows
|
||||||
|
var err error
|
||||||
|
if channel.ID != 0 {
|
||||||
|
rows, err = d.db.NamedQuery(
|
||||||
|
`select
|
||||||
|
"m"."id" as "id",
|
||||||
|
"u"."username" as "sender_name",
|
||||||
|
"m"."channel_id" as "channel_id",
|
||||||
|
"m"."time" as "time",
|
||||||
|
"m"."content" as "content"
|
||||||
|
from "message" as "m"
|
||||||
|
inner join "user" "u" on "u"."id" = "m"."sender_id"
|
||||||
|
where "m"."channel_id" = :id order by "time"`,
|
||||||
|
&channel)
|
||||||
|
} else {
|
||||||
|
rows, err = d.db.NamedQuery(
|
||||||
|
`select
|
||||||
|
"m"."id" as "id",
|
||||||
|
"u"."username" as "sender_name",
|
||||||
|
"m"."channel_id" as "channel_id",
|
||||||
|
"m"."time" as "time",
|
||||||
|
"m"."content" as "content"
|
||||||
|
from "message" as "m"
|
||||||
|
inner join "user" "u" on "u"."id" = "m"."sender_id"
|
||||||
|
inner join "channel" "c" on "c"."id" = "m"."channel_id"
|
||||||
|
where "c"."name" = :name order by "time"`,
|
||||||
|
&channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
messages := make([]model.Message, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
message := model.Message{}
|
||||||
|
|
||||||
|
err = rows.StructScan(&message)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
messages = append(messages, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages, util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the contents and time of a Message with the given ID
|
||||||
|
func (d MessageDAO) Update(message model.Message) *util.ChatError {
|
||||||
|
_, err := d.db.NamedExec(`update "message" set "content" = :content, "time" = :time where "id" = :id`, &message)
|
||||||
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a message by ID
|
||||||
|
func (d MessageDAO) Delete(id int) *util.ChatError {
|
||||||
|
var err error
|
||||||
|
_, err = d.db.NamedExec(`delete from "message" where "id" = $1`, id)
|
||||||
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeMessageDAO() (MessageDAO, *util.ChatError) {
|
||||||
|
dao := MessageDAO{}
|
||||||
|
conn, err := getDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return dao, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dao.db = conn
|
||||||
|
return dao, nil
|
||||||
|
}
|
@ -32,7 +32,7 @@ func (d UserDAOPG) Read(user model.User) (model.User, *util.ChatError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !rows.Next() {
|
if !rows.Next() {
|
||||||
return user, &util.ChatError{Message: "", Code: util.USER_NOT_FOUND}
|
return user, &util.ChatError{Message: "", Code: util.NOT_FOUND}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = rows.StructScan(&user)
|
err = rows.StructScan(&user)
|
||||||
@ -81,10 +81,6 @@ func (d UserDAOPG) Delete(user model.User) *util.ChatError {
|
|||||||
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
return util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d UserDAOPG) Ready() bool {
|
|
||||||
return d.db != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeUserDAO() (UserDAOPG, *util.ChatError) {
|
func MakeUserDAO() (UserDAOPG, *util.ChatError) {
|
||||||
dao := UserDAOPG{}
|
dao := UserDAOPG{}
|
||||||
conn, err := getDatabase()
|
conn, err := getDatabase()
|
||||||
|
65
dao/valkey/NotificationDAO.go
Normal file
65
dao/valkey/NotificationDAO.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package valkey
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/model"
|
||||||
|
"git.tek.govt.hu/dowerx/chat/server/util"
|
||||||
|
"github.com/valkey-io/valkey-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CHANNEL_PREFIX string = "channel:"
|
||||||
|
|
||||||
|
type NotificationDAOVK struct {
|
||||||
|
vkDAO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d NotificationDAOVK) SendMessage(message model.Message) *util.ChatError {
|
||||||
|
data, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return util.MakeError(err, util.GENERAL_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := (*d.vk).B().Publish().Channel(CHANNEL_PREFIX + strconv.Itoa(message.Channel)).Message(string(data)).Build()
|
||||||
|
|
||||||
|
return util.MakeError((*d.vk).Do(context.Background(), cmd).Error(), util.DATABASE_QUERY_FAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d NotificationDAOVK) SubscribeToChannel(ctx context.Context, id int) (<-chan model.Message, <-chan *util.ChatError) {
|
||||||
|
cmd := (*d.vk).B().Subscribe().Channel(CHANNEL_PREFIX + strconv.Itoa(id)).Build()
|
||||||
|
|
||||||
|
var messages chan model.Message = make(chan model.Message, 1)
|
||||||
|
var errChan chan *util.ChatError = make(chan *util.ChatError, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := (*d.vk).Receive(ctx, cmd, func(msg valkey.PubSubMessage) {
|
||||||
|
go func() {
|
||||||
|
message := model.Message{}
|
||||||
|
err := json.Unmarshal([]byte(msg.Message), &message)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
messages <- message
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
defer close(messages)
|
||||||
|
|
||||||
|
errChan <- util.MakeError(err, util.DATABASE_QUERY_FAULT)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return messages, errChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeNotificationDAO() (NotificationDAOVK, *util.ChatError) {
|
||||||
|
dao := NotificationDAOVK{}
|
||||||
|
conn, err := getClient()
|
||||||
|
if err != nil {
|
||||||
|
return dao, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dao.vk = conn
|
||||||
|
return dao, nil
|
||||||
|
}
|
@ -89,11 +89,7 @@ func (d SessionDAOVK) Bump(token string, time int) *util.ChatError {
|
|||||||
return util.MakeError((*d.vk).Do(context.Background(), cmd).Error(), util.DATABASE_QUERY_FAULT)
|
return util.MakeError((*d.vk).Do(context.Background(), cmd).Error(), util.DATABASE_QUERY_FAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d SessionDAOVK) Ready() bool {
|
func MakeSessionDAO() (SessionDAOVK, *util.ChatError) {
|
||||||
return d.vk != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeUserDAO() (SessionDAOVK, *util.ChatError) {
|
|
||||||
dao := SessionDAOVK{}
|
dao := SessionDAOVK{}
|
||||||
conn, err := getClient()
|
conn, err := getClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
1
go.mod
1
go.mod
@ -20,6 +20,7 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -25,6 +25,8 @@ github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqw
|
|||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
ID int
|
ID int `db:"id" json:"id"`
|
||||||
Name string
|
Name string `db:"name" json:"name"`
|
||||||
|
Description string `db:"description" json:"description"`
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,10 @@ package model
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
ID int
|
ID int `db:"id" json:"id"`
|
||||||
Sender string // username
|
SenderID int `db:"sender_id" json:"-"`
|
||||||
Channel Channel // channel.id
|
SenderName string `db:"sender_name" json:"sender_name"`
|
||||||
Time time.Time
|
Channel int `db:"channel_id" form:"channel_id" json:"channel_id"`
|
||||||
Content string
|
Time time.Time `db:"time" json:"time"`
|
||||||
|
Content string `db:"content" form:"content" json:"content"`
|
||||||
}
|
}
|
||||||
|
@ -13,22 +13,25 @@ const (
|
|||||||
DATABASE_CONNECTION_FAULT
|
DATABASE_CONNECTION_FAULT
|
||||||
DATABASE_QUERY_FAULT
|
DATABASE_QUERY_FAULT
|
||||||
|
|
||||||
USER_NOT_FOUND
|
NOT_FOUND
|
||||||
WRONG_PASSWORD
|
WRONG_PASSWORD
|
||||||
USERNAME_TOO_SHORT
|
USERNAME_TOO_SHORT
|
||||||
PASSWORD_TOO_SHORT
|
PASSWORD_TOO_SHORT
|
||||||
PASSWORDS_DONT_MATCH
|
PASSWORDS_DONT_MATCH
|
||||||
|
|
||||||
|
NOT_LOGGED_IN
|
||||||
)
|
)
|
||||||
|
|
||||||
var codeToMessage = map[ChatErrorCode]string{
|
var codeToMessage = map[ChatErrorCode]string{
|
||||||
GENERAL_ERROR: "an unexpected error occurred",
|
GENERAL_ERROR: "an unexpected error occurred",
|
||||||
DATABASE_CONNECTION_FAULT: "database connection failed",
|
DATABASE_CONNECTION_FAULT: "database connection failed",
|
||||||
DATABASE_QUERY_FAULT: "database query failed",
|
DATABASE_QUERY_FAULT: "database query failed",
|
||||||
USER_NOT_FOUND: "user not found",
|
NOT_FOUND: "item not found",
|
||||||
WRONG_PASSWORD: "incorrect password",
|
WRONG_PASSWORD: "incorrect password",
|
||||||
USERNAME_TOO_SHORT: "username is too short",
|
USERNAME_TOO_SHORT: "username is too short",
|
||||||
PASSWORD_TOO_SHORT: "password is too short",
|
PASSWORD_TOO_SHORT: "password is too short",
|
||||||
PASSWORDS_DONT_MATCH: "passwords do not match",
|
PASSWORDS_DONT_MATCH: "passwords do not match",
|
||||||
|
NOT_LOGGED_IN: "not logged in",
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatError struct {
|
type ChatError struct {
|
||||||
@ -58,7 +61,7 @@ func (e *ChatError) ErrorFromCode() string {
|
|||||||
// Status returns the http status of the error type
|
// Status returns the http status of the error type
|
||||||
func (e *ChatError) Status() int {
|
func (e *ChatError) Status() int {
|
||||||
switch e.Code {
|
switch e.Code {
|
||||||
case USER_NOT_FOUND:
|
case NOT_FOUND:
|
||||||
fallthrough
|
fallthrough
|
||||||
case WRONG_PASSWORD:
|
case WRONG_PASSWORD:
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -68,6 +71,8 @@ func (e *ChatError) Status() int {
|
|||||||
fallthrough
|
fallthrough
|
||||||
case PASSWORDS_DONT_MATCH:
|
case PASSWORDS_DONT_MATCH:
|
||||||
return http.StatusOK
|
return http.StatusOK
|
||||||
|
case NOT_LOGGED_IN:
|
||||||
|
return http.StatusUnauthorized
|
||||||
default:
|
default:
|
||||||
return http.StatusInternalServerError
|
return http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user