Skip to content

Commit

Permalink
Merge pull request #218 from a-wing/dev
Browse files Browse the repository at this point in the history
add http file relay
  • Loading branch information
a-wing authored Dec 10, 2022
2 parents f63a912 + 446ff0b commit 16bee14
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 56 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/filegogo-server.toml

bin
data
build
node_modules

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,6 @@ make

## Run Development

### Server

```bash

# Default Listen port: 8080
go run ./main.go server
```

### Webapp

```bash
Expand All @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ var serverCmd = &cobra.Command{
Listen: "0.0.0.0:8080",
RoomAlive: 1024,
RoomCount: 10000,

StoragePath: "data",
},
}

Expand Down
3 changes: 3 additions & 0 deletions conf/filegogo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ roomAlive = 1024
# room id: [0 - 9999]
roomCount = 10000

# http file relay storage
storagePath = "data"

# Enable Built-in turn server
#[turn]

Expand Down
28 changes: 16 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,35 @@ 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
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
golang.org/x/term v0.1.0
go.etcd.io/bbolt v1.3.6
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
Expand All @@ -38,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
)
73 changes: 51 additions & 22 deletions go.sum

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions server/httpd/file.go
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 2 additions & 0 deletions server/httpd/room.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Config struct {
Listen string
RoomAlive int
RoomCount int

StoragePath string
}

type Server struct {
Expand Down
72 changes: 72 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ import (
"io/fs"
"log"
"net/http"
"os"
"path"
"strings"

"filegogo/server/httpd"
"filegogo/server/turnd"

"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"
bolt "go.etcd.io/bbolt"
)

//go:embed build
Expand All @@ -22,6 +30,11 @@ var dist embed.FS
const (
ApiPathConfig = "/config"
ApiPathSignal = "/s/"

ApiPathBoxInfo = "/api/info/"
ApiPathBoxFile = "/api/file/"

dbName = "store.db"
)

func Run(cfg *Config) {
Expand All @@ -35,6 +48,15 @@ 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(cfg.Http.StoragePath, dbName), 0600, nil)
if err != nil {
log.Fatal(err)
}
store := stow.NewJSONStore(db, []byte("room"))

sr := mux.NewRouter()

Expand Down Expand Up @@ -73,6 +95,56 @@ func Run(cfg *Config) {
}
})

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)
if err != nil {
w.WriteHeader(http.StatusNotFound)
} else {
data, _ := json.Marshal(m)
w.Header().Add("Content-type", "application/json")
w.Write(data)
}
})

sr.HandleFunc(ApiPathBoxFile+"{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,
Type: mime.DetectFileExt(strings.TrimPrefix(path.Ext(fh.Filename), ".")),
UXID: uxid,
})

httpd.SaveUploadedFile(fh, path.Join(cfg.Http.StoragePath, uxid))

}).Methods(http.MethodPost)

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)

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)
Expand Down
7 changes: 5 additions & 2 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ 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',
'/config': 'http://localhost:8080',
'/s': server,
'^/api/.*': server,
'/config': server,
'^/s/.*': {
target: 'ws://localhost:8080',
ws: true,
Expand Down
40 changes: 36 additions & 4 deletions webapp/components/File.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import { useRef, useState, ChangeEvent } from 'react'
import styles from './File.module.scss'
import { putBoxFile, getBoxFile, delBoxFile } from '../lib/api'

let tmp: File | undefined

function File(props: {
recver: boolean,
isBox: boolean,
reLoad: () => void,
percent: number,
handleFile: (files: FileList | null) => void,
getFile: () => void }) {

const hiddenFileInput = useRef<HTMLInputElement>(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')
Expand All @@ -33,8 +45,28 @@ function File(props: {
id="upload"
type="file"
ref={ hiddenFileInput }
onChange={ (ev: ChangeEvent<HTMLInputElement>) => { handleFile(ev.target.files) } }
onChange={ (ev: ChangeEvent<HTMLInputElement>) => { handleFile(ev.target.files); tmp = ev.target.files?.[0] } }
/>

{ props.recver
? <button
className={ styles.button }
style={{ backgroundColor: "darksalmon" }}
onClick={ async () => {
await delBoxFile()
props.reLoad()
}}
>Clear</button>
: <button
className={ styles.button }
style={{ backgroundColor: "deepskyblue" }}
onClick={ async () => {
if (tmp) {
await putBoxFile(tmp)
props.reLoad()
} }}
>Relay Box</button>
}
</>
)
}
Expand Down
Loading

0 comments on commit 16bee14

Please sign in to comment.