github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/playlist.go (about) 1 package sdk 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "net/url" 8 "strings" 9 10 "github.com/0chain/gosdk/core/encryption" 11 "github.com/0chain/gosdk/core/resty" 12 "github.com/0chain/gosdk/core/sys" 13 "github.com/0chain/gosdk/zboxcore/client" 14 "github.com/0chain/gosdk/zboxcore/fileref" 15 "github.com/0chain/gosdk/zboxcore/logger" 16 "github.com/0chain/gosdk/zboxcore/zboxutil" 17 ) 18 19 type PlaylistFile struct { 20 LookupHash string `gorm:"column:lookup_hash" json:"lookup_hash"` 21 Name string `gorm:"column:name" json:"name"` 22 Path string `gorm:"column:path" json:"path"` 23 NumBlocks int64 `gorm:"column:num_of_blocks" json:"num_of_blocks"` 24 ParentPath string `gorm:"column:parent_path" json:"parent_path"` 25 Size int64 `gorm:"column:size;" json:"size"` 26 ActualFileSize int64 27 MimeType string `gorm:"column:mimetype" json:"mimetype"` 28 Type string `gorm:"column:type" json:"type"` 29 } 30 31 func GetPlaylist(ctx context.Context, alloc *Allocation, path, since string) ([]PlaylistFile, error) { 32 33 q := &url.Values{} 34 q.Add("path", path) 35 q.Add("since", since) 36 37 return getPlaylistFromBlobbers(ctx, alloc, q.Encode()) 38 } 39 40 func GetPlaylistByAuthTicket(ctx context.Context, alloc *Allocation, authTicket, lookupHash, since string) ([]PlaylistFile, error) { 41 42 q := &url.Values{} 43 q.Add("auth_token", authTicket) 44 q.Add("lookup_hash", lookupHash) 45 q.Add("since", since) 46 47 return getPlaylistFromBlobbers(ctx, alloc, q.Encode()) 48 } 49 50 func getPlaylistFromBlobbers(ctx context.Context, alloc *Allocation, query string) ([]PlaylistFile, error) { 51 52 urls := make([]string, len(alloc.Blobbers)) 53 for i, b := range alloc.Blobbers { 54 sb := &strings.Builder{} 55 sb.WriteString(strings.TrimRight(b.Baseurl, "/")) 56 sb.WriteString(zboxutil.PLAYLIST_LATEST_ENDPOINT) 57 sb.WriteString(alloc.ID) 58 sb.WriteString("?") 59 sb.WriteString(query) 60 61 urls[i] = sb.String() 62 } 63 64 opts := make([]resty.Option, 0, 3) 65 66 opts = append(opts, resty.WithRetry(resty.DefaultRetry)) 67 opts = append(opts, resty.WithRequestInterceptor(func(req *http.Request) error { 68 req.Header.Set("X-App-Client-ID", client.GetClientID()) 69 req.Header.Set("X-App-Client-Key", client.GetClientPublicKey()) 70 71 hash := encryption.Hash(alloc.ID) 72 sign, err := sys.Sign(hash, client.GetClient().SignatureScheme, client.GetClientSysKeys()) 73 if err != nil { 74 return err 75 } 76 77 // ClientSignatureHeader represents http request header contains signature. 78 req.Header.Set("X-App-Client-Signature", sign) 79 80 return nil 81 })) 82 83 c := createPlaylistConsensus(alloc.getConsensuses()) 84 85 r := resty.New(opts...). 86 Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error { 87 if err != nil { 88 logger.Logger.Error("playlist: ", err) 89 return err 90 } 91 92 if resp != nil { 93 if resp.StatusCode == http.StatusOK { 94 if e := c.AddFiles(respBody); e != nil { 95 logger.Logger.Error("playlist: ", e, resp.Request.URL) 96 } 97 98 return nil 99 } 100 101 logger.Logger.Error("playlist: ", resp.Status, resp.Request.URL) 102 return nil 103 104 } 105 106 return nil 107 }) 108 109 r.DoGet(ctx, urls...) 110 111 r.Wait() 112 113 return c.GetConsensusResult(), nil 114 } 115 116 func GetPlaylistFile(ctx context.Context, alloc *Allocation, path string) (*PlaylistFile, error) { 117 q := &url.Values{} 118 q.Add("lookup_hash", fileref.GetReferenceLookup(alloc.ID, path)) 119 120 return getPlaylistFileFromBlobbers(ctx, alloc, q.Encode()) 121 } 122 123 func GetPlaylistFileByAuthTicket(ctx context.Context, alloc *Allocation, authTicket, lookupHash string) (*PlaylistFile, error) { 124 q := &url.Values{} 125 q.Add("auth_token", authTicket) 126 q.Add("lookup_hash", lookupHash) 127 128 return getPlaylistFileFromBlobbers(ctx, alloc, q.Encode()) 129 } 130 131 func getPlaylistFileFromBlobbers(ctx context.Context, alloc *Allocation, query string) (*PlaylistFile, error) { 132 133 urls := make([]string, len(alloc.Blobbers)) 134 for i, b := range alloc.Blobbers { 135 sb := &strings.Builder{} 136 sb.WriteString(strings.TrimRight(b.Baseurl, "/")) 137 sb.WriteString(zboxutil.PLAYLIST_FILE_ENDPOINT) 138 sb.WriteString(alloc.ID) 139 sb.WriteString("?") 140 sb.WriteString(query) 141 142 urls[i] = sb.String() 143 } 144 145 opts := make([]resty.Option, 0, 3) 146 147 opts = append(opts, resty.WithRetry(resty.DefaultRetry)) 148 opts = append(opts, resty.WithRequestInterceptor(func(req *http.Request) error { 149 req.Header.Set("X-App-Client-ID", client.GetClientID()) 150 req.Header.Set("X-App-Client-Key", client.GetClientPublicKey()) 151 152 hash := encryption.Hash(alloc.ID) 153 sign, err := sys.Sign(hash, client.GetClient().SignatureScheme, client.GetClientSysKeys()) 154 if err != nil { 155 return err 156 } 157 158 // ClientSignatureHeader represents http request header contains signature. 159 req.Header.Set("X-App-Client-Signature", sign) 160 161 return nil 162 })) 163 164 c := createPlaylistConsensus(alloc.getConsensuses()) 165 166 r := resty.New(opts...). 167 Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error { 168 if err != nil { 169 logger.Logger.Error("playlist: ", err) 170 return err 171 } 172 173 if resp != nil { 174 if resp.StatusCode == http.StatusOK { 175 if e := c.AddFile(respBody); e != nil { 176 logger.Logger.Error("playlist: ", e, resp.Request.URL) 177 } 178 179 return nil 180 } 181 182 logger.Logger.Error("playlist: ", resp.Status, resp.Request.URL) 183 return nil 184 185 } 186 187 return nil 188 }) 189 190 r.DoGet(ctx, urls...) 191 192 r.Wait() 193 194 files := c.GetConsensusResult() 195 196 if len(files) > 0 { 197 return &files[0], nil 198 } 199 200 return nil, errors.New("playlist: playlist file not found") 201 }