Files
RetroArch/network/cloud_sync_driver.h
T
libretroadmin 0e464bdf41 cloudsync: a blocking driver's calls read settings copied as the sync is pushed
The cloud_sync_capture hook copies the settings a driver's calls read,
on the main thread as the sync's task is pushed, where the task takes
its own copy too. SMB and NFS read the share, the account, the
timeouts and the destructive flag from that copy rather than from the
live settings: their calls run on a worker, read some of them after a
network call returns, and one still blocked past the exit wait would
otherwise read settings the frontend has freed.

cloudsync_async_test checks the hook runs once on the calling thread
and that a driver without one is left alone.
2026-10-05 12:51:48 +02:00

152 lines
5.6 KiB
C

/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLOUD_SYNC_DRIVER__H
#define __CLOUD_SYNC_DRIVER__H
#include <boolean.h>
#include <stddef.h>
#include <streams/file_stream.h>
RETRO_BEGIN_DECLS
/*
* For a read, `success' indicates whether we successfully communicated with the
* server. We may ask to read a file that doesn't exist; in that case, `success'
* is true and `file' is NULL. `file' is expected to be close()'d by the handler
* if non-NULL.
*/
/* The key cloud sync keeps its server manifest under. Drivers that
* treat ordinary files specially (such as backing up the copy an
* upload replaces) leave this one alone: it is rewritten every sync. */
#define CLOUD_SYNC_SERVER_MANIFEST "manifest.server"
typedef void (*cloud_sync_complete_handler_t)(void *user_data, const char *path, bool success, RFILE *file);
typedef struct cloud_sync_driver
{
bool (*cloud_sync_begin)(cloud_sync_complete_handler_t cb, void *user_data);
bool (*cloud_sync_end)(cloud_sync_complete_handler_t cb, void *user_data);
bool (*cloud_sync_read)(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data);
bool (*cloud_sync_update)(const char *path, RFILE *file, cloud_sync_complete_handler_t cb, void *user_data);
bool (*cloud_sync_free)(const char *path, cloud_sync_complete_handler_t cb, void *user_data);
const char *ident;
unsigned flags;
/* Optional. Copies the settings the calls above read, on the main
* thread as a sync is pushed, so none of them reads the live
* settings - a blocking driver's calls run on a worker, and one may
* still be running when the frontend frees them on exit. */
void (*cloud_sync_capture)(void);
} cloud_sync_driver_t;
/* The driver's calls block on the network until they are done and
* call back before returning (SMB, NFS). With threads they are run on
* a worker, and their results are handed back by cloud_sync_poll(). */
#define CLOUD_SYNC_DRIVER_FLG_BLOCKING (1 << 0)
typedef struct
{
const cloud_sync_driver_t *driver;
} cloud_sync_driver_state_t;
cloud_sync_driver_state_t *cloud_sync_state_get_ptr(void);
extern cloud_sync_driver_t cloud_sync_webdav;
#ifdef HAVE_SSL
extern cloud_sync_driver_t cloud_sync_google_drive;
#endif
#ifdef HAVE_S3
extern cloud_sync_driver_t cloud_sync_s3;
#endif
#ifdef HAVE_ICLOUD
extern cloud_sync_driver_t cloud_sync_icloud;
#endif
#ifdef HAVE_ICLOUD_DRIVE
extern cloud_sync_driver_t cloud_sync_icloud_drive;
#endif
#ifdef HAVE_SMBCLIENT
extern cloud_sync_driver_t cloud_sync_smb;
#endif
#ifdef HAVE_NFSCLIENT
extern cloud_sync_driver_t cloud_sync_nfs;
#endif
extern const cloud_sync_driver_t *cloud_sync_drivers[];
/**
* config_get_cloud_sync_driver_options:
*
* Get an enumerated list of all cloud_sync driver names, separated by '|'.
*
* Returns: string listing of all cloud_sync driver names, separated by '|'.
**/
const char* config_get_cloud_sync_driver_options(void);
void cloud_sync_find_driver(const char *drv, const char *prefix,
bool verbosity_enabled);
/**
* cloud_sync_capture:
*
* Main thread, before the sync's task is pushed: the driver copies the
* settings its calls will read.
**/
void cloud_sync_capture(void);
bool cloud_sync_begin(cloud_sync_complete_handler_t cb, void *user_data);
bool cloud_sync_end(cloud_sync_complete_handler_t cb, void *user_data);
bool cloud_sync_read(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data);
bool cloud_sync_update(const char *path, RFILE *file, cloud_sync_complete_handler_t cb, void *user_data);
bool cloud_sync_free(const char *path, cloud_sync_complete_handler_t cb, void *user_data);
/**
* cloud_sync_poll:
*
* @within : asked after each handler whether there is time for another;
* NULL runs every finished one. task_nbio_slice_within_budget
* has this shape.
* @budget : passed to @within.
*
* Runs the completion handlers of calls a blocking driver finished on
* its worker, on the calling thread, in the order the calls were made:
* always the oldest one, then more while @within allows; the rest wait
* for the next poll. The caller of cloud_sync_begin() and friends calls
* this each time it runs; it returns at once when nothing has finished.
**/
typedef bool (*cloud_sync_poll_budget_t)(void *budget, size_t avail,
size_t len);
void cloud_sync_poll(cloud_sync_poll_budget_t within, void *budget);
/**
* cloud_sync_deinit:
* @timeout_ms : longest wait for a call already running on the worker
*
* On exit, once the task queue is drained: drops the calls a blocking
* driver has not started, without running their handlers, and waits
* up to @timeout_ms for the one under way so no driver code runs while
* the frontend is torn down. A call still blocked past the bound is
* left to finish on its own; the worker then frees its result and closes
* its file without running the handler, and a sync begun afterwards
* never sees it.
**/
void cloud_sync_deinit(unsigned timeout_ms);
RETRO_END_DECLS
#endif