revork structures for hub

This commit is contained in:
2026-04-25 16:04:53 +02:00
parent 635139aad2
commit df1e969d49
9 changed files with 165 additions and 157 deletions
-58
View File
@@ -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
)
+11 -9
View File
@@ -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
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
+5 -5
View File
@@ -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
+6 -6
View File
@@ -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)
+5 -6
View File
@@ -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()
}
+132 -68
View File
@@ -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
}
+1
View File
@@ -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