1 module tagion.mobile.DocumentWrapperApi;
2 
3 import tagion.hibon.Document;
4 import tagion.hibon.HiBON;
5 import tagion.mobile.Recycle;
6 
7 // import tagion.basic.Recycle;
8 // import tagion.gossip.GossipNet;
9 // import tagion.wallet.KeyRecover;
10 import tagion.crypto.SecureNet : StdHashNet;
11 
12 // import tagion.wallet.KeyRecover;
13 
14 import core.runtime : rt_init, rt_term;
15 import core.stdc.stdlib;
16 import std.stdint;
17 import std.string : fromStringz, toStringz;
18 import tagion.basic.Types : Buffer;
19 import tagion.hibon.HiBONJSON;
20 
21 public static Recycle!Document recyclerDoc;
22 
23 enum BAD_RESULT = 0;
24 
25 string[] parse_string(const char* str, const uint len) {
26     string[] result;
27     return result;
28 }
29 
30 /// Functions called from d-lang through dart:ffi
31 extern (C) {
32 
33     /// Creating Document by ubyte array
34     export uint32_t create_test_doc() {
35         HiBON hibon = new HiBON();
36         HiBON inner_hibon = new HiBON();
37         HiBON arr_hibon = new HiBON();
38         hibon["teststr"] = "test string";
39         hibon["testnum"] = 123;
40         hibon["testpk"] = cast(Buffer)[1, 1, 1, 1];
41         const testarr = ["first", "second", "third"];
42         foreach (i, a; testarr) {
43             arr_hibon[i] = a;
44         }
45         hibon["testarr"] = Document(arr_hibon);
46         inner_hibon["teststr"] = "inner test string";
47         hibon["inner"] = Document(inner_hibon);
48         auto doc = Document(hibon);
49         if (doc.isInorder()) {
50             auto docId = recyclerDoc.create(doc);
51             return docId;
52         }
53         return BAD_RESULT;
54     }
55     /// Creating Document by ubyte array
56     export uint32_t create_doc(const uint8_t* data_ptr, const uint32_t len) {
57         immutable(ubyte)[] data = cast(immutable(ubyte)[]) data_ptr[0 .. len];
58         auto doc = Document(data);
59         if (doc.isInorder()) {
60             auto docId = recyclerDoc.create(doc);
61             return docId;
62         }
63         return BAD_RESULT;
64     }
65 
66     /// Deleting the specific Document
67     export void delete_doc_by_id(const uint32_t id) {
68         if (id !is BAD_RESULT) {
69             recyclerDoc.erase(id);
70         }
71     }
72 
73     /// Getting the int value from Document by integer index
74     export int32_t doc_get_int_by_id(const uint32_t doc_id, const uint32_t index) {
75         if (recyclerDoc(doc_id).hasMember(index)) {
76             return recyclerDoc(doc_id)[index].get!int;
77         }
78         return BAD_RESULT;
79     }
80 
81     /// Getting the int value from Document by string key
82     export int32_t doc_get_int_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
83         immutable key = cast(immutable)(key_str[0 .. len]);
84         if (recyclerDoc(doc_id).hasMember(key)) {
85             return recyclerDoc(doc_id)[key].get!int;
86         }
87         return BAD_RESULT;
88     }
89     /// Getting the ulong value from Document by string key
90     export int64_t doc_get_ulong_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
91         immutable key = cast(immutable)(key_str[0 .. len]);
92         if (recyclerDoc(doc_id).hasMember(key)) {
93             return recyclerDoc(doc_id)[key].get!ulong;
94         }
95         return BAD_RESULT;
96     }
97     /// Getting the string value from Document by index
98     /// It uses UF-16 codding
99     export const(char*) doc_get_str_by_id(const uint32_t doc_id, const uint32_t index) {
100         if (recyclerDoc(doc_id).hasMember(index)) {
101             string str = recyclerDoc(doc_id)[index].get!string;
102             return toStringz(str);
103         }
104         return null;
105     }
106 
107     /// getting the string value from Document by string key
108     /// It uses UF-16 codding
109     export const(char*) doc_get_str_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
110         immutable key = cast(immutable)(key_str[0 .. len]);
111         if (recyclerDoc(doc_id).hasMember(key)) {
112             string str = recyclerDoc(doc_id)[key].get!string;
113             return toStringz(str);
114         }
115         return null;
116     }
117 
118     /// return doc as json
119     /// It uses UF-16 codding
120     export const(char*) doc_as_json(const uint32_t doc_id) {
121         auto doc = recyclerDoc(doc_id);
122         const json = doc.toJSON.toString();
123         return toStringz(json);
124     }
125 
126     /// Getting the Document value from Document by index
127     /// It uses UF-16 codding
128     export uint64_t doc_get_docLen_by_id(const uint32_t doc_id, const uint32_t index) {
129         if (recyclerDoc(doc_id).hasMember(index)) {
130             const doc = recyclerDoc(doc_id)[index].get!Document;
131             return doc.serialize.length;
132         }
133         return BAD_RESULT;
134     }
135 
136     /// getting the Document value from Document by string key
137     /// It uses UF-16 codding
138     export uint64_t doc_get_docLen_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
139         immutable key = cast(immutable)(key_str[0 .. len]);
140         if (recyclerDoc(doc_id).hasMember(key)) {
141             const doc = recyclerDoc(doc_id)[key].get!Document;
142             return doc.serialize.length;
143         }
144         return BAD_RESULT;
145     }
146 
147     /// Getting the Document value from Document by index
148     /// It uses UF-16 codding
149     export uint8_t* doc_get_docPtr_by_id(const uint32_t doc_id, const uint32_t index) {
150         if (recyclerDoc(doc_id).hasMember(index)) {
151             const doc = recyclerDoc(doc_id)[index].get!Document;
152             return cast(ubyte*) doc.serialize.ptr;
153         }
154         return null;
155     }
156 
157     /// getting the Document value from Document by string key
158     /// It uses UF-16 codding
159     export uint8_t* doc_get_docPtr_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
160         immutable key = cast(immutable)(key_str[0 .. len]);
161         if (recyclerDoc(doc_id).hasMember(key)) {
162             const doc = recyclerDoc(doc_id)[key].get!Document;
163             return cast(ubyte*) doc.serialize.ptr;
164         }
165         return null;
166     }
167 
168     /// getting the Document value
169     /// It uses UF-16 codding
170     export uint64_t get_docLen(const uint32_t doc_id) {
171         const doc = recyclerDoc(doc_id);
172         return doc.serialize.length;
173     }
174 
175     /// getting the Document value
176     /// It uses UF-16 codding
177     export uint8_t* get_docPtr(const uint32_t doc_id) {
178         const doc = recyclerDoc(doc_id);
179         return cast(ubyte*) doc.serialize.ptr;
180     }
181 
182     export uint64_t doc_get_bufferLen_by_id(const uint32_t doc_id, const uint32_t index) {
183         if (recyclerDoc(doc_id).hasMember(index)) {
184             const buf = recyclerDoc(doc_id)[index].get!Buffer;
185             return buf.length;
186         }
187         return BAD_RESULT;
188     }
189 
190     export uint64_t doc_get_bufferLen_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
191         immutable key = cast(immutable)(key_str[0 .. len]);
192         if (recyclerDoc(doc_id).hasMember(key)) {
193             const buf = recyclerDoc(doc_id)[key].get!Buffer;
194             return buf.length;
195         }
196         return BAD_RESULT;
197     }
198 
199     export uint8_t* doc_get_bufferPtr_by_id(const uint32_t doc_id, const uint32_t index) {
200         if (recyclerDoc(doc_id).hasMember(index)) {
201             const doc = recyclerDoc(doc_id)[index].get!Buffer;
202             return cast(ubyte*) doc.ptr;
203         }
204         return null;
205     }
206 
207     export uint8_t* doc_get_bufferPtr_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) {
208         immutable key = cast(immutable)(key_str[0 .. len]);
209         if (recyclerDoc(doc_id).hasMember(key)) {
210             const doc = recyclerDoc(doc_id)[key].get!Buffer;
211             return cast(ubyte*) doc.ptr;
212         }
213         return null;
214     }
215 
216     export uint64_t doc_get_memberCount(const uint32_t doc_id) {
217         return recyclerDoc(doc_id).length;
218     }
219     // /// Getting the keys of Document
220     // /// It uses UF-16 codding
221     // export const(char*) doc_get_keys(const uint32_t doc_id)
222     // {
223     //     if (recyclerDoc.exists(doc_id))
224     //     {
225     //         string[] keys = recyclerDoc(doc_id).keys();
226     //         string keysStr = join(keys, ";");
227     //         return toStringz(keysStr);
228     //     }
229     //     return null;
230     // }
231 }
232 
233 pragma(msg, "fixme(cbr): This unittest does not pass");
234 version (none) unittest {
235     pragma(msg, "fixme(cbr): Fix this unittest ");
236     import std.stdio : writefln, writeln;
237     import std.string : fromStringz;
238     import tagion.hibon.HiBON : HiBON;
239 
240     // Aux HiBON for testing
241     auto hib = new HiBON;
242     hib["doc2"] = "test_str_with_key";
243 
244     // Tests for create_doc()
245     {
246         // Test for null request
247         assert(create_doc(null, 0) is 1);
248 
249         // Test for empty array
250         const(ubyte)[] empty_data = new ubyte[0];
251         assert(create_doc(empty_data.ptr, 0) is 2);
252 
253         // Tests for ubytes' sequence
254         // const data1 = hib.serialize;
255         // const data2 = hib.serialize;
256 
257         // const doc_id_data_1 = create_doc(data1.ptr, cast(uint)data1.length);
258         // const doc_id_data_2 = create_doc(data2.ptr, cast(uint)data2.length);
259 
260         // writefln("doc_id_data_1=%d", doc_id_data_1);
261         // writefln("doc_id_data_2=%d", doc_id_data_2);
262         //assert(create_doc(data1.ptr, data1.length) is 2);
263         //assert(create_doc(data2.ptr, data2.length) is 3);
264     }
265 
266     // Tests for delete_doc_by_id()
267     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
268     version (none) {
269 
270         assert(recyclerDoc.exists(1));
271         assert(recyclerDoc.exists(2));
272 
273         delete_doc_by_id(1);
274         delete_doc_by_id(2);
275 
276         assert(!recyclerDoc.exists(1));
277         assert(!recyclerDoc.exists(2));
278 
279         // Append two docs and check whether they exists by indicies
280         const data = hib.serialize;
281         const doc_id_data_a = create_doc(data.ptr, cast(uint) data.length);
282         writefln("doc_id_0=%d", doc_id_data_a);
283         assert(recyclerDoc.exists(doc_id_data_a));
284 
285         const doc_id_data_b = create_doc(data.ptr, cast(uint) data.length);
286         writefln("doc_id_1=%d", doc_id_data_b);
287         assert(recyclerDoc.exists(doc_id_data_b));
288     }
289     // Range of Document' indexes in RecyclerDoc [0 .. 3]
290 
291     // Tests for doc_get_int_by_key()
292     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
293     version (none) {
294 
295         assert(doc_get_int_by_key(0, "doc1", 4) is 100);
296         assert(doc_get_int_by_key(1, "doc1", 4) is 100);
297         assert(doc_get_int_by_key(2, "doc1", 4) is 100);
298         assert(doc_get_int_by_key(3, "doc1", 4) is 100);
299 
300         // Testing an absense of the key
301         assert(doc_get_int_by_key(0, "doc", 3) is BAD_RESULT);
302         assert(doc_get_int_by_key(1, "doc", 3) is BAD_RESULT);
303         assert(doc_get_int_by_key(2, "doc", 3) is BAD_RESULT);
304         assert(doc_get_int_by_key(3, "doc", 3) is BAD_RESULT);
305 
306         // Testing a wrong key size with correct key
307         assert(doc_get_int_by_key(0, "doc1", 3) is BAD_RESULT);
308         assert(doc_get_int_by_key(1, "doc1", 3) is BAD_RESULT);
309         assert(doc_get_int_by_key(2, "doc1", 3) is BAD_RESULT);
310         assert(doc_get_int_by_key(3, "doc1", 3) is BAD_RESULT);
311 
312         // Testing a wrong key size with incorrect key
313         assert(doc_get_int_by_key(0, "doc", 10) is BAD_RESULT);
314         assert(doc_get_int_by_key(1, "doc", 10) is BAD_RESULT);
315         assert(doc_get_int_by_key(2, "doc", 10) is BAD_RESULT);
316         assert(doc_get_int_by_key(3, "doc", 10) is BAD_RESULT);
317     }
318 
319     // Tests for doc_get_int_by_id()
320     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
321     version (none) {
322         assert(doc_get_int_by_id(0, 1) is 101);
323         assert(doc_get_int_by_id(1, 1) is 101);
324         assert(doc_get_int_by_id(2, 1) is 101);
325         assert(doc_get_int_by_id(3, 1) is 101);
326 
327         // Testing an absense of the key
328         assert(doc_get_int_by_id(0, 3) is BAD_RESULT);
329         assert(doc_get_int_by_id(1, 3) is BAD_RESULT);
330         assert(doc_get_int_by_id(2, 3) is BAD_RESULT);
331         assert(doc_get_int_by_id(3, 3) is BAD_RESULT);
332     }
333 
334     // Tests for doc_get_str_by_id()
335     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
336     version (none) {
337         const(char)[] expected_str = "test_str_with_id";
338 
339         assert(fromStringz(doc_get_str_by_id(0, 2)) == expected_str);
340         assert(fromStringz(doc_get_str_by_id(1, 2)) == expected_str);
341         assert(fromStringz(doc_get_str_by_id(2, 2)) == expected_str);
342         assert(fromStringz(doc_get_str_by_id(3, 2)) == expected_str);
343 
344         // Testing an existed document with wrong id
345         assert(doc_get_str_by_id(0, 0) is null);
346         assert(doc_get_str_by_id(1, 0) is null);
347         assert(doc_get_str_by_id(2, 0) is null);
348         assert(doc_get_str_by_id(3, 0) is null);
349     }
350 
351     // Tests for doc_get_str_by_key()
352     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
353     version (none) {
354         const(char)[] expected_str = "test_str_with_key";
355 
356         assert(fromStringz(doc_get_str_by_key(0, "doc2", 4)) == expected_str);
357         assert(fromStringz(doc_get_str_by_key(1, "doc2", 4)) == expected_str);
358         assert(fromStringz(doc_get_str_by_key(2, "doc2", 4)) == expected_str);
359         assert(fromStringz(doc_get_str_by_key(3, "doc2", 4)) == expected_str);
360 
361         // Testing an absense of the key
362         assert(doc_get_str_by_key(0, "doc", 3) is null);
363         assert(doc_get_str_by_key(1, "doc", 3) is null);
364         assert(doc_get_str_by_key(2, "doc", 3) is null);
365         assert(doc_get_str_by_key(3, "doc", 3) is null);
366 
367         // Testing a wrong key's size with correct key
368         assert(doc_get_str_by_key(0, "doc2", 3) is null);
369         assert(doc_get_str_by_key(1, "doc2", 3) is null);
370         assert(doc_get_str_by_key(2, "doc2", 3) is null);
371         assert(doc_get_str_by_key(3, "doc2", 3) is null);
372 
373         // Testing a wrong key's size with incorrect key
374         assert(doc_get_str_by_key(0, "doc", 10) is null);
375         assert(doc_get_str_by_key(1, "doc", 10) is null);
376         assert(doc_get_str_by_key(2, "doc", 10) is null);
377         assert(doc_get_str_by_key(3, "doc", 10) is null);
378     }
379 
380     pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")");
381     version (none) {
382         import std.algorithm;
383 
384         auto hib1 = new HiBON;
385         hib1["test"] = "test";
386         hib["doc3"] = Document(hib1);
387         const expected = hib1.serialize;
388 
389         const data = hib.serialize;
390         auto index = create_doc(data.ptr, cast(uint) data.length);
391 
392         const docLen = doc_get_docLen_by_key(index, "test", 4);
393         immutable docPtr = cast(immutable) doc_get_docPtr_by_key(index, "test", 4);
394         const doc = Document(docPtr[0 .. cast(uint) docLen]);
395         assert(equal(expected, doc.serialize));
396     }
397 }