Uploader/main.go

284 lines
6.7 KiB
Go
Raw Permalink Normal View History

package main
import (
2024-05-18 14:36:44 +02:00
"context"
"fmt"
"io"
"log"
"net/http"
"os"
2024-07-12 03:33:30 +02:00
"time"
"github.com/gin-gonic/gin"
2024-07-12 03:33:30 +02:00
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jaswdr/faker"
)
2024-07-12 03:33:30 +02:00
var dbpool *pgxpool.Pool
2024-06-03 19:44:53 +02:00
var uploadFolder string
2024-06-03 19:36:41 +02:00
func initUpload(c *gin.Context) {
fileName, err := io.ReadAll(c.Request.Body)
if err != nil {
c.JSON(http.StatusBadRequest, "Couldn't read html request body")
return
}
2024-07-12 03:33:30 +02:00
rows, _ := dbpool.Query(context.Background(), "select filepath from videos")
2024-06-03 19:36:41 +02:00
for rows.Next() {
var filepath string
err = rows.Scan(&filepath)
if err != nil {
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("initUpload: %v\n", err)
2024-06-03 19:36:41 +02:00
}
2024-06-03 19:44:53 +02:00
if filepath == fmt.Sprintf("%s/%s", uploadFolder, fileName) {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusForbidden, "File already exists")
return
}
}
err = rows.Err()
if err != nil {
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("initUpload: %v\n", err)
2024-06-03 19:36:41 +02:00
}
2024-07-12 03:33:30 +02:00
sqlStmt := `
DROP TABLE IF EXISTS chunks;
CREATE TABLE IF NOT EXISTS chunks
(
id integer,
fileName text,
chunk bytea
)
`
_, err = dbpool.Exec(context.Background(), sqlStmt)
if err != nil {
log.Panicf("initUpload: %v\n", err)
}
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusOK, "Upload can proceed")
}
2024-06-03 21:04:50 +02:00
func receiveChunk(c *gin.Context) {
2024-05-19 00:19:47 +02:00
chunk, err := io.ReadAll(c.Request.Body)
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusBadRequest, "Couldn't read html request body")
2024-05-18 14:36:44 +02:00
return
}
2024-07-12 03:33:30 +02:00
_, err = dbpool.Exec(context.Background(), "insert into chunks(id, fileName, chunk) values($1, $2, $3)", c.GetHeader("chunk-id"), c.GetHeader("file-name"), chunk)
2024-05-18 14:36:44 +02:00
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusInternalServerError, "")
2024-06-03 22:15:43 +02:00
log.Panicf("receiveChunk: %v\n", err)
2024-05-18 14:36:44 +02:00
}
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusOK, "Received chunk")
}
2024-06-03 19:36:41 +02:00
func finishUpload(c *gin.Context) {
2024-07-12 03:33:30 +02:00
allChunks := map[int][]byte{}
2024-05-19 00:19:47 +02:00
fileName, err := io.ReadAll(c.Request.Body)
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusBadRequest, "Couldn't read html request body")
return
}
2024-07-12 03:33:30 +02:00
time.Sleep(time.Second)
rows, _ := dbpool.Query(context.Background(), "select id, chunk from chunks where fileName like $1", fileName)
for rows.Next() {
var id int
var chunk []byte
err := rows.Scan(&id, &chunk)
if err != nil {
c.JSON(http.StatusInternalServerError, "")
log.Panicf("finishUpload: %v\n", err)
}
allChunks[id] = chunk
}
err = rows.Err()
if err != nil {
c.JSON(http.StatusInternalServerError, "")
log.Panicf("finishUpload: %v\n", err)
}
for i := 0; i < len(allChunks); i++ {
f, err := os.OpenFile(fmt.Sprintf("%s/%s", uploadFolder, fileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0640)
if err != nil {
c.JSON(http.StatusInternalServerError, "")
log.Panicf("finishUpload: %v\n", err)
}
if _, err := f.Write(allChunks[i]); err != nil {
c.JSON(http.StatusInternalServerError, "")
log.Panicf("finishUpload: %v\n", err)
}
if err := f.Close(); err != nil {
c.JSON(http.StatusInternalServerError, "")
log.Panicf("finishUpload: %v\n", err)
}
}
_, err = dbpool.Exec(context.Background(), "insert into videos(filepath) values($1)", fmt.Sprintf("%s/%s", uploadFolder, fileName))
2024-05-19 00:19:47 +02:00
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("finishUpload: %v\n", err)
2024-02-23 23:23:06 +01:00
}
2024-06-03 22:15:43 +02:00
c.JSON(http.StatusOK, "File uploaded successfully")
}
2024-05-19 00:19:47 +02:00
func listVideos(c *gin.Context) {
allVideos := map[int]string{}
2024-07-12 03:33:30 +02:00
rows, _ := dbpool.Query(context.Background(), "select * from videos")
2024-05-19 00:19:47 +02:00
for rows.Next() {
var id int
var filepath string
2024-06-11 00:18:41 +02:00
err := rows.Scan(&id, &filepath)
2024-05-19 00:19:47 +02:00
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("listVideos: %v\n", err)
}
allVideos[id] = filepath
}
2024-06-11 00:18:41 +02:00
err := rows.Err()
2024-05-19 00:19:47 +02:00
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("listVideos: %v\n", err)
}
2024-06-01 13:58:16 +02:00
2024-06-03 21:19:36 +02:00
c.JSON(http.StatusOK, allVideos)
}
2024-05-19 00:19:47 +02:00
func getVideo(c *gin.Context) {
2024-07-12 03:33:30 +02:00
rows, _ := dbpool.Query(context.Background(), "select filepath from videos where id = $1", c.Param("id"))
2024-06-01 13:58:16 +02:00
rows.Next()
2024-06-11 00:18:41 +02:00
err := rows.Err()
2024-06-01 13:58:16 +02:00
if err != nil {
2024-06-03 19:36:41 +02:00
c.JSON(http.StatusInternalServerError, "")
2024-06-03 21:19:36 +02:00
log.Panicf("getVideo: %v\n", err)
2024-06-01 13:58:16 +02:00
}
var filepath string
err = rows.Scan(&filepath)
2024-06-01 13:58:16 +02:00
if err != nil {
c.JSON(http.StatusBadRequest, "Video does not exist")
2024-06-03 21:19:36 +02:00
log.Panicf("getVideo: %v\n", err)
2024-06-01 13:58:16 +02:00
}
2024-06-03 22:15:43 +02:00
c.JSON(http.StatusOK, filepath)
2024-06-01 13:58:16 +02:00
}
func deleteVideo(c *gin.Context) {
2024-07-12 03:33:30 +02:00
rows, _ := dbpool.Query(context.Background(), "select filepath from videos where id = $1", c.Param("id"))
2024-06-01 13:58:16 +02:00
rows.Next()
2024-06-11 00:18:41 +02:00
err := rows.Err()
2024-06-01 13:58:16 +02:00
if err != nil {
c.JSON(http.StatusInternalServerError, "")
2024-06-03 22:15:43 +02:00
log.Panicf("deleteVideo: %v\n", err)
2024-05-19 00:19:47 +02:00
}
var filepath string
err = rows.Scan(&filepath)
2024-05-19 00:19:47 +02:00
if err != nil {
c.JSON(http.StatusBadRequest, "Video does not exist")
2024-06-03 21:19:36 +02:00
log.Panicf("deleteVideo: %v\n", err)
2024-06-01 13:58:16 +02:00
}
2024-07-12 03:33:30 +02:00
_, err = dbpool.Exec(context.Background(), "delete from videos where id = $1", c.Param("id"))
2024-06-01 13:58:16 +02:00
if err != nil {
c.JSON(http.StatusInternalServerError, "Id was likely invalid")
2024-06-03 21:19:36 +02:00
log.Panicf("deleteVideo: %v\n", err)
}
2024-06-01 13:58:16 +02:00
if err = os.Remove(filepath); err != nil {
c.JSON(http.StatusInternalServerError, "DB entry was deleted, but file likely doesn't exist")
2024-06-03 21:19:36 +02:00
log.Panicf("deleteVideo: %v\n", err)
2024-06-01 13:58:16 +02:00
}
2024-06-03 22:15:43 +02:00
c.JSON(http.StatusOK, "File deleted successfully")
}
2024-07-12 00:32:52 +02:00
func main() {
var err error
2024-07-12 03:33:30 +02:00
dbpool, err = pgxpool.New(context.Background(), "postgresql://postgres:postgres@172.18.0.3:5432/postgres")
2024-07-12 00:32:52 +02:00
if err != nil {
log.Fatal(err)
}
2024-07-12 03:33:30 +02:00
defer dbpool.Close()
2024-07-12 00:32:52 +02:00
sqlStmt := `
DROP TABLE IF EXISTS videos;
CREATE TABLE IF NOT EXISTS videos
(
id serial NOT NULL,
filepath text,
CONSTRAINT videos_pkey PRIMARY KEY (id)
)
`
2024-07-12 03:33:30 +02:00
_, err = dbpool.Exec(context.Background(), sqlStmt)
2024-07-12 00:32:52 +02:00
if err != nil {
log.Panicf("main: %v\n", err)
}
faker := faker.New()
for i := 0; i < 10; i++ {
2024-07-12 03:33:30 +02:00
_, err = dbpool.Exec(context.Background(), "insert into videos(filepath) values($1)", faker.File().AbsoluteFilePathForUnix(2))
2024-07-12 00:32:52 +02:00
if err != nil {
log.Panicf("main: %v\n", err)
}
}
currentDir, err := os.Getwd()
if err != nil {
log.Panicf("main: %v\n", err)
}
uploadFolder = fmt.Sprintf("%s/upload", currentDir)
if _, err := os.Stat(uploadFolder); err != nil {
if !os.IsNotExist(err) {
log.Panicf("main: %v\n", err)
}
if err := os.Mkdir(uploadFolder, 0750); err != nil {
log.Panicf("main: %v\n", err)
}
}
files, err := os.ReadDir(uploadFolder)
if err != nil {
panic(err)
}
if len(files) != 0 {
for _, file := range files {
if file.IsDir() {
continue
}
2024-07-12 03:33:30 +02:00
_, err = dbpool.Exec(context.Background(), "insert into videos(filepath) values($1)", fmt.Sprintf("%s/%s", uploadFolder, file.Name()))
2024-07-12 00:32:52 +02:00
if err != nil {
log.Panicf("main: %v\n", err)
}
}
}
router := gin.Default()
router.SetTrustedProxies(nil)
router.POST("/video/init", initUpload)
router.POST("/video/chunk", receiveChunk)
router.POST("/video/completed", finishUpload)
router.GET("/videos", listVideos)
router.GET("/videos/:id", getVideo)
router.DELETE("/videos/:id", deleteVideo)
router.Run("localhost:8080")
}