github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/rc/internal.go (about)

     1  // Define the internal rc functions
     2  
     3  package rc
     4  
     5  import (
     6  	"context"
     7  	"os"
     8  	"runtime"
     9  	"time"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/rclone/rclone/fs"
    14  	"github.com/rclone/rclone/fs/config/obscure"
    15  	"github.com/rclone/rclone/fs/version"
    16  	"github.com/rclone/rclone/lib/atexit"
    17  )
    18  
    19  func init() {
    20  	Add(Call{
    21  		Path:         "rc/noopauth",
    22  		AuthRequired: true,
    23  		Fn:           rcNoop,
    24  		Title:        "Echo the input to the output parameters requiring auth",
    25  		Help: `
    26  This echoes the input parameters to the output parameters for testing
    27  purposes.  It can be used to check that rclone is still alive and to
    28  check that parameter passing is working properly.`,
    29  	})
    30  	Add(Call{
    31  		Path:  "rc/noop",
    32  		Fn:    rcNoop,
    33  		Title: "Echo the input to the output parameters",
    34  		Help: `
    35  This echoes the input parameters to the output parameters for testing
    36  purposes.  It can be used to check that rclone is still alive and to
    37  check that parameter passing is working properly.`,
    38  	})
    39  }
    40  
    41  // Echo the input to the output parameters
    42  func rcNoop(ctx context.Context, in Params) (out Params, err error) {
    43  	return in, nil
    44  }
    45  
    46  func init() {
    47  	Add(Call{
    48  		Path:  "rc/error",
    49  		Fn:    rcError,
    50  		Title: "This returns an error",
    51  		Help: `
    52  This returns an error with the input as part of its error string.
    53  Useful for testing error handling.`,
    54  	})
    55  }
    56  
    57  // Return an error regardless
    58  func rcError(ctx context.Context, in Params) (out Params, err error) {
    59  	return nil, errors.Errorf("arbitrary error on input %+v", in)
    60  }
    61  
    62  func init() {
    63  	Add(Call{
    64  		Path:  "rc/list",
    65  		Fn:    rcList,
    66  		Title: "List all the registered remote control commands",
    67  		Help: `
    68  This lists all the registered remote control commands as a JSON map in
    69  the commands response.`,
    70  	})
    71  }
    72  
    73  // List the registered commands
    74  func rcList(ctx context.Context, in Params) (out Params, err error) {
    75  	out = make(Params)
    76  	out["commands"] = Calls.List()
    77  	return out, nil
    78  }
    79  
    80  func init() {
    81  	Add(Call{
    82  		Path:  "core/pid",
    83  		Fn:    rcPid,
    84  		Title: "Return PID of current process",
    85  		Help: `
    86  This returns PID of current process.
    87  Useful for stopping rclone process.`,
    88  	})
    89  }
    90  
    91  // Return PID of current process
    92  func rcPid(ctx context.Context, in Params) (out Params, err error) {
    93  	out = make(Params)
    94  	out["pid"] = os.Getpid()
    95  	return out, nil
    96  }
    97  
    98  func init() {
    99  	Add(Call{
   100  		Path:  "core/memstats",
   101  		Fn:    rcMemStats,
   102  		Title: "Returns the memory statistics",
   103  		Help: `
   104  This returns the memory statistics of the running program.  What the values mean
   105  are explained in the go docs: https://golang.org/pkg/runtime/#MemStats
   106  
   107  The most interesting values for most people are:
   108  
   109  * HeapAlloc: This is the amount of memory rclone is actually using
   110  * HeapSys: This is the amount of memory rclone has obtained from the OS
   111  * Sys: this is the total amount of memory requested from the OS
   112    * It is virtual memory so may include unused memory
   113  `,
   114  	})
   115  }
   116  
   117  // Return the memory statistics
   118  func rcMemStats(ctx context.Context, in Params) (out Params, err error) {
   119  	out = make(Params)
   120  	var m runtime.MemStats
   121  	runtime.ReadMemStats(&m)
   122  	out["Alloc"] = m.Alloc
   123  	out["TotalAlloc"] = m.TotalAlloc
   124  	out["Sys"] = m.Sys
   125  	out["Mallocs"] = m.Mallocs
   126  	out["Frees"] = m.Frees
   127  	out["HeapAlloc"] = m.HeapAlloc
   128  	out["HeapSys"] = m.HeapSys
   129  	out["HeapIdle"] = m.HeapIdle
   130  	out["HeapInuse"] = m.HeapInuse
   131  	out["HeapReleased"] = m.HeapReleased
   132  	out["HeapObjects"] = m.HeapObjects
   133  	out["StackInuse"] = m.StackInuse
   134  	out["StackSys"] = m.StackSys
   135  	out["MSpanInuse"] = m.MSpanInuse
   136  	out["MSpanSys"] = m.MSpanSys
   137  	out["MCacheInuse"] = m.MCacheInuse
   138  	out["MCacheSys"] = m.MCacheSys
   139  	out["BuckHashSys"] = m.BuckHashSys
   140  	out["GCSys"] = m.GCSys
   141  	out["OtherSys"] = m.OtherSys
   142  	return out, nil
   143  }
   144  
   145  func init() {
   146  	Add(Call{
   147  		Path:  "core/gc",
   148  		Fn:    rcGc,
   149  		Title: "Runs a garbage collection.",
   150  		Help: `
   151  This tells the go runtime to do a garbage collection run.  It isn't
   152  necessary to call this normally, but it can be useful for debugging
   153  memory problems.
   154  `,
   155  	})
   156  }
   157  
   158  // Do a garbage collection run
   159  func rcGc(ctx context.Context, in Params) (out Params, err error) {
   160  	runtime.GC()
   161  	return nil, nil
   162  }
   163  
   164  func init() {
   165  	Add(Call{
   166  		Path:  "core/version",
   167  		Fn:    rcVersion,
   168  		Title: "Shows the current version of rclone and the go runtime.",
   169  		Help: `
   170  This shows the current version of go and the go runtime
   171  
   172  - version - rclone version, eg "v1.44"
   173  - decomposed - version number as [major, minor, patch, subpatch]
   174      - note patch and subpatch will be 999 for a git compiled version
   175  - isGit - boolean - true if this was compiled from the git version
   176  - os - OS in use as according to Go
   177  - arch - cpu architecture in use according to Go
   178  - goVersion - version of Go runtime in use
   179  
   180  `,
   181  	})
   182  }
   183  
   184  // Return version info
   185  func rcVersion(ctx context.Context, in Params) (out Params, err error) {
   186  	decomposed, err := version.New(fs.Version)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	out = Params{
   191  		"version":    fs.Version,
   192  		"decomposed": decomposed,
   193  		"isGit":      decomposed.IsGit(),
   194  		"os":         runtime.GOOS,
   195  		"arch":       runtime.GOARCH,
   196  		"goVersion":  runtime.Version(),
   197  	}
   198  	return out, nil
   199  }
   200  
   201  func init() {
   202  	Add(Call{
   203  		Path:  "core/obscure",
   204  		Fn:    rcObscure,
   205  		Title: "Obscures a string passed in.",
   206  		Help: `
   207  Pass a clear string and rclone will obscure it for the config file:
   208  - clear - string
   209  
   210  Returns
   211  - obscured - string
   212  `,
   213  	})
   214  }
   215  
   216  // Return obscured string
   217  func rcObscure(ctx context.Context, in Params) (out Params, err error) {
   218  	clear, err := in.GetString("clear")
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	obscured, err := obscure.Obscure(clear)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	out = Params{
   227  		"obscured": obscured,
   228  	}
   229  	return out, nil
   230  }
   231  
   232  func init() {
   233  	Add(Call{
   234  		Path:  "core/quit",
   235  		Fn:    rcQuit,
   236  		Title: "Terminates the app.",
   237  		Help: `
   238  (optional) Pass an exit code to be used for terminating the app:
   239  - exitCode - int
   240  `,
   241  	})
   242  }
   243  
   244  // Terminates app
   245  func rcQuit(ctx context.Context, in Params) (out Params, err error) {
   246  	code, err := in.GetInt64("exitCode")
   247  
   248  	if IsErrParamInvalid(err) {
   249  		return nil, err
   250  	}
   251  	if IsErrParamNotFound(err) {
   252  		code = 0
   253  	}
   254  	exitCode := int(code)
   255  
   256  	go func(exitCode int) {
   257  		time.Sleep(time.Millisecond * 1500)
   258  		atexit.Run()
   259  		os.Exit(exitCode)
   260  	}(exitCode)
   261  
   262  	return nil, nil
   263  }
   264  
   265  func init() {
   266  	Add(Call{
   267  		Path:  "debug/set-mutex-profile-fraction",
   268  		Fn:    rcSetMutexProfileFraction,
   269  		Title: "Set runtime.SetMutexProfileFraction for mutex profiling.",
   270  		Help: `
   271  SetMutexProfileFraction controls the fraction of mutex contention
   272  events that are reported in the mutex profile. On average 1/rate
   273  events are reported. The previous rate is returned.
   274  
   275  To turn off profiling entirely, pass rate 0. To just read the current
   276  rate, pass rate < 0. (For n>1 the details of sampling may change.)
   277  
   278  Once this is set you can look use this to profile the mutex contention:
   279  
   280      go tool pprof http://localhost:5572/debug/pprof/mutex
   281  
   282  Parameters
   283  
   284  - rate - int
   285  
   286  Results
   287  
   288  - previousRate - int
   289  `,
   290  	})
   291  }
   292  
   293  // Terminates app
   294  func rcSetMutexProfileFraction(ctx context.Context, in Params) (out Params, err error) {
   295  	rate, err := in.GetInt64("rate")
   296  	if err != nil {
   297  		return nil, err
   298  	}
   299  	previousRate := runtime.SetMutexProfileFraction(int(rate))
   300  	out = make(Params)
   301  	out["previousRate"] = previousRate
   302  	return out, nil
   303  }
   304  
   305  func init() {
   306  	Add(Call{
   307  		Path:  "debug/set-block-profile-rate",
   308  		Fn:    rcSetBlockProfileRate,
   309  		Title: "Set runtime.SetBlockProfileRate for blocking profiling.",
   310  		Help: `
   311  SetBlockProfileRate controls the fraction of goroutine blocking events
   312  that are reported in the blocking profile. The profiler aims to sample
   313  an average of one blocking event per rate nanoseconds spent blocked.
   314  
   315  To include every blocking event in the profile, pass rate = 1. To turn
   316  off profiling entirely, pass rate <= 0.
   317  
   318  After calling this you can use this to see the blocking profile:
   319  
   320      go tool pprof http://localhost:5572/debug/pprof/block
   321  
   322  Parameters
   323  
   324  - rate - int
   325  `,
   326  	})
   327  }
   328  
   329  // Terminates app
   330  func rcSetBlockProfileRate(ctx context.Context, in Params) (out Params, err error) {
   331  	rate, err := in.GetInt64("rate")
   332  	if err != nil {
   333  		return nil, err
   334  	}
   335  	runtime.SetBlockProfileRate(int(rate))
   336  	return nil, nil
   337  }