Release 0.3.0 (#37)
* chore(cicd): add build and start script * fix(client/web): fix fail to reupload same file, avoid default worker * test(client/web): add case for worker list filtering
This commit is contained in:
parent
ede6c239f0
commit
c8a3f911e8
16 changed files with 117 additions and 15 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -14,5 +14,6 @@
|
||||||
**/*/files/
|
**/*/files/
|
||||||
**/*/uploadings/
|
**/*/uploadings/
|
||||||
|
|
||||||
# misc
|
# build
|
||||||
dist
|
dist
|
||||||
|
tmp
|
BIN
cmd/quickshare
BIN
cmd/quickshare
Binary file not shown.
|
@ -1,6 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ihexxa/gocfg"
|
"github.com/ihexxa/gocfg"
|
||||||
goflags "github.com/jessevdk/go-flags"
|
goflags "github.com/jessevdk/go-flags"
|
||||||
|
|
||||||
|
@ -30,7 +33,14 @@ func main() {
|
||||||
}
|
}
|
||||||
if len(opts.Configs) > 0 {
|
if len(opts.Configs) > 0 {
|
||||||
for _, configPath := range opts.Configs {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
21
configs/dev.yml
Normal file
21
configs/dev.yml
Normal file
|
@ -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
|
1
go.mod
1
go.mod
|
@ -10,6 +10,7 @@ require (
|
||||||
github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086
|
github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086
|
||||||
github.com/ihexxa/multipart v0.0.0-20201207132919-72f6e0e58b25
|
github.com/ihexxa/multipart v0.0.0-20201207132919-72f6e0e58b25
|
||||||
github.com/jessevdk/go-flags v1.4.0
|
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/parnurzeal/gorequest v0.2.16
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/robbert229/jwt v2.0.0+incompatible
|
github.com/robbert229/jwt v2.0.0+incompatible
|
||||||
|
|
6
go.sum
6
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/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 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
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 h1:1IzU4pzD8NyEHgJGLOS3Iq56b0zlAylRwbJq+08PD9Y=
|
||||||
github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs=
|
github.com/ihexxa/gocfg v0.0.0-20201206115732-ab537e3b1086/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs=
|
||||||
github.com/ihexxa/multipart v0.0.0-20201201114901-e265a43930c0 h1:L2fR7u66Kgh0DYOZWJPxOj23JrwEgUqOOivZHp6qfG8=
|
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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
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 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
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=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"src/client/web"
|
"src/client/web"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "scripts/build"
|
"build": "scripts/build",
|
||||||
|
"start": "go run cmd/start/main.go -c `pwd`/configs/dev.yml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,30 @@
|
||||||
export QSROOT=`pwd`
|
export QSROOT=`pwd`
|
||||||
rm -r dist && mkdir dist
|
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
|
cd $QSROOT/src/client/web
|
||||||
yarn build
|
yarn build
|
||||||
cp -r $QSROOT/public $QSROOT/dist
|
|
||||||
cd $QSROOT
|
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/*
|
||||||
|
|
|
@ -5,3 +5,7 @@ export function alertMsg(msg: string) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function comfirmMsg(msg: string): boolean {
|
||||||
|
return confirm(msg);
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { List, Map } from "immutable";
|
||||||
import FileSize from "filesize";
|
import FileSize from "filesize";
|
||||||
|
|
||||||
import { Layouter } from "./layouter";
|
import { Layouter } from "./layouter";
|
||||||
import { alertMsg } from "../common/env";
|
import { alertMsg, comfirmMsg } from "../common/env";
|
||||||
import { updater } from "./browser.updater";
|
import { updater } from "./browser.updater";
|
||||||
import { ICoreState } from "./core_state";
|
import { ICoreState } from "./core_state";
|
||||||
import {
|
import {
|
||||||
|
@ -139,6 +139,11 @@ export class Browser extends React.Component<Props, State, {}> {
|
||||||
selectedItems: Map<string, boolean>(),
|
selectedItems: Map<string, boolean>(),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
const filesToDel = this.state.selectedItems.keySeq().join(", ");
|
||||||
|
if (!comfirmMsg(`do you want to delete ${filesToDel}?`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updater()
|
updater()
|
||||||
|
|
|
@ -32,7 +32,6 @@ export function initWithWorker(worker: IWorker): ICoreState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init(): ICoreState {
|
export function init(): ICoreState {
|
||||||
const scripts = Array.from(document.querySelectorAll("script"));
|
|
||||||
const worker = Worker == null ? new FgWorker() : new BgWorker();
|
const worker = Worker == null ? new FgWorker() : new BgWorker();
|
||||||
initUploadMgr(worker);
|
initUploadMgr(worker);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,12 @@ describe("upload.worker", () => {
|
||||||
expectedUploaderStartInput: "file1",
|
expectedUploaderStartInput: "file1",
|
||||||
currentFilePath: "file0",
|
currentFilePath: "file0",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
infos: [makeEntry("file1", true)],
|
||||||
|
expectedUploadingFile: "file1",
|
||||||
|
expectedUploaderStartInput: "file1",
|
||||||
|
currentFilePath: "file1",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < tcs.length; i++) {
|
for (let i = 0; i < tcs.length; i++) {
|
||||||
|
|
|
@ -57,10 +57,10 @@ export class UploadWorker {
|
||||||
infoArray[i].runnable &&
|
infoArray[i].runnable &&
|
||||||
infoArray[i].uploaded < infoArray[i].size
|
infoArray[i].uploaded < infoArray[i].size
|
||||||
) {
|
) {
|
||||||
if (infoArray[i].filePath !== this.filePath) {
|
// infoArray[i].filePath !== this.filePath, it may re-uploading a deleted file
|
||||||
this.stopUploader();
|
// and it will stuck or the file will be renamed in the future
|
||||||
this.startUploader(infoArray[i].file, infoArray[i].filePath);
|
this.stopUploader();
|
||||||
}
|
this.startUploader(infoArray[i].file, infoArray[i].filePath);
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!infoArray[i].runnable &&
|
!infoArray[i].runnable &&
|
||||||
|
|
|
@ -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 => {
|
export const initUploadMgr = (worker: IWorker): UploadMgr => {
|
||||||
uploadMgr = new UploadMgr(worker);
|
uploadMgr = new UploadMgr(worker);
|
||||||
return uploadMgr;
|
return uploadMgr;
|
||||||
|
|
|
@ -28,6 +28,7 @@ type ServerCfg struct {
|
||||||
ReadTimeout int `json:"readTimeout"`
|
ReadTimeout int `json:"readTimeout"`
|
||||||
WriteTimeout int `json:"writeTimeout"`
|
WriteTimeout int `json:"writeTimeout"`
|
||||||
MaxHeaderBytes int `json:"maxHeaderBytes"`
|
MaxHeaderBytes int `json:"maxHeaderBytes"`
|
||||||
|
PublicPath string `json:"publicPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -66,6 +67,7 @@ func DefaultConfig() (string, error) {
|
||||||
ReadTimeout: 2000,
|
ReadTimeout: 2000,
|
||||||
WriteTimeout: 1000 * 3600 * 24, // 1 day
|
WriteTimeout: 1000 * 3600 * 24, // 1 day
|
||||||
MaxHeaderBytes: 512,
|
MaxHeaderBytes: 512,
|
||||||
|
PublicPath: "public",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-contrib/static"
|
"github.com/gin-contrib/static"
|
||||||
|
@ -56,6 +58,22 @@ func NewServer(cfg gocfg.ICfg) (*Server, error) {
|
||||||
}, nil
|
}, 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 {
|
func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
secret, ok := cfg.String("ENV.TOKENSECRET")
|
secret, ok := cfg.String("ENV.TOKENSECRET")
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -64,6 +82,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
}
|
}
|
||||||
|
|
||||||
rootPath := cfg.GrabString("Fs.Root")
|
rootPath := cfg.GrabString("Fs.Root")
|
||||||
|
mkRoot(rootPath)
|
||||||
opensLimit := cfg.GrabInt("Fs.OpensLimit")
|
opensLimit := cfg.GrabInt("Fs.OpensLimit")
|
||||||
openTTL := cfg.GrabInt("Fs.OpenTTL")
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
publicPath, ok := cfg.String("Server.PublicPath")
|
||||||
|
if !ok || publicPath == "" {
|
||||||
|
return nil, errors.New("publicPath not found or empty")
|
||||||
|
}
|
||||||
|
|
||||||
// middleware
|
// middleware
|
||||||
router.Use(userHdrs.Auth())
|
router.Use(userHdrs.Auth())
|
||||||
// tmp static server
|
// tmp static server
|
||||||
router.Use(static.Serve("/", static.LocalFile("../public", false)))
|
router.Use(static.Serve("/", static.LocalFile(publicPath, false)))
|
||||||
|
|
||||||
// handler
|
// handler
|
||||||
v1 := router.Group("/v1")
|
v1 := router.Group("/v1")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue