Files
go-socket/httpConnectionAndDm.go
T
2026-04-11 23:04:50 +02:00

332 lines
8.5 KiB
Go

package main
import (
json2 "encoding/json"
"maps"
"net/http"
"slices"
"time"
"go-socket/Enums/ConnectionState"
"github.com/google/uuid"
)
func HttpHandleUserMessage(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
user, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
targetConnection, err := ConvertStringUuid(request.FormValue("connectionid"))
if err != nil {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
conn, ok := CacheGetConnection(user, targetConnection)
if !ok {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
msgContent := request.FormValue("msgContent")
if msgContent == "" {
http.Error(response, "empty msgContent", http.StatusBadRequest)
return
}
var target *User
if user.Id == conn.RequestorId {
target, err = GetUserById(ctx, conn.RecipientId)
} else if user.Id == conn.RecipientId {
target, err = GetUserById(ctx, conn.RequestorId)
} else {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
message := &Message{
Id: uuid.New(),
Content: msgContent,
CreatedAt: time.Now(),
Sender: user.Id,
Receiver: conn.Id,
}
WsMessageSendToUser(target, message)
err = DbMessageSave(ctx, message)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted)
}
func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
user, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
if err != nil {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
before, err := ConvertStringTimestamp(request.FormValue("before"))
if err != nil {
before = time.Now()
}
messagesCap, err := ConvertStringUint32(request.FormValue("messages"))
if err != nil {
messagesCap = MaxDirectMsgCache
}
conn, ok := CacheGetConnection(user, connectionId)
if !ok {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
buffer, bufferSize := conn.GetSortedMessagesBuff()
var validBufCount uint32
for validBufCount < bufferSize && buffer[validBufCount].CreatedAt.Before(before) {
validBufCount++
}
var messages []*Message
if validBufCount >= messagesCap {
start := validBufCount - messagesCap
messages = make([]*Message, messagesCap)
for i := uint32(0); i < messagesCap; i++ {
messages[i] = buffer[start+i]
}
} else {
remaining := messagesCap - validBufCount
cutoff := before
if validBufCount > 0 {
cutoff = buffer[0].CreatedAt
}
dbMessages, err := DbConnectionGetMessagesBefore(ctx, cutoff, connectionId, remaining)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
messages = make([]*Message, 0, uint32(len(dbMessages))+validBufCount)
messages = append(messages, dbMessages...)
for i := uint32(0); i < validBufCount; i++ {
messages = append(messages, buffer[i])
}
}
json, err := json2.Marshal(messages)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
response.Write(json)
}
func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
requestor, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
recipientId, err := ConvertStringUint32(request.FormValue("recipient"))
if err != nil {
http.Error(response, "no such user", http.StatusUnauthorized)
return
}
recipient, err := GetUserById(ctx, recipientId)
if err != nil {
http.Error(response, "no such user", http.StatusUnauthorized)
return
}
if requestor.Id == recipient.Id {
http.Error(response, "cannot connect to yourself", http.StatusBadRequest)
return
}
requestor.Mu.RLock()
for _, connection := range requestor.Connections {
if (connection.RequestorId == requestor.Id && connection.RecipientId == recipient.Id) ||
(connection.RecipientId == requestor.Id && connection.RequestorId == recipient.Id) {
requestor.Mu.RUnlock()
http.Error(response, "connection already exists", http.StatusBadRequest)
return
}
}
requestor.Mu.RUnlock()
connection := &Connection{
CreatedAt: time.Now(),
RequestorId: requestor.Id,
RecipientId: recipient.Id,
State: ConnectionState.Stranger,
}
err = DbConnectionSave(ctx, connection)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
CacheAddConnection(requestor, recipient, connection)
response.WriteHeader(http.StatusCreated)
return
}
func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
user, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
if err != nil {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
conn, ok := CacheGetConnection(user, connectionId)
if !ok {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
var user2 *User
if conn.RequestorId == user.Id {
recipient, err := GetUserById(ctx, conn.RecipientId)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
user2 = recipient
} else if conn.RecipientId == user.Id {
requestor, err := GetUserById(ctx, conn.RequestorId)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
user2 = requestor
} else {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
err = DbConnectionDelete(ctx, conn)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
CacheDeleteConnection(user, user2, connectionId)
response.WriteHeader(http.StatusAccepted)
}
func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
user, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
if err != nil {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
conn, ok := CacheGetConnection(user, connectionId)
if !ok {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
if conn.RecipientId != user.Id {
http.Error(response, "invalid connectionid", http.StatusBadRequest)
return
}
switch conn.State {
case ConnectionState.Stranger:
conn.State = ConnectionState.Friend
break
case ConnectionState.GroupFellow:
conn.State = ConnectionState.Stranger
break
default:
http.Error(response, "cannot elevate further", http.StatusBadRequest)
return
}
err = DbConnectionUpdateState(ctx, conn)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted)
}
func HttpHandleUserGetConnections(response http.ResponseWriter, request *http.Request) {
if !HttpMethodAllowed(&response, request) {
return
}
ctx := request.Context()
user, err := GetUserByToken(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
user.Mu.RLock()
connections := slices.Collect(maps.Values(user.Connections))
user.Mu.RUnlock()
json, err := json2.Marshal(connections)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
response.Write(json)
}