github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/filemetaworker.go (about)

     1  package sdk
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"mime/multipart"
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/0chain/errors"
    14  	"github.com/0chain/gosdk/constants"
    15  	"github.com/0chain/gosdk/zboxcore/blockchain"
    16  	"github.com/0chain/gosdk/zboxcore/fileref"
    17  	l "github.com/0chain/gosdk/zboxcore/logger"
    18  	"github.com/0chain/gosdk/zboxcore/zboxutil"
    19  )
    20  
    21  type fileMetaResponse struct {
    22  	fileref    *fileref.FileRef
    23  	blobberIdx int
    24  	err        error
    25  }
    26  
    27  type fileMetaByNameResponse struct {
    28  	filerefs   []*fileref.FileRef
    29  	blobberIdx int
    30  	err        error
    31  }
    32  
    33  func (req *ListRequest) getFileMetaInfoFromBlobber(blobber *blockchain.StorageNode, blobberIdx int, rspCh chan<- *fileMetaResponse) {
    34  	body := new(bytes.Buffer)
    35  	formWriter := multipart.NewWriter(body)
    36  
    37  	var fileRef *fileref.FileRef
    38  	var err error
    39  	fileMetaRetFn := func() {
    40  		rspCh <- &fileMetaResponse{fileref: fileRef, blobberIdx: blobberIdx, err: err}
    41  	}
    42  	defer fileMetaRetFn()
    43  	if len(req.remotefilepath) > 0 {
    44  		req.remotefilepathhash = fileref.GetReferenceLookup(req.allocationID, req.remotefilepath)
    45  	}
    46  	if singleClientMode {
    47  		fileMetaHash := fileref.GetCacheKey(req.remotefilepathhash, blobber.ID)
    48  		cachedRef, ok := fileref.GetFileRef(fileMetaHash)
    49  		if ok {
    50  			fileRef = &cachedRef
    51  			return
    52  		}
    53  		defer func() {
    54  			if fileRef != nil && err == nil {
    55  				fileref.StoreFileRef(fileMetaHash, *fileRef)
    56  			}
    57  		}()
    58  	}
    59  	err = formWriter.WriteField("path_hash", req.remotefilepathhash)
    60  	if err != nil {
    61  		l.Logger.Error("File meta info request error: ", err.Error())
    62  		return
    63  	}
    64  
    65  	if req.authToken != nil {
    66  		authTokenBytes, err := json.Marshal(req.authToken)
    67  		if err != nil {
    68  			l.Logger.Error(blobber.Baseurl, " creating auth token bytes", err)
    69  			return
    70  		}
    71  		err = formWriter.WriteField("auth_token", string(authTokenBytes))
    72  		if err != nil {
    73  			l.Logger.Error(blobber.Baseurl, "error writing field", err)
    74  			return
    75  		}
    76  	}
    77  
    78  	formWriter.Close()
    79  	httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body)
    80  	if err != nil {
    81  		l.Logger.Error("File meta info request error: ", err.Error())
    82  		return
    83  	}
    84  
    85  	httpreq.Header.Add("Content-Type", formWriter.FormDataContentType())
    86  	ctx, cncl := context.WithTimeout(req.ctx, (time.Second * 30))
    87  	err = zboxutil.HttpDo(ctx, cncl, httpreq, func(resp *http.Response, err error) error {
    88  		if err != nil {
    89  			l.Logger.Error("GetFileMeta : ", err)
    90  			return err
    91  		}
    92  		defer resp.Body.Close()
    93  		resp_body, err := io.ReadAll(resp.Body)
    94  		if err != nil {
    95  			return errors.Wrap(err, "Error: Resp")
    96  		}
    97  		// l.Logger.Info("File Meta result:", string(resp_body))
    98  		l.Logger.Debug("File meta response status: ", resp.Status)
    99  		if resp.StatusCode == http.StatusOK {
   100  			err = json.Unmarshal(resp_body, &fileRef)
   101  			if err != nil {
   102  				return errors.Wrap(err, "file meta data response parse error")
   103  			}
   104  			return nil
   105  		} else if resp.StatusCode == http.StatusBadRequest {
   106  			return constants.ErrNotFound
   107  		}
   108  		return fmt.Errorf("unexpected response. status code: %d, response: %s",
   109  			resp.StatusCode, string(resp_body))
   110  	})
   111  }
   112  
   113  func (req *ListRequest) getFileMetaByNameInfoFromBlobber(blobber *blockchain.StorageNode, blobberIdx int, rspCh chan<- *fileMetaByNameResponse) {
   114  	body := new(bytes.Buffer)
   115  	formWriter := multipart.NewWriter(body)
   116  
   117  	var fileRef []*fileref.FileRef
   118  	var err error
   119  	fileMetaRetFn := func() {
   120  		rspCh <- &fileMetaByNameResponse{filerefs: fileRef, blobberIdx: blobberIdx, err: err}
   121  	}
   122  	defer fileMetaRetFn()
   123  
   124  	if req.filename != "" {
   125  		err = formWriter.WriteField("name", req.filename)
   126  		if err != nil {
   127  			l.Logger.Error("File meta info request error: ", err.Error())
   128  			return
   129  		}
   130  	}
   131  	if req.authToken != nil {
   132  		authTokenBytes, err := json.Marshal(req.authToken)
   133  		if err != nil {
   134  			l.Logger.Error(blobber.Baseurl, " creating auth token bytes", err)
   135  			return
   136  		}
   137  		err = formWriter.WriteField("auth_token", string(authTokenBytes))
   138  		if err != nil {
   139  			l.Logger.Error(blobber.Baseurl, "error writing field", err)
   140  			return
   141  		}
   142  	}
   143  	formWriter.Close()
   144  	httpreq, err := zboxutil.NewFileMetaRequest(blobber.Baseurl, req.allocationID, req.allocationTx, req.sig, body)
   145  	if err != nil {
   146  		l.Logger.Error("File meta info request error: ", err.Error())
   147  		return
   148  	}
   149  
   150  	httpreq.Header.Add("Content-Type", formWriter.FormDataContentType())
   151  	ctx, cncl := context.WithTimeout(req.ctx, (time.Second * 30))
   152  	err = zboxutil.HttpDo(ctx, cncl, httpreq, func(resp *http.Response, err error) error {
   153  		if err != nil {
   154  			l.Logger.Error("GetFileMeta : ", err)
   155  			return err
   156  		}
   157  		defer resp.Body.Close()
   158  		resp_body, err := io.ReadAll(resp.Body)
   159  		if err != nil {
   160  			return errors.Wrap(err, "Error: Resp")
   161  		}
   162  		// l.Logger.Info("File Meta result:", string(resp_body))
   163  		l.Logger.Debug("File meta response status: ", resp.Status)
   164  		if resp.StatusCode == http.StatusOK {
   165  			err = json.Unmarshal(resp_body, &fileRef)
   166  			if err != nil {
   167  				return errors.Wrap(err, "file meta data response parse error")
   168  			}
   169  			return nil
   170  		} else if resp.StatusCode == http.StatusBadRequest {
   171  			return constants.ErrNotFound
   172  		}
   173  		return fmt.Errorf("unexpected response. status code: %d, response: %s",
   174  			resp.StatusCode, string(resp_body))
   175  	})
   176  }
   177  
   178  func (req *ListRequest) getFileMetaFromBlobbers() []*fileMetaResponse {
   179  	numList := len(req.blobbers)
   180  	rspCh := make(chan *fileMetaResponse, numList)
   181  	for i := 0; i < numList; i++ {
   182  		go req.getFileMetaInfoFromBlobber(req.blobbers[i], i, rspCh)
   183  	}
   184  	fileInfos := make([]*fileMetaResponse, len(req.blobbers))
   185  	for i := 0; i < numList; i++ {
   186  		ch := <-rspCh
   187  		fileInfos[ch.blobberIdx] = ch
   188  	}
   189  	return fileInfos
   190  }
   191  
   192  func (req *ListRequest) getFileMetaByNameFromBlobbers() []*fileMetaByNameResponse {
   193  	numList := len(req.blobbers)
   194  	rspCh := make(chan *fileMetaByNameResponse, numList)
   195  	for i := 0; i < numList; i++ {
   196  		go req.getFileMetaByNameInfoFromBlobber(req.blobbers[i], i, rspCh)
   197  	}
   198  	fileInfos := make([]*fileMetaByNameResponse, len(req.blobbers))
   199  	for i := 0; i < numList; i++ {
   200  		ch := <-rspCh
   201  		fileInfos[ch.blobberIdx] = ch
   202  	}
   203  	return fileInfos
   204  }
   205  
   206  func (req *ListRequest) getFileConsensusFromBlobbers() (zboxutil.Uint128, zboxutil.Uint128, *fileref.FileRef, []*fileMetaResponse) {
   207  	lR := req.getFileMetaFromBlobbers()
   208  	var selected *fileMetaResponse
   209  	foundMask := zboxutil.NewUint128(0)
   210  	deleteMask := zboxutil.NewUint128(0)
   211  	req.consensus = 0
   212  	retMap := make(map[string]int)
   213  	for i := 0; i < len(lR); i++ {
   214  		ti := lR[i]
   215  		if ti.err != nil || ti.fileref == nil {
   216  			continue
   217  		}
   218  		fileMetaHash := ti.fileref.FileMetaHash
   219  		retMap[fileMetaHash]++
   220  		if retMap[fileMetaHash] > req.consensus {
   221  			req.consensus = retMap[fileMetaHash]
   222  			selected = ti
   223  		}
   224  		if req.isConsensusOk() {
   225  			selected = ti
   226  			break
   227  		} else {
   228  			selected = nil
   229  		}
   230  	}
   231  	if selected == nil {
   232  		l.Logger.Error("File consensus not found for ", req.remotefilepath)
   233  		for i := 0; i < len(lR); i++ {
   234  			ti := lR[i]
   235  			if ti.err != nil || ti.fileref == nil {
   236  				continue
   237  			}
   238  			shift := zboxutil.NewUint128(1).Lsh(uint64(ti.blobberIdx))
   239  			deleteMask = deleteMask.Or(shift)
   240  		}
   241  		return foundMask, deleteMask, nil, nil
   242  	}
   243  
   244  	for i := 0; i < len(lR); i++ {
   245  		if lR[i].fileref != nil && selected.fileref.FileMetaHash == lR[i].fileref.FileMetaHash {
   246  			shift := zboxutil.NewUint128(1).Lsh(uint64(lR[i].blobberIdx))
   247  			foundMask = foundMask.Or(shift)
   248  		} else if lR[i].fileref != nil {
   249  			shift := zboxutil.NewUint128(1).Lsh(uint64(lR[i].blobberIdx))
   250  			deleteMask = deleteMask.Or(shift)
   251  		}
   252  	}
   253  	return foundMask, deleteMask, selected.fileref, lR
   254  }
   255  
   256  func (req *ListRequest) getMultipleFileConsensusFromBlobbers() (zboxutil.Uint128, zboxutil.Uint128, []*fileref.FileRef, []*fileMetaByNameResponse) {
   257  	lR := req.getFileMetaByNameFromBlobbers()
   258  	var filerRefs []*fileref.FileRef
   259  	uniquePathHashes := map[string]bool{}
   260  	for i := 0; i < len(lR); i++ {
   261  		ti := lR[i]
   262  		if ti.err != nil || len(ti.filerefs) == 0 {
   263  			continue
   264  		}
   265  		for _, fileRef := range ti.filerefs {
   266  			uniquePathHashes[fileRef.PathHash] = true
   267  		}
   268  	}
   269  	// take the pathhash as unique and for each path hash append the fileref which have consensus.
   270  
   271  	for pathHash := range uniquePathHashes {
   272  		req.consensus = 0
   273  		retMap := make(map[string]int)
   274  	outerLoop:
   275  		for i := 0; i < len(lR); i++ {
   276  			ti := lR[i]
   277  			if ti.err != nil || len(ti.filerefs) == 0 {
   278  				continue
   279  			}
   280  			for _, fRef := range ti.filerefs {
   281  				if fRef == nil {
   282  					continue
   283  				}
   284  				if pathHash == fRef.PathHash {
   285  					fileMetaHash := fRef.FileMetaHash
   286  					retMap[fileMetaHash]++
   287  					if retMap[fileMetaHash] > req.consensus {
   288  						req.consensus = retMap[fileMetaHash]
   289  					}
   290  					if req.isConsensusOk() {
   291  						filerRefs = append(filerRefs, fRef)
   292  						break outerLoop
   293  					}
   294  					break
   295  				}
   296  			}
   297  		}
   298  	}
   299  	return zboxutil.NewUint128(0), zboxutil.NewUint128(0), filerRefs, lR
   300  }
   301  
   302  // return upload mask and delete mask