Skip to content

Commit 951832b

Browse files
committed
feat: update endpoints to use databaseMangedId for /v2/cloudsync api
1 parent f8469b4 commit 951832b

File tree

4 files changed

+69
-126
lines changed

4 files changed

+69
-126
lines changed

src/cloudsync.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
extern "C" {
1818
#endif
1919

20-
#define CLOUDSYNC_VERSION "0.9.117"
20+
#define CLOUDSYNC_VERSION "0.9.118"
2121
#define CLOUDSYNC_MAX_TABLENAME_LEN 512
2222

2323
#define CLOUDSYNC_VALUE_NOTSET -1

src/network.c

Lines changed: 66 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -600,120 +600,60 @@ int network_extract_query_param (const char *query, const char *key, char *outpu
600600
return -3; // Key not found
601601
}
602602

603-
bool network_compute_endpoints (sqlite3_context *context, network_data *data, const char *conn_string) {
604-
// JSON format: {"address":"https://host:port","database":"db.sqlite","projectID":"abc","organizationID":"org","apikey":"KEY"}
605-
bool result = false;
606-
size_t conn_len = strlen(conn_string);
607-
608-
char *address = json_extract_string(conn_string, conn_len, "address");
609-
char *database = json_extract_string(conn_string, conn_len, "database");
610-
char *project_id = json_extract_string(conn_string, conn_len, "projectID");
611-
char *org_id = json_extract_string(conn_string, conn_len, "organizationID");
612-
char *apikey = json_extract_string(conn_string, conn_len, "apikey");
613-
char *token = json_extract_string(conn_string, conn_len, "token");
614-
615-
char *authentication = NULL;
616-
char *check_endpoint = NULL;
617-
char *upload_endpoint = NULL;
618-
char *apply_endpoint = NULL;
619-
char *status_endpoint = NULL;
620-
621-
// validate mandatory fields
622-
if (!address || !database || !project_id || !org_id) {
623-
sqlite3_result_error(context, "JSON must contain address, database, projectID, and organizationID", -1);
603+
static bool network_compute_endpoints_with_address (sqlite3_context *context, network_data *data, const char *address, const char *managedDatabaseId) {
604+
if (!managedDatabaseId || managedDatabaseId[0] == '\0') {
605+
sqlite3_result_error(context, "managedDatabaseId cannot be empty", -1);
624606
sqlite3_result_error_code(context, SQLITE_ERROR);
625-
goto finalize;
607+
return false;
626608
}
627609

628-
// parse address: scheme://host[:port]
629-
const char *scheme_end = strstr(address, "://");
630-
if (!scheme_end) {
631-
sqlite3_result_error(context, "address must include scheme (e.g. https://host:port)", -1);
610+
if (!address || address[0] == '\0') {
611+
sqlite3_result_error(context, "address cannot be empty", -1);
632612
sqlite3_result_error_code(context, SQLITE_ERROR);
633-
goto finalize;
634-
}
635-
636-
size_t scheme_len = scheme_end - address;
637-
const char *host_start = scheme_end + 3;
638-
const char *port_sep = strchr(host_start, ':');
639-
const char *host_end = port_sep ? port_sep : host_start + strlen(host_start);
640-
const char *port_str = port_sep ? port_sep + 1 : CLOUDSYNC_DEFAULT_ENDPOINT_PORT;
641-
642-
// build authentication from apikey or token
643-
if (apikey) {
644-
authentication = network_authentication_token("apikey", apikey);
645-
} else if (token) {
646-
authentication = network_authentication_token("token", token);
613+
return false;
647614
}
648615

649-
// build endpoints: {scheme}://{host}:{port}/v2/cloudsync/{projectID}/{database}/{siteId}/{action}
650-
size_t requested = scheme_len + 3 + (host_end - host_start) + 1 + strlen(port_str) + 1
651-
+ strlen(CLOUDSYNC_ENDPOINT_PREFIX) + 1 + strlen(project_id) + 1
652-
+ strlen(database) + 1 + UUID_STR_MAXLEN + 1 + 16;
653-
check_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
654-
upload_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
655-
apply_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
656-
status_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
616+
// build endpoints: {address}/v2/cloudsync/databases/{managedDatabaseId}/{siteId}/{action}
617+
size_t requested = strlen(address) + 1
618+
+ strlen(CLOUDSYNC_ENDPOINT_PREFIX) + 1 + strlen(managedDatabaseId) + 1
619+
+ UUID_STR_MAXLEN + 1 + 16;
620+
char *check_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
621+
char *upload_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
622+
char *apply_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
623+
char *status_endpoint = (char *)cloudsync_memory_zeroalloc(requested);
657624

658625
if (!check_endpoint || !upload_endpoint || !apply_endpoint || !status_endpoint) {
659626
sqlite3_result_error_code(context, SQLITE_NOMEM);
660-
goto finalize;
661-
}
662-
663-
// format: scheme://host:port/v2/cloudsync/projectID/database/siteId/action
664-
snprintf(check_endpoint, requested, "%.*s://%.*s:%s/%s/%s/%s/%s/%s",
665-
(int)scheme_len, address, (int)(host_end - host_start), host_start, port_str,
666-
CLOUDSYNC_ENDPOINT_PREFIX, project_id, database, data->site_id, CLOUDSYNC_ENDPOINT_CHECK);
667-
snprintf(upload_endpoint, requested, "%.*s://%.*s:%s/%s/%s/%s/%s/%s",
668-
(int)scheme_len, address, (int)(host_end - host_start), host_start, port_str,
669-
CLOUDSYNC_ENDPOINT_PREFIX, project_id, database, data->site_id, CLOUDSYNC_ENDPOINT_UPLOAD);
670-
snprintf(apply_endpoint, requested, "%.*s://%.*s:%s/%s/%s/%s/%s/%s",
671-
(int)scheme_len, address, (int)(host_end - host_start), host_start, port_str,
672-
CLOUDSYNC_ENDPOINT_PREFIX, project_id, database, data->site_id, CLOUDSYNC_ENDPOINT_APPLY);
673-
snprintf(status_endpoint, requested, "%.*s://%.*s:%s/%s/%s/%s/%s/%s",
674-
(int)scheme_len, address, (int)(host_end - host_start), host_start, port_str,
675-
CLOUDSYNC_ENDPOINT_PREFIX, project_id, database, data->site_id, CLOUDSYNC_ENDPOINT_STATUS);
676-
677-
result = true;
678-
679-
finalize:
680-
if (result) {
681-
if (authentication) {
682-
if (data->authentication) cloudsync_memory_free(data->authentication);
683-
data->authentication = authentication;
684-
}
685-
686-
if (data->org_id) cloudsync_memory_free(data->org_id);
687-
data->org_id = cloudsync_string_dup(org_id);
688-
689-
if (data->check_endpoint) cloudsync_memory_free(data->check_endpoint);
690-
data->check_endpoint = check_endpoint;
691-
692-
if (data->upload_endpoint) cloudsync_memory_free(data->upload_endpoint);
693-
data->upload_endpoint = upload_endpoint;
694-
695-
if (data->apply_endpoint) cloudsync_memory_free(data->apply_endpoint);
696-
data->apply_endpoint = apply_endpoint;
697-
698-
if (data->status_endpoint) cloudsync_memory_free(data->status_endpoint);
699-
data->status_endpoint = status_endpoint;
700-
} else {
701-
if (authentication) cloudsync_memory_free(authentication);
702627
if (check_endpoint) cloudsync_memory_free(check_endpoint);
703628
if (upload_endpoint) cloudsync_memory_free(upload_endpoint);
704629
if (apply_endpoint) cloudsync_memory_free(apply_endpoint);
705630
if (status_endpoint) cloudsync_memory_free(status_endpoint);
631+
return false;
706632
}
707633

708-
// cleanup JSON-extracted strings
709-
if (address) cloudsync_memory_free(address);
710-
if (database) cloudsync_memory_free(database);
711-
if (project_id) cloudsync_memory_free(project_id);
712-
if (org_id) cloudsync_memory_free(org_id);
713-
if (apikey) cloudsync_memory_free(apikey);
714-
if (token) cloudsync_memory_free(token);
634+
// format: {address}/v2/cloudsync/databases/{managedDatabaseID}/{siteId}/{action}
635+
snprintf(check_endpoint, requested, "%s/%s/%s/%s/%s",
636+
address, CLOUDSYNC_ENDPOINT_PREFIX, managedDatabaseId, data->site_id, CLOUDSYNC_ENDPOINT_CHECK);
637+
snprintf(upload_endpoint, requested, "%s/%s/%s/%s/%s",
638+
address, CLOUDSYNC_ENDPOINT_PREFIX, managedDatabaseId, data->site_id, CLOUDSYNC_ENDPOINT_UPLOAD);
639+
snprintf(apply_endpoint, requested, "%s/%s/%s/%s/%s",
640+
address, CLOUDSYNC_ENDPOINT_PREFIX, managedDatabaseId, data->site_id, CLOUDSYNC_ENDPOINT_APPLY);
641+
snprintf(status_endpoint, requested, "%s/%s/%s/%s/%s",
642+
address, CLOUDSYNC_ENDPOINT_PREFIX, managedDatabaseId, data->site_id, CLOUDSYNC_ENDPOINT_STATUS);
715643

716-
return result;
644+
if (data->check_endpoint) cloudsync_memory_free(data->check_endpoint);
645+
data->check_endpoint = check_endpoint;
646+
647+
if (data->upload_endpoint) cloudsync_memory_free(data->upload_endpoint);
648+
data->upload_endpoint = upload_endpoint;
649+
650+
if (data->apply_endpoint) cloudsync_memory_free(data->apply_endpoint);
651+
data->apply_endpoint = apply_endpoint;
652+
653+
if (data->status_endpoint) cloudsync_memory_free(data->status_endpoint);
654+
data->status_endpoint = status_endpoint;
655+
656+
return true;
717657
}
718658

719659
void network_result_to_sqlite_error (sqlite3_context *context, NETWORK_RESULT res, const char *default_error_message) {
@@ -733,57 +673,60 @@ network_data *cloudsync_network_data (sqlite3_context *context) {
733673
return netdata;
734674
}
735675

736-
void cloudsync_network_init (sqlite3_context *context, int argc, sqlite3_value **argv) {
737-
DEBUG_FUNCTION("cloudsync_network_init");
738-
676+
static void cloudsync_network_init_internal (sqlite3_context *context, const char *address, const char *managedDatabaseId) {
739677
#ifndef CLOUDSYNC_OMIT_CURL
740678
curl_global_init(CURL_GLOBAL_ALL);
741679
#endif
742-
743-
// no real network operations here
744-
// just setup the network_data struct
680+
745681
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
746682
network_data *netdata = cloudsync_network_data(context);
747683
if (!netdata) goto abort_memory;
748-
684+
749685
// init context
750686
uint8_t *site_id = (uint8_t *)cloudsync_context_init(data);
751687
if (!site_id) goto abort_siteid;
752-
688+
753689
// save site_id string representation: 01957493c6c07e14803727e969f1d2cc
754690
cloudsync_uuid_v7_stringify(site_id, netdata->site_id, false);
755-
756-
// connection string is a JSON object:
757-
// {"address":"https://UUID.sqlite.cloud:443","database":"chinook.sqlite","projectID":"abc123","organizationID":"org456","apikey":"KEY"}
758-
// apikey/token are optional and can be set later via cloudsync_network_set_token/cloudsync_network_set_apikey
759-
760-
const char *connection_param = (const char *)sqlite3_value_text(argv[0]);
761-
691+
762692
// compute endpoints
763-
if (network_compute_endpoints(context, netdata, connection_param) == false) {
764-
// error message/code already set inside network_compute_endpoints
693+
// authentication can be set later via cloudsync_network_set_token/cloudsync_network_set_apikey
694+
if (network_compute_endpoints_with_address(context, netdata, address, managedDatabaseId) == false) {
765695
goto abort_cleanup;
766696
}
767-
697+
768698
cloudsync_set_auxdata(data, netdata);
769699
sqlite3_result_int(context, SQLITE_OK);
770700
return;
771-
701+
772702
abort_memory:
773703
sqlite3_result_error(context, "Unable to allocate memory in cloudsync_network_init.", -1);
774704
sqlite3_result_error_code(context, SQLITE_NOMEM);
775705
goto abort_cleanup;
776-
706+
777707
abort_siteid:
778708
sqlite3_result_error(context, "Unable to compute/retrieve site_id.", -1);
779709
sqlite3_result_error_code(context, SQLITE_MISUSE);
780710
goto abort_cleanup;
781-
711+
782712
abort_cleanup:
783713
cloudsync_set_auxdata(data, NULL);
784714
network_data_free(netdata);
785715
}
786716

717+
void cloudsync_network_init (sqlite3_context *context, int argc, sqlite3_value **argv) {
718+
DEBUG_FUNCTION("cloudsync_network_init");
719+
const char *managedDatabaseId = (const char *)sqlite3_value_text(argv[0]);
720+
cloudsync_network_init_internal(context, CLOUDSYNC_DEFAULT_ADDRESS, managedDatabaseId);
721+
}
722+
723+
void cloudsync_network_init_custom (sqlite3_context *context, int argc, sqlite3_value **argv) {
724+
DEBUG_FUNCTION("cloudsync_network_init_custom");
725+
const char *address = (const char *)sqlite3_value_text(argv[0]);
726+
const char *managedDatabaseId = (const char *)sqlite3_value_text(argv[1]);
727+
cloudsync_network_init_internal(context, address, managedDatabaseId);
728+
}
729+
787730
void cloudsync_network_cleanup_internal (sqlite3_context *context) {
788731
cloudsync_context *data = (cloudsync_context *)sqlite3_user_data(context);
789732
network_data *netdata = cloudsync_network_data(context);
@@ -828,7 +771,7 @@ void cloudsync_network_set_token (sqlite3_context *context, int argc, sqlite3_va
828771

829772
void cloudsync_network_set_apikey (sqlite3_context *context, int argc, sqlite3_value **argv) {
830773
DEBUG_FUNCTION("cloudsync_network_set_apikey");
831-
774+
832775
const char *value = (const char *)sqlite3_value_text(argv[0]);
833776
bool result = cloudsync_network_set_authentication_token(context, value, false);
834777
(result) ? sqlite3_result_int(context, SQLITE_OK) : sqlite3_result_error_code(context, SQLITE_NOMEM);
@@ -1258,6 +1201,9 @@ int cloudsync_network_register (sqlite3 *db, char **pzErrMsg, void *ctx) {
12581201
rc = sqlite3_create_function(db, "cloudsync_network_init", 1, DEFAULT_FLAGS, ctx, cloudsync_network_init, NULL, NULL);
12591202
if (rc != SQLITE_OK) goto cleanup;
12601203

1204+
rc = sqlite3_create_function(db, "cloudsync_network_init_custom", 2, DEFAULT_FLAGS, ctx, cloudsync_network_init_custom, NULL, NULL);
1205+
if (rc != SQLITE_OK) return rc;
1206+
12611207
rc = sqlite3_create_function(db, "cloudsync_network_cleanup", 0, DEFAULT_FLAGS, ctx, cloudsync_network_cleanup, NULL, NULL);
12621208
if (rc != SQLITE_OK) return rc;
12631209

src/network.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ void network_buffer_cleanup (void *xdata) {
1313
if (xdata) CFRelease(xdata);
1414
}
1515

16-
// network_compute_endpoints is implemented in network.c (shared across all platforms)
17-
1816
bool network_send_buffer(network_data *data, const char *endpoint, const char *authentication, const void *blob, int blob_size) {
1917
NSString *urlString = [NSString stringWithUTF8String:endpoint];
2018
NSURL *url = [NSURL URLWithString:urlString];

src/network_private.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
#ifndef __CLOUDSYNC_NETWORK_PRIVATE__
99
#define __CLOUDSYNC_NETWORK_PRIVATE__
1010

11-
#define CLOUDSYNC_ENDPOINT_PREFIX "v2/cloudsync"
11+
#define CLOUDSYNC_DEFAULT_ADDRESS "https://cloudsync.sqlite.ai"
12+
#define CLOUDSYNC_ENDPOINT_PREFIX "v2/cloudsync/databases"
1213
#define CLOUDSYNC_ENDPOINT_UPLOAD "upload"
1314
#define CLOUDSYNC_ENDPOINT_CHECK "check"
1415
#define CLOUDSYNC_ENDPOINT_APPLY "apply"
1516
#define CLOUDSYNC_ENDPOINT_STATUS "status"
16-
#define CLOUDSYNC_DEFAULT_ENDPOINT_PORT "443"
1717
#define CLOUDSYNC_HEADER_SQLITECLOUD "Accept: sqlc/plain"
1818
#define CLOUDSYNC_HEADER_ORG "X-CloudSync-Org"
1919

@@ -35,7 +35,6 @@ char *network_data_get_siteid (network_data *data);
3535
char *network_data_get_orgid (network_data *data);
3636
bool network_data_set_endpoints (network_data *data, char *auth, char *check, char *upload, char *apply, char *status);
3737

38-
bool network_compute_endpoints (sqlite3_context *context, network_data *data, const char *conn_string);
3938
bool network_send_buffer(network_data *data, const char *endpoint, const char *authentication, const void *blob, int blob_size);
4039
NETWORK_RESULT network_receive_buffer (network_data *data, const char *endpoint, const char *authentication, bool zero_terminated, bool is_post_request, char *json_payload, const char *custom_header);
4140

0 commit comments

Comments
 (0)