github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/sharing/reupload.go (about)

     1  package sharing
     2  
     3  import (
     4  	"net/http"
     5  	"net/url"
     6  
     7  	"github.com/cozy/cozy-stack/client/request"
     8  	"github.com/cozy/cozy-stack/model/instance"
     9  	"github.com/cozy/cozy-stack/model/instance/lifecycle"
    10  	"github.com/cozy/cozy-stack/pkg/consts"
    11  	"github.com/cozy/cozy-stack/pkg/couchdb"
    12  	multierror "github.com/hashicorp/go-multierror"
    13  )
    14  
    15  func init() {
    16  	lifecycle.AskReupload = AskReupload
    17  }
    18  
    19  // AskReupload is used when the disk quota of an instance is increased to tell
    20  // to the other instances that have a sharing with it that they can retry to
    21  // upload files.
    22  func AskReupload(inst *instance.Instance) error {
    23  	// XXX If there are more than 100 sharings, it is probably better to rely
    24  	// on the existing retry mechanism than asking for all of the sharings, as
    25  	// it may slow down the sharings.
    26  	req := &couchdb.AllDocsRequest{
    27  		Limit: 100,
    28  	}
    29  	var sharings []*Sharing
    30  	err := couchdb.GetAllDocs(inst, consts.Sharings, req, &sharings)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	var errm error
    35  	for _, s := range sharings {
    36  		if !s.Active || s.FirstFilesRule() == nil {
    37  			continue
    38  		}
    39  		if s.Owner {
    40  			for i, m := range s.Members {
    41  				if i == 0 {
    42  					continue // skip the owner
    43  				}
    44  				if m.Status != MemberStatusReady {
    45  					continue
    46  				}
    47  				if err := askReuploadTo(inst, s, &s.Members[i], &s.Credentials[i-1]); err != nil {
    48  					errm = multierror.Append(errm, err)
    49  				}
    50  			}
    51  
    52  			continue
    53  		}
    54  
    55  		if len(s.Credentials) > 0 {
    56  			if err := askReuploadTo(inst, s, &s.Members[0], &s.Credentials[0]); err != nil {
    57  				errm = multierror.Append(errm, err)
    58  			}
    59  		}
    60  	}
    61  	return errm
    62  }
    63  
    64  func askReuploadTo(inst *instance.Instance, s *Sharing, m *Member, c *Credentials) error {
    65  	if c == nil || c.AccessToken == nil {
    66  		return nil
    67  	}
    68  	u, err := url.Parse(m.Instance)
    69  	if err != nil {
    70  		return err
    71  	}
    72  	opts := &request.Options{
    73  		Method: http.MethodPost,
    74  		Scheme: u.Scheme,
    75  		Domain: u.Host,
    76  		Path:   "/sharings/" + s.SID + "/reupload",
    77  		Headers: request.Headers{
    78  			"Authorization": "Bearer " + c.AccessToken.AccessToken,
    79  		},
    80  		ParseError: ParseRequestError,
    81  	}
    82  	res, err := request.Req(opts)
    83  	if res != nil && res.StatusCode/100 == 4 {
    84  		res, err = RefreshToken(inst, err, s, m, c, opts, nil)
    85  	}
    86  	if err != nil {
    87  		return err
    88  	}
    89  	defer res.Body.Close()
    90  	return nil
    91  }
    92  
    93  // PushUploadJob pushs a job for the share-upload worker, to try again to
    94  // reupload files.
    95  func PushUploadJob(s *Sharing, inst *instance.Instance) {
    96  	if s.Active && s.FirstFilesRule() != nil {
    97  		s.pushJob(inst, "share-upload")
    98  	}
    99  }