update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / common / python / rift / downloader / base.py
1 #
2 # Copyright 2016 RIFT.IO Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # Author(s): Varun Prasad
17 # Creation Date: 09/25/2016
18 #
19
20 import abc
21 import enum
22 import os
23 import uuid
24 import time
25
26
27 class InvalidDestinationError(Exception):
28 pass
29
30
31 class DownloaderProtocol:
32 """Listener of this class can implement the following method to get a
33 callback
34 """
35 def on_download_started(self, job):
36 """Called when the download starts
37
38 Args:
39 job (DownloadJob): Yang Model
40
41 """
42 pass
43
44 def on_download_progress(self, job):
45 """Called after each chunk is downloaded
46
47 Args:
48 job (DownloadJob): Yang Model
49
50 """
51 pass
52
53 def on_download_succeeded(self, job):
54 """Called when the download is completed successfully
55
56 Args:
57 job (DownloadJob): Yang Model
58
59 """
60 pass
61
62 def on_download_failed(self, job):
63 """Called when the download fails
64
65 Args:
66 job (DownloadJob): Yang Model
67
68 """
69 pass
70
71 def on_download_cancelled(self, job):
72 """Called when the download is canceled
73
74 Args:
75 job (DownloadJob): Yang Model
76
77 """
78 pass
79
80 def on_download_finished(self, job):
81 """Called when the download finishes regardless of the status of the
82 download (success, failed or canceled)
83
84 Args:
85 job (DownloadJob): Yang Model
86
87 """
88 pass
89
90
91 class DownloadStatus(enum.Enum):
92 STARTED = 1
93 IN_PROGRESS = 2
94 COMPLETED = 3
95 FAILED = 4
96 CANCELLED = 5
97
98
99 class DownloadMeta:
100 """Model data used by the downloader.
101 """
102 def __init__(self, url, dest_file):
103 self.url = url
104 self.filepath = dest_file
105 self.download_id = str(uuid.uuid4())
106 self.bytes_total = 0
107 self.progress_percent = 0
108 self.bytes_downloaded = 0
109 self.bytes_per_second = 0
110 self.status = None
111 self.start_time = 0
112 self.stop_time = 0
113 self.detail = ""
114
115 @property
116 def filename(self):
117 return os.path.basename(self.filepath)
118
119 def start_download(self):
120 self.start_time = time.time()
121
122 def end_download(self):
123 self.end_time = time.time()
124
125 def set_state(self, state):
126 self.status = state
127
128 def update_with_data(self, downloaded_chunk):
129 self.bytes_downloaded += len(downloaded_chunk)
130
131 if self.bytes_total != 0:
132 self.progress_percent = \
133 int((self.bytes_downloaded / self.bytes_total) * 100)
134
135 # compute bps
136 seconds_elapsed = time.time() - self.start_time
137 self.bytes_per_second = self.bytes_downloaded // seconds_elapsed
138
139 def update_data_with_head(self, headers):
140 """Update the model from the header of HEAD request
141
142 Args:
143 headers (dict): headers from HEAD response
144 """
145 if 'Content-Length' in headers:
146 self.bytes_total = int(headers['Content-Length'])
147
148 def as_dict(self):
149 return self.__dict__
150
151
152 class AbstractDownloader:
153
154 def __init__(self):
155 self._delegate = None
156
157 @property
158 def delegate(self):
159 return self._delegate
160
161 @delegate.setter
162 def delegate(self, delegate):
163 self._delegate = delegate
164
165 @abc.abstractproperty
166 def download_id(self):
167 pass
168
169 @abc.abstractmethod
170 def cancel_download(self):
171 pass
172
173 @abc.abstractmethod
174 def close(self):
175 pass
176
177 @abc.abstractmethod
178 def download(self):
179 pass