From d395245beee5732adfba289b692a3e485a6154bb Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Sun, 6 Nov 2022 01:15:51 +0800 Subject: [PATCH 01/11] feat(server): http file server interface #199 --- go.mod | 3 +++ go.sum | 9 ++++++++ server/httpd/file.go | 53 ++++++++++++++++++++++++++++++++++++++++++++ server/server.go | 45 +++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 server/httpd/file.go diff --git a/go.mod b/go.mod index 4faa2968..a576a736 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/BurntSushi/toml v1.2.1 github.com/a-wing/lightcable v0.1.1 + github.com/djherbis/stow/v4 v4.0.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 @@ -14,11 +15,13 @@ require ( github.com/pion/transport v0.13.1 github.com/pion/turn/v2 v2.0.8 github.com/pion/webrtc/v3 v3.1.47 + github.com/rs/xid v1.4.0 github.com/sb-im/jsonrpc-lite v0.2.0 github.com/schollz/progressbar/v3 v3.12.0 github.com/sirupsen/logrus v1.9.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/spf13/cobra v1.6.1 + go.etcd.io/bbolt v1.3.6 golang.org/x/term v0.1.0 ) diff --git a/go.sum b/go.sum index 4ea0939b..9268f623 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/djherbis/stow/v4 v4.0.0 h1:9ncmiT8vIIGEMVsRWr3IHS+AUXLEcfsgzIrHcsTVpTY= +github.com/djherbis/stow/v4 v4.0.0/go.mod h1:aJlUphKUMWUrtg5FQhbakgaPZ5SNPhzWZ8iSHrwcZI0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -96,6 +98,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sb-im/jsonrpc-lite v0.2.0 h1:r45VX/mESjt6SYBX7V6yIDr3EUWi40EjQIXzz0B0lzo= github.com/sb-im/jsonrpc-lite v0.2.0/go.mod h1:dHV+dbbKl+2+/pDgAavKuAWdEfjGWGck0M7Au+Tkj8Q= @@ -118,6 +122,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -149,7 +156,9 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/server/httpd/file.go b/server/httpd/file.go new file mode 100644 index 00000000..010f835c --- /dev/null +++ b/server/httpd/file.go @@ -0,0 +1,53 @@ +package httpd + +import ( + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "unicode" +) + +type Meta struct { + Name string `json:"name"` + Type string `json:"type"` + Size int64 `json:"size"` + UXID string `json:"uxid"` +} + +func SaveUploadedFile(file *multipart.FileHeader, dst string) error { + src, err := file.Open() + if err != nil { + return err + } + defer src.Close() + + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, src) + return err +} + +func FileAttachment(w http.ResponseWriter, r *http.Request, filepath, filename string) { + if isASCII(filename) { + w.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`) + } else { + w.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename)) + } + http.ServeFile(w, r, filepath) +} + +// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters +func isASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] > unicode.MaxASCII { + return false + } + } + return true +} diff --git a/server/server.go b/server/server.go index a0e4249d..c073619c 100644 --- a/server/server.go +++ b/server/server.go @@ -7,6 +7,7 @@ import ( "io/fs" "log" "net/http" + "path" "filegogo/server/httpd" "filegogo/server/turnd" @@ -14,6 +15,10 @@ import ( "github.com/a-wing/lightcable" "github.com/gorilla/mux" "github.com/pion/webrtc/v3" + "github.com/rs/xid" + + "github.com/djherbis/stow/v4" + bolt "go.etcd.io/bbolt" ) //go:embed build @@ -22,6 +27,12 @@ var dist embed.FS const ( ApiPathConfig = "/config" ApiPathSignal = "/s/" + + ApiPathFileInfo = "/info/" + ApiPathFileRaw = "/raw/" + + dataPath = "tmp" + dbName = "store.db" ) func Run(cfg *Config) { @@ -36,6 +47,13 @@ func Run(cfg *Config) { defer turnSrv.Close() } + db, err := bolt.Open(path.Join(dataPath, dbName), 0600, nil) + if err != nil { + log.Fatal(err) + } + + store := stow.NewJSONStore(db, []byte("room")) + sr := mux.NewRouter() cable := lightcable.New(lightcable.DefaultConfig) @@ -73,6 +91,33 @@ func Run(cfg *Config) { } }) + sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + uxid := xid.New().String() + + f, fh, err := r.FormFile("f") + if err != nil { + return + } + f.Close() + + store.Put(mux.Vars(r)["room"], &httpd.Meta{ + Name: fh.Filename, + Size: fh.Size, + UXID: uxid, + }) + + httpd.SaveUploadedFile(fh, path.Join(dataPath, uxid)) + + }).Methods(http.MethodPost) + + sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + room := mux.Vars(r)["room"] + var m httpd.Meta + store.Get(room, &m) + + httpd.FileAttachment(w, r, path.Join(dataPath, m.UXID), m.Name) + }).Methods(http.MethodGet) + fsys, err := fs.Sub(dist, "build") if err != nil { log.Fatal(err) From bd1a7018bf23bd58688f504fd8a52b599f23241f Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Sun, 6 Nov 2022 11:30:01 +0800 Subject: [PATCH 02/11] feat(server): tmp file storage #199 --- .gitignore | 1 + README.md | 16 ++++++++-------- cmd/server.go | 2 ++ conf/filegogo.toml | 3 +++ server/httpd/room.go | 2 ++ server/server.go | 14 ++++++++------ 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 6df6bd22..97c9170a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /filegogo-server.toml bin +data build node_modules diff --git a/README.md b/README.md index 699a4862..1c69332f 100644 --- a/README.md +++ b/README.md @@ -41,14 +41,6 @@ make ## Run Development -### Server - -```bash - -# Default Listen port: 8080 -go run ./main.go server -``` - ### Webapp ```bash @@ -60,6 +52,14 @@ npm install npm run dev ``` +### Server + +```bash + +# Default Listen port: 8080 +go run ./main.go server +``` + ### Client > run cli client. For example: diff --git a/cmd/server.go b/cmd/server.go index 02c8c5b2..5ca1d185 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -21,6 +21,8 @@ var serverCmd = &cobra.Command{ Listen: "0.0.0.0:8080", RoomAlive: 1024, RoomCount: 10000, + + StoragePath: "data", }, } diff --git a/conf/filegogo.toml b/conf/filegogo.toml index 3da177f0..cfbc9a3c 100644 --- a/conf/filegogo.toml +++ b/conf/filegogo.toml @@ -9,6 +9,9 @@ roomAlive = 1024 # room id: [0 - 9999] roomCount = 10000 +# http file relay storage +storagePath = "data" + # Enable Built-in turn server #[turn] diff --git a/server/httpd/room.go b/server/httpd/room.go index 9ad13a84..2c290efe 100644 --- a/server/httpd/room.go +++ b/server/httpd/room.go @@ -22,6 +22,8 @@ type Config struct { Listen string RoomAlive int RoomCount int + + StoragePath string } type Server struct { diff --git a/server/server.go b/server/server.go index c073619c..f9f9a0e6 100644 --- a/server/server.go +++ b/server/server.go @@ -7,6 +7,7 @@ import ( "io/fs" "log" "net/http" + "os" "path" "filegogo/server/httpd" @@ -31,8 +32,7 @@ const ( ApiPathFileInfo = "/info/" ApiPathFileRaw = "/raw/" - dataPath = "tmp" - dbName = "store.db" + dbName = "store.db" ) func Run(cfg *Config) { @@ -46,12 +46,14 @@ func Run(cfg *Config) { } defer turnSrv.Close() } + if err := os.MkdirAll(cfg.Http.StoragePath, os.ModePerm); err != nil { + log.Fatal(err) + } - db, err := bolt.Open(path.Join(dataPath, dbName), 0600, nil) + db, err := bolt.Open(path.Join(cfg.Http.StoragePath, dbName), 0600, nil) if err != nil { log.Fatal(err) } - store := stow.NewJSONStore(db, []byte("room")) sr := mux.NewRouter() @@ -106,7 +108,7 @@ func Run(cfg *Config) { UXID: uxid, }) - httpd.SaveUploadedFile(fh, path.Join(dataPath, uxid)) + httpd.SaveUploadedFile(fh, path.Join(cfg.Http.StoragePath, uxid)) }).Methods(http.MethodPost) @@ -115,7 +117,7 @@ func Run(cfg *Config) { var m httpd.Meta store.Get(room, &m) - httpd.FileAttachment(w, r, path.Join(dataPath, m.UXID), m.Name) + httpd.FileAttachment(w, r, path.Join(cfg.Http.StoragePath, m.UXID), m.Name) }).Methods(http.MethodGet) fsys, err := fs.Sub(dist, "build") From 5ef2be4a8dab4f2f20448080aa6a93f8ffda8212 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Fri, 2 Dec 2022 00:07:54 +0800 Subject: [PATCH 03/11] feat(webapp): upload button #199 --- vite.config.ts | 1 + webapp/components/File.tsx | 5 +++-- webapp/components/index.tsx | 2 ++ webapp/components/upload.module.scss | 20 ++++++++++++++++++++ webapp/components/upload.tsx | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 webapp/components/upload.module.scss create mode 100644 webapp/components/upload.tsx diff --git a/vite.config.ts b/vite.config.ts index 7f5a7325..dd1d8b91 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,6 +7,7 @@ export default defineConfig({ port: 3000, proxy: { '/s': 'http://localhost:8080', + '^/raw/.*': 'http://localhost:8080', '/config': 'http://localhost:8080', '^/s/.*': { target: 'ws://localhost:8080', diff --git a/webapp/components/File.tsx b/webapp/components/File.tsx index d986dbcc..b940c265 100644 --- a/webapp/components/File.tsx +++ b/webapp/components/File.tsx @@ -23,7 +23,7 @@ function File(props: { } return ( - <> +
@@ -32,10 +32,11 @@ function File(props: { // This id e2e test need id="upload" type="file" + name="f" ref={ hiddenFileInput } onChange={ (ev: ChangeEvent) => { handleFile(ev.target.files) } } /> - + ) } diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index 8b385d5d..d929305a 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -10,6 +10,7 @@ import Address from './Address' import File from './File' import Qrcode from './QRCode' import Card from './card' +import Upload from './upload' import { DomSendFile, DomRecvFile } from '../libfgg/pool/file/dom' @@ -92,6 +93,7 @@ function Index(props: { address: string }) { handleFile={ (files: any) => { handleFile(files) } } getFile={ getfile } > + ) } diff --git a/webapp/components/upload.module.scss b/webapp/components/upload.module.scss new file mode 100644 index 00000000..51acd92b --- /dev/null +++ b/webapp/components/upload.module.scss @@ -0,0 +1,20 @@ +.button { + width: 100%; + border: 1px solid #ccc; + display: inline-block; + padding: 10px 0px; + cursor: pointer; + text-align: center; + border-radius: 5px; + color: white; + font-size: calc(10px + 2vmin); +} + +.button:hover { + border: 1px solid #0bffa5; +} + +.button:active { + box-shadow: 0 5px #666; + transform: translateY(5px); +} diff --git a/webapp/components/upload.tsx b/webapp/components/upload.tsx new file mode 100644 index 00000000..2af7076d --- /dev/null +++ b/webapp/components/upload.tsx @@ -0,0 +1,19 @@ +import styles from './upload.module.scss' + +function Upload(props: { name: string, file: any }) { + const send = () => { + const form = document.getElementById('form-upload') + const formData = new FormData(form as HTMLFormElement) + const xhr = new XMLHttpRequest() + xhr.open("POST", `/raw/${props.name}`, true) + xhr.send(formData) + } + + return ( + <> + + + ) +} + +export default Upload From d2b4fd8d46cd4e686d71ab0b3142a7d4e7dacd1e Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Sat, 3 Dec 2022 00:02:33 +0800 Subject: [PATCH 04/11] feat(webapp): download button #199 --- webapp/components/download.tsx | 15 +++++++++++++++ webapp/components/index.tsx | 18 +++++++++++------- webapp/components/upload.module.scss | 1 + 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 webapp/components/download.tsx diff --git a/webapp/components/download.tsx b/webapp/components/download.tsx new file mode 100644 index 00000000..014510f3 --- /dev/null +++ b/webapp/components/download.tsx @@ -0,0 +1,15 @@ +import styles from './upload.module.scss' + +function Download(props: { name: string }) { + const send = () => { + window.open(`/raw/${props.name}`) + } + + return ( + <> + + + ) +} + +export default Download diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index d929305a..bf403063 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -13,6 +13,7 @@ import Card from './card' import Upload from './upload' import { DomSendFile, DomRecvFile } from '../libfgg/pool/file/dom' +import Download from './download' const fgg = new LibFgg() let enabled = true @@ -87,13 +88,16 @@ function Index(props: { address: string }) {
} - { handleFile(files) } } - getFile={ getfile } - > - +
+ { handleFile(files) } } + getFile={ getfile } + > + + +
) } diff --git a/webapp/components/upload.module.scss b/webapp/components/upload.module.scss index 51acd92b..e93490f8 100644 --- a/webapp/components/upload.module.scss +++ b/webapp/components/upload.module.scss @@ -3,6 +3,7 @@ border: 1px solid #ccc; display: inline-block; padding: 10px 0px; + background-color: #f14668; cursor: pointer; text-align: center; border-radius: 5px; From 58d423aa7708cb596733f2b878ae60708a35a41a Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Sun, 4 Dec 2022 00:48:14 +0800 Subject: [PATCH 05/11] feat(server): add relay file info #199 --- server/server.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/server.go b/server/server.go index f9f9a0e6..26d8c812 100644 --- a/server/server.go +++ b/server/server.go @@ -93,6 +93,14 @@ func Run(cfg *Config) { } }) + sr.HandleFunc(ApiPathFileInfo+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + room := mux.Vars(r)["room"] + var m httpd.Meta + store.Get(room, &m) + data, _ := json.Marshal(m) + w.Header().Add("Content-type", "application/json") + w.Write(data) + }) sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { uxid := xid.New().String() From 82d89175a88c89bcbf3386d136f334d821853a27 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Wed, 7 Dec 2022 20:50:28 +0800 Subject: [PATCH 06/11] refactor(webapp): add relay file #199 --- webapp/components/File.tsx | 11 ++++++++--- webapp/components/download.tsx | 15 --------------- webapp/components/index.tsx | 4 ---- webapp/components/upload.module.scss | 21 --------------------- webapp/components/upload.tsx | 19 ------------------- webapp/lib/api.ts | 21 +++++++++++++++++++++ 6 files changed, 29 insertions(+), 62 deletions(-) delete mode 100644 webapp/components/download.tsx delete mode 100644 webapp/components/upload.module.scss delete mode 100644 webapp/components/upload.tsx diff --git a/webapp/components/File.tsx b/webapp/components/File.tsx index b940c265..a1efdaf0 100644 --- a/webapp/components/File.tsx +++ b/webapp/components/File.tsx @@ -1,5 +1,8 @@ import { useRef, useState, ChangeEvent } from 'react' import styles from './File.module.scss' +import { putRawFile, getRawFile } from '../lib/api' + +let tmp: File | undefined function File(props: { recver: boolean, @@ -23,7 +26,7 @@ function File(props: { } return ( -
+ <> @@ -34,9 +37,11 @@ function File(props: { type="file" name="f" ref={ hiddenFileInput } - onChange={ (ev: ChangeEvent) => { handleFile(ev.target.files) } } + onChange={ (ev: ChangeEvent) => { handleFile(ev.target.files); tmp = ev.target.files?.[0] } } /> - + + + ) } diff --git a/webapp/components/download.tsx b/webapp/components/download.tsx deleted file mode 100644 index 014510f3..00000000 --- a/webapp/components/download.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import styles from './upload.module.scss' - -function Download(props: { name: string }) { - const send = () => { - window.open(`/raw/${props.name}`) - } - - return ( - <> - - - ) -} - -export default Download diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index bf403063..fe059ff4 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -10,10 +10,8 @@ import Address from './Address' import File from './File' import Qrcode from './QRCode' import Card from './card' -import Upload from './upload' import { DomSendFile, DomRecvFile } from '../libfgg/pool/file/dom' -import Download from './download' const fgg = new LibFgg() let enabled = true @@ -95,8 +93,6 @@ function Index(props: { address: string }) { handleFile={ (files: any) => { handleFile(files) } } getFile={ getfile } > - - ) diff --git a/webapp/components/upload.module.scss b/webapp/components/upload.module.scss deleted file mode 100644 index e93490f8..00000000 --- a/webapp/components/upload.module.scss +++ /dev/null @@ -1,21 +0,0 @@ -.button { - width: 100%; - border: 1px solid #ccc; - display: inline-block; - padding: 10px 0px; - background-color: #f14668; - cursor: pointer; - text-align: center; - border-radius: 5px; - color: white; - font-size: calc(10px + 2vmin); -} - -.button:hover { - border: 1px solid #0bffa5; -} - -.button:active { - box-shadow: 0 5px #666; - transform: translateY(5px); -} diff --git a/webapp/components/upload.tsx b/webapp/components/upload.tsx deleted file mode 100644 index 2af7076d..00000000 --- a/webapp/components/upload.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import styles from './upload.module.scss' - -function Upload(props: { name: string, file: any }) { - const send = () => { - const form = document.getElementById('form-upload') - const formData = new FormData(form as HTMLFormElement) - const xhr = new XMLHttpRequest() - xhr.open("POST", `/raw/${props.name}`, true) - xhr.send(formData) - } - - return ( - <> - - - ) -} - -export default Upload diff --git a/webapp/lib/api.ts b/webapp/lib/api.ts index d74ccc86..029ec753 100644 --- a/webapp/lib/api.ts +++ b/webapp/lib/api.ts @@ -26,10 +26,31 @@ async function getRoom(): Promise { return result.room || '' } +async function putRawFile(f: File): Promise { + const room = shareGetRoom(window.location.href) + if (room === '') throw "not room" + + let formData = new FormData() + formData.append('f', f, f.name) + await fetch(`/raw/${room}`, { + method: "post", + body: formData, + }) + return +} + +async function getRawFile(): Promise { + const room = shareGetRoom(window.location.href) + window.open(`/raw/${room}`) +} + + export { getServer, getConfig, getRoom, getLogLevel, + putRawFile, + getRawFile, shareGetRoom, } From db0906392131dae58308e8ab6b6923ab787a5bbf Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Thu, 8 Dec 2022 16:42:49 +0800 Subject: [PATCH 07/11] refactor(webapp): add relay file info #199 --- server/server.go | 12 ++++++++---- vite.config.ts | 9 ++++++--- webapp/components/File.tsx | 6 ++++-- webapp/components/index.tsx | 16 ++++++++++++++-- webapp/lib/api.ts | 8 ++++++++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/server/server.go b/server/server.go index 26d8c812..cfcf9fd8 100644 --- a/server/server.go +++ b/server/server.go @@ -96,10 +96,14 @@ func Run(cfg *Config) { sr.HandleFunc(ApiPathFileInfo+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { room := mux.Vars(r)["room"] var m httpd.Meta - store.Get(room, &m) - data, _ := json.Marshal(m) - w.Header().Add("Content-type", "application/json") - w.Write(data) + err := store.Get(room, &m) + if err != nil { + w.WriteHeader(http.StatusNotFound) + } else { + data, _ := json.Marshal(m) + w.Header().Add("Content-type", "application/json") + w.Write(data) + } }) sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { uxid := xid.New().String() diff --git a/vite.config.ts b/vite.config.ts index dd1d8b91..65c7d904 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,13 +2,16 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ + +const server = 'http://localhost:8080' export default defineConfig({ server: { port: 3000, proxy: { - '/s': 'http://localhost:8080', - '^/raw/.*': 'http://localhost:8080', - '/config': 'http://localhost:8080', + '/s': server, + '^/raw/.*': server, + '^/info/.*': server, + '/config': server, '^/s/.*': { target: 'ws://localhost:8080', ws: true, diff --git a/webapp/components/File.tsx b/webapp/components/File.tsx index a1efdaf0..eca832d9 100644 --- a/webapp/components/File.tsx +++ b/webapp/components/File.tsx @@ -39,8 +39,10 @@ function File(props: { ref={ hiddenFileInput } onChange={ (ev: ChangeEvent) => { handleFile(ev.target.files); tmp = ev.target.files?.[0] } } /> - - +
+ + +
) } diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index fe059ff4..7dc157fe 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react' import { ProtoHttpToWs } from '../lib/util' -import { getServer, getConfig, shareGetRoom } from '../lib/api' +import { getServer, getConfig, shareGetRoom, getRawInfo } from '../lib/api' import LibFgg from '../libfgg/libfgg' import log from 'loglevel' import { Meta } from '../libfgg/pool/data' @@ -77,9 +77,21 @@ function Index(props: { address: string }) { } }, [props.address]) + useEffect(() => { + const load = async () => { + + let data = await getRawInfo() + console.log(data) + if (data) { + setMeta(data) + } + } + load() + }, [props.address]) + return ( <> - { recver && meta + { meta ? : <> diff --git a/webapp/lib/api.ts b/webapp/lib/api.ts index 029ec753..df56a0d6 100644 --- a/webapp/lib/api.ts +++ b/webapp/lib/api.ts @@ -44,6 +44,13 @@ async function getRawFile(): Promise { window.open(`/raw/${room}`) } +async function getRawInfo(): Promise { + const room = shareGetRoom(window.location.href) + const response = await fetch(`/info/${room}`) + if (response.status == 200) { + return await response.json() + } +} export { getServer, @@ -52,5 +59,6 @@ export { getLogLevel, putRawFile, getRawFile, + getRawInfo, shareGetRoom, } From 725aad42fe7983532c2fcb3b33878ce11ca5a8c2 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Thu, 8 Dec 2022 17:06:16 +0800 Subject: [PATCH 08/11] feat(server): add file mime type #199 --- go.mod | 1 + go.sum | 2 ++ server/server.go | 3 +++ 3 files changed, 6 insertions(+) diff --git a/go.mod b/go.mod index a576a736..fc3b188d 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/pion/transport v0.13.1 github.com/pion/turn/v2 v2.0.8 github.com/pion/webrtc/v3 v3.1.47 + github.com/qingstor/go-mime v0.1.0 github.com/rs/xid v1.4.0 github.com/sb-im/jsonrpc-lite v0.2.0 github.com/schollz/progressbar/v3 v3.12.0 diff --git a/go.sum b/go.sum index 9268f623..bcd32b6b 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/pion/webrtc/v3 v3.1.47 h1:2dFEKRI1rzFvehXDq43hK9OGGyTGJSusUi3j6QKHC5s github.com/pion/webrtc/v3 v3.1.47/go.mod h1:8U39MYZCLVV4sIBn01htASVNkWQN2zDa/rx5xisEXWs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/qingstor/go-mime v0.1.0 h1:FhTJtM7TRm9pfgCXpjGUxqwbumGojrgE9ecRz5PXvfc= +github.com/qingstor/go-mime v0.1.0/go.mod h1:EDwWgaMufg74m7futsF0ZGkdA52ajjAycY+XDeV8M88= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= diff --git a/server/server.go b/server/server.go index cfcf9fd8..5cfe6dd5 100644 --- a/server/server.go +++ b/server/server.go @@ -9,6 +9,7 @@ import ( "net/http" "os" "path" + "strings" "filegogo/server/httpd" "filegogo/server/turnd" @@ -16,6 +17,7 @@ import ( "github.com/a-wing/lightcable" "github.com/gorilla/mux" "github.com/pion/webrtc/v3" + "github.com/qingstor/go-mime" "github.com/rs/xid" "github.com/djherbis/stow/v4" @@ -117,6 +119,7 @@ func Run(cfg *Config) { store.Put(mux.Vars(r)["room"], &httpd.Meta{ Name: fh.Filename, Size: fh.Size, + Type: mime.DetectFileExt(strings.TrimPrefix(path.Ext(fh.Filename), ".")), UXID: uxid, }) From 237121397828e02660533bf025213caa2025f821 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Thu, 8 Dec 2022 18:47:21 +0800 Subject: [PATCH 09/11] feat(server): add relay file delete #199 --- server/server.go | 20 +++++++++++++++----- vite.config.ts | 3 +-- webapp/components/File.tsx | 34 +++++++++++++++++++++++++--------- webapp/components/index.tsx | 10 ++++++---- webapp/lib/api.ts | 26 +++++++++++++++++--------- 5 files changed, 64 insertions(+), 29 deletions(-) diff --git a/server/server.go b/server/server.go index 5cfe6dd5..8fc699a0 100644 --- a/server/server.go +++ b/server/server.go @@ -31,8 +31,8 @@ const ( ApiPathConfig = "/config" ApiPathSignal = "/s/" - ApiPathFileInfo = "/info/" - ApiPathFileRaw = "/raw/" + ApiPathBoxInfo = "/api/info/" + ApiPathBoxFile = "/api/file/" dbName = "store.db" ) @@ -95,7 +95,7 @@ func Run(cfg *Config) { } }) - sr.HandleFunc(ApiPathFileInfo+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + sr.HandleFunc(ApiPathBoxInfo+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { room := mux.Vars(r)["room"] var m httpd.Meta err := store.Get(room, &m) @@ -107,7 +107,8 @@ func Run(cfg *Config) { w.Write(data) } }) - sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + + sr.HandleFunc(ApiPathBoxFile+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { uxid := xid.New().String() f, fh, err := r.FormFile("f") @@ -127,7 +128,7 @@ func Run(cfg *Config) { }).Methods(http.MethodPost) - sr.HandleFunc(ApiPathFileRaw+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + sr.HandleFunc(ApiPathBoxFile+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { room := mux.Vars(r)["room"] var m httpd.Meta store.Get(room, &m) @@ -135,6 +136,15 @@ func Run(cfg *Config) { httpd.FileAttachment(w, r, path.Join(cfg.Http.StoragePath, m.UXID), m.Name) }).Methods(http.MethodGet) + sr.HandleFunc(ApiPathBoxFile+"{room:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { + room := mux.Vars(r)["room"] + var m httpd.Meta + store.Get(room, &m) + store.Delete(room) + os.Remove(path.Join(cfg.Http.StoragePath, m.UXID)) + + }).Methods(http.MethodDelete) + fsys, err := fs.Sub(dist, "build") if err != nil { log.Fatal(err) diff --git a/vite.config.ts b/vite.config.ts index 65c7d904..89de6355 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,8 +9,7 @@ export default defineConfig({ port: 3000, proxy: { '/s': server, - '^/raw/.*': server, - '^/info/.*': server, + '^/api/.*': server, '/config': server, '^/s/.*': { target: 'ws://localhost:8080', diff --git a/webapp/components/File.tsx b/webapp/components/File.tsx index eca832d9..c5016ad7 100644 --- a/webapp/components/File.tsx +++ b/webapp/components/File.tsx @@ -1,20 +1,28 @@ import { useRef, useState, ChangeEvent } from 'react' import styles from './File.module.scss' -import { putRawFile, getRawFile } from '../lib/api' +import { putBoxFile, getBoxFile, delBoxFile } from '../lib/api' let tmp: File | undefined function File(props: { recver: boolean, + isBox: boolean, percent: number, handleFile: (files: FileList | null) => void, getFile: () => void }) { const hiddenFileInput = useRef(null) const handleClick = () => { - props.recver - ? props.getFile() - : hiddenFileInput.current?.click?.() + if (props.recver) { + if (props.isBox) { + getBoxFile() + } else { + props.getFile() + } + } else { + hiddenFileInput.current?.click?.() + } + } const [filename, setFilename] = useState('Select File') @@ -35,14 +43,22 @@ function File(props: { // This id e2e test need id="upload" type="file" - name="f" ref={ hiddenFileInput } onChange={ (ev: ChangeEvent) => { handleFile(ev.target.files); tmp = ev.target.files?.[0] } } /> -
- - -
+ + { props.recver + ? + : + } ) } diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index 7dc157fe..dc5d56f4 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react' import { ProtoHttpToWs } from '../lib/util' -import { getServer, getConfig, shareGetRoom, getRawInfo } from '../lib/api' +import { getServer, getConfig, shareGetRoom, getBoxInfo } from '../lib/api' import LibFgg from '../libfgg/libfgg' import log from 'loglevel' import { Meta } from '../libfgg/pool/data' @@ -22,6 +22,7 @@ function Index(props: { address: string }) { const [meta, setMeta] = useState(null) const [progress, setProgress] = useState(0) const [recver, setRecver] = useState(false) + const [isBox, setIsBox] = useState(false) const refIce = useRef([]) @@ -79,11 +80,11 @@ function Index(props: { address: string }) { useEffect(() => { const load = async () => { - - let data = await getRawInfo() - console.log(data) + let data = await getBoxInfo() if (data) { setMeta(data) + setIsBox(true) + setRecver(true) } } load() @@ -101,6 +102,7 @@ function Index(props: { address: string }) {
{ handleFile(files) } } getFile={ getfile } diff --git a/webapp/lib/api.ts b/webapp/lib/api.ts index df56a0d6..a298ecf5 100644 --- a/webapp/lib/api.ts +++ b/webapp/lib/api.ts @@ -26,27 +26,34 @@ async function getRoom(): Promise { return result.room || '' } -async function putRawFile(f: File): Promise { +async function putBoxFile(f: File): Promise { const room = shareGetRoom(window.location.href) if (room === '') throw "not room" let formData = new FormData() formData.append('f', f, f.name) - await fetch(`/raw/${room}`, { + await fetch(`/api/file/${room}`, { method: "post", body: formData, }) return } -async function getRawFile(): Promise { +async function getBoxFile(): Promise { const room = shareGetRoom(window.location.href) - window.open(`/raw/${room}`) + window.open(`/api/file/${room}`) } -async function getRawInfo(): Promise { +async function delBoxFile(): Promise { const room = shareGetRoom(window.location.href) - const response = await fetch(`/info/${room}`) + await fetch(`/api/file/${room}`, { + method: "delete", + }) +} + +async function getBoxInfo(): Promise { + const room = shareGetRoom(window.location.href) + const response = await fetch(`/api/info/${room}`) if (response.status == 200) { return await response.json() } @@ -57,8 +64,9 @@ export { getConfig, getRoom, getLogLevel, - putRawFile, - getRawFile, - getRawInfo, + putBoxFile, + getBoxFile, + delBoxFile, + getBoxInfo, shareGetRoom, } From a3a48d1b20d85ab0a6c4b77e9eaeeb9867eed3a1 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Thu, 8 Dec 2022 19:38:05 +0800 Subject: [PATCH 10/11] feat(webapp): add reload #199 --- webapp/components/File.tsx | 12 ++++++++++-- webapp/components/index.tsx | 21 +++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/webapp/components/File.tsx b/webapp/components/File.tsx index c5016ad7..90a426a0 100644 --- a/webapp/components/File.tsx +++ b/webapp/components/File.tsx @@ -7,6 +7,7 @@ let tmp: File | undefined function File(props: { recver: boolean, isBox: boolean, + reLoad: () => void, percent: number, handleFile: (files: FileList | null) => void, getFile: () => void }) { @@ -51,12 +52,19 @@ function File(props: { ? : } diff --git a/webapp/components/index.tsx b/webapp/components/index.tsx index dc5d56f4..42f89d7e 100644 --- a/webapp/components/index.tsx +++ b/webapp/components/index.tsx @@ -78,15 +78,19 @@ function Index(props: { address: string }) { } }, [props.address]) - useEffect(() => { - const load = async () => { - let data = await getBoxInfo() - if (data) { - setMeta(data) - setIsBox(true) - setRecver(true) - } + const load = async () => { + let data = await getBoxInfo() + if (data) { + setMeta(data) + setIsBox(true) + setRecver(true) + } else { + setIsBox(false) + setRecver(false) + setMeta(null) } + } + useEffect(() => { load() }, [props.address]) @@ -103,6 +107,7 @@ function Index(props: { address: string }) { { handleFile(files) } } getFile={ getfile } From 446ff0b209350ffbacc77648abef70d6ed282254 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Sat, 10 Dec 2022 13:26:20 +0800 Subject: [PATCH 11/11] chore(deps): update gomod --- go.mod | 24 +++++++++++------------ go.sum | 62 +++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index fc3b188d..2255369e 100644 --- a/go.mod +++ b/go.mod @@ -12,28 +12,28 @@ require ( github.com/pion/datachannel v1.5.2 github.com/pion/logging v0.2.2 github.com/pion/sctp v1.8.3 - github.com/pion/transport v0.13.1 - github.com/pion/turn/v2 v2.0.8 - github.com/pion/webrtc/v3 v3.1.47 + github.com/pion/transport v0.14.1 + github.com/pion/turn/v2 v2.0.9 + github.com/pion/webrtc/v3 v3.1.49 github.com/qingstor/go-mime v0.1.0 github.com/rs/xid v1.4.0 github.com/sb-im/jsonrpc-lite v0.2.0 - github.com/schollz/progressbar/v3 v3.12.0 + github.com/schollz/progressbar/v3 v3.12.2 github.com/sirupsen/logrus v1.9.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/spf13/cobra v1.6.1 go.etcd.io/bbolt v1.3.6 - golang.org/x/term v0.1.0 + golang.org/x/term v0.3.0 ) require ( github.com/google/uuid v1.3.0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/pion/dtls/v2 v2.1.5 // indirect - github.com/pion/ice/v2 v2.2.11 // indirect - github.com/pion/interceptor v0.1.11 // indirect + github.com/pion/ice/v2 v2.2.12 // indirect + github.com/pion/interceptor v0.1.12 // indirect github.com/pion/mdns v0.0.5 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.10 // indirect @@ -42,9 +42,9 @@ require ( github.com/pion/srtp/v2 v2.0.10 // indirect github.com/pion/stun v0.3.5 // indirect github.com/pion/udp v0.1.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect + github.com/rivo/uniseg v0.4.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect - golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/crypto v0.4.0 // indirect + golang.org/x/net v0.4.0 // indirect + golang.org/x/sys v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index bcd32b6b..dc5a1516 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,9 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -57,10 +58,11 @@ github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6 github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c= github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY= -github.com/pion/ice/v2 v2.2.11 h1:wiAy7TSrVZ4KdyjC0CcNTkwltz9ywetbe4wbHLKUbIg= -github.com/pion/ice/v2 v2.2.11/go.mod h1:NqUDUao6SjSs1+4jrqpexDmFlptlVhGxQjcymXLaVvE= -github.com/pion/interceptor v0.1.11 h1:00U6OlqxA3FFB50HSg25J/8cWi7P6FbSzw4eFn24Bvs= +github.com/pion/ice/v2 v2.2.12 h1:n3M3lUMKQM5IoofhJo73D3qVla+mJN2nVvbSPq32Nig= +github.com/pion/ice/v2 v2.2.12/go.mod h1:z2KXVFyRkmjetRlaVRgjO9U3ShKwzhlUylvxKfHfd5A= github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8= +github.com/pion/interceptor v0.1.12 h1:CslaNriCFUItiXS5o+hh5lpL0t0ytQkFnUcbbCs2Zq8= +github.com/pion/interceptor v0.1.12/go.mod h1:bDtgAD9dRkBZpWHGKaoKb42FhDHTG2rX8Ii9LRALLVA= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw= @@ -73,7 +75,6 @@ github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA= github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= -github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= github.com/pion/sctp v1.8.3 h1:LWcciN2ptLkw9Ugp/Ks2E76fiWy7yk3Wm79D6oFbFNo= github.com/pion/sctp v1.8.3/go.mod h1:OHbDjdk7kg+L+7TJim9q/qGVefdEJohuA2SZyihccgI= github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw= @@ -85,28 +86,30 @@ github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2U github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g= -github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA= github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg= -github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw= +github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40= +github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI= github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= +github.com/pion/turn/v2 v2.0.9 h1:jcDPw0Vfd5I4iTc7s0Upfc2aMnyu2lgJ9vV0SUrNC1o= +github.com/pion/turn/v2 v2.0.9/go.mod h1:DQlwUwx7hL8Xya6TTAabbd9DdKXTNR96Xf5g5Qqso/M= github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o= github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= -github.com/pion/webrtc/v3 v3.1.47 h1:2dFEKRI1rzFvehXDq43hK9OGGyTGJSusUi3j6QKHC5s= -github.com/pion/webrtc/v3 v3.1.47/go.mod h1:8U39MYZCLVV4sIBn01htASVNkWQN2zDa/rx5xisEXWs= +github.com/pion/webrtc/v3 v3.1.49 h1:rbsNGxK9jMYts+xE6zYAJMUQHnGwmk/JYze8yttW+to= +github.com/pion/webrtc/v3 v3.1.49/go.mod h1:kHf/o47QW4No1rgpsFux/h7lUhtUnwFnSFDZOXeLapw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/qingstor/go-mime v0.1.0 h1:FhTJtM7TRm9pfgCXpjGUxqwbumGojrgE9ecRz5PXvfc= github.com/qingstor/go-mime v0.1.0/go.mod h1:EDwWgaMufg74m7futsF0ZGkdA52ajjAycY+XDeV8M88= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sb-im/jsonrpc-lite v0.2.0 h1:r45VX/mESjt6SYBX7V6yIDr3EUWi40EjQIXzz0B0lzo= github.com/sb-im/jsonrpc-lite v0.2.0/go.mod h1:dHV+dbbKl+2+/pDgAavKuAWdEfjGWGck0M7Au+Tkj8Q= -github.com/schollz/progressbar/v3 v3.12.0 h1:BVFNM+V/l20JUYkJ5fO/CnOYPV3Et3tON8FmJepkdq4= -github.com/schollz/progressbar/v3 v3.12.0/go.mod h1:g7QSuwyGpqCjVQPFZXA31MSxtrhka9Y9LMdF+XT77/Y= +github.com/schollz/progressbar/v3 v3.12.2 h1:yLqqqpQNMxGxHY8uEshRihaHWwa0rf0yb7/Zrpgq2C0= +github.com/schollz/progressbar/v3 v3.12.2/go.mod h1:HFJYIYQQJX32UJdyoigUl19xoV6aMwZt6iX/C30RWfg= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -117,23 +120,31 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI= golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= +golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -141,17 +152,20 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= -golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -171,22 +185,26 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=