diff --git a/postgres/.gitignore b/docker/minIO/.gitignore similarity index 100% rename from postgres/.gitignore rename to docker/minIO/.gitignore diff --git a/docker/minIO/docker-compose.yml b/docker/minIO/docker-compose.yml new file mode 100644 index 0000000..a5c8fa1 --- /dev/null +++ b/docker/minIO/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.8" + +services: + minio: + image: minio/minio:RELEASE.2024-03-19T00-00-00Z + container_name: minio + restart: unless-stopped + environment: + MINIO_ROOT_USER: root + MINIO_ROOT_PASSWORD: change_to_env + volumes: + - ./data:/data + - ./config:/root/.minio + ports: + - "9000:9000" + - "9001:9001" + command: server /data --console-address ":9001" \ No newline at end of file diff --git a/docker/postgres/.gitignore b/docker/postgres/.gitignore new file mode 100644 index 0000000..6320cd2 --- /dev/null +++ b/docker/postgres/.gitignore @@ -0,0 +1 @@ +data \ No newline at end of file diff --git a/postgres/docker-compose.yml b/docker/postgres/docker-compose.yml similarity index 80% rename from postgres/docker-compose.yml rename to docker/postgres/docker-compose.yml index f4a5a19..1ffdffe 100644 --- a/postgres/docker-compose.yml +++ b/docker/postgres/docker-compose.yml @@ -7,4 +7,4 @@ services: ports: - "5432:5432" volumes: - - ./data:/var/lib/postgresql/data + - ./data:/var/lib/postgresql/dat diff --git a/get.go b/get.go deleted file mode 100644 index 4e3cea5..0000000 --- a/get.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "context" - - "github.com/google/uuid" -) - -func GetUserById(ctx context.Context, userId uuid.UUID) (*User, error) { - user, err := CacheGetUserById(userId) - if err != nil { - user = &User{Id: userId} - err = PgGetWholeUser(ctx, user) - if err != nil { - return nil, err - } - } - - return user, nil -} - -func GetUserByToken(ctx context.Context, token string) (*User, error) { - userId, err := TokenValidateGetId(token) - if err != nil { - return nil, err - } - return GetUserById(ctx, userId) -} diff --git a/go.mod b/go.mod index 394e0a1..e4c6aa1 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,23 @@ require ( ) require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/klauspost/compress v1.18.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.11 // indirect + github.com/klauspost/crc32 v1.3.0 // indirect + github.com/minio/crc64nvme v1.1.1 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.100 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/rs/xid v1.6.0 // indirect + github.com/tinylib/msgp v1.6.1 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect ) require ( diff --git a/main.go b/main.go index f2304ae..9fc8956 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,10 @@ import ( "context" "log" "net/http" + + http2 "go-socket/packages/http" + "go-socket/packages/postgresql" + "go-socket/packages/wsServer" ) func withCORS(h http.HandlerFunc) http.HandlerFunc { @@ -15,23 +19,23 @@ func withCORS(h http.HandlerFunc) http.HandlerFunc { func main() { ctx := context.Background() - PgInit(ctx) + postgresql.PgInit(ctx) - http.HandleFunc("/new/user", withCORS(HttpHandleUserNew)) - http.HandleFunc("/new/connection", withCORS(HttpHandleUserNewConnection)) - http.HandleFunc("/new/token", withCORS(HttpHandleUserNewToken)) - http.HandleFunc("/mod/user/appearence", withCORS(HttpHandleUserModifyAppearance)) - http.HandleFunc("/mod/user/about", withCORS(HttpHandleUserModifyAbout)) - http.HandleFunc("/mod/connection/accept", withCORS(HttpHandleUserElevateConnection)) + http.HandleFunc("/new/user", withCORS(http2.HandleUserNew)) + http.HandleFunc("/new/connection", withCORS(http2.HandleUserNewConnection)) + http.HandleFunc("/new/token", withCORS(http2.HandleUserNewToken)) + http.HandleFunc("/mod/user/appearence", withCORS(http2.HandleUserModifyAppearance)) + http.HandleFunc("/mod/user/about", withCORS(http2.HandleUserModifyAbout)) + http.HandleFunc("/mod/connection/accept", withCORS(http2.HandleUserElevateConnection)) - http.HandleFunc("/get/connections", withCORS(HttpHandleUserGetConnections)) - http.HandleFunc("/get/connection/messages", withCORS(HttpHandleUserGetConnectionMessages)) + http.HandleFunc("/get/connections", withCORS(http2.HandleUserGetConnections)) + http.HandleFunc("/get/connection/messages", withCORS(http2.HandleUserGetConnectionMessages)) - http.HandleFunc("/del/user", withCORS(HttpHandleUserDelete)) - http.HandleFunc("/del/connection", withCORS(HttpHandleUserDeleteConnection)) + http.HandleFunc("/del/user", withCORS(http2.HandleUserDelete)) + http.HandleFunc("/del/connection", withCORS(http2.HandleUserDeleteConnection)) - http.HandleFunc("/msg/user", withCORS(HttpHandleDm)) - http.HandleFunc("/ws", ServeWsConnection) + http.HandleFunc("/msg/user", withCORS(http2.HandleDm)) + http.HandleFunc("/ws", wsServer.ServeWsConnection) log.Println("listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) diff --git a/Enums/ConnectionState/ConnectionState.go b/packages/Enums/ConnectionState/ConnectionState.go similarity index 100% rename from Enums/ConnectionState/ConnectionState.go rename to packages/Enums/ConnectionState/ConnectionState.go diff --git a/Enums/WsEventType/WsMessageFrom.go b/packages/Enums/WsEventType/WsMessageFrom.go similarity index 100% rename from Enums/WsEventType/WsMessageFrom.go rename to packages/Enums/WsEventType/WsMessageFrom.go diff --git a/cache.go b/packages/cache/cache.go similarity index 54% rename from cache.go rename to packages/cache/cache.go index 3efd49a..369fda8 100644 --- a/cache.go +++ b/packages/cache/cache.go @@ -1,33 +1,35 @@ -package main +package cache import ( "fmt" "sync" + "go-socket/packages/types" + "github.com/google/uuid" ) var ( - mu sync.RWMutex - CacheUsers = make(map[uuid.UUID]*User) + Mu sync.RWMutex + Users = make(map[uuid.UUID]*types.User) ) -func CacheGetUserById(id uuid.UUID) (*User, error) { - mu.RLock() - defer mu.RUnlock() +func CacheGetUserById(id uuid.UUID) (*types.User, error) { + Mu.RLock() + defer Mu.RUnlock() - user, ok := CacheUsers[id] + user, ok := Users[id] if !ok { return nil, fmt.Errorf("user %s not found", id) } return user, nil } -func CacheGetUserByName(name string) (*User, error) { - mu.RLock() - defer mu.RUnlock() +func CacheGetUserByName(name string) (*types.User, error) { + Mu.RLock() + defer Mu.RUnlock() - for _, user := range CacheUsers { + for _, user := range Users { if user.Name == name { return user, nil } @@ -35,21 +37,21 @@ func CacheGetUserByName(name string) (*User, error) { return nil, fmt.Errorf("user %s not found", name) } -func CacheSaveUser(user *User) { - mu.Lock() - defer mu.Unlock() +func CacheSaveUser(user *types.User) { + Mu.Lock() + defer Mu.Unlock() - CacheUsers[user.Id] = user + Users[user.Id] = user } func CacheDeleteUser(id uuid.UUID) { - mu.Lock() - defer mu.Unlock() + Mu.Lock() + defer Mu.Unlock() - delete(CacheUsers, id) + delete(Users, id) } -func CacheAddConnection(a, b *User, conn *Connection) { +func CacheAddConnection(a, b *types.User, conn *types.Connection) { first, second := a, b if a.Id.String() > b.Id.String() { first, second = b, a @@ -62,7 +64,7 @@ func CacheAddConnection(a, b *User, conn *Connection) { first.Mu.Unlock() } -func CacheDeleteConnection(a, b *User, id uuid.UUID) { +func CacheDeleteConnection(a, b *types.User, id uuid.UUID) { first, second := a, b if a.Id.String() > b.Id.String() { first, second = b, a @@ -75,10 +77,9 @@ func CacheDeleteConnection(a, b *User, id uuid.UUID) { first.Mu.Unlock() } -func CacheGetConnection(user *User, id uuid.UUID) (*Connection, bool) { +func CacheGetConnection(user *types.User, id uuid.UUID) (*types.Connection, bool) { user.Mu.RLock() defer user.Mu.RUnlock() conn, ok := user.Connections[id] return conn, ok } - diff --git a/convertions.go b/packages/convertions/convertions.go similarity index 72% rename from convertions.go rename to packages/convertions/convertions.go index ec2e307..5320c1d 100644 --- a/convertions.go +++ b/packages/convertions/convertions.go @@ -1,4 +1,4 @@ -package main +package convertions import ( "fmt" @@ -6,6 +6,8 @@ import ( "strings" "time" + "go-socket/packages/types" + "github.com/google/uuid" ) @@ -14,12 +16,12 @@ func ConvertStringUint32(s string) (uint32, error) { return uint32(v), err } -func ConvertStringToRgba(str string) (*Rgba, error) { +func ConvertStringToRgba(str string) (*types.Rgba, error) { parts := strings.SplitN(str, ",", 5) if len(parts) != 4 { return nil, fmt.Errorf("invalid rgba") } - rgba := &Rgba{} + rgba := &types.Rgba{} for i, p := range parts { n, err := strconv.ParseUint(strings.TrimSpace(p), 10, 8) if err != nil { @@ -30,12 +32,12 @@ func ConvertStringToRgba(str string) (*Rgba, error) { return rgba, nil } -func RgbaToUint32(r *Rgba) uint32 { +func RgbaToUint32(r *types.Rgba) uint32 { return uint32(r[0])<<24 | uint32(r[1])<<16 | uint32(r[2])<<8 | uint32(r[3]) } -func Uint32ToRgba(v uint32) *Rgba { - return &Rgba{uint8(v >> 24), uint8(v >> 16), uint8(v >> 8), uint8(v)} +func Uint32ToRgba(v uint32) *types.Rgba { + return &types.Rgba{uint8(v >> 24), uint8(v >> 16), uint8(v >> 8), uint8(v)} } func ConvertStringUuid(str string) (uuid.UUID, error) { diff --git a/globals.go b/packages/globals/globals.go similarity index 72% rename from globals.go rename to packages/globals/globals.go index 5c839a2..c0fff61 100644 --- a/globals.go +++ b/packages/globals/globals.go @@ -1,4 +1,4 @@ -package main +package globals const ( MaxDirectMsgCache uint32 = 12 diff --git a/packages/http/get.go b/packages/http/get.go new file mode 100644 index 0000000..951fc83 --- /dev/null +++ b/packages/http/get.go @@ -0,0 +1,33 @@ +package http + +import ( + "context" + + "go-socket/packages/cache" + "go-socket/packages/postgresql" + "go-socket/packages/tokens" + "go-socket/packages/types" + + "github.com/google/uuid" +) + +func GetUserById(ctx context.Context, userId uuid.UUID) (*types.User, error) { + user, err := cache.CacheGetUserById(userId) + if err != nil { + user = &types.User{Id: userId} + err = postgresql.PgGetWholeUser(ctx, user) + if err != nil { + return nil, err + } + } + + return user, nil +} + +func GetUserByToken(ctx context.Context, token string) (*types.User, error) { + userId, err := tokens.TokenValidateGetId(token) + if err != nil { + return nil, err + } + return GetUserById(ctx, userId) +} diff --git a/http.go b/packages/http/helper.go similarity index 62% rename from http.go rename to packages/http/helper.go index 8611f61..f115f63 100644 --- a/http.go +++ b/packages/http/helper.go @@ -1,10 +1,10 @@ -package main +package http import ( "net/http" ) -func HttpMethodAllowed(response *http.ResponseWriter, request *http.Request) bool { +func methodAllowed(response *http.ResponseWriter, request *http.Request) bool { if request.Method != http.MethodPost { http.Error(*response, "POST only", http.StatusMethodNotAllowed) return false diff --git a/httpConnectionAndDm.go b/packages/http/httpConnectionAndDm.go similarity index 71% rename from httpConnectionAndDm.go rename to packages/http/httpConnectionAndDm.go index 98b06e7..52d03e3 100644 --- a/httpConnectionAndDm.go +++ b/packages/http/httpConnectionAndDm.go @@ -1,4 +1,4 @@ -package main +package http import ( json2 "encoding/json" @@ -7,14 +7,20 @@ import ( "slices" "time" - "go-socket/Enums/ConnectionState" - "go-socket/Enums/WsEventType" + "go-socket/packages/Enums/ConnectionState" + "go-socket/packages/Enums/WsEventType" + "go-socket/packages/cache" + "go-socket/packages/convertions" + "go-socket/packages/globals" + "go-socket/packages/postgresql" + "go-socket/packages/types" + "go-socket/packages/wsServer" "github.com/google/uuid" ) -func HttpHandleDm(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleDm(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } @@ -25,12 +31,12 @@ func HttpHandleDm(response http.ResponseWriter, request *http.Request) { return } - targetConnection, err := ConvertStringUuid(request.FormValue("connectionid")) + targetConnection, err := convertions.ConvertStringUuid(request.FormValue("connectionid")) if err != nil { http.Error(response, "invalid connectionid", http.StatusBadRequest) return } - conn, ok := CacheGetConnection(user, targetConnection) + conn, ok := cache.CacheGetConnection(user, targetConnection) if !ok { http.Error(response, "invalid connectionid", http.StatusBadRequest) return @@ -42,7 +48,7 @@ func HttpHandleDm(response http.ResponseWriter, request *http.Request) { return } - var target *User + var target *types.User if user.Id == conn.RequestorId { target, err = GetUserById(ctx, conn.RecipientId) @@ -57,7 +63,7 @@ func HttpHandleDm(response http.ResponseWriter, request *http.Request) { http.Error(response, "internal server error", http.StatusInternalServerError) return } - message := &Message{ + message := &types.Message{ Id: uuid.New(), Content: msgContent, CreatedAt: time.Now(), @@ -65,12 +71,12 @@ func HttpHandleDm(response http.ResponseWriter, request *http.Request) { Receiver: conn.Id, } - WsSendMessageCloseIfTimeout(target, WsEventMessage{ + wsServer.WsSendMessageCloseIfTimeout(target, types.WsEventMessage{ Type: WsEventType.DirectMessage, Event: message, }) - err = PgConnectionMessageSave(ctx, message) + err = postgresql.PgConnectionMessageSave(ctx, message) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -79,8 +85,8 @@ func HttpHandleDm(response http.ResponseWriter, request *http.Request) { response.WriteHeader(http.StatusAccepted) } -func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserGetConnectionMessages(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() @@ -90,23 +96,23 @@ func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request * return } - connectionId, err := ConvertStringUuid(request.FormValue("connectionid")) + connectionId, err := convertions.ConvertStringUuid(request.FormValue("connectionid")) if err != nil { http.Error(response, "invalid connectionid", http.StatusBadRequest) return } - before, err := ConvertStringTimestamp(request.FormValue("before")) + before, err := convertions.ConvertStringTimestamp(request.FormValue("before")) if err != nil { before = time.Now() } - messagesCap, err := ConvertStringUint32(request.FormValue("messages")) + messagesCap, err := convertions.ConvertStringUint32(request.FormValue("messages")) if err != nil { - messagesCap = MaxDirectMsgCache + messagesCap = globals.MaxDirectMsgCache } - conn, ok := CacheGetConnection(user, connectionId) + conn, ok := cache.CacheGetConnection(user, connectionId) if !ok { http.Error(response, "invalid connectionid", http.StatusBadRequest) return @@ -119,11 +125,11 @@ func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request * validBufCount++ } - var messages []*Message + var messages []*types.Message if validBufCount >= messagesCap { start := validBufCount - messagesCap - messages = make([]*Message, messagesCap) + messages = make([]*types.Message, messagesCap) for i := uint32(0); i < messagesCap; i++ { messages[i] = buffer[start+i] } @@ -133,12 +139,12 @@ func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request * if validBufCount > 0 { cutoff = buffer[0].CreatedAt } - dbMessages, err := PgConnectionGetMessagesBefore(ctx, cutoff, connectionId, remaining) + dbMessages, err := postgresql.PgConnectionGetMessagesBefore(ctx, cutoff, connectionId, remaining) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - messages = make([]*Message, 0, uint32(len(dbMessages))+validBufCount) + messages = make([]*types.Message, 0, uint32(len(dbMessages))+validBufCount) messages = append(messages, dbMessages...) for i := uint32(0); i < validBufCount; i++ { messages = append(messages, buffer[i]) @@ -155,8 +161,8 @@ func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request * response.Write(json) } -func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserNewConnection(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() @@ -165,7 +171,7 @@ func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Req http.Error(response, "invalid token", http.StatusUnauthorized) return } - recipientId, err := ConvertStringUuid(request.FormValue("recipient")) + recipientId, err := convertions.ConvertStringUuid(request.FormValue("recipient")) if err != nil { http.Error(response, "no such user", http.StatusUnauthorized) return @@ -192,20 +198,20 @@ func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Req } requestor.Mu.RUnlock() - connection := &Connection{ + connection := &types.Connection{ CreatedAt: time.Now(), RequestorId: requestor.Id, RecipientId: recipient.Id, State: ConnectionState.Stranger, } - err = PgConnectionSave(ctx, connection) + err = postgresql.PgConnectionSave(ctx, connection) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - CacheAddConnection(requestor, recipient, connection) + cache.CacheAddConnection(requestor, recipient, connection) - WsSendMessageCloseIfTimeout(recipient, WsEventMessage{ + wsServer.WsSendMessageCloseIfTimeout(recipient, types.WsEventMessage{ Type: WsEventType.ConnectionCreated, Event: connection, }) @@ -214,8 +220,8 @@ func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Req return } -func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserDeleteConnection(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() @@ -226,19 +232,19 @@ func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http. return } - connectionId, err := ConvertStringUuid(request.FormValue("connectionid")) + connectionId, err := convertions.ConvertStringUuid(request.FormValue("connectionid")) if err != nil { http.Error(response, "invalid connectionid", http.StatusBadRequest) return } - conn, ok := CacheGetConnection(user, connectionId) + conn, ok := cache.CacheGetConnection(user, connectionId) if !ok { http.Error(response, "invalid connectionid", http.StatusBadRequest) return } - var user2 *User + var user2 *types.User if conn.RequestorId == user.Id { recipient, err := GetUserById(ctx, conn.RecipientId) if err != nil { @@ -258,14 +264,14 @@ func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http. return } - err = PgConnectionDelete(ctx, conn) + err = postgresql.PgConnectionDelete(ctx, conn) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - CacheDeleteConnection(user, user2, connectionId) - WsSendMessageCloseIfTimeout(user2, WsEventMessage{ + cache.CacheDeleteConnection(user, user2, connectionId) + wsServer.WsSendMessageCloseIfTimeout(user2, types.WsEventMessage{ Type: WsEventType.ConnectionDeleted, Event: connectionId, }) @@ -273,8 +279,8 @@ func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http. response.WriteHeader(http.StatusAccepted) } -func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserElevateConnection(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() @@ -283,12 +289,12 @@ func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http http.Error(response, "invalid token", http.StatusUnauthorized) return } - connectionId, err := ConvertStringUuid(request.FormValue("connectionid")) + connectionId, err := convertions.ConvertStringUuid(request.FormValue("connectionid")) if err != nil { http.Error(response, "invalid connectionid", http.StatusBadRequest) return } - conn, ok := CacheGetConnection(user, connectionId) + conn, ok := cache.CacheGetConnection(user, connectionId) if !ok { http.Error(response, "invalid connectionid", http.StatusBadRequest) return @@ -309,14 +315,14 @@ func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http return } - err = PgConnectionUpdateState(ctx, conn) + err = postgresql.PgConnectionUpdateState(ctx, conn) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.Write([]byte("elevated")) - var user2 *User + var user2 *types.User if conn.RequestorId == user.Id { user2, err = GetUserById(ctx, conn.RecipientId) } else { @@ -327,9 +333,9 @@ func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http return } - WsSendMessageCloseIfTimeout(user2, WsEventMessage{ + wsServer.WsSendMessageCloseIfTimeout(user2, types.WsEventMessage{ Type: WsEventType.ConnectionElevated, - Event: ConnectionElevationData{ + Event: types.ConnectionElevationData{ Id: connectionId, NewState: conn.State, }, @@ -342,8 +348,8 @@ func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http response.Write([]byte("waiting for second user to elevate")) } -func HttpHandleUserGetConnections(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserGetConnections(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() diff --git a/httpUser.go b/packages/http/httpUser.go similarity index 59% rename from httpUser.go rename to packages/http/httpUser.go index a863a2c..fc4fc02 100644 --- a/httpUser.go +++ b/packages/http/httpUser.go @@ -1,15 +1,22 @@ -package main +package http import ( json2 "encoding/json" "net/http" "time" + "go-socket/packages/cache" + "go-socket/packages/convertions" + "go-socket/packages/passwords" + "go-socket/packages/postgresql" + "go-socket/packages/tokens" + "go-socket/packages/types" + "golang.org/x/crypto/bcrypt" ) -func HttpHandleUserNewToken(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserNewToken(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } @@ -19,27 +26,27 @@ func HttpHandleUserNewToken(response http.ResponseWriter, request *http.Request) return } - password := request.FormValue("password") + password := request.FormValue("passwords") if len(password) < 8 { - http.Error(response, "no or short password", http.StatusBadRequest) + http.Error(response, "no or short passwords", http.StatusBadRequest) return } var ( - user *User + user *types.User err error ctx = request.Context() ) - user, err = CacheGetUserByName(username) + user, err = cache.CacheGetUserByName(username) if err != nil { - user = &User{Name: username} - if err = PgUserGetStandardInfoByName(ctx, user); err != nil { + user = &types.User{Name: username} + if err = postgresql.PgUserGetStandardInfoByName(ctx, user); err != nil { http.Error(response, "bad login", http.StatusUnauthorized) return } - if err = PgGetWholeUser(ctx, user); err != nil { + if err = postgresql.PgGetWholeUser(ctx, user); err != nil { http.Error(response, err.Error(), http.StatusInternalServerError) return } @@ -51,13 +58,13 @@ func HttpHandleUserNewToken(response http.ResponseWriter, request *http.Request) return } - token, err := TokenCreate(user.Id) + token, err := tokens.TokenCreate(user.Id) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - json, err := json2.Marshal(LoginReturn{Token: token, UserId: user.Id}) + json, err := json2.Marshal(types.LoginReturn{Token: token, UserId: user.Id}) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -67,8 +74,8 @@ func HttpHandleUserNewToken(response http.ResponseWriter, request *http.Request) response.Write(json) } -func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserNew(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } @@ -78,28 +85,28 @@ func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) { return } - password := request.FormValue("password") + password := request.FormValue("passwords") if len(password) < 8 { - http.Error(response, "no or short password", http.StatusBadRequest) + http.Error(response, "no or short passwords", http.StatusBadRequest) return } - hashedPassword, err := PasswordHash(password) + hashedPassword, err := passwords.PasswordHash(password) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - newUser := &User{ + newUser := &types.User{ Name: username, PasswordHash: hashedPassword, - Color: Rgba{}.GetRandom(), + Color: types.Rgba{}.GetRandom(), CreatedAt: time.Now(), } ctx := request.Context() - err = PgUserSave(ctx, newUser) + err = postgresql.PgUserSave(ctx, newUser) if err != nil { http.Error(response, "name taken", http.StatusUnauthorized) return @@ -108,31 +115,31 @@ func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) { response.WriteHeader(http.StatusCreated) } -func HttpHandleUserDelete(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +func HandleUserDelete(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } ctx := request.Context() - userId, err := TokenValidateGetId(request.FormValue("token")) + userId, err := tokens.TokenValidateGetId(request.FormValue("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } - err = PgUserDelete(ctx, userId) + err = postgresql.PgUserDelete(ctx, userId) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - CacheDeleteUser(userId) + cache.CacheDeleteUser(userId) response.WriteHeader(http.StatusAccepted) } -// HttpHandleUserModifyAppearance currently just color -func HttpHandleUserModifyAppearance(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +// HandleUserModifyAppearance currently just color +func HandleUserModifyAppearance(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } @@ -143,13 +150,13 @@ func HttpHandleUserModifyAppearance(response http.ResponseWriter, request *http. return } - color, err := ConvertStringToRgba(request.FormValue("color")) + color, err := convertions.ConvertStringToRgba(request.FormValue("color")) if err != nil { http.Error(response, "invalid color", http.StatusBadRequest) return } user.Color = color - err = PgUserSetColor(ctx, user) + err = postgresql.PgUserSetColor(ctx, user) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return @@ -157,9 +164,9 @@ func HttpHandleUserModifyAppearance(response http.ResponseWriter, request *http. response.WriteHeader(http.StatusAccepted) } -// HttpHandleUserModifyAbout currently just pronouns -func HttpHandleUserModifyAbout(response http.ResponseWriter, request *http.Request) { - if !HttpMethodAllowed(&response, request) { +// HandleUserModifyAbout currently just pronouns +func HandleUserModifyAbout(response http.ResponseWriter, request *http.Request) { + if !methodAllowed(&response, request) { return } @@ -177,7 +184,7 @@ func HttpHandleUserModifyAbout(response http.ResponseWriter, request *http.Reque } user.Pronouns = pronouns - err = PgUserSetPronouns(ctx, user) + err = postgresql.PgUserSetPronouns(ctx, user) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return diff --git a/packages/minio/minio.go b/packages/minio/minio.go new file mode 100644 index 0000000..e9c16b7 --- /dev/null +++ b/packages/minio/minio.go @@ -0,0 +1,28 @@ +package minio + +import ( + "context" + + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" +) + +func MinInit() { + ctx := context.Background() + + dbConn, err := minio.New("localhost:9000", &minio.Options{ + Creds: credentials.NewStaticV4("root", "change_to_env", ""), + Secure: false, + }) // TODO change in production + if err != nil { + panic(err) + } + + exists, err := dbConn.BucketExists(ctx, "main") + if err != nil { + panic(err) + } + + if !exists { + } +} diff --git a/password.go b/packages/passwords/password.go similarity index 95% rename from password.go rename to packages/passwords/password.go index afee84f..04d7e23 100644 --- a/password.go +++ b/packages/passwords/password.go @@ -1,4 +1,4 @@ -package main +package passwords import "golang.org/x/crypto/bcrypt" diff --git a/postgresql.go b/packages/postgresql/postgresql.go similarity index 78% rename from postgresql.go rename to packages/postgresql/postgresql.go index aa6fe51..4473bd0 100644 --- a/postgresql.go +++ b/packages/postgresql/postgresql.go @@ -1,10 +1,14 @@ -package main +package postgresql import ( "context" "fmt" "time" + "go-socket/packages/cache" + "go-socket/packages/convertions" + "go-socket/packages/types" + "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) @@ -65,12 +69,12 @@ func PgInit(ctx context.Context) { } -func PgUserSave(ctx context.Context, user *User) error { +func PgUserSave(ctx context.Context, user *types.User) error { err := dbConn.QueryRow(ctx, ` INSERT INTO users (name, pass_hash, pronouns, rgba, created_at) VALUES ($1, $2, $3, $4, $5) RETURNING id - `, user.Name, user.PasswordHash, user.Pronouns, RgbaToUint32(user.Color), user.CreatedAt). + `, user.Name, user.PasswordHash, user.Pronouns, convertions.RgbaToUint32(user.Color), user.CreatedAt). Scan(&user.Id) return err } @@ -82,43 +86,43 @@ func PgUserDelete(ctx context.Context, id uuid.UUID) error { return err } -func PgUserGetStandardInfoByName(ctx context.Context, user *User) error { +func PgUserGetStandardInfoByName(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT id, name, pass_hash, COALESCE(pronouns, ''), rgba, created_at FROM users WHERE name = $1 `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt) if err == nil { - user.Color = Uint32ToRgba(uint32(rgba)) + user.Color = convertions.Uint32ToRgba(uint32(rgba)) } return err } -func PgUserGetById(ctx context.Context, user *User) error { +func PgUserGetById(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT name, pass_hash, COALESCE(pronouns, ''), rgba, created_at FROM users WHERE id = $1 `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt) if err == nil { - user.Color = Uint32ToRgba(uint32(rgba)) + user.Color = convertions.Uint32ToRgba(uint32(rgba)) } return err } -func PgUserSetColor(ctx context.Context, user *User) error { +func PgUserSetColor(ctx context.Context, user *types.User) error { _, err := dbConn.Exec(ctx, ` UPDATE users SET rgba = $1 WHERE id = $2 - `, RgbaToUint32(user.Color), user.Id) + `, convertions.RgbaToUint32(user.Color), user.Id) return err } -func PgUserSetPronouns(ctx context.Context, user *User) error { +func PgUserSetPronouns(ctx context.Context, user *types.User) error { _, err := dbConn.Exec(ctx, ` UPDATE users SET pronouns = $1 WHERE id = $2 `, user.Pronouns, user.Id) return err } -func PgGetWholeUser(ctx context.Context, user *User) error { +func PgGetWholeUser(ctx context.Context, user *types.User) error { if err := PgUserGetById(ctx, user); err != nil { return err } @@ -126,25 +130,25 @@ func PgGetWholeUser(ctx context.Context, user *User) error { return err } - CacheSaveUser(user) + cache.CacheSaveUser(user) return nil } -func PgConnectionSave(ctx context.Context, conn *Connection) error { +func PgConnectionSave(ctx context.Context, conn *types.Connection) error { return dbConn.QueryRow(ctx, ` INSERT INTO user_connections (requestor_id, recipient_id, state, created_at) VALUES ($1, $2, $3, $4) RETURNING id `, conn.RequestorId, conn.RecipientId, conn.State, conn.CreatedAt).Scan(&conn.Id) } -func PgConnectionDelete(ctx context.Context, conn *Connection) error { +func PgConnectionDelete(ctx context.Context, conn *types.Connection) error { _, err := dbConn.Exec(ctx, ` DELETE FROM user_connections WHERE id = $1 `, conn.Id) return err } -func PgConnectionsGetBelongingToUser(ctx context.Context, user *User) error { +func PgConnectionsGetBelongingToUser(ctx context.Context, user *types.User) error { rows, err := dbConn.Query(ctx, ` SELECT id, requestor_id, recipient_id, state, created_at FROM user_connections @@ -156,11 +160,11 @@ func PgConnectionsGetBelongingToUser(ctx context.Context, user *User) error { defer rows.Close() if user.Connections == nil { - user.Connections = make(map[uuid.UUID]*Connection) + user.Connections = make(map[uuid.UUID]*types.Connection) } for rows.Next() { - conn := &Connection{} + conn := &types.Connection{} if err = rows.Scan(&conn.Id, &conn.RequestorId, &conn.RecipientId, &conn.State, &conn.CreatedAt); err != nil { return fmt.Errorf("scanning connection row: %w", err) } @@ -169,14 +173,14 @@ func PgConnectionsGetBelongingToUser(ctx context.Context, user *User) error { return rows.Err() } -func PgConnectionUpdateState(ctx context.Context, conn *Connection) error { +func PgConnectionUpdateState(ctx context.Context, conn *types.Connection) error { _, err := dbConn.Exec(ctx, ` UPDATE user_connections SET state = $1 WHERE id = $2 `, conn.State, conn.Id) return err } -func PgConnectionMessageSave(ctx context.Context, message *Message) error { +func PgConnectionMessageSave(ctx context.Context, message *types.Message) error { if message.Id != (uuid.UUID{}) { _, err := dbConn.Exec(ctx, ` INSERT INTO direct_messages (id, sender_id, receiver_id, created_at, content) VALUES ($1, $2, $3, $4, $5) @@ -189,7 +193,7 @@ func PgConnectionMessageSave(ctx context.Context, message *Message) error { `, message.Sender, message.Receiver, message.CreatedAt, message.Content).Scan(&message.Id) } -func PgConnectionGetMessagesBefore(ctx context.Context, before time.Time, connection uuid.UUID, cap uint32) ([]*Message, error) { +func PgConnectionGetMessagesBefore(ctx context.Context, before time.Time, connection uuid.UUID, cap uint32) ([]*types.Message, error) { rows, err := dbConn.Query(ctx, ` SELECT id, sender_id, receiver_id, created_at, content FROM ( @@ -207,9 +211,9 @@ func PgConnectionGetMessagesBefore(ctx context.Context, before time.Time, connec } defer rows.Close() - messages := make([]*Message, 0, cap) + messages := make([]*types.Message, 0, cap) for rows.Next() { - msg := &Message{} + msg := &types.Message{} if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content); err != nil { return nil, err } diff --git a/tokens.go b/packages/tokens/tokens.go similarity index 98% rename from tokens.go rename to packages/tokens/tokens.go index 4fbb255..4911800 100644 --- a/tokens.go +++ b/packages/tokens/tokens.go @@ -1,4 +1,4 @@ -package main +package tokens import ( "fmt" diff --git a/type.go b/packages/types/types.go similarity index 52% rename from type.go rename to packages/types/types.go index be48e17..150ad03 100644 --- a/type.go +++ b/packages/types/types.go @@ -1,12 +1,13 @@ -package main +package types import ( "math/rand/v2" "sync" "time" - "go-socket/Enums/ConnectionState" - "go-socket/Enums/WsEventType" + "go-socket/packages/Enums/ConnectionState" + "go-socket/packages/Enums/WsEventType" + "go-socket/packages/globals" "github.com/coder/websocket" "github.com/google/uuid" @@ -34,31 +35,31 @@ type User struct { } type Connection struct { - Mu sync.RWMutex `json:"-"` - Id uuid.UUID `json:"id"` - CreatedAt time.Time `json:"createdAt"` - MessagesBuff [MaxDirectMsgCache]*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"` + Mu sync.RWMutex `json:"-"` + Id uuid.UUID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + MessagesBuff [globals.MaxDirectMsgCache]*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 (conn *Connection) AddMessageToBuff(message *Message) { conn.Mu.Lock() defer conn.Mu.Unlock() - conn.MessagesBuff[conn.NextBuffIdx%MaxDirectMsgCache] = message + conn.MessagesBuff[conn.NextBuffIdx%globals.MaxDirectMsgCache] = message conn.NextBuffIdx++ - if conn.NextBuffIdx >= MaxDirectMsgCache { + if conn.NextBuffIdx >= globals.MaxDirectMsgCache { conn.HaveOverflowed = true } } // GetSortedMessagesBuff returns arr, length -func (conn *Connection) GetSortedMessagesBuff() (*[MaxDirectMsgCache]*Message, uint32) { +func (conn *Connection) GetSortedMessagesBuff() (*[globals.MaxDirectMsgCache]*Message, uint32) { conn.Mu.RLock() defer conn.Mu.RUnlock() @@ -66,11 +67,11 @@ func (conn *Connection) GetSortedMessagesBuff() (*[MaxDirectMsgCache]*Message, u return &conn.MessagesBuff, conn.NextBuffIdx } - sorted := new([MaxDirectMsgCache]*Message) - for i := uint32(0); i < MaxDirectMsgCache; i++ { - sorted[i] = conn.MessagesBuff[(conn.NextBuffIdx+i)%MaxDirectMsgCache] + sorted := new([globals.MaxDirectMsgCache]*Message) + for i := uint32(0); i < globals.MaxDirectMsgCache; i++ { + sorted[i] = conn.MessagesBuff[(conn.NextBuffIdx+i)%globals.MaxDirectMsgCache] } - return sorted, MaxDirectMsgCache + return sorted, globals.MaxDirectMsgCache } type ConnectionElevationData struct { @@ -93,7 +94,7 @@ type LoginReturn struct { } type WsEventMessage struct { - Type WsEventType.WsEventType `json:"type"` + Type WsEventType.WsEventType `json:"types"` Event any `json:"event"` } diff --git a/wsServer.go b/packages/wsServer/wsServer.go similarity index 69% rename from wsServer.go rename to packages/wsServer/wsServer.go index bfca2bc..ac11fba 100644 --- a/wsServer.go +++ b/packages/wsServer/wsServer.go @@ -1,4 +1,4 @@ -package main +package wsServer import ( "context" @@ -7,7 +7,10 @@ import ( "net/http" "time" - "go-socket/Enums/WsEventType" + "go-socket/packages/Enums/WsEventType" + "go-socket/packages/cache" + "go-socket/packages/tokens" + "go-socket/packages/types" "github.com/coder/websocket" "github.com/coder/websocket/wsjson" @@ -25,7 +28,7 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request ctx, cancel := context.WithCancel(context.Background()) defer cancel() - var user = User{WsConn: connection} + var user = types.User{WsConn: connection} var isAuthenticated bool var ignoreCache bool @@ -54,7 +57,7 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request } } -func WsSendMessageCloseIfTimeout(user *User, message any) { +func WsSendMessageCloseIfTimeout(user *types.User, message any) { if user.WsConn == nil { return } @@ -72,29 +75,29 @@ func WsSendMessageCloseIfTimeout(user *User, message any) { } func sendToAllMessageCloseIfTimeout(message *map[string]any) { - mu.RLock() - users := make([]*User, 0, len(CacheUsers)) - for _, user := range CacheUsers { + cache.Mu.RLock() + users := make([]*types.User, 0, len(cache.Users)) + for _, user := range cache.Users { users = append(users, user) } - mu.RUnlock() + cache.Mu.RUnlock() for _, user := range users { WsSendMessageCloseIfTimeout(user, message) } } -func handleAuthenticatedMessage(user *User, userMessage *map[string]any) bool { +func handleAuthenticatedMessage(user *types.User, userMessage *map[string]any) bool { WsSendMessageCloseIfTimeout(user, userMessage) return true } -func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage *map[string]any) bool { +func handleUnauthenticatedMessage(ctx context.Context, user *types.User, userMessage *map[string]any) bool { token, ok := (*userMessage)["token"].(string) - response := WsEventMessage{Type: WsEventType.Authentication} + response := types.WsEventMessage{Type: WsEventType.Authentication} if !ok { - response.Event = WsAuthMessage{ + response.Event = types.WsAuthMessage{ Success: false, Error: "no token in message", } @@ -102,9 +105,9 @@ func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage * return false } - userId, err := TokenValidateGetId(token) + userId, err := tokens.TokenValidateGetId(token) if err != nil { - response.Event = WsAuthMessage{ + response.Event = types.WsAuthMessage{ Success: false, Error: "invalid token", } @@ -112,9 +115,9 @@ func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage * return false } - userFromCache, err := CacheGetUserById(userId) + userFromCache, err := cache.CacheGetUserById(userId) if err != nil { - response.Event = WsAuthMessage{ + response.Event = types.WsAuthMessage{ Success: false, Error: "user not found", } @@ -125,7 +128,7 @@ func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage * userFromCache.WsConn = user.WsConn *user = *userFromCache - response.Event = WsAuthMessage{ + response.Event = types.WsAuthMessage{ Success: true, Error: "", } @@ -133,9 +136,9 @@ func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage * return true } -func closeConnection(user *User, ignoreCache bool) { +func closeConnection(user *types.User, ignoreCache bool) { if !ignoreCache { - CacheDeleteUser(user.Id) + cache.CacheDeleteUser(user.Id) } if user.WsConn != nil { user.WsConn.CloseNow()