From 9062e48450483ce2046bb899d481d3ed472bf9d5 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Jony Date: Mon, 30 Oct 2023 01:23:51 +0600 Subject: [PATCH] # Add file upload and download endpoints --- api.go | 249 +++++++++++++++++++++++++--- awazz.go | 15 +- go.mod | 3 +- go.sum | 7 +- internal/model/file.go | 113 +++++++++++++ internal/model/file.pb.go | 334 ++++++++++++++++++++++++++++++++++++++ internal/model/file.proto | 25 +++ internal/model/token.go | 3 +- 8 files changed, 715 insertions(+), 34 deletions(-) create mode 100644 internal/model/file.go create mode 100644 internal/model/file.pb.go create mode 100644 internal/model/file.proto diff --git a/api.go b/api.go index f8f118d..8c9c3e4 100644 --- a/api.go +++ b/api.go @@ -5,11 +5,15 @@ import ( "errors" "fmt" "log" + "net/http" + "os" + "path/filepath" "time" "github.com/SohelAhmedJoni/Awazz-Backend/internal/durable" "github.com/SohelAhmedJoni/Awazz-Backend/internal/middlewares" "github.com/SohelAhmedJoni/Awazz-Backend/internal/model" + "github.com/SohelAhmedJoni/Awazz-Backend/pkg" "github.com/davecgh/go-spew/spew" "github.com/gin-gonic/gin" "google.golang.org/protobuf/proto" @@ -32,7 +36,7 @@ func check_login(c *gin.Context) error { // UserId is missing, return 401 return errors.New("missing Anon-User") } - ldb, err := durable.LeveldbCreateDatabase("Database/", "Token", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "Token", "/") if err != nil { return err } @@ -86,7 +90,7 @@ func login(c *gin.Context) { return } // check if user exists - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -109,7 +113,7 @@ func login(c *gin.Context) { } ldb.Close() - ldb, err = durable.LeveldbCreateDatabase("Database/", "Token", "/") + ldb, err = durable.LevelDBCreateDatabase("Database/", "Token", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -171,7 +175,7 @@ func register(c *gin.Context) { } // check if user exists - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -222,7 +226,7 @@ func getPost(c *gin.Context) { // c.JSON(500, gin.H{"error": err.Error()}) // return // } - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -261,7 +265,7 @@ func savePost(c *gin.Context) { c.JSON(500, gin.H{"error": err.Error()}) return } - lbd, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + lbd, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -292,7 +296,7 @@ func getPerson(c *gin.Context) { // return // } //! spew.Dump(p) - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -348,7 +352,7 @@ func savePerson(c *gin.Context) { person.Liked = c.QueryArray("Liked") // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -385,7 +389,7 @@ func saveCommunity(c *gin.Context) { spew.Dump(community) // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -436,7 +440,7 @@ func getCommunity(c *gin.Context) { cid := c.Query("id") //! println("pid: " + pid) // err := p.GetCommunity(cid) - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -495,7 +499,7 @@ func saveInstance(c *gin.Context) { p.Tags = c.QueryArray("Tags") // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -522,7 +526,7 @@ func getInstance(c *gin.Context) { Iid := c.Query("Id") //! println("pid: " + pid) // err := p.GetCommunity(Iid) - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -626,7 +630,7 @@ func saveMessage(c *gin.Context) { } // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -650,7 +654,7 @@ func getMessage(c *gin.Context) { var p model.Messages msg_id := c.Query("MsgId") - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -699,7 +703,7 @@ func saveNotification(c *gin.Context) { } // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -723,7 +727,7 @@ func getNotification(c *gin.Context) { var p model.Notifications notification_id := c.Query("NotificationId") - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -772,7 +776,7 @@ func saveFollower(c *gin.Context) { } // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -796,7 +800,7 @@ func getFollower(c *gin.Context) { var p model.Follower user_id := c.Query("UserId") - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -844,7 +848,7 @@ func saveFollowee(c *gin.Context) { } // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -868,7 +872,7 @@ func getFollowee(c *gin.Context) { p := model.Followee{} user_id := c.Query("UserId") - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -917,7 +921,7 @@ func saveLikes(c *gin.Context) { } // CREATING LEVELDB DATABASE - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { panic(err) } @@ -941,7 +945,7 @@ func getLikes(c *gin.Context) { } p := model.Likes{} - ldb, err := durable.LeveldbCreateDatabase("Database/", "NOSQL", "/") + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") if err != nil { c.JSON(500, gin.H{"error": err.Error()}) return @@ -956,3 +960,204 @@ func getLikes(c *gin.Context) { ldb.Close() c.JSON(200, p) } +func UploadFile(c *gin.Context) { + /* + UploadFile function handles the upload of a single file. + It gets the file from the form data, saves it to the defined path, + generates a unique identifier for the file, saves the file metadata to the database, + and returns a success message and the file metadata. + */ + // Get the file from the form data + file, err := c.FormFile("file") + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + uuid := pkg.GetUlid() + dir := filepath.Join("Database", "assets") + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0755); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file directory"}) + return + } + } + // Define the path where the file will be saved + filePath := filepath.Join(dir, uuid) + // Save the file to the defined path + if err := c.SaveUploadedFile(file, filePath); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"}) + return + } + + // Save file metadata to database + fileMetadata := model.File{ + Uuid: uuid, + Name: file.Filename, + CreatedAt: time.Now().Unix(), + UpdatedAt: 0, + Hash: pkg.FileHashGeneration(filePath), + MimeType: file.Header.Get("Content-Type"), + Ext: filepath.Ext(file.Filename), + } + err = fileMetadata.Save() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file metadata"}) + return + } + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file directory"}) + return + } + defer ldb.Close() + blob, err := proto.Marshal(&fileMetadata) + if err != nil { + log.Print(err) + } + + err = ldb.Put([]byte(fmt.Sprintf("file_%v", fileMetadata.Uuid)), blob, nil) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file metadata"}) + return + } + ldb.Close() + + // Return a success message and the file metadata + c.JSON(http.StatusOK, gin.H{"message": "File uploaded successfully", "Details": fileMetadata}) +} + +func UploadFiles(c *gin.Context) { + /* + UploadFiles function handles the upload of multiple files. + It gets the files from the form data, saves each file to the defined path, + generates a unique identifier for each file, saves the file metadata to the database, + and returns a success message and the file metadata. + */ + // Get the files from the form data + form, err := c.MultipartForm() + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + files := form.File["files"] + var fileMetadata model.FileList + // Save each file to the defined path and generate a unique identifier for each file + dir := filepath.Join("Database", "assets") + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0755); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file directory"}) + return + } + } + for i, file := range files { + filePath := filepath.Join(dir, file.Filename) + if err := c.SaveUploadedFile(file, filePath); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"}) + return + } + fileMetadata.Files[i] = &model.File{ + Uuid: pkg.GetUlid(), + Name: file.Filename, + CreatedAt: time.Now().Unix(), + UpdatedAt: 0, + Hash: pkg.FileHashGeneration(filePath), + MimeType: file.Header.Get("Content-Type"), + Ext: filepath.Ext(file.Filename), + } + // Save file metadata to database + fileMetadata.Files[i].Save() + } + c.JSON(http.StatusOK, gin.H{"message": "Files uploaded successfully", "Details": fileMetadata}) +} + +// DownloadFile function handles the download of a single file. +// It gets the file metadata from the database, gets the file from the defined path, +// and returns the file. +func DownloadFile(c *gin.Context) { + /* + GetFile function retrieves a file from the server. + It gets the unique identifier of the file to be retrieved, + retrieves the file metadata from the database, + defines the path of the file to be retrieved, + opens the file, reads the first 512 bytes of the file to determine its content type, + gets the file info, sets the headers for the file transfer, and returns the file. + */ + // Get the unique identifier of the file to be retrieved + ulid := c.Query("id") + var file model.File + // Retrieve the file metadata from the database + ldb, err := durable.LevelDBCreateDatabase("Database/", "NOSQL", "/") + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create file directory"}) + return + } + defer ldb.Close() + blob, err := ldb.Get([]byte(fmt.Sprintf("file_%v", ulid)), nil) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file metadata" + err.Error() + ulid}) + return + } + err = proto.Unmarshal(blob, &file) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file metadata" + err.Error() + ulid}) + return + } + + // Define the path of the file to be retrieved + filePath := filepath.Join("Database", "assets", file.GetUuid()) + // redirect to file + c.Redirect(http.StatusMovedPermanently, filePath) + +} + +// DownloadFiles function handles the download of multiple files. +// It gets the file metadata from the database, gets the files from the defined path, +// and returns the files. +// func DownloadFiles(c *gin.Context) { +// /* +// GetFiles function retrieves multiple files from the server. +// It gets the unique identifiers of the files to be retrieved, +// retrieves the file metadata from the database, +// defines the path of the files to be retrieved, +// opens the files, reads the first 512 bytes of the files to determine their content type, +// gets the files info, sets the headers for the files transfer, and returns the files. +// */ +// // Get the unique identifiers of the files to be retrieved +// ulids := c.QueryArray("ulids") +// var fileMetadata model.FileList +// // Retrieve the file metadata from the database +// fileMetadata.Get(ulids) +// // Define the path of the files to be retrieved +// dir := filepath.Join("Database", "assets") +// // Open the files +// for _, file := range fileMetadata.Files { +// filePath := filepath.Join(dir, file.Name) +// fileData, err := os.Open(filePath) +// if err != nil { +// c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open file"}) +// return +// } +// defer fileData.Close() +// // Read the first 512 bytes of the files to determine their content type +// fileHeader := make([]byte, 512) +// _, err = fileData.Read(fileHeader) +// if err != nil { +// c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file"}) +// return +// } +// // Get the files info +// fileInfo, err := fileData.Stat() +// if err != nil { +// c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file info"}) +// return +// } +// // Set the headers for the files transfer and return the files +// c.Header("Content-Description", "File Transfer") +// c.Header("Content-Transfer-Encoding", "binary") +// c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", file.Name)) +// c.Header("Content-Type", file.MimeType) +// c.Header("Content-Length", fmt.Sprintf("%d", fileInfo.Size())) +// fileData.Close() +// c.File(filePath) +// } +// } diff --git a/awazz.go b/awazz.go index 264baba..2162ef5 100644 --- a/awazz.go +++ b/awazz.go @@ -1,13 +1,10 @@ package main -// "github.com/SohelAhmedJoni/Awazz-Backend/internal/model" +import "github.com/gin-gonic/gin" -import ( - "github.com/gin-gonic/gin" -) +// "github.com/SohelAhmedJoni/Awazz-Backend/internal/model" func main() { - r := gin.Default() r.GET("/post", getPost) r.POST("/post", savePost) @@ -31,9 +28,11 @@ func main() { r.GET("/likes", getLikes) r.GET("/login", login) r.POST("/register", register) - - // r.GET("/login", getMessage) - // r.POST("/register", saveMessage) + r.POST("/upload", UploadFile) + r.GET("/download", DownloadFile) + r.POST("/uploads", UploadFiles) + r.Static("/Database/assets/", "./Database/assets/") + // r.GET("/downloads", DownloadFiles) r.Run(":9091") } diff --git a/go.mod b/go.mod index 2475e9f..ed281fe 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,11 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/gin-gonic/gin v1.9.1 github.com/glebarez/go-sqlite v1.21.2 - github.com/mr-tron/base58 v1.2.0 + github.com/oklog/ulid/v2 v2.1.0 github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.0 golang.org/x/crypto v0.9.0 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d google.golang.org/protobuf v1.31.0 ) diff --git a/go.sum b/go.sum index 5f51dcf..f40f712 100644 --- a/go.sum +++ b/go.sum @@ -56,13 +56,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= -github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= +github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -93,6 +94,8 @@ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= diff --git a/internal/model/file.go b/internal/model/file.go new file mode 100644 index 0000000..1f68fa1 --- /dev/null +++ b/internal/model/file.go @@ -0,0 +1,113 @@ +package model + +import ( + "fmt" + + "github.com/SohelAhmedJoni/Awazz-Backend/internal/durable" +) + +func (s *File) Save() error { + db, err := durable.CreateDatabase("./Database/", "Common", "Shard_0.sqlite") + if err != nil { + panic(err) + } + defer db.Close() + str := `CREATE TABLE IF NOT EXISTS FILE( + ULID VARCHAR(128) PRIMARY KEY, + Name TEXT NOT NULL, + CreatedAt INTEGER NOT NULL, + UpdatedAt INTEGER, + Hash TEXT NOT NULL, + HashType TEXT NOT NULL, + MimeType TEXT NOT NULL, + Ext TEXT NOT NULL + )` + _, err = db.Exec(str) + if err != nil { + panic(err) + } + + statement, err := db.Prepare("INSERT INTO FILE (ULID,Name,CreatedAt,UpdatedAt,Hash,HashType,MimeType,Ext) VALUES (?,?,?,?,?,?,?,?)") + + if err != nil { + panic(err) + } + + _, err = statement.Exec(s.Uuid, s.Name, s.CreatedAt, s.UpdatedAt, s.Hash, s.HashType, s.MimeType, s.Ext) + if err != nil { + panic(err) + } + return nil +} + +func (g *File) Get(ULID string) error { + db, err := durable.CreateDatabase("./Database/", "Common", "Shard_0.sqlite") + if err != nil { + panic(err) + } + defer db.Close() + + rows, err := db.Query("SELECT * from FILE where ULID = ?", ULID) + if err != nil { + panic(err) + } + defer rows.Close() + + for rows.Next() { + err = rows.Scan(&g.Uuid, &g.Name, &g.CreatedAt, &g.UpdatedAt, &g.Hash, &g.HashType, &g.MimeType, &g.Ext) + if err != nil { + panic(err) + } + } + + err = rows.Err() + if err != nil { + panic(err) + } + + return nil +} + +func (d *File) Delete(ULID string) error { + db, err := durable.CreateDatabase("./Database/", "Common", "Shard_0.sqlite") + if err != nil { + panic(err) + } + defer db.Close() + + _, err = db.Exec("DELETE FROM FILE WHERE ULID= ?", ULID) + + if err != nil { + panic(err) + } + return nil +} + +func (u *FileList) Get(ULIDS []string) error { + db, err := durable.CreateDatabase("./Database/", "Common", "Shard_0.sqlite") + if err != nil { + panic(err) + } + defer db.Close() + + for _, ULID := range ULIDS { + var g File + rows, err := db.Query(fmt.Sprintf("SELECT * from FILE where ULID = %v", ULID)) + if err != nil { + panic(err) + } + defer rows.Close() + rows.Next() + err = rows.Scan(g.Uuid, g.Name, g.CreatedAt, g.UpdatedAt, g.Hash, g.HashType, g.MimeType, g.Ext) + if err != nil { + panic(err) + } + u.Files = append(u.Files, &g) + err = rows.Err() + if err != nil { + panic(err) + } + } + + return nil +} diff --git a/internal/model/file.pb.go b/internal/model/file.pb.go new file mode 100644 index 0000000..944bb30 --- /dev/null +++ b/internal/model/file.pb.go @@ -0,0 +1,334 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0-devel +// protoc v3.14.0 +// source: file.proto + +package model + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type File struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + CreatedAt int64 `protobuf:"varint,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt int64 `protobuf:"varint,4,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + Hash string `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"` + HashType string `protobuf:"bytes,6,opt,name=hash_type,json=hashType,proto3" json:"hash_type,omitempty"` + MimeType string `protobuf:"bytes,7,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` + Ext string `protobuf:"bytes,8,opt,name=ext,proto3" json:"ext,omitempty"` +} + +func (x *File) Reset() { + *x = File{} + if protoimpl.UnsafeEnabled { + mi := &file_file_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *File) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File) ProtoMessage() {} + +func (x *File) ProtoReflect() protoreflect.Message { + mi := &file_file_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File.ProtoReflect.Descriptor instead. +func (*File) Descriptor() ([]byte, []int) { + return file_file_proto_rawDescGZIP(), []int{0} +} + +func (x *File) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *File) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *File) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *File) GetUpdatedAt() int64 { + if x != nil { + return x.UpdatedAt + } + return 0 +} + +func (x *File) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *File) GetHashType() string { + if x != nil { + return x.HashType + } + return "" +} + +func (x *File) GetMimeType() string { + if x != nil { + return x.MimeType + } + return "" +} + +func (x *File) GetExt() string { + if x != nil { + return x.Ext + } + return "" +} + +type FileList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Files []*File `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"` +} + +func (x *FileList) Reset() { + *x = FileList{} + if protoimpl.UnsafeEnabled { + mi := &file_file_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FileList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileList) ProtoMessage() {} + +func (x *FileList) ProtoReflect() protoreflect.Message { + mi := &file_file_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileList.ProtoReflect.Descriptor instead. +func (*FileList) Descriptor() ([]byte, []int) { + return file_file_proto_rawDescGZIP(), []int{1} +} + +func (x *FileList) GetFiles() []*File { + if x != nil { + return x.Files + } + return nil +} + +type File_FileData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *File_FileData) Reset() { + *x = File_FileData{} + if protoimpl.UnsafeEnabled { + mi := &file_file_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *File_FileData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File_FileData) ProtoMessage() {} + +func (x *File_FileData) ProtoReflect() protoreflect.Message { + mi := &file_file_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File_FileData.ProtoReflect.Descriptor instead. +func (*File_FileData) Descriptor() ([]byte, []int) { + return file_file_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *File_FileData) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +var File_file_proto protoreflect.FileDescriptor + +var file_file_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x22, 0xec, 0x01, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x61, 0x73, 0x68, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, + 0x78, 0x74, 0x1a, 0x1e, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x22, 0x2d, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x21, + 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_file_proto_rawDescOnce sync.Once + file_file_proto_rawDescData = file_file_proto_rawDesc +) + +func file_file_proto_rawDescGZIP() []byte { + file_file_proto_rawDescOnce.Do(func() { + file_file_proto_rawDescData = protoimpl.X.CompressGZIP(file_file_proto_rawDescData) + }) + return file_file_proto_rawDescData +} + +var file_file_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_file_proto_goTypes = []interface{}{ + (*File)(nil), // 0: model.File + (*FileList)(nil), // 1: model.FileList + (*File_FileData)(nil), // 2: model.File.FileData +} +var file_file_proto_depIdxs = []int32{ + 0, // 0: model.FileList.files:type_name -> model.File + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_file_proto_init() } +func file_file_proto_init() { + if File_file_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_file_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*File); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_file_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FileList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_file_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*File_FileData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_file_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_file_proto_goTypes, + DependencyIndexes: file_file_proto_depIdxs, + MessageInfos: file_file_proto_msgTypes, + }.Build() + File_file_proto = out.File + file_file_proto_rawDesc = nil + file_file_proto_goTypes = nil + file_file_proto_depIdxs = nil +} diff --git a/internal/model/file.proto b/internal/model/file.proto new file mode 100644 index 0000000..5d62e21 --- /dev/null +++ b/internal/model/file.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package model; +option go_package = ".;model"; + +message File{ + string uuid = 1; + string name = 2; + int64 created_at = 3; + int64 updated_at = 4; + string hash = 5; + string hash_type = 6; + string mime_type = 7; + string ext = 8; + + message FileData{ + bytes data = 1; + } +} + + + +message FileList{ + repeated File files = 1; +} diff --git a/internal/model/token.go b/internal/model/token.go index 8edfb7a..335c3c6 100644 --- a/internal/model/token.go +++ b/internal/model/token.go @@ -24,8 +24,9 @@ func (s *Token) SaveToken() error { panic(err) } - statement, err := db.Prepare("INSERT INTO TOKEN (UserName, Token, GenerateTime) VALUES (?,?,?)") + // check if user already exist + statement, err := db.Prepare("INSERT OR REPLACE INTO TOKEN (UserName, Token, GenerateTime) VALUES (?,?,?)") if err != nil { panic(err) }