gitlab.com/SiaPrime/SiaPrime@v1.4.1/node/api/client/renter.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/url"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"gitlab.com/NebulousLabs/errors"
    12  
    13  	"gitlab.com/SiaPrime/SiaPrime/modules"
    14  	"gitlab.com/SiaPrime/SiaPrime/node/api"
    15  	"gitlab.com/SiaPrime/SiaPrime/types"
    16  )
    17  
    18  type (
    19  	// AllowanceRequestPost is a helper type to be able to build an allowance
    20  	// request.
    21  	AllowanceRequestPost struct {
    22  		c      *Client
    23  		sent   bool
    24  		values url.Values
    25  	}
    26  )
    27  
    28  // RenterPostPartialAllowance starts an allowance request which can be extended
    29  // using its methods.
    30  func (c *Client) RenterPostPartialAllowance() *AllowanceRequestPost {
    31  	return &AllowanceRequestPost{c: c, values: make(url.Values)}
    32  }
    33  
    34  // WithFunds adds the funds field to the request.
    35  func (a *AllowanceRequestPost) WithFunds(funds types.Currency) *AllowanceRequestPost {
    36  	a.values.Set("funds", funds.String())
    37  	return a
    38  }
    39  
    40  // WithHosts adds the hosts field to the request.
    41  func (a *AllowanceRequestPost) WithHosts(hosts uint64) *AllowanceRequestPost {
    42  	a.values.Set("hosts", fmt.Sprint(hosts))
    43  	return a
    44  }
    45  
    46  // WithPeriod adds the period field to the request.
    47  func (a *AllowanceRequestPost) WithPeriod(period types.BlockHeight) *AllowanceRequestPost {
    48  	a.values.Set("period", fmt.Sprint(period))
    49  	return a
    50  }
    51  
    52  // WithRenewWindow adds the renewwindow field to the request.
    53  func (a *AllowanceRequestPost) WithRenewWindow(renewWindow types.BlockHeight) *AllowanceRequestPost {
    54  	a.values.Set("renewwindow", fmt.Sprint(renewWindow))
    55  	return a
    56  }
    57  
    58  // WithExpectedStorage adds the expected storage field to the request.
    59  func (a *AllowanceRequestPost) WithExpectedStorage(expectedStorage uint64) *AllowanceRequestPost {
    60  	a.values.Set("expectedstorage", fmt.Sprint(expectedStorage))
    61  	return a
    62  }
    63  
    64  // WithExpectedUpload adds the expected upload field to the request.
    65  func (a *AllowanceRequestPost) WithExpectedUpload(expectedUpload uint64) *AllowanceRequestPost {
    66  	a.values.Set("expectedupload", fmt.Sprint(expectedUpload))
    67  	return a
    68  }
    69  
    70  // WithExpectedDownload adds the expected download field to the request.
    71  func (a *AllowanceRequestPost) WithExpectedDownload(expectedDownload uint64) *AllowanceRequestPost {
    72  	a.values.Set("expecteddownload", fmt.Sprint(expectedDownload))
    73  	return a
    74  }
    75  
    76  // WithExpectedRedundancy adds the expected redundancy field to the request.
    77  func (a *AllowanceRequestPost) WithExpectedRedundancy(expectedRedundancy float64) *AllowanceRequestPost {
    78  	a.values.Set("expectedredundancy", fmt.Sprint(expectedRedundancy))
    79  	return a
    80  }
    81  
    82  // FilterHostsSubnet is not in the Allowance but RenterSettings
    83  // WithFilterHostsSubnet adds the filterhostssubnet field to the request.
    84  //func (a *AllowanceRequestPost) WithFilterHostsSubnet(filterHostsSubnet bool) *AllowanceRequestPost {
    85  //	a.values.Set("filterhostssubnet", fmt.Sprint(filterHostsSubnet))
    86  //	return a
    87  //}
    88  
    89  // Send finalizes and sends the request.
    90  func (a *AllowanceRequestPost) Send() (err error) {
    91  	if a.sent {
    92  		return errors.New("Error, request already sent")
    93  	}
    94  	a.sent = true
    95  	err = a.c.post("/renter", a.values.Encode(), nil)
    96  	return
    97  }
    98  
    99  // escapeSiaPath escapes the siapath to make it safe to use within a URL. This
   100  // should only be used on SiaPaths which are used as part of the URL path.
   101  // Paths within the query have to be escaped with url.PathEscape.
   102  func escapeSiaPath(siaPath modules.SiaPath) string {
   103  	sp := siaPath.String()
   104  	pathSegments := strings.Split(sp, "/")
   105  	escapedSegments := make([]string, 0, len(pathSegments))
   106  	for _, segment := range pathSegments {
   107  		escapedSegments = append(escapedSegments, url.PathEscape(segment))
   108  	}
   109  	return strings.Join(escapedSegments, "/")
   110  }
   111  
   112  // RenterContractCancelPost uses the /renter/contract/cancel endpoint to cancel
   113  // a contract
   114  func (c *Client) RenterContractCancelPost(id types.FileContractID) (err error) {
   115  	values := url.Values{}
   116  	values.Set("id", id.String())
   117  	err = c.post("/renter/contract/cancel", values.Encode(), nil)
   118  	return
   119  }
   120  
   121  // RenterAllContractsGet requests the /renter/contracts resource with all
   122  // options set to true
   123  func (c *Client) RenterAllContractsGet() (rc api.RenterContracts, err error) {
   124  	values := url.Values{}
   125  	values.Set("disabled", fmt.Sprint(true))
   126  	values.Set("expired", fmt.Sprint(true))
   127  	values.Set("recoverable", fmt.Sprint(true))
   128  	err = c.get("/renter/contracts?"+values.Encode(), &rc)
   129  	return
   130  }
   131  
   132  // RenterContractsGet requests the /renter/contracts resource and returns
   133  // Contracts and ActiveContracts
   134  func (c *Client) RenterContractsGet() (rc api.RenterContracts, err error) {
   135  	err = c.get("/renter/contracts", &rc)
   136  	return
   137  }
   138  
   139  // RenterDisabledContractsGet requests the /renter/contracts resource with the
   140  // disabled flag set to true
   141  func (c *Client) RenterDisabledContractsGet() (rc api.RenterContracts, err error) {
   142  	values := url.Values{}
   143  	values.Set("disabled", fmt.Sprint(true))
   144  	err = c.get("/renter/contracts?"+values.Encode(), &rc)
   145  	return
   146  }
   147  
   148  // RenterInactiveContractsGet requests the /renter/contracts resource with the
   149  // inactive flag set to true
   150  func (c *Client) RenterInactiveContractsGet() (rc api.RenterContracts, err error) {
   151  	values := url.Values{}
   152  	values.Set("inactive", fmt.Sprint(true))
   153  	err = c.get("/renter/contracts?"+values.Encode(), &rc)
   154  	return
   155  }
   156  
   157  // RenterInitContractRecoveryScanPost initializes a contract recovery scan
   158  // using the /renter/recoveryscan endpoint.
   159  func (c *Client) RenterInitContractRecoveryScanPost() (err error) {
   160  	err = c.post("/renter/recoveryscan", "", nil)
   161  	return
   162  }
   163  
   164  // RenterContractRecoveryProgressGet returns information about potentially
   165  // ongoing contract recovery scans.
   166  func (c *Client) RenterContractRecoveryProgressGet() (rrs api.RenterRecoveryStatusGET, err error) {
   167  	err = c.get("/renter/recoveryscan", &rrs)
   168  	return
   169  }
   170  
   171  // RenterExpiredContractsGet requests the /renter/contracts resource with the
   172  // expired flag set to true
   173  func (c *Client) RenterExpiredContractsGet() (rc api.RenterContracts, err error) {
   174  	values := url.Values{}
   175  	values.Set("expired", fmt.Sprint(true))
   176  	err = c.get("/renter/contracts?"+values.Encode(), &rc)
   177  	return
   178  }
   179  
   180  // RenterRecoverableContractsGet requests the /renter/contracts resource with the
   181  // recoverable flag set to true
   182  func (c *Client) RenterRecoverableContractsGet() (rc api.RenterContracts, err error) {
   183  	values := url.Values{}
   184  	values.Set("recoverable", fmt.Sprint(true))
   185  	err = c.get("/renter/contracts?"+values.Encode(), &rc)
   186  	return
   187  }
   188  
   189  // RenterCancelDownloadPost requests the /renter/download/cancel endpoint to
   190  // cancel an ongoing doing.
   191  func (c *Client) RenterCancelDownloadPost(id string) (err error) {
   192  	values := url.Values{}
   193  	values.Set("id", id)
   194  	err = c.post("/renter/download/cancel", values.Encode(), nil)
   195  	return
   196  }
   197  
   198  // RenterDeletePost uses the /renter/delete endpoint to delete a file.
   199  func (c *Client) RenterDeletePost(siaPath modules.SiaPath) (err error) {
   200  	sp := escapeSiaPath(siaPath)
   201  	err = c.post(fmt.Sprintf("/renter/delete/%s", sp), "", nil)
   202  	return
   203  }
   204  
   205  // RenterDownloadGet uses the /renter/download endpoint to download a file to a
   206  // destination on disk.
   207  func (c *Client) RenterDownloadGet(siaPath modules.SiaPath, destination string, offset, length uint64, async bool) (string, error) {
   208  	sp := escapeSiaPath(siaPath)
   209  	values := url.Values{}
   210  	values.Set("destination", destination)
   211  	values.Set("offset", fmt.Sprint(offset))
   212  	values.Set("length", fmt.Sprint(length))
   213  	values.Set("async", fmt.Sprint(async))
   214  	h, _, err := c.getRawResponse(fmt.Sprintf("/renter/download/%s?%s", sp, values.Encode()))
   215  	return h.Get("ID"), err
   216  }
   217  
   218  // RenterBackups lists the backups the renter has uploaded to hosts.
   219  func (c *Client) RenterBackups() (ubs api.RenterBackupsGET, err error) {
   220  	err = c.get("/renter/backups", &ubs)
   221  	return
   222  }
   223  
   224  // RenterCreateBackupPost creates a backup of the SiaFiles of the renter and
   225  // uploads it to hosts.
   226  func (c *Client) RenterCreateBackupPost(name string) (err error) {
   227  	values := url.Values{}
   228  	values.Set("name", name)
   229  	err = c.post("/renter/backups/create", values.Encode(), nil)
   230  	return
   231  }
   232  
   233  // RenterRecoverBackupPost downloads and restores the specified backup.
   234  func (c *Client) RenterRecoverBackupPost(name string) (err error) {
   235  	values := url.Values{}
   236  	values.Set("name", name)
   237  	err = c.post("/renter/backups/restore", values.Encode(), nil)
   238  	return
   239  }
   240  
   241  // RenterCreateLocalBackupPost creates a local backup of the SiaFiles of the
   242  // renter.
   243  //
   244  // Deprecated: Use RenterCreateBackupPost instead.
   245  func (c *Client) RenterCreateLocalBackupPost(dst string) (err error) {
   246  	values := url.Values{}
   247  	values.Set("destination", dst)
   248  	err = c.post("/renter/backup", values.Encode(), nil)
   249  	return
   250  }
   251  
   252  // RenterRecoverLocalBackupPost restores the specified backup.
   253  //
   254  // Deprecated: Use RenterCreateBackupPost instead.
   255  func (c *Client) RenterRecoverLocalBackupPost(src string) (err error) {
   256  	values := url.Values{}
   257  	values.Set("source", src)
   258  	err = c.post("/renter/recoverbackup", values.Encode(), nil)
   259  	return
   260  }
   261  
   262  // RenterDownloadFullGet uses the /renter/download endpoint to download a full
   263  // file.
   264  func (c *Client) RenterDownloadFullGet(siaPath modules.SiaPath, destination string, async bool) (string, error) {
   265  	sp := escapeSiaPath(siaPath)
   266  	values := url.Values{}
   267  	values.Set("destination", destination)
   268  	values.Set("httpresp", fmt.Sprint(false))
   269  	values.Set("async", fmt.Sprint(async))
   270  	h, _, err := c.getRawResponse(fmt.Sprintf("/renter/download/%s?%s", sp, values.Encode()))
   271  	return h.Get("ID"), err
   272  }
   273  
   274  // RenterClearAllDownloadsPost requests the /renter/downloads/clear resource
   275  // with no parameters
   276  func (c *Client) RenterClearAllDownloadsPost() (err error) {
   277  	err = c.post("/renter/downloads/clear", "", nil)
   278  	return
   279  }
   280  
   281  // RenterClearDownloadsAfterPost requests the /renter/downloads/clear resource
   282  // with only the after timestamp provided
   283  func (c *Client) RenterClearDownloadsAfterPost(after time.Time) (err error) {
   284  	values := url.Values{}
   285  	values.Set("after", strconv.FormatInt(after.UnixNano(), 10))
   286  	err = c.post("/renter/downloads/clear", values.Encode(), nil)
   287  	return
   288  }
   289  
   290  // RenterClearDownloadsBeforePost requests the /renter/downloads/clear resource
   291  // with only the before timestamp provided
   292  func (c *Client) RenterClearDownloadsBeforePost(before time.Time) (err error) {
   293  	values := url.Values{}
   294  	values.Set("before", strconv.FormatInt(before.UnixNano(), 10))
   295  	err = c.post("/renter/downloads/clear", values.Encode(), nil)
   296  	return
   297  }
   298  
   299  // RenterClearDownloadsRangePost requests the /renter/downloads/clear resource
   300  // with both before and after timestamps provided
   301  func (c *Client) RenterClearDownloadsRangePost(after, before time.Time) (err error) {
   302  	values := url.Values{}
   303  	values.Set("before", strconv.FormatInt(before.UnixNano(), 10))
   304  	values.Set("after", strconv.FormatInt(after.UnixNano(), 10))
   305  	err = c.post("/renter/downloads/clear", values.Encode(), nil)
   306  	return
   307  }
   308  
   309  // RenterDownloadsGet requests the /renter/downloads resource
   310  func (c *Client) RenterDownloadsGet() (rdq api.RenterDownloadQueue, err error) {
   311  	err = c.get("/renter/downloads", &rdq)
   312  	return
   313  }
   314  
   315  // RenterDownloadHTTPResponseGet uses the /renter/download endpoint to download
   316  // a file and return its data.
   317  func (c *Client) RenterDownloadHTTPResponseGet(siaPath modules.SiaPath, offset, length uint64) (resp []byte, err error) {
   318  	sp := escapeSiaPath(siaPath)
   319  	values := url.Values{}
   320  	values.Set("offset", fmt.Sprint(offset))
   321  	values.Set("length", fmt.Sprint(length))
   322  	values.Set("httpresp", fmt.Sprint(true))
   323  	_, resp, err = c.getRawResponse(fmt.Sprintf("/renter/download/%s?%s", sp, values.Encode()))
   324  	return
   325  }
   326  
   327  // RenterFileGet uses the /renter/file/:siapath endpoint to query a file.
   328  func (c *Client) RenterFileGet(siaPath modules.SiaPath) (rf api.RenterFile, err error) {
   329  	sp := escapeSiaPath(siaPath)
   330  	err = c.get("/renter/file/"+sp, &rf)
   331  	return
   332  }
   333  
   334  // RenterFilesGet requests the /renter/files resource.
   335  func (c *Client) RenterFilesGet(cached bool) (rf api.RenterFiles, err error) {
   336  	err = c.get("/renter/files?cached="+fmt.Sprint(cached), &rf)
   337  	return
   338  }
   339  
   340  // RenterGet requests the /renter resource.
   341  func (c *Client) RenterGet() (rg api.RenterGET, err error) {
   342  	err = c.get("/renter", &rg)
   343  	return
   344  }
   345  
   346  // RenterPostAllowance uses the /renter endpoint to change the renter's allowance
   347  func (c *Client) RenterPostAllowance(allowance modules.Allowance) error {
   348  	a := c.RenterPostPartialAllowance()
   349  	a = a.WithFunds(allowance.Funds)
   350  	a = a.WithHosts(allowance.Hosts)
   351  	a = a.WithPeriod(allowance.Period)
   352  	a = a.WithRenewWindow(allowance.RenewWindow)
   353  	//	a = a.WithFilterHostsSubnet(allowance.FilterHostsSubnet)
   354  	a = a.WithExpectedStorage(allowance.ExpectedStorage)
   355  	a = a.WithExpectedUpload(allowance.ExpectedUpload)
   356  	a = a.WithExpectedDownload(allowance.ExpectedDownload)
   357  	a = a.WithExpectedRedundancy(allowance.ExpectedRedundancy)
   358  	return a.Send()
   359  }
   360  
   361  // RenterCancelAllowance uses the /renter endpoint to cancel the allowance.
   362  func (c *Client) RenterCancelAllowance() (err error) {
   363  	err = c.RenterPostAllowance(modules.Allowance{})
   364  	return
   365  }
   366  
   367  // RenterPricesGet requests the /renter/prices endpoint's resources.
   368  func (c *Client) RenterPricesGet(allowance modules.Allowance) (rpg api.RenterPricesGET, err error) {
   369  	query := fmt.Sprintf("?funds=%v&hosts=%v&period=%v&renewwindow=%v",
   370  		allowance.Funds, allowance.Hosts, allowance.Period, allowance.RenewWindow)
   371  	err = c.get("/renter/prices"+query, &rpg)
   372  	return
   373  }
   374  
   375  // RenterPostRateLimit uses the /renter endpoint to change the renter's bandwidth rate
   376  // limit.
   377  func (c *Client) RenterPostRateLimit(readBPS, writeBPS int64) (err error) {
   378  	values := url.Values{}
   379  	values.Set("maxdownloadspeed", strconv.FormatInt(readBPS, 10))
   380  	values.Set("maxuploadspeed", strconv.FormatInt(writeBPS, 10))
   381  	err = c.post("/renter", values.Encode(), nil)
   382  	return
   383  }
   384  
   385  // RenterRenamePost uses the /renter/rename/:siapath endpoint to rename a file.
   386  func (c *Client) RenterRenamePost(siaPathOld, siaPathNew modules.SiaPath) (err error) {
   387  	spo := escapeSiaPath(siaPathOld)
   388  	values := url.Values{}
   389  	values.Set("newsiapath", fmt.Sprintf("/%s", siaPathNew.String()))
   390  	err = c.post(fmt.Sprintf("/renter/rename/%s", spo), values.Encode(), nil)
   391  	return
   392  }
   393  
   394  // RenterSetStreamCacheSizePost uses the /renter endpoint to change the renter's
   395  // streamCacheSize for streaming
   396  func (c *Client) RenterSetStreamCacheSizePost(cacheSize uint64) (err error) {
   397  	values := url.Values{}
   398  	values.Set("streamcachesize", fmt.Sprint(cacheSize))
   399  	err = c.post("/renter", values.Encode(), nil)
   400  	return
   401  }
   402  
   403  // RenterSetCheckIPViolationPost uses the /renter endpoint to enable/disable the IP
   404  // violation check in the renter.
   405  func (c *Client) RenterSetCheckIPViolationPost(enabled bool) (err error) {
   406  	values := url.Values{}
   407  	values.Set("checkforipviolation", fmt.Sprint(enabled))
   408  	err = c.post("/renter", values.Encode(), nil)
   409  	return
   410  }
   411  
   412  // RenterStreamGet uses the /renter/stream endpoint to download data as a
   413  // stream.
   414  func (c *Client) RenterStreamGet(siaPath modules.SiaPath) (resp []byte, err error) {
   415  	sp := escapeSiaPath(siaPath)
   416  	_, resp, err = c.getRawResponse(fmt.Sprintf("/renter/stream/%s", sp))
   417  	return
   418  }
   419  
   420  // RenterStreamPartialGet uses the /renter/stream endpoint to download a part
   421  // of data as a stream.
   422  func (c *Client) RenterStreamPartialGet(siaPath modules.SiaPath, start, end uint64) (resp []byte, err error) {
   423  	sp := escapeSiaPath(siaPath)
   424  	resp, err = c.getRawPartialResponse(fmt.Sprintf("/renter/stream/%s", sp), start, end)
   425  	return
   426  }
   427  
   428  // RenterSetRepairPathPost uses the /renter/tracking endpoint to set the repair
   429  // path of a file to a new location. The file at newPath must exists.
   430  func (c *Client) RenterSetRepairPathPost(siaPath modules.SiaPath, newPath string) (err error) {
   431  	sp := escapeSiaPath(siaPath)
   432  	values := url.Values{}
   433  	values.Set("trackingpath", newPath)
   434  	err = c.post(fmt.Sprintf("/renter/file/%v", sp), values.Encode(), nil)
   435  	return
   436  }
   437  
   438  // RenterSetFileStuckPost sets the 'stuck' field of the siafile at siaPath to
   439  // stuck.
   440  func (c *Client) RenterSetFileStuckPost(siaPath modules.SiaPath, stuck bool) (err error) {
   441  	sp := escapeSiaPath(siaPath)
   442  	values := url.Values{}
   443  	values.Set("stuck", fmt.Sprint(stuck))
   444  	err = c.post(fmt.Sprintf("/renter/file/%v", sp), values.Encode(), nil)
   445  	return
   446  }
   447  
   448  // RenterUploadPost uses the /renter/upload endpoint to upload a file
   449  func (c *Client) RenterUploadPost(path string, siaPath modules.SiaPath, dataPieces, parityPieces uint64) (err error) {
   450  	return c.RenterUploadForcePost(path, siaPath, dataPieces, parityPieces, false)
   451  }
   452  
   453  // RenterUploadForcePost uses the /renter/upload endpoint to upload a file
   454  // and to overwrite if the file already exists
   455  func (c *Client) RenterUploadForcePost(path string, siaPath modules.SiaPath, dataPieces, parityPieces uint64, force bool) (err error) {
   456  	sp := escapeSiaPath(siaPath)
   457  	values := url.Values{}
   458  	values.Set("source", path)
   459  	values.Set("datapieces", strconv.FormatUint(dataPieces, 10))
   460  	values.Set("paritypieces", strconv.FormatUint(parityPieces, 10))
   461  	values.Set("force", strconv.FormatBool(force))
   462  	err = c.post(fmt.Sprintf("/renter/upload/%s", sp), values.Encode(), nil)
   463  	return
   464  }
   465  
   466  // RenterUploadDefaultPost uses the /renter/upload endpoint with default
   467  // redundancy settings to upload a file.
   468  func (c *Client) RenterUploadDefaultPost(path string, siaPath modules.SiaPath) (err error) {
   469  	sp := escapeSiaPath(siaPath)
   470  	values := url.Values{}
   471  	values.Set("source", path)
   472  	err = c.post(fmt.Sprintf("/renter/upload/%s", sp), values.Encode(), nil)
   473  	return
   474  }
   475  
   476  // RenterUploadStreamPost uploads data using a stream.
   477  func (c *Client) RenterUploadStreamPost(r io.Reader, siaPath modules.SiaPath, dataPieces, parityPieces uint64, force bool) error {
   478  	sp := escapeSiaPath(siaPath)
   479  	values := url.Values{}
   480  	values.Set("datapieces", strconv.FormatUint(dataPieces, 10))
   481  	values.Set("paritypieces", strconv.FormatUint(parityPieces, 10))
   482  	values.Set("force", strconv.FormatBool(force))
   483  	values.Set("stream", strconv.FormatBool(true))
   484  	_, err := c.postRawResponse(fmt.Sprintf("/renter/uploadstream/%s?%s", sp, values.Encode()), r)
   485  	return err
   486  }
   487  
   488  // RenterUploadStreamRepairPost a siafile using a stream. If the data provided
   489  // by r is not the same as the previously uploaded data, the data will be
   490  // corrupted.
   491  func (c *Client) RenterUploadStreamRepairPost(r io.Reader, siaPath modules.SiaPath) error {
   492  	sp := escapeSiaPath(siaPath)
   493  	values := url.Values{}
   494  	values.Set("repair", strconv.FormatBool(true))
   495  	values.Set("stream", strconv.FormatBool(true))
   496  	_, err := c.postRawResponse(fmt.Sprintf("/renter/uploadstream/%s?%s", sp, values.Encode()), r)
   497  	return err
   498  }
   499  
   500  // RenterDirCreatePost uses the /renter/dir/ endpoint to create a directory for the
   501  // renter
   502  func (c *Client) RenterDirCreatePost(siaPath modules.SiaPath) (err error) {
   503  	sp := escapeSiaPath(siaPath)
   504  	err = c.post(fmt.Sprintf("/renter/dir/%s", sp), "action=create", nil)
   505  	return
   506  }
   507  
   508  // RenterDirDeletePost uses the /renter/dir/ endpoint to delete a directory for the
   509  // renter
   510  func (c *Client) RenterDirDeletePost(siaPath modules.SiaPath) (err error) {
   511  	sp := escapeSiaPath(siaPath)
   512  	err = c.post(fmt.Sprintf("/renter/dir/%s", sp), "action=delete", nil)
   513  	return
   514  }
   515  
   516  // RenterDirRenamePost uses the /renter/dir/ endpoint to rename a directory for the
   517  // renter
   518  func (c *Client) RenterDirRenamePost(siaPath, newSiaPath modules.SiaPath) (err error) {
   519  	sp := escapeSiaPath(siaPath)
   520  	nsp := escapeSiaPath(newSiaPath)
   521  	err = c.post(fmt.Sprintf("/renter/dir/%s?newsiapath=%s", sp, nsp), "action=rename", nil)
   522  	return
   523  }
   524  
   525  // RenterGetDir uses the /renter/dir/ endpoint to query a directory
   526  func (c *Client) RenterGetDir(siaPath modules.SiaPath) (rd api.RenterDirectory, err error) {
   527  	sp := escapeSiaPath(siaPath)
   528  	err = c.get(fmt.Sprintf("/renter/dir/%s", sp), &rd)
   529  	return
   530  }
   531  
   532  // RenterValidateSiaPathPost uses the /renter/validatesiapath endpoint to
   533  // validate a potential siapath
   534  //
   535  // NOTE: This function specifically takes a string as an argument not a type
   536  // SiaPath
   537  func (c *Client) RenterValidateSiaPathPost(siaPathStr string) (err error) {
   538  	err = c.post(fmt.Sprintf("/renter/validatesiapath/%s", siaPathStr), "", nil)
   539  	return
   540  }