aboutsummaryrefslogtreecommitdiff
path: root/src/cli
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2022-06-06 22:03:57 +0200
committerJan200101 <sentrycraft123@gmail.com>2022-06-08 20:06:12 +0200
commitd5d61d18c89af3f6743b7c56774eebdfdcc87b2c (patch)
treeb4299c1af7e194e9083d4de1bce382102ea46e95 /src/cli
downloadOFQT-d5d61d18c89af3f6743b7c56774eebdfdcc87b2c.tar.gz
OFQT-d5d61d18c89af3f6743b7c56774eebdfdcc87b2c.zip
Release 0.1.00.1.0
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/CMakeLists.txt12
-rw-r--r--src/cli/commands.c242
-rw-r--r--src/cli/commands.h15
-rw-r--r--src/cli/main.c50
-rw-r--r--src/cli/updater.c143
-rw-r--r--src/cli/updater.h6
6 files changed, 468 insertions, 0 deletions
diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt
new file mode 100644
index 0000000..fc46a42
--- /dev/null
+++ b/src/cli/CMakeLists.txt
@@ -0,0 +1,12 @@
+SET(FRONTEND_NAME "OFCL")
+
+SET(CLI_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/commands.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/commands.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/updater.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/updater.h
+)
+
+add_executable(${FRONTEND_NAME} ${CLI_SOURCES})
+target_link_libraries(${FRONTEND_NAME} PRIVATE libofqt)
diff --git a/src/cli/commands.c b/src/cli/commands.c
new file mode 100644
index 0000000..4bac2f7
--- /dev/null
+++ b/src/cli/commands.c
@@ -0,0 +1,242 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "steam.h"
+#include "toast.h"
+
+#include "commands.h"
+#include "updater.h"
+
+#define ARRAY_LEN(arr) sizeof(arr) / sizeof(arr[0])
+
+static int install(int, char**);
+static int update(int, char**);
+static int run(int, char**);
+static int info(int, char**);
+
+const struct Command commands[] = {
+ { .name = "install", .func = install, .description = "Install OpenFortress"},
+ { .name = "update", .func = update, .description = "Update an existing install"},
+ { .name = "run", .func = run, .description = "Run OpenFortress"},
+ { .name = "info", .func = info, .description = "Show info about the current setup"},
+};
+const size_t commands_size = ARRAY_LEN(commands);
+
+static int install(int c, char** v)
+{
+ int exit_val = EXIT_SUCCESS;
+ char* of_dir = NULL;
+ char* remote = NULL;
+ for (int i = 1; i < c; ++i)
+ {
+ if (!strcmp(v[i], "--dir"))
+ {
+ if (!v[++i])
+ {
+ puts("No Directory specified");
+ return EXIT_FAILURE;
+ }
+ of_dir = strdup(v[i]);
+ printf("Using %s as the directory\n", of_dir);
+ }
+ else if (!strcmp(v[i], "--remote"))
+ {
+ if (!v[++i])
+ {
+ puts("No URL specified");
+ return EXIT_FAILURE;
+ }
+ remote = strdup(v[i]);
+ printf("Using %s as the server\n", remote);
+ }
+ else
+ {
+ if (strcmp(v[i], "--help"))
+ printf("%s is not a valid flag\n\n", v[i]);
+
+ puts(
+ "OFCL install\n"
+ "\t--dir\t\tspecify where to download OpenFortress to\n"
+ "\t--remote\tspecify the server to use\n"
+ "\t--help\t\tshows this text"
+ );
+ return EXIT_FAILURE;
+ }
+ }
+ if (!of_dir)
+ of_dir = getOpenFortressDir();
+
+ if (getLocalRevision(of_dir) >= 0)
+ {
+ puts("OpenFortress is already installed");
+ exit_val = EXIT_FAILURE;
+ goto install_cleanup;
+ }
+
+ if (!remote)
+ remote = getLocalRemote(of_dir);
+
+ int remote_rev = getLatestRemoteRevision(remote);
+
+ if (remote_rev != -1)
+ {
+ update_setup(of_dir, remote, 0, remote_rev);
+ }
+ else
+ {
+ puts("Failed to get the latest revision");
+ exit_val = EXIT_FAILURE;
+ }
+
+ install_cleanup:
+ if (remote)
+ free(remote);
+ free(of_dir);
+
+ return exit_val;
+}
+
+static int update(int c, char** v)
+{
+ int exit_val = EXIT_SUCCESS;
+ int force = 0;
+ char* of_dir = NULL;
+ char* remote = NULL;
+ for (int i = 1; i < c; ++i)
+ {
+ if (!strcmp(v[i], "--force"))
+ force = 1;
+ else if (!strcmp(v[i], "--dir"))
+ {
+ if (!v[++i])
+ {
+ puts("No Directory specified");
+ return EXIT_FAILURE;
+ }
+ of_dir = strdup(v[i]);
+ printf("Using %s as the directory\n", of_dir);
+ }
+ else if (!strcmp(v[i], "--remote"))
+ {
+ if (!v[++i])
+ {
+ puts("No URL specified");
+ return EXIT_FAILURE;
+ }
+ remote = strdup(v[i]);
+ printf("Using %s as the server\n", remote);
+ }
+ else
+ {
+ if (strcmp(v[i], "--help"))
+ printf("%s is not a valid flag\n\n", v[i]);
+
+ puts(
+ "OFCL update\n"
+ "\t--force\t\tforce update\n"
+ "\t--dir\t\tspecify where to download OpenFortress to\n"
+ "\t--remote\tspecify the server to use\n"
+ "\t--help\t\tshows this text"
+ );
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (!of_dir)
+ of_dir = getOpenFortressDir();
+
+ int local_rev = getLocalRevision(of_dir);
+ if (force)
+ {
+ local_rev = 0;
+ }
+ else if (0 > local_rev)
+ {
+ puts("OpenFortress is not installed");
+ exit_val = EXIT_FAILURE;
+ goto update_cleanup;
+ }
+
+ if (!remote)
+ remote = getLocalRemote(of_dir);
+
+ if (!strlen(remote))
+ {
+ puts("Remote is invalid");
+ exit_val = EXIT_FAILURE;
+ goto update_cleanup;
+ }
+
+ int remote_rev = getLatestRemoteRevision(remote);
+
+ if (remote_rev == -1)
+ {
+ puts("Failed to get the latest revision");
+ exit_val = EXIT_FAILURE;
+ goto update_cleanup;
+ }
+ else if (remote_rev <= local_rev)
+ {
+ puts("Already up to date");
+ goto update_cleanup;
+ }
+
+ update_setup(of_dir, remote, local_rev, remote_rev);
+
+ update_cleanup:
+ if (remote)
+ free(remote);
+ free(of_dir);
+ return exit_val;
+}
+
+static int run(int c, char** v)
+{
+ int exit_val = EXIT_SUCCESS;
+ char* of_dir = getOpenFortressDir();
+
+ int local_rev = getLocalRevision(of_dir);
+ if (0 > local_rev)
+ {
+ puts("OpenFortress is not installed");
+ exit_val = EXIT_FAILURE;
+ goto run_cleanup;
+ }
+
+ if (getSteamPID() == -1)
+ {
+ puts("Steam is not running");
+ exit_val = EXIT_FAILURE;
+ goto run_cleanup;
+ }
+
+ runOpenFortress();
+
+ run_cleanup:
+ free(of_dir);
+ return exit_val;
+}
+
+static int info(int c, char** v)
+{
+ char* of_dir = getOpenFortressDir();
+ if (!of_dir)
+ of_dir = strdup("Not Found");
+ printf("Install Directory:\n\t%s\n", of_dir);
+
+ char* remote = getLocalRemote(of_dir);
+ printf("Server:\n\t%s\n", remote);
+ free(remote);
+
+ int local_rev = getLocalRevision(of_dir);
+ printf("Revision:\t\n");
+ if (local_rev == -1)
+ puts("\tNot installed");
+ else
+ printf("\t%i\n", local_rev);
+
+ free(of_dir);
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/cli/commands.h b/src/cli/commands.h
new file mode 100644
index 0000000..d55edb9
--- /dev/null
+++ b/src/cli/commands.h
@@ -0,0 +1,15 @@
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include <stddef.h>
+
+struct Command {
+ char* name;
+ int (*func)(int, char**);
+ char* description;
+};
+
+extern const struct Command commands[];
+extern const size_t commands_size;
+
+#endif \ No newline at end of file
diff --git a/src/cli/main.c b/src/cli/main.c
new file mode 100644
index 0000000..7971c7d
--- /dev/null
+++ b/src/cli/main.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "net.h"
+#include "commands.h"
+
+static void help()
+{
+ fprintf(stderr, "OFCL <command>\n"); \
+
+ size_t longestStr;
+ size_t length;
+
+ if (commands_size)
+ {
+ longestStr = 0;
+
+ for (size_t i = 0; i < commands_size; ++i)
+ {
+ length = strlen(commands[i].name);
+
+ if (length > longestStr) longestStr = length;
+ }
+
+ fprintf(stderr, "\nList of commands:\n");
+ for (size_t i = 0; i < commands_size; ++i)
+ {
+ fprintf(stderr, "\t%-*s\t %s\n", (int)longestStr, commands[i].name, commands[i].description);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ net_init();
+ atexit(net_deinit);
+
+ for (int i = 1; i < argc; ++i)
+ {
+ for (size_t j = 0; j < commands_size; ++j)
+ {
+ if (!strcmp(commands[j].name, argv[i]))
+ return commands[j].func(argc-i, argv+i);
+ }
+ }
+
+ help();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/src/cli/updater.c b/src/cli/updater.c
new file mode 100644
index 0000000..8b0cc03
--- /dev/null
+++ b/src/cli/updater.c
@@ -0,0 +1,143 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "fs.h"
+#include "toast.h"
+
+#include "updater.h"
+
+#include <assert.h>
+
+#define THREAD_COUNT 8
+
+struct thread_object_info {
+ int working;
+
+ char* of_dir;
+ char* remote;
+ struct revision_t* rev;
+ size_t index;
+};
+
+static void* thread_download(void* pinfo)
+{
+ struct thread_object_info* info = pinfo;
+ if (info)
+ {
+ char* of_dir = info->of_dir;
+ char* remote = info->remote;
+ struct revision_t* rev = info->rev;
+ size_t i = info->index;
+
+ struct file_info* file = &rev->files[i];
+ if (file->type == TYPE_WRITE)
+ {
+ fprintf(stderr, "\rChecking %lu/%lu (%s)", i+1, rev->file_count, file->object);
+
+ if (verifyFileHash(of_dir, file))
+ {
+ fprintf(stderr, "\rDownloading %lu/%lu (%s)", i+1, rev->file_count, file->object);
+ downloadObject(of_dir, remote, file);
+ }
+ }
+ }
+
+ info->working = 0;
+ pthread_exit(0);
+
+ return NULL;
+}
+
+
+void update_setup(char* of_dir, char* remote, int local_rev, int remote_rev)
+{
+ struct revision_t* rev = fastFowardRevisions(remote, local_rev, remote_rev);
+
+ if (rev)
+ {
+ pthread_t download_threads[THREAD_COUNT] = {0};
+ struct thread_object_info thread_info[THREAD_COUNT] = {0};
+ size_t tindex = 0;
+
+ for (size_t i = 0; i < rev->file_count; ++i)
+ {
+ while (thread_info[tindex].working)
+ {
+ tindex = (tindex+1) % THREAD_COUNT;
+ }
+
+ pthread_t* thread = &download_threads[tindex];
+ struct thread_object_info* info = &thread_info[tindex];
+
+ info->working = 1;
+ info->of_dir = of_dir;
+ info->remote = remote;
+ info->rev = rev;
+ info->index = i;
+
+ pthread_create(thread, NULL, thread_download, info);
+ }
+
+ for (size_t i = 0; i < THREAD_COUNT; ++i)
+ {
+ pthread_t* thread = &download_threads[i];
+ if (*thread)
+ pthread_join(*thread, NULL);
+ }
+
+ for (size_t i = 0; i < rev->file_count; ++i)
+ {
+ struct file_info* file = &rev->files[i];
+ if (file->type != TYPE_MKDIR)
+ continue;
+
+ size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1;
+ char* buf = malloc(len);
+ snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path);
+ makeDir(buf);
+ free(buf);
+ }
+
+ fprintf(stderr, "\rInstalling...");
+ for (size_t i = 0; i < rev->file_count; ++i)
+ {
+ struct file_info* file = &rev->files[i];
+
+ switch (file->type)
+ {
+ case TYPE_WRITE:
+ case TYPE_MKDIR:
+ {
+ int k = applyObject(of_dir, file);
+ if (k)
+ {
+ printf("Failed to write %s\n", file->path);
+ }
+ }
+ break;
+
+ case TYPE_DELETE:
+ {
+ size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1;
+ char* buf = malloc(len);
+ snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path);
+ if (isFile(buf) && remove(buf))
+ {
+ printf("Failed to delete %s\n", file->path);
+ }
+ free(buf);
+ }
+ break;
+ }
+ }
+
+ removeObjects(of_dir);
+ setLocalRemote(of_dir, remote);
+ setLocalRevision(of_dir, remote_rev);
+
+ fprintf(stderr, "\rUpdated OpenFortress\n");
+ freeRevision(rev);
+ }
+}
diff --git a/src/cli/updater.h b/src/cli/updater.h
new file mode 100644
index 0000000..71fc751
--- /dev/null
+++ b/src/cli/updater.h
@@ -0,0 +1,6 @@
+#ifndef UPDATER_H
+#define UPDATER_H
+
+void update_setup(char*, char*, int, int);
+
+#endif \ No newline at end of file