diff options
Diffstat (limited to 'send_over_http.go')
-rw-r--r-- | send_over_http.go | 103 |
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() { |