51a5ca3f68
During a batch request, pass the hash algorithm we're using to the remote server, and read the value, if any, that we get back. If it is not either absent or the string "sha256", fail, since that means that the client and server don't agree on the proper hash algorithm.
119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package tq
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/errors"
|
|
"github.com/git-lfs/git-lfs/v3/git"
|
|
"github.com/git-lfs/git-lfs/v3/lfsapi"
|
|
"github.com/git-lfs/git-lfs/v3/lfshttp"
|
|
"github.com/rubyist/tracerx"
|
|
)
|
|
|
|
type tqClient struct {
|
|
maxRetries int
|
|
*lfsapi.Client
|
|
}
|
|
|
|
type batchRef struct {
|
|
Name string `json:"name,omitempty"`
|
|
}
|
|
|
|
type batchRequest struct {
|
|
Operation string `json:"operation"`
|
|
Objects []*Transfer `json:"objects"`
|
|
TransferAdapterNames []string `json:"transfers,omitempty"`
|
|
Ref *batchRef `json:"ref"`
|
|
HashAlgorithm string `json:"hash_algo"`
|
|
}
|
|
|
|
type BatchResponse struct {
|
|
Objects []*Transfer `json:"objects"`
|
|
TransferAdapterName string `json:"transfer"`
|
|
HashAlgorithm string `json:"hash_algo"`
|
|
endpoint lfshttp.Endpoint
|
|
}
|
|
|
|
func Batch(m *Manifest, dir Direction, remote string, remoteRef *git.Ref, objects []*Transfer) (*BatchResponse, error) {
|
|
if len(objects) == 0 {
|
|
return &BatchResponse{}, nil
|
|
}
|
|
|
|
return m.batchClient().Batch(remote, &batchRequest{
|
|
Operation: dir.String(),
|
|
Objects: objects,
|
|
TransferAdapterNames: m.GetAdapterNames(dir),
|
|
Ref: &batchRef{Name: remoteRef.Refspec()},
|
|
HashAlgorithm: "sha256",
|
|
})
|
|
}
|
|
|
|
type BatchClient interface {
|
|
Batch(remote string, bReq *batchRequest) (*BatchResponse, error)
|
|
MaxRetries() int
|
|
SetMaxRetries(n int)
|
|
}
|
|
|
|
func (c *tqClient) MaxRetries() int {
|
|
return c.maxRetries
|
|
}
|
|
|
|
func (c *tqClient) SetMaxRetries(n int) {
|
|
c.maxRetries = n
|
|
}
|
|
|
|
func (c *tqClient) Batch(remote string, bReq *batchRequest) (*BatchResponse, error) {
|
|
bRes := &BatchResponse{}
|
|
if len(bReq.Objects) == 0 {
|
|
return bRes, nil
|
|
}
|
|
|
|
if len(bReq.TransferAdapterNames) == 1 && bReq.TransferAdapterNames[0] == "basic" {
|
|
bReq.TransferAdapterNames = nil
|
|
}
|
|
|
|
missing := make(map[string]bool)
|
|
for _, obj := range bReq.Objects {
|
|
missing[obj.Oid] = obj.Missing
|
|
}
|
|
|
|
bRes.endpoint = c.Endpoints.Endpoint(bReq.Operation, remote)
|
|
requestedAt := time.Now()
|
|
|
|
req, err := c.NewRequest("POST", bRes.endpoint, "objects/batch", bReq)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "batch request")
|
|
}
|
|
|
|
tracerx.Printf("api: batch %d files", len(bReq.Objects))
|
|
|
|
req = c.Client.LogRequest(req, "lfs.batch")
|
|
res, err := c.DoAPIRequestWithAuth(remote, lfshttp.WithRetries(req, c.MaxRetries()))
|
|
if err != nil {
|
|
tracerx.Printf("api error: %s", err)
|
|
return nil, errors.Wrap(err, "batch response")
|
|
}
|
|
|
|
if err := lfshttp.DecodeJSON(res, bRes); err != nil {
|
|
return bRes, errors.Wrap(err, "batch response")
|
|
}
|
|
|
|
if bRes.HashAlgorithm != "" && bRes.HashAlgorithm != "sha256" {
|
|
return bRes, errors.Wrap(fmt.Errorf("unsupported hash algorithm"), "batch response")
|
|
}
|
|
|
|
if res.StatusCode != 200 {
|
|
return nil, lfshttp.NewStatusCodeError(res)
|
|
}
|
|
|
|
for _, obj := range bRes.Objects {
|
|
obj.Missing = missing[obj.Oid]
|
|
for _, a := range obj.Actions {
|
|
a.createdAt = requestedAt
|
|
}
|
|
}
|
|
|
|
return bRes, nil
|
|
}
|