def open(self): rq = { 'command': 'request_download', 'file_ids': [self.file_id], } api.resolve_record_access_path(self.params, self.record_uid, path=rq) rs = api.communicate(self.params, rq) if rs['result'] == 'success': dl = rs['downloads'][0] if 'url' in dl: with requests.get(dl['url'], stream=True) as rq_http: yield rq_http.raw
def upload_attachment(params, attachments): ''' :param attachments: :type attachments: [(str, ImportAttachment)] ''' print('Uploading attachments:') while len(attachments) > 0: chunk = attachments[:90] attachments = attachments[90:] uploads = None file_no = 0 file_size = 0 for _, att in chunk: file_no += 1 file_size += att.size or 0 #TODO check storage subscription rq = {'command': 'request_upload', 'file_count': file_no} try: rs = api.communicate(params, rq) if rs['result'] == 'success': uploads = rs['file_uploads'] except Exception as e: logging.error(e) return uploaded = {} for record_id, atta in chunk: if not uploads: break try: upload = uploads.pop() buffer = io.BytesIO() cipher = None key = atta.key if not key: key = os.urandom(32) iv = os.urandom(16) cipher = AES.new(key, AES.MODE_CBC, iv) buffer.write(iv) with atta.open() as s: finished = False while not finished: chunk = s.read(10240) if len(chunk) > 0: if cipher is not None: if len(chunk) < 10240: finished = True chunk = api.pad_binary(chunk) chunk = cipher.encrypt(chunk) buffer.write(chunk) else: finished = True size = buffer.tell() - 16 if size > 0: buffer.seek(0, io.SEEK_SET) files = { upload['file_parameter']: (atta.name, buffer, 'application/octet-stream') } print('{0} ... '.format(atta.name), end='', flush=True) response = requests.post(upload['url'], files=files, data=upload['parameters']) if response.status_code == upload['success_status_code']: if record_id not in uploaded: uploaded[record_id] = [] uploaded[record_id].append({ 'key': base64.urlsafe_b64encode(key).decode().rstrip('='), 'name': atta.name, 'file_id': upload['file_id'], 'size': size }) print('Done') else: print('Failed') except Exception as e: logging.warning(e) if len(uploaded) > 0: rq = { 'command': 'record_update', 'pt': 'Commander', 'device_id': 'Commander', 'client_time': api.current_milli_time(), 'update_records': [] } for record_id in uploaded: if record_id in params.record_cache: rec = params.record_cache[record_id] extra = json.loads(rec['extra_unencrypted'].decode( 'utf-8')) if 'extra' in rec else {} files = extra.get('files') if files is None: files = [] extra['files'] = files udata = rec['udata'] if 'udata' in rec else {} file_ids = udata.get('file_ids') if file_ids is None: file_ids = [] udata['file_ids'] = file_ids for atta in uploaded[record_id]: file_ids.append(atta['file_id']) files.append({ 'id': atta['file_id'], 'name': atta['name'], 'size': atta['size'], 'key': atta['key'] }) ru = { 'record_uid': record_id, 'version': 2, 'client_modified_time': api.current_milli_time(), 'extra': api.encrypt_aes( json.dumps(extra).encode('utf-8'), rec['record_key_unencrypted']), 'udata': udata, 'revision': rec['revision'] } api.resolve_record_access_path(params, record_id, path=ru) rq['update_records'].append(ru) try: rs = api.communicate(params, rq) if rs['result'] == 'success': api.sync_down(params) except Exception as e: logging.debug(e)