Example #1
0
def dropbox_post_connect_tasks(backend,
                               details,
                               response,
                               user=None,
                               is_new=False,
                               *args,
                               **kwargs):

    from dropbox import Dropbox, DropboxTeam, create_session

    print 'dropbox_post_connect_tasks'

    print 'backend:  %s' % backend
    print 'details:  %s' % details
    print 'response: %s' % response
    print 'user:     %s' % user
    print 'is_new:   %s' % is_new
    print

    # Get Access Token and Secret
    try:
        social_user = UserSocialAuth.objects.get(user=user, provider='dropbox')
    except UserSocialAuth.DoesNotExist:
        social_user = None

    print social_user

    access_token = social_user.tokens['access_token']

    token = access_token.split('&')[0].split('=')[1]
    secret = access_token.split('&')[1].split('=')[1]

    print 'token:  %s' % token
    print 'secret: %s' % secret

    sess = session.DropboxSession(DROPBOX_APP_ID, DROPBOX_API_SECRET)
    sess.set_token(token, secret)
    c = client.DropboxClient(sess)

    oauth2_access_token = c.create_oauth2_access_token()

    print oauth2_access_token

    dbx = Dropbox(oauth2_access_token)

    paths = [
        '/Downloads',
        '/Uploads',
        '/Uploads [completed]',
        '/Uploads [errors]',
    ]

    for path in paths:
        try:
            dbx.files_create_folder(path)
        except Exception as e:
            print e
Example #2
0
class DropboxConnector:
    def __init__(self, account):
        self.client = Dropbox(account["access_token"])

    # Dropbox does not like the "/" path for some stupid reason...
    # "" refers to the root directory
    @staticmethod
    def convert_to_dropbox_path(path):
        if path == "/":
            return ""
        else:
            return path

    def make_directory(self, path):
        self.client.files_create_folder(path)

    def change_mode(self, path, mode):
        pass

    def change_owner(self, path, user_id, group_id):
        pass

    def getattr(self, path, file_handle=None):
        dropbox_path = DropboxConnector.convert_to_dropbox_path(path)
        metadata = self.client.files_get_metadata(dropbox_path)
        file_status = FileStatus()

        # I'm going to change this hard coded stuff later
        file_status.group_id = 20
        file_status.user_id = 501

    @property
    def total_storage(self):
        space_usage = self.client.users_get_space_usage()
        return space_usage.allocation.get_individual().allocated

    @property
    def free_storage(self):
        space_usage = self.client.users_get_space_usage()
        return space_usage.used
Example #3
0
class DropboxFS(FS):
    def __init__(self, accessToken):
        super().__init__()
        self.dropbox = Dropbox(accessToken)
        _meta = self._meta = {
            "case_insensitive": False,  # I think?
            "invalid_path_chars": ":",  # not sure what else
            "max_path_length": None,  # don't know what the limit is
            "max_sys_path_length": None,  # there's no syspath
            "network": True,
            "read_only": False,
            "supports_rename": False  # since we don't have a syspath...
        }

    def __repr__(self):
        return "<DropboxDriveFS>"

    def _infoFromMetadata(self, metadata):  # pylint: disable=no-self-use
        rawInfo = {
            "basic": {
                "name": metadata.name,
                "is_dir": isinstance(metadata, FolderMetadata),
            }
        }
        if isinstance(metadata, FileMetadata):
            rawInfo.update({
                "details": {
                    "accessed": None,  # not supported by Dropbox API
                    "created": None,  # not supported by Dropbox API?,
                    "metadata_changed": None,  # not supported by Dropbox
                    "modified": datetime_to_epoch(
                        metadata.server_modified
                    ),  # API documentation says that this is reliable
                    "size": metadata.size,
                    "type": 0
                },
                "dropbox": {
                    "content_hash": metadata.
                    content_hash,  # see https://www.dropbox.com/developers/reference/content-hash
                    "rev": metadata.rev,
                    "client_modified": metadata.
                    client_modified  # unverified value coming from dropbox clients
                }
            })
            if metadata.media_info is not None and metadata.media_info.is_metadata(
            ) is True:
                media_info_metadata = metadata.media_info.get_metadata()
                if media_info_metadata.time_taken is not None:
                    rawInfo.update({
                        "media_info": {
                            "taken_date_time":
                            datetime_to_epoch(media_info_metadata.time_taken)
                        }
                    })
                if media_info_metadata.location is not None:
                    rawInfo.update({
                        "media_info": {
                            "location_latitude":
                            media_info_metadata.location.latitude,
                            "location_longitude":
                            media_info_metadata.location.longitude
                        }
                    })
                # Dropbox doesn't parse some jpgs properly
                if media_info_metadata.dimensions is not None:
                    rawInfo.update({
                        "media_info": {
                            "dimensions_height":
                            media_info_metadata.dimensions.height,
                            "dimensions_width":
                            media_info_metadata.dimensions.width
                        }
                    })
        elif isinstance(metadata, FolderMetadata):
            rawInfo.update({
                "details": {
                    "accessed": None,  # not supported by Dropbox API
                    "created": None,  # not supported by Dropbox API,
                    "metadata_changed": None,  # not supported by Dropbox
                    "modified": None,  # not supported for folders
                    "size": None,  # not supported for folders
                    "type": 1
                }
            })
        else:
            assert False, f"{metadata.name}, {metadata}, {type(metadata)}"
        return Info(rawInfo)

    def getinfo(self, path, namespaces=None):
        if path == "/":
            return Info({"basic": {"name": "", "is_dir": True}})
        try:
            if not path.startswith("/"):
                path = "/" + path
            metadata = self.dropbox.files_get_metadata(path,
                                                       include_media_info=True)
        except ApiError as e:
            raise ResourceNotFound(path=path, exc=e)
        return self._infoFromMetadata(metadata)

    def setinfo(self, path, info):  # pylint: disable=too-many-branches
        # dropbox doesn't support changing any of the metadata values
        pass

    def listdir(self, path):
        return [x.name for x in self.scandir(path)]

    def makedir(self, path, permissions=None, recreate=False):
        try:
            folderMetadata = self.dropbox.files_create_folder(path)
        except ApiError as e:
            assert isinstance(e.reason, CreateFolderError)
            # TODO - there are other possibilities
            raise DirectoryExpected(path=path)
        # don't need to close this filesystem so we return the non-closing version
        return SubFS(self, path)

    def openbin(self, path, mode="r", buffering=-1, **options):
        mode = Mode(mode)
        exists = True
        isDir = False
        try:
            isDir = self.getinfo(path).is_dir
        except ResourceNotFound:
            exists = False
        if mode.exclusive and exists:
            raise FileExists(path)
        elif mode.reading and not mode.create and not exists:
            raise ResourceNotFound(path)
        elif isDir:
            raise FileExpected(path)
        return DropboxFile(self.dropbox, path, mode)

    def remove(self, path):
        try:
            self.dropbox.files_delete(path)
        except ApiError as e:
            raise FileExpected(path=path, exc=e)

    def removedir(self, path):
        try:
            self.dropbox.files_delete(path)
        except ApiError as e:
            assert e.reason is DeleteError
            raise DirectoryExpected(path=path, exc=e)

    # non-essential method - for speeding up walk
    def scandir(self, path, namespaces=None, page=None):
        #
        if path == "/":
            path = ""
        # get all the avaliable metadata since it's cheap
        # TODO - this call has a recursive flag so we can either use that and cache OR override walk
        result = self.dropbox.files_list_folder(path, include_media_info=True)
        allEntries = result.entries
        while result.has_more:
            result = self.dropbox.files_list_folder_continue(result.cursor)
            allEntries += result.entries
        return [self._infoFromMetadata(x) for x in allEntries]
Example #4
0
class DropboxStorage(Storage):
    """
    A storage class providing access to resources in a Dropbox folder.
    """
    def __init__(self, token=ACCESS_TOKEN, location=ROOT_FOLDER):
        if not token:
            raise ImproperlyConfigured("You must configure an access token at "
                                       "'settings.DROPBOX_ACCESS_TOKEN'.")

        self.client = Dropbox(token)
        self.account_info = self.client.users_get_current_account()
        self.location = location or DEFAULT_ROOT_FOLDER
        self.base_url = 'https://dl.dropboxusercontent.com/'

    def _get_abs_path(self, name):
        return os.path.realpath(os.path.join(self.location, name))

    def _open(self, name, mode='rb'):
        name = self._get_abs_path(name)
        remote_file = DropboxFile(name, self, mode=mode)
        return remote_file

    def _save(self, name, content):
        name = self._get_abs_path(name)
        directory = os.path.dirname(name)
        if not self.exists(directory) and directory:
            self.client.files_create_folder(directory)
        # response = self.client.files_get_metadata(directory)
        # if not response['is_dir']:
        #     raise IOError("%s exists and is not a directory." % directory)
        abs_name = os.path.realpath(os.path.join(self.location, name))
        self.client.files_upload(content.read(), abs_name)
        return name

    def delete(self, name):
        name = self._get_abs_path(name)
        try:
            self.client.files_delete(name)
        except ApiError as e:
            if isinstance(e.error, DeleteError)\
                    and e.error.is_path_lookup()\
                    and e.error.get_path_lookup().is_not_found():
                # not found
                return False
            # error
            raise e
        # deleted
        return True

    def exists(self, name):
        name = self._get_abs_path(name)
        try:
            self.client.files_get_metadata(name)
        except ApiError as e:
            if hasattr(e.error, 'is_path')\
                    and e.error.is_path()\
                    and e.error.get_path().is_not_found():
                # not found
                return False
            # error
            raise e
        # found
        return True

    def listdir(self, path):
        path = self._get_abs_path(path)
        response = self.client.files_list_folder(path)
        directories = []
        files = []
        for entry in response.entries:
            if isinstance(entry, FolderMetadata):
                directories.append(os.path.basename(entry.path_display))
            elif isinstance(entry, FileMetadata):
                files.append(os.path.basename(entry.path_display))
        return directories, files

    def size(self, name):
        name = self._get_abs_path(name)
        return self.client.files_get_metadata(name).size

    def url(self, name):
        name = self._get_abs_path(name)
        return self.client.files_get_temporary_link(name).link

    def modified_time(self, name):
        name = self._get_abs_path(name)
        return self.client.files_get_metadata(name).server_modified

    def accessed_time(self, name):
        name = self._get_abs_path(name)
        # Note to the unwary, this is actually an mtime
        return self.client.files_get_metadata(name).client_modified

    def get_available_name(self, name, max_length=None):
        """
        Returns a filename that's free on the target storage system, and
        available for new content to be written to.
        """
        name = self._get_abs_path(name)
        dir_name, file_name = os.path.split(name)
        file_root, file_ext = os.path.splitext(file_name)
        # If the filename already exists, add an underscore and a number (before
        # the file extension, if one exists) to the filename until the generated
        # filename doesn't exist.
        count = itertools.count(1)
        while self.exists(name):
            # file_ext includes the dot.
            _fn = "%s_%s%s" % (file_root, count.next(), file_ext)
            name = os.path.join(dir_name, _fn)

        return name
Example #5
0
class DropboxStorage(Storage):
    """
    A storage class providing access to resources in a Dropbox Public folder.
    """

    def __init__(self, location='/Public'):
        self.client = Dropbox(ACCESS_TOKEN)
        self.account_info = self.client.users_get_current_account()
        self.location = location
        self.base_url = 'https://dl.dropboxusercontent.com/'

    def _get_abs_path(self, name):
        return os.path.realpath(os.path.join(self.location, name))

    def _open(self, name, mode='rb'):
        name = self._get_abs_path(name)
        remote_file = DropboxFile(name, self, mode=mode)
        return remote_file

    def _save(self, name, content):
        name = self._get_abs_path(name)
        directory = os.path.dirname(name)
        if not self.exists(directory) and directory:
            self.client.files_create_folder(directory)
        # response = self.client.files_get_metadata(directory)
        # if not response['is_dir']:
        #     raise IOError("%s exists and is not a directory." % directory)
        abs_name = os.path.realpath(os.path.join(self.location, name))
        foo = self.client.files_upload(content.read(), abs_name)
        return name

    def delete(self, name):
        name = self._get_abs_path(name)
        self.client.files_delete(name)

    def exists(self, name):
        name = self._get_abs_path(name)
        try:
            self.client.files_get_metadata(name)
        except ApiError as e:
            if e.error.is_path() and e.error.get_path().is_not_found():  # not found
                return False
            raise e
        return True

    def listdir(self, path):
        path = self._get_abs_path(path)
        response = self.client.files_list_folder(path)
        directories = []
        files = []
        for entry in response.entries:
            if type(entry) == FolderMetadata:
                directories.append(os.path.basename(entry.path_display))
            elif type(entry) == FileMetadata:
                files.append(os.path.basename(entry.path_display))
        return directories, files

    def size(self, name):
        cache_key = 'django-dropbox-size:{}'.format(filepath_to_uri(name))
        size = cache.get(cache_key)

        if not size:
            size = self.client.files_get_metadata(name).size
            cache.set(cache_key, size, CACHE_TIMEOUT)
        return size

    def url(self, name):
        if name.startswith(self.location):
            name = name[len(self.location) + 1:]

        name = os.path.basename(self.location) + "/" + name

        if self.base_url is None:
            raise ValueError("This file is not accessible via a URL.")

        myurl = urlparse.urljoin(self.base_url, filepath_to_uri(name))

        if "static" not in self.location:
            # Use a dynamic URL for "non-static" files.
            try:
                new_name = os.path.dirname(self.location) + "/" + name
                fp = filepath_to_uri(new_name)
                cache_key = 'django-dropbox-size:{}'.format(fp)
                myurl = cache.get(cache_key)
                if not myurl:
                    try:
                        shared_link = self.client.sharing_create_shared_link(fp)
                        myurl = shared_link.url + '&raw=1'
                        logger.debug("shared link: {0}, myurl: {1}".format(shared_link, myurl))
                    except Exception,e:
                        logger.exception(e)
                    if myurl is None:
                        temp_link = self.client.files_get_temporary_link(fp)
                        myurl = temp_link.link
                        logger.debug("temp link: {0}, myurl: {1}".format(temp_link, myurl))
                    cache.set(cache_key, myurl, SHARE_LINK_CACHE_TIMEOUT)
            except Exception,e:
                logger.exception(e)

        return myurl

        """
Example #6
0
class DropboxStorage(Storage):
    """
    A storage class providing access to resources in a Dropbox Public folder.
    """
    def __init__(self, location='/Public'):
        self.client = Dropbox(ACCESS_TOKEN)
        self.account_info = self.client.users_get_current_account()
        self.location = location
        self.base_url = 'https://dl.dropboxusercontent.com/'

    def _get_abs_path(self, name):
        return os.path.realpath(os.path.join(self.location, name))

    def _open(self, name, mode='rb'):
        name = self._get_abs_path(name)
        remote_file = DropboxFile(name, self, mode=mode)
        return remote_file

    def _save(self, name, content):
        name = self._get_abs_path(name)
        directory = os.path.dirname(name)
        if not self.exists(directory) and directory:
            self.client.files_create_folder(directory)
        # response = self.client.files_get_metadata(directory)
        # if not response['is_dir']:
        #     raise IOError("%s exists and is not a directory." % directory)
        abs_name = os.path.realpath(os.path.join(self.location, name))
        foo = self.client.files_upload(content.read(), abs_name)
        return name

    def delete(self, name):
        name = self._get_abs_path(name)
        self.client.files_delete(name)

    def exists(self, name):
        name = self._get_abs_path(name)
        try:
            self.client.files_get_metadata(name)
        except ApiError as e:
            if e.error.is_path() and e.error.get_path().is_not_found(
            ):  # not found
                return False
            raise e
        return True

    def listdir(self, path):
        path = self._get_abs_path(path)
        response = self.client.files_list_folder(path)
        directories = []
        files = []
        for entry in response.entries:
            if type(entry) == FolderMetadata:
                directories.append(os.path.basename(entry.path_display))
            elif type(entry) == FileMetadata:
                files.append(os.path.basename(entry.path_display))
        return directories, files

    def size(self, name):
        cache_key = 'django-dropbox-size:{}'.format(filepath_to_uri(name))
        size = cache.get(cache_key)

        if not size:
            size = self.client.files_get_metadata(name).size
            cache.set(cache_key, size, CACHE_TIMEOUT)
        return size

    def url(self, name):
        cache_key = 'django-dropbox-size:{}'.format(filepath_to_uri(name))
        url = cache.get(cache_key)

        if not url:
            url = self.client.files_get_temporary_link(name).link
            cache.set(cache_key, url, SHARE_LINK_CACHE_TIMEOUT)

        return url

    def get_available_name(self, name):
        """
        Returns a filename that's free on the target storage system, and
        available for new content to be written to.
        """
        name = self._get_abs_path(name)
        dir_name, file_name = os.path.split(name)
        file_root, file_ext = os.path.splitext(file_name)
        # If the filename already exists, add an underscore and a number (before
        # the file extension, if one exists) to the filename until the generated
        # filename doesn't exist.
        count = itertools.count(1)
        while self.exists(name):
            # file_ext includes the dot.
            name = os.path.join(
                dir_name, "%s_%s%s" % (file_root, count.next(), file_ext))

        return name
Example #7
0
class rpiImageDbxClass(rpiBaseClass):
	"""
	Implements the rpiImageDb class to manage images in a remote directory (dropbox).
	"""

	def __init__(self, name, rpi_apscheduler, rpi_events, rpi_config, cam_rpififo=None):

		### Get the Dbx error event
		#self._eventDbErr 	= rpi_events.eventErrList["DBXJob"]

		### Get the custom config parameters
		self._config = rpi_config

		### Get FIFO buffer for images from the camera (deque)
		self._imageFIFO = cam_rpififo

		### The FIFO buffer for the uploaded images (deque)
		self.imageUpldFIFO = rpififo.rpiFIFOClass([], 576)
		self.imageUpldFIFO.crtSubDir = ''

		### Init base class
		super().__init__(name, rpi_apscheduler, rpi_events)

	def __repr__(self):
		return "<%s (name=%s, rpi_apscheduler=%s, rpi_events=dict(), rpi_config=%s, dbuff_rpififo=%s)>" % (self.__class__.__name__, self.name, self._sched, self._config, self._imageFIFO)

	def __str__(self):
		msg = super().__str__()
		return "%s::: dbinfo: %s, config: %s\nimageUpldFIFO: %s\n%s" % \
				(self.name, self.dbinfo, self._config, self.imageUpldFIFO, msg)

	def __del__(self):
		### Clean base class
		super().__del__()



	#
	# Main interface methods
	#

	def jobRun(self):

		try:
			# Lock the buffer
			self._imageFIFO.acquireSemaphore()

			# Get the current images in the FIFO
			# Refresh the last remote image when available
			if len(self._imageFIFO):

				# Update remote cam image with the current (last) image
				if not (self._imageFIFO[-1] == self.crt_image_snap):
					self._putImage(self._imageFIFO[-1], self._config['image_snap'], True)
					self.crt_image_snap = self._imageFIFO[-1]
					self.numImgUpdDb += 1
					logging.info("Updated remote %s with %s" % (self._config['image_snap'], self._imageFIFO[-1]) )


				# Lock the upload buffer
				self.imageUpldFIFO.acquireSemaphore()

				# Check if a new upload sub-folder has to be used
				if not (self.imageUpldFIFO.crtSubDir == self._imageFIFO.crtSubDir):
					self.imageUpldFIFO.crtSubDir = self._imageFIFO.crtSubDir
					self.upldir = os.path.normpath(os.path.join(self._config['image_dir'], self.imageUpldFIFO.crtSubDir))
					self._mkdirImage(self.upldir)

				# Upload only images in the FIFO which have not been uploaded yet
				for img in self._imageFIFO:
					if not img in self.imageUpldFIFO:
						self._putImage(img, os.path.join(self.upldir, os.path.basename(img)))
						logging.info("Uploaded %s" % img )

				# Release the upload buffer
				self.imageUpldFIFO.releaseSemaphore()

				# Update status
				self.statusUpdate = (self.name, self.numImgUpdDb)

			else:
				# Update status
				self.statusUpdate = (self.name, ERRNONE)

				logging.info('Nothing to upload')


		# Handle exceptions, mostly HTTP/SSL related!
		except exceptions.Timeout as e:
			# Catching this error will catch both ReadTimeout and ConnectTimeout.
			raise rpiBaseClassError("%s::: jobRun(): Connect/ReadTimeoutError:\n%s" % (self.name, str(e)), ERRLEV2)

		except exceptions.ConnectionError as e:
			# A Connection error occurred.
			raise rpiBaseClassError("%s::: jobRun(): ConnectionError:\n%s" % (self.name, str(e)), ERRLEV2)

		except exceptions.HTTPError as e:
			# An HTTP error occurred.
			raise rpiBaseClassError("%s::: jobRun(): HTTPError:\n%s" % (self.name, str(e)), ERRLEV2)

		except exceptions.RequestException as e:
			# There was an ambiguous exception that occurred while handling your request.
			raise rpiBaseClassError("%s::: jobRun(): RequestException:\n%s" % (self.name, str(e)), ERRLEV2)

# 			except BadStatusLine as e:
# 				self.eventErr_set('run()')
# 				logging.debug("BadStatusLine:\n%s" % str(e))
# 				pass

		except rpiBaseClassError as e:
			if e.errval == ERRCRIT:
				self.endDayOAM()
			raise rpiBaseClassError("%s::: jobRun(): %s" % (self.name, e.errmsg), e.errval)

		except RuntimeError as e:
			self.endDayOAM()
			raise rpiBaseClassError("%s::: jobRun(): RuntimeError:\n%s" % (self.name, str(e)), ERRCRIT)

		except:
			self.endDayOAM()
			raise rpiBaseClassError("%s::: jobRun(): Unhandled Exception:\n%s" % (self.name, str(sys.exc_info())), ERRCRIT)

		finally:
			# Release the buffer
			self._imageFIFO.releaseSemaphore()


	def initClass(self):
		""""
		(re)Initialize the class.
		"""

		#self.imageDbHash = None
		self._imageDbCursor = None
		self.imageDbList = []
		self.numImgUpdDb = 0

		self.crt_image_snap = None
		self.imgid = self._imageFIFO.camID + '.jpg'
		self.upldir = os.path.normpath(os.path.join(self._config['image_dir'], self.imageUpldFIFO.crtSubDir))
		self.logfile = './upldlog.json'

		### When there are already images listed in the upload log file, then
		# make sure we don't upload them to the remote folder again
		# Else, create the file with an empty list; to be updated in endDayOAM()
		try:
			self.imageUpldFIFO.acquireSemaphore()
			self.imageUpldFIFO.clear()

			if os.path.isfile(self.logfile):
				with open(self.logfile,'r') as logf:
					upldimg = json.load(logf)

				for img in upldimg:
					self.imageUpldFIFO.append(img)

				del upldimg

				logging.info("%s::: Local log file %s found and loaded." % (self.name, self.logfile))
			else:
				with open(self.logfile,'w') as logf:
					json.dump([], logf)
					logging.info("%s::: Local log file %s initialized." % (self.name, self.logfile))

		except IOError:
			raise rpiBaseClassError("%s::: initClass(): Local log file %s was not found or could not be created." % (self.name, self.logfile), ERRCRIT)

		finally:
			# Release the upload buffer
			self.imageUpldFIFO.releaseSemaphore()

		### Init Dropbox API client
		self._token_file = self._config['token_file']
		self._dbx = None
		self.dbinfo = None
		try:
			with open(self._token_file, 'r') as token:
				self._dbx = Dropbox(token.read())

			info = self._dbx.users_get_current_account()
			# info._all_field_names_ =
			# {'account_id', 'is_paired', 'locale', 'email', 'name', 'team', 'country', 'account_type', 'referral_link'}
			self.dbinfo ={'email': info.email, 'referral_link': info.referral_link}

			logging.info("%s::: Loaded access token from ''%s''" % (self.name, self._token_file) )

			### Create remote root folder (relative to app root) if it does not exist yet
			self._mkdirImage(os.path.normpath(self._config['image_dir']))

		except rpiBaseClassError as e:
			if e.errval == ERRCRIT:
				self.endDayOAM()
			raise rpiBaseClassError("initClass(): %s" % e.errmsg, e.errval)

		except IOError:
			self.endDayOAM()
			raise rpiBaseClassError("initClass(): Token file ''%s'' could not be read." % (self.name, self._token_file), ERRCRIT)

		except AuthError as e:
			self.endDayOAM()
			raise rpiBaseClassError("initClass(): AuthError:\n%s" % e.error, ERRCRIT)

		except DropboxException as e:
			self.endDayOAM()
			raise rpiBaseClassError("initClass(): DropboxException:\n%s" %  str(e), ERRCRIT)

		except InternalServerError as e:
			self.endDayOAM()
			raise rpiBaseClassError("initClass(): InternalServerError:\n%s" % str(e.status_code),  ERRCRIT)


	def endDayOAM(self):
		"""
		End-of-Day Operation and Maintenance sequence.
		"""

		self._lsImage(self.upldir)
		logging.info("%s::: %d images in the remote folder %s" % (self.name, len(self.imageDbList), self.upldir))

		# Lock the uplaod buffer
		self.imageUpldFIFO.acquireSemaphore()

		try:
			upldimg=[]
			for img in self.imageUpldFIFO:
				upldimg.append(img)

			with open(self.logfile,'w') as logf:
				json.dump(upldimg, logf)

			del upldimg

			logging.info("%s::: Local log file %s updated." % (self.name, self.logfile))

		except IOError:
			raise rpiBaseClassError("endDayOAM(): Local log file %s was not found." % self.logfile,  ERRCRIT)

		finally:
			# Release the upload buffer
			self.imageUpldFIFO.releaseSemaphore()

#	def endOAM(self):
#		"""
#		End OAM procedure.
#		"""
	@atexit.register
	def atexitend():
		self.endDayOAM()

	def _lsImage(self,from_path):
		"""
		List the image/video files in the remote directory.
		Stores the found file names in self.imageDbList.
		"""
		try:
			if self._imageDbCursor is None:
				self.ls_ref = self._dbx.files_list_folder('/' + os.path.normpath(from_path), recursive=False, include_media_info=True )
			else:
				new_ls = self._dbx.files_list_folder_continue(self._imageDbCursor)
				if new_ls.entries == []:
					logging.debug("%s::: _lsImage():: No changes on the server." % self.name)
				else:
					self.ls_ref = new_ls

			# Select only images and only the ones for the current imgid (camid)
			foundImg = False
			for f in self.ls_ref.entries:
				if 'media_info' in f._all_field_names_ and \
					f.media_info is not None:
					if self.imgid in f.path_lower:
						img = '.%s' % f.path_lower
						foundImg = True
						if not img in self.imageDbList:
							self.imageDbList.append(img)


			if not foundImg:
				self.imageDbList = []

			### Store the hash of the folder
			self._imageDbCursor = self.ls_ref.cursor

			if len(self.imageDbList) > 0:
				logging.debug("%s::: _lsImage():: imageDbList[0..%d]: %s .. %s" % (self.name, len(self.imageDbList)-1, self.imageDbList[0], self.imageDbList[-1]) )
			else:
				logging.debug("%s::: _lsImage():: imageDbList[]: empty" % self.name)

		except ApiError as e:
			raise rpiBaseClassError("_lsImage(): %s" % e.error, ERRLEV2)


	def _putImage(self, from_path, to_path, overwrite=False):
		"""
		Copy local file to remote file.
		Stores the uploaded files names in self.imageUpldFIFO.

		Examples:
		_putImage('./path/test.jpg', '/path/dropbox-upload-test.jpg')
		"""
		try:
			mode = (WriteMode.overwrite if overwrite else WriteMode.add)

			with open(from_path, "rb") as from_file:
				self._dbx.files_upload( from_file, '/' + os.path.normpath(to_path), mode)

			if not overwrite:
				self.imageUpldFIFO.append(from_path)

			logging.debug("%s::: _putImage(): Uploaded file from %s to remote %s" % (self.name, from_path, to_path))

		except IOError:
			raise rpiBaseClassError("_putImage(): Local img file %s could not be opened." %  from_path, ERRCRIT)

		except ApiError as e:
			raise rpiBaseClassError("_putImage(): %s" % e.error, ERRLEV2)


	def _mkdirImage(self, path):
		"""
		Create a new remote directory.

		Examples:
		_mkdirImage('/dropbox_dir_test')
		"""
		try:
			self._dbx.files_create_folder('/' + os.path.normpath(path))

			logging.debug("%s::: Remote output folder /%s created." % (self.name, path))

		except ApiError as e:
			noerr = False
			# dropbox.files.CreateFolderError
			if e.error.is_path():
				# dropbox.files.WriteError
				we = e.error.get_path()
				if we.is_conflict():
					# dropbox.files.WriteConflictError
					wce = we.get_conflict()
					# union tag is 'folder'
					if wce.is_folder():
						logging.info("%s::: Remote output folder /%s already exist!" % (self.name, path))
						noerr = True

			if not noerr:
				raise rpiBaseClassError("_mkdirImage(): Remote output folder /%s was not created! %s" % (path, e.error), ERRCRIT)
			else:
				pass


	def _mvImage(self, from_path, to_path):
		"""
		Move/rename a remote file or directory.

		Examples:
		_mvImage('./path1/dropbox-move-test.jpg', '/path2/dropbox-move-test.jpg')
		"""
		try:
			self._dbx.files_move( '/' + os.path.normpath(from_path), '/' +  os.path.normpath(to_path) )

			logging.debug("%s::: _mvImage(): Moved file from %s to %s" % (self.name, from_path, to_path))

		except ApiError as e:
			raise rpiBaseClassError("_mvImage(): Image %s could not be moved to %s! %s" % (from_path, to_path, e.error), ERRLEV2)