From 2051f7714a08aede2bab444f0ed2050c28fb5d6a Mon Sep 17 00:00:00 2001 From: jmjatlanta Date: Thu, 21 Sep 2017 07:51:18 -0500 Subject: [PATCH] ipfs name command line options processing --- cmd/Makefile | 20 ++++- cmd/cli.c | 26 ++++++ commands/cli/parse.c | 20 ++++- core/ipfs_node.c | 9 +- importer/exporter.c | 3 +- include/ipfs/cmd/cli.h | 19 +++++ include/ipfs/cmd/ipfs/init.h | 8 ++ include/ipfs/commands/cli/parse.h | 2 +- include/ipfs/core/ipfs_node.h | 3 +- include/ipfs/namesys/name.h | 11 +++ main/Makefile | 1 + main/main.c | 131 ++++++++++++++++++++++-------- namesys/Makefile | 2 +- namesys/name.c | 65 +++++++++++++++ test/core/test_api.h | 5 +- test/journal/test_journal.h | 2 +- test/namesys/test_publisher.h | 2 +- test/node/test_importer.h | 2 +- 18 files changed, 278 insertions(+), 53 deletions(-) create mode 100644 cmd/cli.c create mode 100644 include/ipfs/cmd/cli.h create mode 100644 include/ipfs/namesys/name.h create mode 100644 namesys/name.c diff --git a/cmd/Makefile b/cmd/Makefile index dd8c1d8..cf0e41a 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -1,5 +1,23 @@ -all: +CC = gcc +CFLAGS = -O0 -I../include -I../../c-libp2p/include -I../../c-multiaddr/include -I../../c-protobuf -Wall + +ifdef DEBUG +CFLAGS += -g3 +endif + +LFLAGS = +DEPS = +OBJS = cli.o + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +ipfs: $(OBJS) + $(CC) -o $@ $^ $(LFLAGS) + +all: $(OBJS) cd ipfs; make all; clean: + rm -f *.o cd ipfs; make clean; \ No newline at end of file diff --git a/cmd/cli.c b/cmd/cli.c new file mode 100644 index 0000000..4d9692d --- /dev/null +++ b/cmd/cli.c @@ -0,0 +1,26 @@ +#include +#include "ipfs/cmd/cli.h" + +int cli_get_verb_index(struct CliArguments* args) { + return 0; +} + +char* cli_get_config_dir(struct CliArguments* args) { + return NULL; +} + + +struct CliArguments* cli_arguments_new(int argc, char** argv) { + struct CliArguments* args = (struct CliArguments*) malloc(sizeof(struct CliArguments)); + if (args != NULL) { + args->argc = argc; + args->argv = argv; + args->verb_index = cli_get_verb_index(args); + args->config_dir = cli_get_config_dir(args); + } + return args; +} + +void cli_arguments_free(struct CliArguments* args) { + free(args); +} diff --git a/commands/cli/parse.c b/commands/cli/parse.c index 050f9b7..73f3577 100644 --- a/commands/cli/parse.c +++ b/commands/cli/parse.c @@ -1,5 +1,23 @@ +#include + +#include "libp2p/utils/logger.h" #include "ipfs/commands/cli/parse.h" -int cli_parse(char** params, FILE* inStream, struct Command* cmd, struct Request* request) { + +/*** + * Parse command line arguments, and place them in a Command struct + * @param argc number of arguments + * @param argv arguments + * @param inStream an incoming stream (not implemented yet) + * @param cmd the Command struct to allocate + * @param request not sure what this is for yet + * @returns true(1) on success, false(0) otherwise + */ +int cli_parse(int argc, char** argv, FILE* inStream, struct Command** cmd, struct Request* request) { + *cmd = (struct Command*) malloc(sizeof(struct Command)); + if (*cmd == NULL) { + libp2p_logger_error("parse", "Unable to allocate memory for the command structure.\n"); + return 0; + } return 0; } diff --git a/core/ipfs_node.c b/core/ipfs_node.c index dc62b98..390779b 100644 --- a/core/ipfs_node.c +++ b/core/ipfs_node.c @@ -95,7 +95,7 @@ int ipfs_node_online_new(pthread_t *pth_scope, const char* repo_path, struct Ipf * @param node the completed IpfsNode struct * @returns true(1) on success */ -int ipfs_node_offline_new(pthread_t *pth_scope, const char* repo_path, struct IpfsNode** node) { +int ipfs_node_offline_new(const char* repo_path, struct IpfsNode** node) { struct FSRepo* fs_repo = NULL; *node = (struct IpfsNode*)malloc(sizeof(struct IpfsNode)); @@ -112,13 +112,13 @@ int ipfs_node_offline_new(pthread_t *pth_scope, const char* repo_path, struct Ip // build the struct if (!ipfs_repo_fsrepo_new(repo_path, NULL, &fs_repo)) { - ipfs_node_free(pth_scope, local_node); + ipfs_node_free(NULL, local_node); *node = NULL; return 0; } // open the repo if (!ipfs_repo_fsrepo_open(fs_repo)) { - ipfs_node_free(pth_scope, local_node); + ipfs_node_free(NULL, local_node); *node = NULL; return 0; } @@ -147,7 +147,8 @@ int ipfs_node_offline_new(pthread_t *pth_scope, const char* repo_path, struct Ip */ int ipfs_node_free(pthread_t *pth_scope, struct IpfsNode* node) { if (node != NULL) { - api_stop(pth_scope); + if (pth_scope != NULL) + api_stop(pth_scope); if (node->exchange != NULL) { node->exchange->Close(node->exchange); } diff --git a/importer/exporter.c b/importer/exporter.c index c883fe0..9b45b17 100644 --- a/importer/exporter.c +++ b/importer/exporter.c @@ -266,14 +266,13 @@ int ipfs_exporter_object_cat_to_file(struct IpfsNode *local_node, unsigned char* int ipfs_exporter_object_cat(int argc, char** argv) { struct IpfsNode *local_node = NULL; char* repo_dir = NULL; - pthread_t api_pth = 0; if (!ipfs_repo_get_directory(argc, argv, &repo_dir)) { fprintf(stderr, "Unable to open repo: %s\n", repo_dir); return 0; } - if (!ipfs_node_offline_new(&api_pth, repo_dir, &local_node)) + if (!ipfs_node_offline_new(repo_dir, &local_node)) return 0; if (local_node->mode == MODE_API_AVAILABLE) { diff --git a/include/ipfs/cmd/cli.h b/include/ipfs/cmd/cli.h new file mode 100644 index 0000000..90d8bd1 --- /dev/null +++ b/include/ipfs/cmd/cli.h @@ -0,0 +1,19 @@ +#pragma once + +/** + * Helps parse the command line. + */ + +/** + * A structure to hold the command line arguments + */ +struct CliArguments { + int argc; + char** argv; + int verb_index; + char* config_dir; +}; + +struct CliArguments* cli_arguments_new(int argc, char** argv); + +void cli_arguments_free(struct CliArguments* args); diff --git a/include/ipfs/cmd/ipfs/init.h b/include/ipfs/cmd/ipfs/init.h index cc2ce98..37bd8b6 100644 --- a/include/ipfs/cmd/ipfs/init.h +++ b/include/ipfs/cmd/ipfs/init.h @@ -20,4 +20,12 @@ int ipfs_cmd_ipfs_init_command_new(struct Command* command); */ int ipfs_cmd_ipfs_init_command_free(struct Command* command); +/*** + * Parse the command line + * @param argc the number of arguments + * @param argv the actual arguments + * @returns a command structure + */ +struct Command* ipfs_cmd_parse_command_line(int argc, char** argv); + #endif diff --git a/include/ipfs/commands/cli/parse.h b/include/ipfs/commands/cli/parse.h index aa90bc6..dbcfc44 100644 --- a/include/ipfs/commands/cli/parse.h +++ b/include/ipfs/commands/cli/parse.h @@ -16,7 +16,7 @@ * @param request the end result, something that can be passed on that actually does something * @returns 0 if something bad happens, otherwise 1 */ -int cli_parse(char** params, FILE* inStream, struct Command* cmd, struct Request* request); +int cli_parse(int argc, char** params, FILE* inStream, struct Command** cmd, struct Request* request); int cli_parse_opts(char** params, struct Command* cmd, char* path, char** stringVals); diff --git a/include/ipfs/core/ipfs_node.h b/include/ipfs/core/ipfs_node.h index 7d99d53..20cd01e 100644 --- a/include/ipfs/core/ipfs_node.h +++ b/include/ipfs/core/ipfs_node.h @@ -1,5 +1,6 @@ #pragma once +#include #include "libp2p/peer/peerstore.h" #include "libp2p/peer/providerstore.h" #include "ipfs/blocks/blockstore.h" @@ -55,7 +56,7 @@ int ipfs_node_online_new(pthread_t *pth_scope, const char* repo_path, struct Ipf * @param node the completed IpfsNode struct * @returns true(1) on success */ -int ipfs_node_offline_new(pthread_t *pth_scope, const char* repo_path, struct IpfsNode** node); +int ipfs_node_offline_new(const char* repo_path, struct IpfsNode** node); /*** * Free resources from the creation of an IpfsNode diff --git a/include/ipfs/namesys/name.h b/include/ipfs/namesys/name.h new file mode 100644 index 0000000..a5e4ec9 --- /dev/null +++ b/include/ipfs/namesys/name.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ipfs/cmd/cli.h" + +/** + * We received a cli command "ipfs name". Do the right thing. + * @param argc number of arguments on the command line + * @param argv actual command line arguments + * @returns true(1) on success, false(0) otherwise + */ +int ipfs_name(struct CliArguments* args); diff --git a/main/Makefile b/main/Makefile index aff6171..47db460 100644 --- a/main/Makefile +++ b/main/Makefile @@ -6,6 +6,7 @@ OBJS = main.o \ ../blocks/block.o ../blocks/blockstore.o \ ../cid/cid.o \ ../cmd/ipfs/init.o \ + ../cmd/*.o \ ../commands/argument.o ../commands/command_option.o ../commands/command.o ../commands/cli/parse.o \ ../core/*.o \ ../datastore/ds_helper.o \ diff --git a/main/main.c b/main/main.c index 2b5a882..81d3505 100644 --- a/main/main.c +++ b/main/main.c @@ -7,6 +7,8 @@ #include "ipfs/importer/exporter.h" #include "ipfs/dnslink/dnslink.h" #include "ipfs/core/daemon.h" +#include "ipfs/cmd/cli.h" +#include "ipfs/namesys/name.h" #ifdef __MINGW32__ void bzero(void *s, size_t n) @@ -59,39 +61,84 @@ void strip_quotes(int argc, char** argv) { #define DAEMON 6 #define PING 7 #define GET 8 +#define NAME 9 + +/** + * Find out if this command line argument is part of a switch + * @param argc the number of arguments + * @param argv the arguments + * @param index the argument to look at + * @returns 0 if not a switch, 1 if it is a regular switch, 2 if the next parameter is also part of the switch + */ +int is_switch(int argc, char** argv, int index) { + char* to_test = argv[index]; + if (to_test[0] == '-') { + if (strcmp(to_test, "-c") == 0 || strcmp(to_test, "--config") == 0) { + return 2; + } + return 1; + } + return 0; +} + +/** + * Find the command line piece that will actually do something + * @param argc the number of command line arguments + * @param argv the actual command line arguments + * @returns the index of the item that does something, or false(0) + */ +int get_cli_verb(int argc, char** argv) { + for(int i = 1; i < argc; i++) { + int advance_by_more_than_one = is_switch(argc, argv, i); + if (advance_by_more_than_one == 0) { + // this is the verb + return i; + } else { + if (advance_by_more_than_one == 2) { + // skip the next one + i++; + } + } + } + return 0; +} /*** * Basic parsing of command line arguments to figure out where the user wants to go */ int parse_arguments(int argc, char** argv) { - if (argc == 1) { - printf("No parameters passed.\n"); + int index = get_cli_verb(argc, argv); + if (argc == 1 || index == 0) { + libp2p_logger_error("main", "No parameters passed.\n"); return 0; } - if (strcmp("init", argv[1]) == 0) { + if (strcmp("init", argv[index]) == 0) { return INIT; } - if (strcmp("add", argv[1]) == 0) { + if (strcmp("add", argv[index]) == 0) { return ADD; } - if (strcmp("object", argv[1]) == 0 && argc > 2 && strcmp("get", argv[2]) == 0) { + if (strcmp("object", argv[index]) == 0 && argc > 2 && strcmp("get", argv[index+1]) == 0) { return OBJECT_GET; } - if (strcmp("cat", argv[1]) == 0) { + if (strcmp("cat", argv[index]) == 0) { return CAT; } - if (strcmp("dns", argv[1]) == 0) { + if (strcmp("dns", argv[index]) == 0) { return DNS; } - if (strcmp("daemon", argv[1]) == 0) { + if (strcmp("daemon", argv[index]) == 0) { return DAEMON; } - if (strcmp("ping", argv[1]) == 0) { + if (strcmp("ping", argv[index]) == 0) { return PING; } - if (strcmp("get", argv[1]) == 0) { + if (strcmp("get", argv[index]) == 0) { return GET; } + if (strcmp("name", argv[index]) == 0) { + return NAME; + } return -1; } @@ -111,32 +158,44 @@ int main(int argc, char** argv) { libp2p_logger_add_class("lmdb_datastore"); strip_quotes(argc, argv); - int retVal = parse_arguments(argc, argv); - switch (retVal) { - case (INIT): - return ipfs_repo_init(argc, argv); - break; - case (ADD): - ipfs_import_files(argc, argv); - break; - case (OBJECT_GET): - ipfs_exporter_object_get(argc, argv); - break; - case(GET): - //ipfs_exporter_get(argc, argv); - //break; - case (CAT): - ipfs_exporter_object_cat(argc, argv); - break; - case (DNS): - ipfs_dns(argc, argv); - break; - case (DAEMON): - ipfs_daemon(argc, argv); - break; - case (PING): - ipfs_ping(argc, argv); - break; + // CliArguments is the new way to do it. Eventually, all will use this structure + struct CliArguments* args = cli_arguments_new(argc, argv); + if (args != NULL) { + // until then, use the old way + int retVal = parse_arguments(argc, argv); + switch (retVal) { + case (INIT): + return ipfs_repo_init(argc, argv); + break; + case (ADD): + ipfs_import_files(argc, argv); + break; + case (OBJECT_GET): + ipfs_exporter_object_get(argc, argv); + break; + case(GET): + //ipfs_exporter_get(argc, argv); + //break; + case (CAT): + ipfs_exporter_object_cat(argc, argv); + break; + case (DNS): + ipfs_dns(argc, argv); + break; + case (DAEMON): + ipfs_daemon(argc, argv); + break; + case (PING): + ipfs_ping(argc, argv); + break; + case (NAME): + ipfs_name(args); + break; + default: + libp2p_logger_error("main", "Invalid command line arguments.\n"); + break; + } + cli_arguments_free(args); } libp2p_logger_free(); } diff --git a/namesys/Makefile b/namesys/Makefile index b46a400..d42674d 100644 --- a/namesys/Makefile +++ b/namesys/Makefile @@ -7,7 +7,7 @@ endif LFLAGS = DEPS = -OBJS = base.o dns.o isdomain.o namesys.o proquint.o publisher.o pb.o +OBJS = base.o dns.o isdomain.o namesys.o proquint.o publisher.o pb.o name.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/namesys/name.c b/namesys/name.c new file mode 100644 index 0000000..44fbdea --- /dev/null +++ b/namesys/name.c @@ -0,0 +1,65 @@ +/** + * Handles the command line options for "ipfs name" + */ +#include +#include "libp2p/utils/logger.h" +#include "ipfs/core/ipfs_node.h" +#include "ipfs/cmd/cli.h" + +/*** + * Publish IPNS name + */ +int ipfs_name_publish(struct IpfsNode* local_node, char* name) { + // call api + return 0; +} + +int ipfs_name_resolve(struct IpfsNode* local_node, char* name) { + // ask api + return 0; +} + +/** + * We received a cli command "ipfs name". Do the right thing. + * @param argc number of arguments on the command line + * @param argv actual command line arguments + * @returns true(1) on success, false(0) otherwise + */ +int ipfs_name(struct CliArguments* args) { + int retVal = 0; + struct IpfsNode* client_node = NULL; + + if (args->argc < (args->verb_index + 2)) { + libp2p_logger_error("name", "Not enough command line arguments. Should be \"name resolve\" or \"name publish\".\n"); + goto exit; + } + + char* which = args->argv[args->verb_index+1]; + char* path = args->argv[args->verb_index+2]; + + // make sure API is running + if (!ipfs_node_offline_new(args->config_dir, &client_node)) { + libp2p_logger_error("name", "Unable to create offline node.\n"); + goto exit; + } + if (client_node->mode != MODE_API_AVAILABLE) { + libp2p_logger_error("name", "API must be running.\n"); + goto exit; + } + + // determine what we're doing + if (strcmp(which, "publish") == 0) { + retVal = ipfs_name_publish(client_node, path); + } else if (strcmp(which, "resolve") == 0) { + retVal = ipfs_name_resolve(client_node, path); + } else { + libp2p_logger_error("name", "Nothing found on command line. Should be \"name resolve\" or \"name publish\".\n"); + goto exit; + } + + exit: + // shut everything down + ipfs_node_free(NULL, client_node); + + return retVal; +} diff --git a/test/core/test_api.h b/test/core/test_api.h index 43442e9..40c298a 100644 --- a/test/core/test_api.h +++ b/test/core/test_api.h @@ -11,7 +11,6 @@ int test_core_api_startup_shutdown() { char* repo_path = "/tmp/ipfs_1/.ipfs"; char* peer_id = NULL; int retVal = 0; - pthread_t api_pth; if (!drop_and_build_repository(repo_path, 4001, NULL, &peer_id)) goto exit; @@ -21,7 +20,7 @@ int test_core_api_startup_shutdown() { sleep(3); struct IpfsNode* client_node = NULL; - if (!ipfs_node_offline_new(&api_pth, repo_path, &client_node)) { + if (!ipfs_node_offline_new(repo_path, &client_node)) { goto exit; } // test to see if it is working @@ -99,7 +98,7 @@ int test_core_api_object_cat() { size_t bytes_written; struct IpfsNode *local_node = NULL; pthread_t api_pth = 0; - ipfs_node_offline_new(&api_pth, ipfs_path1, &local_node); + ipfs_node_offline_new(ipfs_path1, &local_node); ipfs_import_file(NULL, filename, &node, local_node, &bytes_written, 0); memset(hash, 0, 256); ipfs_cid_hash_to_base58(node->hash, node->hash_size, (unsigned char*)hash, 256); diff --git a/test/journal/test_journal.h b/test/journal/test_journal.h index 2a0d5a1..6923e2e 100644 --- a/test/journal/test_journal.h +++ b/test/journal/test_journal.h @@ -120,7 +120,7 @@ int test_journal_server_1() { size_t bytes_written; struct IpfsNode *local_node = NULL; pthread_t api_pth = 0; - ipfs_node_offline_new(&api_pth, ipfs_path, &local_node); + ipfs_node_offline_new(ipfs_path, &local_node); ipfs_import_file(NULL, filename, &node, local_node, &bytes_written, 0); ipfs_node_free(&api_pth, local_node); ipfs_hashtable_node_free(node); diff --git a/test/namesys/test_publisher.h b/test/namesys/test_publisher.h index 98c4f50..39d8e68 100644 --- a/test/namesys/test_publisher.h +++ b/test/namesys/test_publisher.h @@ -14,7 +14,7 @@ int test_namesys_publisher_publish() { pthread_t api_pth = 0; // get a local node - if (!ipfs_node_offline_new(&api_pth, repo_path, &local_node)) { + if (!ipfs_node_offline_new(repo_path, &local_node)) { libp2p_logger_error("test_publisher", "publish: Unable to open ipfs repository.\n"); goto exit; } diff --git a/test/node/test_importer.h b/test/node/test_importer.h index 66ef62a..6f2e0db 100644 --- a/test/node/test_importer.h +++ b/test/node/test_importer.h @@ -157,7 +157,7 @@ int test_import_small_file() { // get the repo drop_and_build_repository(repo_path, 4001, NULL, NULL); - ipfs_node_offline_new(&api_pth, repo_path, &local_node); + ipfs_node_offline_new(repo_path, &local_node); // write to ipfs struct HashtableNode* write_node;