rc: ensure rclone fails to start up if the --rc port is in use already
This commit is contained in:
parent
0b80d1481a
commit
b961e07c57
4 changed files with 44 additions and 28 deletions
|
@ -353,7 +353,10 @@ func initConfig() {
|
||||||
fs.Debugf("rclone", "Version %q starting with parameters %q", fs.Version, os.Args)
|
fs.Debugf("rclone", "Version %q starting with parameters %q", fs.Version, os.Args)
|
||||||
|
|
||||||
// Start the remote control server if configured
|
// Start the remote control server if configured
|
||||||
rcserver.Start(&rcflags.Opt)
|
_, err = rcserver.Start(&rcflags.Opt)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to start remote control: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Setup CPU profiling if desired
|
// Setup CPU profiling if desired
|
||||||
if *cpuProfile != "" {
|
if *cpuProfile != "" {
|
||||||
|
|
|
@ -37,8 +37,13 @@ See the [rc documentation](/rc/) for more info on the rc flags.
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
rcflags.Opt.Files = args[0]
|
rcflags.Opt.Files = args[0]
|
||||||
}
|
}
|
||||||
rcserver.Start(&rcflags.Opt)
|
s, err := rcserver.Start(&rcflags.Opt)
|
||||||
// Run the rc forever
|
if err != nil {
|
||||||
select {}
|
log.Fatalf("Failed to start remote control: %v", err)
|
||||||
|
}
|
||||||
|
if s == nil {
|
||||||
|
log.Fatal("rc server not configured")
|
||||||
|
}
|
||||||
|
s.Wait()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,25 +21,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start the remote control server if configured
|
// Start the remote control server if configured
|
||||||
func Start(opt *rc.Options) {
|
//
|
||||||
|
// If the server wasn't configured the *Server returned may be nil
|
||||||
|
func Start(opt *rc.Options) (*Server, error) {
|
||||||
if opt.Enabled {
|
if opt.Enabled {
|
||||||
// Serve on the DefaultServeMux so can have global registrations appear
|
// Serve on the DefaultServeMux so can have global registrations appear
|
||||||
s := newServer(opt, http.DefaultServeMux)
|
s := newServer(opt, http.DefaultServeMux)
|
||||||
go s.serve()
|
return s, s.Serve()
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// server contains everything to run the server
|
// Server contains everything to run the rc server
|
||||||
type server struct {
|
type Server struct {
|
||||||
srv *httplib.Server
|
*httplib.Server
|
||||||
files http.Handler
|
files http.Handler
|
||||||
opt *rc.Options
|
opt *rc.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServer(opt *rc.Options, mux *http.ServeMux) *server {
|
func newServer(opt *rc.Options, mux *http.ServeMux) *Server {
|
||||||
s := &server{
|
s := &Server{
|
||||||
srv: httplib.NewServer(mux, &opt.HTTPOptions),
|
Server: httplib.NewServer(mux, &opt.HTTPOptions),
|
||||||
opt: opt,
|
opt: opt,
|
||||||
}
|
}
|
||||||
mux.HandleFunc("/", s.handler)
|
mux.HandleFunc("/", s.handler)
|
||||||
|
|
||||||
|
@ -55,18 +58,20 @@ func newServer(opt *rc.Options, mux *http.ServeMux) *server {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve runs the http server - doesn't return
|
// Serve runs the http server in the background.
|
||||||
func (s *server) serve() {
|
//
|
||||||
err := s.srv.Serve()
|
// Use s.Close() and s.Wait() to shutdown server
|
||||||
|
func (s *Server) Serve() error {
|
||||||
|
err := s.Server.Serve()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Errorf(nil, "Opening listener: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
fs.Logf(nil, "Serving remote control on %s", s.srv.URL())
|
fs.Logf(nil, "Serving remote control on %s", s.URL())
|
||||||
// Open the files in the browser if set
|
// Open the files in the browser if set
|
||||||
if s.files != nil {
|
if s.files != nil {
|
||||||
_ = open.Start(s.srv.URL())
|
_ = open.Start(s.URL())
|
||||||
}
|
}
|
||||||
s.srv.Wait()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeError writes a formatted error to the output
|
// writeError writes a formatted error to the output
|
||||||
|
@ -94,7 +99,7 @@ func writeError(path string, in rc.Params, w http.ResponseWriter, err error, sta
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler reads incoming requests and dispatches them
|
// handler reads incoming requests and dispatches them
|
||||||
func (s *server) handler(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
|
||||||
path := strings.TrimLeft(r.URL.Path, "/")
|
path := strings.TrimLeft(r.URL.Path, "/")
|
||||||
|
|
||||||
w.Header().Add("Access-Control-Allow-Origin", "*")
|
w.Header().Add("Access-Control-Allow-Origin", "*")
|
||||||
|
@ -116,7 +121,7 @@ func (s *server) handler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) handlePost(w http.ResponseWriter, r *http.Request, path string) {
|
func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string) {
|
||||||
contentType := r.Header.Get("Content-Type")
|
contentType := r.Header.Get("Content-Type")
|
||||||
|
|
||||||
values := r.URL.Query()
|
values := r.URL.Query()
|
||||||
|
@ -184,11 +189,11 @@ func (s *server) handlePost(w http.ResponseWriter, r *http.Request, path string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) handleOptions(w http.ResponseWriter, r *http.Request, path string) {
|
func (s *Server) handleOptions(w http.ResponseWriter, r *http.Request, path string) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) serveRoot(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) serveRoot(w http.ResponseWriter, r *http.Request) {
|
||||||
remotes := config.FileSections()
|
remotes := config.FileSections()
|
||||||
sort.Strings(remotes)
|
sort.Strings(remotes)
|
||||||
directory := serve.NewDirectory("")
|
directory := serve.NewDirectory("")
|
||||||
|
@ -201,7 +206,7 @@ func (s *server) serveRoot(w http.ResponseWriter, r *http.Request) {
|
||||||
directory.Serve(w, r)
|
directory.Serve(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) serveRemote(w http.ResponseWriter, r *http.Request, path string, fsName string) {
|
func (s *Server) serveRemote(w http.ResponseWriter, r *http.Request, path string, fsName string) {
|
||||||
f, err := rc.GetCachedFs(fsName)
|
f, err := rc.GetCachedFs(fsName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(path, nil, w, errors.Wrap(err, "failed to make Fs"), http.StatusInternalServerError)
|
writeError(path, nil, w, errors.Wrap(err, "failed to make Fs"), http.StatusInternalServerError)
|
||||||
|
@ -234,7 +239,7 @@ func (s *server) serveRemote(w http.ResponseWriter, r *http.Request, path string
|
||||||
// Match URLS of the form [fs]/remote
|
// Match URLS of the form [fs]/remote
|
||||||
var fsMatch = regexp.MustCompile(`^\[(.*?)\](.*)$`)
|
var fsMatch = regexp.MustCompile(`^\[(.*?)\](.*)$`)
|
||||||
|
|
||||||
func (s *server) handleGet(w http.ResponseWriter, r *http.Request, path string) {
|
func (s *Server) handleGet(w http.ResponseWriter, r *http.Request, path string) {
|
||||||
// Look to see if this has an fs in the path
|
// Look to see if this has an fs in the path
|
||||||
match := fsMatch.FindStringSubmatch(path)
|
match := fsMatch.FindStringSubmatch(path)
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -36,8 +36,11 @@ func TestRcServer(t *testing.T) {
|
||||||
opt.Files = testFs
|
opt.Files = testFs
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
rcServer := newServer(&opt, mux)
|
rcServer := newServer(&opt, mux)
|
||||||
go rcServer.serve()
|
assert.NoError(t, rcServer.Serve())
|
||||||
defer rcServer.srv.Close()
|
defer func() {
|
||||||
|
rcServer.Close()
|
||||||
|
rcServer.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
// Do the simplest possible test to check the server is alive
|
// Do the simplest possible test to check the server is alive
|
||||||
// Do it a few times to wait for the server to start
|
// Do it a few times to wait for the server to start
|
||||||
|
|
Loading…
Reference in a new issue