HEX
Server: Apache/2.2.34 (Unix) mod_fastcgi/mod_fastcgi-SNAP-0910052141
System: Linux Kou-Etsu-Dou 4.4.59+ #25556 SMP PREEMPT Thu Mar 4 18:03:46 CST 2021 x86_64
User: hosam (1026)
PHP: 7.2.29
Disabled: NONE
Upload Files
File: //volume1/@appstore/HyperBackup/addon/dropbox/python/dropbox_agent.py
#!/usr/bin/env python
#-*-coding: utf-8 -*-

import os, sys, json
from struct import pack, unpack
from syslog import syslog, LOG_ERR

PY3 = sys.version_info[0] == 3

# add include path
script_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
sys.path.insert(0, script_dir + '/module')
import dropbox
from dropbox.files import WriteMode
from dropbox.files import UploadSessionCursor
import requests

debug = False
def log_debug(*args):
        if debug:
                print >> sys.stderr, ' '.join(args)

def _is_scoket_exception(e):
        import socket
        if type(e) == socket.gaierror or type(e) == socket.error or type(e) == socket.herror or type(e) == socket.timeout:
                return True
        return False

def _convert_socket_error_code(message):
        error_code = -1
        if -1 != message.find("[Errno -2] Name or service not known"):
                error_code = -2
        elif -1 != message.find("[Errno -3] Temporary failure in name resolution"):
                error_code = -2
        elif -1 != message.find("[Errno -5] No address associated with hostname"):
                error_code = -2
        elif -1 != message.find("[Errno 110] Connection timed out"):
                error_code = 408
        elif -1 != message.find("[Errno 101] Network is unreachable"):
                error_code = -4
        elif -1 != message.find("[Errno 111] Connection refused"):
                error_code = -4
        elif -1 != message.find("[Errno 113] No route to host"):
                error_code = -4
        elif -1 != message.find("[Errno 104] Connection reset by peer"):
                error_code = -4
        elif -1 != message.find("[Errno 32] Broken pipe"):
                error_code = 408
        return error_code

def _is_ssl_timeout(message):
        #ssl.SSLErr_timeouteption log
        if -1 != message.find("timed out"):
                # The read operation timed out
                # The write operation timed out
                # The handshake operation timed out
                return True
        return False

def _convert_socket_exception(e):
        import socket

        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'

        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls
                if type(e) == socket.gaierror:
                        if hasattr(e, 'strerror') and e.strerror:
                                error_msg = e.strerror
                        if e.errno == -2:
                                # socket.gaierror: [Errno -2] Name or service not known
                                # 1. dns not set
                                # 2. set to a wrong dns
                                error_code = -2
                        elif e.errno == -3:
                                # socket.gaierror: [Errno -3] Temporary failure in name resolution
                                # man gai_strerror, and find EAI_AGAIN:
                                # The name server returned a temporary failure indication.  Try again later.
                                error_code = -2
                        elif e.errno == -5:
                                # socket.gaierror: [Errno -5] No address associated with hostname
                                # man gai_strerror, and find EAI_NODATA:
                                # The specified network host exists, but does not have any network addresses defined.
                                error_code = -2
                        elif e.errno < 100 and e.errno > 0:
                                error_code = e.errno
                elif type(e) == socket.error or type(e) == socket.herror:
                        if hasattr(e, 'strerror') and e.strerror:
                                error_msg = e.strerror
                        if e.errno == socket.errno.ETIMEDOUT:
                                # socket.error: [Errno 110] Connection timed out
                                error_code = 408
                        elif e.errno == socket.errno.ENETUNREACH:
                                # socket.error: [Errno 101] Network is unreachable
                                error_code = -4
                        elif e.errno == socket.errno.ECONNREFUSED:
                                # socket.error: [Errno 111] Connection refused
                                error_code = -4
                        elif e.errno == socket.errno.EHOSTUNREACH:
                                # socket.error: [Errno 113] No route to host
                                error_code = -4
                        elif e.errno == socket.errno.ECONNRESET:
                                # socket.error: [Errno 104] Connection reset by peer
                                error_code = -4
                        elif e.errno == socket.errno.EPIPE:
                                # socket.error: [Errno 32] Broken pipe
                                error_code = 408
                        elif e.errno < 100 and e.errno > 0:
                                error_code = e.errno
                        #syslog(LOG_ERR, "get network error %d:%s" % (e.errno, error_msg))
                elif type(e) == socket.timeout:
                        error_msg = 'timed out'
                        error_code = 408
                elif type(e) == requests.exceptions.ChunkedEncodingError:
                        error_code = -4
                else:
                        syslog(LOG_ERR, "BUG: exception [%s], type [%s]" % (str(e), type(e)))
                #syslog(LOG_ERR, "error %s:%d:%s" % (error_cls, error_code, str(error_msg)))

                if -1 == error_code:
                        if hasattr(e, "args"):
                                syslog(LOG_ERR, "error args: [%s]" % (str(e.args)))
                        if hasattr(e, "errno"):
                                syslog(LOG_ERR, "error errno: [%s]" % (str(e.errno)))
                        if hasattr(e, "strerror"):
                                syslog(LOG_ERR, "error strerror: [%s]" % (str(e.strerror)))
        except Exception as ee:
                syslog(LOG_ERR, "parse socket exception failed: [%s]" % (str(ee)))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }

def _convert_dropbox_write_error(e):
        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'

        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls
                error_msg = str(e)

                if e.is_conflict():
                        #Couldn’t write to the target path because there was something in the way
                        if e.get_conflict().is_folder():
                                error_code = 10001
                        elif e.get_conflict().is_file_ancestor():
                                error_code = 10002
                        elif e.get_conflict().is_file():
                                error_code = 10003
                        elif e.get_conflict().is_other():
                                error_code = 10004
                elif e.is_malformed_path():
                        error_code = 400
                elif e.is_disallowed_name():
                        #Dropbox will not save the file or folder because of its name.
                        error_code = 400
                elif e.is_insufficient_space():
                        #The user doesn’t have enough available space (bytes) to write more data.
                        error_code = 507
                elif e.is_no_write_permission():
                        #The user doesn’t have permissions to write to the target location.
                        error_code = 403
                elif e.is_too_many_write_operations():
                        #There are too many write operations
                        #happening in the user's Dropbox. You should retry uploading this file.
                        error_code = 429
                elif e.is_team_folder():
                        #This endpoint cannot move or delete team folders.
                        error_code = 10031
                elif e.is_other():
                        error_code = -1

        except Exception as e:
                syslog(LOG_ERR, "parse dropbox write exception failed. %s" % str(e))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }

def _convert_dropbox_lookup_error(e):
        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'

        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls
                error_msg = str(e)

                if e.is_malformed_path():
                        error_code = 400
                elif e.is_not_file():
                        #We were expecting a file, but the given path refers to something that isn’t a file.
                        error_code = 10011
                elif e.is_not_folder():
                        #We were expecting a folder, but the given path refers to something that isn’t a folder.
                        error_code = 10012
                elif e.is_not_found():
                        #There is nothing at the given path.
                        error_code = 404
                elif e.is_restricted_content():
                        #The file cannot be transferred because the content is restricted.
                        #For example, sometimes there are legal restrictions due to copyright claims.
                        error_code = 10013
                elif e.is_unsupported_content_type():
                        #This operation is not supported for this content type.
                        error_code = 10014
                elif e.is_other():
                        error_code = -1
        except Exception as e:
                syslog(LOG_ERR, "parse dropbox lookup exception failed. %s" % str(e))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }

def _convert_dropbox_upload_session_lookup_error(e):
        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'

        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls
                error_msg = str(e)
                if e.is_incorrect_offset():
                    #This error may occur when a previous request was received and processed successfully but the client did not receive the response
                        #e.g. due to a network error.
                        error_code = 10021
                elif e.is_closed():
                    #You are attempting to append data to an upload session that has alread been closed (i.e. committed).
                        error_code = -4
                elif e.is_not_closed():
                    #The session must be closed before calling upload_session/finish_batch.
                        error_code = -1
                elif e.is_not_found():
                    #The upload session id was not found
                        error_code = -1
                elif e.is_too_large():
                    #You can not append to the upload session because the size
                    #of a file should not reach the max file size limit (i.e. 350GB).
                        error_code = 413
                elif e.is_other():
                        error_code = -1
        except Exception as e:
                syslog(LOG_ERR, "parse dropbox upload session exception failed. %s" % str(e))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }

def _convert_dropbox_exception(e):
        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'
        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls
                error_msg = str(e)

                if type(e) == dropbox.files.CreateFolderError:
                        if e.is_path():
                               return _convert_dropbox_write_error(e.get_path())
                elif type(e) == dropbox.files.GetMetadataError:
                        if e.is_path():
                                return _convert_dropbox_lookup_error(e.get_path())
                elif type(e) == dropbox.files.ListFolderError:
                        if e.is_path():
                                return _convert_dropbox_lookup_error(e.get_path())
                        elif e.is_other():
                                error_code = -1
                elif type(e) == dropbox.files.ListFolderContinueError:
                        if e.is_path():
                                return _convert_dropbox_lookup_error(e.get_path())
                        elif e.is_reset():
                                #Indicates that the cursor has been invalidated. Call
                                #dropbox.dropbox.Dropbox.files_list_folder() to obtain a new cursor.
                                error_code = -1
                        elif e.is_other():
                                error_code = -1
                elif type(e) == dropbox.files.DeleteError:
                        if e.is_path_lookup():
                                return _convert_dropbox_lookup_error(e.get_path_lookup())
                        elif e.is_path_write():
                               return _convert_dropbox_write_error(e.get_path_write())
                        elif e.is_too_many_files():
                                error_code = 406
                        elif e.is_too_many_write_operations():
                                #There are too many write operations
                                #happening in the user's Dropbox. You should retry uploading this file.
                                error_code = 429
                        elif e.is_other():
                                error_code = -1
                elif type(e) == dropbox.files.UploadError:
                        if e.is_path():
                               return _convert_dropbox_write_error(e.get_path().reason)
                        elif e.is_properties_error():
                                #The supplied property group is invalid. The file has uploaded without
                                # property groups.
                                error_code = -1
                        elif e.is_other():
                               error_code = -1
                elif type(e) == dropbox.files.UploadSessionLookupError:
                        return _convert_dropbox_upload_session_lookup_error(e)
                elif type(e) == dropbox.files.UploadSessionFinishError:
                        if e.is_lookup_failed():
                                #The session arguments are incorrect; the value explains the reason.
                                return _convert_dropbox_upload_session_lookup_error(e.get_lookup_failed())
                        elif e.is_path():
                                #Unable to save the uploaded contents to a file.
                               return _convert_dropbox_write_error(e.get_path())
                        elif e.is_too_many_shared_folder_targets():
                                #The batch request commits files into too many different shared folders.
                                #Please limit your batch request to files contained in a single shared folder.
                                error_code = -1
                        elif e.is_too_many_write_operations():
                                #There are too many write operations
                                #happening in the user's Dropbox. You should retry uploading this file.
                                error_code = 429
                        elif e.is_properties_error():
                                #The supplied property group is invalid. The file has uploaded without
                                # property groups.
                                error_code = -1
                        elif e.is_other():
                                error_code = -1
                elif type(e) == dropbox.files.DownloadError:
                        if e.is_path():
                                return _convert_dropbox_lookup_error(e.get_path())
                        elif e.is_other():
                                error_code = -1

        except Exception as e:
                syslog(LOG_ERR, "parse dropbox exception failed. %s" % str(e))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }


def _convert_exception(e):
        #syslog(LOG_ERR, "convert_exception: %s" % str(e))
        import socket
        import httplib
        import ssl

        error_code = -1
        error_msg = 'Unknown'
        error_cls = 'Unknown'

        try:
                error_cls = type(e).__name__
                if hasattr(e, '__module__') and e.__module__:
                        error_cls = e.__module__ + '.' + error_cls

                try:
                        if type(e.message) is unicode:
                                error_msg = repr(e.message).split('\\n')[0]
                        else:
                                error_msg = str(e.message).split('\n')[0]
                        log_debug("\033[31mexception: \033[0m", error_msg)
                except:
                        log_debug("\033[31mexception: \033[0m", "could not parse error msg")
                if type(e) == dropbox.exceptions.ApiError:
                        #syslog(LOG_ERR, "dropbox Api error %s:%s:%s" % (str(e.request_id), str(e.error), str(e.user_message_text)))
                        return _convert_dropbox_exception(e.error)
                elif type(e) == dropbox.exceptions.AuthError:
                        error_code = 401
                        error_msg = str(e.error)
                elif type(e) == dropbox.exceptions.BadInputError:
                        error_code = 400
                elif type(e) == dropbox.exceptions.DropboxException:
                        #All errors related to making an API request extend this
                        error_code = -1
                        error_msg = str(e)
                elif type(e) == dropbox.exceptions.HttpError:
                        #Errors produced at the HTTP layer
                        error_code = e.status_code
                        error_msg = str(e)
                elif type(e) == dropbox.exceptions.InternalServerError:
                        #Errors due to a problem on Dropbox
                        error_code = e.status_code
                        error_msg = str(e)
                elif type(e) == dropbox.exceptions.RateLimitError:
                        #Error caused by rate limiting
                        error_code = 429
                        error_msg = str(e)
                elif type(e) == TypeError:
                        # this exception will raise when base64 decode for auth failed
                        if error_msg == "Incorrect padding":
                                error_code = 401
                elif type(e) == UnicodeDecodeError:
                        error_code = -5
                elif type(e) == requests.exceptions.ConnectionError:
                        error_code = -4
                        if type(e.args[0]) == requests.packages.urllib3.exceptions.ProtocolError:
                                if "BadStatusLine" in str(e.args[0]):
                                        error_code = -4
                                elif _is_scoket_exception(e.args[0].args[1]):
                                        return _convert_socket_exception(e.args[0].args[1])
                                else:
                                        syslog(LOG_ERR, "ProtocolError: exception [%s], type [%s]" % (str(e.args[0].args[1]), type(e.args[0].args[1])))
                        elif type(e.args[0]) == requests.packages.urllib3.exceptions.MaxRetryError:
                                if hasattr(e.args[0], 'reason') and e.args[0].reason:
                                        if type(e.args[0].reason) == requests.packages.urllib3.exceptions.NewConnectionError:
                                                error_code = _convert_socket_error_code(str(e.args[0].reason))
                                        else:
                                                syslog(LOG_ERR, "MaxRetryError: exception [%s], type [%s]" % (str(e.args[0].reason), type(e.args[0].reason)))
                        elif _is_scoket_exception(e.args[0]):
                                return _convert_socket_exception(e.args[0])
                        elif type(e.args[0]) == ssl.SSLError or type(e.args[0]) == requests.packages.urllib3.exceptions.SSLError:
                                if hasattr(e.args[0], 'message') and e.args[0].message:
                                        error_msg = e.args[0].message
                                if _is_ssl_timeout(str(error_msg)):
                                        error_code = 408
                                else:
                                        syslog(LOG_ERR, "SSLError: exception [%s], type [%s]" % (str(error_msg), type(error_msg)))
                elif type(e) == requests.exceptions.SSLError:
                        error_code = -4
                        # EOF occurred in violation of protocol
                        # SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC
                        # SSL: SSLV3_ALERT_BAD_RECORD_MAC
                        # SSL: SSLV3_ALERT_ILLEGAL_PARAMETER
                        # SSL: TLSV1_ALERT_DECRYPT_ERROR
                        # SSL: TLSV1_ALERT_DECODE_ERROR
                        # SSL: CERTIFICATE_VERIFY_FAILED
                        if _is_ssl_timeout(str(e)):
                                error_code = 408
                elif type(e) == requests.packages.urllib3.exceptions.NewConnectionError:
                        error_code = _convert_socket_error_code(str(e))
                elif type(e) == requests.packages.urllib3.exceptions.ConnectTimeoutError:
                        error_code = 408
                elif type(e) == requests.packages.urllib3.exceptions.ReadTimeoutError:
                        error_code = 408
                elif type(e) == requests.exceptions.ConnectTimeout:
                        error_code = 408
                elif type(e) == requests.exceptions.ReadTimeout:
                        error_code = 408
                elif type(e) == httplib.ResponseNotReady:
                        error_code = -4
                elif type(e) == httplib.BadStatusLine:
                        error_code = -4
                elif type(e) == httplib.IncompleteRead:
                        error_code = -4
                elif type(e) == ssl.SSLError:
                        error_code = -4
                        if hasattr(e, "strerror") and e.strerror:
                                # SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC
                                # SSL: SSLV3_ALERT_BAD_RECORD_MAC
                                # SSL: CERTIFICATE_VERIFY_FAILED
                                error_msg = e.strerror
                        if _is_ssl_timeout(str(error_msg)):
                                error_code = 408
                elif type(e) == ssl.SSLEOFError:
                        # ssl.SSLEOFError: [Errno 8] EOF occurred in violation of protocol
                        if hasattr(e, 'strerror') and e.strerror:
                                error_msg = e.strerror
                        error_code = -4
                elif type(e) == IOError:
                        if hasattr(e, 'strerror') and e.strerror:
                                error_msg = e.strerror
                        error_code = _convert_socket_error_code(str(e))
                elif _is_scoket_exception(e):
                        return _convert_socket_exception(e)
                else:
                        syslog(LOG_ERR, "exception [%s]" % str(e))
                        syslog(LOG_ERR, "type [%s]" % type(e))
                #syslog(LOG_ERR, "error %s:%d:%s" % (error_cls, error_code, str(error_msg)))

                if -1 == error_code:
                        if hasattr(e, "args"):
                                syslog(LOG_ERR, "error args: [%s]" % (str(e.args)))
                        if hasattr(e, "errno"):
                                syslog(LOG_ERR, "error errno: [%s]" % (str(e.errno)))
                        if hasattr(e, "strerror"):
                                syslog(LOG_ERR, "error strerror: [%s]" % (str(e.strerror)))

        except Exception as ee:
                syslog(LOG_ERR, "parse exception failed: [%s]" % (str(ee)))
                pass

        return {
                'success': False,
                'error_class': error_cls,
                'error_message': error_msg,
                'error_code': error_code
        }
def _convert_time(val):
        if val is None:
            return 0

        import calendar
        return calendar.timegm(val)

def _convert_properties(properties):
        out_json = {}
        if type(properties) is dropbox.files.FolderMetadata:
                out_json = {
                        'is_dir': True,
                        'path': properties.path_display,
                }
        elif type(properties) is dropbox.files.FileMetadata:
                out_json = {
                        'LastModified': _convert_time(properties.server_modified.utctimetuple()),
                        'ContentLength': properties.size,
                        'is_dir': False,
                        'path': properties.path_display,
                        'id': properties.id,
                        'rev': properties.rev,
                        'is_downloadable': properties.is_downloadable,
                        'content_hash': properties.content_hash,
                        'client_modified': _convert_time(properties.client_modified.utctimetuple())
                }
        elif type(properties) is dropbox.files.DeletedMetadata:
                out_json = {
                        'is_deleted': True,
                        'path': properties.path_display,
                }
        return out_json

class SimpleIO(object):
        def read_int(self):
                data = ''
                n = 4
                while n > 0:
                        read_data = sys.stdin.read(n)
                        if 0 == len(read_data):
                                raise StopIteration
                        data += read_data
                        n -= len(read_data)
                if data:
                        return unpack('i', data)[0]
                else:
                        # check eof?
                        raise StopIteration
        def read_string(self):
                n = self.read_int()
                if 0 == n:
                        return ''
                data = ''
                while n > 0:
                        read_data = sys.stdin.read(n)
                        if 0 == len(read_data):
                                raise StopIteration
                        data += read_data
                        n -= len(read_data)
                if data:
                        return data
                else:
                        raise SystemError
        def read_json(self):
                json_str = self.read_string()
                if json_str:
                        return json.loads(json_str)
                else:
                        return None
        def write_int(self, val):
                data = pack('i', val)
                sys.stdout.write(data)
                sys.stdout.flush()
        def write_string(self, val):
                self.write_int(len(val))
                sys.stdout.write(val)
                sys.stdout.flush()
                # log
        def write_json(self, val):
                s = json.dumps(val)
                self.write_string(s)
        def write_exception(self, e):
                self.write_json(_convert_exception(e))

class FileObjectWithProgress(object):
        """
        Readable file object with progress wrapper.
        """

        def __init__(self, io):
                """
                Wrap the underlying file object

                :param file_obj: the file object to wrap
                """
                self._io = io
                self._file_obj = None
                self._prev_process_size = 0

        def __getattr__(self, attr):
                return getattr(self._file_obj, attr)

        def set_file_obj(self, file_obj):
                self._file_obj = file_obj
                self._prev_process_size = 0

        def read(self, length=None):
                read_data = self._file_obj.read(length)
                self._prev_process_size += len(read_data)

                res = {
                        'success': True,
                        'complete': False,
                        'uploaded': self._prev_process_size
                }
                if self._io:
                        self._io.write_json(res)
                else:
                        print res
                return read_data

        def write(self, write_data):
                self._file_obj.write(write_data)
                self._prev_process_size += len(write_data)

                res = {
                        'success': True,
                        'complete': False,
                        'downloaded': self._prev_process_size
                }
                if self._io:
                        self._io.write_json(res)
                else:
                        print res
                return None
        def tell(self):
                return self._file_obj.tell();
        def seek(self, offset, whence=os.SEEK_SET):
                self._file_obj.seek(offset, whence)

class DropboxStoreageApi(object):
        def __init__(self, io=None):
            self._file_obj_progress = FileObjectWithProgress(io)
            access_token = os.environ.pop('DROPBOX_ACCESS_TOKEN', None)
            refresh_token = os.environ.pop('DROPBOX_REFRESH_TOKEN', None)
            client_id = os.environ.pop('DROPBOX_CLIENT_ID', None)
            client_secret = os.environ.pop('DROPBOX_CLIENT_SECRET', None)
            self.dropbox = dropbox.Dropbox(
                    oauth2_access_token=access_token,
                    oauth2_refresh_token=refresh_token,
                    app_key=client_id,
                    app_secret=client_secret
            )

        def metaData(self, in_json):
            #syslog(LOG_ERR, "metaData: %s" % str(in_json))
            path = in_json.get('path', None)
            metadata = self.dropbox.files_get_metadata(path, include_media_info=False,
                    include_deleted=False, include_has_explicit_shared_members=False)
            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata),
            }

            #print out_json
            return out_json

        def createDir(self, in_json):
            #print 'createDir:', in_json
            path = in_json.get('path', None)
            #print path
            metadata = self.dropbox.files_create_folder(path)

            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata)
            }
            return out_json

        def removeObject(self, in_json):
            #print 'removeObject:', in_json
            path = in_json.get('path', None)
            #print path
            metadata = self.dropbox.files_delete(path)

            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata)
            }
            return out_json

        def getAccountInfo(self, in_json):
            account = self.dropbox.users_get_current_account()
            account_type = ""
            team_id = ""
            team_name = ""
            if account.account_type.is_basic():
                    account_type = "basic"
            elif account.account_type.is_business():
                    account_type = "business"
            elif account.account_type.is_pro():
                    account_type = "pro"

            if account.team is not None:
                    team_id = account.team.id
                    team_name = account.team.name

            out_json = {
                    'success': True,
                    'name': account.name.display_name,
                    'account_id': account.account_id,
                    'account_type': account_type,
                    'disabled': account.disabled,
                    'email': account.email,
                    'email_verified': account.email_verified,
                    'country': account.country,
                    'is_paired': account.is_paired,
                    'locale': account.locale,
                    'team_id': team_id,
                    'team_name': team_name,
            }
            return out_json

        def getSpaceInfo(self, in_json):
            space = self.dropbox.users_get_space_usage()
            #print space
            individual_allocation = 0
            team_allocation = 0
            team_used  = 0
            if space.allocation.is_individual():
                    individual_allocation = space.allocation.get_individual().allocated
            if space.allocation.is_team():
                    team_allocation = space.allocation.get_team().allocated
                    team_used = space.allocation.get_team().used

            out_json = {
                    'success': True,
                    'individual_used': space.used,
                    'team_used': team_used,
                    'individual_allocation': individual_allocation,
                    'team_allocation': team_allocation
            }
            return out_json

        def putFile(self, in_json):
            #print 'in_json:', in_json
            from_path = in_json.get('from_path')
            to_path = in_json.get('to_path')

            with  open(from_path, "rb") as from_file:
                metadata = self.dropbox.files_upload(from_file.read(), to_path, autorename=False, mode=WriteMode('overwrite'), mute=True)

            #print 'Metadata:', metadata
            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata)
            }
            return out_json

        def getFileRevisions(self, in_json):
            path = in_json.get('path', None)
            result = self.dropbox.files_list_revisions(path)

            out_json = {
                    'success': True,
                    'Name': os.path.basename(path),
                    'entries': []
            }

            count = 0
            for metadata in result.entries:
                    print metadata
                    if metadata is not None:
                        out_json['entries'].append({
                            'Properties': _convert_properties(metadata)
                        })
                        count += 1

            out_json['count'] = count
            #print out_json
            return out_json

        def getFileAndMeta(self, in_json):
            from_path = in_json.get('from_path')
            to_path = in_json.get('to_path')
            rev = in_json.get('rev', None)

            metadata = self.dropbox.files_download_to_file(to_path, from_path, rev)

            #print 'Metadata:', metadata
            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata)
            }
            return out_json

        def startChunk(self, in_json):
            #print in_json
            from_path = in_json.get('from_path')
            length = int(in_json.get('length'))
            with open(from_path, "rb") as from_file:
                    self._file_obj_progress.set_file_obj(from_file)
                    result = self.dropbox.files_upload_session_start(self._file_obj_progress.read(length))
                    new_offset = self._file_obj_progress.tell()

            out_json = {
                    'success': True,
                    'upload_id': result.session_id,
                    'new_offset': new_offset
            }
            return out_json

        def putChunk(self, in_json):
            #print in_json
            from_path = in_json.get('from_path')
            length = int(in_json.get('length'))
            offset = int(in_json.get('offset', 0))
            upload_id = in_json.get('upload_id', None)
            #print "off_set:",offset, " upload_id:", upload_id
            with open(from_path, "rb") as from_file:
                    self._file_obj_progress.set_file_obj(from_file)
                    self._file_obj_progress.seek(offset)
                    self.dropbox.files_upload_session_append_v2(self._file_obj_progress.read(length),
                                                    UploadSessionCursor(upload_id, offset))
                    new_offset = self._file_obj_progress.tell()

            out_json = {
                    'success': True,
                    'upload_id': upload_id,
                    'new_offset': new_offset
            }
            return out_json

        def commitChunks(self, in_json):
            #print in_json
            from_path = in_json.get('from_path')
            to_path = in_json.get('to_path')
            offset = int(in_json.get('offset', 0))
            length = int(in_json.get('length'))
            upload_id = in_json.get('upload_id')
            commitInfo = dropbox.files.CommitInfo(path=to_path, mode=WriteMode('overwrite'), mute=True)
            with open(from_path, "rb") as from_file:
                self._file_obj_progress.set_file_obj(from_file)
                self._file_obj_progress.seek(offset)
                metadata = self.dropbox.files_upload_session_finish(self._file_obj_progress.read(length),
                                                                        UploadSessionCursor(upload_id, offset),
                                                                        commitInfo)

            out_json = {
                    'success': True,
                    'Name': os.path.basename(metadata.path_display),
                    'Properties': _convert_properties(metadata)
            }
            return out_json


        def listFolder(self, in_json):
            #syslog(LOG_ERR, "listFolder: %s" % str(in_json))
            #print in_json
            recursive = in_json.get('recursive', False)
            path = in_json.get('path', '')
            result = self.dropbox.files_list_folder(path, recursive)
            #print result
            count = 0
            out_json = {
                    'success': True,
                    'cursor': result.cursor,
                    'has_more': result.has_more,
                    'entries': []
            }
            #if not exist metadata is none, return count = 0
            for metadata in result.entries:
                    if metadata is not None:
                        out_json['entries'].append({
                            'Properties': _convert_properties(metadata)
                        })
                        count += 1

            out_json['count'] = count
            #print out_json
            return out_json
        def listFolderContinue(self, in_json):
            #syslog(LOG_ERR, "listFolderContinue: %s" % str(in_json))
            #print in_json
            cursor = in_json.get('cursor', None)
            result = self.dropbox.files_list_folder_continue(cursor)
            #print result
            count = 0
            out_json = {
                    'success': True,
                    'cursor': result.cursor,
                    'has_more': result.has_more,
                    'entries': []
            }
            #if not exist metadata is none, return count = 0
            for metadata in result.entries:
                    if metadata is not None:
                        out_json['entries'].append({
                            'Properties': _convert_properties(metadata)
                        })
                        count += 1

            out_json['count'] = count
            #print out_json
            return out_json


def start_server():
        io = SimpleIO()

        try:
                api = DropboxStoreageApi(io)
        except Exception as e:
                io.write_exception(e)
                return False

        io.write_string('start')

        while True:
                try:
                        in_json = io.read_json()
                        fn_name = in_json['fn']
                        fn = getattr(api, fn_name)
                        del in_json['fn']

                        if fn is None:
                                raise SystemError('no such fn: ' + fn_name)

                        #log_debug('\033[34mexecute: ' + fn_name + ' ' + json.dumps(in_json) + '\033[0m');

                        res = fn(in_json)
                        io.write_json(res)
                except StopIteration:
                        break
                except Exception as e:
                        io.write_exception(e)
                        continue

if __name__ == '__main__':
        res = start_server()

        sys.exit(0 if res else 1)