aboutsummaryrefslogtreecommitdiff
path: root/send_over_http.go
diff options
context:
space:
mode:
Diffstat (limited to 'send_over_http.go')
-rw-r--r--send_over_http.go103
1 files changed, 72 insertions, 31 deletions
diff --git a/send_over_http.go b/send_over_http.go
index 98b7e6e..2af7890 100644
--- a/send_over_http.go
+++ b/send_over_http.go
@@ -1,7 +1,7 @@
package sendoverhttp
import (
- "fmt"
+ "errors"
"io/fs"
"log"
"net"
@@ -9,32 +9,73 @@ import (
"net/url"
"os"
"path/filepath"
- "strconv"
)
-// port is the IP port address to listen on.
-const port = 8081
+// Config contains the configuration parameters for the service.
+type Config struct {
+ // FilePath is the file to serve.
+ FilePath string
+ // ListenAddress is the network address to listen for connections.
+ ListenAddress string
+ // Network type to listen on.
+ Network string
+}
+
+// Source a single listening address to listen on.
+func getListenAddress(config Config) (string, error) {
+ switch config.Network {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return config.ListenAddress, nil
+ }
+
+ addr, port, err := net.SplitHostPort(config.ListenAddress)
+ if err != nil {
+ addr = config.ListenAddress
+ port = "0"
+ }
+
+ if addr != "" {
+ ip := net.ParseIP(addr)
+ if ip == nil {
+ return config.ListenAddress, nil
+ }
+ if !ip.IsUnspecified() {
+ return config.ListenAddress, nil
+ }
+ }
-func preferredIP() (*net.IP, error) {
ips, err := net.InterfaceAddrs()
if err != nil {
- return nil, err
+ return "", err
}
+
+ // Valid fallback if no other interfaces available
+ var loopback *net.IP = nil
+
for _, addr := range ips {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
+ if config.Network == "tcp6" && ipNet.IP.To4() != nil {
+ continue
+ }
if ipNet.IP.IsLoopback() {
+ loopback = &ipNet.IP
continue
}
- return &ipNet.IP, nil
+ return net.JoinHostPort(ipNet.IP.String(), port), nil
+ }
+
+ if loopback != nil {
+ return net.JoinHostPort((*loopback).String(), port), nil
}
- return nil, nil
+ return "", errors.New("no valid network address could be found")
}
type Server struct {
- filepath string
+ config Config
closeCh chan struct{}
mr *MultiRunner
@@ -67,48 +108,48 @@ func (s SingleFileDir) Open(name string) (http.File, error) {
}
}
-func NewServer(fp string) *Server {
+func NewServer(config Config) *Server {
return &Server{
- closeCh: make(chan struct{}),
- filepath: fp,
- mr: NewMultiRunner(),
+ config: config,
+
+ closeCh: make(chan struct{}),
+ mr: NewMultiRunner(),
}
}
func (s *Server) Start() error {
- ip, err := preferredIP()
+ listenAddr, err := getListenAddress(s.config)
if err != nil {
- return err
+ log.Fatal(err)
+ }
+
+ l, err := net.Listen(s.config.Network, listenAddr)
+ if err != nil {
+ log.Fatal(err)
}
u := url.URL{
Scheme: "http",
- Host: fmt.Sprintf("%s:%d", ip, port),
+ Host: l.Addr().String(),
}
- if stat, _ := os.Stat(s.filepath); !stat.IsDir() {
- u.Path = filepath.Base(s.filepath)
+ if stat, _ := os.Stat(s.config.FilePath); !stat.IsDir() {
+ u.Path = filepath.Base(s.config.FilePath)
}
qrCodeShower := NewTerminalQRShower(u.String())
go s.mr.Run(qrCodeShower)
- httpRunner := NewRunner()
- httpSrv := &http.Server{
- Addr: ":" + strconv.Itoa(port),
- }
-
- var d http.FileSystem = http.Dir(s.filepath)
- if stat, _ := os.Stat(s.filepath); !stat.IsDir() {
+ var d http.FileSystem = http.Dir(s.config.FilePath)
+ if stat, _ := os.Stat(s.config.FilePath); !stat.IsDir() {
// Show user the name of the file
- d = SingleFileDir(s.filepath)
+ d = SingleFileDir(s.config.FilePath)
+ }
+ httpSrv := &http.Server{
+ Handler: http.FileServer(d),
}
- httpSrv.Handler = http.FileServer(d)
+ httpRunner := NewRunner()
httpRunner.OnStart = func() error {
- l, err := net.Listen("tcp4", u.Host)
- if err != nil {
- log.Fatal(err)
- }
return httpSrv.Serve(l)
}
httpRunner.OnStop = func() {