mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add flushing/reloading
This commit is contained in:
parent
91474e179c
commit
63d96ab712
|
@ -15,6 +15,7 @@ CXX_GUARD_START
|
||||||
|
|
||||||
struct VFile;
|
struct VFile;
|
||||||
void mScriptContextAttachStorage(struct mScriptContext* context);
|
void mScriptContextAttachStorage(struct mScriptContext* context);
|
||||||
|
void mScriptStorageFlushAll(struct mScriptContext* context);
|
||||||
|
|
||||||
bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucket);
|
bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucket);
|
||||||
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf);
|
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf);
|
||||||
|
|
|
@ -24,15 +24,18 @@ struct mScriptStorageContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
void mScriptStorageBucketDeinit(void*);
|
void mScriptStorageBucketDeinit(void*);
|
||||||
struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* adapter, const char* key);
|
struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* bucket, const char* key);
|
||||||
static void mScriptStorageBucketSet(struct mScriptStorageBucket* adapter, const char* key, struct mScriptValue* value);
|
static void mScriptStorageBucketSet(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value);
|
||||||
static void mScriptStorageBucketSetVoid(struct mScriptStorageBucket* adapter, const char* key, struct mScriptValue* value);
|
static void mScriptStorageBucketSetVoid(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value);
|
||||||
static void mScriptStorageBucketSetSInt(struct mScriptStorageBucket* adapter, const char* key, int64_t value);
|
static void mScriptStorageBucketSetSInt(struct mScriptStorageBucket* bucket, const char* key, int64_t value);
|
||||||
static void mScriptStorageBucketSetUInt(struct mScriptStorageBucket* adapter, const char* key, uint64_t value);
|
static void mScriptStorageBucketSetUInt(struct mScriptStorageBucket* bucket, const char* key, uint64_t value);
|
||||||
static void mScriptStorageBucketSetFloat(struct mScriptStorageBucket* adapter, const char* key, double value);
|
static void mScriptStorageBucketSetFloat(struct mScriptStorageBucket* bucket, const char* key, double value);
|
||||||
static void mScriptStorageBucketSetBool(struct mScriptStorageBucket* adapter, const char* key, bool value);
|
static void mScriptStorageBucketSetBool(struct mScriptStorageBucket* bucket, const char* key, bool value);
|
||||||
|
static bool mScriptStorageBucketReload(struct mScriptStorageBucket* bucket);
|
||||||
|
static bool mScriptStorageBucketFlush(struct mScriptStorageBucket* bucket);
|
||||||
|
|
||||||
void mScriptStorageContextDeinit(struct mScriptStorageContext*);
|
static void mScriptStorageContextDeinit(struct mScriptStorageContext*);
|
||||||
|
static void mScriptStorageContextFlushAll(struct mScriptStorageContext*);
|
||||||
struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext*, const char* name);
|
struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext*, const char* name);
|
||||||
|
|
||||||
static bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out);
|
static bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out);
|
||||||
|
@ -48,6 +51,8 @@ mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setStr, mScriptStorageB
|
||||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setList, mScriptStorageBucketSet, 2, CHARP, key, WLIST, value);
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setList, mScriptStorageBucketSet, 2, CHARP, key, WLIST, value);
|
||||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setTable, mScriptStorageBucketSet, 2, CHARP, key, WTABLE, value);
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setTable, mScriptStorageBucketSet, 2, CHARP, key, WTABLE, value);
|
||||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setVoid, mScriptStorageBucketSetVoid, 2, CHARP, key, NUL, value);
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setVoid, mScriptStorageBucketSetVoid, 2, CHARP, key, NUL, value);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, BOOL, reload, mScriptStorageBucketReload, 0);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, BOOL, flush, mScriptStorageBucketFlush, 0);
|
||||||
|
|
||||||
mSCRIPT_DEFINE_STRUCT(mScriptStorageBucket)
|
mSCRIPT_DEFINE_STRUCT(mScriptStorageBucket)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setSInt)
|
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setSInt)
|
||||||
|
@ -59,15 +64,19 @@ mSCRIPT_DEFINE_STRUCT(mScriptStorageBucket)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setTable)
|
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setTable)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setVoid)
|
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setVoid)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(mScriptStorageBucket)
|
mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(mScriptStorageBucket)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageBucket, reload)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageBucket, flush)
|
||||||
mSCRIPT_DEFINE_END;
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptStorageContext);
|
mSCRIPT_DECLARE_STRUCT(mScriptStorageContext);
|
||||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageContext, _deinit, mScriptStorageContextDeinit, 0);
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageContext, _deinit, mScriptStorageContextDeinit, 0);
|
||||||
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageContext, S(mScriptStorageBucket), getBucket, mScriptStorageGetBucket, 1, CHARP, key);
|
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageContext, S(mScriptStorageBucket), getBucket, mScriptStorageGetBucket, 1, CHARP, key);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageContext, flushAll, mScriptStorageContextFlushAll, 0);
|
||||||
|
|
||||||
mSCRIPT_DEFINE_STRUCT(mScriptStorageContext)
|
mSCRIPT_DEFINE_STRUCT(mScriptStorageContext)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptStorageContext)
|
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptStorageContext)
|
||||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageContext, getBucket)
|
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageContext, getBucket)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageContext, flushAll)
|
||||||
mSCRIPT_DEFINE_END;
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* bucket, const char* key) {
|
struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* bucket, const char* key) {
|
||||||
|
@ -218,14 +227,7 @@ bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
|
static bool _mScriptStorageBucketFlushVF(struct mScriptStorageBucket* bucket, struct VFile* vf) {
|
||||||
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
|
|
||||||
if (!value) {
|
|
||||||
vf->close(vf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
struct mScriptStorageContext* storage = value->value.opaque;
|
|
||||||
struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName);
|
|
||||||
struct json_object* rootObj;
|
struct json_object* rootObj;
|
||||||
bool ok = mScriptStorageToJson(bucket->root, &rootObj);
|
bool ok = mScriptStorageToJson(bucket->root, &rootObj);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
@ -249,6 +251,24 @@ bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* buck
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mScriptStorageBucketFlush(struct mScriptStorageBucket* bucket) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
mScriptStorageGetBucketPath(bucket->name, path);
|
||||||
|
struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
|
||||||
|
return _mScriptStorageBucketFlushVF(bucket, vf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
|
||||||
|
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
|
||||||
|
if (!value) {
|
||||||
|
vf->close(vf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptStorageContext* storage = value->value.opaque;
|
||||||
|
struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName);
|
||||||
|
return _mScriptStorageBucketFlushVF(bucket, vf);
|
||||||
|
}
|
||||||
|
|
||||||
bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucketName) {
|
bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucketName) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
mScriptStorageGetBucketPath(bucketName, path);
|
mScriptStorageGetBucketPath(bucketName, path);
|
||||||
|
@ -314,6 +334,51 @@ struct mScriptValue* mScriptStorageFromJson(struct json_object* json) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct mScriptValue* _mScriptStorageLoadJson(struct VFile* vf) {
|
||||||
|
ssize_t size = vf->size(vf);
|
||||||
|
if (size < 2) {
|
||||||
|
vf->close(vf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char* json = calloc(1, size + 1);
|
||||||
|
if (vf->read(vf, json, size) != size) {
|
||||||
|
vf->close(vf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vf->close(vf);
|
||||||
|
|
||||||
|
struct json_object* obj = json_tokener_parse(json);
|
||||||
|
free(json);
|
||||||
|
if (!obj) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mScriptValue* root = mScriptStorageFromJson(obj);
|
||||||
|
json_object_put(obj);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mScriptStorageBucketReload(struct mScriptStorageBucket* bucket) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
mScriptStorageGetBucketPath(bucket->name, path);
|
||||||
|
struct VFile* vf = VFileOpen(path, O_RDONLY);
|
||||||
|
if (!vf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptValue* root = _mScriptStorageLoadJson(vf);
|
||||||
|
if (!root) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bucket->root) {
|
||||||
|
mScriptValueDeref(bucket->root);
|
||||||
|
}
|
||||||
|
bucket->root = root;
|
||||||
|
|
||||||
|
bucket->dirty = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
|
bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
|
||||||
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
|
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
@ -321,35 +386,16 @@ bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* buck
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct mScriptStorageContext* storage = value->value.opaque;
|
struct mScriptStorageContext* storage = value->value.opaque;
|
||||||
|
struct mScriptValue* root = _mScriptStorageLoadJson(vf);
|
||||||
ssize_t size = vf->size(vf);
|
|
||||||
if (size < 2) {
|
|
||||||
vf->close(vf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
char* json = calloc(1, size + 1);
|
|
||||||
if (vf->read(vf, json, size) != size) {
|
|
||||||
vf->close(vf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vf->close(vf);
|
|
||||||
|
|
||||||
struct json_object* obj = json_tokener_parse(json);
|
|
||||||
free(json);
|
|
||||||
if (!obj) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mScriptValue* root = mScriptStorageFromJson(obj);
|
|
||||||
json_object_put(obj);
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName);
|
struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName);
|
||||||
mScriptValueDeref(bucket->root);
|
mScriptValueDeref(bucket->root);
|
||||||
bucket->root = root;
|
bucket->root = root;
|
||||||
|
|
||||||
|
bucket->dirty = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,10 +421,29 @@ void mScriptContextAttachStorage(struct mScriptContext* context) {
|
||||||
mScriptContextSetDocstring(context, "storage", "Singleton instance of struct::mScriptStorageContext");
|
mScriptContextSetDocstring(context, "storage", "Singleton instance of struct::mScriptStorageContext");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mScriptStorageFlushAll(struct mScriptContext* context) {
|
||||||
|
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct mScriptStorageContext* storage = value->value.opaque;
|
||||||
|
mScriptStorageContextFlushAll(storage);
|
||||||
|
}
|
||||||
|
|
||||||
void mScriptStorageContextDeinit(struct mScriptStorageContext* storage) {
|
void mScriptStorageContextDeinit(struct mScriptStorageContext* storage) {
|
||||||
HashTableDeinit(&storage->buckets);
|
HashTableDeinit(&storage->buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mScriptStorageContextFlushAll(struct mScriptStorageContext* storage) {
|
||||||
|
struct TableIterator iter;
|
||||||
|
if (HashTableIteratorStart(&storage->buckets, &iter)) {
|
||||||
|
do {
|
||||||
|
struct mScriptStorageBucket* bucket = HashTableIteratorGetValue(&storage->buckets, &iter);
|
||||||
|
mScriptStorageBucketFlush(bucket);
|
||||||
|
} while (HashTableIteratorNext(&storage->buckets, &iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext* storage, const char* name) {
|
struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext* storage, const char* name) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -401,14 +466,19 @@ struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContex
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket = calloc(1, sizeof(*bucket));
|
bucket = calloc(1, sizeof(*bucket));
|
||||||
bucket->root = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
|
|
||||||
bucket->name = strdup(name);
|
bucket->name = strdup(name);
|
||||||
|
if (!mScriptStorageBucketReload(bucket)) {
|
||||||
|
bucket->root = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
|
||||||
|
}
|
||||||
HashTableInsert(&storage->buckets, name, bucket);
|
HashTableInsert(&storage->buckets, name, bucket);
|
||||||
return bucket;
|
return bucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mScriptStorageBucketDeinit(void* data) {
|
void mScriptStorageBucketDeinit(void* data) {
|
||||||
struct mScriptStorageBucket* bucket = data;
|
struct mScriptStorageBucket* bucket = data;
|
||||||
|
if (bucket->dirty) {
|
||||||
|
mScriptStorageBucketFlush(bucket);
|
||||||
|
}
|
||||||
mScriptValueDeref(bucket->root);
|
mScriptValueDeref(bucket->root);
|
||||||
free(bucket->name);
|
free(bucket->name);
|
||||||
free(bucket);
|
free(bucket);
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
mScriptContextInit(&context); \
|
mScriptContextInit(&context); \
|
||||||
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \
|
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \
|
||||||
mScriptContextAttachStdlib(&context); \
|
mScriptContextAttachStdlib(&context); \
|
||||||
mScriptContextAttachStorage(&context)
|
mScriptContextAttachStorage(&context); \
|
||||||
|
char bucketPath[PATH_MAX]; \
|
||||||
|
mScriptStorageGetBucketPath("xtest", bucketPath); \
|
||||||
|
remove(bucketPath)
|
||||||
|
|
||||||
M_TEST_SUITE_SETUP(mScriptStorage) {
|
M_TEST_SUITE_SETUP(mScriptStorage) {
|
||||||
if (mSCRIPT_ENGINE_LUA->init) {
|
if (mSCRIPT_ENGINE_LUA->init) {
|
||||||
|
|
Loading…
Reference in New Issue