2021-09-26 02:35:02 +00:00
package v1
import (
2023-03-13 01:42:18 +00:00
"encoding/json"
2022-08-15 03:37:21 +00:00
"fmt"
2021-09-26 02:35:02 +00:00
"io"
"io/ioutil"
2022-06-08 10:19:45 +00:00
"log"
2021-09-26 02:35:02 +00:00
"net/http"
2022-06-08 10:19:45 +00:00
"net/url"
2022-04-06 04:10:51 +00:00
url2 "net/url"
2021-09-26 02:35:02 +00:00
"os"
"path"
2022-06-08 10:19:45 +00:00
"path/filepath"
2022-03-09 08:37:03 +00:00
"strconv"
2022-02-17 10:43:25 +00:00
"strings"
2022-06-08 11:31:01 +00:00
"sync"
2023-03-06 08:10:19 +00:00
"time"
2021-10-15 03:43:41 +00:00
2022-11-29 17:17:14 +00:00
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
2021-10-15 03:43:41 +00:00
"github.com/IceWhaleTech/CasaOS/model"
2023-03-13 01:42:18 +00:00
"github.com/gorilla/websocket"
"github.com/robfig/cron/v3"
"github.com/tidwall/gjson"
2023-02-02 03:36:59 +00:00
2022-06-29 03:09:58 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
2021-10-15 03:43:41 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service"
2023-03-13 01:42:18 +00:00
model2 "github.com/IceWhaleTech/CasaOS/service/model"
2023-02-02 03:36:59 +00:00
2021-10-15 03:43:41 +00:00
"github.com/gin-gonic/gin"
2022-06-08 10:19:45 +00:00
uuid "github.com/satori/go.uuid"
2022-10-20 06:25:26 +00:00
"go.uber.org/zap"
2023-02-06 09:43:40 +00:00
"github.com/h2non/filetype"
2021-09-26 02:35:02 +00:00
)
2023-03-06 08:10:19 +00:00
type ListReq struct {
model . PageReq
Path string ` json:"path" form:"path" `
//Refresh bool `json:"refresh"`
}
type ObjResp struct {
Name string ` json:"name" `
Size int64 ` json:"size" `
IsDir bool ` json:"is_dir" `
Modified time . Time ` json:"modified" `
Sign string ` json:"sign" `
Thumb string ` json:"thumb" `
Type int ` json:"type" `
Path string ` json:"path" `
Date time . Time ` json:"date" `
Extensions map [ string ] interface { } ` json:"extensions" `
}
type FsListResp struct {
Content [ ] ObjResp ` json:"content" `
Total int64 ` json:"total" `
Readme string ` json:"readme,omitempty" `
Write bool ` json:"write,omitempty" `
Provider string ` json:"provider,omitempty" `
Index int ` json:"index" `
Size int ` json:"size" `
}
2023-03-13 01:42:18 +00:00
var (
// 升级成 WebSocket 协议
upgraderFile = websocket . Upgrader {
// 允许CORS跨域请求
CheckOrigin : func ( r * http . Request ) bool {
return true
} ,
}
conn * websocket . Conn
err error
)
2021-09-26 02:35:02 +00:00
// @Summary 读取文件
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "路径"
// @Success 200 {string} string "ok"
// @Router /file/read [get]
func GetFilerContent ( c * gin . Context ) {
filePath := c . Query ( "path" )
if len ( filePath ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . INVALID_PARAMS ,
Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) ,
2021-09-26 02:35:02 +00:00
} )
return
}
if ! file . Exists ( filePath ) {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . FILE_DOES_NOT_EXIST ,
Message : common_err . GetMsg ( common_err . FILE_DOES_NOT_EXIST ) ,
2021-09-26 02:35:02 +00:00
} )
return
}
2022-10-20 06:25:26 +00:00
// 文件读取任务是将文件内容读取到内存中。
2021-09-26 02:35:02 +00:00
info , err := ioutil . ReadFile ( filePath )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . FILE_READ_ERROR ,
Message : common_err . GetMsg ( common_err . FILE_READ_ERROR ) ,
2021-09-26 02:35:02 +00:00
Data : err . Error ( ) ,
} )
return
}
result := string ( info )
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . SUCCESS ,
Message : common_err . GetMsg ( common_err . SUCCESS ) ,
2021-09-26 02:35:02 +00:00
Data : result ,
} )
}
func GetLocalFile ( c * gin . Context ) {
path := c . Query ( "path" )
if len ( path ) == 0 {
c . JSON ( http . StatusOK , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . INVALID_PARAMS ,
Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) ,
2021-09-26 02:35:02 +00:00
} )
return
}
if ! file . Exists ( path ) {
c . JSON ( http . StatusOK , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . FILE_DOES_NOT_EXIST ,
Message : common_err . GetMsg ( common_err . FILE_DOES_NOT_EXIST ) ,
2021-09-26 02:35:02 +00:00
} )
return
}
c . File ( path )
}
2022-02-17 10:43:25 +00:00
// @Summary download
2021-09-26 02:35:02 +00:00
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
2022-07-22 03:02:11 +00:00
// @Param format query string false "Compression format" Enums(zip,tar,targz)
2022-06-08 10:19:45 +00:00
// @Param files query string true "file list eg: filename1,filename2,filename3 "
2021-09-26 02:35:02 +00:00
// @Success 200 {string} string "ok"
// @Router /file/download [get]
func GetDownloadFile ( c * gin . Context ) {
2022-07-22 03:02:11 +00:00
t := c . Query ( "format" )
2022-06-08 10:19:45 +00:00
files := c . Query ( "files" )
if len ( files ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . INVALID_PARAMS ,
Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) ,
2021-09-26 02:35:02 +00:00
} )
return
}
2022-06-08 10:19:45 +00:00
list := strings . Split ( files , "," )
for _ , v := range list {
if ! file . Exists ( v ) {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . FILE_DOES_NOT_EXIST ,
Message : common_err . GetMsg ( common_err . FILE_DOES_NOT_EXIST ) ,
2022-06-08 10:19:45 +00:00
} )
return
}
2021-09-26 02:35:02 +00:00
}
c . Header ( "Content-Type" , "application/octet-stream" )
c . Header ( "Content-Transfer-Encoding" , "binary" )
c . Header ( "Cache-Control" , "no-cache" )
2022-06-08 10:19:45 +00:00
// handles only single files not folders and multiple files
if len ( list ) == 1 {
2021-09-26 02:35:02 +00:00
2022-06-08 10:19:45 +00:00
filePath := list [ 0 ]
info , err := os . Stat ( filePath )
if err != nil {
c . JSON ( http . StatusOK , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . FILE_DOES_NOT_EXIST ,
Message : common_err . GetMsg ( common_err . FILE_DOES_NOT_EXIST ) ,
2022-06-08 10:19:45 +00:00
} )
return
}
if ! info . IsDir ( ) {
2021-09-26 02:35:02 +00:00
2022-10-20 06:25:26 +00:00
// 打开文件
2022-06-08 10:19:45 +00:00
fileTmp , _ := os . Open ( filePath )
defer fileTmp . Close ( )
2022-10-20 06:25:26 +00:00
// 获取文件的名称
2022-06-08 10:19:45 +00:00
fileName := path . Base ( filePath )
c . Header ( "Content-Disposition" , "attachment; filename*=utf-8''" + url2 . PathEscape ( fileName ) )
c . File ( filePath )
return
}
}
extension , ar , err := file . GetCompressionAlgorithm ( t )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result {
2022-06-29 03:09:58 +00:00
Success : common_err . INVALID_PARAMS ,
Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) ,
2022-04-06 04:10:51 +00:00
} )
return
}
2022-06-08 10:19:45 +00:00
err = ar . Create ( c . Writer )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result {
Success : common_err . SERVICE_ERROR ,
Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) ,
2022-06-08 10:19:45 +00:00
Data : err . Error ( ) ,
2022-04-06 04:10:51 +00:00
} )
return
}
2022-06-08 10:19:45 +00:00
defer ar . Close ( )
commonDir := file . CommonPrefix ( filepath . Separator , list ... )
2022-04-06 04:10:51 +00:00
2022-06-08 10:19:45 +00:00
currentPath := filepath . Base ( commonDir )
name := "_" + currentPath
name += extension
c . Header ( "Content-Disposition" , "attachment; filename*=utf-8''" + url . PathEscape ( name ) )
for _ , fname := range list {
err = file . AddFile ( ar , fname , commonDir )
if err != nil {
log . Printf ( "Failed to archive %s: %v" , fname , err )
}
}
}
func GetDownloadSingleFile ( c * gin . Context ) {
2022-07-22 03:02:11 +00:00
filePath := c . Query ( "path" )
if len ( filePath ) == 0 {
2022-12-20 06:05:16 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result {
2022-07-22 03:02:11 +00:00
Success : common_err . INVALID_PARAMS ,
Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) ,
} )
return
}
2023-02-02 03:36:59 +00:00
fileName := path . Base ( filePath )
// c.Header("Content-Disposition", "inline")
c . Header ( "Content-Disposition" , "attachment; filename*=utf-8''" + url2 . PathEscape ( fileName ) )
2023-02-06 09:43:40 +00:00
fi , err := os . Open ( filePath )
if err != nil {
panic ( err )
}
2023-02-02 03:36:59 +00:00
2023-02-06 09:43:40 +00:00
// We only have to pass the file header = first 261 bytes
buffer := make ( [ ] byte , 261 )
_ , _ = fi . Read ( buffer )
kind , _ := filetype . Match ( buffer )
if kind != filetype . Unknown {
c . Header ( "Content-Type" , kind . MIME . Value )
2023-02-02 03:36:59 +00:00
}
2023-02-06 09:43:40 +00:00
node , err := os . Stat ( filePath )
// Set the Last-Modified header to the timestamp
c . Header ( "Last-Modified" , node . ModTime ( ) . UTC ( ) . Format ( http . TimeFormat ) )
2023-02-02 03:36:59 +00:00
2023-02-06 09:43:40 +00:00
knownSize := node . Size ( ) >= 0
if knownSize {
c . Header ( "Content-Length" , strconv . FormatInt ( node . Size ( ) , 10 ) )
}
http . ServeContent ( c . Writer , c . Request , fileName , node . ModTime ( ) , fi )
//http.ServeFile(c.Writer, c.Request, filePath)
defer fi . Close ( )
return
2022-07-22 03:02:11 +00:00
fileTmp , err := os . Open ( filePath )
if err != nil {
c . JSON ( common_err . SERVICE_ERROR , model . Result {
Success : common_err . FILE_DOES_NOT_EXIST ,
Message : common_err . GetMsg ( common_err . FILE_DOES_NOT_EXIST ) ,
} )
return
}
2022-06-08 10:19:45 +00:00
defer fileTmp . Close ( )
2022-04-06 04:10:51 +00:00
2022-06-08 10:19:45 +00:00
c . File ( filePath )
2022-04-06 04:10:51 +00:00
}
2021-09-26 02:35:02 +00:00
// @Summary 获取目录列表
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string false "路径"
// @Success 200 {string} string "ok"
// @Router /file/dirpath [get]
func DirPath ( c * gin . Context ) {
2023-01-16 05:54:44 +00:00
var req ListReq
if err := c . ShouldBind ( & req ) ; err != nil {
2023-02-07 06:38:21 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . CLIENT_ERROR , Message : common_err . GetMsg ( common_err . CLIENT_ERROR ) , Data : err . Error ( ) } )
2023-01-16 05:54:44 +00:00
return
}
req . Validate ( )
2023-02-07 06:38:21 +00:00
info , err := service . MyService . System ( ) . GetDirPath ( req . Path )
if err != nil {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
return
}
2022-08-15 03:37:21 +00:00
shares := service . MyService . Shares ( ) . GetSharesList ( )
sharesMap := make ( map [ string ] string )
for _ , v := range shares {
sharesMap [ v . Path ] = fmt . Sprint ( v . ID )
}
2023-02-02 15:59:33 +00:00
// if len(info) <= (req.Page-1)*req.Size {
// c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "page out of range"})
// return
// }
forEnd := req . Index * req . Size
if forEnd > len ( info ) {
forEnd = len ( info )
}
for i := ( req . Index - 1 ) * req . Size ; i < forEnd ; i ++ {
2022-08-15 03:37:21 +00:00
if v , ok := sharesMap [ info [ i ] . Path ] ; ok {
ex := make ( map [ string ] interface { } )
shareEx := make ( map [ string ] string )
shareEx [ "shared" ] = "true"
shareEx [ "id" ] = v
ex [ "share" ] = shareEx
2023-02-07 06:38:21 +00:00
ex [ "mounted" ] = false
info [ i ] . Extensions = ex
}
}
if strings . HasPrefix ( req . Path , "/mnt" ) || strings . HasPrefix ( req . Path , "/media" ) {
for i := ( req . Index - 1 ) * req . Size ; i < forEnd ; i ++ {
ex := info [ i ] . Extensions
if ex == nil {
ex = make ( map [ string ] interface { } )
}
mounted := service . IsMounted ( info [ i ] . Path )
ex [ "mounted" ] = mounted
2022-08-15 03:37:21 +00:00
info [ i ] . Extensions = ex
}
}
2022-10-20 06:25:26 +00:00
// Hide the files or folders in operation
2022-06-08 10:19:45 +00:00
fileQueue := make ( map [ string ] string )
2022-06-10 06:47:50 +00:00
if len ( service . OpStrArr ) > 0 {
for _ , v := range service . OpStrArr {
v , ok := service . FileQueue . Load ( v )
if ! ok {
continue
}
vt := v . ( model . FileOperate )
for _ , i := range vt . Item {
lastPath := i . From [ strings . LastIndex ( i . From , "/" ) + 1 : ]
fileQueue [ vt . To + "/" + lastPath ] = i . From
}
2022-06-08 10:19:45 +00:00
}
}
2022-06-10 06:47:50 +00:00
2023-01-16 05:54:44 +00:00
pathList := [ ] ObjResp { }
2023-02-02 15:59:33 +00:00
for i := ( req . Index - 1 ) * req . Size ; i < forEnd ; i ++ {
2022-10-20 06:25:26 +00:00
if info [ i ] . Name == ".temp" && info [ i ] . IsDir {
continue
}
2022-06-08 10:19:45 +00:00
if _ , ok := fileQueue [ info [ i ] . Path ] ; ! ok {
2023-01-16 05:54:44 +00:00
t := ObjResp { }
t . IsDir = info [ i ] . IsDir
t . Name = info [ i ] . Name
t . Modified = info [ i ] . Date
2023-02-10 11:11:36 +00:00
t . Date = info [ i ] . Date
2023-01-16 05:54:44 +00:00
t . Size = info [ i ] . Size
t . Path = info [ i ] . Path
2023-02-02 15:59:33 +00:00
t . Extensions = info [ i ] . Extensions
2023-01-16 05:54:44 +00:00
pathList = append ( pathList , t )
2023-02-02 15:59:33 +00:00
2022-06-08 10:19:45 +00:00
}
}
2023-01-16 05:54:44 +00:00
flist := FsListResp {
2023-02-02 15:59:33 +00:00
Content : pathList ,
Total : int64 ( len ( info ) ) ,
// Readme: "",
// Write: true,
// Provider: "local",
Index : req . Index ,
Size : req . Size ,
2023-01-16 05:54:44 +00:00
}
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) , Data : flist } )
2021-09-26 02:35:02 +00:00
}
2022-02-17 10:43:25 +00:00
// @Summary rename file or dir
2021-09-26 02:35:02 +00:00
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param oldpath body string true "path of old"
// @Param newpath body string true "path of new"
2021-09-26 02:35:02 +00:00
// @Success 200 {string} string "ok"
// @Router /file/rename [put]
func RenamePath ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
json := make ( map [ string ] string )
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & json )
op := json [ "old_path" ]
np := json [ "new_path" ]
2021-09-26 02:35:02 +00:00
if len ( op ) == 0 || len ( np ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2021-09-26 02:35:02 +00:00
return
}
2023-02-07 06:38:21 +00:00
mounted := service . IsMounted ( op )
if mounted {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . MOUNTED_DIRECTIORIES , Message : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) , Data : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) } )
return
}
2022-06-29 03:09:58 +00:00
success , err := service . MyService . System ( ) . RenameFile ( op , np )
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : success , Message : common_err . GetMsg ( success ) , Data : err } )
2021-09-26 02:35:02 +00:00
}
2022-02-17 10:43:25 +00:00
// @Summary create folder
2021-09-26 02:35:02 +00:00
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2021-09-26 02:35:02 +00:00
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param path body string true "path of folder"
2021-09-26 02:35:02 +00:00
// @Success 200 {string} string "ok"
// @Router /file/mkdir [post]
func MkdirAll ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
json := make ( map [ string ] string )
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & json )
2022-06-08 10:19:45 +00:00
path := json [ "path" ]
2021-09-26 02:35:02 +00:00
var code int
if len ( path ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2021-09-26 02:35:02 +00:00
return
}
2022-06-08 10:19:45 +00:00
// decodedPath, err := url.QueryUnescape(path)
// if err != nil {
2022-06-29 03:09:58 +00:00
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
2022-06-08 10:19:45 +00:00
// return
// }
2022-06-29 03:09:58 +00:00
code , _ = service . MyService . System ( ) . MkdirAll ( path )
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : code , Message : common_err . GetMsg ( code ) } )
2021-09-26 02:35:02 +00:00
}
2022-03-09 08:37:03 +00:00
// @Summary create file
2021-10-15 03:43:41 +00:00
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2021-10-15 03:43:41 +00:00
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param path body string true "path of folder (path need to url encode)"
2021-10-15 03:43:41 +00:00
// @Success 200 {string} string "ok"
// @Router /file/create [post]
func PostCreateFile ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
json := make ( map [ string ] string )
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & json )
2022-06-08 10:19:45 +00:00
path := json [ "path" ]
2021-10-15 03:43:41 +00:00
var code int
if len ( path ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2021-10-15 03:43:41 +00:00
return
}
2022-06-08 10:19:45 +00:00
// decodedPath, err := url.QueryUnescape(path)
// if err != nil {
2022-06-29 03:09:58 +00:00
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
2022-06-08 10:19:45 +00:00
// return
// }
2022-06-29 03:09:58 +00:00
code , _ = service . MyService . System ( ) . CreateFile ( path )
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : code , Message : common_err . GetMsg ( code ) } )
2021-10-15 03:43:41 +00:00
}
2022-03-09 08:37:03 +00:00
// @Summary upload file
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2022-03-09 08:37:03 +00:00
// @Tags file
// @Security ApiKeyAuth
// @Param path formData string false "file path"
// @Param file formData file true "file"
// @Success 200 {string} string "ok"
// @Router /file/upload [get]
func GetFileUpload ( c * gin . Context ) {
relative := c . Query ( "relativePath" )
fileName := c . Query ( "filename" )
2022-03-09 11:44:08 +00:00
chunkNumber := c . Query ( "chunkNumber" )
2022-03-10 05:40:42 +00:00
totalChunks , _ := strconv . Atoi ( c . DefaultQuery ( "totalChunks" , "0" ) )
2022-03-09 08:37:03 +00:00
path := c . Query ( "path" )
2022-03-09 11:44:08 +00:00
dirPath := ""
2022-03-10 08:25:33 +00:00
hash := file . GetHashByContent ( [ ] byte ( fileName ) )
2022-10-20 06:25:26 +00:00
tempDir := filepath . Join ( path , ".temp" , hash + strconv . Itoa ( totalChunks ) ) + "/"
2022-03-09 08:37:03 +00:00
if fileName != relative {
2022-03-09 11:44:08 +00:00
dirPath = strings . TrimSuffix ( relative , fileName )
2022-03-10 08:25:33 +00:00
tempDir += dirPath
2022-03-09 08:37:03 +00:00
file . MkDir ( path + "/" + dirPath )
}
2022-03-10 08:25:33 +00:00
tempDir += chunkNumber
2022-03-09 11:44:08 +00:00
if ! file . CheckNotExist ( tempDir ) {
2022-06-29 03:09:58 +00:00
c . JSON ( 200 , model . Result { Success : 200 , Message : common_err . GetMsg ( common_err . FILE_ALREADY_EXISTS ) } )
2022-03-09 08:37:03 +00:00
return
}
2022-06-29 03:09:58 +00:00
c . JSON ( 204 , model . Result { Success : 204 , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2022-03-09 08:37:03 +00:00
}
2022-02-17 10:43:25 +00:00
// @Summary upload file
2021-09-26 02:35:02 +00:00
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
2022-02-17 10:43:25 +00:00
// @Param path formData string false "file path"
// @Param file formData file true "file"
2021-09-26 02:35:02 +00:00
// @Success 200 {string} string "ok"
2022-02-17 10:43:25 +00:00
// @Router /file/upload [post]
2021-09-26 02:35:02 +00:00
func PostFileUpload ( c * gin . Context ) {
2022-02-17 10:43:25 +00:00
f , _ , _ := c . Request . FormFile ( "file" )
2022-03-09 08:37:03 +00:00
relative := c . PostForm ( "relativePath" )
fileName := c . PostForm ( "filename" )
2022-03-09 11:44:08 +00:00
totalChunks , _ := strconv . Atoi ( c . DefaultPostForm ( "totalChunks" , "0" ) )
chunkNumber := c . PostForm ( "chunkNumber" )
dirPath := ""
2022-03-09 08:37:03 +00:00
path := c . PostForm ( "path" )
2022-03-09 11:44:08 +00:00
hash := file . GetHashByContent ( [ ] byte ( fileName ) )
2022-02-17 10:43:25 +00:00
if len ( path ) == 0 {
2022-11-29 17:17:14 +00:00
logger . Error ( "path should not be empty" )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusBadRequest , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2022-02-17 10:43:25 +00:00
return
}
2022-10-20 06:25:26 +00:00
tempDir := filepath . Join ( path , ".temp" , hash + strconv . Itoa ( totalChunks ) ) + "/"
2022-03-09 08:37:03 +00:00
if fileName != relative {
2022-03-09 11:44:08 +00:00
dirPath = strings . TrimSuffix ( relative , fileName )
2022-03-10 08:25:33 +00:00
tempDir += dirPath
2022-10-20 06:25:26 +00:00
if err := file . MkDir ( path + "/" + dirPath ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to create `" + path + "/" + dirPath + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
2022-03-09 08:37:03 +00:00
}
2022-03-10 05:40:42 +00:00
2022-03-09 08:37:03 +00:00
path += "/" + relative
2022-03-10 08:25:33 +00:00
if ! file . CheckNotExist ( tempDir + chunkNumber ) {
2022-10-20 06:25:26 +00:00
if err := file . RMDir ( tempDir + chunkNumber ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to remove existing `" + tempDir + chunkNumber + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
2022-02-17 10:43:25 +00:00
}
2022-03-09 08:37:03 +00:00
2022-03-09 11:44:08 +00:00
if totalChunks > 1 {
2022-10-20 06:25:26 +00:00
if err := file . IsNotExistMkDir ( tempDir ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to create `" + tempDir + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
out , err := os . OpenFile ( tempDir + chunkNumber , os . O_WRONLY | os . O_CREATE , 0 o644 )
if err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to open `" + tempDir + chunkNumber + "` for creation" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
2022-03-09 11:44:08 +00:00
defer out . Close ( )
2022-10-20 06:25:26 +00:00
if _ , err := io . Copy ( out , f ) ; err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to write to `" + tempDir + chunkNumber + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
fileNum , err := ioutil . ReadDir ( tempDir )
2022-03-09 11:44:08 +00:00
if err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to read number of files under `" + tempDir + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
2022-03-09 11:44:08 +00:00
return
}
2022-10-20 06:25:26 +00:00
if totalChunks == len ( fileNum ) {
if err := file . SpliceFiles ( tempDir , path , totalChunks , 1 ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to splice files under `" + tempDir + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
if err := file . RMDir ( tempDir ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to remove `" + tempDir + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
return
}
}
2022-03-09 11:44:08 +00:00
} else {
2022-10-20 06:25:26 +00:00
out , err := os . OpenFile ( path , os . O_WRONLY | os . O_CREATE , 0 o644 )
2022-03-09 11:44:08 +00:00
if err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to open `" + path + "` for creation" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : err . Error ( ) } )
2022-03-09 11:44:08 +00:00
return
}
2022-10-20 06:25:26 +00:00
defer out . Close ( )
if _ , err := io . Copy ( out , f ) ; err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
2022-11-29 17:17:14 +00:00
logger . Error ( "error when trying to write to `" + path + "`" , zap . Error ( err ) )
2022-10-20 06:25:26 +00:00
c . JSON ( http . StatusInternalServerError , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
return
}
}
c . JSON ( http . StatusOK , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2021-09-26 02:35:02 +00:00
}
2021-12-29 08:42:20 +00:00
2023-03-20 11:47:13 +00:00
func PostFileOctet ( c * gin . Context ) {
content_length := c . Request . ContentLength
if content_length <= 0 || content_length > 1024 * 1024 * 1024 * 2 * 1024 {
log . Printf ( "content_length error\n" )
c . JSON ( http . StatusBadRequest , model . Result { Success : common_err . CLIENT_ERROR , Message : common_err . GetMsg ( common_err . CLIENT_ERROR ) , Data : "content_length error" } )
return
}
content_type_ , has_key := c . Request . Header [ "Content-Type" ]
if ! has_key {
log . Printf ( "Content-Type error\n" )
c . JSON ( http . StatusBadRequest , model . Result { Success : common_err . CLIENT_ERROR , Message : common_err . GetMsg ( common_err . CLIENT_ERROR ) , Data : "Content-Type error" } )
return
}
if len ( content_type_ ) != 1 {
log . Printf ( "Content-Type count error\n" )
c . JSON ( http . StatusBadRequest , model . Result { Success : common_err . CLIENT_ERROR , Message : common_err . GetMsg ( common_err . CLIENT_ERROR ) , Data : "Content-Type count error" } )
return
}
content_type := content_type_ [ 0 ]
const BOUNDARY string = "; boundary="
loc := strings . Index ( content_type , BOUNDARY )
2023-03-22 08:06:48 +00:00
if loc == - 1 {
2023-03-20 11:47:13 +00:00
log . Printf ( "Content-Type error, no boundary\n" )
c . JSON ( http . StatusBadRequest , model . Result { Success : common_err . CLIENT_ERROR , Message : common_err . GetMsg ( common_err . CLIENT_ERROR ) , Data : "Content-Type error, no boundary" } )
return
}
boundary := [ ] byte ( content_type [ ( loc + len ( BOUNDARY ) ) : ] )
log . Printf ( "[%s]\n\n" , boundary )
read_data := make ( [ ] byte , 1024 * 24 )
var read_total int = 0
for {
file_header , file_data , err := file . ParseFromHead ( read_data , read_total , append ( boundary , [ ] byte ( "\r\n" ) ... ) , c . Request . Body )
if err != nil {
log . Printf ( "%v" , err )
return
}
log . Printf ( "file :%s\n" , file_header )
//
2023-03-21 02:12:03 +00:00
//os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
f , err := os . OpenFile ( file_header [ "path" ] + "/" + file_header [ "filename" ] , os . O_WRONLY | os . O_CREATE , 0 o644 )
2023-03-20 11:47:13 +00:00
if err != nil {
log . Printf ( "create file fail:%v\n" , err )
return
}
f . Write ( file_data )
file_data = nil
2023-03-21 02:12:03 +00:00
2023-03-20 11:47:13 +00:00
temp_data , reach_end , err := file . ReadToBoundary ( boundary , c . Request . Body , f )
f . Close ( )
if err != nil {
log . Printf ( "%v\n" , err )
return
}
if reach_end {
break
} else {
copy ( read_data [ 0 : ] , temp_data )
read_total = len ( temp_data )
continue
}
}
c . JSON ( http . StatusOK , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
}
2022-02-17 10:43:25 +00:00
// @Summary copy or move file
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2022-02-17 10:43:25 +00:00
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param body body model.FileOperate true "type:move,copy"
2022-02-17 10:43:25 +00:00
// @Success 200 {string} string "ok"
// @Router /file/operate [post]
func PostOperateFileOrDir ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
list := model . FileOperate { }
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & list )
2022-06-08 10:19:45 +00:00
if len ( list . Item ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2022-02-17 10:43:25 +00:00
return
2021-12-29 08:42:20 +00:00
}
2022-06-10 05:33:53 +00:00
if list . To == list . Item [ 0 ] . From [ : strings . LastIndex ( list . Item [ 0 ] . From , "/" ) ] {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SOURCE_DES_SAME , Message : common_err . GetMsg ( common_err . SOURCE_DES_SAME ) } )
2022-06-10 05:33:53 +00:00
return
}
2022-06-08 10:19:45 +00:00
var total int64 = 0
for i := 0 ; i < len ( list . Item ) ; i ++ {
size , err := file . GetFileOrDirSize ( list . Item [ i ] . From )
2022-02-17 10:43:25 +00:00
if err != nil {
2022-06-08 10:19:45 +00:00
continue
2022-02-17 10:43:25 +00:00
}
2022-06-08 10:19:45 +00:00
list . Item [ i ] . Size = size
total += size
2023-02-07 06:38:21 +00:00
if list . Type == "move" {
mounted := service . IsMounted ( list . Item [ i ] . From )
if mounted {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . MOUNTED_DIRECTIORIES , Message : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) , Data : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) } )
return
}
}
2022-06-08 10:19:45 +00:00
}
list . TotalSize = total
list . ProcessedSize = 0
uid := uuid . NewV4 ( ) . String ( )
service . FileQueue . Store ( uid , list )
service . OpStrArr = append ( service . OpStrArr , uid )
if len ( service . OpStrArr ) == 1 {
go service . ExecOpFile ( )
go service . CheckFileStatus ( )
2022-06-08 11:31:01 +00:00
go service . MyService . Notify ( ) . SendFileOperateNotify ( false )
2021-12-29 08:42:20 +00:00
}
2022-06-08 10:19:45 +00:00
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2021-12-29 08:42:20 +00:00
}
2022-02-28 06:14:39 +00:00
// @Summary delete file
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2022-02-28 06:14:39 +00:00
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param body body string true "paths eg ["/a/b/c","/d/e/f"]"
2022-02-28 06:14:39 +00:00
// @Success 200 {string} string "ok"
// @Router /file/delete [delete]
2022-02-17 10:43:25 +00:00
func DeleteFile ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
paths := [ ] string { }
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & paths )
2022-06-08 10:19:45 +00:00
if len ( paths ) == 0 {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . CLIENT_ERROR , model . Result { Success : common_err . INVALID_PARAMS , Message : common_err . GetMsg ( common_err . INVALID_PARAMS ) } )
2022-02-17 10:43:25 +00:00
return
2021-12-29 08:42:20 +00:00
}
2022-06-08 10:19:45 +00:00
// path := c.Query("path")
// paths := strings.Split(path, ",")
2023-02-07 06:38:21 +00:00
for _ , v := range paths {
mounted := service . IsMounted ( v )
if mounted {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . MOUNTED_DIRECTIORIES , Message : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) , Data : common_err . GetMsg ( common_err . MOUNTED_DIRECTIORIES ) } )
return
}
}
2022-06-08 10:19:45 +00:00
for _ , v := range paths {
err := os . RemoveAll ( v )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . FILE_DELETE_ERROR , Message : common_err . GetMsg ( common_err . FILE_DELETE_ERROR ) , Data : err } )
2022-06-08 10:19:45 +00:00
return
}
}
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2021-12-29 08:42:20 +00:00
}
2022-03-09 08:37:03 +00:00
// @Summary update file
// @Produce application/json
2022-06-08 10:19:45 +00:00
// @Accept application/json
2022-03-09 08:37:03 +00:00
// @Tags file
// @Security ApiKeyAuth
2022-06-08 10:19:45 +00:00
// @Param path body string true "path"
// @Param content body string true "content"
2022-03-09 08:37:03 +00:00
// @Success 200 {string} string "ok"
// @Router /file/update [put]
func PutFileContent ( c * gin . Context ) {
2022-06-08 10:19:45 +00:00
fi := model . FileUpdate { }
2022-07-22 03:02:11 +00:00
c . ShouldBind ( & fi )
2022-06-08 10:19:45 +00:00
// path := c.PostForm("path")
// content := c.PostForm("content")
if ! file . Exists ( fi . FilePath ) {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . FILE_ALREADY_EXISTS , Message : common_err . GetMsg ( common_err . FILE_ALREADY_EXISTS ) } )
2022-03-09 08:37:03 +00:00
return
}
2022-10-20 06:25:26 +00:00
// err := os.Remove(path)
2023-02-06 09:43:40 +00:00
f , err := os . Stat ( fi . FilePath )
if err != nil {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . FILE_ALREADY_EXISTS , Message : common_err . GetMsg ( common_err . FILE_ALREADY_EXISTS ) } )
return
}
fm := f . Mode ( )
2022-03-09 08:37:03 +00:00
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . FILE_DELETE_ERROR , Message : common_err . GetMsg ( common_err . FILE_DELETE_ERROR ) , Data : err } )
2022-03-09 08:37:03 +00:00
return
}
2023-02-06 09:43:40 +00:00
os . OpenFile ( fi . FilePath , os . O_CREATE , fm )
err = file . WriteToFullPath ( [ ] byte ( fi . FileContent ) , fi . FilePath , fm )
2022-03-09 08:37:03 +00:00
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
2022-03-09 08:37:03 +00:00
return
}
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2022-03-09 08:37:03 +00:00
}
2022-05-05 05:46:55 +00:00
// @Summary image thumbnail/original image
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "path"
// @Param type query string false "original,thumbnail" Enums(original,thumbnail)
// @Success 200 {string} string "ok"
// @Router /file/image [get]
func GetFileImage ( c * gin . Context ) {
t := c . Query ( "type" )
path := c . Query ( "path" )
if ! file . Exists ( path ) {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . FILE_ALREADY_EXISTS , Message : common_err . GetMsg ( common_err . FILE_ALREADY_EXISTS ) } )
2022-05-05 05:46:55 +00:00
return
}
if t == "thumbnail" {
f , err := file . GetImage ( path , 100 , 0 )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
2022-05-05 05:46:55 +00:00
return
}
c . Writer . WriteString ( string ( f ) )
return
}
f , err := os . Open ( path )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
2022-05-05 05:46:55 +00:00
return
}
defer f . Close ( )
data , err := ioutil . ReadAll ( f )
if err != nil {
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
2022-05-05 05:46:55 +00:00
return
}
c . Writer . WriteString ( string ( data ) )
}
2022-06-08 11:31:01 +00:00
func DeleteOperateFileOrDir ( c * gin . Context ) {
id := c . Param ( "id" )
if id == "0" {
service . FileQueue = sync . Map { }
service . OpStrArr = [ ] string { }
} else {
service . FileQueue . Delete ( id )
tempList := [ ] string { }
for _ , v := range service . OpStrArr {
if v != id {
tempList = append ( tempList , v )
}
}
service . OpStrArr = tempList
}
go service . MyService . Notify ( ) . SendFileOperateNotify ( true )
2022-07-22 03:02:11 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
2022-06-08 11:31:01 +00:00
}
2022-12-20 06:05:16 +00:00
func GetSize ( c * gin . Context ) {
json := make ( map [ string ] string )
c . ShouldBind ( & json )
path := json [ "path" ]
size , err := file . GetFileOrDirSize ( path )
if err != nil {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
return
}
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) , Data : size } )
}
2023-03-13 01:42:18 +00:00
2023-03-13 10:30:22 +00:00
func GetFileCount ( c * gin . Context ) {
json := make ( map [ string ] string )
c . ShouldBind ( & json )
path := json [ "path" ]
list , err := ioutil . ReadDir ( path )
if err != nil {
c . JSON ( common_err . SERVICE_ERROR , model . Result { Success : common_err . SERVICE_ERROR , Message : common_err . GetMsg ( common_err . SERVICE_ERROR ) , Data : err . Error ( ) } )
return
}
2023-03-20 07:24:45 +00:00
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) , Data : len ( list ) } )
2023-03-13 10:30:22 +00:00
}
2023-03-13 01:42:18 +00:00
type CenterHandler struct {
// 广播通道,有数据则循环每个用户广播出去
broadcast chan [ ] byte
// 注册通道,有用户进来 则推到用户集合map中
register chan * Client
// 注销通道,有用户关闭连接 则将该用户剔出集合map中
unregister chan * Client
// 用户集合,每个用户本身也在跑两个协程,监听用户的读、写的状态
clients map [ string ] * Client
}
type Client struct {
handler * CenterHandler
conn * websocket . Conn
// 每个用户自己的循环跑起来的状态监控
send chan [ ] byte
ID string ` json:"id" `
IP string ` json:"ip" `
Name service . Name ` json:"name" `
RtcSupported bool ` json:"rtcSupported" `
TimerId int ` json:"timerId" `
LastBeat time . Time ` json:"lastBeat" `
}
type PeerModel struct {
ID string ` json:"id" `
Name service . Name ` json:"name" `
RtcSupported bool ` json:"rtcSupported" `
}
func ConnectWebSocket ( c * gin . Context ) {
peerId := c . Query ( "peer" )
writer := c . Writer
request := c . Request
key := uuid . NewV4 ( ) . String ( )
//peerModel := service.MyService.Peer().GetPeerByUserAgent(c.Request.UserAgent())
peerModel := model2 . PeerDriveDBModel { }
name := service . GetName ( request )
if conn , err = upgraderFile . Upgrade ( writer , request , writer . Header ( ) ) ; err != nil {
log . Println ( err )
return
}
client := & Client { handler : & handler , conn : conn , send : make ( chan [ ] byte , 256 ) , ID : service . GetPeerId ( request , key ) , IP : service . GetIP ( request ) , Name : name , RtcSupported : true , TimerId : 0 , LastBeat : time . Now ( ) }
if peerId != "" || len ( peerModel . ID ) > 0 {
if len ( peerModel . ID ) == 0 {
peerModel = service . MyService . Peer ( ) . GetPeerByID ( peerId )
}
if len ( peerModel . ID ) > 0 {
key = peerId
client . ID = peerModel . ID
client . Name = service . GetNameByDB ( peerModel )
}
}
var list = service . MyService . Peer ( ) . GetPeers ( )
if len ( peerModel . ID ) == 0 {
peerModel . ID = key
peerModel . DisplayName = name . DisplayName
peerModel . DeviceName = name . DeviceName
peerModel . Model = name . Model
peerModel . OS = name . OS
peerModel . Browser = name . Browser
peerModel . UserAgent = c . Request . UserAgent ( )
peerModel . IP = client . IP
service . MyService . Peer ( ) . CreatePeer ( & peerModel )
list = append ( list , peerModel )
}
cookie := http . Cookie {
Name : "peerid" ,
Value : key ,
Path : "/" ,
}
http . SetCookie ( writer , & cookie )
if len ( list ) > 10 {
kickoutList := [ ] Client { }
count := len ( list ) - 10
for i := len ( list ) - 1 ; count > 0 && i > - 1 ; i -- {
if _ , ok := handler . clients [ list [ i ] . ID ] ; ! ok {
count --
kickoutList = append ( kickoutList , Client { ID : list [ i ] . ID , Name : service . GetNameByDB ( list [ i ] ) , IP : list [ i ] . IP } )
service . MyService . Peer ( ) . DeletePeer ( list [ i ] . ID )
}
}
// if len(kickoutList) > 0 {
// other := make(map[string]interface{})
// other["type"] = "kickout"
// other["peers"] = kickoutList
// otherBy, err := json.Marshal(other)
// fmt.Println(err)
// client.handler.broadcast <- otherBy
// }
}
list = service . MyService . Peer ( ) . GetPeers ( )
if len ( list ) > 10 {
fmt . Println ( "解决完后依然有溢出" , list )
}
currentPeer := PeerModel { ID : client . ID , Name : client . Name , RtcSupported : client . RtcSupported }
pmsg := make ( map [ string ] interface { } )
pmsg [ "type" ] = "peer-joined"
pmsg [ "peer" ] = currentPeer
pby , err := json . Marshal ( pmsg )
fmt . Println ( err )
for _ , v := range handler . clients {
v . send <- pby
}
//client.handler.broadcast <- pby
clients := [ ] PeerModel { }
for _ , v := range client . handler . clients {
if _ , ok := handler . clients [ v . ID ] ; ok {
clients = append ( clients , PeerModel { ID : v . ID , Name : v . Name , RtcSupported : v . RtcSupported } )
}
}
other := make ( map [ string ] interface { } )
other [ "type" ] = "peers"
other [ "peers" ] = clients
otherBy , err := json . Marshal ( other )
fmt . Println ( err )
client . send <- otherBy
// 推给监控中心注册到用户集合中
handler . register <- client
client . send <- [ ] byte ( ` { "type":"ping"} ` )
data := make ( map [ string ] string )
data [ "displayName" ] = client . Name . DisplayName
data [ "deviceName" ] = client . Name . DeviceName
data [ "id" ] = client . ID
msg := make ( map [ string ] interface { } )
msg [ "type" ] = "display-name"
msg [ "message" ] = data
by , _ := json . Marshal ( msg )
client . send <- by
// 每个 client 都挂起 2 个新的协程,监控读、写状态
go client . writePump ( )
go client . readPump ( )
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) } )
}
var handler = CenterHandler { broadcast : make ( chan [ ] byte ) ,
register : make ( chan * Client ) ,
unregister : make ( chan * Client ) ,
clients : make ( map [ string ] * Client ) }
func init ( ) {
// 起个协程跑起来,监听注册、注销、消息 3 个 channel
go handler . monitoring ( )
crontab := cron . New ( cron . WithSeconds ( ) ) //精确到秒
//定义定时器调用的任务函数
task := func ( ) {
handler . broadcast <- [ ] byte ( ` { "type":"ping"} ` )
}
//定时任务
spec := "*/30 * * * * ?" //cron表达式, 每五秒一次
// 添加定时任务,
crontab . AddFunc ( spec , task )
// 启动定时器
crontab . Start ( )
}
func ( c * Client ) writePump ( ) {
defer func ( ) {
c . handler . unregister <- c
2023-03-20 09:02:42 +00:00
2023-03-13 01:42:18 +00:00
c . conn . Close ( )
} ( )
for {
// 广播推过来的新消息, 马上通过websocket推给自己
message , _ := <- c . send
fmt . Println ( "推送消息" , string ( message ) , "1" )
if err := c . conn . WriteMessage ( websocket . TextMessage , message ) ; err != nil {
return
}
}
}
// 读,监听客户端是否有推送内容过来服务端
func ( c * Client ) readPump ( ) {
defer func ( ) {
c . handler . unregister <- c
c . conn . Close ( )
} ( )
for {
// 循环监听是否该用户是否要发言
_ , message , err := c . conn . ReadMessage ( )
if err != nil {
// 异常关闭的处理
if websocket . IsUnexpectedCloseError ( err , websocket . CloseGoingAway , websocket . CloseAbnormalClosure ) {
log . Printf ( "error: %v" , err )
}
2023-03-20 09:02:42 +00:00
c . handler . broadcast <- [ ] byte ( ` { "type":"peer-left","peerId":" ` + c . ID + ` "} ` )
2023-03-13 01:42:18 +00:00
break
}
// 要的话,推给广播中心,广播中心再推给每个用户
t := gjson . GetBytes ( message , "type" )
if t . String ( ) == "disconnect" {
c . handler . unregister <- c
c . conn . Close ( )
// clients := []Client{}
// list := service.MyService.Peer().GetPeers()
// for _, v := range list {
// if _, ok := handler.clients[v.ID]; ok {
// clients = append(clients, *handler.clients[v.ID])
// } else {
// clients = append(clients, Client{ID: v.ID, Name: service.GetNameByDB(v), IP: v.IP, Offline: true})
// }
// }
// other := make(map[string]interface{})
// other["type"] = "peers"
// other["peers"] = clients
// otherBy, err := json.Marshal(other)
// fmt.Println(err)
c . handler . broadcast <- [ ] byte ( ` { "type":"peer-left","peerId":" ` + c . ID + ` "} ` )
//c.handler.broadcast <- otherBy
break
} else if t . String ( ) == "pong" {
c . LastBeat = time . Now ( )
continue
}
to := gjson . GetBytes ( message , "to" )
if len ( to . String ( ) ) > 0 {
toC := c . handler . clients [ to . String ( ) ]
if toC == nil {
continue
}
data := map [ string ] interface { } { }
json . Unmarshal ( message , & data )
data [ "sender" ] = c . ID
delete ( data , "to" )
message , err = json . Marshal ( data )
toC . send <- message
continue
}
c . handler . broadcast <- message
}
}
func ( ch * CenterHandler ) monitoring ( ) {
for {
select {
// 注册,新用户连接过来会推进注册通道,这里接收推进来的用户指针
case client := <- ch . register :
ch . clients [ client . ID ] = client
// 注销,关闭连接或连接异常会将用户推出群聊
case client := <- ch . unregister :
delete ( ch . clients , client . ID )
// 消息,监听到有新消息到来
case message := <- ch . broadcast :
println ( "消息来了, message: " + string ( message ) )
// 推送给每个用户的通道, 每个用户都有跑协程起了writePump的监听
for _ , client := range ch . clients {
client . send <- message
}
}
}
}
func GetPeers ( c * gin . Context ) {
peers := service . MyService . Peer ( ) . GetPeers ( )
for i := 0 ; i < len ( peers ) ; i ++ {
if _ , ok := handler . clients [ peers [ i ] . ID ] ; ok {
peers [ i ] . Online = true
}
}
c . JSON ( common_err . SUCCESS , model . Result { Success : common_err . SUCCESS , Message : common_err . GetMsg ( common_err . SUCCESS ) , Data : peers } )
}