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