rewrite connections, messages system, add dm message history, fix multiple bugs, update machine-client
This commit is contained in:
@@ -12,6 +12,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-socket/Enums/ConnectionState"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
@@ -23,20 +25,29 @@ func isMethodAllowed(response *http.ResponseWriter, request *http.Request) bool
|
||||
return true
|
||||
}
|
||||
|
||||
func getWholeUserFromDb(ctx context.Context, user *User) error {
|
||||
if err := DbUserGetById(ctx, user); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DbUserGetGroups(ctx, user); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DbConnectionsGetBelongingToUser(ctx, user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
CacheSaveUser(user)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUserById(ctx context.Context, userId uint32) (*User, error) {
|
||||
user, err := CacheGetUserById(userId)
|
||||
if err != nil {
|
||||
user = &User{Id: userId}
|
||||
if err = DbUserGetById(ctx, user); err != nil {
|
||||
err = getWholeUserFromDb(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = DbUserGetGroups(ctx, user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = DbConnectionsGetBelongingToUser(ctx, user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
CacheSaveUser(user)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
@@ -98,6 +109,25 @@ func getIfOwnerUserAndGroup(ctx context.Context, response *http.ResponseWriter,
|
||||
return user, group, nil
|
||||
}
|
||||
|
||||
func getUserByTokenGetUserByIdStrHandleHttp(ctx context.Context, response *http.ResponseWriter, token string, userIdStr string) (*User, *User, error) {
|
||||
user, err := getUserByToken(ctx, token)
|
||||
if err != nil {
|
||||
http.Error(*response, "invalid token", http.StatusUnauthorized)
|
||||
return nil, nil, err
|
||||
}
|
||||
affectedUserId, err := ConvertStringUint32(userIdStr)
|
||||
if err != nil {
|
||||
http.Error(*response, "no such user", http.StatusUnauthorized)
|
||||
return nil, nil, err
|
||||
}
|
||||
user2, err := getUserById(ctx, affectedUserId)
|
||||
if err != nil {
|
||||
http.Error(*response, "no such user", http.StatusUnauthorized)
|
||||
return nil, nil, err
|
||||
}
|
||||
return user, user2, nil
|
||||
}
|
||||
|
||||
func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) {
|
||||
if !isMethodAllowed(&response, request) {
|
||||
return
|
||||
@@ -234,19 +264,97 @@ func HttpHandleUserMessage(response http.ResponseWriter, request *http.Request)
|
||||
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{
|
||||
Content: msgContent,
|
||||
CreatedAt: time.Now(),
|
||||
Sender: user.Id,
|
||||
Receiver: target.Id,
|
||||
IsGroupMessage: false,
|
||||
}
|
||||
|
||||
err = DbMessageSave(ctx, message)
|
||||
if err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
WsSendToUser(target, message)
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Request) {
|
||||
if !isMethodAllowed(&response, request) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx := request.Context()
|
||||
user, err := getUserByToken(ctx, request.FormValue("token"))
|
||||
requestor, recipient, err := getUserByTokenGetUserByIdStrHandleHttp(ctx, &response, request.FormValue("token"), request.FormValue("recipient"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid token", 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) {
|
||||
@@ -260,19 +368,94 @@ func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http.
|
||||
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 HttpHandleUserAcceptConnection(response http.ResponseWriter, request *http.Request) {
|
||||
func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http.Request) {
|
||||
if !isMethodAllowed(&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) {
|
||||
@@ -285,6 +468,18 @@ func HttpHandleUserGetConnections(response http.ResponseWriter, request *http.Re
|
||||
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)
|
||||
}
|
||||
|
||||
func HttpHandleTokenNew(response http.ResponseWriter, request *http.Request) {
|
||||
@@ -314,19 +509,14 @@ func HttpHandleTokenNew(response http.ResponseWriter, request *http.Request) {
|
||||
user, err = CacheGetUserByName(username)
|
||||
if err != nil {
|
||||
user = &User{Name: username}
|
||||
if err = DbUserGetByName(ctx, user); err != nil {
|
||||
if err = DbUserGetStandardInfoByName(ctx, user); err != nil {
|
||||
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if err = DbUserGetGroups(ctx, user); err != nil {
|
||||
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||
if err = getWholeUserFromDb(ctx, user); err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err = DbUserGetConnections(ctx, user); err != nil {
|
||||
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
CacheSaveUser(user)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password))
|
||||
@@ -342,9 +532,13 @@ func HttpHandleTokenNew(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
json, err := json2.Marshal(LoginReturn{Token: token, UserId: user.Id})
|
||||
if err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteHeader(http.StatusCreated)
|
||||
response.Write([]byte(json))
|
||||
response.Write(json)
|
||||
}
|
||||
|
||||
func HttpHandeGroupCreate(response http.ResponseWriter, request *http.Request) {
|
||||
@@ -411,6 +605,7 @@ func HttpHandleGroupDelete(response http.ResponseWriter, request *http.Request)
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
CacheDeleteGroup(group.Id)
|
||||
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
@@ -466,6 +661,11 @@ func HttpHandleGroupAddUsers(response http.ResponseWriter, request *http.Request
|
||||
|
||||
for i := uint32(0); i < idx; i++ {
|
||||
group.Users[ids[i]] = struct{}{}
|
||||
if cachedUser, err := CacheGetUserById(ids[i]); err == nil {
|
||||
cachedUser.Mu.Lock()
|
||||
cachedUser.Groups[group.Id] = struct{}{}
|
||||
cachedUser.Mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
@@ -513,6 +713,11 @@ func HttpHandleGroupRemoveUser(response http.ResponseWriter, request *http.Reque
|
||||
|
||||
for i := uint32(0); i < idx; i++ {
|
||||
delete(group.Users, ids[i])
|
||||
if cachedUser, err := CacheGetUserById(ids[i]); err == nil {
|
||||
cachedUser.Mu.Lock()
|
||||
delete(cachedUser.Groups, group.Id)
|
||||
cachedUser.Mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
@@ -563,13 +768,16 @@ func HttpHandleGroupChangeOwner(response http.ResponseWriter, request *http.Requ
|
||||
newOwner, err := CacheGetUserByName(newOwnerName)
|
||||
if err != nil {
|
||||
newOwner = &User{Name: newOwnerName}
|
||||
err = DbUserGetByName(ctx, newOwner)
|
||||
err = DbUserGetStandardInfoByName(ctx, newOwner)
|
||||
if err != nil {
|
||||
http.Error(response, "user not in group", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
CacheSaveUser(newOwner)
|
||||
if err = getWholeUserFromDb(ctx, newOwner); err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, ok := group.Users[newOwner.Id]
|
||||
@@ -646,8 +854,15 @@ func HttpHandleGroupsGetWithoutMembers(response http.ResponseWriter, request *ht
|
||||
return
|
||||
}
|
||||
|
||||
groups := make(map[uint32]*Group, len(user.Groups))
|
||||
user.Mu.RLock()
|
||||
groupIds := make([]uint32, 0, len(user.Groups))
|
||||
for groupId := range user.Groups {
|
||||
groupIds = append(groupIds, groupId)
|
||||
}
|
||||
user.Mu.RUnlock()
|
||||
|
||||
groups := make(map[uint32]*Group, len(groupIds))
|
||||
for _, groupId := range groupIds {
|
||||
group, err := getGroup(ctx, groupId)
|
||||
if err != nil {
|
||||
continue
|
||||
@@ -684,7 +899,9 @@ func HttpHandleGroupMembersGet(response http.ResponseWriter, request *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
user.Mu.RLock()
|
||||
_, ok := user.Groups[groupId]
|
||||
user.Mu.RUnlock()
|
||||
if !ok {
|
||||
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user