Expose repository functions to sharedlibs

This commit is contained in:
Pijus Kamandulis 2024-12-20 20:25:32 +02:00
parent 363f822e5a
commit bcf4b513b6
10 changed files with 484 additions and 41 deletions

View File

@ -0,0 +1,89 @@
package main
import "C"
import (
"encoding/json"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
)
//export CreateCollection
func CreateCollection(serverName *C.char, databaseId *C.char, collectionJson *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionStr := C.GoString(collectionJson)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
var collection repositorymodels.Collection
err := json.Unmarshal([]byte(collectionStr), &collection)
if err != nil {
return ResponseFailedToParseRequest
}
_, code := serverInstance.repository.CreateCollection(databaseIdStr, collection)
return repositoryStatusToResponseCode(code)
}
//export GetCollection
func GetCollection(serverName *C.char, databaseId *C.char, collectionId *C.char) *C.char {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
collection, code := serverInstance.repository.GetCollection(databaseIdStr, collectionIdStr)
if code != repositorymodels.StatusOk {
return C.CString("")
}
collectionJson, _ := json.Marshal(collection)
return C.CString(string(collectionJson))
}
//export GetAllCollections
func GetAllCollections(serverName *C.char, databaseId *C.char) *C.char {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
collections, code := serverInstance.repository.GetAllCollections(databaseIdStr)
if code != repositorymodels.StatusOk {
return C.CString("")
}
collectionsJson, _ := json.Marshal(collections)
return C.CString(string(collectionsJson))
}
//export DeleteCollection
func DeleteCollection(serverName *C.char, databaseId *C.char, collectionId *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
code := serverInstance.repository.DeleteCollection(databaseIdStr, collectionIdStr)
return repositoryStatusToResponseCode(code)
}

View File

@ -0,0 +1,89 @@
package main
import "C"
import (
"encoding/json"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
)
//export CreateDatabase
func CreateDatabase(serverName *C.char, databaseJson *C.char) int {
serverNameStr := C.GoString(serverName)
databaseStr := C.GoString(databaseJson)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
var database repositorymodels.Database
err := json.Unmarshal([]byte(databaseStr), &database)
if err != nil {
return ResponseFailedToParseRequest
}
_, code := serverInstance.repository.CreateDatabase(database)
return repositoryStatusToResponseCode(code)
}
//export GetDatabase
func GetDatabase(serverName *C.char, databaseId *C.char) *C.char {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
database, code := serverInstance.repository.GetDatabase(databaseIdStr)
if code != repositorymodels.StatusOk {
return C.CString("")
}
databaseJson, _ := json.Marshal(database)
return C.CString(string(databaseJson))
}
//export GetAllDatabases
func GetAllDatabases(serverName *C.char) *C.char {
serverNameStr := C.GoString(serverName)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
databases, code := serverInstance.repository.GetAllDatabases()
if code != repositorymodels.StatusOk {
return C.CString("")
}
databasesJson, err := json.Marshal(databases)
if err != nil {
return C.CString("")
}
return C.CString(string(databasesJson))
}
//export DeleteDatabase
func DeleteDatabase(serverName *C.char, databaseId *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
code := serverInstance.repository.DeleteDatabase(databaseIdStr)
return repositoryStatusToResponseCode(code)
}

122
sharedlibrary/documents.go Normal file
View File

@ -0,0 +1,122 @@
package main
import "C"
import (
"encoding/json"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
)
//export CreateDocument
func CreateDocument(serverName *C.char, databaseId *C.char, collectionId *C.char, documentJson *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
documentStr := C.GoString(documentJson)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
var document repositorymodels.Document
err := json.Unmarshal([]byte(documentStr), &document)
if err != nil {
return ResponseFailedToParseRequest
}
_, code := serverInstance.repository.CreateDocument(databaseIdStr, collectionIdStr, document)
return repositoryStatusToResponseCode(code)
}
//export GetDocument
func GetDocument(serverName *C.char, databaseId *C.char, collectionId *C.char, documentId *C.char) *C.char {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
documentIdStr := C.GoString(documentId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
document, code := serverInstance.repository.GetDocument(databaseIdStr, collectionIdStr, documentIdStr)
if code != repositorymodels.StatusOk {
return C.CString("")
}
documentJson, _ := json.Marshal(document)
return C.CString(string(documentJson))
}
//export GetAllDocuments
func GetAllDocuments(serverName *C.char, databaseId *C.char, collectionId *C.char) *C.char {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return C.CString("")
}
documents, code := serverInstance.repository.GetAllDocuments(databaseIdStr, collectionIdStr)
if code != repositorymodels.StatusOk {
return C.CString("")
}
documentsJson, _ := json.Marshal(documents)
return C.CString(string(documentsJson))
}
//export UpdateDocument
func UpdateDocument(serverName *C.char, databaseId *C.char, collectionId *C.char, documentId *C.char, documentJson *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
documentIdStr := C.GoString(documentId)
documentStr := C.GoString(documentJson)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
var document repositorymodels.Document
err := json.Unmarshal([]byte(documentStr), &document)
if err != nil {
return ResponseFailedToParseRequest
}
code := serverInstance.repository.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
if code != repositorymodels.StatusOk {
return repositoryStatusToResponseCode(code)
}
_, code = serverInstance.repository.CreateDocument(databaseIdStr, collectionIdStr, document)
return repositoryStatusToResponseCode(code)
}
//export DeleteDocument
func DeleteDocument(serverName *C.char, databaseId *C.char, collectionId *C.char, documentId *C.char) int {
serverNameStr := C.GoString(serverName)
databaseIdStr := C.GoString(databaseId)
collectionIdStr := C.GoString(collectionId)
documentIdStr := C.GoString(documentId)
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = getInstance(serverNameStr); !ok {
return ResponseServerInstanceNotFound
}
code := serverInstance.repository.DeleteDocument(databaseIdStr, collectionIdStr, documentIdStr)
return repositoryStatusToResponseCode(code)
}

86
sharedlibrary/shared.go Normal file
View File

@ -0,0 +1,86 @@
package main
import (
"sync"
"github.com/pikami/cosmium/api"
"github.com/pikami/cosmium/internal/repositories"
repositorymodels "github.com/pikami/cosmium/internal/repository_models"
)
type ServerInstance struct {
server *api.ApiServer
repository *repositories.DataRepository
}
var serverInstances map[string]*ServerInstance
var mutex sync.RWMutex
const (
ResponseSuccess = 0
ResponseUnknown = 100
ResponseFailedToParseConfiguration = 101
ResponseFailedToLoadState = 102
ResponseFailedToParseRequest = 103
ResponseServerInstanceAlreadyExists = 104
ResponseServerInstanceNotFound = 105
ResponseRepositoryNotFound = 200
ResponseRepositoryConflict = 201
ResponseRepositoryBadRequest = 202
)
func getInstance(serverName string) (*ServerInstance, bool) {
mutex.RLock()
defer mutex.RUnlock()
if serverInstances == nil {
serverInstances = make(map[string]*ServerInstance)
}
var ok bool
var serverInstance *ServerInstance
if serverInstance, ok = serverInstances[serverName]; !ok {
return nil, false
}
return serverInstance, true
}
func addInstance(serverName string, serverInstance *ServerInstance) {
mutex.Lock()
defer mutex.Unlock()
if serverInstances == nil {
serverInstances = make(map[string]*ServerInstance)
}
serverInstances[serverName] = serverInstance
}
func removeInstance(serverName string) {
mutex.Lock()
defer mutex.Unlock()
if serverInstances == nil {
return
}
delete(serverInstances, serverName)
}
func repositoryStatusToResponseCode(status repositorymodels.RepositoryStatus) int {
switch status {
case repositorymodels.StatusOk:
return ResponseSuccess
case repositorymodels.StatusNotFound:
return ResponseRepositoryNotFound
case repositorymodels.Conflict:
return ResponseRepositoryConflict
case repositorymodels.BadRequest:
return ResponseRepositoryBadRequest
default:
return ResponseUnknown
}
}

View File

@ -9,32 +9,12 @@ import (
"github.com/pikami/cosmium/internal/repositories"
)
type ServerInstance struct {
server *api.ApiServer
repository *repositories.DataRepository
}
var serverInstances map[string]*ServerInstance
const (
ResponseSuccess = 0
ResponseUnknown = 1
ResponseServerInstanceAlreadyExists = 2
ResponseFailedToParseConfiguration = 3
ResponseServerInstanceNotFound = 4
ResponseFailedToLoadState = 5
)
//export CreateServerInstance
func CreateServerInstance(serverName *C.char, configurationJSON *C.char) int {
configStr := C.GoString(configurationJSON)
serverNameStr := C.GoString(serverName)
if serverInstances == nil {
serverInstances = make(map[string]*ServerInstance)
}
if _, ok := serverInstances[serverNameStr]; ok {
if _, ok := getInstance(serverNameStr); ok {
return ResponseServerInstanceAlreadyExists
}
@ -55,19 +35,21 @@ func CreateServerInstance(serverName *C.char, configurationJSON *C.char) int {
server := api.NewApiServer(repository, configuration)
server.Start()
serverInstances[serverNameStr] = &ServerInstance{
addInstance(serverNameStr, &ServerInstance{
server: server,
repository: repository,
}
})
return ResponseSuccess
}
//export StopServerInstance
func StopServerInstance(serverName *C.char) int {
if serverInstance, ok := serverInstances[C.GoString(serverName)]; ok {
serverNameStr := C.GoString(serverName)
if serverInstance, ok := getInstance(serverNameStr); ok {
serverInstance.server.Stop()
delete(serverInstances, C.GoString(serverName))
removeInstance(serverNameStr)
return ResponseSuccess
}
@ -76,7 +58,9 @@ func StopServerInstance(serverName *C.char) int {
//export GetServerInstanceState
func GetServerInstanceState(serverName *C.char) *C.char {
if serverInstance, ok := serverInstances[C.GoString(serverName)]; ok {
serverNameStr := C.GoString(serverName)
if serverInstance, ok := getInstance(serverNameStr); ok {
stateJSON, err := serverInstance.repository.GetState()
if err != nil {
return nil
@ -92,7 +76,7 @@ func LoadServerInstanceState(serverName *C.char, stateJSON *C.char) int {
serverNameStr := C.GoString(serverName)
stateJSONStr := C.GoString(stateJSON)
if serverInstance, ok := serverInstances[serverNameStr]; ok {
if serverInstance, ok := getInstance(serverNameStr); ok {
err := serverInstance.repository.LoadStateJSON(stateJSONStr)
if err != nil {
return ResponseFailedToLoadState

View File

@ -1,8 +1,9 @@
#include "shared.h"
void test_CreateServerInstance();
void test_StopServerInstance();
void test_ServerInstanceStateMethods();
int test_CreateServerInstance();
int test_StopServerInstance();
int test_ServerInstanceStateMethods();
int test_Databases();
int main(int argc, char *argv[])
{
@ -21,9 +22,24 @@ int main(int argc, char *argv[])
}
printf("Running tests for library: %s\n", libPath);
test_CreateServerInstance();
test_ServerInstanceStateMethods();
test_StopServerInstance();
int results[] = {
test_CreateServerInstance(),
test_Databases(),
test_ServerInstanceStateMethods(),
test_StopServerInstance(),
};
int numTests = sizeof(results) / sizeof(results[0]);
int numPassed = 0;
for (int i = 0; i < numTests; i++)
{
if (results[i])
{
numPassed++;
}
}
printf("Tests passed: %d/%d\n", numPassed, numTests);
dlclose(handle);
return EXIT_SUCCESS;

View File

@ -1,6 +1,6 @@
#include "shared.h"
void test_CreateServerInstance()
int test_CreateServerInstance()
{
typedef int (*CreateServerInstanceFn)(char *, char *);
CreateServerInstanceFn CreateServerInstance = (CreateServerInstanceFn)load_function("CreateServerInstance");
@ -8,7 +8,7 @@ void test_CreateServerInstance()
if (!CreateServerInstance)
{
fprintf(stderr, "Failed to find CreateServerInstance function\n");
return;
return 0;
}
char *serverName = "TestServer";
@ -22,5 +22,8 @@ void test_CreateServerInstance()
else
{
printf("CreateServerInstance: FAILED (result = %d)\n", result);
return 0;
}
return 1;
}

View File

@ -0,0 +1,47 @@
#include "shared.h"
int test_Databases()
{
typedef int (*CreateDatabaseFn)(char *, char *);
CreateDatabaseFn CreateDatabase = (CreateDatabaseFn)load_function("CreateDatabase");
if (!CreateDatabase)
{
fprintf(stderr, "Failed to find CreateDatabase function\n");
return 0;
}
char *serverName = "TestServer";
char *configJSON = "{\"id\":\"test-db\"}";
int result = CreateDatabase(serverName, configJSON);
if (result == 0)
{
printf("CreateDatabase: SUCCESS\n");
}
else
{
printf("CreateDatabase: FAILED (result = %d)\n", result);
return 0;
}
typedef char *(*GetDatabaseFn)(char *, char *);
GetDatabaseFn GetDatabase = (GetDatabaseFn)load_function("GetDatabase");
if (!GetDatabase)
{
fprintf(stderr, "Failed to find GetDatabase function\n");
return 0;
}
char *database = GetDatabase(serverName, "test-db");
if (database)
{
printf("GetDatabase: SUCCESS (database = %s)\n", database);
}
else
{
printf("GetDatabase: FAILED\n");
return 0;
}
return 1;
}

View File

@ -1,13 +1,13 @@
#include "shared.h"
void test_ServerInstanceStateMethods()
int test_ServerInstanceStateMethods()
{
typedef int (*LoadServerInstanceStateFn)(char *, char *);
LoadServerInstanceStateFn LoadServerInstanceState = (LoadServerInstanceStateFn)load_function("LoadServerInstanceState");
if (!LoadServerInstanceState)
{
fprintf(stderr, "Failed to find LoadServerInstanceState function\n");
return;
return 0;
}
char *serverName = "TestServer";
@ -20,6 +20,7 @@ void test_ServerInstanceStateMethods()
else
{
printf("LoadServerInstanceState: FAILED (result = %d)\n", result);
return 0;
}
typedef char *(*GetServerInstanceStateFn)(char *);
@ -27,7 +28,7 @@ void test_ServerInstanceStateMethods()
if (!GetServerInstanceState)
{
fprintf(stderr, "Failed to find GetServerInstanceState function\n");
return;
return 0;
}
char *state = GetServerInstanceState(serverName);
@ -38,6 +39,7 @@ void test_ServerInstanceStateMethods()
else
{
printf("GetServerInstanceState: FAILED\n");
return 0;
}
const char *expected_state = "{\"databases\":{\"test-db\":{\"id\":\"test-db\",\"_ts\":0,\"_rid\":\"\",\"_etag\":\"\",\"_self\":\"\"}},\"collections\":{\"test-db\":{}},\"documents\":{\"test-db\":{}}}";
@ -45,7 +47,7 @@ void test_ServerInstanceStateMethods()
if (!compact_state)
{
free(state);
return;
return 0;
}
if (strcmp(compact_state, expected_state) == 0)
@ -57,8 +59,10 @@ void test_ServerInstanceStateMethods()
printf("GetServerInstanceState: State does not match expected value.\n");
printf("Expected: %s\n", expected_state);
printf("Actual: %s\n", compact_state);
return 0;
}
free(state);
free(compact_state);
return 1;
}

View File

@ -1,6 +1,6 @@
#include "shared.h"
void test_StopServerInstance()
int test_StopServerInstance()
{
typedef int (*StopServerInstanceFn)(char *);
StopServerInstanceFn StopServerInstance = (StopServerInstanceFn)load_function("StopServerInstance");
@ -8,7 +8,7 @@ void test_StopServerInstance()
if (!StopServerInstance)
{
fprintf(stderr, "Failed to find StopServerInstance function\n");
return;
return 0;
}
char *serverName = "TestServer";
@ -20,5 +20,8 @@ void test_StopServerInstance()
else
{
printf("StopServerInstance: FAILED (result = %d)\n", result);
return 0;
}
return 1;
}