1 /*
2  * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef HISTREAMER_DOWNLOADER_H
17 #define HISTREAMER_DOWNLOADER_H
18 
19 #include <functional>
20 #include <memory>
21 #include <string>
22 #include "foundation/osal/thread/task.h"
23 #include "foundation/osal/thread/mutex.h"
24 #include "foundation/utils/blocking_queue.h"
25 #include "foundation/osal/utils/util.h"
26 #include "network_client.h"
27 
28 namespace OHOS {
29 namespace Media {
30 namespace Plugin {
31 namespace HttpPlugin {
32 enum struct DownloadStatus {
33     PARTTAL_DOWNLOAD,
34 };
35 
36 struct HeaderInfo {
37     char contentType[32]; // 32 chars
38     size_t fileContentLen {0};
39     long contentLen {0};
40     bool isChunked {false};
41     bool isClosed {false};
42 
UpdateHeaderInfo43     void Update(const HeaderInfo* info)
44     {
45         (void)memcpy_s(contentType, sizeof(contentType), info->contentType, sizeof(contentType));
46         fileContentLen = info->fileContentLen;
47         contentLen = info->contentLen;
48         isChunked = info->isChunked;
49     }
50 
GetFileContentLengthHeaderInfo51     size_t GetFileContentLength() const
52     {
53         while (fileContentLen == 0 && !isChunked && !isClosed) {
54             OSAL::SleepFor(10); // 10, wait for fileContentLen updated
55         }
56         return fileContentLen;
57     }
58 };
59 
60 // uint8_t* : the data should save
61 // uint32_t : length
62 using DataSaveFunc = std::function<bool(uint8_t*, uint32_t)>;
63 class Downloader;
64 class DownloadRequest;
65 using StatusCallbackFunc = std::function<void(DownloadStatus, std::shared_ptr<Downloader>&,
66     std::shared_ptr<DownloadRequest>&)>;
67 
68 class DownloadRequest {
69 public:
70     DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback,
71                     bool requestWholeFile = false);
72     size_t GetFileContentLength() const;
73     void SaveHeader(const HeaderInfo* header);
74     bool IsChunked() const;
75     bool IsEos() const;
76     int GetRetryTimes() const;
77     NetworkClientErrorCode GetClientError() const;
78     NetworkServerErrorCode GetServerError() const;
IsSame(const std::shared_ptr<DownloadRequest> & other)79     bool IsSame(const std::shared_ptr<DownloadRequest>& other) const
80     {
81         return url_ == other->url_ && startPos_ == other->startPos_;
82     }
GetUrl()83     std::string GetUrl() const
84     {
85         return url_;
86     }
87     bool IsClosed() const;
88     void Close();
89 
90 private:
91     void WaitHeaderUpdated() const;
92 
93     std::string url_;
94     DataSaveFunc saveData_;
95     StatusCallbackFunc statusCallback_;
96 
97     HeaderInfo headerInfo_;
98 
99     bool isHeaderUpdated {false};
100     bool isEos_ {false}; // file download finished
101     int64_t startPos_;
102     bool isDownloading_;
103     bool requestWholeFile_ {false};
104     int requestSize_;
105     int retryTimes_ {0};
106     NetworkClientErrorCode clientError_ {NetworkClientErrorCode::ERROR_OK};
107     NetworkServerErrorCode serverError_ {0};
108 
109     friend class Downloader;
110 };
111 
112 class Downloader {
113 public:
114     explicit Downloader(std::string name) noexcept;
115     virtual ~Downloader();
116 
117     bool Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs);
118     void Start();
119     void Pause();
120     void Resume();
121     void Stop(bool isAsync = false);
122     bool Seek(int64_t offset);
123     bool Retry(const std::shared_ptr<DownloadRequest>& request);
124 private:
125     bool BeginDownload();
126 
127     void HttpDownloadLoop();
128     void HandleRetOK();
129     static size_t RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam);
130     static size_t RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam);
131 
132     std::string name_;
133     std::shared_ptr<NetworkClient> client_;
134     std::shared_ptr<OSAL::Task> task_;
135     std::shared_ptr<BlockingQueue<std::shared_ptr<DownloadRequest>>> requestQue_;
136     OSAL::Mutex operatorMutex_{};
137 
138     std::shared_ptr<DownloadRequest> currentRequest_;
139     bool shouldStartNextRequest {false};
140 };
141 }
142 }
143 }
144 }
145 #endif