diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/mirror/CMakeLists.txt | 17 | ||||
-rw-r--r-- | src/mirror/main.c | 171 |
3 files changed, 192 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 80a59bb..d993dba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,3 +54,7 @@ endif() if(BUILD_QT) add_subdirectory(qt) endif() + +if (BUILD_MIRROR) + add_subdirectory(mirror) +endif() diff --git a/src/mirror/CMakeLists.txt b/src/mirror/CMakeLists.txt new file mode 100644 index 0000000..6d0b114 --- /dev/null +++ b/src/mirror/CMakeLists.txt @@ -0,0 +1,17 @@ +SET(FRONTEND_NAME "OFmirror") + +if (NOT UNIX) + message(FATAL_ERROR "Mirroring is not supported on Windows") +endif() + +SET(MIRROR_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/main.c +) + +add_executable(${FRONTEND_NAME} ${MIRROR_SOURCES}) +target_include_directories(${FRONTEND_NAME} PUBLIC ${JSONC_INCLUDE_DIRS}) +target_compile_options(${FRONTEND_NAME} PUBLIC ${CFLAGS}) +target_link_libraries(${FRONTEND_NAME} PRIVATE tvn) +target_link_libraries(${FRONTEND_NAME} PRIVATE threading) +target_link_libraries(${FRONTEND_NAME} LINK_PUBLIC ${JSONC_LIBRARIES}) +install(TARGETS ${FRONTEND_NAME}) diff --git a/src/mirror/main.c b/src/mirror/main.c new file mode 100644 index 0000000..a97dea0 --- /dev/null +++ b/src/mirror/main.c @@ -0,0 +1,171 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "toast.h" +#include "fs.h" +#include "pool.h" + +struct thread_object_info { + int i; + size_t j; + + char* output_dir; + char* remote; + struct revision_t* rev; + struct file_info* file; +}; + +static void* thread_download(void* pinfo) +{ + struct thread_object_info* info = pinfo; + if (info) + { + struct file_info* file = info->file; + fprintf(stderr, "\r [%i][%li/%li] Processing %s", info->i, info->j+1, info->rev->file_count, file->object); + + // downloadObject checks if an object with the current hash is already present + downloadObject(info->output_dir, info->remote, info->file); + } + return NULL; +} + +int main(int argc, char** argv) +{ + int retval = 0; + char* remote = NULL; + char* output_dir = NULL; + + for (int i = 1; i < argc; ++i) + { + if (!strcmp(argv[i], "--remote")) + { + if (!argv[++i]) + { + puts("No URL specified"); + return EXIT_FAILURE; + } + remote = strdup(argv[i]); + printf("Using %s as the server\n", remote); + } + else if (!output_dir) + output_dir = strdup(argv[i]); + else + { + + puts("Too many arguments"); + retval = 1; + goto cleanup; + } + } + + if (!output_dir) + { + printf("%s [output_dir]\n", argv[0]); + retval = 1; + goto cleanup; + } + + if (!remote) + remote = getLocalRemote(output_dir); + else + setLocalRemote(output_dir, remote); + + + // symlink objects directory + size_t len = strlen(output_dir) + strlen(OS_PATH_SEP) + strlen(TOAST_LOCAL_OBJECTS) + 1; + char* objects_dir = malloc(len); + snprintf(objects_dir, len, "%s%s%s", output_dir, OS_PATH_SEP, TOAST_LOCAL_OBJECTS); + + if (!isDir(objects_dir)) + { + symlink(TOAST_LOCAL_OBJECTS_PATH, objects_dir); + } + + free(objects_dir); + + + // setup revisions directory and a buffer to put the paths into + len = strlen(output_dir) + strlen(OS_PATH_SEP) + strlen(TOAST_REVISIONS_ENDPOINT) + strlen(OS_PATH_SEP) + strlen("latest") + 1; + char* revisions_dir = malloc(len); + snprintf(revisions_dir, len, "%s%s%s", output_dir, OS_PATH_SEP, TOAST_REVISIONS_ENDPOINT); + char* revisions_dir_end = revisions_dir+strlen(revisions_dir); + + if (!isDir(revisions_dir)) + { + makeDir(revisions_dir); + } + + // download objects + printf("Downloading objects\n"); + int latest_rev = getLatestRemoteRevision(remote); + size_t rev_len = 1; + { + + int rev_copy = latest_rev; + while (rev_copy >= 10) + { + rev_copy /= 10; + rev_len++; + } + } + + for (int i = 0; i <= latest_rev; ++i) + { + fprintf(stderr, "\r [%i] Downloading", i); + sprintf(revisions_dir_end, "%s%i", OS_PATH_SEP, i); + + len = strlen(remote) + 1 + strlen(TOAST_REVISIONS_ENDPOINT) + 1 + rev_len + 1; + char* buf = malloc(len); + snprintf(buf, len, "%s/%s/%i", remote, TOAST_REVISIONS_ENDPOINT, i); + downloadToFile(buf, revisions_dir); + free(buf); + + struct revision_t* rev = getRevisionData(remote, i); + struct thread_object_info* thread_info = malloc(sizeof(struct thread_object_info) * rev->file_count); + struct pool_t* pool = pool_init(); + + fprintf(stderr, "\r [%i] Preparing ", i); + for (size_t j = 0; j < rev->file_count; ++j) + { + struct file_info* file = &rev->files[j]; + + if (file->object) + { + struct thread_object_info* info = &thread_info[j]; + info->i = i; + info->j = j; + info->output_dir = output_dir; + info->remote = remote; + info->rev = rev; + info->file = file; + + pool_submit(pool, thread_download, info); + } + } + pool_complete(pool); + printf("\n"); + pool_free(pool); + freeRevision(rev); + free(thread_info); + } + + char* buf = malloc(rev_len+1); + sprintf(buf, "%i", latest_rev); + sprintf(revisions_dir_end, "%slatest", OS_PATH_SEP); + + symlink(buf, revisions_dir); + + free(buf); + free(revisions_dir); + + cleanup: + + if (remote) + free(remote); + if (output_dir) + free(output_dir); + + return retval; +}
\ No newline at end of file |