comparison sat/tools/stream.py @ 3968:0dd79c6cc1d2

tools (strem): fix `mode` + add `pre_close_cb` callback: rel 378
author Goffi <goffi@goffi.org>
date Mon, 31 Oct 2022 04:04:32 +0100
parents e4631d073c8b
children 524856bd7b19
comparison
equal deleted inserted replaced
3967:f461f11ea176 3968:0dd79c6cc1d2
16 # You should have received a copy of the GNU Affero General Public License 16 # You should have received a copy of the GNU Affero General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 18
19 """ interfaces """ 19 """ interfaces """
20 20
21 from argparse import OPTIONAL
22 from pathlib import Path
23 from typing import Callable, Optional, Union
21 import uuid 24 import uuid
22 import os 25 import os
23 from zope import interface 26 from zope import interface
24 from sat.core import exceptions 27 from sat.core import exceptions
25 from sat.core.constants import Const as C 28 from sat.core.constants import Const as C
29 from sat.core.core_types import SatXMPPEntity
26 from sat.core.log import getLogger 30 from sat.core.log import getLogger
27 from twisted.protocols import basic 31 from twisted.protocols import basic
28 from twisted.internet import interfaces 32 from twisted.internet import interfaces
29 33
34 from sat.core.sat_main import SAT
35
30 log = getLogger(__name__) 36 log = getLogger(__name__)
31 37
32 38
33 class IStreamProducer(interface.Interface): 39 class IStreamProducer(interface.Interface):
34 def startStream(consumer): 40 def startStream(consumer):
42 class SatFile: 48 class SatFile:
43 """A file-like object to have high level files manipulation""" 49 """A file-like object to have high level files manipulation"""
44 50
45 # TODO: manage "with" statement 51 # TODO: manage "with" statement
46 52
47 def __init__(self, host, client, path, mode="rb", uid=None, size=None, data_cb=None, 53 def __init__(
48 auto_end_signals=True, check_size_with_read=False): 54 self,
55 host: SAT,
56 client: SatXMPPEntity,
57 path: Union[str, Path],
58 mode: str = "rb",
59 uid: Optional[str] = None,
60 size: Optional[int] = None,
61 data_cb: Optional[Callable] = None,
62 auto_end_signals: bool = True,
63 check_size_with_read: bool = False,
64 pre_close_cb: Optional[Callable]=None
65 ) -> None:
49 """ 66 """
50 @param host: %(doc_host)s 67 @param host: %(doc_host)s
51 @param path(Path, str): path to the file to get or write to 68 @param path(Path, str): path to the file to get or write to
52 @param mode(str): same as for built-in "open" function 69 @param mode(str): same as for built-in "open" function
53 @param uid(unicode, None): unique id identifing this progressing element 70 @param uid(unicode, None): unique id identifing this progressing element
63 if False, you'll have to call self.progressFinished and self.progressError 80 if False, you'll have to call self.progressFinished and self.progressError
64 yourself. 81 yourself.
65 progressStarted signal is always sent automatically 82 progressStarted signal is always sent automatically
66 @param check_size_with_read(bool): if True, size will be checked using number of 83 @param check_size_with_read(bool): if True, size will be checked using number of
67 bytes read or written. This is useful when data_cb modifiy len of file. 84 bytes read or written. This is useful when data_cb modifiy len of file.
85 @param pre_close_cb:
68 """ 86 """
69 self.host = host 87 self.host = host
70 self.profile = client.profile 88 self.profile = client.profile
71 self.uid = uid or str(uuid.uuid4()) 89 self.uid = uid or str(uuid.uuid4())
72 self._file = open(path, mode) 90 self._file = open(path, mode)
73 self.size = size 91 self.size = size
74 self.data_cb = data_cb 92 self.data_cb = data_cb
75 self.auto_end_signals = auto_end_signals 93 self.auto_end_signals = auto_end_signals
94 self.pre_close_cb = pre_close_cb
76 metadata = self.getProgressMetadata() 95 metadata = self.getProgressMetadata()
77 self.host.registerProgressCb( 96 self.host.registerProgressCb(
78 self.uid, self.getProgress, metadata, profile=client.profile 97 self.uid, self.getProgress, metadata, profile=client.profile
79 ) 98 )
80 self.host.bridge.progressStarted(self.uid, metadata, client.profile) 99 self.host.bridge.progressStarted(self.uid, metadata, client.profile)
117 mutually exclusive with progress_metadata 136 mutually exclusive with progress_metadata
118 error can happen even if error is None, if current size differ from given size 137 error can happen even if error is None, if current size differ from given size
119 """ 138 """
120 if self._file.closed: 139 if self._file.closed:
121 return # avoid double close (which is allowed) error 140 return # avoid double close (which is allowed) error
141 if self.pre_close_cb is not None:
142 self.pre_close_cb()
122 if error is None: 143 if error is None:
123 try: 144 try:
124 size_ok = self.checkSize() 145 size_ok = self.checkSize()
125 except exceptions.NotFound: 146 except exceptions.NotFound:
126 size_ok = True 147 size_ok = True
180 self._file.seek(offset, whence) 201 self._file.seek(offset, whence)
181 202
182 def tell(self): 203 def tell(self):
183 return self._file.tell() 204 return self._file.tell()
184 205
206 @property
185 def mode(self): 207 def mode(self):
186 return self._file.mode() 208 return self._file.mode
187 209
188 def getProgressMetadata(self): 210 def getProgressMetadata(self):
189 """Return progression metadata as given to progressStarted 211 """Return progression metadata as given to progressStarted
190 212
191 @return (dict): metadata (check bridge for documentation) 213 @return (dict): metadata (check bridge for documentation)