From bd1168aef7c95109bd8ae68f0b8a7fdc5b2105f9 Mon Sep 17 00:00:00 2001 From: Sisi Date: Fri, 3 Apr 2026 19:33:26 +0200 Subject: [PATCH] change client to user --- cache.go | 36 ++++++------ database.go | 92 +++++++++++++++--------------- globals.go | 4 +- http.go | 157 ++++++++++++++++++++++++++-------------------------- main.go | 6 +- structs.go | 32 +++++------ tokens.go | 4 +- wsServer.go | 94 +++++++++++++++---------------- 8 files changed, 212 insertions(+), 213 deletions(-) diff --git a/cache.go b/cache.go index 9b4bbd3..8462f47 100644 --- a/cache.go +++ b/cache.go @@ -6,54 +6,54 @@ import ( ) var ( - CacheClients = make(map[uint32]*Client) - mu sync.RWMutex - Groups = make(map[uint32]*Group) + CacheUsers = make(map[uint32]*User) + mu sync.RWMutex + Groups = make(map[uint32]*Group) ) -func CacheGetClientById(id uint32) (*Client, error) { +func CacheGetUserById(id uint32) (*User, error) { mu.RLock() defer mu.RUnlock() - client, ok := CacheClients[id] + user, ok := CacheUsers[id] if !ok { - return nil, fmt.Errorf("client %d not found", id) + return nil, fmt.Errorf("user %d not found", id) } - return client, nil + return user, nil } func CacheGetIdByName(name string) (uint32, error) { - client, err := CacheGetClientByName(name) + user, err := CacheGetUserByName(name) if err != nil { return 0, err } - return client.Id, nil + return user.Id, nil } -func CacheGetClientByName(name string) (*Client, error) { +func CacheGetUserByName(name string) (*User, error) { mu.RLock() defer mu.RUnlock() - for _, client := range CacheClients { - if client.Name == name { - return client, nil + for _, user := range CacheUsers { + if user.Name == name { + return user, nil } } - return nil, fmt.Errorf("client %s not found", name) + return nil, fmt.Errorf("user %s not found", name) } -func CacheSaveClient(client *Client) { +func CacheSaveUser(user *User) { mu.Lock() defer mu.Unlock() - CacheClients[client.Id] = client + CacheUsers[user.Id] = user } -func CacheDeleteClient(id uint32) { +func CacheDeleteUser(id uint32) { mu.Lock() defer mu.Unlock() - delete(CacheClients, id) + delete(CacheUsers, id) } func CacheSaveGroup(group *Group) { diff --git a/database.go b/database.go index 44bc12b..a4a8ad5 100644 --- a/database.go +++ b/database.go @@ -63,57 +63,57 @@ func DbInit(ctx context.Context) { } } -// DbSaveClientWithoutGroups saves client in db without groups and sets its id +// DbSaveUserWithoutGroups saves user in db without groups and sets its id // return: error if not successful -func DbSaveClientWithoutGroups(ctx context.Context, client *Client) error { +func DbSaveUserWithoutGroups(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` INSERT INTO clients (name, pass_hash, pronouns, color_red, color_green, color_blue, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id - `, client.Name, client.PasswordHash, client.Pronouns, client.Color[0], client.Color[1], client.Color[2], client.CreatedAt). - Scan(&client.Id) + `, user.Name, user.PasswordHash, user.Pronouns, user.Color[0], user.Color[1], user.Color[2], user.CreatedAt). + Scan(&user.Id) return err } -// DbSetClientByName sets all fields of given struct with database's data using name +// DbSetUserByName sets all fields of given struct with database's data using name // return: error if not successful -func DbSetClientByName(ctx context.Context, client *Client) error { +func DbSetUserByName(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` SELECT id, name, pass_hash, pronouns, color_red, color_green, color_blue, created_at FROM clients WHERE name = $1 - `, client.Name).Scan(&client.Id, &client.Name, &client.PasswordHash, &client.Pronouns, &client.Color[0], &client.Color[1], &client.Color[2], &client.CreatedAt) + `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &user.Color[0], &user.Color[1], &user.Color[2], &user.CreatedAt) if err != nil { return err } - return DbSetClientGroups(ctx, client) + return DbSetUserGroups(ctx, user) } -// DbSetClientByIdWithoutGroups sets all fields of given struct with database's data using id, excluding groups +// DbSetUserByIdWithoutGroups sets all fields of given struct with database's data using id, excluding groups // return: error if not successful -func DbSetClientByIdWithoutGroups(ctx context.Context, client *Client) error { +func DbSetUserByIdWithoutGroups(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` SELECT name, pass_hash, pronouns, color_red, color_green, color_blue, created_at FROM clients WHERE id = $1 - `, client.Id).Scan(&client.Name, &client.PasswordHash, &client.Pronouns, &client.Color[0], &client.Color[1], &client.Color[2], &client.CreatedAt) + `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &user.Color[0], &user.Color[1], &user.Color[2], &user.CreatedAt) return err } -// DbSetClientById sets all fields of given struct with database's data using id, including groups +// DbSetUserById sets all fields of given struct with database's data using id, including groups // return: error if not successful -func DbSetClientById(ctx context.Context, client *Client) error { - err := DbSetClientByIdWithoutGroups(ctx, client) +func DbSetUserById(ctx context.Context, user *User) error { + err := DbSetUserByIdWithoutGroups(ctx, user) if err != nil { return err } - return DbSetClientGroups(ctx, client) + return DbSetUserGroups(ctx, user) } -// DbSaveGroupWithoutClients saves group in db and sets its id, also adds the owner as first member +// DbSaveGroupWithoutUsers saves group in db and sets its id, also adds the owner as first member // return: error if not successful -func DbSaveGroupWithoutClients(ctx context.Context, group *Group) error { +func DbSaveGroupWithoutUsers(ctx context.Context, group *Group) error { err := dbConn.QueryRow(ctx, ` INSERT INTO chat_groups (name, creator_id, owner_id, enable_client_colors, color_red, color_green, color_blue, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id - `, group.Name, group.CreatorId, group.OwnerId, group.EnableClientColors, group.Color[0], group.Color[1], group.Color[2], group.CreatedAt). + `, group.Name, group.CreatorId, group.OwnerId, group.EnableUserColors, group.Color[0], group.Color[1], group.Color[2], group.CreatedAt). Scan(&group.Id) if err != nil { return err @@ -134,12 +134,12 @@ func DbDeleteGroup(ctx context.Context, group *Group) error { return err } -// DbSetGroupByIdWithoutClients sets all fields of given struct with database's data using id, populates Clients map with member ids but not their data +// DbSetGroupByIdWithoutUsers sets all fields of given struct with database's data using id, populates Users map with member ids but not their data // return: error if not successful -func DbSetGroupByIdWithoutClients(ctx context.Context, group *Group) error { +func DbSetGroupByIdWithoutUsers(ctx context.Context, group *Group) error { err := dbConn.QueryRow(ctx, ` SELECT name, creator_id, owner_id, enable_client_colors, color_red, color_green, color_blue, created_at FROM chat_groups WHERE id = $1 - `, group.Id).Scan(&group.Name, &group.CreatorId, &group.OwnerId, &group.EnableClientColors, &group.Color[0], &group.Color[1], &group.Color[2], &group.CreatedAt) + `, group.Id).Scan(&group.Name, &group.CreatorId, &group.OwnerId, &group.EnableUserColors, &group.Color[0], &group.Color[1], &group.Color[2], &group.CreatedAt) if err != nil { return err } @@ -152,30 +152,30 @@ func DbSetGroupByIdWithoutClients(ctx context.Context, group *Group) error { } defer rows.Close() - group.Clients = make(map[uint32]struct{}) + group.Users = make(map[uint32]struct{}) for rows.Next() { var userId uint32 if err := rows.Scan(&userId); err != nil { return err } - group.Clients[userId] = struct{}{} + group.Users[userId] = struct{}{} } return rows.Err() } -// DbSetGroupById sets all fields of given struct with database's data using id, including full member client data +// DbSetGroupById sets all fields of given struct with database's data using id, including full member user data // return: error if not successful func DbSetGroupById(ctx context.Context, group *Group) error { - err := DbSetGroupByIdWithoutClients(ctx, group) + err := DbSetGroupByIdWithoutUsers(ctx, group) if err != nil { return err } - return DbSetGroupMemberClients(ctx, group) + return DbSetGroupMemberUsers(ctx, group) } -// DbSetGroupMemberClients populates group's Clients map with ids of all members from database +// DbSetGroupMemberUsers populates group's Users map with ids of all members from database // return: error if not successful -func DbSetGroupMemberClients(ctx context.Context, group *Group) error { +func DbSetGroupMemberUsers(ctx context.Context, group *Group) error { rows, err := dbConn.Query(ctx, ` SELECT user_id FROM chat_group_members WHERE group_id = $1 `, group.Id) @@ -184,32 +184,32 @@ func DbSetGroupMemberClients(ctx context.Context, group *Group) error { } defer rows.Close() - group.Clients = make(map[uint32]struct{}) + group.Users = make(map[uint32]struct{}) for rows.Next() { var userId uint32 if err := rows.Scan(&userId); err != nil { return err } - group.Clients[userId] = struct{}{} + group.Users[userId] = struct{}{} } return rows.Err() } -// DbAddClientsToGroup adds given clients to group in db, silently ignores already existing members +// DbAddUsersToGroup adds given users to group in db, silently ignores already existing members // return: error if not successful -func DbAddClientsToGroup(ctx context.Context, groupId uint32, clientIds *[MaxClientsInGroup]uint32) error { +func DbAddUsersToGroup(ctx context.Context, groupId uint32, userIds *[MaxUsersInGroup]uint32) error { batch := &pgx.Batch{} now := time.Now() var count int - for _, cid := range clientIds { - if cid == 0 { + for _, uid := range userIds { + if uid == 0 { continue } batch.Queue(` INSERT INTO chat_group_members (group_id, user_id, joined_at) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING - `, groupId, cid, now) + `, groupId, uid, now) count++ } br := dbConn.SendBatch(ctx, batch) @@ -222,18 +222,18 @@ func DbAddClientsToGroup(ctx context.Context, groupId uint32, clientIds *[MaxCli return nil } -// DbRemoveClientsFromGroup removes given clients from group in db, silently ignores not existing members -// return: deleted clients count, error if not successful -func DbRemoveClientsFromGroup(ctx context.Context, groupId uint32, clientIds *[MaxClientsInGroup]uint32) (int, error) { +// DbRemoveUsersFromGroup removes given users from group in db, silently ignores not existing members +// return: deleted users count, error if not successful +func DbRemoveUsersFromGroup(ctx context.Context, groupId uint32, userIds *[MaxUsersInGroup]uint32) (int, error) { batch := &pgx.Batch{} var count int - for _, cid := range clientIds { - if cid == 0 { + for _, uid := range userIds { + if uid == 0 { continue } batch.Queue(` DELETE FROM chat_group_members WHERE group_id = $1 AND user_id = $2 - `, groupId, cid) + `, groupId, uid) count++ } br := dbConn.SendBatch(ctx, batch) @@ -249,24 +249,24 @@ func DbRemoveClientsFromGroup(ctx context.Context, groupId uint32, clientIds *[M return deleted, nil } -// DbSetClientGroups populates client's Groups map with ids of all groups the client belongs to from database +// DbSetUserGroups populates user's Groups map with ids of all groups the user belongs to from database // return: error if not successful -func DbSetClientGroups(ctx context.Context, client *Client) error { +func DbSetUserGroups(ctx context.Context, user *User) error { rows, err := dbConn.Query(ctx, ` SELECT group_id FROM chat_group_members WHERE user_id = $1 - `, client.Id) + `, user.Id) if err != nil { return err } defer rows.Close() - client.Groups = make(map[uint32]struct{}) + user.Groups = make(map[uint32]struct{}) for rows.Next() { var groupId uint32 if err := rows.Scan(&groupId); err != nil { return err } - client.Groups[groupId] = struct{}{} + user.Groups[groupId] = struct{}{} } return rows.Err() } diff --git a/globals.go b/globals.go index a0e012d..20a4e42 100644 --- a/globals.go +++ b/globals.go @@ -1,6 +1,6 @@ package main const ( - MaxGroupsForClient uint32 = 8 - MaxClientsInGroup uint32 = 12 + MaxGroupsForUser uint32 = 8 + MaxUsersInGroup uint32 = 12 ) diff --git a/http.go b/http.go index 12cb662..18fae96 100644 --- a/http.go +++ b/http.go @@ -22,23 +22,23 @@ func isMethodAllowed(response *http.ResponseWriter, request *http.Request) bool return true } -func getClient(ctx context.Context, token string) (*Client, error) { - clientId, err := TokenValidateGetId(token) +func getUser(ctx context.Context, token string) (*User, error) { + userId, err := TokenValidateGetId(token) if err != nil { return nil, err } - client, err := CacheGetClientById(clientId) + user, err := CacheGetUserById(userId) if err != nil { - client = &Client{Id: clientId} - err = DbSetClientById(ctx, client) + user = &User{Id: userId} + err = DbSetUserById(ctx, user) if err != nil { return nil, err } - CacheSaveClient(client) + CacheSaveUser(user) } - return client, nil + return user, nil } func getGroup(ctx context.Context, groupId uint32) (*Group, error) { @@ -54,15 +54,15 @@ func getGroup(ctx context.Context, groupId uint32) (*Group, error) { return group, nil } -func isOwner(client *Client, group *Group) bool { - if group.OwnerId == client.Id { +func isOwner(user *User, group *Group) bool { + if group.OwnerId == user.Id { return true } return false } -func getIfOwnerClientAndGroup(ctx context.Context, response *http.ResponseWriter, request *http.Request) (*Client, *Group, error) { - client, err := getClient(ctx, request.FormValue("token")) +func getIfOwnerUserAndGroup(ctx context.Context, response *http.ResponseWriter, request *http.Request) (*User, *Group, error) { + user, err := getUser(ctx, request.FormValue("token")) if err != nil { http.Error(*response, "invalid token", http.StatusUnauthorized) return nil, nil, err @@ -80,14 +80,14 @@ func getIfOwnerClientAndGroup(ctx context.Context, response *http.ResponseWriter return nil, nil, err } - if !isOwner(client, group) { + if !isOwner(user, group) { http.Error(*response, "no such group", http.StatusUnauthorized) return nil, nil, err } - return client, group, nil + return user, group, nil } -func HttpHandleNewClient(response http.ResponseWriter, request *http.Request) { +func HttpHandleNewUser(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } @@ -116,7 +116,7 @@ func HttpHandleNewClient(response http.ResponseWriter, request *http.Request) { return } - newClient := &Client{ + newUser := &User{ Name: username, PasswordHash: hashedPassword, Color: color, @@ -125,14 +125,13 @@ func HttpHandleNewClient(response http.ResponseWriter, request *http.Request) { ctx := request.Context() - err = DbSaveClientWithoutGroups(ctx, newClient) + err = DbSaveUserWithoutGroups(ctx, newUser) if err != nil { http.Error(response, "name taken", http.StatusUnauthorized) return } response.WriteHeader(http.StatusCreated) - response.Write([]byte("created")) } func HttpHandleNewToken(response http.ResponseWriter, request *http.Request) { @@ -154,30 +153,30 @@ func HttpHandleNewToken(response http.ResponseWriter, request *http.Request) { } var ( - client *Client - err error - ctx = request.Context() + user *User + err error + ctx = request.Context() ) - client, err = CacheGetClientByName(username) + user, err = CacheGetUserByName(username) if err != nil { - client = &Client{Name: username} + user = &User{Name: username} - err := DbSetClientByName(ctx, client) + err := DbSetUserByName(ctx, user) if err != nil { http.Error(response, "bad login1", http.StatusUnauthorized) return } - CacheSaveClient(client) + CacheSaveUser(user) } - err = bcrypt.CompareHashAndPassword([]byte(client.PasswordHash), []byte(password)) + err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) if err != nil { http.Error(response, "bad login2", http.StatusUnauthorized) return } - token, err := TokenCreate(client.Id) + token, err := TokenCreate(user.Id) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -194,7 +193,7 @@ func HttpHandeGroupCreate(response http.ResponseWriter, request *http.Request) { ctx := request.Context() - client, err := getClient(ctx, request.FormValue("token")) + user, err := getUser(ctx, request.FormValue("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return @@ -211,18 +210,18 @@ func HttpHandeGroupCreate(response http.ResponseWriter, request *http.Request) { group := Group{ Name: name, CreatedAt: time.Now(), - OwnerId: client.Id, - CreatorId: client.Id, + OwnerId: user.Id, + CreatorId: user.Id, Color: color, - Clients: map[uint32]struct{}{client.Id: {}}, + Users: map[uint32]struct{}{user.Id: {}}, } - enableClientColors := request.FormValue("enableClientColors") - if enableClientColors == "1" { - group.EnableClientColors = true + enableUserColors := request.FormValue("enableUserColors") + if enableUserColors == "1" { + group.EnableUserColors = true } - err = DbSaveGroupWithoutClients(ctx, &group) + err = DbSaveGroupWithoutUsers(ctx, &group) if err != nil { http.Error(response, err.Error(), http.StatusInternalServerError) return @@ -237,7 +236,7 @@ func HttpHandleGroupRemove(response http.ResponseWriter, request *http.Request) } ctx := request.Context() - _, group, err := getIfOwnerClientAndGroup(ctx, &response, request) + _, group, err := getIfOwnerUserAndGroup(ctx, &response, request) if err != nil { return } @@ -251,35 +250,35 @@ func HttpHandleGroupRemove(response http.ResponseWriter, request *http.Request) response.WriteHeader(http.StatusAccepted) } -func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Request) { +func HttpHandleGroupAddUser(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } ctx := request.Context() - _, group, err := getIfOwnerClientAndGroup(ctx, &response, request) + _, group, err := getIfOwnerUserAndGroup(ctx, &response, request) if err != nil { return } - clientsString := request.FormValue("clients") - var remainingUsersCount = int(MaxClientsInGroup) - len(group.Clients) + usersString := request.FormValue("users") + var remainingUsersCount = int(MaxUsersInGroup) - len(group.Users) if remainingUsersCount < 1 { http.Error(response, "max users", http.StatusUnauthorized) return } - clientsStringSlice := strings.SplitN(clientsString, ",", remainingUsersCount+1) - if len(clientsStringSlice) == 0 { + usersStringSlice := strings.SplitN(usersString, ",", remainingUsersCount+1) + if len(usersStringSlice) == 0 { http.Error(response, "no users to add", http.StatusBadRequest) return } - var ids [MaxClientsInGroup]uint32 + var ids [MaxUsersInGroup]uint32 var idx uint32 = 0 - for _, s := range clientsStringSlice { - if idx >= MaxClientsInGroup { + for _, s := range usersStringSlice { + if idx >= MaxUsersInGroup { break } id, err := ConvertStringUint32(strings.TrimSpace(s)) @@ -294,39 +293,39 @@ func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Reques return } - err = DbAddClientsToGroup(ctx, group.Id, &ids) + err = DbAddUsersToGroup(ctx, group.Id, &ids) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } for i := uint32(0); i < idx; i++ { - group.Clients[ids[i]] = struct{}{} + group.Users[ids[i]] = struct{}{} } response.WriteHeader(http.StatusAccepted) } -func HttpHandleGroupRemoveClient(response http.ResponseWriter, request *http.Request) { +func HttpHandleGroupRemoveUser(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } ctx := request.Context() - _, group, err := getIfOwnerClientAndGroup(ctx, &response, request) + _, group, err := getIfOwnerUserAndGroup(ctx, &response, request) if err != nil { return } - clientsString := request.FormValue("clients") + usersString := request.FormValue("users") - clientsStringSlice := strings.SplitN(clientsString, ",", int(MaxClientsInGroup)+1) + usersStringSlice := strings.SplitN(usersString, ",", int(MaxUsersInGroup)+1) - var ids [MaxClientsInGroup]uint32 + var ids [MaxUsersInGroup]uint32 var idx uint32 = 0 - for _, s := range clientsStringSlice { - if idx >= MaxClientsInGroup { + for _, s := range usersStringSlice { + if idx >= MaxUsersInGroup { break } id, err := ConvertStringUint32(strings.TrimSpace(s)) @@ -341,14 +340,14 @@ func HttpHandleGroupRemoveClient(response http.ResponseWriter, request *http.Req return } - count, err := DbRemoveClientsFromGroup(ctx, group.Id, &ids) + count, err := DbRemoveUsersFromGroup(ctx, group.Id, &ids) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } for i := uint32(0); i < idx; i++ { - delete(group.Clients, ids[i]) + delete(group.Users, ids[i]) } response.WriteHeader(http.StatusAccepted) @@ -361,7 +360,7 @@ func HttpHandleGroupChangeColor(response http.ResponseWriter, request *http.Requ } ctx := request.Context() - _, group, err := getIfOwnerClientAndGroup(ctx, &response, request) + _, group, err := getIfOwnerUserAndGroup(ctx, &response, request) if err != nil { return } @@ -389,28 +388,28 @@ func HttpHandleGroupChangeOwner(response http.ResponseWriter, request *http.Requ } ctx := request.Context() - client, group, err := getIfOwnerClientAndGroup(ctx, &response, request) + user, group, err := getIfOwnerUserAndGroup(ctx, &response, request) if err != nil { return } newOwnerName := request.FormValue("newOwner") - newOwner, err := CacheGetClientByName(newOwnerName) + newOwner, err := CacheGetUserByName(newOwnerName) if err != nil { - newOwner = &Client{Name: newOwnerName} - err = DbSetClientByName(ctx, newOwner) + newOwner = &User{Name: newOwnerName} + err = DbSetUserByName(ctx, newOwner) if err != nil { - http.Error(response, "client not in group", http.StatusBadRequest) + http.Error(response, "user not in group", http.StatusBadRequest) return } - CacheSaveClient(client) + CacheSaveUser(user) } - _, ok := group.Clients[newOwner.Id] + _, ok := group.Users[newOwner.Id] if !ok { - http.Error(response, "client not in group", http.StatusBadRequest) + http.Error(response, "user not in group", http.StatusBadRequest) return } @@ -430,7 +429,7 @@ func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) { } ctx := request.Context() - client, err := getClient(ctx, request.FormValue("token")) + user, err := getUser(ctx, request.FormValue("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return @@ -453,7 +452,7 @@ func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) { return } - err = WsSendToGroup(ctx, targetId, client.Id, content) + err = WsSendToGroup(ctx, targetId, user.Id, content) if err != nil { http.Error(response, err.Error(), http.StatusBadRequest) return @@ -468,28 +467,28 @@ func HttpHandleGroupsGetWithoutMembers(response http.ResponseWriter, request *ht ctx := request.Context() - client, err := getClient(ctx, request.FormValue("token")) + user, err := getUser(ctx, request.FormValue("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } - groups := make([]GroupNoMembers, 0, len(client.Groups)) + groups := make([]GroupNoMembers, 0, len(user.Groups)) - for groupId := range client.Groups { + for groupId := range user.Groups { group, err := getGroup(ctx, groupId) if err != nil { continue } groups = append(groups, GroupNoMembers{ - Id: groupId, - Name: group.Name, - CreatedAt: group.CreatedAt, - CreatorId: group.CreatorId, - OwnerId: group.OwnerId, - Color: group.Color, - EnableClientsColors: group.EnableClientColors, + Id: groupId, + Name: group.Name, + CreatedAt: group.CreatedAt, + CreatorId: group.CreatorId, + OwnerId: group.OwnerId, + Color: group.Color, + EnableUsersColors: group.EnableUserColors, }) } @@ -509,7 +508,7 @@ func HttpHandleGroupMembersGet(response http.ResponseWriter, request *http.Reque } ctx := request.Context() - client, err := getClient(ctx, request.FormValue("token")) + user, err := getUser(ctx, request.FormValue("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return @@ -522,7 +521,7 @@ func HttpHandleGroupMembersGet(response http.ResponseWriter, request *http.Reque return } - _, ok := client.Groups[groupId] + _, ok := user.Groups[groupId] if !ok { http.Error(response, "no such group", http.StatusUnauthorized) return @@ -534,7 +533,7 @@ func HttpHandleGroupMembersGet(response http.ResponseWriter, request *http.Reque return } - groupMembers := slices.Collect(maps.Keys(group.Clients)) + groupMembers := slices.Collect(maps.Keys(group.Users)) json, err := json2.Marshal(groupMembers) if err != nil { diff --git a/main.go b/main.go index d260a83..dc73d21 100644 --- a/main.go +++ b/main.go @@ -17,12 +17,12 @@ func main() { ctx := context.Background() DbInit(ctx) - http.HandleFunc("/new/client", withCORS(HttpHandleNewClient)) + http.HandleFunc("/new/user", withCORS(HttpHandleNewUser)) http.HandleFunc("/new/token", withCORS(HttpHandleNewToken)) http.HandleFunc("/new/group", withCORS(HttpHandeGroupCreate)) http.HandleFunc("/new/message", withCORS(HttpHandleNewMessage)) - http.HandleFunc("/mod/group/addclients", withCORS(HttpHandleGroupAddClient)) - http.HandleFunc("/mod/group/removeclients", withCORS(HttpHandleGroupRemoveClient)) + http.HandleFunc("/mod/group/addusers", withCORS(HttpHandleGroupAddUser)) + http.HandleFunc("/mod/group/removeusers", withCORS(HttpHandleGroupRemoveUser)) http.HandleFunc("/mod/group/color", withCORS(HttpHandleGroupChangeColor)) http.HandleFunc("/mod/group/owner", withCORS(HttpHandleGroupChangeOwner)) http.HandleFunc("/get/groups", withCORS(HttpHandleGroupsGetWithoutMembers)) diff --git a/structs.go b/structs.go index b792c4e..24800e7 100644 --- a/structs.go +++ b/structs.go @@ -6,7 +6,7 @@ import ( "github.com/coder/websocket" ) -type Client struct { +type User struct { Name string Pronouns string PasswordHash string @@ -18,22 +18,22 @@ type Client struct { } type Group struct { - Name string - CreatedAt time.Time - Id uint32 - CreatorId uint32 - OwnerId uint32 - Clients map[uint32]struct{} - Color [3]uint8 - EnableClientColors bool + Name string + CreatedAt time.Time + Id uint32 + CreatorId uint32 + OwnerId uint32 + Users map[uint32]struct{} + Color [3]uint8 + EnableUserColors bool } type GroupNoMembers struct { - Name string `json:"name"` - CreatedAt time.Time `json:"createdAt"` - Id uint32 `json:"id"` - CreatorId uint32 `json:"creatorId"` - OwnerId uint32 `json:"ownerId"` - Color [3]uint8 `json:"color"` - EnableClientsColors bool `json:"enableClientsColors"` + Name string `json:"name"` + CreatedAt time.Time `json:"createdAt"` + Id uint32 `json:"id"` + CreatorId uint32 `json:"creatorId"` + OwnerId uint32 `json:"ownerId"` + Color [3]uint8 `json:"color"` + EnableUsersColors bool `json:"enableUsersColors"` } diff --git a/tokens.go b/tokens.go index 65d60ef..7a08042 100644 --- a/tokens.go +++ b/tokens.go @@ -11,10 +11,10 @@ import ( const tokenSecret = "tmp" // TODO delete in production const tokenExpiration = time.Hour -func TokenCreate(clientId uint32) (string, error) { +func TokenCreate(userId uint32) (string, error) { now := time.Now() signedToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{ - Subject: strconv.FormatUint(uint64(clientId), 10), + Subject: strconv.FormatUint(uint64(userId), 10), IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(tokenExpiration)), }).SignedString([]byte(tokenSecret)) diff --git a/wsServer.go b/wsServer.go index 76b1ce0..76af0a7 100644 --- a/wsServer.go +++ b/wsServer.go @@ -23,26 +23,26 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request ctx, cancel := context.WithCancel(context.Background()) defer cancel() - var client = Client{WsConn: connection} + var user = User{WsConn: connection} var isAuthenticated bool var ignoreCache bool - defer closeConnection(&client, ignoreCache) + defer closeConnection(&user, ignoreCache) for { - var clientMessage map[string]any - err = wsjson.Read(ctx, connection, &clientMessage) + var userMessage map[string]any + err = wsjson.Read(ctx, connection, &userMessage) if err != nil { log.Printf("read error: %v", err) return } - if len(clientMessage) > 0 { + if len(userMessage) > 0 { if isAuthenticated { - if !handleAuthenticatedMessage(&client, &clientMessage) { + if !handleAuthenticatedMessage(&user, &userMessage) { return } } else { - if !handleUnauthenticatedMessage(ctx, &client, &clientMessage) { + if !handleUnauthenticatedMessage(ctx, &user, &userMessage) { ignoreCache = true return } @@ -52,18 +52,18 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request } } -func sendMessageCloseIfTimeout(client *Client, message *map[string]any) { - if client.WsConn == nil { +func sendMessageCloseIfTimeout(user *User, message *map[string]any) { + if user.WsConn == nil { return } ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - err := wsjson.Write(ctx, client.WsConn, message) + err := wsjson.Write(ctx, user.WsConn, message) if err != nil { if errors.Is(err, context.DeadlineExceeded) { - closeConnection(client, false) + closeConnection(user, false) } log.Printf("write error: %v", err) } @@ -72,8 +72,8 @@ func sendMessageCloseIfTimeout(client *Client, message *map[string]any) { func sendToAllMessageCloseIfTimeout(message *map[string]any) { mu.RLock() defer mu.RUnlock() - for _, client := range CacheClients { - sendMessageCloseIfTimeout(client, message) + for _, user := range CacheUsers { + sendMessageCloseIfTimeout(user, message) } } @@ -83,88 +83,88 @@ func WsSendToGroup(ctx context.Context, groupId uint32, senderId uint32, message return errors.New("group invalid") } - client, err := CacheGetClientById(senderId) + sender, err := CacheGetUserById(senderId) if err != nil { - client = &Client{Id: senderId} - err = DbSetClientById(ctx, client) + sender = &User{Id: senderId} + err = DbSetUserById(ctx, sender) if err != nil { return errors.New("non existing sender") } } - for groupClientId := range group.Clients { - groupClient, err := CacheGetClientById(groupClientId) - if err != nil || groupClient.Id == client.Id { + for groupUserId := range group.Users { + groupUser, err := CacheGetUserById(groupUserId) + if err != nil || groupUser.Id == sender.Id { continue } var msg = map[string]any{ "from": "group", "group": group.Id, - "sender": client.Name, + "sender": sender.Name, "content": message, } - sendMessageCloseIfTimeout(groupClient, &msg) + sendMessageCloseIfTimeout(groupUser, &msg) } return nil } -func handleAuthenticatedMessage(client *Client, clientMessage *map[string]any) bool { - sendMessageCloseIfTimeout(client, clientMessage) +func handleAuthenticatedMessage(user *User, userMessage *map[string]any) bool { + sendMessageCloseIfTimeout(user, userMessage) return true } -func handleUnauthenticatedMessage(ctx context.Context, client *Client, clientMessage *map[string]any) bool { - token, ok := (*clientMessage)["token"].(string) +func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage *map[string]any) bool { + token, ok := (*userMessage)["token"].(string) if !ok { var msg = map[string]any{ "from": "server", "error": "no token in message", } - sendMessageCloseIfTimeout(client, &msg) + sendMessageCloseIfTimeout(user, &msg) return false } - clientId, err := TokenValidateGetId(token) + userId, err := TokenValidateGetId(token) if err != nil { var msg = map[string]any{ "from": "server", "error": "invalid token", } - sendMessageCloseIfTimeout(client, &msg) + sendMessageCloseIfTimeout(user, &msg) return false } - clientFromCache, err := CacheGetClientById(clientId) + userFromCache, err := CacheGetUserById(userId) if err != nil { - dbClient := &Client{Id: clientId} - err = DbSetClientByIdWithoutGroups(ctx, dbClient) + dbUser := &User{Id: userId} + err = DbSetUserByIdWithoutGroups(ctx, dbUser) if err != nil { var msg = map[string]any{ "from": "server", - "error": "invalid client data", + "error": "invalid user data", } - sendMessageCloseIfTimeout(client, &msg) + sendMessageCloseIfTimeout(user, &msg) return false } - err = DbSetClientGroups(ctx, dbClient) + err = DbSetUserGroups(ctx, dbUser) if err != nil { var msg = map[string]any{ "from": "server", - "error": "invalid client data", + "error": "invalid user data", } - sendMessageCloseIfTimeout(client, &msg) + sendMessageCloseIfTimeout(user, &msg) return false } - dbClient.WsConn = client.WsConn - CacheSaveClient(dbClient) - clientFromCache = dbClient + dbUser.WsConn = user.WsConn + CacheSaveUser(dbUser) + userFromCache = dbUser } - clientFromCache.WsConn = client.WsConn - *client = *clientFromCache + userFromCache.WsConn = user.WsConn + *user = *userFromCache - for groupId, _ := range clientFromCache.Groups { + for groupId, _ := range userFromCache.Groups { _, err = CacheGetGroup(groupId) if err != nil { dbGroup := &Group{Id: groupId} @@ -173,9 +173,9 @@ func handleUnauthenticatedMessage(ctx context.Context, client *Client, clientMes if err != nil { var msg = map[string]any{ "from": "server", - "error": "invalid client data", + "error": "invalid user data", } - sendMessageCloseIfTimeout(client, &msg) + sendMessageCloseIfTimeout(user, &msg) return false } CacheSaveGroup(dbGroup) @@ -184,9 +184,9 @@ func handleUnauthenticatedMessage(ctx context.Context, client *Client, clientMes return true } -func closeConnection(client *Client, ignoreCache bool) { +func closeConnection(user *User, ignoreCache bool) { if !ignoreCache { - CacheDeleteClient(client.Id) + CacheDeleteUser(user.Id) } - client.WsConn.CloseNow() + user.WsConn.CloseNow() }