working file sharing
This commit is contained in:
@@ -7,7 +7,7 @@ const (
|
||||
FileStorageBucketName string = "communicator"
|
||||
MaxPostBytes uint32 = 4 << 10
|
||||
MaxPostWithFileBytes uint32 = 1 << 30
|
||||
FileProcessingPartSize uint64 = 24 << 10
|
||||
FileProcessingPartSize uint64 = 12 << 20
|
||||
FileProcessingThreads uint = 3
|
||||
FileDownloadLinkTtl time.Duration = 24 * time.Hour
|
||||
)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package http
|
||||
package httpRequest
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"maps"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-socket/packages/Enums/ConnectionState"
|
||||
@@ -43,11 +44,18 @@ func HandleDm(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
msgContent := request.FormValue("msgContent")
|
||||
if msgContent == "" {
|
||||
attachedFile := request.FormValue("attachedFile")
|
||||
|
||||
if msgContent == "" && attachedFile == "" {
|
||||
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if attachedFile != "" && !strings.HasPrefix(attachedFile, targetConnection.String()+"/") {
|
||||
http.Error(response, "invalid attachedFile", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var target *types.User
|
||||
|
||||
if user.Id == conn.RequestorId {
|
||||
@@ -64,11 +72,12 @@ func HandleDm(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
message := &types.Message{
|
||||
Id: uuid.New(),
|
||||
Content: msgContent,
|
||||
CreatedAt: time.Now(),
|
||||
Sender: user.Id,
|
||||
Receiver: conn.Id,
|
||||
Id: uuid.New(),
|
||||
Content: msgContent,
|
||||
AttachedFile: attachedFile,
|
||||
CreatedAt: time.Now(),
|
||||
Sender: user.Id,
|
||||
Receiver: conn.Id,
|
||||
}
|
||||
|
||||
wsServer.WsSendMessageCloseIfTimeout(target, types.WsEventMessage{
|
||||
@@ -1,12 +1,12 @@
|
||||
package http
|
||||
package httpRequest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go-socket/packages/convertions"
|
||||
"go-socket/packages/globals"
|
||||
"go-socket/packages/minio"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func HandleFileUpload(response http.ResponseWriter, request *http.Request) {
|
||||
@@ -47,17 +47,54 @@ func HandleFileUpload(response http.ResponseWriter, request *http.Request) {
|
||||
defer file.Close()
|
||||
|
||||
contentType := header.Header.Get("Content-Type")
|
||||
key := minio.GetKey(connectionId, contentType)
|
||||
|
||||
key :=
|
||||
|
||||
if err = minio.Upload(ctx, fileId.String(), file, header.Size, contentType, map[string]string{
|
||||
"orginalName": header.Filename,
|
||||
"uploaderId": user.Id.String(),
|
||||
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
|
||||
"originalName": header.Filename,
|
||||
"uploaderId": user.Id.String(),
|
||||
}); err != nil {
|
||||
http.Error(response, "upload failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
response.Write([]byte(fileId.String()))
|
||||
response.WriteHeader(http.StatusCreated)
|
||||
response.Write([]byte(key))
|
||||
}
|
||||
|
||||
func HandleFileDownload(response http.ResponseWriter, request *http.Request) {
|
||||
if !postValidCheckWithResponseOnFail(&response, request, false) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
|
||||
user, err := getUserByToken(ctx, request.Header.Get("token"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
connectionId, err := convertions.ConvertStringUuid(request.FormValue("connectionid"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if _, ok := user.Connections[connectionId]; !ok {
|
||||
http.Error(response, "no such connection", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
key := request.FormValue("key")
|
||||
if !strings.HasPrefix(key, connectionId.String()+"/") {
|
||||
http.Error(response, "no such file", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
url, err := minio.GetDownloadUrl(ctx, key)
|
||||
if err != nil {
|
||||
http.Error(response, "no such file", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteHeader(http.StatusOK)
|
||||
response.Write([]byte(url.String()))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package http
|
||||
package httpRequest
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -1,4 +1,4 @@
|
||||
package http
|
||||
package httpRequest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -1,4 +1,4 @@
|
||||
package http
|
||||
package httpRequest
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
@@ -26,7 +26,7 @@ func HandleUserNewToken(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
password := request.FormValue("passwords")
|
||||
password := request.FormValue("password")
|
||||
|
||||
if len(password) < 8 {
|
||||
http.Error(response, "no or short passwords", http.StatusBadRequest)
|
||||
@@ -85,7 +85,7 @@ func HandleUserNew(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
password := request.FormValue("passwords")
|
||||
password := request.FormValue("password")
|
||||
if len(password) < 8 {
|
||||
http.Error(response, "no or short passwords", http.StatusBadRequest)
|
||||
return
|
||||
+13
-25
@@ -5,42 +5,27 @@ import (
|
||||
"io"
|
||||
"mime"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go-socket/packages/globals"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
)
|
||||
|
||||
var minClient *minio.Client
|
||||
|
||||
var canonicalExt = map[string]string{
|
||||
"image/jpeg": ".jpg",
|
||||
"image/png": ".png",
|
||||
"image/gif": ".gif",
|
||||
"image/webp": ".webp",
|
||||
"video/mp4": ".mp4",
|
||||
"application/pdf": ".pdf",
|
||||
}
|
||||
|
||||
func extensionFromContentType(ct string) string {
|
||||
if ext, ok := canonicalExt[ct]; ok {
|
||||
return ext
|
||||
func GetKey(connectionId uuid.UUID, mimeType string) string {
|
||||
extensions, err := mime.ExtensionsByType(mimeType)
|
||||
if err != nil || len(extensions) == 0 {
|
||||
extensions = []string{".unknown"}
|
||||
}
|
||||
exts, err := mime.ExtensionsByType(ct)
|
||||
if err != nil || len(exts) == 0 {
|
||||
return ".unk"
|
||||
}
|
||||
return exts[0]
|
||||
return connectionId.String() + "/" + strconv.FormatInt(time.Now().UnixMilli(), 10) + extensions[0]
|
||||
}
|
||||
|
||||
func GetKey(hash string, contentType string) string {
|
||||
return hash + extensionFromContentType(contentType)
|
||||
}
|
||||
|
||||
func Init() {
|
||||
ctx := context.Background()
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
var err error
|
||||
minClient, err = minio.New("localhost:9000", &minio.Options{
|
||||
Creds: credentials.NewStaticV4("root", "change_to_env", ""),
|
||||
@@ -58,7 +43,10 @@ func Init() {
|
||||
if !exists {
|
||||
err = minClient.MakeBucket(ctx, globals.FileStorageBucketName, minio.MakeBucketOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
exists, checkErr := minClient.BucketExists(ctx, globals.FileStorageBucketName)
|
||||
if checkErr != nil || !exists {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@ func Init(ctx context.Context) {
|
||||
sender_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
receiver_id UUID NOT NULL REFERENCES user_connections(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
content TEXT NOT NULL
|
||||
content TEXT NOT NULL,
|
||||
attached_file TEXT NOT NULL DEFAULT ''
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -182,21 +183,21 @@ func ConnectionUpdateState(ctx context.Context, conn *types.Connection) error {
|
||||
func ConnectionMessageSave(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)
|
||||
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content)
|
||||
INSERT INTO direct_messages (id, sender_id, receiver_id, created_at, content, attached_file) VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile)
|
||||
return err
|
||||
}
|
||||
return dbConn.QueryRow(ctx, `
|
||||
INSERT INTO direct_messages (sender_id, receiver_id, created_at, content) VALUES ($1, $2, $3, $4)
|
||||
INSERT INTO direct_messages (sender_id, receiver_id, created_at, content, attached_file) VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id
|
||||
`, message.Sender, message.Receiver, message.CreatedAt, message.Content).Scan(&message.Id)
|
||||
`, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile).Scan(&message.Id)
|
||||
}
|
||||
|
||||
func ConnectionGetMessagesBefore(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
|
||||
SELECT id, sender_id, receiver_id, created_at, content, attached_file
|
||||
FROM (
|
||||
SELECT id, sender_id, receiver_id, created_at, content
|
||||
SELECT id, sender_id, receiver_id, created_at, content, attached_file
|
||||
FROM direct_messages
|
||||
WHERE receiver_id = $1
|
||||
AND created_at < $2
|
||||
@@ -213,7 +214,7 @@ func ConnectionGetMessagesBefore(ctx context.Context, before time.Time, connecti
|
||||
messages := make([]*types.Message, 0, cap)
|
||||
for rows.Next() {
|
||||
msg := &types.Message{}
|
||||
if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content); err != nil {
|
||||
if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content, &msg.AttachedFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages = append(messages, msg)
|
||||
|
||||
@@ -82,12 +82,12 @@ type ConnectionElevationData struct {
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Id uuid.UUID `json:"id"`
|
||||
AttachedMedia string `json:"attachedMedia"`
|
||||
Content string `json:"content"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Sender uuid.UUID `json:"sender"`
|
||||
Receiver uuid.UUID `json:"receiver"`
|
||||
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 {
|
||||
@@ -96,7 +96,7 @@ type LoginReturn struct {
|
||||
}
|
||||
|
||||
type WsEventMessage struct {
|
||||
Type WsEventType.WsEventType `json:"types"`
|
||||
Type WsEventType.WsEventType `json:"type"`
|
||||
Event any `json:"event"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user