diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a406eb2
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+FROM golang:1.15 as build-be
+ADD . /quickshare
+WORKDIR /quickshare
+RUN /quickshare/scripts/build_be_docker.sh
+
+FROM node as build-fe
+COPY --from=build-be /quickshare /quickshare
+WORKDIR /quickshare
+RUN yarn install \
+ && yarn --cwd "src/client/web" run build \
+ && cp -R /quickshare/public /quickshare/dist/quickshare
+
+FROM gcr.io/distroless/base-debian10
+COPY --from=build-fe /quickshare/dist/quickshare /quickshare
+ADD configs/docker.yml /quickshare
+CMD ["/quickshare/start", "-c", "/quickshare/docker.yml"]
diff --git a/README.md b/README.md
index 49094be..3565bb9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
Quickshare
- Simple file sharing service built with Go/Golang, Typescript, Gin, React, Boltdb, etc.
+ Quick and simple file sharing between different devices.
@@ -24,26 +24,55 @@ Choose Language: English | [简体中文](./docs/README_zh-cn.md)
## Main Features
-- Sharing files among different devices (Adaptive UI)
+- Sharing and accessing from different devices (Adaptive UI)
- Be compatible with Linux, Mac and Windows
- Stopping and resuming uploading/downloading
- Do uploading and downloading in web browser
+- Manage files in browser or in OS
## Quick Start
-**Downloading**: Download last distribution(s) in [Release Page](https://github.com/ihexxa/quickshare/releases).
+### Run in Docker
-**Unzipping**: Unzip it and run following command `./quickshare`. (You may update its execution permission: e.g. run `chmod u+x quickshare` on Linux)
+Following will start a `quickshare` docker and listen to `8686` port.
-**Starting**: At the first run, Quickshare will let you input your user name and generate a random password for you (here `quickshare` is the user name). It may output something like following (password is `2fdc98`):
+Then you can open `http://127.0.0.1:8686` and log in with user name `qs` and password `1234`:
```
-Please input admin name: quickshare
-password is generated: 2fdc98, please update it after login
-user (quickshare) is created
+docker run \
+ --name quickshare \
+ -d -p :8686:8686 \
+ -v `pwd`/quickshare/root:/quickshare/root \
+ -e DEFAULTADMIN=qs \
+ -e DEFAULTADMINPWD=1234 \
+ hexxa/quickshare:0.3.0
```
-**Accessing**: At last, open your browser and visit `http://127.0.0.1:8686`.
+- `DEFAULTADMIN` is the default user name
+- `DEFAULTADMINPWD` is the default user password
+- `/quickshare/root` is where Quickshare stores files and directories.
+
+### Run from source code
+
+Before start, please ensure Go/Golang (>1.15), Node.js and Yarn are installed on your machine.
+
+```
+# clone this repo
+git clone git@github.com:ihexxa/quickshare.git
+
+# go to repo's folder
+cd quickshare
+
+DEFAULTADMIN=qs DEFAULTADMINPWD=1234 yarn start
+```
+
+OK! Open `http://127.0.0.1:8686` in browser, and log in with user name `qs` and password `1234`.
+
+### Run executable file
+
+- **Downloading**: Download last distribution(s) in [Release Page](https://github.com/ihexxa/quickshare/releases).
+- **Unzipping**: Unzip it and run following command `DEFAULTADMIN=qs DEFAULTADMINPWD=1234 ./quickshare`. (You may update its execution permission: e.g. run `chmod u+x quickshare`)
+- **Accessing**: At last, open `http://127.0.0.1:8686` in browser, and log in with user name `qs` and password `1234`.
### FAQ
diff --git a/cmd/start/main.go b/cmd/start/main.go
index 4e73c2d..07aca62 100644
--- a/cmd/start/main.go
+++ b/cmd/start/main.go
@@ -31,11 +31,14 @@ func main() {
if err != nil {
panic(err)
}
+
if len(opts.Configs) > 0 {
for _, configPath := range opts.Configs {
if strings.HasSuffix(configPath, ".yml") || strings.HasSuffix(configPath, ".yaml") {
+ fmt.Printf("launching config: %s\n", configPath)
cfg, err = cfg.Load(gocfg.YAML(configPath))
} else if strings.HasSuffix(configPath, ".json") {
+ fmt.Printf("launching config: %s\n", configPath)
cfg, err = cfg.Load(gocfg.JSON(configPath))
} else {
panic(fmt.Sprintf("unknown config file type (.yml .yaml .json are supported): %s", configPath))
@@ -62,6 +65,7 @@ func main() {
panic(err)
}
+ fmt.Printf("quickshare is listening %d\n", cfg.GrabInt("Server.Port"))
err = srv.Start()
if err != nil {
panic(err)
diff --git a/configs/docker.yml b/configs/docker.yml
new file mode 100644
index 0000000..d354a60
--- /dev/null
+++ b/configs/docker.yml
@@ -0,0 +1,21 @@
+fs:
+ root: "/quickshare/root"
+ opensLimit: 128
+ openTTL: 60 # 1 min
+secrets:
+ tokenSecret: ""
+server:
+ debug: false
+ host: "0.0.0.0"
+ port: 8686
+ readTimeout: 2000
+ writerTimeout: 86400000 # 1 day
+ maxHeaderBytes: 512
+ publicPath: "/quickshare/public"
+users:
+ enableAuth: true
+ defaultAdmin: ""
+ defaultAdminPwd: ""
+ cookieTTL: 604800 # 1 week
+ cookieSecure: false
+ cookieHttpOnly: true
diff --git a/package.json b/package.json
index 2488b97..08dc5f1 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"src/client/web"
],
"scripts": {
- "build": "scripts/build",
- "start": "go run cmd/start/main.go -c `pwd`/configs/dev.yml"
+ "build": "scripts/build.sh",
+ "start": "cd src/client/web/ && yarn && yarn build && cd ../../.. && go run cmd/start/main.go -c `pwd`/configs/dev.yml"
}
}
diff --git a/scripts/build b/scripts/build.sh
similarity index 100%
rename from scripts/build
rename to scripts/build.sh
diff --git a/scripts/build_be_docker.sh b/scripts/build_be_docker.sh
new file mode 100755
index 0000000..96a3910
--- /dev/null
+++ b/scripts/build_be_docker.sh
@@ -0,0 +1,11 @@
+export QSROOT=`pwd`
+rm -r dist && mkdir dist
+
+# set this for builders behind GFW...
+go env -w GOPROXY=https://goproxy.cn,direct
+go get -d -v ./...
+go get github.com/mitchellh/gox
+cd cmd/start
+gox \
+ -osarch="linux/amd64" \
+ -output "$QSROOT/dist/quickshare/start"
diff --git a/scripts/docker_run.sh b/scripts/docker_run.sh
new file mode 100644
index 0000000..8d81b96
--- /dev/null
+++ b/scripts/docker_run.sh
@@ -0,0 +1,7 @@
+docker run \
+ --name quickshare \
+ -d -p :8686:8686 \
+ -v `pwd`/quickshare/root:/quickshare/root \
+ -e DEFAULTADMIN=qs \
+ -e DEFAULTADMINPWD=1234 \
+ hexxa/quickshare:0.3.0
diff --git a/src/client/web/package.json b/src/client/web/package.json
index 50e15f7..4b4c3e9 100644
--- a/src/client/web/package.json
+++ b/src/client/web/package.json
@@ -4,7 +4,8 @@
"description": "web client for quickshare",
"main": "",
"scripts": {
- "build": "yarn prod:addjs && webpack --config webpack.app.prod.js",
+ "build": "yarn prod:addjs && yarn build:prod:wp",
+ "build:prod:wp": "webpack --config webpack.app.prod.js",
"build:watch": "webpack --config webpack.app.prod.js --watch",
"build:dev": "yarn dev:addjs && webpack --config webpack.app.dev.js --watch",
"test": "jest test --maxWorkers=2",
diff --git a/src/handlers/fileshdr/handlers.go b/src/handlers/fileshdr/handlers.go
index 5f2aa5f..e478134 100644
--- a/src/handlers/fileshdr/handlers.go
+++ b/src/handlers/fileshdr/handlers.go
@@ -46,6 +46,7 @@ type FileHandlers struct {
func NewFileHandlers(cfg gocfg.ICfg, deps *depidx.Deps) (*FileHandlers, error) {
var err error
+
if err = deps.FS().MkdirAll(UploadDir); err != nil {
return nil, err
}
@@ -113,7 +114,7 @@ func (h *FileHandlers) Create(c *gin.Context) {
}
userName := c.MustGet(singleuserhdr.UserParam).(string)
- tmpFilePath := getTmpPath(req.Path)
+ tmpFilePath := h.getTmpPath(req.Path)
locker := h.NewAutoLocker(c, lockName(userName, tmpFilePath))
locker.Exec(func() {
err := h.deps.FS().Create(tmpFilePath)
@@ -261,7 +262,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
}
userName := c.MustGet(singleuserhdr.UserParam).(string)
- tmpFilePath := getTmpPath(req.Path)
+ tmpFilePath := h.getTmpPath(req.Path)
locker := h.NewAutoLocker(c, lockName(userName, tmpFilePath))
locker.Exec(func() {
var err error
@@ -331,7 +332,7 @@ func (h *FileHandlers) UploadStatus(c *gin.Context) {
}
userName := c.MustGet(singleuserhdr.UserParam).(string)
- tmpFilePath := getTmpPath(filePath)
+ tmpFilePath := h.getTmpPath(filePath)
locker := h.NewAutoLocker(c, lockName(userName, tmpFilePath))
locker.Exec(func() {
_, fileSize, uploaded, err := h.uploadMgr.GetInfo(userName, tmpFilePath)
@@ -468,7 +469,7 @@ func (h *FileHandlers) CopyDir(c *gin.Context) {
c.JSON(q.NewMsgResp(501, "Not Implemented"))
}
-func getTmpPath(filePath string) string {
+func (h *FileHandlers) getTmpPath(filePath string) string {
return path.Join(UploadDir, fmt.Sprintf("%x", sha1.Sum([]byte(filePath))))
}
@@ -504,7 +505,7 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
userName := c.MustGet(singleuserhdr.UserParam).(string)
var err error
- tmpFilePath := getTmpPath(filePath)
+ tmpFilePath := h.getTmpPath(filePath)
locker := h.NewAutoLocker(c, lockName(userName, tmpFilePath))
locker.Exec(func() {
err = h.deps.FS().Remove(tmpFilePath)
diff --git a/src/server/config.go b/src/server/config.go
index 49ef828..f1d94dd 100644
--- a/src/server/config.go
+++ b/src/server/config.go
@@ -9,33 +9,33 @@ type FSConfig struct {
}
type UsersCfg struct {
- EnableAuth bool `json:"enableAuth"`
- DefaultAdmin string `json:"defaultAdmin" cfg:"env"`
- DefaultAdminPwd string `json:"defaultAdminPwd" cfg:"env"`
- CookieTTL int `json:"cookieTTL"`
- CookieSecure bool `json:"cookieSecure"`
- CookieHttpOnly bool `json:"cookieHttpOnly"`
+ EnableAuth bool `json:"enableAuth" yaml:"enableAuth"`
+ DefaultAdmin string `json:"defaultAdmin" yaml:"defaultAdmin" cfg:"env"`
+ DefaultAdminPwd string `json:"defaultAdminPwd" yaml:"defaultAdminPwd" cfg:"env"`
+ CookieTTL int `json:"cookieTTL" yaml:"cookieTTL"`
+ CookieSecure bool `json:"cookieSecure" yaml:"cookieSecure"`
+ CookieHttpOnly bool `json:"cookieHttpOnly" yaml:"cookieHttpOnly"`
}
type Secrets struct {
- TokenSecret string `json:"tokenSecret" cfg:"env"`
+ TokenSecret string `json:"tokenSecret" yaml:"tokenSecret" cfg:"env"`
}
type ServerCfg struct {
- Debug bool `json:"debug"`
- Host string `json:"host"`
- Port int `json:"port"`
- ReadTimeout int `json:"readTimeout"`
- WriteTimeout int `json:"writeTimeout"`
- MaxHeaderBytes int `json:"maxHeaderBytes"`
- PublicPath string `json:"publicPath"`
+ Debug bool `json:"debug" yaml:"debug"`
+ Host string `json:"host" yaml:"host"`
+ Port int `json:"port" yaml:"port"`
+ ReadTimeout int `json:"readTimeout" yaml:"readTimeout"`
+ WriteTimeout int `json:"writeTimeout" yaml:"writeTimeout"`
+ MaxHeaderBytes int `json:"maxHeaderBytes" yaml:"maxHeaderBytes"`
+ PublicPath string `json:"publicPath" yaml:"publicPath"`
}
type Config struct {
- Fs *FSConfig `json:"fs"`
- Secrets *Secrets `json:"secrets"`
- Server *ServerCfg `json:"server"`
- Users *UsersCfg `json:"users"`
+ Fs *FSConfig `json:"fs" yaml:"fs"`
+ Secrets *Secrets `json:"secrets" yaml:"secrets"`
+ Server *ServerCfg `json:"server" yaml:"server"`
+ Users *UsersCfg `json:"users" yaml:"users"`
}
func NewConfig() *Config {
@@ -45,7 +45,7 @@ func NewConfig() *Config {
func DefaultConfig() (string, error) {
defaultCfg := &Config{
Fs: &FSConfig{
- Root: ".",
+ Root: "root",
OpensLimit: 128,
OpenTTL: 60, // 1 min
},