| 252 | } |
| 253 | |
| 254 | func DownloadFileWithProxyStream(url, dst string) error { |
| 255 | resp, err := req_helper.HandleGetWithProxy(url) |
| 256 | if err != nil { |
| 257 | return err |
| 258 | } |
| 259 | defer resp.Body.Close() |
| 260 | if resp.StatusCode >= http.StatusBadRequest { |
| 261 | return fmt.Errorf("download file [%s] failed, status code: %d", url, resp.StatusCode) |
| 262 | } |
| 263 | |
| 264 | tmpDst := dst + ".part" |
| 265 | _ = os.Remove(tmpDst) |
| 266 | out, err := os.Create(tmpDst) |
| 267 | if err != nil { |
| 268 | return fmt.Errorf("create download file [%s] error, err %s", dst, err.Error()) |
| 269 | } |
| 270 | success := false |
| 271 | defer func() { |
| 272 | _ = out.Close() |
| 273 | if !success { |
| 274 | _ = os.Remove(tmpDst) |
| 275 | } |
| 276 | }() |
| 277 | |
| 278 | n, err := io.Copy(out, resp.Body) |
| 279 | if err != nil { |
| 280 | return fmt.Errorf("save download file [%s] error, err %s", dst, err.Error()) |
| 281 | } |
| 282 | if resp.ContentLength > 0 && n != resp.ContentLength { |
| 283 | return fmt.Errorf("save download file [%s] error, content-length mismatch: expected %d, actual %d", dst, resp.ContentLength, n) |
| 284 | } |
| 285 | if err = out.Sync(); err != nil { |
| 286 | return fmt.Errorf("sync download file [%s] error, err %s", dst, err.Error()) |
| 287 | } |
| 288 | if err = os.Rename(tmpDst, dst); err != nil { |
| 289 | return fmt.Errorf("rename download file [%s] error, err %s", dst, err.Error()) |
| 290 | } |
| 291 | success = true |
| 292 | return nil |
| 293 | } |
| 294 | |
| 295 | func Stat(path string) bool { |
| 296 | _, err := os.Stat(path) |