diff --git a/.gitignore b/.gitignore index 3d0a5c7..6eb44a1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ **/*/files/ **/*/uploadings/ -# misc -dist \ No newline at end of file +# build +dist +tmp \ No newline at end of file diff --git a/cmd/quickshare b/cmd/quickshare deleted file mode 100755 index 92494e0..0000000 Binary files a/cmd/quickshare and /dev/null differ diff --git a/cmd/main.go b/cmd/start/main.go similarity index 74% rename from cmd/main.go rename to cmd/start/main.go index ea3e9e2..4e73c2d 100644 --- a/cmd/main.go +++ b/cmd/start/main.go @@ -1,6 +1,9 @@ package main import ( + "fmt" + "strings" + "github.com/ihexxa/gocfg" goflags "github.com/jessevdk/go-flags" @@ -30,7 +33,14 @@ func main() { } if len(opts.Configs) > 0 { for _, configPath := range opts.Configs { - cfg, err = cfg.Load(gocfg.JSON(configPath)) + if strings.HasSuffix(configPath, ".yml") || strings.HasSuffix(configPath, ".yaml") { + cfg, err = cfg.Load(gocfg.YAML(configPath)) + } else if strings.HasSuffix(configPath, ".json") { + cfg, err = cfg.Load(gocfg.JSON(configPath)) + } else { + panic(fmt.Sprintf("unknown config file type (.yml .yaml .json are supported): %s", configPath)) + } + if err != nil { panic(err) } diff --git a/configs/dev.yml b/configs/dev.yml new file mode 100644 index 0000000..7a30ba8 --- /dev/null +++ b/configs/dev.yml @@ -0,0 +1,21 @@ +fs: + root: "tmp" + opensLimit: 128 + openTTL: 60 # 1 min +secrets: + tokenSecret: "" +server: + debug: true + host: "0.0.0.0" + port: 8686 + readTimeout: 2000 + writerTimeout: 86400000 # 1 day + maxHeaderBytes: 512 + publicPath: "public" +users: + enableAuth: true + defaultAdmin: "" + defaultAdminPwd: "" + cookieTTL: 604800 # 1 week + cookieSecure: false + cookieHttpOnly: true diff --git a/go.mod b/go.mod index 31978a8..6504b11 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086 github.com/ihexxa/multipart v0.0.0-20201207132919-72f6e0e58b25 github.com/jessevdk/go-flags v1.4.0 + github.com/mitchellh/gox v1.0.1 // indirect github.com/parnurzeal/gorequest v0.2.16 github.com/pkg/errors v0.9.1 // indirect github.com/robbert229/jwt v2.0.0+incompatible diff --git a/go.sum b/go.sum index 131bb81..2bfd23f 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086 h1:1IzU4pzD8NyEHgJGLOS3Iq56b0zlAylRwbJq+08PD9Y= github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs= github.com/ihexxa/multipart v0.0.0-20201201114901-e265a43930c0 h1:L2fR7u66Kgh0DYOZWJPxOj23JrwEgUqOOivZHp6qfG8= @@ -50,6 +52,10 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= +github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= diff --git a/package.json b/package.json index 91d25fd..2488b97 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "src/client/web" ], "scripts": { - "build": "scripts/build" + "build": "scripts/build", + "start": "go run cmd/start/main.go -c `pwd`/configs/dev.yml" } } diff --git a/scripts/build b/scripts/build index 3c65f95..a0903f4 100755 --- a/scripts/build +++ b/scripts/build @@ -1,8 +1,30 @@ export QSROOT=`pwd` rm -r dist && mkdir dist -cd cmd -go build -o $QSROOT/dist/quickshare + +go get github.com/mitchellh/gox +cd cmd/start +gox \ + -osarch="windows/386 windows/amd64 darwin/amd64 linux/386 linux/amd64 linux/arm linux/arm64" \ + -output "$QSROOT/dist/quickshare_{{.OS}}_{{.Arch}}/quickshare" + cd $QSROOT/src/client/web yarn build -cp -r $QSROOT/public $QSROOT/dist + cd $QSROOT +cp -R $QSROOT/public $QSROOT/dist/quickshare_windows_386 +cp -R $QSROOT/public $QSROOT/dist/quickshare_windows_amd64 +cp -R $QSROOT/public $QSROOT/dist/quickshare_darwin_amd64 +cp -R $QSROOT/public $QSROOT/dist/quickshare_linux_386 +cp -R $QSROOT/public $QSROOT/dist/quickshare_linux_amd64 +cp -R $QSROOT/public $QSROOT/dist/quickshare_linux_arm +cp -R $QSROOT/public $QSROOT/dist/quickshare_linux_arm64 + +cd $QSROOT/dist + +zip -r -q $QSROOT/dist/quickshare_windows_386.zip quickshare_windows_386/* +zip -r -q $QSROOT/dist/quickshare_windows_amd64.zip quickshare_windows_amd64/* +zip -r -q $QSROOT/dist/quickshare_darwin_amd64.zip quickshare_darwin_amd64/* +zip -r -q $QSROOT/dist/quickshare_linux_386.zip quickshare_linux_386/* +zip -r -q $QSROOT/dist/quickshare_linux_amd64.zip quickshare_linux_amd64/* +zip -r -q $QSROOT/dist/quickshare_linux_arm.zip quickshare_linux_arm/* +zip -r -q $QSROOT/dist/quickshare_linux_arm64.zip quickshare_linux_arm64/* diff --git a/src/client/web/src/common/env.ts b/src/client/web/src/common/env.ts index 6a95c48..984a275 100644 --- a/src/client/web/src/common/env.ts +++ b/src/client/web/src/common/env.ts @@ -5,3 +5,7 @@ export function alertMsg(msg: string) { console.log(msg); } } + +export function comfirmMsg(msg: string): boolean { + return confirm(msg); +} diff --git a/src/client/web/src/components/browser.tsx b/src/client/web/src/components/browser.tsx index 15c0092..825a876 100644 --- a/src/client/web/src/components/browser.tsx +++ b/src/client/web/src/components/browser.tsx @@ -4,7 +4,7 @@ import { List, Map } from "immutable"; import FileSize from "filesize"; import { Layouter } from "./layouter"; -import { alertMsg } from "../common/env"; +import { alertMsg, comfirmMsg } from "../common/env"; import { updater } from "./browser.updater"; import { ICoreState } from "./core_state"; import { @@ -139,6 +139,11 @@ export class Browser extends React.Component { selectedItems: Map(), }); return; + } else { + const filesToDel = this.state.selectedItems.keySeq().join(", "); + if (!comfirmMsg(`do you want to delete ${filesToDel}?`)) { + return; + } } updater() diff --git a/src/client/web/src/components/core_state.ts b/src/client/web/src/components/core_state.ts index 7be585e..c7470c2 100644 --- a/src/client/web/src/components/core_state.ts +++ b/src/client/web/src/components/core_state.ts @@ -32,7 +32,6 @@ export function initWithWorker(worker: IWorker): ICoreState { } export function init(): ICoreState { - const scripts = Array.from(document.querySelectorAll("script")); const worker = Worker == null ? new FgWorker() : new BgWorker(); initUploadMgr(worker); diff --git a/src/client/web/src/worker/__test__/upload.worker.test.ts b/src/client/web/src/worker/__test__/upload.worker.test.ts index 045c6a0..157da2e 100644 --- a/src/client/web/src/worker/__test__/upload.worker.test.ts +++ b/src/client/web/src/worker/__test__/upload.worker.test.ts @@ -62,6 +62,12 @@ describe("upload.worker", () => { expectedUploaderStartInput: "file1", currentFilePath: "file0", }, + { + infos: [makeEntry("file1", true)], + expectedUploadingFile: "file1", + expectedUploaderStartInput: "file1", + currentFilePath: "file1", + }, ]; for (let i = 0; i < tcs.length; i++) { diff --git a/src/client/web/src/worker/upload.baseworker.ts b/src/client/web/src/worker/upload.baseworker.ts index 43460ed..50968d6 100644 --- a/src/client/web/src/worker/upload.baseworker.ts +++ b/src/client/web/src/worker/upload.baseworker.ts @@ -57,10 +57,10 @@ export class UploadWorker { infoArray[i].runnable && infoArray[i].uploaded < infoArray[i].size ) { - if (infoArray[i].filePath !== this.filePath) { - this.stopUploader(); - this.startUploader(infoArray[i].file, infoArray[i].filePath); - } + // infoArray[i].filePath !== this.filePath, it may re-uploading a deleted file + // and it will stuck or the file will be renamed in the future + this.stopUploader(); + this.startUploader(infoArray[i].file, infoArray[i].filePath); break; } else if ( !infoArray[i].runnable && diff --git a/src/client/web/src/worker/upload_mgr.ts b/src/client/web/src/worker/upload_mgr.ts index 3e4c6ac..03bd474 100644 --- a/src/client/web/src/worker/upload_mgr.ts +++ b/src/client/web/src/worker/upload_mgr.ts @@ -144,7 +144,7 @@ export class UploadMgr { }; } -export let uploadMgr = new UploadMgr(new FgWorker()); +export let uploadMgr: UploadMgr = undefined; export const initUploadMgr = (worker: IWorker): UploadMgr => { uploadMgr = new UploadMgr(worker); return uploadMgr; diff --git a/src/server/config.go b/src/server/config.go index 74a48b8..49ef828 100644 --- a/src/server/config.go +++ b/src/server/config.go @@ -28,6 +28,7 @@ type ServerCfg struct { ReadTimeout int `json:"readTimeout"` WriteTimeout int `json:"writeTimeout"` MaxHeaderBytes int `json:"maxHeaderBytes"` + PublicPath string `json:"publicPath"` } type Config struct { @@ -66,6 +67,7 @@ func DefaultConfig() (string, error) { ReadTimeout: 2000, WriteTimeout: 1000 * 3600 * 24, // 1 day MaxHeaderBytes: 512, + PublicPath: "public", }, } diff --git a/src/server/server.go b/src/server/server.go index 93383f3..b56b69c 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -4,8 +4,10 @@ import ( "context" "crypto/rand" "crypto/sha1" + "errors" "fmt" "net/http" + "os" "time" "github.com/gin-contrib/static" @@ -56,6 +58,22 @@ func NewServer(cfg gocfg.ICfg) (*Server, error) { }, nil } +func mkRoot(rootPath string) { + info, err := os.Stat(rootPath) + if err != nil { + if os.IsNotExist(err) { + err = os.MkdirAll(rootPath, 0760) + if err != nil { + panic(err) + } + } else { + panic(err) + } + } else if !info.IsDir() { + panic(fmt.Sprintf("can not create %s folder: there is a file with same name", rootPath)) + } +} + func initDeps(cfg gocfg.ICfg) *depidx.Deps { secret, ok := cfg.String("ENV.TOKENSECRET") if !ok { @@ -64,6 +82,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps { } rootPath := cfg.GrabString("Fs.Root") + mkRoot(rootPath) opensLimit := cfg.GrabInt("Fs.OpensLimit") openTTL := cfg.GrabInt("Fs.OpenTTL") @@ -121,10 +140,15 @@ func initHandlers(router *gin.Engine, cfg gocfg.ICfg, deps *depidx.Deps) (*gin.E return nil, err } + publicPath, ok := cfg.String("Server.PublicPath") + if !ok || publicPath == "" { + return nil, errors.New("publicPath not found or empty") + } + // middleware router.Use(userHdrs.Auth()) // tmp static server - router.Use(static.Serve("/", static.LocalFile("../public", false))) + router.Use(static.Serve("/", static.LocalFile(publicPath, false))) // handler v1 := router.Group("/v1")