mirror of
https://github.com/haiwen/seafile.git
synced 2025-01-08 11:57:44 +08:00
Merge branch 'http-sync'
Conflicts: fileserver/Makefile.am server/Makefile.am
This commit is contained in:
commit
299746d77c
@ -17,14 +17,14 @@ else
|
||||
endif
|
||||
|
||||
if COMPILE_SERVER
|
||||
MAKE_SERVER = server tools fileserver $(MAKE_CONTROLLER) $(MAKE_FUSE)
|
||||
MAKE_SERVER = server tools $(MAKE_CONTROLLER) $(MAKE_FUSE)
|
||||
endif
|
||||
|
||||
SUBDIRS = include lib common app python tests doc \
|
||||
$(MAKE_CLIENT) $(MAKE_SERVER)
|
||||
|
||||
DIST_SUBDIRS = include lib common app python tests \
|
||||
daemon server tools fileserver controller \
|
||||
daemon server tools controller \
|
||||
doc fuse
|
||||
|
||||
INTLTOOL = \
|
||||
|
@ -152,7 +152,7 @@ seafile_set_upload_rate_limit (int limit, GError **error)
|
||||
if (limit < 0)
|
||||
limit = 0;
|
||||
|
||||
seaf->transfer_mgr->upload_limit = limit;
|
||||
seaf->sync_mgr->upload_limit = limit;
|
||||
|
||||
return seafile_session_config_set_int (seaf, KEY_UPLOAD_LIMIT, limit);
|
||||
}
|
||||
@ -163,7 +163,7 @@ seafile_set_download_rate_limit (int limit, GError **error)
|
||||
if (limit < 0)
|
||||
limit = 0;
|
||||
|
||||
seaf->transfer_mgr->download_limit = limit;
|
||||
seaf->sync_mgr->download_limit = limit;
|
||||
|
||||
return seafile_session_config_set_int (seaf, KEY_DOWNLOAD_LIMIT, limit);
|
||||
}
|
||||
@ -396,10 +396,8 @@ seafile_get_clone_tasks (GError **error)
|
||||
"state", clone_task_state_to_str(task->state),
|
||||
"error_str", clone_task_error_to_str(task->error),
|
||||
"repo_id", task->repo_id,
|
||||
"peer_id", task->peer_id,
|
||||
"repo_name", task->repo_name,
|
||||
"worktree", task->worktree,
|
||||
"tx_id", task->tx_id,
|
||||
NULL);
|
||||
ret = g_list_prepend (ret, t);
|
||||
}
|
||||
@ -448,14 +446,10 @@ convert_task (TransferTask *task)
|
||||
if (task->protocol_version < 7)
|
||||
get_task_size (task, &rsize, &dsize);
|
||||
|
||||
g_object_set (t, "tx_id", task->tx_id,
|
||||
g_object_set (t,
|
||||
"repo_id", task->repo_id,
|
||||
"dest_id", task->dest_id,
|
||||
"from_branch", task->from_branch,
|
||||
"to_branch", task->to_branch,
|
||||
"state", task_state_to_str(task->state),
|
||||
"rt_state", task_rt_state_to_str(task->runtime_state),
|
||||
"rsize", rsize, "dsize", dsize,
|
||||
"error_str", task_error_str(task->error),
|
||||
NULL);
|
||||
|
||||
@ -485,50 +479,66 @@ convert_task (TransferTask *task)
|
||||
return t;
|
||||
}
|
||||
|
||||
static SeafileTask *
|
||||
convert_http_task (HttpTxTask *task)
|
||||
{
|
||||
SeafileTask *t = seafile_task_new();
|
||||
|
||||
g_object_set (t,
|
||||
"repo_id", task->repo_id,
|
||||
"state", http_task_state_to_str(task->state),
|
||||
"rt_state", http_task_rt_state_to_str(task->runtime_state),
|
||||
"error_str", http_task_error_str(task->error),
|
||||
NULL);
|
||||
|
||||
if (task->type == HTTP_TASK_TYPE_DOWNLOAD) {
|
||||
g_object_set (t, "ttype", "download", NULL);
|
||||
if (task->runtime_state == HTTP_TASK_RT_STATE_BLOCK) {
|
||||
g_object_set (t, "block_total", task->n_files,
|
||||
"block_done", task->done_files,
|
||||
NULL);
|
||||
g_object_set (t, "rate", http_tx_task_get_rate(task), NULL);
|
||||
}
|
||||
} else {
|
||||
g_object_set (t, "ttype", "upload", NULL);
|
||||
if (task->runtime_state == HTTP_TASK_RT_STATE_BLOCK) {
|
||||
g_object_set (t, "block_total", task->n_blocks,
|
||||
"block_done", task->done_blocks,
|
||||
NULL);
|
||||
g_object_set (t, "rate", http_tx_task_get_rate(task), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
GObject *
|
||||
seafile_find_transfer_task (const char *repo_id, GError *error)
|
||||
{
|
||||
TransferTask *task;
|
||||
HttpTxTask *http_task;
|
||||
|
||||
task = seaf_transfer_manager_find_transfer_by_repo (
|
||||
seaf->transfer_mgr, repo_id);
|
||||
if (!task)
|
||||
return NULL;
|
||||
task = seaf_transfer_manager_find_transfer_by_repo (seaf->transfer_mgr, repo_id);
|
||||
if (task)
|
||||
return (GObject *)convert_task (task);
|
||||
|
||||
return (GObject *)convert_task (task);
|
||||
http_task = http_tx_manager_find_task (seaf->http_tx_mgr, repo_id);
|
||||
if (task)
|
||||
return (GObject *)convert_http_task (http_task);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_get_upload_rate(GError **error)
|
||||
{
|
||||
int rate = 0;
|
||||
GList *ptr, *tasks = seaf_transfer_manager_get_upload_tasks(seaf->transfer_mgr);
|
||||
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
TransferTask *task = (TransferTask *)ptr->data;
|
||||
rate += transfer_task_get_rate (task);
|
||||
}
|
||||
|
||||
g_list_free(tasks);
|
||||
|
||||
return rate;
|
||||
return seaf->sync_mgr->last_sent_bytes;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_get_download_rate(GError **error)
|
||||
{
|
||||
int rate = 0;
|
||||
GList *ptr, *tasks = seaf_transfer_manager_get_download_tasks(seaf->transfer_mgr);
|
||||
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
TransferTask *task = (TransferTask *)ptr->data;
|
||||
rate += transfer_task_get_rate (task);
|
||||
}
|
||||
|
||||
g_list_free(tasks);
|
||||
|
||||
return rate;
|
||||
return seaf->sync_mgr->last_recv_bytes;
|
||||
}
|
||||
|
||||
|
||||
@ -574,9 +584,7 @@ seafile_get_repo_sync_task (const char *repo_id, GError **error)
|
||||
const char *sync_state;
|
||||
char allzeros[41] = {0};
|
||||
|
||||
if (!ccnet_peer_is_ready(seaf->ccnetrpc_client, repo->relay_id)) {
|
||||
sync_state = "relay not connected";
|
||||
} else if (!info->in_sync && memcmp(allzeros, info->head_commit, 41) == 0) {
|
||||
if (!info->in_sync && memcmp(allzeros, info->head_commit, 41) == 0) {
|
||||
sync_state = "waiting for sync";
|
||||
} else {
|
||||
sync_state = sync_state_to_str(task->state);
|
||||
@ -588,8 +596,6 @@ seafile_get_repo_sync_task (const char *repo_id, GError **error)
|
||||
"force_upload", task->is_manual_sync,
|
||||
"state", sync_state,
|
||||
"error", sync_error_to_str(task->error),
|
||||
"tx_id", task->tx_id,
|
||||
"dest_id", task->dest_id,
|
||||
"repo_id", info->repo_id,
|
||||
NULL);
|
||||
|
||||
@ -617,9 +623,7 @@ seafile_get_sync_task_list (GError **error)
|
||||
"force_upload", task->is_manual_sync,
|
||||
"state", sync_state_to_str(task->state),
|
||||
"error", sync_error_to_str(task->error),
|
||||
"dest_id", task->dest_id,
|
||||
"repo_id", info->repo_id,
|
||||
"tx_id", task->tx_id,
|
||||
NULL);
|
||||
task_list = g_list_prepend (task_list, s_task);
|
||||
}
|
||||
|
@ -310,12 +310,10 @@ if test x${compile_server} = xyes; then
|
||||
AC_SUBST(LIBARCHIVE_LIBS)
|
||||
fi
|
||||
|
||||
# We use http to communicate with Riak, check for libcurl.
|
||||
if test "${compile_riak}" = "yes"; then
|
||||
if test "${compile_client}" = "yes"; then
|
||||
PKG_CHECK_MODULES(CURL, [libcurl >= $CURL_REQUIRED])
|
||||
AC_SUBST(CURL_CFLAGS)
|
||||
AC_SUBST(CURL_LIBS)
|
||||
AC_DEFINE([RIAK_BACKEND], [1], ["define if support Riak backend"])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([HAVE_KEYSTORAGE_GK], [test "${compile_gnome_keyring}" = "yes"])
|
||||
@ -345,7 +343,6 @@ AC_CONFIG_FILES(
|
||||
python/seafile/Makefile
|
||||
python/seaserv/Makefile
|
||||
controller/Makefile
|
||||
fileserver/Makefile
|
||||
tools/Makefile
|
||||
tests/Makefile
|
||||
tests/common-conf.sh
|
||||
|
@ -10,6 +10,7 @@ AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||
@SEARPC_CFLAGS@ \
|
||||
@GLIB2_CFLAGS@ \
|
||||
@MSVC_CFLAGS@ \
|
||||
@CURL_CFLAGS@
|
||||
-Wall
|
||||
|
||||
bin_PROGRAMS =
|
||||
@ -57,6 +58,7 @@ noinst_HEADERS = \
|
||||
block-tx-client.h \
|
||||
seafile-config.h \
|
||||
client-migrate.h \
|
||||
http-tx-mgr.h \
|
||||
$(proc_headers)
|
||||
|
||||
if LINUX
|
||||
@ -72,6 +74,7 @@ wt_monitor_src = wt-monitor.c wt-monitor-macos.c wt-monitor-structs.c
|
||||
endif
|
||||
|
||||
common_src = \
|
||||
http-tx-mgr.c \
|
||||
transfer-mgr.c \
|
||||
../common/unpack-trees.c ../common/seaf-tree-walk.c \
|
||||
merge.c merge-recursive.c vc-utils.c \
|
||||
@ -124,7 +127,7 @@ seaf_daemon_LDADD = $(top_builddir)/lib/libseafile_common.la \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \
|
||||
$(top_builddir)/common/cdc/libcdc.la \
|
||||
$(top_builddir)/common/index/libindex.la ${LIB_WS32} \
|
||||
@SEARPC_LIBS@ @CCNET_LIBS@ @GNOME_KEYRING_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@
|
||||
@SEARPC_LIBS@ @CCNET_LIBS@ @GNOME_KEYRING_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@ @CURL_LIBS@
|
||||
|
||||
seaf_daemon_LDFLAGS = @STATIC_COMPILE@ @CONSOLE@
|
||||
|
||||
|
@ -574,7 +574,7 @@ send_encrypted_block (BlockTxClient *client,
|
||||
|
||||
/* Update global transferred bytes. */
|
||||
g_atomic_int_add (&(info->task->tx_bytes), n);
|
||||
g_atomic_int_add (&(seaf->transfer_mgr->sent_bytes), n);
|
||||
g_atomic_int_add (&(seaf->sync_mgr->sent_bytes), n);
|
||||
|
||||
/* If uploaded bytes exceeds the limit, wait until the counter
|
||||
* is reset. We check the counter every 100 milliseconds, so we
|
||||
@ -582,9 +582,9 @@ send_encrypted_block (BlockTxClient *client,
|
||||
* the counter is reset.
|
||||
*/
|
||||
while (1) {
|
||||
gint sent = g_atomic_int_get(&(seaf->transfer_mgr->sent_bytes));
|
||||
if (seaf->transfer_mgr->upload_limit > 0 &&
|
||||
sent > seaf->transfer_mgr->upload_limit)
|
||||
gint sent = g_atomic_int_get(&(seaf->sync_mgr->sent_bytes));
|
||||
if (seaf->sync_mgr->upload_limit > 0 &&
|
||||
sent > seaf->sync_mgr->upload_limit)
|
||||
/* 100 milliseconds */
|
||||
g_usleep (100000);
|
||||
else
|
||||
@ -648,12 +648,12 @@ save_block_content_cb (char *content, int clen, int end, void *cbarg)
|
||||
|
||||
/* Update global transferred bytes. */
|
||||
g_atomic_int_add (&(task->tx_bytes), clen);
|
||||
g_atomic_int_add (&(seaf->transfer_mgr->recv_bytes), clen);
|
||||
g_atomic_int_add (&(seaf->sync_mgr->recv_bytes), clen);
|
||||
|
||||
while (1) {
|
||||
gint recv_bytes = g_atomic_int_get (&(seaf->transfer_mgr->recv_bytes));
|
||||
if (seaf->transfer_mgr->download_limit > 0 &&
|
||||
recv_bytes > seaf->transfer_mgr->download_limit) {
|
||||
gint recv_bytes = g_atomic_int_get (&(seaf->sync_mgr->recv_bytes));
|
||||
if (seaf->sync_mgr->download_limit > 0 &&
|
||||
recv_bytes > seaf->sync_mgr->download_limit) {
|
||||
g_usleep (100000);
|
||||
} else {
|
||||
break;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "unpack-trees.h"
|
||||
#include "vc-utils.h"
|
||||
#include "utils.h"
|
||||
#include "seafile-config.h"
|
||||
|
||||
#include "processors/checkff-proc.h"
|
||||
|
||||
@ -24,6 +25,11 @@ on_repo_fetched (SeafileSession *seaf,
|
||||
TransferTask *tx_task,
|
||||
SeafCloneManager *mgr);
|
||||
|
||||
static void
|
||||
on_repo_http_fetched (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafCloneManager *mgr);
|
||||
|
||||
static void
|
||||
on_checkout_done (CheckoutTask *task, SeafRepo *repo, void *data);
|
||||
|
||||
@ -48,6 +54,7 @@ add_transfer_task (CloneTask *task, GError **error);
|
||||
static const char *state_str[] = {
|
||||
"init",
|
||||
"connect",
|
||||
"connect",
|
||||
"connect", /* Use "connect" for CHECK_PROTOCOL */
|
||||
"index",
|
||||
"fetch",
|
||||
@ -114,6 +121,9 @@ mark_clone_done_v2 (SeafRepo *repo, CloneTask *task)
|
||||
seaf_repo_set_readonly (repo);
|
||||
}
|
||||
|
||||
if (task->server_url)
|
||||
repo->server_url = g_strdup(task->server_url);
|
||||
|
||||
if (repo->auto_sync && !task->is_readonly) {
|
||||
if (seaf_wt_monitor_watch_repo (seaf->wt_monitor,
|
||||
repo->id, repo->worktree) < 0) {
|
||||
@ -157,6 +167,13 @@ start_clone_v2 (CloneTask *task)
|
||||
seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email);
|
||||
seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id,
|
||||
task->peer_addr, task->peer_port);
|
||||
seaf_repo_manager_set_repo_relay_id (seaf->repo_mgr, repo, task->peer_id);
|
||||
if (task->server_url) {
|
||||
seaf_repo_manager_set_repo_property (seaf->repo_mgr,
|
||||
repo->id,
|
||||
REPO_PROP_SERVER_URL,
|
||||
task->server_url);
|
||||
}
|
||||
|
||||
mark_clone_done_v2 (repo, task);
|
||||
return;
|
||||
@ -215,6 +232,90 @@ start_check_protocol_proc (const char *peer_id, CloneTask *task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
start_connect_task_relay (CloneTask *task, GError **error)
|
||||
{
|
||||
CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, task->peer_id);
|
||||
if (!peer) {
|
||||
/* clone from a new relay */
|
||||
GString *buf = NULL;
|
||||
seaf_message ("add relay before clone, %s:%s\n",
|
||||
task->peer_addr, task->peer_port);
|
||||
buf = g_string_new(NULL);
|
||||
g_string_append_printf (buf, "add-relay --id %s --addr %s:%s",
|
||||
task->peer_id, task->peer_addr, task->peer_port);
|
||||
ccnet_send_command (seaf->session, buf->str, NULL, NULL);
|
||||
transition_state (task, CLONE_STATE_CONNECT);
|
||||
g_string_free (buf, TRUE);
|
||||
} else {
|
||||
/* The peer is added to ccnet already and will be connected,
|
||||
* only need to transition the state
|
||||
*/
|
||||
transition_state (task, CLONE_STATE_CONNECT);
|
||||
}
|
||||
|
||||
if (peer)
|
||||
g_object_unref (peer);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_non_http_server (CloneTask *task)
|
||||
{
|
||||
if (!ccnet_peer_is_ready (seaf->ccnetrpc_client, task->peer_id))
|
||||
start_connect_task_relay (task, NULL);
|
||||
else
|
||||
start_check_protocol_proc (task->peer_id, task);
|
||||
}
|
||||
|
||||
static void
|
||||
check_head_commit_done (HttpHeadCommit *result, void *user_data)
|
||||
{
|
||||
CloneTask *task = user_data;
|
||||
|
||||
if (result->check_success && !result->is_corrupt && !result->is_deleted) {
|
||||
memcpy (task->server_head_id, result->head_commit, 40);
|
||||
start_clone_v2 (task);
|
||||
} else {
|
||||
task->http_sync = FALSE;
|
||||
connect_non_http_server (task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
http_check_head_commit (CloneTask *task)
|
||||
{
|
||||
http_tx_manager_check_head_commit (seaf->http_tx_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
task->server_url,
|
||||
task->token,
|
||||
check_head_commit_done,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
check_http_protocol_done (HttpProtocolVersion *result, void *user_data)
|
||||
{
|
||||
CloneTask *task = user_data;
|
||||
|
||||
if (result->check_success && !result->not_supported) {
|
||||
task->http_protocol_version = result->version;
|
||||
task->http_sync = TRUE;
|
||||
http_check_head_commit (task);
|
||||
} else
|
||||
connect_non_http_server (task);
|
||||
}
|
||||
|
||||
static void
|
||||
check_http_protocol (CloneTask *task)
|
||||
{
|
||||
http_tx_manager_check_protocol_version (seaf->http_tx_mgr,
|
||||
task->server_url,
|
||||
check_http_protocol_done,
|
||||
task);
|
||||
transition_state (task, CLONE_STATE_CHECK_HTTP);
|
||||
}
|
||||
|
||||
static CloneTask *
|
||||
clone_task_new (const char *repo_id,
|
||||
const char *peer_id,
|
||||
@ -255,6 +356,7 @@ clone_task_free (CloneTask *task)
|
||||
g_free (task->peer_port);
|
||||
g_free (task->email);
|
||||
g_free (task->random_key);
|
||||
g_free (task->server_url);
|
||||
|
||||
g_free (task);
|
||||
}
|
||||
@ -373,6 +475,9 @@ load_more_info_cb (sqlite3_stmt *stmt, void *data)
|
||||
|
||||
json_t *integer = json_object_get (object, "is_readonly");
|
||||
task->is_readonly = json_integer_value (integer);
|
||||
json_t *string = json_object_get (object, "server_url");
|
||||
if (string)
|
||||
task->server_url = g_strdup (json_string_value (string));
|
||||
json_decref (object);
|
||||
|
||||
return FALSE;
|
||||
@ -432,10 +537,10 @@ restart_task (sqlite3_stmt *stmt, void *data)
|
||||
if (repo != NULL && repo->head != NULL) {
|
||||
transition_state (task, CLONE_STATE_DONE);
|
||||
return TRUE;
|
||||
} else if (!ccnet_peer_is_ready (seaf->ccnetrpc_client, task->peer_id))
|
||||
start_connect_task_relay (task, NULL);
|
||||
} else if (seaf->enable_http_sync && task->repo_version > 0 && task->server_url)
|
||||
check_http_protocol (task);
|
||||
else
|
||||
start_check_protocol_proc (task->peer_id, task);
|
||||
connect_non_http_server (task);
|
||||
|
||||
g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task);
|
||||
|
||||
@ -470,6 +575,11 @@ seaf_clone_manager_init (SeafCloneManager *mgr)
|
||||
if (sqlite_query_exec (mgr->db, sql) < 0)
|
||||
return -1;
|
||||
|
||||
sql = "CREATE TABLE IF NOT EXISTS CloneServerURL "
|
||||
"(repo_id TEXT PRIMARY KEY, server_url TEXT);";
|
||||
if (sqlite_query_exec (mgr->db, sql) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -514,6 +624,8 @@ seaf_clone_manager_start (SeafCloneManager *mgr)
|
||||
|
||||
g_signal_connect (seaf, "repo-fetched",
|
||||
(GCallback)on_repo_fetched, mgr);
|
||||
g_signal_connect (seaf, "repo-http-fetched",
|
||||
(GCallback)on_repo_http_fetched, mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -564,13 +676,15 @@ save_task_to_db (SeafCloneManager *mgr, CloneTask *task)
|
||||
}
|
||||
sqlite3_free (sql);
|
||||
|
||||
if (task->is_readonly) {
|
||||
if (task->is_readonly || task->server_url) {
|
||||
/* need to store more info */
|
||||
json_t *object = NULL;
|
||||
gchar *info = NULL;
|
||||
|
||||
object = json_object ();
|
||||
json_object_set_new (object, "is_readonly", json_integer (task->is_readonly));
|
||||
if (task->server_url)
|
||||
json_object_set_new (object, "server_url", json_string(task->server_url));
|
||||
|
||||
info = json_dumps (object, 0);
|
||||
json_decref (object);
|
||||
@ -655,19 +769,36 @@ transition_to_error (CloneTask *task, int error)
|
||||
static int
|
||||
add_transfer_task (CloneTask *task, GError **error)
|
||||
{
|
||||
task->tx_id = seaf_transfer_manager_add_download (seaf->transfer_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
task->peer_id,
|
||||
"fetch_head",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
task->passwd,
|
||||
task->worktree,
|
||||
error);
|
||||
if (!task->tx_id)
|
||||
return -1;
|
||||
if (!task->http_sync) {
|
||||
task->tx_id = seaf_transfer_manager_add_download (seaf->transfer_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
task->peer_id,
|
||||
"fetch_head",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
task->passwd,
|
||||
task->worktree,
|
||||
error);
|
||||
if (!task->tx_id)
|
||||
return -1;
|
||||
} else {
|
||||
int ret = http_tx_manager_add_download (seaf->http_tx_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
task->server_url,
|
||||
task->token,
|
||||
task->server_head_id,
|
||||
TRUE,
|
||||
task->passwd,
|
||||
task->worktree,
|
||||
task->http_protocol_version,
|
||||
error);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
task->tx_id = g_strdup(task->repo_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -765,32 +896,6 @@ start_index_or_transfer (SeafCloneManager *mgr, CloneTask *task, GError **error)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
start_connect_task_relay (CloneTask *task, GError **error)
|
||||
{
|
||||
CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, task->peer_id);
|
||||
if (!peer) {
|
||||
/* clone from a new relay */
|
||||
GString *buf = NULL;
|
||||
seaf_message ("add relay before clone, %s:%s\n",
|
||||
task->peer_addr, task->peer_port);
|
||||
buf = g_string_new(NULL);
|
||||
g_string_append_printf (buf, "add-relay --id %s --addr %s:%s",
|
||||
task->peer_id, task->peer_addr, task->peer_port);
|
||||
ccnet_send_command (seaf->session, buf->str, NULL, NULL);
|
||||
transition_state (task, CLONE_STATE_CONNECT);
|
||||
g_string_free (buf, TRUE);
|
||||
} else {
|
||||
/* The peer is added to ccnet already and will be connected,
|
||||
* only need to transition the state
|
||||
*/
|
||||
transition_state (task, CLONE_STATE_CONNECT);
|
||||
}
|
||||
|
||||
if (peer)
|
||||
g_object_unref (peer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_duplicate_task (SeafCloneManager *mgr, const char *repo_id)
|
||||
{
|
||||
@ -1047,6 +1152,18 @@ seaf_clone_manager_check_worktree_path (SeafCloneManager *mgr, const char *path,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
canonical_server_url (const char *url_in)
|
||||
{
|
||||
char *url = g_strdup(url_in);
|
||||
int len = strlen(url);
|
||||
|
||||
if (url[len - 1] == '/')
|
||||
url[len - 1] = 0;
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
static char *
|
||||
add_task_common (SeafCloneManager *mgr,
|
||||
const char *repo_id,
|
||||
@ -1089,7 +1206,10 @@ add_task_common (SeafCloneManager *mgr,
|
||||
}
|
||||
|
||||
json_t *integer = json_object_get (object, "is_readonly");
|
||||
task->is_readonly = json_integer_value (integer);
|
||||
task->is_readonly = json_integer_value (integer);
|
||||
json_t *string = json_object_get (object, "server_url");
|
||||
if (string)
|
||||
task->server_url = canonical_server_url (json_string_value (string));
|
||||
json_decref (object);
|
||||
}
|
||||
|
||||
@ -1099,13 +1219,10 @@ add_task_common (SeafCloneManager *mgr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ccnet_peer_is_ready(seaf->ccnetrpc_client, task->peer_id)) {
|
||||
/* the relay is not connected yet.
|
||||
* We need relay connected even before checkout.
|
||||
*/
|
||||
start_connect_task_relay (task, error);
|
||||
} else
|
||||
start_check_protocol_proc (task->peer_id, task);
|
||||
if (seaf->enable_http_sync && task->repo_version > 0 && task->server_url)
|
||||
check_http_protocol (task);
|
||||
else
|
||||
connect_non_http_server (task);
|
||||
|
||||
/* The old task for this repo will be freed. */
|
||||
g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task);
|
||||
@ -1373,9 +1490,14 @@ seaf_clone_manager_cancel_task (SeafCloneManager *mgr,
|
||||
transition_state (task, CLONE_STATE_CANCELED);
|
||||
break;
|
||||
case CLONE_STATE_FETCH:
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_DOWNLOAD);
|
||||
if (!task->http_sync)
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_DOWNLOAD);
|
||||
else
|
||||
http_tx_manager_cancel_task (seaf->http_tx_mgr,
|
||||
task->repo_id,
|
||||
HTTP_TASK_TYPE_DOWNLOAD);
|
||||
transition_state (task, CLONE_STATE_CANCEL_PENDING);
|
||||
break;
|
||||
case CLONE_STATE_INDEX:
|
||||
@ -2043,6 +2165,13 @@ on_repo_fetched (SeafileSession *seaf,
|
||||
seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email);
|
||||
seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id,
|
||||
task->peer_addr, task->peer_port);
|
||||
seaf_repo_manager_set_repo_relay_id (seaf->repo_mgr, repo, task->peer_id);
|
||||
if (task->server_url) {
|
||||
seaf_repo_manager_set_repo_property (seaf->repo_mgr,
|
||||
repo->id,
|
||||
REPO_PROP_SERVER_URL,
|
||||
task->server_url);
|
||||
}
|
||||
|
||||
if (!task->server_side_merge)
|
||||
start_checkout (repo, task);
|
||||
@ -2050,6 +2179,53 @@ on_repo_fetched (SeafileSession *seaf,
|
||||
mark_clone_done_v2 (repo, task);
|
||||
}
|
||||
|
||||
static void
|
||||
on_repo_http_fetched (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafCloneManager *mgr)
|
||||
{
|
||||
CloneTask *task;
|
||||
|
||||
/* Only handle clone task. */
|
||||
if (!tx_task->is_clone)
|
||||
return;
|
||||
|
||||
task = g_hash_table_lookup (mgr->tasks, tx_task->repo_id);
|
||||
g_return_if_fail (task != NULL);
|
||||
|
||||
if (tx_task->state == HTTP_TASK_STATE_CANCELED) {
|
||||
/* g_assert (task->state == CLONE_STATE_CANCEL_PENDING); */
|
||||
transition_state (task, CLONE_STATE_CANCELED);
|
||||
return;
|
||||
} else if (tx_task->state == HTTP_TASK_STATE_ERROR) {
|
||||
transition_to_error (task, CLONE_ERROR_FETCH);
|
||||
return;
|
||||
}
|
||||
|
||||
SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr,
|
||||
tx_task->repo_id);
|
||||
if (repo == NULL) {
|
||||
seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n",
|
||||
tx_task->repo_id);
|
||||
transition_to_error (task, CLONE_ERROR_INTERNAL);
|
||||
return;
|
||||
}
|
||||
|
||||
seaf_repo_manager_set_repo_token (seaf->repo_mgr, repo, task->token);
|
||||
seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email);
|
||||
seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id,
|
||||
task->peer_addr, task->peer_port);
|
||||
seaf_repo_manager_set_repo_relay_id (seaf->repo_mgr, repo, task->peer_id);
|
||||
if (task->server_url) {
|
||||
seaf_repo_manager_set_repo_property (seaf->repo_mgr,
|
||||
repo->id,
|
||||
REPO_PROP_SERVER_URL,
|
||||
task->server_url);
|
||||
}
|
||||
|
||||
mark_clone_done_v2 (repo, task);
|
||||
}
|
||||
|
||||
static void
|
||||
on_checkout_done (CheckoutTask *ctask, SeafRepo *repo, void *data)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ typedef struct _SeafCloneManager SeafCloneManager;
|
||||
|
||||
enum {
|
||||
CLONE_STATE_INIT,
|
||||
CLONE_STATE_CHECK_HTTP,
|
||||
CLONE_STATE_CONNECT,
|
||||
CLONE_STATE_CHECK_PROTOCOL,
|
||||
CLONE_STATE_INDEX,
|
||||
@ -58,6 +59,12 @@ struct _CloneTask {
|
||||
char root_id[41];
|
||||
gboolean is_readonly;
|
||||
|
||||
/* Http sync fields */
|
||||
char *server_url;
|
||||
int http_protocol_version;
|
||||
gboolean http_sync;
|
||||
char server_head_id[41];
|
||||
|
||||
gboolean server_side_merge;
|
||||
};
|
||||
|
||||
|
2775
daemon/http-tx-mgr.c
Normal file
2775
daemon/http-tx-mgr.c
Normal file
File diff suppressed because it is too large
Load Diff
189
daemon/http-tx-mgr.h
Normal file
189
daemon/http-tx-mgr.h
Normal file
@ -0,0 +1,189 @@
|
||||
#ifndef HTTP_TX_MGR_H
|
||||
#define HTTP_TX_MGR_H
|
||||
|
||||
enum {
|
||||
HTTP_TASK_TYPE_DOWNLOAD = 0,
|
||||
HTTP_TASK_TYPE_UPLOAD,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The state that can be set by user.
|
||||
*
|
||||
* A task in NORMAL state can be canceled;
|
||||
* A task in RT_STATE_FINISHED can be removed.
|
||||
*/
|
||||
enum HttpTaskState {
|
||||
HTTP_TASK_STATE_NORMAL = 0,
|
||||
HTTP_TASK_STATE_CANCELED,
|
||||
HTTP_TASK_STATE_FINISHED,
|
||||
HTTP_TASK_STATE_ERROR,
|
||||
N_HTTP_TASK_STATE,
|
||||
};
|
||||
|
||||
enum HttpTaskRuntimeState {
|
||||
HTTP_TASK_RT_STATE_INIT = 0,
|
||||
HTTP_TASK_RT_STATE_CHECK,
|
||||
HTTP_TASK_RT_STATE_COMMIT,
|
||||
HTTP_TASK_RT_STATE_FS,
|
||||
HTTP_TASK_RT_STATE_BLOCK, /* Only used in upload. */
|
||||
HTTP_TASK_RT_STATE_UPDATE_BRANCH, /* Only used in upload. */
|
||||
HTTP_TASK_RT_STATE_FINISHED,
|
||||
N_HTTP_TASK_RT_STATE,
|
||||
};
|
||||
|
||||
enum HttpTaskError {
|
||||
HTTP_TASK_OK = 0,
|
||||
HTTP_TASK_ERR_FORBIDDEN,
|
||||
HTTP_TASK_ERR_NET,
|
||||
HTTP_TASK_ERR_SERVER,
|
||||
HTTP_TASK_ERR_BAD_REQUEST,
|
||||
HTTP_TASK_ERR_BAD_LOCAL_DATA,
|
||||
HTTP_TASK_ERR_NOT_ENOUGH_MEMORY,
|
||||
HTTP_TASK_ERR_WRITE_LOCAL_DATA,
|
||||
HTTP_TASK_ERR_NO_QUOTA,
|
||||
HTTP_TASK_ERR_UNKNOWN,
|
||||
N_HTTP_TASK_ERROR,
|
||||
};
|
||||
|
||||
struct _SeafileSession;
|
||||
struct _HttpTxPriv;
|
||||
|
||||
struct _HttpTxManager {
|
||||
struct _SeafileSession *seaf;
|
||||
|
||||
struct _HttpTxPriv *priv;
|
||||
};
|
||||
|
||||
typedef struct _HttpTxManager HttpTxManager;
|
||||
|
||||
struct _HttpTxTask {
|
||||
HttpTxManager *manager;
|
||||
|
||||
char repo_id[37];
|
||||
int repo_version;
|
||||
char *token;
|
||||
int protocol_version;
|
||||
int type;
|
||||
char *host;
|
||||
gboolean is_clone;
|
||||
|
||||
char head[41];
|
||||
|
||||
char *passwd;
|
||||
char *worktree;
|
||||
|
||||
int state;
|
||||
int runtime_state;
|
||||
int error;
|
||||
|
||||
/* For upload progress */
|
||||
int n_blocks;
|
||||
int done_blocks;
|
||||
/* For download progress */
|
||||
int n_files;
|
||||
int done_files;
|
||||
|
||||
gint tx_bytes; /* bytes transferred in this second. */
|
||||
gint last_tx_bytes; /* bytes transferred in the last second. */
|
||||
};
|
||||
typedef struct _HttpTxTask HttpTxTask;
|
||||
|
||||
HttpTxManager *
|
||||
http_tx_manager_new (struct _SeafileSession *seaf);
|
||||
|
||||
int
|
||||
http_tx_manager_start (HttpTxManager *mgr);
|
||||
|
||||
int
|
||||
http_tx_manager_add_download (HttpTxManager *manager,
|
||||
const char *repo_id,
|
||||
int repo_version,
|
||||
const char *host,
|
||||
const char *token,
|
||||
const char *server_head_id,
|
||||
gboolean is_clone,
|
||||
const char *passwd,
|
||||
const char *worktree,
|
||||
int protocol_version,
|
||||
GError **error);
|
||||
|
||||
int
|
||||
http_tx_manager_add_upload (HttpTxManager *manager,
|
||||
const char *repo_id,
|
||||
int repo_version,
|
||||
const char *host,
|
||||
const char *token,
|
||||
int protocol_version,
|
||||
GError **error);
|
||||
|
||||
struct _HttpProtocolVersion {
|
||||
gboolean check_success; /* TRUE if we get response from the server. */
|
||||
gboolean not_supported;
|
||||
int version;
|
||||
};
|
||||
typedef struct _HttpProtocolVersion HttpProtocolVersion;
|
||||
|
||||
typedef void (*HttpProtocolVersionCallback) (HttpProtocolVersion *result,
|
||||
void *user_data);
|
||||
|
||||
/* Asynchronous interface for getting protocol version from a server.
|
||||
* Also used to determine if the server support http sync.
|
||||
*/
|
||||
int
|
||||
http_tx_manager_check_protocol_version (HttpTxManager *manager,
|
||||
const char *host,
|
||||
HttpProtocolVersionCallback callback,
|
||||
void *user_data);
|
||||
|
||||
struct _HttpHeadCommit {
|
||||
gboolean check_success;
|
||||
gboolean is_corrupt;
|
||||
gboolean is_deleted;
|
||||
char head_commit[41];
|
||||
};
|
||||
typedef struct _HttpHeadCommit HttpHeadCommit;
|
||||
|
||||
typedef void (*HttpHeadCommitCallback) (HttpHeadCommit *result,
|
||||
void *user_data);
|
||||
|
||||
/* Asynchronous interface for getting head commit info from a server. */
|
||||
int
|
||||
http_tx_manager_check_head_commit (HttpTxManager *manager,
|
||||
const char *repo_id,
|
||||
int repo_version,
|
||||
const char *host,
|
||||
const char *token,
|
||||
HttpHeadCommitCallback callback,
|
||||
void *user_data);
|
||||
|
||||
int
|
||||
http_tx_task_download_file_blocks (HttpTxTask *task, const char *file_id);
|
||||
|
||||
GList*
|
||||
http_tx_manager_get_upload_tasks (HttpTxManager *manager);
|
||||
|
||||
GList*
|
||||
http_tx_manager_get_download_tasks (HttpTxManager *manager);
|
||||
|
||||
HttpTxTask *
|
||||
http_tx_manager_find_task (HttpTxManager *manager, const char *repo_id);
|
||||
|
||||
void
|
||||
http_tx_manager_cancel_task (HttpTxManager *manager,
|
||||
const char *repo_id,
|
||||
int task_type);
|
||||
|
||||
int
|
||||
http_tx_task_get_rate (HttpTxTask *task);
|
||||
|
||||
const char *
|
||||
http_task_state_to_str (int state);
|
||||
|
||||
const char *
|
||||
http_task_rt_state_to_str (int rt_state);
|
||||
|
||||
const char *
|
||||
http_task_error_str (int task_errno);
|
||||
|
||||
#endif
|
@ -1743,6 +1743,8 @@ checkout_file (const char *repo_id,
|
||||
SeafileCrypt *crypt,
|
||||
struct cache_entry *ce,
|
||||
TransferTask *task,
|
||||
HttpTxTask *http_task,
|
||||
gboolean is_http,
|
||||
const char *conflict_head_id,
|
||||
GHashTable *conflict_hash,
|
||||
GHashTable *no_conflict_hash)
|
||||
@ -1813,20 +1815,33 @@ checkout_file (const char *repo_id,
|
||||
}
|
||||
|
||||
/* Download the blocks of this file. */
|
||||
int rc = seaf_transfer_manager_download_file_blocks (seaf->transfer_mgr,
|
||||
int rc;
|
||||
if (!is_http) {
|
||||
rc = seaf_transfer_manager_download_file_blocks (seaf->transfer_mgr,
|
||||
task, file_id);
|
||||
switch (rc) {
|
||||
case BLOCK_CLIENT_SUCCESS:
|
||||
break;
|
||||
case BLOCK_CLIENT_UNKNOWN:
|
||||
case BLOCK_CLIENT_FAILED:
|
||||
case BLOCK_CLIENT_NET_ERROR:
|
||||
case BLOCK_CLIENT_SERVER_ERROR:
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_TRANSFER_ERROR;
|
||||
case BLOCK_CLIENT_CANCELED:
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_CANCELED;
|
||||
switch (rc) {
|
||||
case BLOCK_CLIENT_SUCCESS:
|
||||
break;
|
||||
case BLOCK_CLIENT_UNKNOWN:
|
||||
case BLOCK_CLIENT_FAILED:
|
||||
case BLOCK_CLIENT_NET_ERROR:
|
||||
case BLOCK_CLIENT_SERVER_ERROR:
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_TRANSFER_ERROR;
|
||||
case BLOCK_CLIENT_CANCELED:
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_CANCELED;
|
||||
}
|
||||
} else {
|
||||
rc = http_tx_task_download_file_blocks (http_task, file_id);
|
||||
if (http_task->state == HTTP_TASK_STATE_CANCELED) {
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_CANCELED;
|
||||
}
|
||||
if (rc < 0) {
|
||||
g_free (path);
|
||||
return FETCH_CHECKOUT_TRANSFER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* The worktree file may have been changed when we're downloading the blocks. */
|
||||
@ -1978,8 +1993,16 @@ cleanup_file_blocks (const char *repo_id, int version, const char *file_id)
|
||||
|
||||
int
|
||||
seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
HttpTxTask *http_task,
|
||||
gboolean is_http,
|
||||
const char *remote_head_id)
|
||||
{
|
||||
char *repo_id;
|
||||
int repo_version;
|
||||
gboolean is_clone;
|
||||
char *worktree;
|
||||
char *passwd;
|
||||
|
||||
SeafRepo *repo = NULL;
|
||||
SeafBranch *master = NULL;
|
||||
SeafCommit *remote_head = NULL, *master_head = NULL;
|
||||
@ -1991,64 +2014,75 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
GHashTable *conflict_hash = NULL, *no_conflict_hash = NULL;
|
||||
GList *ignore_list = NULL;
|
||||
|
||||
if (is_http) {
|
||||
repo_id = http_task->repo_id;
|
||||
repo_version = http_task->repo_version;
|
||||
is_clone = http_task->is_clone;
|
||||
worktree = http_task->worktree;
|
||||
passwd = http_task->passwd;
|
||||
} else {
|
||||
repo_id = task->repo_id;
|
||||
repo_version = task->repo_version;
|
||||
is_clone = task->is_clone;
|
||||
worktree = task->worktree;
|
||||
passwd = task->passwd;
|
||||
}
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s",
|
||||
seaf->repo_mgr->index_dir, task->repo_id);
|
||||
if (read_index_from (&istate, index_path, task->repo_version) < 0) {
|
||||
seaf->repo_mgr->index_dir, repo_id);
|
||||
if (read_index_from (&istate, index_path, repo_version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return FETCH_CHECKOUT_FAILED;
|
||||
}
|
||||
|
||||
if (!task->is_clone) {
|
||||
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, task->repo_id);
|
||||
if (!is_clone) {
|
||||
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
|
||||
if (!repo) {
|
||||
seaf_warning ("Failed to get repo %.8s.\n", task->repo_id);
|
||||
seaf_warning ("Failed to get repo %.8s.\n", repo_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
master = seaf_branch_manager_get_branch (seaf->branch_mgr,
|
||||
task->repo_id, "master");
|
||||
repo_id, "master");
|
||||
if (!master) {
|
||||
seaf_warning ("Failed to get master branch for repo %.8s.\n",
|
||||
task->repo_id);
|
||||
repo_id);
|
||||
ret = FETCH_CHECKOUT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
master_head = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
repo_id,
|
||||
repo_version,
|
||||
master->commit_id);
|
||||
if (!master_head) {
|
||||
seaf_warning ("Failed to get master head %s of repo %.8s.\n",
|
||||
task->repo_id, master->commit_id);
|
||||
repo_id, master->commit_id);
|
||||
ret = FETCH_CHECKOUT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
char *worktree;
|
||||
if (!task->is_clone)
|
||||
if (!is_clone)
|
||||
worktree = repo->worktree;
|
||||
else
|
||||
worktree = task->worktree;
|
||||
|
||||
remote_head = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
task->repo_id,
|
||||
task->repo_version,
|
||||
repo_id,
|
||||
repo_version,
|
||||
remote_head_id);
|
||||
if (!remote_head) {
|
||||
seaf_warning ("Failed to get remote head %s of repo %.8s.\n",
|
||||
task->repo_id, remote_head_id);
|
||||
repo_id, remote_head_id);
|
||||
ret = FETCH_CHECKOUT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (diff_commit_roots (task->repo_id, task->repo_version,
|
||||
if (diff_commit_roots (repo_id, repo_version,
|
||||
master_head ? master_head->root_id : EMPTY_SHA1,
|
||||
remote_head->root_id,
|
||||
&results, FALSE) < 0) {
|
||||
seaf_warning ("Failed to diff for repo %.8s.\n", task->repo_id);
|
||||
seaf_warning ("Failed to diff for repo %.8s.\n", repo_id);
|
||||
ret = FETCH_CHECKOUT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
@ -2069,14 +2103,14 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
#endif
|
||||
|
||||
if (remote_head->encrypted) {
|
||||
if (!task->is_clone) {
|
||||
if (!is_clone) {
|
||||
crypt = seafile_crypt_new (repo->enc_version,
|
||||
repo->enc_key,
|
||||
repo->enc_iv);
|
||||
} else {
|
||||
unsigned char enc_key[32], enc_iv[16];
|
||||
seafile_decrypt_repo_enc_key (remote_head->enc_version,
|
||||
task->passwd,
|
||||
passwd,
|
||||
remote_head->random_key,
|
||||
enc_key, enc_iv);
|
||||
crypt = seafile_crypt_new (remote_head->enc_version,
|
||||
@ -2095,8 +2129,12 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
|
||||
for (ptr = results; ptr; ptr = ptr->next) {
|
||||
de = ptr->data;
|
||||
if (de->status == DIFF_STATUS_ADDED || de->status == DIFF_STATUS_MODIFIED)
|
||||
++(task->n_to_download);
|
||||
if (de->status == DIFF_STATUS_ADDED || de->status == DIFF_STATUS_MODIFIED) {
|
||||
if (!is_http)
|
||||
++(task->n_to_download);
|
||||
else
|
||||
++(http_task->n_files);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete/rename files before deleting dirs,
|
||||
@ -2188,8 +2226,8 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
add_ce = TRUE;
|
||||
}
|
||||
|
||||
int rc = checkout_file (task->repo_id,
|
||||
task->repo_version,
|
||||
int rc = checkout_file (repo_id,
|
||||
repo_version,
|
||||
worktree,
|
||||
de->name,
|
||||
file_id,
|
||||
@ -2198,6 +2236,8 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
crypt,
|
||||
ce,
|
||||
task,
|
||||
http_task,
|
||||
is_http,
|
||||
remote_head_id,
|
||||
conflict_hash,
|
||||
no_conflict_hash);
|
||||
@ -2218,9 +2258,12 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cleanup_file_blocks (task->repo_id, task->repo_version, file_id);
|
||||
cleanup_file_blocks (repo_id, repo_version, file_id);
|
||||
|
||||
++(task->n_downloaded);
|
||||
if (!is_http)
|
||||
++(task->n_downloaded);
|
||||
else
|
||||
++(http_task->done_files);
|
||||
|
||||
if (add_ce) {
|
||||
if (!(ce->ce_flags & CE_REMOVE))
|
||||
@ -3080,7 +3123,10 @@ load_repo (SeafRepoManager *manager, const char *repo_id)
|
||||
|
||||
repo->email = load_repo_property (manager, repo->id, REPO_PROP_EMAIL);
|
||||
repo->token = load_repo_property (manager, repo->id, REPO_PROP_TOKEN);
|
||||
|
||||
|
||||
/* May be NULL if this property is not set in db. */
|
||||
repo->server_url = load_repo_property (manager, repo->id, REPO_PROP_SERVER_URL);
|
||||
|
||||
if (repo->head != NULL && seaf_repo_check_worktree (repo) < 0) {
|
||||
if (seafile_session_config_get_allow_invalid_worktree(seaf)) {
|
||||
seaf_warning ("Worktree for repo \"%s\" is invalid, but still keep it.\n",
|
||||
@ -3279,6 +3325,17 @@ seaf_repo_manager_set_repo_relay_id (SeafRepoManager *mgr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
canonical_server_url (const char *url_in)
|
||||
{
|
||||
char *url = g_strdup(url_in);
|
||||
int len = strlen(url);
|
||||
|
||||
if (url[len - 1] == '/')
|
||||
url[len - 1] = 0;
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
int
|
||||
seaf_repo_manager_set_repo_property (SeafRepoManager *manager,
|
||||
@ -3322,6 +3379,13 @@ seaf_repo_manager_set_repo_property (SeafRepoManager *manager,
|
||||
if (strcmp(key, REPO_RELAY_ID) == 0)
|
||||
return seaf_repo_manager_set_repo_relay_id (manager, repo, value);
|
||||
|
||||
if (strcmp (key, REPO_PROP_SERVER_URL) == 0) {
|
||||
char *url = canonical_server_url (value);
|
||||
repo->server_url = url;
|
||||
save_repo_property (manager, repo_id, key, url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
save_repo_property (manager, repo_id, key, value);
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define REPO_ENCRYPTED 0x1
|
||||
#define REPO_PROP_DOWNLOAD_HEAD "download-head"
|
||||
#define REPO_PROP_IS_READONLY "is-readonly"
|
||||
#define REPO_PROP_SERVER_URL "server-url"
|
||||
|
||||
struct _SeafRepoManager;
|
||||
typedef struct _SeafRepo SeafRepo;
|
||||
@ -79,6 +80,9 @@ struct _SeafRepo {
|
||||
int version;
|
||||
|
||||
gboolean create_partial_commit;
|
||||
|
||||
/* Used for http sync. */
|
||||
char *server_url;
|
||||
};
|
||||
|
||||
|
||||
@ -410,9 +414,12 @@ enum {
|
||||
};
|
||||
|
||||
struct _TransferTask;
|
||||
struct _HttpTxTask;
|
||||
|
||||
int
|
||||
seaf_repo_fetch_and_checkout (struct _TransferTask *task,
|
||||
struct _HttpTxTask *http_task,
|
||||
gboolean is_http,
|
||||
const char *remote_head_id);
|
||||
|
||||
#endif
|
||||
|
@ -202,7 +202,7 @@ start_rpc_service (CcnetClient *client)
|
||||
seafile_download,
|
||||
"seafile_download",
|
||||
searpc_signature_string__string_int_string_string_string_string_string_string_string_string_string_string_int_string());
|
||||
|
||||
|
||||
searpc_server_register_function ("seafile-rpcserver",
|
||||
seafile_cancel_clone_task,
|
||||
"seafile_cancel_clone_task",
|
||||
|
@ -96,6 +96,20 @@ seafile_session_config_set_string (SeafileSession *session,
|
||||
session->sync_extra_temp_file = FALSE;
|
||||
}
|
||||
|
||||
if (g_strcmp0(key, KEY_ENABLE_HTTP_SYNC) == 0) {
|
||||
if (g_strcmp0(value, "true") == 0)
|
||||
session->enable_http_sync = TRUE;
|
||||
else
|
||||
session->enable_http_sync = FALSE;
|
||||
}
|
||||
|
||||
if (g_strcmp0(key, KEY_DISABLE_VERIFY_CERTIFICATE) == 0) {
|
||||
if (g_strcmp0(value, "true") == 0)
|
||||
session->disable_verify_certificate = TRUE;
|
||||
else
|
||||
session->disable_verify_certificate = FALSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
#define KEY_ALLOW_INVALID_WORKTREE "allow_invalid_worktree"
|
||||
#define KEY_ALLOW_REPO_NOT_FOUND_ON_SERVER "allow_repo_not_found_on_server"
|
||||
#define KEY_SYNC_EXTRA_TEMP_FILE "sync_extra_temp_file"
|
||||
#define KEY_ENABLE_HTTP_SYNC "enable_http_sync"
|
||||
#define KEY_DISABLE_VERIFY_CERTIFICATE "disable_verify_certificate"
|
||||
|
||||
/*
|
||||
* Returns: config value in string. The string should be freed by caller.
|
||||
|
@ -35,6 +35,8 @@ enum {
|
||||
REPO_COMMITTED,
|
||||
REPO_FETCHED,
|
||||
REPO_UPLOADED,
|
||||
REPO_HTTP_FETCHED,
|
||||
REPO_HTTP_UPLOADED,
|
||||
REPO_WORKTREE_CHECKED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -71,7 +73,21 @@ seafile_session_class_init (SeafileSessionClass *klass)
|
||||
NULL, NULL, /* no accumulator */
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
signals[REPO_HTTP_FETCHED] =
|
||||
g_signal_new ("repo-http-fetched", SEAFILE_TYPE_SESSION,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, /* no class singal handler */
|
||||
NULL, NULL, /* no accumulator */
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
|
||||
signals[REPO_HTTP_UPLOADED] =
|
||||
g_signal_new ("repo-http-uploaded", SEAFILE_TYPE_SESSION,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, /* no class singal handler */
|
||||
NULL, NULL, /* no accumulator */
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
}
|
||||
|
||||
|
||||
@ -150,13 +166,15 @@ seafile_session_new(const char *seafile_dir,
|
||||
session->clone_mgr = seaf_clone_manager_new (session);
|
||||
if (!session->clone_mgr)
|
||||
goto onerror;
|
||||
#ifndef SEAF_TOOL
|
||||
session->sync_mgr = seaf_sync_manager_new (session);
|
||||
if (!session->sync_mgr)
|
||||
goto onerror;
|
||||
session->wt_monitor = seaf_wt_monitor_new (session);
|
||||
if (!session->wt_monitor)
|
||||
goto onerror;
|
||||
session->http_tx_mgr = http_tx_manager_new (session);
|
||||
if (!session->http_tx_mgr)
|
||||
goto onerror;
|
||||
|
||||
session->job_mgr = ccnet_job_manager_new (MAX_THREADS);
|
||||
session->ev_mgr = cevent_manager_new ();
|
||||
@ -166,7 +184,6 @@ seafile_session_new(const char *seafile_dir,
|
||||
session->mq_mgr = seaf_mq_manager_new (session);
|
||||
if (!session->mq_mgr)
|
||||
goto onerror;
|
||||
#endif
|
||||
|
||||
return session;
|
||||
|
||||
@ -192,6 +209,12 @@ seafile_session_prepare (SeafileSession *session)
|
||||
session->sync_extra_temp_file = seafile_session_config_get_bool
|
||||
(session, KEY_SYNC_EXTRA_TEMP_FILE);
|
||||
|
||||
session->enable_http_sync = seafile_session_config_get_bool
|
||||
(session, KEY_ENABLE_HTTP_SYNC);
|
||||
|
||||
session->disable_verify_certificate = seafile_session_config_get_bool
|
||||
(session, KEY_DISABLE_VERIFY_CERTIFICATE);
|
||||
|
||||
/* Start mq manager earlier, so that we can send notifications
|
||||
* when start repo manager. */
|
||||
seaf_mq_manager_init (session->mq_mgr);
|
||||
@ -313,6 +336,11 @@ cleanup_job_done (void *vdata)
|
||||
return;
|
||||
}
|
||||
|
||||
if (http_tx_manager_start (session->http_tx_mgr) < 0) {
|
||||
g_error ("Failed to start http transfer manager.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (seaf_sync_manager_start (session->sync_mgr) < 0) {
|
||||
g_error ("Failed to start sync manager.\n");
|
||||
return;
|
||||
|
@ -20,6 +20,9 @@
|
||||
#include "sync-mgr.h"
|
||||
#include "wt-monitor.h"
|
||||
#include "mq-mgr.h"
|
||||
|
||||
#include "http-tx-mgr.h"
|
||||
|
||||
#include <searpc-client.h>
|
||||
|
||||
struct _CcnetClient;
|
||||
@ -64,10 +67,14 @@ struct _SeafileSession {
|
||||
CEventManager *ev_mgr;
|
||||
CcnetJobManager *job_mgr;
|
||||
|
||||
HttpTxManager *http_tx_mgr;
|
||||
|
||||
/* Set after all components are up and running. */
|
||||
gboolean started;
|
||||
|
||||
gboolean sync_extra_temp_file;
|
||||
gboolean enable_http_sync;
|
||||
gboolean disable_verify_certificate;
|
||||
};
|
||||
|
||||
struct _SeafileSessionClass
|
||||
|
@ -24,10 +24,31 @@
|
||||
|
||||
#define DEFAULT_SYNC_INTERVAL 30 /* 30s */
|
||||
#define CHECK_SYNC_INTERVAL 1000 /* 1s */
|
||||
#define UPDATE_TX_STATE_INTERVAL 1000 /* 1s */
|
||||
#define MAX_RUNNING_SYNC_TASKS 5
|
||||
|
||||
enum {
|
||||
SERVER_SIDE_MERGE_UNKNOWN = 0,
|
||||
SERVER_SIDE_MERGE_SUPPORTED,
|
||||
SERVER_SIDE_MERGE_UNSUPPORTED,
|
||||
};
|
||||
|
||||
struct _ServerState {
|
||||
int server_side_merge;
|
||||
gboolean checking;
|
||||
};
|
||||
typedef struct _ServerState ServerState;
|
||||
|
||||
struct _HttpServerState {
|
||||
gboolean http_not_supported;
|
||||
int http_version;
|
||||
gboolean checking;
|
||||
};
|
||||
typedef struct _HttpServerState HttpServerState;
|
||||
|
||||
struct _SeafSyncManagerPriv {
|
||||
struct CcnetTimer *check_sync_timer;
|
||||
struct CcnetTimer *update_tx_state_timer;
|
||||
int pulse_count;
|
||||
|
||||
/* When FALSE, auto sync is globally disabled */
|
||||
@ -40,12 +61,20 @@ start_sync (SeafSyncManager *manager, SeafRepo *repo,
|
||||
gboolean is_initial_commit);
|
||||
|
||||
static int auto_sync_pulse (void *vmanager);
|
||||
|
||||
static void on_repo_fetched (SeafileSession *seaf,
|
||||
TransferTask *tx_task,
|
||||
SeafSyncManager *manager);
|
||||
static void on_repo_uploaded (SeafileSession *seaf,
|
||||
TransferTask *tx_task,
|
||||
SeafSyncManager *manager);
|
||||
static void on_repo_http_fetched (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafSyncManager *manager);
|
||||
static void on_repo_http_uploaded (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafSyncManager *manager);
|
||||
|
||||
static inline void
|
||||
transition_sync_state (SyncTask *task, int new_state);
|
||||
|
||||
@ -74,6 +103,22 @@ seaf_sync_manager_new (SeafileSession *seaf)
|
||||
mgr->server_states = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
|
||||
mgr->http_server_states = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
|
||||
gboolean exists;
|
||||
int download_limit = seafile_session_config_get_int (seaf,
|
||||
KEY_DOWNLOAD_LIMIT,
|
||||
&exists);
|
||||
if (exists)
|
||||
mgr->download_limit = download_limit;
|
||||
|
||||
int upload_limit = seafile_session_config_get_int (seaf,
|
||||
KEY_UPLOAD_LIMIT,
|
||||
&exists);
|
||||
if (exists)
|
||||
mgr->upload_limit = upload_limit;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
@ -171,13 +216,136 @@ add_repo_relays ()
|
||||
g_list_free (repo_list);
|
||||
}
|
||||
|
||||
static void
|
||||
format_transfer_task_detail (TransferTask *task, GString *buf)
|
||||
{
|
||||
if (task->state != TASK_STATE_NORMAL ||
|
||||
task->runtime_state == TASK_RT_STATE_INIT ||
|
||||
task->runtime_state == TASK_RT_STATE_FINISHED ||
|
||||
task->runtime_state == TASK_RT_STATE_NETDOWN)
|
||||
return;
|
||||
|
||||
SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr,
|
||||
task->repo_id);
|
||||
char *repo_name;
|
||||
char *type;
|
||||
|
||||
if (repo) {
|
||||
repo_name = repo->name;
|
||||
type = (task->type == TASK_TYPE_UPLOAD) ? "upload" : "download";
|
||||
|
||||
} else if (task->is_clone) {
|
||||
CloneTask *ctask;
|
||||
ctask = seaf_clone_manager_get_task (seaf->clone_mgr, task->repo_id);
|
||||
repo_name = ctask->repo_name;
|
||||
type = "download";
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int rate = transfer_task_get_rate(task);
|
||||
|
||||
g_string_append_printf (buf, "%s\t%d %s\n", type, rate, repo_name);
|
||||
}
|
||||
|
||||
static void
|
||||
format_http_task_detail (HttpTxTask *task, GString *buf)
|
||||
{
|
||||
if (task->state != HTTP_TASK_STATE_NORMAL ||
|
||||
task->runtime_state == HTTP_TASK_RT_STATE_INIT ||
|
||||
task->runtime_state == HTTP_TASK_RT_STATE_FINISHED)
|
||||
return;
|
||||
|
||||
SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr,
|
||||
task->repo_id);
|
||||
char *repo_name;
|
||||
char *type;
|
||||
|
||||
if (repo) {
|
||||
repo_name = repo->name;
|
||||
type = (task->type == HTTP_TASK_TYPE_UPLOAD) ? "upload" : "download";
|
||||
|
||||
} else if (task->is_clone) {
|
||||
CloneTask *ctask;
|
||||
ctask = seaf_clone_manager_get_task (seaf->clone_mgr, task->repo_id);
|
||||
repo_name = ctask->repo_name;
|
||||
type = "download";
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int rate = http_tx_task_get_rate(task);
|
||||
|
||||
g_string_append_printf (buf, "%s\t%d %s\n", type, rate, repo_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Publish a notification message to report :
|
||||
*
|
||||
* [uploading/downloading]\t[transfer-rate] [repo-name]\n
|
||||
*/
|
||||
static int
|
||||
update_tx_state (void *vmanager)
|
||||
{
|
||||
SeafSyncManager *mgr = vmanager;
|
||||
GString *buf = g_string_new (NULL);
|
||||
GList *tasks, *ptr;
|
||||
TransferTask *task;
|
||||
HttpTxTask *http_task;
|
||||
|
||||
mgr->last_sent_bytes = g_atomic_int_get (&mgr->sent_bytes);
|
||||
g_atomic_int_set (&mgr->sent_bytes, 0);
|
||||
mgr->last_recv_bytes = g_atomic_int_get (&mgr->recv_bytes);
|
||||
g_atomic_int_set (&mgr->recv_bytes, 0);
|
||||
|
||||
tasks = seaf_transfer_manager_get_upload_tasks (seaf->transfer_mgr);
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
task = ptr->data;
|
||||
format_transfer_task_detail (task, buf);
|
||||
}
|
||||
g_list_free (tasks);
|
||||
|
||||
tasks = seaf_transfer_manager_get_download_tasks (seaf->transfer_mgr);
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
task = ptr->data;
|
||||
format_transfer_task_detail (task, buf);
|
||||
}
|
||||
g_list_free (tasks);
|
||||
|
||||
tasks = http_tx_manager_get_upload_tasks (seaf->http_tx_mgr);
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
http_task = ptr->data;
|
||||
format_http_task_detail (http_task, buf);
|
||||
}
|
||||
g_list_free (tasks);
|
||||
|
||||
tasks = http_tx_manager_get_download_tasks (seaf->http_tx_mgr);
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
http_task = ptr->data;
|
||||
format_http_task_detail (http_task, buf);
|
||||
}
|
||||
g_list_free (tasks);
|
||||
|
||||
if (buf->len != 0)
|
||||
seaf_mq_manager_publish_notification (seaf->mq_mgr, "transfer",
|
||||
buf->str);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
seaf_sync_manager_start (SeafSyncManager *mgr)
|
||||
{
|
||||
add_repo_relays ();
|
||||
|
||||
mgr->priv->check_sync_timer = ccnet_timer_new (
|
||||
auto_sync_pulse, mgr, CHECK_SYNC_INTERVAL);
|
||||
|
||||
mgr->priv->update_tx_state_timer = ccnet_timer_new (
|
||||
update_tx_state, mgr, UPDATE_TX_STATE_INTERVAL);
|
||||
|
||||
ccnet_proc_factory_register_processor (mgr->seaf->session->proc_factory,
|
||||
"seafile-sync-repo",
|
||||
SEAFILE_TYPE_SYNC_REPO_PROC);
|
||||
@ -191,6 +359,10 @@ seaf_sync_manager_start (SeafSyncManager *mgr)
|
||||
(GCallback)on_repo_fetched, mgr);
|
||||
g_signal_connect (seaf, "repo-uploaded",
|
||||
(GCallback)on_repo_uploaded, mgr);
|
||||
g_signal_connect (seaf, "repo-http-fetched",
|
||||
(GCallback)on_repo_http_fetched, mgr);
|
||||
g_signal_connect (seaf, "repo-http-uploaded",
|
||||
(GCallback)on_repo_http_uploaded, mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -269,15 +441,25 @@ seaf_sync_manager_cancel_sync_task (SeafSyncManager *mgr,
|
||||
|
||||
switch (task->state) {
|
||||
case SYNC_STATE_FETCH:
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_DOWNLOAD);
|
||||
if (!task->http_sync)
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_DOWNLOAD);
|
||||
else
|
||||
http_tx_manager_cancel_task (seaf->http_tx_mgr,
|
||||
repo_id,
|
||||
HTTP_TASK_TYPE_DOWNLOAD);
|
||||
transition_sync_state (task, SYNC_STATE_CANCEL_PENDING);
|
||||
break;
|
||||
case SYNC_STATE_UPLOAD:
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_UPLOAD);
|
||||
if (!task->http_sync)
|
||||
seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
|
||||
task->tx_id,
|
||||
TASK_TYPE_UPLOAD);
|
||||
else
|
||||
http_tx_manager_cancel_task (seaf->http_tx_mgr,
|
||||
repo_id,
|
||||
HTTP_TASK_TYPE_UPLOAD);
|
||||
transition_sync_state (task, SYNC_STATE_CANCEL_PENDING);
|
||||
break;
|
||||
case SYNC_STATE_COMMIT:
|
||||
@ -424,6 +606,7 @@ static const char *sync_error_str[] = {
|
||||
"Conflict in merge.",
|
||||
"Files changed in local folder, skip merge.",
|
||||
"Server version is too old.",
|
||||
"Failed to get sync info from server.",
|
||||
"Unknown error.",
|
||||
};
|
||||
|
||||
@ -472,52 +655,89 @@ static void
|
||||
start_upload_if_necessary (SyncTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
SeafRepo *repo = task->repo;
|
||||
const char *repo_id = task->repo->id;
|
||||
|
||||
char *tx_id = seaf_transfer_manager_add_upload (seaf->transfer_mgr,
|
||||
repo_id,
|
||||
task->repo->version,
|
||||
task->dest_id,
|
||||
"local",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
&error);
|
||||
if (error != NULL) {
|
||||
seaf_warning ("Failed to start upload: %s\n", error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_UPLOAD);
|
||||
return;
|
||||
if (!task->http_sync) {
|
||||
char *tx_id = seaf_transfer_manager_add_upload (seaf->transfer_mgr,
|
||||
repo_id,
|
||||
task->repo->version,
|
||||
task->dest_id,
|
||||
"local",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
&error);
|
||||
if (error != NULL) {
|
||||
seaf_warning ("Failed to start upload: %s\n", error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_UPLOAD);
|
||||
return;
|
||||
}
|
||||
task->tx_id = tx_id;
|
||||
} else {
|
||||
if (http_tx_manager_add_upload (seaf->http_tx_mgr,
|
||||
repo->id,
|
||||
repo->version,
|
||||
repo->server_url,
|
||||
repo->token,
|
||||
task->http_version,
|
||||
&error) < 0) {
|
||||
seaf_warning ("Failed to start http upload: %s\n", error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_UPLOAD);
|
||||
return;
|
||||
}
|
||||
task->tx_id = g_strdup(repo->id);
|
||||
}
|
||||
task->tx_id = tx_id;
|
||||
|
||||
transition_sync_state (task, SYNC_STATE_UPLOAD);
|
||||
}
|
||||
|
||||
static void
|
||||
start_fetch_if_necessary (SyncTask *task)
|
||||
start_fetch_if_necessary (SyncTask *task, const char *remote_head)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *tx_id;
|
||||
SeafRepo *repo = task->repo;
|
||||
const char *repo_id = task->repo->id;
|
||||
|
||||
tx_id = seaf_transfer_manager_add_download (seaf->transfer_mgr,
|
||||
repo_id,
|
||||
task->repo->version,
|
||||
task->dest_id,
|
||||
"fetch_head",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if (!task->http_sync) {
|
||||
tx_id = seaf_transfer_manager_add_download (seaf->transfer_mgr,
|
||||
repo_id,
|
||||
task->repo->version,
|
||||
task->dest_id,
|
||||
"fetch_head",
|
||||
"master",
|
||||
task->token,
|
||||
task->server_side_merge,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (error != NULL) {
|
||||
seaf_warning ("[sync-mgr] Failed to start download: %s\n",
|
||||
error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_FETCH);
|
||||
return;
|
||||
if (error != NULL) {
|
||||
seaf_warning ("[sync-mgr] Failed to start download: %s\n",
|
||||
error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_FETCH);
|
||||
return;
|
||||
}
|
||||
task->tx_id = tx_id;
|
||||
} else {
|
||||
if (http_tx_manager_add_download (seaf->http_tx_mgr,
|
||||
repo->id,
|
||||
repo->version,
|
||||
repo->server_url,
|
||||
repo->token,
|
||||
remote_head,
|
||||
FALSE,
|
||||
NULL, NULL,
|
||||
task->http_version,
|
||||
&error) < 0) {
|
||||
seaf_warning ("Failed to start http download: %s.\n", error->message);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_FETCH);
|
||||
return;
|
||||
}
|
||||
task->tx_id = g_strdup(repo->id);
|
||||
}
|
||||
task->tx_id = tx_id;
|
||||
|
||||
transition_sync_state (task, SYNC_STATE_FETCH);
|
||||
}
|
||||
|
||||
@ -778,7 +998,7 @@ getca_done_cb (CcnetProcessor *processor, gboolean success, void *data)
|
||||
"master");
|
||||
|
||||
if (!master || strcmp (info->head_commit, master->commit_id) != 0) {
|
||||
start_fetch_if_necessary (task);
|
||||
start_fetch_if_necessary (task, NULL);
|
||||
} else if (strcmp (repo->head->commit_id, master->commit_id) != 0) {
|
||||
/* Try to merge even if we don't need to fetch. */
|
||||
merge_branches_if_necessary (task);
|
||||
@ -1004,7 +1224,7 @@ update_sync_status (SyncTask *task)
|
||||
goto out;
|
||||
|
||||
if (!master || strcmp (info->head_commit, master->commit_id) != 0) {
|
||||
start_fetch_if_necessary (task);
|
||||
start_fetch_if_necessary (task, NULL);
|
||||
} else if (strcmp (local->commit_id, master->commit_id) != 0) {
|
||||
/* Try to merge even if we don't need to fetch. */
|
||||
merge_branches_if_necessary (task);
|
||||
@ -1076,7 +1296,7 @@ update_sync_status_v2 (SyncTask *task)
|
||||
} else
|
||||
transition_sync_state (task, SYNC_STATE_DONE);
|
||||
} else
|
||||
start_fetch_if_necessary (task);
|
||||
start_fetch_if_necessary (task, task->info->head_commit);
|
||||
}
|
||||
|
||||
seaf_branch_unref (local);
|
||||
@ -1156,6 +1376,40 @@ start_sync_repo_proc (SeafSyncManager *manager, SyncTask *task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
check_head_commit_done (HttpHeadCommit *result, void *user_data)
|
||||
{
|
||||
SyncTask *task = user_data;
|
||||
SyncInfo *info = task->info;
|
||||
|
||||
if (!result->check_success) {
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_GET_SYNC_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
info->deleted_on_relay = result->is_deleted;
|
||||
info->repo_corrupted = result->is_corrupt;
|
||||
memcpy (info->head_commit, result->head_commit, 40);
|
||||
|
||||
update_sync_status_v2 (task);
|
||||
}
|
||||
|
||||
static int
|
||||
check_head_commit_http (SyncTask *task)
|
||||
{
|
||||
SeafRepo *repo = task->repo;
|
||||
|
||||
int ret = http_tx_manager_check_head_commit (seaf->http_tx_mgr,
|
||||
repo->id, repo->version,
|
||||
repo->server_url,
|
||||
repo->token,
|
||||
check_head_commit_done,
|
||||
task);
|
||||
if (ret == 0)
|
||||
transition_sync_state (task, SYNC_STATE_INIT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct CommitResult {
|
||||
SyncTask *task;
|
||||
gboolean changed;
|
||||
@ -1232,9 +1486,12 @@ commit_job_done (void *vres)
|
||||
} else {
|
||||
if (res->changed)
|
||||
start_upload_if_necessary (res->task);
|
||||
else if (task->is_manual_sync || task->is_initial_commit)
|
||||
start_sync_repo_proc (task->mgr, task);
|
||||
else
|
||||
else if (task->is_manual_sync || task->is_initial_commit) {
|
||||
if (task->http_sync)
|
||||
check_head_commit_http (task);
|
||||
else
|
||||
start_sync_repo_proc (task->mgr, task);
|
||||
} else
|
||||
transition_sync_state (task, SYNC_STATE_DONE);
|
||||
}
|
||||
|
||||
@ -1389,6 +1646,17 @@ create_sync_task_v2 (SeafSyncManager *manager, SeafRepo *repo,
|
||||
task->info->in_sync = TRUE;
|
||||
task->repo = repo;
|
||||
|
||||
if (repo->server_url) {
|
||||
HttpServerState *state = g_hash_table_lookup (manager->http_server_states,
|
||||
repo->server_url);
|
||||
if (state) {
|
||||
if (!state->http_not_supported) {
|
||||
task->http_sync = TRUE;
|
||||
task->http_version = state->http_version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
@ -1476,7 +1744,7 @@ sync_repo_v2 (SeafSyncManager *manager, SeafRepo *repo, gboolean is_manual_sync)
|
||||
if (last_download && strcmp (last_download, EMPTY_SHA1) != 0) {
|
||||
if (is_manual_sync || can_schedule_repo (manager, repo)) {
|
||||
task = create_sync_task_v2 (manager, repo, is_manual_sync, FALSE);
|
||||
start_fetch_if_necessary (task);
|
||||
start_fetch_if_necessary (task, last_download);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -1497,7 +1765,10 @@ sync_repo_v2 (SeafSyncManager *manager, SeafRepo *repo, gboolean is_manual_sync)
|
||||
|
||||
if (is_manual_sync || can_schedule_repo (manager, repo)) {
|
||||
task = create_sync_task_v2 (manager, repo, is_manual_sync, FALSE);
|
||||
start_sync_repo_proc (manager, task);
|
||||
if (task->http_sync)
|
||||
check_head_commit_http (task);
|
||||
else
|
||||
start_sync_repo_proc (manager, task);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -1596,6 +1867,66 @@ check_relay_status (SeafSyncManager *mgr, SeafRepo *repo)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_http_protocol_done (HttpProtocolVersion *result, void *user_data)
|
||||
{
|
||||
HttpServerState *state = user_data;
|
||||
|
||||
state->checking = FALSE;
|
||||
|
||||
if (result->check_success) {
|
||||
state->http_not_supported = result->not_supported;
|
||||
if (!result->not_supported)
|
||||
state->http_version = result->version;
|
||||
} else
|
||||
state->http_not_supported = TRUE;
|
||||
}
|
||||
|
||||
#define CHECK_HTTP_INTERVAL 10
|
||||
|
||||
/*
|
||||
* Returns TRUE if we can use http-sync; otherwise FALSE.
|
||||
* If FALSE is returned, the caller should also check @is_checking value.
|
||||
* If @is_checking is set to TRUE, we're still determining whether the
|
||||
* server supports http-sync.
|
||||
*/
|
||||
static gboolean
|
||||
check_http_protocol (SeafSyncManager *mgr, SeafRepo *repo, gboolean *is_checking)
|
||||
{
|
||||
*is_checking = FALSE;
|
||||
|
||||
/* If a repo was cloned before 4.0, server-url is not set. */
|
||||
if (!repo->server_url)
|
||||
return FALSE;
|
||||
|
||||
HttpServerState *state = g_hash_table_lookup (mgr->http_server_states,
|
||||
repo->server_url);
|
||||
if (!state) {
|
||||
state = g_new0 (HttpServerState, 1);
|
||||
g_hash_table_insert (mgr->http_server_states,
|
||||
g_strdup(repo->server_url), state);
|
||||
}
|
||||
|
||||
if (state->checking) {
|
||||
*is_checking = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (state->http_not_supported)
|
||||
return FALSE;
|
||||
if (state->http_version > 0)
|
||||
return TRUE;
|
||||
|
||||
http_tx_manager_check_protocol_version (seaf->http_tx_mgr,
|
||||
repo->server_url,
|
||||
check_http_protocol_done,
|
||||
state);
|
||||
state->checking = TRUE;
|
||||
*is_checking = TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user upgarde from 3.0.x, there may be more than one commit to upload
|
||||
* on the local branch. The new syncing protocol can't handle more than one
|
||||
@ -1717,17 +2048,28 @@ auto_sync_pulse (void *vmanager)
|
||||
if (!manager->priv->auto_sync_enabled || !repo->auto_sync)
|
||||
continue;
|
||||
|
||||
SyncInfo *info = get_sync_info (manager, repo->id);
|
||||
|
||||
if (info->in_sync)
|
||||
continue;
|
||||
|
||||
/* Try to use http sync first if enabled. */
|
||||
gboolean is_checking_http = FALSE;
|
||||
if (seaf->enable_http_sync && repo->version > 0) {
|
||||
if (check_http_protocol (manager, repo, &is_checking_http)) {
|
||||
sync_repo_v2 (manager, repo, FALSE);
|
||||
continue;
|
||||
} else if (is_checking_http)
|
||||
continue;
|
||||
/* Otherwise we've determined the server doesn't support http-sync. */
|
||||
}
|
||||
|
||||
/* If relay is not ready or protocol version is not determined,
|
||||
* need to wait.
|
||||
*/
|
||||
if (!check_relay_status (manager, repo))
|
||||
continue;
|
||||
|
||||
SyncInfo *info = get_sync_info (manager, repo->id);
|
||||
|
||||
if (info->in_sync)
|
||||
continue;
|
||||
|
||||
ServerState *state = g_hash_table_lookup (manager->server_states,
|
||||
repo->relay_id);
|
||||
|
||||
@ -1821,7 +2163,10 @@ on_repo_uploaded (SeafileSession *seaf,
|
||||
transition_sync_state (task, SYNC_STATE_DONE);
|
||||
else {
|
||||
task->uploaded = TRUE;
|
||||
start_sync_repo_proc (manager, task);
|
||||
if (!task->http_sync)
|
||||
start_sync_repo_proc (manager, task);
|
||||
else
|
||||
check_head_commit_http (task);
|
||||
}
|
||||
} else if (tx_task->state == TASK_STATE_CANCELED) {
|
||||
transition_sync_state (task, SYNC_STATE_CANCELED);
|
||||
@ -1844,6 +2189,87 @@ on_repo_uploaded (SeafileSession *seaf,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_repo_http_fetched (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafSyncManager *manager)
|
||||
{
|
||||
SyncInfo *info = get_sync_info (manager, tx_task->repo_id);
|
||||
SyncTask *task = info->current_task;
|
||||
|
||||
/* Clone tasks are handled by clone manager. */
|
||||
if (tx_task->is_clone)
|
||||
return;
|
||||
|
||||
if (task->repo->delete_pending) {
|
||||
transition_sync_state (task, SYNC_STATE_CANCELED);
|
||||
seaf_repo_manager_del_repo (seaf->repo_mgr, task->repo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tx_task->state == HTTP_TASK_STATE_FINISHED) {
|
||||
memcpy (info->head_commit, tx_task->head, 41);
|
||||
transition_sync_state (task, SYNC_STATE_DONE);
|
||||
} else if (tx_task->state == HTTP_TASK_STATE_CANCELED) {
|
||||
transition_sync_state (task, SYNC_STATE_CANCELED);
|
||||
} else if (tx_task->state == HTTP_TASK_STATE_ERROR) {
|
||||
if (tx_task->error == HTTP_TASK_ERR_FORBIDDEN) {
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_ACCESS_DENIED);
|
||||
if (!task->repo->access_denied_notified) {
|
||||
send_sync_error_notification (task->repo, "sync.access_denied");
|
||||
task->repo->access_denied_notified = 1;
|
||||
}
|
||||
} else
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_FETCH);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_repo_http_uploaded (SeafileSession *seaf,
|
||||
HttpTxTask *tx_task,
|
||||
SeafSyncManager *manager)
|
||||
{
|
||||
SyncInfo *info = get_sync_info (manager, tx_task->repo_id);
|
||||
SyncTask *task = info->current_task;
|
||||
|
||||
g_return_if_fail (task != NULL && info->in_sync);
|
||||
|
||||
if (task->repo->delete_pending) {
|
||||
transition_sync_state (task, SYNC_STATE_CANCELED);
|
||||
seaf_repo_manager_del_repo (seaf->repo_mgr, task->repo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tx_task->state == HTTP_TASK_STATE_FINISHED) {
|
||||
memcpy (info->head_commit, tx_task->head, 41);
|
||||
|
||||
/* Save current head commit id for GC. */
|
||||
seaf_repo_manager_set_repo_property (seaf->repo_mgr,
|
||||
task->repo->id,
|
||||
REPO_LOCAL_HEAD,
|
||||
task->repo->head->commit_id);
|
||||
task->uploaded = TRUE;
|
||||
check_head_commit_http (task);
|
||||
} else if (tx_task->state == HTTP_TASK_STATE_CANCELED) {
|
||||
transition_sync_state (task, SYNC_STATE_CANCELED);
|
||||
} else if (tx_task->state == HTTP_TASK_STATE_ERROR) {
|
||||
if (tx_task->error == HTTP_TASK_ERR_FORBIDDEN) {
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_ACCESS_DENIED);
|
||||
if (!task->repo->access_denied_notified) {
|
||||
send_sync_error_notification (task->repo, "sync.access_denied");
|
||||
task->repo->access_denied_notified = 1;
|
||||
}
|
||||
} else if (tx_task->error == HTTP_TASK_ERR_NO_QUOTA) {
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_QUOTA_FULL);
|
||||
/* Only notify "quota full" once. */
|
||||
if (!task->repo->quota_full_notified) {
|
||||
send_sync_error_notification (task->repo, "sync.quota_full");
|
||||
task->repo->quota_full_notified = 1;
|
||||
}
|
||||
} else
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_UPLOAD);
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
sync_error_to_str (int error)
|
||||
|
@ -61,6 +61,7 @@ enum {
|
||||
SYNC_ERROR_MERGE,
|
||||
SYNC_ERROR_WORKTREE_DIRTY,
|
||||
SYNC_ERROR_DEPRECATED_SERVER,
|
||||
SYNC_ERROR_GET_SYNC_INFO, /* for http sync */
|
||||
SYNC_ERROR_UNKNOWN,
|
||||
SYNC_ERROR_NUM,
|
||||
};
|
||||
@ -80,22 +81,12 @@ struct _SyncTask {
|
||||
gboolean server_side_merge;
|
||||
gboolean uploaded;
|
||||
|
||||
gboolean http_sync;
|
||||
int http_version;
|
||||
|
||||
SeafRepo *repo; /* for convenience, only valid when in_sync. */
|
||||
};
|
||||
|
||||
enum {
|
||||
SERVER_SIDE_MERGE_UNKNOWN = 0,
|
||||
SERVER_SIDE_MERGE_SUPPORTED,
|
||||
SERVER_SIDE_MERGE_UNSUPPORTED,
|
||||
};
|
||||
|
||||
struct _ServerState {
|
||||
int server_side_merge;
|
||||
gboolean checking;
|
||||
};
|
||||
|
||||
typedef struct _ServerState ServerState;
|
||||
|
||||
struct _SeafileSession;
|
||||
|
||||
struct _SeafSyncManager {
|
||||
@ -107,6 +98,19 @@ struct _SeafSyncManager {
|
||||
int sync_interval;
|
||||
|
||||
GHashTable *server_states;
|
||||
GHashTable *http_server_states;
|
||||
|
||||
/* Sent/recv bytes from all transfer tasks in this second.
|
||||
* Since we have http and non-http tasks, sync manager is
|
||||
* the only reasonable place to put these variables.
|
||||
*/
|
||||
gint sent_bytes;
|
||||
gint recv_bytes;
|
||||
gint last_sent_bytes;
|
||||
gint last_recv_bytes;
|
||||
/* Upload/download rate limits. */
|
||||
gint upload_limit;
|
||||
gint download_limit;
|
||||
|
||||
SeafSyncManagerPriv *priv;
|
||||
};
|
||||
|
@ -438,19 +438,6 @@ seaf_transfer_manager_new (struct _SeafileSession *seaf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean exists;
|
||||
int download_limit = seafile_session_config_get_int (seaf,
|
||||
KEY_DOWNLOAD_LIMIT,
|
||||
&exists);
|
||||
if (exists)
|
||||
mgr->download_limit = download_limit;
|
||||
|
||||
int upload_limit = seafile_session_config_get_int (seaf,
|
||||
KEY_UPLOAD_LIMIT,
|
||||
&exists);
|
||||
if (exists)
|
||||
mgr->upload_limit = upload_limit;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
@ -1390,7 +1377,7 @@ download_and_checkout_files_thread (void *vdata)
|
||||
piperead (task->tx_info->done_pipe[0], &rsp, sizeof(rsp));
|
||||
|
||||
if (rsp == BLOCK_CLIENT_READY) {
|
||||
data->status = seaf_repo_fetch_and_checkout (task, task->head);
|
||||
data->status = seaf_repo_fetch_and_checkout (task, NULL, FALSE, task->head);
|
||||
|
||||
block_tx_client_run_command (task->tx_info, BLOCK_CLIENT_CMD_END);
|
||||
|
||||
@ -1805,12 +1792,6 @@ update_local_repo (TransferTask *task)
|
||||
branch = seaf_branch_new ("master", task->repo_id, task->head);
|
||||
seaf_branch_manager_add_branch (seaf->branch_mgr, branch);
|
||||
seaf_branch_unref (branch);
|
||||
|
||||
/* Set relay to where this repo from. */
|
||||
if (is_peer_relay (task->dest_id)) {
|
||||
seaf_repo_manager_set_repo_relay_id (seaf->repo_mgr, repo,
|
||||
task->dest_id);
|
||||
}
|
||||
} else {
|
||||
if (!repo) {
|
||||
transition_state_to_error (task, TASK_ERR_UNKNOWN);
|
||||
@ -2343,56 +2324,6 @@ state_machine_tick (TransferTask *task)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
format_transfer_task_detail (TransferTask *task, GString *buf)
|
||||
{
|
||||
SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr,
|
||||
task->repo_id);
|
||||
char *repo_name;
|
||||
char *type;
|
||||
|
||||
if (repo) {
|
||||
repo_name = repo->name;
|
||||
type = (task->type == TASK_TYPE_UPLOAD) ? "upload" : "download";
|
||||
|
||||
} else if (task->is_clone) {
|
||||
CloneTask *ctask;
|
||||
ctask = seaf_clone_manager_get_task (seaf->clone_mgr, task->repo_id);
|
||||
repo_name = ctask->repo_name;
|
||||
type = "download";
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int rate = transfer_task_get_rate(task);
|
||||
|
||||
g_string_append_printf (buf, "%s\t%d %s\n", type, rate, repo_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Publish a notification message to report :
|
||||
*
|
||||
* [uploading/downloading]\t[transfer-rate] [repo-name]\n
|
||||
*/
|
||||
static void
|
||||
send_transfer_message (GList *tasks)
|
||||
{
|
||||
GList *ptr;
|
||||
TransferTask *task;
|
||||
GString *buf = g_string_new (NULL);
|
||||
|
||||
for (ptr = tasks; ptr; ptr = ptr->next) {
|
||||
task = ptr->data;
|
||||
format_transfer_task_detail(task, buf);
|
||||
}
|
||||
|
||||
seaf_mq_manager_publish_notification (seaf->mq_mgr, "transfer",
|
||||
buf->str);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
schedule_task_pulse (void *vmanager)
|
||||
{
|
||||
@ -2401,58 +2332,17 @@ schedule_task_pulse (void *vmanager)
|
||||
gpointer key, value;
|
||||
TransferTask *task;
|
||||
|
||||
GList *tasks_in_transfer = NULL;
|
||||
|
||||
g_hash_table_iter_init (&iter, mgr->download_tasks);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
task = value;
|
||||
state_machine_tick (task);
|
||||
if ((task->state == TASK_STATE_NORMAL)
|
||||
&& (task->runtime_state == TASK_RT_STATE_COMMIT ||
|
||||
task->runtime_state == TASK_RT_STATE_FS ||
|
||||
task->runtime_state == TASK_RT_STATE_CHECK_BLOCKS ||
|
||||
task->runtime_state == TASK_RT_STATE_CHUNK_SERVER ||
|
||||
task->runtime_state == TASK_RT_STATE_DATA)) {
|
||||
tasks_in_transfer = g_list_prepend (tasks_in_transfer, task);
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, mgr->upload_tasks);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
task = value;
|
||||
state_machine_tick (task);
|
||||
if ((task->state == TASK_STATE_NORMAL)
|
||||
&& (task->runtime_state == TASK_RT_STATE_COMMIT ||
|
||||
task->runtime_state == TASK_RT_STATE_FS ||
|
||||
task->runtime_state == TASK_RT_STATE_CHECK_BLOCKS ||
|
||||
task->runtime_state == TASK_RT_STATE_CHUNK_SERVER ||
|
||||
task->runtime_state == TASK_RT_STATE_DATA)) {
|
||||
tasks_in_transfer = g_list_prepend (tasks_in_transfer, task);
|
||||
}
|
||||
}
|
||||
|
||||
if (tasks_in_transfer) {
|
||||
send_transfer_message (tasks_in_transfer);
|
||||
g_list_free (tasks_in_transfer);
|
||||
}
|
||||
|
||||
/* Save tx_bytes to last_tx_bytes and reset tx_bytes to 0 every second */
|
||||
g_hash_table_iter_init (&iter, mgr->download_tasks);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
task = value;
|
||||
task->last_tx_bytes = g_atomic_int_get (&task->tx_bytes);
|
||||
g_atomic_int_set (&task->tx_bytes, 0);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, mgr->upload_tasks);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
task = value;
|
||||
task->last_tx_bytes = g_atomic_int_get (&task->tx_bytes);
|
||||
g_atomic_int_set (&task->tx_bytes, 0);
|
||||
}
|
||||
|
||||
g_atomic_int_set (&mgr->sent_bytes, 0);
|
||||
g_atomic_int_set (&mgr->recv_bytes, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -211,13 +211,6 @@ struct _SeafTransferManager {
|
||||
GHashTable *upload_tasks;
|
||||
|
||||
CcnetTimer *schedule_timer;
|
||||
|
||||
/* Sent/recv bytes from all tasks in this second. */
|
||||
gint sent_bytes;
|
||||
gint recv_bytes;
|
||||
/* Upload/download rate limits. */
|
||||
gint upload_limit;
|
||||
gint download_limit;
|
||||
};
|
||||
|
||||
typedef struct _SeafTransferManager SeafTransferManager;
|
||||
|
@ -1,55 +0,0 @@
|
||||
|
||||
AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||
-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
|
||||
-DSEAFILE_SERVER \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_builddir)/lib \
|
||||
-I$(top_srcdir)/common \
|
||||
-I$(includedir) \
|
||||
@CCNET_CFLAGS@ \
|
||||
@SEARPC_CFLAGS@ \
|
||||
@GLIB2_CFLAGS@ \
|
||||
@ZDB_CFLAGS@ \
|
||||
@CURL_CFLAGS@ \
|
||||
@LIBARCHIVE_CFLAGS@ \
|
||||
@MSVC_CFLAGS@ \
|
||||
-Wall
|
||||
|
||||
bin_PROGRAMS = fileserver
|
||||
|
||||
noinst_HEADERS = seafile-session.h repo-mgr.h \
|
||||
fileserver.h access-file.h upload-file.h pack-dir.h fileserver-config.h
|
||||
|
||||
fileserver_SOURCES = \
|
||||
fileserver.c \
|
||||
access-file.c \
|
||||
upload-file.c \
|
||||
seafile-session.c \
|
||||
repo-mgr.c \
|
||||
pack-dir.c \
|
||||
fileserver-config.c \
|
||||
../common/seaf-db.c \
|
||||
../common/branch-mgr.c \
|
||||
../common/fs-mgr.c \
|
||||
../common/block-mgr.c \
|
||||
../common/block-backend.c \
|
||||
../common/block-backend-fs.c \
|
||||
../common/commit-mgr.c \
|
||||
../common/log.c \
|
||||
../common/object-list.c \
|
||||
../common/seaf-utils.c \
|
||||
../common/obj-store.c \
|
||||
../common/obj-backend-fs.c \
|
||||
../common/seafile-crypt.c
|
||||
|
||||
# XXX: -levent_openssl must be behind in -levhtp
|
||||
fileserver_LDADD = @LIBEVENT_LIBS@ -levhtp @SSL_LIBS@ -levent_openssl \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @LIB_RT@ \
|
||||
@CCNET_LIBS@ \
|
||||
$(top_builddir)/lib/libseafile.la \
|
||||
$(top_builddir)/common/cdc/libcdc.la \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ \
|
||||
@LIBARCHIVE_LIBS@ ${LIB_WS32} @ZLIB_LIBS@
|
||||
|
||||
fileserver_LDFLAGS = @STATIC_COMPILE@
|
@ -1,7 +0,0 @@
|
||||
== Compile ==
|
||||
|
||||
1. compile and install libevhtp library first
|
||||
cd libevhtp
|
||||
cmake . # you need to install cmake program to compile it
|
||||
make
|
||||
make install
|
@ -1,35 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "fileserver-config.h"
|
||||
|
||||
const char *OLD_GROUP_NAME = "httpserver";
|
||||
const char *GROUP_NAME = "fileserver";
|
||||
|
||||
static const char *
|
||||
get_group_name(GKeyFile *config)
|
||||
{
|
||||
return g_key_file_has_group (config, GROUP_NAME) ? GROUP_NAME : OLD_GROUP_NAME;
|
||||
}
|
||||
|
||||
int
|
||||
fileserver_config_get_integer(GKeyFile *config, char *key, GError **error)
|
||||
{
|
||||
const char *group = get_group_name(config);
|
||||
return g_key_file_get_integer (config, group, key, error);
|
||||
}
|
||||
|
||||
char *
|
||||
fileserver_config_get_string(GKeyFile *config, char *key, GError **error)
|
||||
{
|
||||
const char *group = get_group_name(config);
|
||||
return g_key_file_get_string (config, group, key, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fileserver_config_get_boolean(GKeyFile *config, char *key, GError **error)
|
||||
{
|
||||
const char *group = get_group_name(config);
|
||||
return g_key_file_get_boolean (config, group, key, error);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#ifndef SEAFILE_FILESERVER_CONFIG_H
|
||||
#define SEAFILE_FILESERVER_CONFIG_H
|
||||
|
||||
struct GKeyFile;
|
||||
|
||||
int
|
||||
fileserver_config_get_integer(GKeyFile *config, char *key, GError **error);
|
||||
|
||||
char *
|
||||
fileserver_config_get_string(GKeyFile *config, char *key, GError **error);
|
||||
|
||||
gboolean
|
||||
fileserver_config_get_boolean(GKeyFile *config, char *key, GError **error);
|
||||
|
||||
#endif // SEAFILE_FILESERVER_CONFIG_H
|
@ -1,369 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <event2/event.h>
|
||||
#else
|
||||
#include <event.h>
|
||||
#endif
|
||||
|
||||
#include <evhtp.h>
|
||||
|
||||
#include <ccnet.h>
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "fileserver-config.h"
|
||||
#include "fileserver.h"
|
||||
#include "access-file.h"
|
||||
#include "upload-file.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define DEFAULT_BIND_HOST "0.0.0.0"
|
||||
#define DEFAULT_BIND_PORT 8082
|
||||
#define DEFAULT_MAX_DOWNLOAD_DIR_SIZE 100 * ((gint64)1 << 20) /* 100MB */
|
||||
|
||||
static char *config_dir = NULL;
|
||||
static char *seafile_dir = NULL;
|
||||
static char *bind_addr = NULL;
|
||||
static uint16_t bind_port = 0;
|
||||
static int num_threads = 10;
|
||||
|
||||
static char *pidfile = NULL;
|
||||
|
||||
CcnetClient *ccnet_client;
|
||||
SeafileSession *seaf;
|
||||
|
||||
static const char *short_opts = "hvfc:d:t:l:g:G:D:k:P:";
|
||||
static const struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, 'h', },
|
||||
{ "version", no_argument, NULL, 'v', },
|
||||
{ "foreground", no_argument, NULL, 'f', },
|
||||
{ "ccnet-config-dir", required_argument, NULL, 'c', },
|
||||
{ "seafdir", required_argument, NULL, 'd', },
|
||||
{ "threads", required_argument, NULL, 't', },
|
||||
{ "log", required_argument, NULL, 'l' },
|
||||
{ "ccnet-debug-level", required_argument, NULL, 'g' },
|
||||
{ "http-debug-level", required_argument, NULL, 'G' },
|
||||
{ "debug", required_argument, NULL, 'D' },
|
||||
{ "temp-file-dir", required_argument, NULL, 'k' },
|
||||
{ "pidfile", required_argument, NULL, 'P' },
|
||||
};
|
||||
|
||||
static void usage ()
|
||||
{
|
||||
fprintf (stderr,
|
||||
"usage: fileserver [-c config_dir] [-d seafile_dir] \n");
|
||||
}
|
||||
|
||||
static void
|
||||
default_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
/* Return empty page. */
|
||||
evhtp_send_reply (req, EVHTP_RES_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_pidfile (const char *pidfile)
|
||||
{
|
||||
if (pidfile) {
|
||||
g_unlink (pidfile);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
write_pidfile (const char *pidfile_path)
|
||||
{
|
||||
if (!pidfile_path)
|
||||
return -1;
|
||||
|
||||
pid_t pid = getpid();
|
||||
|
||||
FILE *pidfile = g_fopen(pidfile_path, "w");
|
||||
if (!pidfile) {
|
||||
seaf_warning ("Failed to fopen() pidfile %s: %s\n",
|
||||
pidfile_path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof(buf), "%d\n", pid);
|
||||
if (fputs(buf, pidfile) < 0) {
|
||||
seaf_warning ("Failed to write pidfile %s: %s\n",
|
||||
pidfile_path, strerror(errno));
|
||||
fclose (pidfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fflush (pidfile);
|
||||
fclose (pidfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
on_fileserver_exit(void)
|
||||
{
|
||||
if (pidfile)
|
||||
remove_pidfile (pidfile);
|
||||
}
|
||||
|
||||
static void
|
||||
load_fileserver_config (SeafileSession *session)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *host = NULL;
|
||||
int port = 0;
|
||||
int max_upload_size_mb;
|
||||
int max_download_dir_size_mb;
|
||||
|
||||
host = fileserver_config_get_string (session->config, "host", &error);
|
||||
if (!error) {
|
||||
bind_addr = host;
|
||||
} else {
|
||||
if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
|
||||
error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
|
||||
seaf_warning ("[conf] Error: failed to read the value of 'host'\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
bind_addr = DEFAULT_BIND_HOST;
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
port = fileserver_config_get_integer (session->config, "port", &error);
|
||||
if (!error) {
|
||||
bind_port = port;
|
||||
} else {
|
||||
if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
|
||||
error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
|
||||
seaf_warning ("[conf] Error: failed to read the value of 'port'\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
bind_port = DEFAULT_BIND_PORT;
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
max_upload_size_mb = fileserver_config_get_integer (session->config,
|
||||
"max_upload_size",
|
||||
&error);
|
||||
if (error) {
|
||||
session->max_upload_size = -1; /* no limit */
|
||||
g_clear_error (&error);
|
||||
} else {
|
||||
if (max_upload_size_mb <= 0)
|
||||
session->max_upload_size = -1; /* no limit */
|
||||
else
|
||||
session->max_upload_size = max_upload_size_mb * ((gint64)1 << 20);
|
||||
}
|
||||
|
||||
max_download_dir_size_mb = fileserver_config_get_integer (session->config,
|
||||
"max_download_dir_size",
|
||||
&error);
|
||||
if (error) {
|
||||
session->max_download_dir_size = DEFAULT_MAX_DOWNLOAD_DIR_SIZE;
|
||||
g_clear_error (&error);
|
||||
} else {
|
||||
if (max_download_dir_size_mb <= 0)
|
||||
session->max_download_dir_size = DEFAULT_MAX_DOWNLOAD_DIR_SIZE;
|
||||
else
|
||||
session->max_download_dir_size = max_download_dir_size_mb * ((gint64)1 << 20);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
/* Get the commandline arguments in unicode, then convert them to utf8 */
|
||||
static char **
|
||||
get_argv_utf8 (int *argc)
|
||||
{
|
||||
int i = 0;
|
||||
char **argv = NULL;
|
||||
const wchar_t *cmdline = NULL;
|
||||
wchar_t **argv_w = NULL;
|
||||
|
||||
cmdline = GetCommandLineW();
|
||||
argv_w = CommandLineToArgvW (cmdline, argc);
|
||||
if (!argv_w) {
|
||||
printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
argv = (char **)malloc (sizeof(char*) * (*argc));
|
||||
for (i = 0; i < *argc; i++) {
|
||||
argv[i] = wchar_to_utf8 (argv_w[i]);
|
||||
}
|
||||
|
||||
return argv;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
evbase_t *evbase = NULL;
|
||||
evhtp_t *htp = NULL;
|
||||
int daemon_mode = 1;
|
||||
int c;
|
||||
char *logfile = NULL;
|
||||
char *ccnet_debug_level_str = "info";
|
||||
char *http_debug_level_str = "debug";
|
||||
const char *debug_str = NULL;
|
||||
char *temp_file_dir = NULL;
|
||||
|
||||
#ifdef WIN32
|
||||
argv = get_argv_utf8 (&argc);
|
||||
#endif
|
||||
|
||||
config_dir = DEFAULT_CONFIG_DIR;
|
||||
|
||||
while ((c = getopt_long(argc, argv,
|
||||
short_opts, long_opts, NULL)) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
case 'v':
|
||||
exit(-1);
|
||||
break;
|
||||
case 'c':
|
||||
config_dir = strdup(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
seafile_dir = strdup(optarg);
|
||||
break;
|
||||
case 't':
|
||||
num_threads = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
daemon_mode = 0;
|
||||
break;
|
||||
case 'l':
|
||||
logfile = g_strdup(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
ccnet_debug_level_str = optarg;
|
||||
break;
|
||||
case 'G':
|
||||
http_debug_level_str = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
debug_str = optarg;
|
||||
break;
|
||||
case 'k':
|
||||
temp_file_dir = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (daemon_mode) {
|
||||
#ifndef __APPLE__
|
||||
daemon (1, 0);
|
||||
#else /* __APPLE */
|
||||
/* daemon is deprecated under APPLE
|
||||
* use fork() instead
|
||||
* */
|
||||
switch (fork ()) {
|
||||
case -1:
|
||||
seaf_warning ("Failed to daemonize");
|
||||
exit (-1);
|
||||
break;
|
||||
case 0:
|
||||
/* all good*/
|
||||
break;
|
||||
default:
|
||||
/* kill origin process */
|
||||
exit (0);
|
||||
}
|
||||
#endif /* __APPLE */
|
||||
}
|
||||
#endif /* !WIN32 */
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(0x0101, &wsadata);
|
||||
#endif
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 35, 0)
|
||||
g_type_init();
|
||||
#endif
|
||||
|
||||
if (!debug_str)
|
||||
debug_str = g_getenv("SEAFILE_DEBUG");
|
||||
seafile_debug_set_flags_string (debug_str);
|
||||
|
||||
if (seafile_dir == NULL)
|
||||
seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
|
||||
if (logfile == NULL)
|
||||
logfile = g_build_filename (seafile_dir, "http.log", NULL);
|
||||
|
||||
if (seafile_log_init (logfile, ccnet_debug_level_str,
|
||||
http_debug_level_str) < 0) {
|
||||
g_warning ("Failed to init log.\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
ccnet_client = ccnet_client_new();
|
||||
if ((ccnet_client_load_confdir(ccnet_client, config_dir)) < 0) {
|
||||
g_warning ("Read config dir error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
seaf = seafile_session_new (seafile_dir, ccnet_client);
|
||||
if (!seaf) {
|
||||
g_warning ("Failed to create seafile session.\n");
|
||||
exit (1);
|
||||
}
|
||||
if (seafile_session_init(seaf) < 0)
|
||||
exit (1);
|
||||
|
||||
if (temp_file_dir == NULL)
|
||||
seaf->http_temp_dir = g_build_filename (seaf->seaf_dir, "httptemp", NULL);
|
||||
else
|
||||
seaf->http_temp_dir = g_strdup(temp_file_dir);
|
||||
|
||||
seaf->client_pool = ccnet_client_pool_new (config_dir);
|
||||
|
||||
load_fileserver_config (seaf);
|
||||
seaf_message ("host = %s, port = %d\n", bind_addr, bind_port);
|
||||
|
||||
evbase = event_base_new();
|
||||
htp = evhtp_new(evbase, NULL);
|
||||
|
||||
if (access_file_init (htp) < 0)
|
||||
exit (1);
|
||||
|
||||
if (upload_file_init (htp) < 0)
|
||||
exit (1);
|
||||
|
||||
evhtp_set_gencb(htp, default_cb, NULL);
|
||||
|
||||
evhtp_use_threads(htp, NULL, num_threads, NULL);
|
||||
|
||||
if (evhtp_bind_socket(htp, bind_addr, bind_port, 128) < 0) {
|
||||
g_warning ("Could not bind socket: %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pidfile) {
|
||||
if (write_pidfile (pidfile) < 0) {
|
||||
seaf_message ("Failed to write pidfile\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
atexit (on_fileserver_exit);
|
||||
|
||||
event_base_loop(evbase, 0);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#ifndef SEAFILE_FILESERVER_H
|
||||
#define SEAFILE_FILESERVER_H
|
||||
|
||||
extern SeafileSession *seaf;
|
||||
|
||||
#endif // SEAFILE_FILESERVER_H
|
@ -1,394 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
#include "common.h"
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include <ccnet.h>
|
||||
#include "utils.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "commit-mgr.h"
|
||||
#include "branch-mgr.h"
|
||||
#include "repo-mgr.h"
|
||||
#include "fs-mgr.h"
|
||||
#include "seafile-error.h"
|
||||
|
||||
#include "seaf-db.h"
|
||||
|
||||
#define INDEX_DIR "index"
|
||||
|
||||
struct _SeafRepoManagerPriv {
|
||||
|
||||
};
|
||||
|
||||
static SeafRepo *
|
||||
load_repo (SeafRepoManager *manager, const char *repo_id);
|
||||
|
||||
gboolean
|
||||
is_repo_id_valid (const char *id)
|
||||
{
|
||||
if (!id)
|
||||
return FALSE;
|
||||
|
||||
return is_uuid_valid (id);
|
||||
}
|
||||
|
||||
SeafRepo*
|
||||
seaf_repo_new (const char *id, const char *name, const char *desc)
|
||||
{
|
||||
SeafRepo* repo;
|
||||
|
||||
/* valid check */
|
||||
|
||||
|
||||
repo = g_new0 (SeafRepo, 1);
|
||||
memcpy (repo->id, id, 36);
|
||||
repo->id[36] = '\0';
|
||||
|
||||
repo->name = g_strdup(name);
|
||||
repo->desc = g_strdup(desc);
|
||||
|
||||
repo->ref_cnt = 1;
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_free (SeafRepo *repo)
|
||||
{
|
||||
if (repo->name) g_free (repo->name);
|
||||
if (repo->desc) g_free (repo->desc);
|
||||
if (repo->category) g_free (repo->category);
|
||||
if (repo->head) seaf_branch_unref (repo->head);
|
||||
g_free (repo);
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_ref (SeafRepo *repo)
|
||||
{
|
||||
g_atomic_int_inc (&repo->ref_cnt);
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_unref (SeafRepo *repo)
|
||||
{
|
||||
if (!repo)
|
||||
return;
|
||||
|
||||
if (g_atomic_int_dec_and_test (&repo->ref_cnt))
|
||||
seaf_repo_free (repo);
|
||||
}
|
||||
|
||||
static void
|
||||
set_head_common (SeafRepo *repo, SeafBranch *branch)
|
||||
{
|
||||
if (repo->head)
|
||||
seaf_branch_unref (repo->head);
|
||||
repo->head = branch;
|
||||
seaf_branch_ref(branch);
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
{
|
||||
repo->name = g_strdup (commit->repo_name);
|
||||
repo->desc = g_strdup (commit->repo_desc);
|
||||
repo->encrypted = commit->encrypted;
|
||||
if (repo->encrypted) {
|
||||
repo->enc_version = commit->enc_version;
|
||||
if (repo->enc_version >= 1)
|
||||
memcpy (repo->magic, commit->magic, 33);
|
||||
}
|
||||
repo->no_local_history = commit->no_local_history;
|
||||
repo->version = commit->version;
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
{
|
||||
commit->repo_name = g_strdup (repo->name);
|
||||
commit->repo_desc = g_strdup (repo->desc);
|
||||
commit->encrypted = repo->encrypted;
|
||||
if (commit->encrypted) {
|
||||
commit->enc_version = repo->enc_version;
|
||||
if (commit->enc_version >= 1)
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
}
|
||||
commit->no_local_history = repo->no_local_history;
|
||||
commit->version = repo->version;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
collect_commit (SeafCommit *commit, void *vlist, gboolean *stop)
|
||||
{
|
||||
GList **commits = vlist;
|
||||
|
||||
/* The traverse function will unref the commit, so we need to ref it.
|
||||
*/
|
||||
seaf_commit_ref (commit);
|
||||
*commits = g_list_prepend (*commits, commit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GList *
|
||||
seaf_repo_get_commits (SeafRepo *repo)
|
||||
{
|
||||
GList *branches;
|
||||
GList *ptr;
|
||||
SeafBranch *branch;
|
||||
GList *commits = NULL;
|
||||
|
||||
branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id);
|
||||
if (branches == NULL) {
|
||||
g_warning ("Failed to get branch list of repo %s.\n", repo->id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ptr = branches; ptr != NULL; ptr = ptr->next) {
|
||||
branch = ptr->data;
|
||||
gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr,
|
||||
repo->id,
|
||||
repo->version,
|
||||
branch->commit_id,
|
||||
collect_commit,
|
||||
&commits,
|
||||
FALSE);
|
||||
if (!res) {
|
||||
for (ptr = commits; ptr != NULL; ptr = ptr->next)
|
||||
seaf_commit_unref ((SeafCommit *)(ptr->data));
|
||||
g_list_free (commits);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
commits = g_list_reverse (commits);
|
||||
|
||||
out:
|
||||
for (ptr = branches; ptr != NULL; ptr = ptr->next) {
|
||||
seaf_branch_unref ((SeafBranch *)ptr->data);
|
||||
}
|
||||
return commits;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_repo (const SeafRepo *srepo, const SeafRepo *trepo)
|
||||
{
|
||||
return g_strcmp0 (srepo->id, trepo->id);
|
||||
}
|
||||
|
||||
SeafRepoManager*
|
||||
seaf_repo_manager_new (SeafileSession *seaf)
|
||||
{
|
||||
SeafRepoManager *mgr = g_new0 (SeafRepoManager, 1);
|
||||
|
||||
mgr->priv = g_new0 (SeafRepoManagerPriv, 1);
|
||||
mgr->seaf = seaf;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
int
|
||||
seaf_repo_manager_init (SeafRepoManager *mgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
seaf_repo_manager_start (SeafRepoManager *mgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
repo_exists_in_db (SeafDB *db, const char *id)
|
||||
{
|
||||
gboolean db_err = FALSE;
|
||||
|
||||
return seaf_db_statement_exists (db,
|
||||
"SELECT repo_id FROM Repo WHERE repo_id = ?",
|
||||
&db_err, 1, "string", id);
|
||||
}
|
||||
|
||||
SeafRepo*
|
||||
seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id)
|
||||
{
|
||||
SeafRepo repo;
|
||||
int len = strlen(id);
|
||||
|
||||
if (len >= 37)
|
||||
return NULL;
|
||||
|
||||
memcpy (repo.id, id, len + 1);
|
||||
|
||||
if (repo_exists_in_db (manager->seaf->db, id)) {
|
||||
SeafRepo *ret = load_repo (manager, id);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
/* seaf_repo_ref (ret); */
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id)
|
||||
{
|
||||
SeafRepo repo;
|
||||
memcpy (repo.id, id, 37);
|
||||
|
||||
return repo_exists_in_db (manager->seaf->db, id);
|
||||
}
|
||||
|
||||
static void
|
||||
load_repo_commit (SeafRepoManager *manager,
|
||||
SeafRepo *repo,
|
||||
SeafBranch *branch)
|
||||
{
|
||||
SeafCommit *commit;
|
||||
|
||||
commit = seaf_commit_manager_get_commit_compatible (manager->seaf->commit_mgr,
|
||||
repo->id,
|
||||
branch->commit_id);
|
||||
if (!commit) {
|
||||
g_warning ("Commit %s is missing\n", branch->commit_id);
|
||||
repo->is_corrupted = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
set_head_common (repo, branch);
|
||||
seaf_repo_from_commit (repo, commit);
|
||||
|
||||
seaf_commit_unref (commit);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_virtual_info (SeafDBRow *row, void *vrepo_id)
|
||||
{
|
||||
char *ret_repo_id = vrepo_id;
|
||||
const char *origin_repo_id;
|
||||
|
||||
origin_repo_id = seaf_db_row_get_column_text (row, 0);
|
||||
memcpy (ret_repo_id, origin_repo_id, 37);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char *
|
||||
get_origin_repo_id (SeafRepoManager *mgr, const char *repo_id)
|
||||
{
|
||||
char *sql;
|
||||
char origin_repo_id[37];
|
||||
|
||||
memset (origin_repo_id, 0, 37);
|
||||
|
||||
sql = "SELECT origin_repo FROM VirtualRepo WHERE repo_id = ?";
|
||||
seaf_db_statement_foreach_row (seaf->db, sql,
|
||||
load_virtual_info, origin_repo_id,
|
||||
1, "string", repo_id);
|
||||
|
||||
if (origin_repo_id[0] != 0)
|
||||
return g_strdup(origin_repo_id);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SeafRepo *
|
||||
load_repo (SeafRepoManager *manager, const char *repo_id)
|
||||
{
|
||||
SeafRepo *repo;
|
||||
SeafBranch *branch;
|
||||
|
||||
repo = seaf_repo_new(repo_id, NULL, NULL);
|
||||
if (!repo) {
|
||||
g_warning ("[repo mgr] failed to alloc repo.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
repo->manager = manager;
|
||||
|
||||
branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master");
|
||||
if (!branch) {
|
||||
g_warning ("Failed to get master branch of repo %.8s.\n", repo_id);
|
||||
repo->is_corrupted = TRUE;
|
||||
} else {
|
||||
load_repo_commit (manager, repo, branch);
|
||||
seaf_branch_unref (branch);
|
||||
}
|
||||
|
||||
if (repo->is_corrupted) {
|
||||
g_warning ("Repo %.8s is corrupted.\n", repo->id);
|
||||
seaf_repo_free (repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *origin_repo_id = get_origin_repo_id (manager, repo->id);
|
||||
if (origin_repo_id)
|
||||
memcpy (repo->store_id, origin_repo_id, 36);
|
||||
else
|
||||
memcpy (repo->store_id, repo->id, 36);
|
||||
g_free (origin_repo_id);
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
collect_repo_id (SeafDBRow *row, void *data)
|
||||
{
|
||||
GList **p_ids = data;
|
||||
const char *repo_id;
|
||||
|
||||
repo_id = seaf_db_row_get_column_text (row, 0);
|
||||
*p_ids = g_list_prepend (*p_ids, g_strdup(repo_id));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GList *
|
||||
seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr)
|
||||
{
|
||||
GList *ret = NULL;
|
||||
char sql[256];
|
||||
|
||||
snprintf (sql, 256, "SELECT repo_id FROM Repo");
|
||||
|
||||
if (seaf_db_foreach_selected_row (mgr->seaf->db, sql,
|
||||
collect_repo_id, &ret) < 0)
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GList *
|
||||
seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit)
|
||||
{
|
||||
GList *id_list = NULL, *ptr;
|
||||
GList *ret = NULL;
|
||||
SeafRepo *repo;
|
||||
int rc;
|
||||
|
||||
if (start == -1 && limit == -1)
|
||||
rc = seaf_db_statement_foreach_row (mgr->seaf->db,
|
||||
"SELECT repo_id FROM Repo",
|
||||
collect_repo_id, &id_list,
|
||||
0);
|
||||
else
|
||||
rc = seaf_db_statement_foreach_row (mgr->seaf->db,
|
||||
"SELECT repo_id FROM Repo LIMIT ?, ?",
|
||||
collect_repo_id, &id_list,
|
||||
2, "int", start, "int", limit);
|
||||
|
||||
if (rc < 0)
|
||||
return NULL;
|
||||
|
||||
for (ptr = id_list; ptr; ptr = ptr->next) {
|
||||
char *repo_id = ptr->data;
|
||||
repo = seaf_repo_manager_get_repo (mgr, repo_id);
|
||||
if (repo != NULL)
|
||||
ret = g_list_prepend (ret, repo);
|
||||
}
|
||||
|
||||
string_list_free (id_list);
|
||||
return g_list_reverse (ret);
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
#ifndef SEAF_REPO_MGR_H
|
||||
#define SEAF_REPO_MGR_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "seafile-object.h"
|
||||
#include "commit-mgr.h"
|
||||
#include "branch-mgr.h"
|
||||
|
||||
#define REPO_AUTO_SYNC "auto-sync"
|
||||
#define REPO_AUTO_FETCH "auto-fetch"
|
||||
#define REPO_AUTO_UPLOAD "auto-upload"
|
||||
#define REPO_AUTO_MERGE "auto-merge"
|
||||
#define REPO_AUTO_COMMIT "auto-commit"
|
||||
#define REPO_RELAY_ID "relay-id"
|
||||
#define REPO_NET_BROWSABLE "net-browsable"
|
||||
#define REPO_DOUBLE_SYNC "double-sync"
|
||||
#define REPO_REMOTE_HEAD "remote-head"
|
||||
#define REPO_ENCRYPTED 0x1
|
||||
|
||||
struct _SeafRepoManager;
|
||||
typedef struct _SeafRepo SeafRepo;
|
||||
|
||||
struct _SeafRepo {
|
||||
struct _SeafRepoManager *manager;
|
||||
|
||||
gchar id[37];
|
||||
gchar *name;
|
||||
gchar *desc;
|
||||
gchar *category; /* not used yet */
|
||||
gboolean encrypted;
|
||||
int enc_version;
|
||||
gchar magic[33]; /* hash(repo_id + passwd), key stretched. */
|
||||
gboolean no_local_history;
|
||||
|
||||
SeafBranch *head;
|
||||
|
||||
gboolean is_corrupted;
|
||||
gboolean delete_pending;
|
||||
int ref_cnt;
|
||||
|
||||
int version;
|
||||
/* Used to access fs and block sotre.
|
||||
* This id is different from repo_id when this repo is virtual.
|
||||
* Virtual repos share fs and block store with its origin repo.
|
||||
* However, commit store for each repo is always independent.
|
||||
* So always use repo_id to access commit store.
|
||||
*/
|
||||
gchar store_id[37];
|
||||
};
|
||||
|
||||
gboolean is_repo_id_valid (const char *id);
|
||||
|
||||
SeafRepo*
|
||||
seaf_repo_new (const char *id, const char *name, const char *desc);
|
||||
|
||||
void
|
||||
seaf_repo_free (SeafRepo *repo);
|
||||
|
||||
void
|
||||
seaf_repo_ref (SeafRepo *repo);
|
||||
|
||||
void
|
||||
seaf_repo_unref (SeafRepo *repo);
|
||||
|
||||
typedef struct _SeafRepoManager SeafRepoManager;
|
||||
typedef struct _SeafRepoManagerPriv SeafRepoManagerPriv;
|
||||
|
||||
struct _SeafRepoManager {
|
||||
struct _SeafileSession *seaf;
|
||||
|
||||
SeafRepoManagerPriv *priv;
|
||||
};
|
||||
|
||||
SeafRepoManager*
|
||||
seaf_repo_manager_new (struct _SeafileSession *seaf);
|
||||
|
||||
int
|
||||
seaf_repo_manager_init (SeafRepoManager *mgr);
|
||||
|
||||
int
|
||||
seaf_repo_manager_start (SeafRepoManager *mgr);
|
||||
|
||||
int
|
||||
seaf_repo_manager_add_repo (SeafRepoManager *mgr, SeafRepo *repo);
|
||||
|
||||
int
|
||||
seaf_repo_manager_del_repo (SeafRepoManager *mgr, SeafRepo *repo);
|
||||
|
||||
SeafRepo*
|
||||
seaf_repo_manager_get_repo (SeafRepoManager *manager, const gchar *id);
|
||||
|
||||
gboolean
|
||||
seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id);
|
||||
|
||||
GList*
|
||||
seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit);
|
||||
|
||||
GList *
|
||||
seaf_repo_manager_get_repo_id_list (SeafRepoManager *mgr);
|
||||
|
||||
#endif
|
@ -1,137 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ccnet.h>
|
||||
#include <utils.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "seaf-utils.h"
|
||||
|
||||
|
||||
/* Zip filename in windows should be encoded in UTF-8 to be consistent across
|
||||
* all system encodings. However, WinRAR(a much popular compress software)
|
||||
* does not support UTF-8 filename.
|
||||
*
|
||||
* To sovle this problem, set the `windows_encoding` under the [zip] category
|
||||
* in seafile.conf. If set, file name would be converted to the specified
|
||||
* encoding. Otherwise, the UTF-8 way would be used.
|
||||
*/
|
||||
void
|
||||
load_zip_encoding_config (SeafileSession *session)
|
||||
{
|
||||
char *encoding;
|
||||
GError *error = NULL;
|
||||
|
||||
encoding = g_key_file_get_string (session->config, "zip", "windows_encoding", &error);
|
||||
if (encoding) {
|
||||
session->windows_encoding = encoding;
|
||||
} else {
|
||||
/* No windows specific encoding is specified. Set the ZIP_UTF8 flag. */
|
||||
setlocale (LC_ALL, "en_US.UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
SeafileSession *
|
||||
seafile_session_new(const char *seafile_dir,
|
||||
CcnetClient *ccnet_session)
|
||||
{
|
||||
char *abs_seafile_dir;
|
||||
char *tmp_file_dir;
|
||||
char *config_file_path;
|
||||
struct stat st;
|
||||
GKeyFile *config;
|
||||
SeafileSession *session = NULL;
|
||||
|
||||
if (!ccnet_session)
|
||||
return NULL;
|
||||
|
||||
abs_seafile_dir = ccnet_expand_path (seafile_dir);
|
||||
tmp_file_dir = g_build_filename (abs_seafile_dir, "tmpfiles", NULL);
|
||||
config_file_path = g_build_filename (abs_seafile_dir, "seafile.conf", NULL);
|
||||
|
||||
if (g_stat(abs_seafile_dir, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||
g_warning ("Seafile data dir %s does not exist and is unable to create\n",
|
||||
abs_seafile_dir);
|
||||
goto onerror;
|
||||
}
|
||||
|
||||
if (g_stat(tmp_file_dir, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||
g_warning ("Seafile tmp dir %s does not exist and is unable to create\n",
|
||||
tmp_file_dir);
|
||||
goto onerror;
|
||||
}
|
||||
|
||||
GError *error = NULL;
|
||||
config = g_key_file_new ();
|
||||
if (!g_key_file_load_from_file (config, config_file_path,
|
||||
G_KEY_FILE_NONE, &error)) {
|
||||
g_warning ("Failed to load config file.\n");
|
||||
g_key_file_free (config);
|
||||
goto onerror;
|
||||
}
|
||||
|
||||
session = g_new0(SeafileSession, 1);
|
||||
session->seaf_dir = abs_seafile_dir;
|
||||
session->tmp_file_dir = tmp_file_dir;
|
||||
session->session = ccnet_session;
|
||||
session->config = config;
|
||||
|
||||
if (load_database_config (session) < 0) {
|
||||
g_warning ("Failed to load database config.\n");
|
||||
goto onerror;
|
||||
}
|
||||
load_zip_encoding_config (session);
|
||||
|
||||
session->fs_mgr = seaf_fs_manager_new (session, abs_seafile_dir);
|
||||
if (!session->fs_mgr)
|
||||
goto onerror;
|
||||
session->block_mgr = seaf_block_manager_new (session, abs_seafile_dir);
|
||||
if (!session->block_mgr)
|
||||
goto onerror;
|
||||
session->commit_mgr = seaf_commit_manager_new (session);
|
||||
if (!session->commit_mgr)
|
||||
goto onerror;
|
||||
session->repo_mgr = seaf_repo_manager_new (session);
|
||||
if (!session->repo_mgr)
|
||||
goto onerror;
|
||||
session->branch_mgr = seaf_branch_manager_new (session);
|
||||
if (!session->branch_mgr)
|
||||
goto onerror;
|
||||
|
||||
return session;
|
||||
|
||||
onerror:
|
||||
free (abs_seafile_dir);
|
||||
g_free (tmp_file_dir);
|
||||
g_free (config_file_path);
|
||||
g_free (session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_session_init (SeafileSession *session)
|
||||
{
|
||||
if (seaf_commit_manager_init (session->commit_mgr) < 0)
|
||||
return -1;
|
||||
|
||||
if (seaf_fs_manager_init (session->fs_mgr) < 0)
|
||||
return -1;
|
||||
|
||||
if (seaf_branch_manager_init (session->branch_mgr) < 0)
|
||||
return -1;
|
||||
|
||||
if (seaf_repo_manager_init (session->repo_mgr) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_session_start (SeafileSession *session)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#ifndef SEAFILE_SESSION_H
|
||||
#define SEAFILE_SESSION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "block-mgr.h"
|
||||
#include "fs-mgr.h"
|
||||
#include "commit-mgr.h"
|
||||
#include "branch-mgr.h"
|
||||
#include "repo-mgr.h"
|
||||
#include "db.h"
|
||||
#include "seaf-db.h"
|
||||
|
||||
struct _CcnetClient;
|
||||
|
||||
typedef struct _SeafileSession SeafileSession;
|
||||
|
||||
struct CcnetClientPool;
|
||||
|
||||
struct _SeafileSession {
|
||||
struct _CcnetClient *session;
|
||||
|
||||
char *seaf_dir;
|
||||
char *tmp_file_dir;
|
||||
/* Config that's only loaded on start */
|
||||
GKeyFile *config;
|
||||
SeafDB *db;
|
||||
char *windows_encoding;
|
||||
gint64 max_upload_size;
|
||||
gint64 max_download_dir_size;
|
||||
char *http_temp_dir;
|
||||
|
||||
struct CcnetClientPool *client_pool;
|
||||
|
||||
SeafBlockManager *block_mgr;
|
||||
SeafFSManager *fs_mgr;
|
||||
SeafCommitManager *commit_mgr;
|
||||
SeafBranchManager *branch_mgr;
|
||||
SeafRepoManager *repo_mgr;
|
||||
};
|
||||
|
||||
extern SeafileSession *seaf;
|
||||
|
||||
SeafileSession *
|
||||
seafile_session_new (const char *seafile_dir,
|
||||
struct _CcnetClient *ccnet);
|
||||
|
||||
int
|
||||
seafile_session_init (SeafileSession *session);
|
||||
|
||||
int
|
||||
seafile_session_start (SeafileSession *session);
|
||||
|
||||
#endif
|
@ -1,7 +0,0 @@
|
||||
#ifndef UPLOAD_FILE_H
|
||||
#define UPLOAD_FILE_H
|
||||
|
||||
int
|
||||
upload_file_init (evhtp_t *htp);
|
||||
|
||||
#endif
|
@ -334,26 +334,6 @@ seafile_gc (GError **error);
|
||||
|
||||
/* ----------------- Task Related -------------- */
|
||||
|
||||
/**
|
||||
* seafile_get_upload_task_list:
|
||||
*
|
||||
* List all the upload tasks.
|
||||
*
|
||||
* Returns: A list of task info.
|
||||
*/
|
||||
GList* seafile_get_upload_task_list (GError **error);
|
||||
|
||||
|
||||
/**
|
||||
* seafile_get_download_task_list:
|
||||
*
|
||||
* List all the download tasks.
|
||||
*
|
||||
* Returns: A list of task info.
|
||||
*/
|
||||
GList* seafile_get_download_task_list (GError **error);
|
||||
|
||||
|
||||
/**
|
||||
* seafile_find_transfer:
|
||||
*
|
||||
|
@ -105,13 +105,13 @@ class SeafileRpcClient(ccnet.RpcClientBase):
|
||||
def gen_default_worktree(worktree_parent, repo_name):
|
||||
pass
|
||||
|
||||
@searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int"])
|
||||
def seafile_clone(repo_id, repo_version, peer_id, repo_name, worktree, token, password, magic, peer_addr, peer_port, email, random_key, enc_version):
|
||||
@searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"])
|
||||
def seafile_clone(repo_id, repo_version, peer_id, repo_name, worktree, token, password, magic, peer_addr, peer_port, email, random_key, enc_version, server_url):
|
||||
pass
|
||||
clone = seafile_clone
|
||||
|
||||
@searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int"])
|
||||
def seafile_download(repo_id, repo_version, peer_id, repo_name, wt_parent, token, password, magic, peer_addr, peer_port, email, random_key, enc_version):
|
||||
@searpc_func("string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"])
|
||||
def seafile_download(repo_id, repo_version, peer_id, repo_name, wt_parent, token, password, magic, peer_addr, peer_port, email, random_key, enc_version, server_url):
|
||||
pass
|
||||
download = seafile_download
|
||||
|
||||
|
@ -14,6 +14,7 @@ AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||
@ZDB_CFLAGS@ \
|
||||
@MSVC_CFLAGS@ \
|
||||
@CURL_CFLAGS@ \
|
||||
@LIBARCHIVE_CFLAGS@
|
||||
-Wall
|
||||
|
||||
bin_PROGRAMS = seaf-server
|
||||
@ -50,6 +51,11 @@ noinst_HEADERS = web-accesstoken-mgr.h chunkserv-mgr.h seafile-session.h \
|
||||
size-sched.h \
|
||||
block-tx-server.h \
|
||||
copy-mgr.h \
|
||||
http-server.h \
|
||||
upload-file.h \
|
||||
access-file.h \
|
||||
pack-dir.h \
|
||||
http-status-codes.h \
|
||||
$(proc_headers)
|
||||
|
||||
seaf_server_SOURCES = \
|
||||
@ -65,6 +71,10 @@ seaf_server_SOURCES = \
|
||||
size-sched.c \
|
||||
virtual-repo.c \
|
||||
copy-mgr.c \
|
||||
http-server.c \
|
||||
upload-file.c \
|
||||
access-file.c \
|
||||
pack-dir.c \
|
||||
monitor-rpc-wrappers.c ../common/seaf-db.c \
|
||||
../common/branch-mgr.c ../common/fs-mgr.c \
|
||||
repo-mgr.c ../common/commit-mgr.c \
|
||||
@ -105,8 +115,9 @@ seaf_server_SOURCES = \
|
||||
seaf_server_LDADD = @CCNET_LIBS@ \
|
||||
$(top_builddir)/lib/libseafile_common.la \
|
||||
$(top_builddir)/common/index/libindex.la \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ -levhtp -levent_openssl \
|
||||
$(top_builddir)/common/cdc/libcdc.la \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ @ZDB_LIBS@ @CURL_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \
|
||||
@LIBARCHIVE_LIBS@
|
||||
|
||||
seaf_server_LDFLAGS = @STATIC_COMPILE@ @SERVER_PKG_RPATH@
|
||||
|
@ -21,12 +21,10 @@
|
||||
|
||||
#include "seafile-object.h"
|
||||
#include "seafile-crypt.h"
|
||||
#include "seafile.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "fileserver.h"
|
||||
#include "access-file.h"
|
||||
#include "pack-dir.h"
|
||||
|
||||
@ -618,7 +616,7 @@ do_dir (evhtp_request_t *req, SeafRepo *repo, const char *dir_id,
|
||||
dir_size = seaf_fs_manager_get_fs_size (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
dir_id);
|
||||
if (dir_size < 0 || dir_size > seaf->max_download_dir_size) {
|
||||
if (dir_size < 0 || dir_size > seaf->http_server->max_download_dir_size) {
|
||||
seaf_warning ("invalid dir size: %"G_GINT64_FORMAT"\n", dir_size);
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -745,7 +743,6 @@ access_cb(evhtp_request_t *req, void *arg)
|
||||
const char *operation = NULL;
|
||||
const char *user = NULL;
|
||||
|
||||
SearpcClient *rpc_client = NULL;
|
||||
GError *err = NULL;
|
||||
char *repo_role = NULL;
|
||||
SeafileCryptKey *key = NULL;
|
||||
@ -762,13 +759,7 @@ access_cb(evhtp_request_t *req, void *arg)
|
||||
token = parts[1];
|
||||
filename = parts[2];
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-rpcserver");
|
||||
|
||||
webaccess = (SeafileWebAccess *) searpc_client_call__object (
|
||||
rpc_client, "seafile_web_query_access_token", SEAFILE_TYPE_WEB_ACCESS,
|
||||
NULL, 1, "string", token);
|
||||
webaccess = seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token);
|
||||
if (!webaccess) {
|
||||
error = "Bad access token";
|
||||
goto bad_req;
|
||||
@ -814,8 +805,8 @@ access_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
if (repo->encrypted) {
|
||||
err = NULL;
|
||||
key = (SeafileCryptKey *) seafile_get_decrypt_key (rpc_client,
|
||||
repo_id, user, &err);
|
||||
key = seaf_passwd_manager_get_decrypt_key (seaf->passwd_mgr,
|
||||
repo_id, user);
|
||||
if (!key) {
|
||||
error = "Repo is encrypted. Please provide password to view it.";
|
||||
goto bad_req;
|
||||
@ -840,8 +831,6 @@ access_cb(evhtp_request_t *req, void *arg)
|
||||
}
|
||||
|
||||
success:
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
g_strfreev (parts);
|
||||
if (repo != NULL)
|
||||
seaf_repo_unref (repo);
|
||||
@ -862,10 +851,6 @@ bad_req:
|
||||
if (webaccess != NULL)
|
||||
g_object_unref (webaccess);
|
||||
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
seaf_warning ("fetch failed: %s\n", error);
|
||||
evbuffer_add_printf(req->buffer_out, "%s\n", error);
|
||||
evhtp_send_reply(req, EVHTP_RES_BADREQ);
|
||||
}
|
||||
@ -975,7 +960,6 @@ access_blks_cb(evhtp_request_t *req, void *arg)
|
||||
const char *id = NULL;
|
||||
const char *operation = NULL;
|
||||
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *repo_role = NULL;
|
||||
SeafileWebAccess *webaccess = NULL;
|
||||
|
||||
@ -990,13 +974,7 @@ access_blks_cb(evhtp_request_t *req, void *arg)
|
||||
token = parts[1];
|
||||
blkid = parts[2];
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-rpcserver");
|
||||
|
||||
webaccess = (SeafileWebAccess *) searpc_client_call__object (
|
||||
rpc_client, "seafile_web_query_access_token", SEAFILE_TYPE_WEB_ACCESS,
|
||||
NULL, 1, "string", token);
|
||||
webaccess = seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token);
|
||||
if (!webaccess) {
|
||||
error = "Bad access token";
|
||||
goto bad_req;
|
||||
@ -1053,8 +1031,6 @@ access_blks_cb(evhtp_request_t *req, void *arg)
|
||||
}
|
||||
|
||||
success:
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
g_strfreev (parts);
|
||||
if (repo != NULL)
|
||||
seaf_repo_unref (repo);
|
||||
@ -1071,10 +1047,6 @@ bad_req:
|
||||
if (webaccess != NULL)
|
||||
g_object_unref (webaccess);
|
||||
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
seaf_warning ("fetch failed: %s\n", error);
|
||||
evbuffer_add_printf(req->buffer_out, "%s\n", error);
|
||||
evhtp_send_reply(req, EVHTP_RES_BADREQ);
|
||||
}
|
1511
server/http-server.c
Normal file
1511
server/http-server.c
Normal file
File diff suppressed because it is too large
Load Diff
46
server/http-server.h
Normal file
46
server/http-server.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef HTTP_SERVER_H
|
||||
#define HTTP_SERVER_H
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <event2/event.h>
|
||||
#else
|
||||
#include <event.h>
|
||||
#endif
|
||||
|
||||
#include <evhtp.h>
|
||||
|
||||
|
||||
struct _SeafileSession;
|
||||
|
||||
typedef struct HttpServer {
|
||||
char *bind_addr;
|
||||
int bind_port;
|
||||
evbase_t *evbase;
|
||||
evhtp_t *evhtp;
|
||||
pthread_t thread_id;
|
||||
|
||||
GHashTable *token_cache;
|
||||
pthread_mutex_t token_cache_lock; /* token -> username */
|
||||
|
||||
GHashTable *perm_cache;
|
||||
pthread_mutex_t perm_cache_lock; /* repo_id:username -> permission */
|
||||
|
||||
event_t *reap_timer;
|
||||
|
||||
struct _SeafileSession *seaf_session;
|
||||
|
||||
char *http_temp_dir; /* temp dir for file upload */
|
||||
char *windows_encoding;
|
||||
gint64 max_upload_size;
|
||||
gint64 max_download_dir_size;
|
||||
} HttpServer;
|
||||
|
||||
HttpServer *
|
||||
seaf_http_server_new (struct _SeafileSession *session);
|
||||
|
||||
void seaf_http_server_release (HttpServer *htp_server);
|
||||
|
||||
int
|
||||
seaf_http_server_start (HttpServer *htp_server);
|
||||
|
||||
#endif
|
12
server/http-status-codes.h
Normal file
12
server/http-status-codes.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef HTTP_STATUS_CODES_H
|
||||
#define HTTP_STATUS_CODES_H
|
||||
|
||||
/* Seafile specific http status codes. */
|
||||
|
||||
#define SEAF_HTTP_RES_BADFILENAME 440
|
||||
#define SEAF_HTTP_RES_EXISTS 441
|
||||
#define SEAF_HTTP_RES_NOT_EXISTS 441
|
||||
#define SEAF_HTTP_RES_TOOLARGE 442
|
||||
#define SEAF_HTTP_RES_NOQUOTA 443
|
||||
|
||||
#endif
|
@ -12,7 +12,6 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "fileserver.h"
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
@ -103,10 +102,13 @@ add_file_to_archive (PackDirData *data,
|
||||
entry = archive_entry_new ();
|
||||
|
||||
/* File name fixup for WinRAR */
|
||||
if (is_windows && seaf->windows_encoding) {
|
||||
char *win_file_name = do_iconv ("UTF-8", seaf->windows_encoding, pathname);
|
||||
if (is_windows && seaf->http_server->windows_encoding) {
|
||||
char *win_file_name = do_iconv ("UTF-8",
|
||||
seaf->http_server->windows_encoding,
|
||||
pathname);
|
||||
if (!win_file_name) {
|
||||
seaf_warning ("Failed to convert file name to %s\n", seaf->windows_encoding);
|
||||
seaf_warning ("Failed to convert file name to %s\n",
|
||||
seaf->http_server->windows_encoding);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
@ -1061,7 +1061,8 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr,
|
||||
|
||||
seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL);
|
||||
|
||||
*ret_json = format_json_ret (name_list, id_list);
|
||||
if (ret_json)
|
||||
*ret_json = format_json_ret (name_list, id_list);
|
||||
|
||||
out:
|
||||
if (repo)
|
||||
@ -2775,7 +2776,8 @@ seaf_repo_manager_put_file (SeafRepoManager *mgr,
|
||||
fullpath, NULL, NULL);
|
||||
|
||||
if (g_strcmp0(old_file_id, new_dent->id) == 0) {
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
if (new_file_id)
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2795,7 +2797,8 @@ seaf_repo_manager_put_file (SeafRepoManager *mgr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
if (new_file_id)
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
|
||||
seaf_repo_manager_merge_virtual_repo (mgr, repo_id, NULL);
|
||||
|
||||
@ -3024,7 +3027,8 @@ seaf_repo_manager_put_file_blocks (SeafRepoManager *mgr,
|
||||
fullpath, NULL, NULL);
|
||||
|
||||
if (g_strcmp0(old_file_id, new_dent->id) == 0) {
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
if (new_file_id)
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -3044,7 +3048,8 @@ seaf_repo_manager_put_file_blocks (SeafRepoManager *mgr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
if (new_file_id)
|
||||
*new_file_id = g_strdup(new_dent->id);
|
||||
|
||||
out:
|
||||
if (repo)
|
||||
|
@ -151,6 +151,10 @@ seafile_session_new(const char *seafile_dir,
|
||||
if (!session->mq_mgr)
|
||||
goto onerror;
|
||||
|
||||
session->http_server = seaf_http_server_new (session);
|
||||
if (!session->http_server)
|
||||
goto onerror;
|
||||
|
||||
return session;
|
||||
|
||||
onerror:
|
||||
@ -234,6 +238,11 @@ seafile_session_start (SeafileSession *session)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (seaf_http_server_start (session->http_server) < 0) {
|
||||
g_error ("Failed to start http server thread.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include "mq-mgr.h"
|
||||
|
||||
#include "http-server.h"
|
||||
|
||||
#include <searpc-client.h>
|
||||
|
||||
struct _CcnetClient;
|
||||
@ -81,6 +83,8 @@ struct _SeafileSession {
|
||||
|
||||
int rpc_thread_pool_size;
|
||||
int sync_thread_pool_size;
|
||||
|
||||
HttpServer *http_server;
|
||||
};
|
||||
|
||||
extern SeafileSession *seaf;
|
||||
|
@ -18,23 +18,13 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <ccnet.h>
|
||||
|
||||
#include "seafile-object.h"
|
||||
#include "seafile.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "seafile-session.h"
|
||||
#include "fileserver.h"
|
||||
#include "upload-file.h"
|
||||
|
||||
|
||||
#define SEAF_HTTP_RES_BADFILENAME 440
|
||||
#define SEAF_HTTP_RES_EXISTS 441
|
||||
#define SEAF_HTTP_RES_NOT_EXISTS 441
|
||||
#define SEAF_HTTP_RES_TOOLARGE 442
|
||||
#define SEAF_HTTP_RES_NOQUOTA 443
|
||||
#include "http-status-codes.h"
|
||||
|
||||
enum RecvState {
|
||||
RECV_INIT,
|
||||
@ -84,6 +74,8 @@ typedef struct RecvFSM {
|
||||
|
||||
#define MAX_CONTENT_LINE 10240
|
||||
|
||||
#define POST_FILE_ERR_FILENAME 401
|
||||
|
||||
static GHashTable *upload_progress;
|
||||
static pthread_mutex_t pg_lock;
|
||||
|
||||
@ -221,7 +213,8 @@ check_tmp_file_list (GList *tmp_files, int *error_code)
|
||||
total_size += (gint64)st.st_size;
|
||||
}
|
||||
|
||||
if (seaf->max_upload_size != -1 && total_size > seaf->max_upload_size) {
|
||||
if (seaf->http_server->max_upload_size != -1 &&
|
||||
total_size > seaf->http_server->max_upload_size) {
|
||||
seaf_warning ("[upload] File size is too large.\n");
|
||||
*error_code = ERROR_SIZE;
|
||||
return FALSE;
|
||||
@ -258,7 +251,6 @@ static void
|
||||
upload_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *parent_dir;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
@ -291,12 +283,7 @@ upload_cb(evhtp_request_t *req, void *arg)
|
||||
if (!check_tmp_file_list (fsm->files, &error_code))
|
||||
goto error;
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[upload] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
@ -304,36 +291,33 @@ upload_cb(evhtp_request_t *req, void *arg)
|
||||
filenames_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
|
||||
char *ret_json = seafile_post_multi_files (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
0,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
0,
|
||||
NULL,
|
||||
&error);
|
||||
g_free (filenames_json);
|
||||
g_free (tmp_files_json);
|
||||
g_free (ret_json);
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
err_file = g_strdup(error->message);
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
err_file = g_strdup(error->message);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
/* Redirect to repo dir page after upload finishes. */
|
||||
redirect_to_success_page (req, fsm->repo_id, parent_dir);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
redirect_to_upload_error (req, fsm->repo_id, parent_dir,
|
||||
err_file, error_code);
|
||||
g_free (err_file);
|
||||
@ -372,7 +356,6 @@ static void
|
||||
upload_api_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *parent_dir, *replace_str;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
@ -416,12 +399,7 @@ upload_api_cb(evhtp_request_t *req, void *arg)
|
||||
if (!check_tmp_file_list (fsm->files, &error_code))
|
||||
goto error;
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[upload] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
@ -429,27 +407,28 @@ upload_api_cb(evhtp_request_t *req, void *arg)
|
||||
filenames_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
|
||||
char *ret_json = seafile_post_multi_files (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
replace,
|
||||
&error);
|
||||
char *ret_json = NULL;
|
||||
int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
replace,
|
||||
&ret_json,
|
||||
&error);
|
||||
g_free (filenames_json);
|
||||
g_free (tmp_files_json);
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
seaf_warning ("[upload] Bad filename.\n");
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
const char *use_json = evhtp_kv_find (req->uri->query, "ret-json");
|
||||
if (use_json) {
|
||||
evbuffer_add (req->buffer_out, ret_json, strlen(ret_json));
|
||||
@ -466,9 +445,6 @@ upload_api_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -502,7 +478,6 @@ static void
|
||||
upload_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *parent_dir, *file_name, *size_str, *replace_str;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
@ -544,12 +519,7 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
if (!check_tmp_file_list (fsm->files, &error_code))
|
||||
goto error;
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[upload-blks] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
@ -557,29 +527,30 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
blockids_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
|
||||
char *new_file_ids = seafile_post_file_blocks (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
file_name,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
file_size,
|
||||
replace,
|
||||
&error);
|
||||
char *new_file_ids = NULL;
|
||||
int rc = seaf_repo_manager_post_file_blocks (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
file_name,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
file_size,
|
||||
replace,
|
||||
&new_file_ids,
|
||||
&error);
|
||||
g_free (blockids_json);
|
||||
g_free (tmp_files_json);
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
seaf_warning ("[upload-blks] Bad filename.\n");
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
evbuffer_add (req->buffer_out, new_file_ids, strlen(new_file_ids));
|
||||
g_free (new_file_ids);
|
||||
set_content_length_header (req);
|
||||
@ -587,9 +558,6 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -623,7 +591,6 @@ static void
|
||||
upload_blks_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *parent_dir, *file_name, *size_str;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
@ -679,12 +646,7 @@ upload_blks_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
if (!check_tmp_file_list (fsm->files, &error_code))
|
||||
goto error;
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[upload-blks] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
@ -692,38 +654,34 @@ upload_blks_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
blockids_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
|
||||
char *new_file_ids = seafile_post_file_blocks (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
file_name,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
file_size,
|
||||
0,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_post_file_blocks (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
file_name,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
file_size,
|
||||
0,
|
||||
NULL,
|
||||
&error);
|
||||
g_free (blockids_json);
|
||||
g_free (tmp_files_json);
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
seaf_warning ("[upload-blks] Bad filename.\n");
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_free (new_file_ids);
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
set_content_length_header (req);
|
||||
evhtp_send_reply (req, EVHTP_RES_OK);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "{\"error\": \"Invalid filename.\"}");
|
||||
@ -761,7 +719,6 @@ static void
|
||||
upload_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *parent_dir;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
@ -820,12 +777,7 @@ upload_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
if (!check_tmp_file_list (fsm->files, &error_code))
|
||||
goto error;
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[upload] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
@ -833,27 +785,28 @@ upload_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
filenames_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
|
||||
char *ret_json = seafile_post_multi_files (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
0,
|
||||
&error);
|
||||
char *ret_json = NULL;
|
||||
int rc = seaf_repo_manager_post_multi_files (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filenames_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
0,
|
||||
&ret_json,
|
||||
&error);
|
||||
g_free (filenames_json);
|
||||
g_free (tmp_files_json);
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
seaf_warning ("[upload] Bad filename.\n");
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (error->code == POST_FILE_ERR_FILENAME) {
|
||||
error_code = ERROR_FILENAME;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
evbuffer_add (req->buffer_out, ret_json, strlen(ret_json));
|
||||
g_free (ret_json);
|
||||
|
||||
@ -862,9 +815,6 @@ upload_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "{\"error\": \"Invalid filename.\"}");
|
||||
@ -898,7 +848,6 @@ static void
|
||||
update_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *target_file, *parent_dir = NULL, *filename = NULL;
|
||||
const char *head_id = NULL;
|
||||
GError *error = NULL;
|
||||
@ -931,37 +880,30 @@ update_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
head_id = evhtp_kv_find (req->uri->query, "head");
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[update] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
|
||||
char *new_file_id = seafile_put_file (rpc_client,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
&error);
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
int rc = seaf_repo_manager_put_file (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
NULL,
|
||||
&error);
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (error->message)
|
||||
seaf_warning ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_free (new_file_id);
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
/* Redirect to repo dir page after upload finishes. */
|
||||
redirect_to_success_page (req, fsm->repo_id, parent_dir);
|
||||
g_free (parent_dir);
|
||||
@ -969,9 +911,6 @@ update_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
redirect_to_update_error (req, fsm->repo_id, target_file, error_code);
|
||||
g_free (parent_dir);
|
||||
g_free (filename);
|
||||
@ -981,7 +920,6 @@ static void
|
||||
update_api_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *target_file, *parent_dir = NULL, *filename = NULL;
|
||||
const char *head_id = NULL;
|
||||
GError *error = NULL;
|
||||
@ -1015,38 +953,33 @@ update_api_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
head_id = evhtp_kv_find (req->uri->query, "head");
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[update] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
|
||||
new_file_id = seafile_put_file (rpc_client,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_put_file (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
&new_file_id,
|
||||
&error);
|
||||
g_free (parent_dir);
|
||||
g_free (filename);
|
||||
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (error->message)
|
||||
seaf_warning ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
/* Send back the new file id, so that the mobile client can update local cache */
|
||||
evbuffer_add(req->buffer_out, new_file_id, strlen(new_file_id));
|
||||
set_content_length_header (req);
|
||||
@ -1056,9 +989,6 @@ update_api_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -1098,7 +1028,6 @@ static void
|
||||
update_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *target_file, *parent_dir = NULL, *filename = NULL, *size_str = NULL;
|
||||
const char *head_id = NULL;
|
||||
GError *error = NULL;
|
||||
@ -1128,44 +1057,39 @@ update_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
head_id = evhtp_kv_find (req->uri->query, "head");
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[update-blks] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
|
||||
blockids_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
new_file_id = seafile_put_file_blocks (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filename,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
head_id,
|
||||
file_size,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_put_file_blocks (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filename,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
head_id,
|
||||
file_size,
|
||||
&new_file_id,
|
||||
&error);
|
||||
g_free (blockids_json);
|
||||
g_free (tmp_files_json);
|
||||
g_free (parent_dir);
|
||||
g_free (filename);
|
||||
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (error->message)
|
||||
seaf_warning ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
/* Send back the new file id, so that the mobile client can update local cache */
|
||||
evbuffer_add(req->buffer_out, new_file_id, strlen(new_file_id));
|
||||
set_content_length_header (req);
|
||||
@ -1175,9 +1099,6 @@ update_blks_api_cb(evhtp_request_t *req, void *arg)
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -1217,12 +1138,10 @@ static void
|
||||
update_blks_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *target_file, *parent_dir = NULL, *filename = NULL, *size_str = NULL;
|
||||
const char *head_id = NULL;
|
||||
GError *error = NULL;
|
||||
int error_code = ERROR_INTERNAL;
|
||||
char *new_file_id = NULL;
|
||||
char *blockids_json, *tmp_files_json;
|
||||
gint64 file_size = -1;
|
||||
|
||||
@ -1273,55 +1192,45 @@ update_blks_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
head_id = evhtp_kv_find (req->uri->query, "head");
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[update-blks] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
|
||||
blockids_json = file_list_to_json (fsm->filenames);
|
||||
tmp_files_json = file_list_to_json (fsm->files);
|
||||
new_file_id = seafile_put_file_blocks (rpc_client,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filename,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
head_id,
|
||||
file_size,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_put_file_blocks (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
parent_dir,
|
||||
filename,
|
||||
blockids_json,
|
||||
tmp_files_json,
|
||||
fsm->user,
|
||||
head_id,
|
||||
file_size,
|
||||
NULL,
|
||||
&error);
|
||||
g_free (blockids_json);
|
||||
g_free (tmp_files_json);
|
||||
g_free (parent_dir);
|
||||
g_free (filename);
|
||||
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (error->message)
|
||||
seaf_warning ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
set_content_length_header (req);
|
||||
evhtp_send_reply (req, EVHTP_RES_OK);
|
||||
|
||||
g_free (new_file_id);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -1361,7 +1270,6 @@ static void
|
||||
update_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
{
|
||||
RecvFSM *fsm = arg;
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *target_file, *parent_dir = NULL, *filename = NULL;
|
||||
const char *head_id = NULL;
|
||||
GError *error = NULL;
|
||||
@ -1421,39 +1329,33 @@ update_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
|
||||
head_id = evhtp_kv_find (req->uri->query, "head");
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-threaded-rpcserver");
|
||||
|
||||
if (seafile_check_quota (rpc_client, fsm->repo_id, NULL) < 0) {
|
||||
seaf_warning ("[update] Out of quota.\n");
|
||||
if (seaf_quota_manager_check_quota (seaf->quota_mgr, fsm->repo_id) < 0) {
|
||||
error_code = ERROR_QUOTA;
|
||||
goto error;
|
||||
}
|
||||
|
||||
new_file_id = seafile_put_file (rpc_client,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
&error);
|
||||
int rc = seaf_repo_manager_put_file (seaf->repo_mgr,
|
||||
fsm->repo_id,
|
||||
(char *)(fsm->files->data),
|
||||
parent_dir,
|
||||
filename,
|
||||
fsm->user,
|
||||
head_id,
|
||||
NULL,
|
||||
&error);
|
||||
g_free (parent_dir);
|
||||
g_free (filename);
|
||||
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
if (rc < 0) {
|
||||
if (error) {
|
||||
if (g_strcmp0 (error->message, "file does not exist") == 0) {
|
||||
error_code = ERROR_NOT_EXIST;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (error->message)
|
||||
seaf_warning ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
GString *res_buf = g_string_new (NULL);
|
||||
GList *ptr;
|
||||
|
||||
@ -1473,13 +1375,9 @@ update_ajax_cb(evhtp_request_t *req, void *arg)
|
||||
set_content_length_header (req);
|
||||
evhtp_send_reply (req, EVHTP_RES_OK);
|
||||
|
||||
g_free (new_file_id);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_FILENAME:
|
||||
evbuffer_add_printf(req->buffer_out, "Invalid filename.\n");
|
||||
@ -1644,7 +1542,7 @@ open_temp_file (RecvFSM *fsm)
|
||||
GString *temp_file = g_string_new (NULL);
|
||||
|
||||
g_string_printf (temp_file, "%s/%sXXXXXX",
|
||||
seaf->http_temp_dir, get_basename(fsm->file_name));
|
||||
seaf->http_server->http_temp_dir, get_basename(fsm->file_name));
|
||||
|
||||
fsm->fd = g_mkstemp (temp_file->str);
|
||||
if (fsm->fd < 0) {
|
||||
@ -1957,15 +1855,14 @@ get_boundary (evhtp_headers_t *hdr)
|
||||
}
|
||||
|
||||
static int
|
||||
check_access_token (SearpcClient *rpc,
|
||||
const char *token,
|
||||
check_access_token (const char *token,
|
||||
char **repo_id,
|
||||
char **user)
|
||||
{
|
||||
SeafileWebAccess *webaccess;
|
||||
|
||||
webaccess = (SeafileWebAccess *)
|
||||
seafile_web_query_access_token (rpc, token, NULL);
|
||||
seaf_web_at_manager_query_access_token (seaf->web_at_mgr, token);
|
||||
if (!webaccess)
|
||||
return -1;
|
||||
|
||||
@ -2005,7 +1902,6 @@ get_progress_info (evhtp_request_t *req,
|
||||
static evhtp_res
|
||||
upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
|
||||
{
|
||||
SearpcClient *rpc_client = NULL;
|
||||
char *token, *repo_id = NULL, *user = NULL;
|
||||
char *boundary = NULL;
|
||||
gint64 content_len;
|
||||
@ -2026,12 +1922,7 @@ upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
|
||||
goto err;
|
||||
}
|
||||
|
||||
rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
|
||||
NULL,
|
||||
"seafserv-rpcserver");
|
||||
|
||||
if (check_access_token (rpc_client, token, &repo_id, &user) < 0) {
|
||||
seaf_warning ("[upload] Invalid token.\n");
|
||||
if (check_access_token (token, &repo_id, &user) < 0) {
|
||||
err_msg = "Access denied";
|
||||
goto err;
|
||||
}
|
||||
@ -2079,8 +1970,6 @@ upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
|
||||
/* Set arg for upload_cb or update_cb. */
|
||||
req->cbarg = fsm;
|
||||
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
return EVHTP_RES_OK;
|
||||
|
||||
err:
|
||||
@ -2096,9 +1985,6 @@ err:
|
||||
set_content_length_header (req);
|
||||
evhtp_send_reply (req, EVHTP_RES_BADREQ);
|
||||
|
||||
if (rpc_client)
|
||||
ccnet_rpc_client_free (rpc_client);
|
||||
|
||||
g_free (repo_id);
|
||||
g_free (user);
|
||||
g_free (boundary);
|
||||
@ -2152,13 +2038,14 @@ upload_progress_cb(evhtp_request_t *req, void *arg)
|
||||
}
|
||||
|
||||
int
|
||||
upload_file_init (evhtp_t *htp)
|
||||
upload_file_init (HttpServer *http_server)
|
||||
{
|
||||
evhtp_t *htp = http_server->evhtp;
|
||||
evhtp_callback_t *cb;
|
||||
|
||||
if (g_mkdir_with_parents (seaf->http_temp_dir, 0777) < 0) {
|
||||
if (g_mkdir_with_parents (http_server->http_temp_dir, 0777) < 0) {
|
||||
seaf_warning ("Failed to create temp file dir %s.\n",
|
||||
seaf->http_temp_dir);
|
||||
http_server->http_temp_dir);
|
||||
return -1;
|
||||
}
|
||||
|
9
server/upload-file.h
Normal file
9
server/upload-file.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef UPLOAD_FILE_H
|
||||
#define UPLOAD_FILE_H
|
||||
|
||||
struct HttpServer;
|
||||
|
||||
int
|
||||
upload_file_init (struct HttpServer *http_server);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user