Пример #1
0
    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
Пример #2
0
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)