From df1e969d4952caf1c08300fad6c0d97572f21743 Mon Sep 17 00:00:00 2001 From: Sisi Date: Sat, 25 Apr 2026 16:04:53 +0200 Subject: [PATCH] revork structures for hub --- packages/Enums/permission/permission.go | 58 ------- packages/config/config.go | 20 ++- packages/httpRequest/connectionsAndDms.go | 2 +- packages/httpRequest/files.go | 8 +- packages/httpRequest/hubs.go | 10 +- packages/httpRequest/user.go | 12 +- packages/postgresql/postgresql.go | 11 +- packages/types/types.go | 200 ++++++++++++++-------- todo.txt | 1 + 9 files changed, 165 insertions(+), 157 deletions(-) delete mode 100644 packages/Enums/permission/permission.go diff --git a/packages/Enums/permission/permission.go b/packages/Enums/permission/permission.go deleted file mode 100644 index 1802e17..0000000 --- a/packages/Enums/permission/permission.go +++ /dev/null @@ -1,58 +0,0 @@ -package permission - -type Global uint32 - -const ( - // Hub permissions - GlobalSetHubName Global = 1 << iota - GlobalSetHubBg - GlobalSetHubColor - GlobalRemoveHub - GlobalSetUserColorAllowed - - // User permissions - GlobalAddUser - GlobalRemoveUser - GlobalRenameUser - GlobalMuteUser - - // Role permissions - GlobalAddRole - GlobalRemoveRole - GlobalChangeRoleName - GlobalChangeRoleColor - GlobalChangeRoleGlobals - GlobalOnlySelfRoleRemove - - // Channel group permissions - GlobalAddChannelGroup - GlobalRemoveChannelGroup - GlobalSetChannelGroupName - GlobalSetChannelGroupColor - GlobalSetChannelGroupPermittedVisibleRoles - - // Channel permissions - GlobalAddChannel - GlobalRemoveChannel - GlobalSetChannelName - GlobalSetChannelPermittedVisibleRoles - GlobalSetChannelPermittedSendMessageRoles - GlobalSetChannelPermittedReadHistoryRoles -) - -type ChannelGroup uint16 - -const ( - // Channel group permission - ChannelGroupSetName ChannelGroup = 1 << iota - ChannelGroupSetColor - ChannelGroupSetPermittedVisibleRoles - - // Channel permission - ChannelGroupAddChannel - ChannelGroupRemoveChannel - ChannelGroupSetChannelName - ChannelGroupSetChannelPermittedVisibleRoles - ChannelGroupSetChannelPermittedSendMessageRoles - ChannelGroupSetChannelPermittedReadHistoryRoles -) diff --git a/packages/config/config.go b/packages/config/config.go index f71bdc0..290bc78 100644 --- a/packages/config/config.go +++ b/packages/config/config.go @@ -12,28 +12,30 @@ import ( var ( Port uint32 = 8080 MaxDirectMsgCache uint32 = 32 - MaxHubMsgCache uint32 = 32 + MaxHubChannelMsgCache uint32 = 16 + MaxUserHubRoles uint8 = 64 FileStorageBucketName string = "communicator" MaxRequestBytes uint32 = 4 << 10 MaxRequestWithFileBytes uint32 = 1 << 30 - MaxRequestWithAvatarBytes uint = 1 << 20 - MaxRequestWithProfileBgBytes uint = 4 << 20 + MaxRequestWithAvatarBytes uint32 = 1 << 20 + MaxRequestWithProfileBgBytes uint32 = 4 << 20 FileProcessingPartBytes uint64 = 12 << 20 - FileProcessingThreads uint = 3 + FileProcessingThreads uint32 = 3 FileDownloadLinkTtl time.Duration = 24 * time.Hour ) type configFile struct { Port uint32 `toml:"port"` MaxDirectMsgCache uint32 `toml:"max_direct_messages_cache"` - MaxHubMsgCache uint32 `toml:"max_hub_msg_cache"` + MaxHubChannelMsgCache uint32 `toml:"max_hub_channel_msg_cache"` + MaxUserHubRoles uint8 `toml:"max_hub_roles"` FileStorageBucketName string `toml:"file_storage_bucket_name"` MaxRequestBytes uint32 `toml:"max_request_bytes"` MaxRequestWithFileBytes uint32 `toml:"max_request_with_file_bytes"` - MaxRequestWithAvatarBytes uint `toml:"max_request_with_avatar_bytes"` - MaxRequestWithProfileBgBytes uint `toml:"max_request_with_profile_bg_bytes"` + MaxRequestWithAvatarBytes uint32 `toml:"max_request_with_avatar_bytes"` + MaxRequestWithProfileBgBytes uint32 `toml:"max_request_with_profile_bg_bytes"` FileProcessingPartBytes uint64 `toml:"file_processing_part_bytes"` - FileProcessingThreads uint `toml:"file_processing_threads"` + FileProcessingThreads uint32 `toml:"file_processing_threads"` FileDownloadLinkTtl time.Duration `toml:"file_download_link_ttl"` } @@ -51,7 +53,7 @@ func LoadConfFile() { Port = cfg.Port MaxDirectMsgCache = cfg.MaxDirectMsgCache - MaxHubMsgCache = cfg.MaxHubMsgCache + MaxHubChannelMsgCache = cfg.MaxHubChannelMsgCache FileStorageBucketName = cfg.FileStorageBucketName MaxRequestBytes = cfg.MaxRequestBytes MaxRequestWithFileBytes = cfg.MaxRequestWithFileBytes diff --git a/packages/httpRequest/connectionsAndDms.go b/packages/httpRequest/connectionsAndDms.go index 5e82fbd..97f2b4c 100644 --- a/packages/httpRequest/connectionsAndDms.go +++ b/packages/httpRequest/connectionsAndDms.go @@ -241,7 +241,7 @@ func HandleUserNewConnection(response http.ResponseWriter, request *http.Request } requestor.Mu.RUnlock() - connection := types.CreateConn() + connection := types.NewConn() connection.CreatedAt = time.Now() connection.RequestorId = requestor.Id connection.RecipientId = recipient.Id diff --git a/packages/httpRequest/files.go b/packages/httpRequest/files.go index e304e53..c9df5ad 100644 --- a/packages/httpRequest/files.go +++ b/packages/httpRequest/files.go @@ -84,12 +84,12 @@ func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) { return } - if target.Avatar == "" { + if target.AvatarUrl == "" { http.Error(response, "no avatar", http.StatusNotFound) return } - url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.Avatar) + url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarUrl) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -122,12 +122,12 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request) return } - if target.ProfileBg == "" { + if target.ProfileBgUrl == "" { http.Error(response, "no profile background", http.StatusNotFound) return } - url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBg) + url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgUrl) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return diff --git a/packages/httpRequest/hubs.go b/packages/httpRequest/hubs.go index 75729ac..d1171fe 100644 --- a/packages/httpRequest/hubs.go +++ b/packages/httpRequest/hubs.go @@ -62,11 +62,11 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) { } hub.ChannelGroups[rootGrp.Id] = rootGrp - rootRole := &types.HubGlobalRole{ - Id: 0, - Name: "root", - Color: types.Rgba{255, 0, 0, 255}, - RolePermission: ^permission.Global(0), + rootRole := &types.HubRole{ + Id: 0, + Name: "root", + Color: types.Rgba{255, 0, 0, 255}, + Permissions: ^permission.Global(0), } hub.GlobalRoles[rootRole.Id] = rootRole diff --git a/packages/httpRequest/user.go b/packages/httpRequest/user.go index ae373fe..b2644a4 100644 --- a/packages/httpRequest/user.go +++ b/packages/httpRequest/user.go @@ -222,8 +222,8 @@ func HandleUserModAvatar(response http.ResponseWriter, request *http.Request) { return } - if user.Avatar != "" { - err = minio.Delete(ctx, user.Avatar) + if user.AvatarUrl != "" { + err = minio.Delete(ctx, user.AvatarUrl) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -243,7 +243,7 @@ func HandleUserModAvatar(response http.ResponseWriter, request *http.Request) { return } - user.Avatar = key + user.AvatarUrl = key err = postgresql.UserUpdateProfile(ctx, user, types.UserProfileUpdateList{Avatar: true}) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) @@ -285,8 +285,8 @@ func HandleUserModProfileBg(response http.ResponseWriter, request *http.Request) return } - if user.ProfileBg != "" { - err = minio.Delete(ctx, user.ProfileBg) + if user.ProfileBgUrl != "" { + err = minio.Delete(ctx, user.ProfileBgUrl) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -306,7 +306,7 @@ func HandleUserModProfileBg(response http.ResponseWriter, request *http.Request) return } - user.ProfileBg = key + user.ProfileBgUrl = key err = postgresql.UserUpdateProfile(ctx, user, types.UserProfileUpdateList{ProfileBg: true}) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) diff --git a/packages/postgresql/postgresql.go b/packages/postgresql/postgresql.go index b0577e4..129eed7 100644 --- a/packages/postgresql/postgresql.go +++ b/packages/postgresql/postgresql.go @@ -95,7 +95,7 @@ func UserGetStandardInfoByName(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT id, name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE name = $1 - `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.Avatar, &user.ProfileBg) + `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarUrl, &user.ProfileBgUrl) if err == nil { user.Color = convertions.Uint32ToRgba(uint32(rgba)) } @@ -106,7 +106,7 @@ func UserGetById(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE id = $1 - `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.Avatar, &user.ProfileBg) + `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarUrl, &user.ProfileBgUrl) if err == nil { user.Color = convertions.Uint32ToRgba(uint32(rgba)) } @@ -135,12 +135,12 @@ func UserUpdateProfile(ctx context.Context, user *types.User, updateList types.U } if updateList.Avatar { setClauses = append(setClauses, fmt.Sprintf("avatar = $%d", argIdx)) - args = append(args, user.Avatar) + args = append(args, user.AvatarUrl) argIdx++ } if updateList.ProfileBg { setClauses = append(setClauses, fmt.Sprintf("profile_bg = $%d", argIdx)) - args = append(args, user.ProfileBg) + args = append(args, user.ProfileBgUrl) argIdx++ } @@ -197,7 +197,7 @@ func ConnectionsGetBelongingToUser(ctx context.Context, user *types.User) error } for rows.Next() { - conn := types.CreateConn() + conn := types.NewConn() if err = rows.Scan(&conn.Id, &conn.RequestorId, &conn.RecipientId, &conn.State, &conn.CreatedAt); err != nil { return fmt.Errorf("scanning connection row: %w", err) } @@ -254,4 +254,3 @@ func ConnectionGetMessagesBefore(ctx context.Context, before time.Time, connecti } return messages, rows.Err() } - diff --git a/packages/types/types.go b/packages/types/types.go index 8686677..297ebbf 100644 --- a/packages/types/types.go +++ b/packages/types/types.go @@ -2,7 +2,6 @@ package types import ( "crypto/sha256" - "go-socket/packages/Enums/permission" "math/rand/v2" "sync" "time" @@ -25,18 +24,13 @@ func (r Rgba) GetRandom() Rgba { return r } -type pairUuidHubChannelGroupRole struct { - first uuid.UUID - second *HubChannelGroupRole -} - type User struct { Mu sync.RWMutex `json:"-"` Name string `json:"name"` Pronouns string `json:"pronouns"` Description string `json:"description"` - Avatar string `json:"avatar"` - ProfileBg string `json:"profileBackground"` + AvatarUrl string `json:"avatarUrl"` + ProfileBgUrl string `json:"profileBackgroundUrl"` PasswordHash string `json:"-"` CreatedAt time.Time `json:"createdAt"` WsConn *websocket.Conn `json:"-"` @@ -66,12 +60,11 @@ type Connection struct { State ConnectionState.ConnectionState `json:"state"` } -func CreateConn() *Connection { +func NewConn() *Connection { return &Connection{ MessagesBuff: make([]*Message, config.MaxDirectMsgCache), } } - func (conn *Connection) AddMessageToBuff(message *Message) { conn.Mu.Lock() defer conn.Mu.Unlock() @@ -130,82 +123,153 @@ type WsAuthMessage struct { Error string `json:"error"` } +type Permissions uint32 + +const ( + // Hub permissions + PermissionSetHubName Permissions = 1 << iota + PermissionSetHubIcon + PermissionSetHubBg + PermissionSetHubColor + PermissionRemoveHub + PermissionSetUserColorAllowed + + // User permissions + PermissionAddUser + PermissionRemoveUser + PermissionRenameUser + PermissionMuteUser + + // Role permissions + PermissionAddRole + PermissionRemoveRole + PermissionChangeRoleName + PermissionChangeRoleColor + PermissionChangeRoleGlobals + PermissionOnlySelfRoleRemove + + // Channel group permissions + PermissionAddChannelGroup + PermissionRemoveChannelGroup + PermissionSetChannelGroupName + PermissionSetChannelGroupColor + PermissionSetChannelGroupPermittedVisibleRoles + + // Channel permissions + PermissionAddChannel + PermissionRemoveChannel + PermissionSetChannelName + PermissionSetChannelIcon + PermissionSetChannelPermittedVisibleRoles + PermissionSetChannelPermittedSendMessageRoles + PermissionSetChannelPermittedReadHistoryRoles +) + type Hub struct { - Mu sync.RWMutex `json:"-"` - Id uuid.UUID `json:"id"` - CreatedAt time.Time `json:"createdAt"` - Users map[uuid.UUID]*HubUser `json:"-"` - GlobalRoles map[uint8]*HubGlobalRole `json:"-"` - ChannelGroupRoles map[uint8]*HubChannelGroupRole `json:"-"` - ChannelGroups map[uuid.UUID]*HubChannelGroup `json:"-"` - Creator uuid.UUID `json:"creator"` - Name string `json:"name"` - Color Rgba `json:"color"` - AllowUserColor bool `json:"allowUserColor"` + Mu sync.RWMutex `json:"-"` + Roles []*HubRole `json:"-"` + Users []*HubUser `json:"-"` + Groups []*HubGroup `json:"-"` + Channels []*HubChannel `json:"-"` + Name string `json:"name"` + IconUrl string `json:"iconUrl"` + BgUrl string `json:"bgUrl"` + Id uuid.UUID `json:"id"` + Color Rgba `json:"color"` + UserColorAllowed bool `json:"userColorAllowed"` } -func CreateHub() *Hub { +func NewHub() *Hub { return &Hub{ - Id: uuid.New(), - Users: make(map[uuid.UUID]*HubUser), - GlobalRoles: make(map[uint8]*HubGlobalRole), - ChannelGroupRoles: make(map[uint8]*HubChannelGroupRole), - ChannelGroups: make(map[uuid.UUID]*HubChannelGroup), + Roles: make([]*HubRole, 0, 255), + Users: make([]*HubUser, 0, 255), + Groups: make([]*HubGroup, 0, 255), + Channels: make([]*HubChannel, 0, 255), } } -type HubChannelGroup struct { - Id uuid.UUID `json:"id"` - Name string `json:"name"` - Color Rgba `json:"color"` - Position uint8 `json:"position"` +type HubRole struct { + Name string `json:"role"` + CreatedAt time.Time `json:"createdAt"` + Permissions Permissions `json:"permissions"` + Color Rgba `json:"color"` + Id uint8 `json:"id"` + BoundedGroup uint8 `json:"boundedGroup"` // BoundedGroup 0 for global } -type HubChannel struct { - Id uuid.UUID `json:"id"` - Name uuid.UUID `json:"name"` - ParentGroupId uuid.UUID `json:"parentGroupId"` - Position uint8 `json:"position"` +func (h *HubRole) GrantPermission(r Permissions) { + h.Permissions |= r +} +func (h *HubRole) RevokePermission(r Permissions) { + h.Permissions &^= r +} +func (h *HubRole) HasPermission(r Permissions) bool { + return h.Permissions&r != 0 +} + +type HubGroup struct { + Name string `json:"name"` + CreatedAt time.Time `json:"createdAt"` + Color Rgba `json:"color"` + Id uint8 `json:"id"` // Id 0 for unused } type HubUser struct { - Id uuid.UUID `json:"id"` - Username string `json:"username"` - GlobalRoles []uint8 `json:"globalRoles"` - ChannelGroupRoles map[uint8]pairUuidHubChannelGroupRole `json:"ChannelGroupRoles"` - CreatedAt time.Time `json:"createdAt"` + Mu sync.RWMutex `json:"mu"` + Roles []*HubRole `json:"roles"` + Name string `json:"name"` + OriginalId uuid.UUID `json:"originalId"` + IsMuted bool `json:"isMuted"` } -type HubGlobalRole struct { - Name string `json:"role"` - Id uint8 `json:"id"` - RolePermission permission.Global `json:"rolePermission"` - Color Rgba `json:"color"` +func NewHubUser() *HubUser { + return &HubUser{ + Roles: make([]*HubRole, 0, config.MaxUserHubRoles), + } } -func (h *HubGlobalRole) GrantPermission(r permission.Global) { - h.RolePermission |= r -} -func (h *HubGlobalRole) RevokePermission(r permission.Global) { - h.RolePermission &^= r -} -func (h *HubGlobalRole) HasPermission(r permission.Global) bool { - return h.RolePermission&r != 0 +type HubChannel struct { + Mu sync.RWMutex `json:"-"` + MessagesBuff []*Message `json:"-"` + Name string `json:"name"` + Description string `json:"description"` + IconUrl string `json:"iconUrl"` + CreatedAt time.Time `json:"createdAt"` + NextBuffIdx uint32 `json:"-"` + Id uint8 `json:"id"` + HaveOverflowed bool `json:"-"` } -type HubChannelGroupRole struct { - Name string `json:"role"` - Id uint8 `json:"id"` - RolePermission permission.ChannelGroup `json:"rolePermission"` - Color Rgba `json:"color"` +func NewHubChannel() *HubChannel { + return &HubChannel{ + MessagesBuff: make([]*Message, config.MaxHubChannelMsgCache), + } +} +func (conn *HubChannel) AddMessageToBuff(message *Message) { + conn.Mu.Lock() + defer conn.Mu.Unlock() + + size := uint32(len(conn.MessagesBuff)) + conn.MessagesBuff[conn.NextBuffIdx%size] = message + conn.NextBuffIdx++ + if conn.NextBuffIdx >= size { + conn.HaveOverflowed = true + } } -func (h *HubChannelGroupRole) GrantPermission(r permission.ChannelGroup) { - h.RolePermission |= r -} -func (h *HubChannelGroupRole) RevokePermission(r permission.ChannelGroup) { - h.RolePermission &^= r -} -func (h *HubChannelGroupRole) HasPermission(r permission.ChannelGroup) bool { - return h.RolePermission&r != 0 +// GetSortedMessagesBuff returns slice and its valid length. +func (conn *HubChannel) GetSortedMessagesBuff() ([]*Message, uint32) { + conn.Mu.RLock() + defer conn.Mu.RUnlock() + + size := uint32(len(conn.MessagesBuff)) + if !conn.HaveOverflowed { + return conn.MessagesBuff, conn.NextBuffIdx + } + + sorted := make([]*Message, size) + for i := uint32(0); i < size; i++ { + sorted[i] = conn.MessagesBuff[(conn.NextBuffIdx+i)%size] + } + return sorted, size } diff --git a/todo.txt b/todo.txt index 96b0991..4d6038c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,7 @@ when user not ws connected collect count of unread messages for each conn (add db table in future) add hubs +check when mutex needed user banners