diff --git a/examples/c/storage.c b/examples/c/storage.c index 4ae34b42..c7d2d4ad 100644 --- a/examples/c/storage.c +++ b/examples/c/storage.c @@ -273,36 +273,21 @@ int cleanup(void *storage_ctx) return RET_ERR; } - r = alloc_resp(); - // Destroy node // No need to wait here as storage_destroy is synchronous - if (storage_destroy(storage_ctx, (StorageCallback)callback, r) != RET_OK) + if (storage_destroy(storage_ctx) != RET_OK) { - free_resp(r); return RET_ERR; } - free_resp(r); - return RET_OK; } int check_version(void *storage_ctx) { - char *res = NULL; - - Resp *r = alloc_resp(); - - // No need to wait here as storage_version is synchronous - if (storage_version(storage_ctx, (StorageCallback)callback, r) != RET_OK) - { - free_resp(r); - return RET_ERR; - } - - free_resp(r); - + char *version = storage_version(storage_ctx); + printf("version: %s\n", version); + free(version); return RET_OK; } diff --git a/library/README.md b/library/README.md index 7b15851e..b9fd0567 100644 --- a/library/README.md +++ b/library/README.md @@ -137,10 +137,11 @@ int storage_close(void *ctx, StorageCallback callback, void *userData); ### `storage_destroy` -Destroy the node instance and free associated resources. Node must be stopped and closed. +Destroys the node instance and frees associated resources. Node must be stopped and closed. +The call is synchronous, so it does not require a callback. ```c -int storage_destroy(void *ctx, StorageCallback callback, void *userData); +int storage_destroy(void *ctx); ``` --- @@ -149,22 +150,22 @@ int storage_destroy(void *ctx, StorageCallback callback, void *userData); ### `storage_version` -Get the Logos Storage version string. -Does not require the node to be started and does not involve a thread call. +Get the Logos Storage version as a null-terminated string. The caller is responsible for freeing it. +Does not require the node to be started. It is also a synchronous call, so it does not require a callback. ```c -int storage_version(void *ctx, StorageCallback callback, void *userData); +char* storage_version(void *ctx); ``` --- ### `storage_revision` -Get the Logos Storage contracts revision. -Does not require the node to be started and does not involve a thread call. +Get the Logos Storage contracts revision as a null-terminated string. The caller is responsible for freeing it. +Does not require the node to be started. It is also a synchronous call, so it does not require a callback. ```c -int storage_revision(void *ctx, StorageCallback callback, void *userData); +char* storage_revision(void *ctx); ``` --- diff --git a/library/libstorage.h b/library/libstorage.h index 458cd313..8e6c8c07 100644 --- a/library/libstorage.h +++ b/library/libstorage.h @@ -61,21 +61,19 @@ extern "C" StorageCallback callback, void *userData); - // Get the Logos Storage version string. + // Get the Logos Storage version as a null-terminated string, which + // must then be freed by the caller. // This call does not require the node to be started and // does not involve a thread call. - int storage_version( - void *ctx, - StorageCallback callback, - void *userData); + // It is also synchronous, so it does not require a callback. + char *storage_version(void *ctx); - // Get the Logos Storage contracts revision. + // Get the Logos Storage contracts revision as a null-terminated + // string, which must then be freed by the caller. // This call does not require the node to be started and // does not involve a thread call. - int storage_revision( - void *ctx, - StorageCallback callback, - void *userData); + // It is also synchronous, so it does not require a callback. + char *storage_revision(void *ctx); // Get the repo (data-dir) used by the node. int storage_repo( @@ -375,6 +373,7 @@ extern "C" // Destroys an instance of a Logos Storage node. // This will free all resources associated with the node. // The node must be stopped and closed before calling this function. + // The call is synchronous, so it does not require a callback. // // Typical usage: // ctx = storage_new(configJson, myCallback, myUserData); @@ -383,9 +382,7 @@ extern "C" // storage_stop(ctx, ...); // storage_close(ctx, ...); // storage_destroy(ctx, ...); - int storage_destroy(void *ctx, - StorageCallback callback, - void *userData); + int storage_destroy(void *ctx); // Not used currently. // Reserved for future use to set an event callback. diff --git a/library/libstorage.nim b/library/libstorage.nim index 06b02172..46f0749c 100644 --- a/library/libstorage.nim +++ b/library/libstorage.nim @@ -8,15 +8,15 @@ # - Thread-safe exported procs callable from C # - Callback registration and invocation for asynchronous communication -# cdecl is C declaration calling convention. +# cdecl is C declaration calling convention. # It’s the standard way C compilers expect functions to behave: -# 1- Caller cleans up the stack after the call +# 1- Caller cleans up the stack after the call # 2- Symbol names are exported in a predictable way # In other termes, it is a glue that makes Nim functions callable as normal C functions. {.pragma: exported, exportc, cdecl, raises: [].} {.pragma: callback, cdecl, raises: [], gcsafe.} -# Ensure code is position-independent so it can be built into a shared library (.so). +# Ensure code is position-independent so it can be built into a shared library (.so). # In other terms, the code that can run no matter where it’s placed in memory. {.passc: "-fPIC".} @@ -53,7 +53,19 @@ template checkLibstorageParams*( if isNil(callback): return RET_MISSING_CALLBACK -# From Nim doc: +proc malloc(size: csize_t): pointer {.importc, header: "".} + +proc asNewCString(s: string): ptr cchar = + # We need malloc so C clients can free it. + let + n = s.len + cstr = cast[ptr UncheckedArray[cchar]](malloc(n.csize_t + 1)) + if n > 0: + copyMem(cstr, addr s[0], n) + cstr[n] = 0.cchar + cast[ptr cchar](cstr) + +# From Nim doc: # "the C targets require you to initialize Nim's internals, which is done calling a NimMain function." # "The name NimMain can be influenced via the --nimMainPrefix:prefix switch." # "Use --nimMainPrefix:MyLib and the function to call is named MyLibNimMain." @@ -110,35 +122,15 @@ proc storage_new( return ctx -proc storage_version( - ctx: ptr StorageContext, callback: StorageCallback, userData: pointer -): cint {.dynlib, exportc.} = +proc storage_version(ctx: ptr StorageContext): ptr cchar {.dynlib, exportc.} = initializeLibrary() - checkLibstorageParams(ctx, callback, userData) - callback( - RET_OK, - cast[ptr cchar](conf.codexVersion), - cast[csize_t](len(conf.codexVersion)), - userData, - ) + return asNewCString(conf.codexVersion) - return RET_OK - -proc storage_revision( - ctx: ptr StorageContext, callback: StorageCallback, userData: pointer -): cint {.dynlib, exportc.} = +proc storage_revision(ctx: ptr StorageContext): ptr cchar {.dynlib, exportc.} = initializeLibrary() - checkLibstorageParams(ctx, callback, userData) - callback( - RET_OK, - cast[ptr cchar](conf.codexRevision), - cast[csize_t](len(conf.codexRevision)), - userData, - ) - - return RET_OK + return asNewCString(conf.codexRevision) proc storage_repo( ctx: ptr StorageContext, callback: StorageCallback, userData: pointer @@ -268,17 +260,10 @@ proc storage_close( return callback.okOrError(res, userData) -proc storage_destroy( - ctx: ptr StorageContext, callback: StorageCallback, userData: pointer -): cint {.dynlib, exportc.} = +proc storage_destroy(ctx: ptr StorageContext): cint {.dynlib, exportc.} = initializeLibrary() - checkLibstorageParams(ctx, callback, userData) - let res = storage_context.destroyStorageContext(ctx) - if res.isErr: - return RET_ERR - - return RET_OK + if res.isErr: RET_ERR else: RET_OK proc storage_upload_init( ctx: ptr StorageContext,