package types import ( "crypto/sha256" "math" "math/rand/v2" "sync" "time" "go-socket/packages/Enums/ConnectionState" "go-socket/packages/Enums/WsEventType" "go-socket/packages/config" "github.com/coder/websocket" "github.com/google/uuid" ) type Rgba [4]uint8 type Sha256Hash [sha256.Size]byte func (r Rgba) GetRandom() Rgba { for i := range r { r[i] = uint8(rand.IntN(256)) } return r } type User struct { Mu sync.RWMutex `json:"-"` Name string `json:"name"` Pronouns string `json:"pronouns"` Description string `json:"description"` AvatarType string `json:"avatarType"` ProfileBgType string `json:"profileBackgroundType"` PasswordHash string `json:"-"` CreatedAt time.Time `json:"createdAt"` WsConn *websocket.Conn `json:"-"` Id uuid.UUID `json:"-"` Connections map[uuid.UUID]*Connection `json:"-"` Hubs map[uuid.UUID]*Hub `json:"-"` Color Rgba `json:"color"` } type UserProfileUpdateList struct { Pronouns bool Description bool Color bool Avatar bool ProfileBg bool } type Connection struct { Mu sync.RWMutex `json:"-"` Id uuid.UUID `json:"id"` CreatedAt time.Time `json:"createdAt"` MessagesBuff []*Message `json:"-"` NextBuffIdx uint32 `json:"-"` RequestorId uuid.UUID `json:"requestorId"` RecipientId uuid.UUID `json:"recipientId"` UserWantingToElevate uuid.UUID `json:"userWantingToElevate"` // TODO add to database HaveOverflowed bool `json:"-"` State ConnectionState.ConnectionState `json:"state"` } func NewConn() *Connection { return &Connection{ MessagesBuff: make([]*Message, config.MaxDirectMsgCache), } } func (conn *Connection) 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 } } // GetSortedMessagesBuff returns slice and its valid length. func (conn *Connection) 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 } func (conn *Connection) GetSecondUser(id uuid.UUID) uuid.UUID { if id == conn.RequestorId { return conn.RecipientId } return conn.RequestorId } type ConnectionStatusSetData struct { Id uuid.UUID `json:"id"` NewState ConnectionState.ConnectionState `json:"newState"` } type ConnectionElevatePendingData struct { Id uuid.UUID `json:"id"` UserWantingToElevate uuid.UUID `json:"userWantingToElevate"` } type Message struct { Id uuid.UUID `json:"id"` AttachedFile string `json:"attachedFile"` Content string `json:"content"` CreatedAt time.Time `json:"createdAt"` Sender uuid.UUID `json:"sender"` Receiver uuid.UUID `json:"receiver"` } type LoginReturn struct { Token string `json:"token"` UserId uuid.UUID `json:"userId"` } type WsEventMessage struct { Type WsEventType.WsEventType `json:"type"` Event any `json:"event"` } type WsAuthMessage struct { Success bool `json:"success"` Error string `json:"error"` } type Permissions uint32 const ( // Hub permissions PermissionSetHubName Permissions = 1 << iota PermissionSetHubIcon PermissionSetHubBg PermissionSetHubColor PermissionRemoveHub PermissionSetUserColorAllowed // User permissions PermissionAddUser PermissionRemoveUser PermissionRenameUser PermissionSelfRename PermissionMuteUser // Role permissions PermissionAddRole PermissionRemoveRole PermissionSetRoleName PermissionSetRoleColor PermissionSelfRoleRemove PermissionOnlySelfRoleRemove // Channel permissions PermissionAddChannel PermissionRemoveChannel PermissionSetChannelName PermissionSetChannelIcon PermissionSetChannelPermittedVisibleRoles PermissionSetChannelPermittedSendMessageRoles PermissionSetChannelPermittedReadHistoryRoles ) func (p *Permissions) Grant(permissions Permissions) { *p |= permissions } func (p *Permissions) GrantMultiple(perms []Permissions) { for _, perm := range perms { *p |= perm } } func (p *Permissions) Revoke(permissions Permissions) { *p &^= permissions } func (p *Permissions) Has(permissions Permissions) bool { return *p&permissions != 0 } func PermissionAll() Permissions { return math.MaxUint32 } type HubBoundRoles [3]uint64 const HubBoundRolesMax uint8 = 191 func (r *HubBoundRoles) Add(bit uint8) { r[bit>>6] |= 1 << (bit & 63) } func (r *HubBoundRoles) Remove(bit uint8) { r[bit>>6] &^= 1 << (bit & 63) } func (r *HubBoundRoles) Has(bit uint8) bool { return r[bit>>6]>>(bit&63)&1 == 1 } func (r *HubBoundRoles) HasSameId(against HubBoundRoles) bool { return against[0]&r[0] != 0 || against[1]&r[1] != 0 || against[2]&r[2] != 0 } type CachedUserPermissions uint8 const ( CachedUserCanView CachedUserPermissions = 1 << iota CachedUserCanReadHistory CachedUserCanMessage ) const CachedUserPermissionsAll = CachedUserCanMessage | CachedUserCanReadHistory | CachedUserCanReadHistory func (p *CachedUserPermissions) SetCanView() { *p |= CachedUserCanView } func (p *CachedUserPermissions) ClearCanView() { *p &^= CachedUserCanView } func (p CachedUserPermissions) CanView() bool { return p&CachedUserCanView != 0 } func (p *CachedUserPermissions) SetCanReadHistory() { *p |= CachedUserCanReadHistory } func (p *CachedUserPermissions) ClearCanReadHistory() { *p &^= CachedUserCanReadHistory } func (p CachedUserPermissions) CanReadHistory() bool { return p&CachedUserCanReadHistory != 0 } func (p *CachedUserPermissions) SetCanMessage() { *p |= CachedUserCanMessage } func (p *CachedUserPermissions) ClearCanMessage() { *p &^= CachedUserCanMessage } func (p CachedUserPermissions) CanMessage() bool { return p&CachedUserCanMessage != 0 } type Hub struct { Mu sync.RWMutex `json:"-"` CreatedAt time.Time `json:"createdAt"` Roles [256]*HubRole `json:"-"` Users map[uuid.UUID]*HubUser `json:"-"` Channels map[uuid.UUID]*HubChannel `json:"-"` Name string `json:"name"` IconUrl string `json:"iconUrl"` BgUrl string `json:"backgroundUrl"` JoinRole *HubRole `json:"joinRole"` Id uuid.UUID `json:"id"` Creator uuid.UUID `json:"creator"` Color Rgba `json:"color"` UserColorAllowed bool `json:"userColorAllowed"` } func NewHub() *Hub { return &Hub{ Users: make(map[uuid.UUID]*HubUser), Channels: make(map[uuid.UUID]*HubChannel), } } 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 IsDeleted bool `json:"-"` } 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 HubUser struct { Mu sync.RWMutex `json:"mu"` CreatedAt time.Time `json:"createdAt"` Roles HubBoundRoles `json:"-"` Name string `json:"name"` // Name empty = original name OriginalId uuid.UUID `json:"originalId"` IsMuted bool `json:"isMuted"` } func NewHubUser() *HubUser { return &HubUser{} } 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"` RolesCanView HubBoundRoles `json:"rolesCanView"` RolesCanMessage HubBoundRoles `json:"rolesCanMessage"` RolesCanReadHistory HubBoundRoles `json:"rolesCanReadHistory"` UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"` NextBuffIdx uint32 `json:"-"` Id uuid.UUID `json:"id"` Position uint8 `json:"position"` HaveOverflowed bool `json:"-"` } func NewHubChannel() *HubChannel { return &HubChannel{ MessagesBuff: make([]*Message, config.MaxHubChannelMsgCache), UsersCachedPermissions: make(map[uuid.UUID]CachedUserPermissions), } } 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 } } // 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 }