mirror of
https://github.com/Expand-sys/CCash
synced 2025-12-17 00:22:14 +11:00
Compare commits
957 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f85e13f11 | ||
|
|
7fcb761aa2 | ||
|
|
caf1d65e16 | ||
|
|
a61a590f3a | ||
|
|
32f5f2a2be | ||
|
|
a98b84955c | ||
|
|
c970b6a42f | ||
|
|
f2da8cdbc2 | ||
|
|
af551ef8b4 | ||
|
|
511aa76795 | ||
|
|
eea9c4b566 | ||
|
|
cb5d12d4dc | ||
|
|
01aedef7a3 | ||
|
|
6ddcf08797 | ||
|
|
4a41cb1ef4 | ||
|
|
dda98f346e | ||
|
|
2419641cd0 | ||
|
|
6dad3ed0af | ||
|
|
88458de0f0 | ||
|
|
47649d6ccd | ||
|
|
370107e3f9 | ||
|
|
8fea062a3f | ||
|
|
779ab90b8f | ||
|
|
0d346b820f | ||
|
|
c659c9b7bd | ||
|
|
5e996b2705 | ||
|
|
7e1954d651 | ||
|
|
ad3bb2c13b | ||
|
|
b74510a113 | ||
|
|
4aa55486c9 | ||
|
|
e413c089dc | ||
|
|
a195e8c5a2 | ||
|
|
396b676ee5 | ||
|
|
dce87bbcfa | ||
|
|
705a746a3c | ||
|
|
6e6d722f9f | ||
|
|
70ac88e894 | ||
|
|
6f1bd193d5 | ||
|
|
69a2f81454 | ||
|
|
113f42a399 | ||
|
|
3629b78e38 | ||
|
|
282bd5e423 | ||
|
|
b656bb7e43 | ||
|
|
3b46c97d0a | ||
|
|
3e73d08227 | ||
|
|
82e3a6384c | ||
|
|
d303016124 | ||
|
|
66b21332b3 | ||
|
|
34039f9fcf | ||
|
|
ce65a4387c | ||
|
|
95c2d47216 | ||
|
|
8696c5d870 | ||
|
|
dbe755da2b | ||
|
|
24665641b4 | ||
|
|
026d2b8493 | ||
|
|
99f47dc6ed | ||
|
|
d8e88ec375 | ||
|
|
8ff1fddf7a | ||
|
|
07b9e20e31 | ||
|
|
83455a0510 | ||
|
|
cc103c7298 | ||
|
|
10c3c6a536 | ||
|
|
21fd1c94e4 | ||
|
|
b69092d732 | ||
|
|
472a9222fc | ||
|
|
878a71f310 | ||
|
|
411d1996c7 | ||
|
|
722f8d0f48 | ||
|
|
aefdb4ce9b | ||
|
|
76388c6423 | ||
|
|
ff0dfc8a93 | ||
|
|
5e253e42d9 | ||
|
|
d63be0ec73 | ||
|
|
4ca1bbe6eb | ||
|
|
54acbf8cc6 | ||
|
|
2c62c89b47 | ||
|
|
37b110d36f | ||
|
|
8e44a3d446 | ||
|
|
e20ac4cebc | ||
|
|
19b6acc48f | ||
|
|
ed0d5c8231 | ||
|
|
6d9c6d6c1c | ||
|
|
04fe7376ec | ||
|
|
292b73001e | ||
|
|
c8791ec7ce | ||
|
|
a308f830c0 | ||
|
|
a49a1730f7 | ||
|
|
0b7de8b905 | ||
|
|
b674a6dded | ||
|
|
49b5b7d35d | ||
|
|
f9aa33afac | ||
|
|
da65fb678a | ||
|
|
7850c721e5 | ||
|
|
09422995e8 | ||
|
|
d5f5b41e20 | ||
|
|
7d4a564513 | ||
|
|
a68e86b216 | ||
|
|
a9e3ca1665 | ||
|
|
f6d8673045 | ||
|
|
206698697b | ||
|
|
f1b03ecb41 | ||
|
|
94c2cb1f65 | ||
|
|
7c31b4d680 | ||
|
|
b874af86af | ||
|
|
73a80de08e | ||
|
|
35c50ac0f4 | ||
|
|
4892ec2655 | ||
|
|
d46fe68559 | ||
|
|
52677f0576 | ||
|
|
d2f0989a15 | ||
|
|
ecb602d6f2 | ||
|
|
a068502643 | ||
|
|
49816dc18c | ||
|
|
e100444042 | ||
|
|
4fd3eb2bd8 | ||
|
|
cf4ba5ccfa | ||
|
|
244ca2561c | ||
|
|
b584f5b4d5 | ||
|
|
ab27971d8e | ||
|
|
7387156d15 | ||
|
|
47d544070b | ||
|
|
1f983322a1 | ||
|
|
5a754a567c | ||
|
|
83f149677d | ||
|
|
61134740f0 | ||
|
|
78b62092b3 | ||
|
|
1b2c763f0b | ||
|
|
a8b7defb36 | ||
|
|
1498d3d028 | ||
|
|
dffd20511d | ||
|
|
6c8ebfa57c | ||
|
|
decfd83931 | ||
|
|
89448a4b12 | ||
|
|
2fa6a7a743 | ||
|
|
d56599f49a | ||
|
|
df21ce4131 | ||
|
|
dcbb65ab6f | ||
|
|
5999a00d68 | ||
|
|
e04cd1af04 | ||
|
|
90add46113 | ||
|
|
c0b02fa7aa | ||
|
|
9761aa93b5 | ||
|
|
e536bb94fb | ||
|
|
279481532e | ||
|
|
0fc044fdda | ||
|
|
5e71954391 | ||
|
|
c9f7e103ce | ||
|
|
6cf167b42d | ||
|
|
3f08055dd0 | ||
|
|
1776eaea2f | ||
|
|
50c88aa32f | ||
|
|
46c97fd813 | ||
|
|
e8576b76f8 | ||
|
|
d71d74678e | ||
|
|
32e91a188a | ||
|
|
5026285d1b | ||
|
|
38dfed90cb | ||
|
|
7cba136a78 | ||
|
|
3d3ee3cc0a | ||
|
|
44af19bfd5 | ||
|
|
de3ec4a5c9 | ||
|
|
93c0b39e11 | ||
|
|
f1c22cb136 | ||
|
|
8975564876 | ||
|
|
8c911675c7 | ||
|
|
1d76bc54bd | ||
|
|
ec0d5900c1 | ||
|
|
b4a72649fd | ||
|
|
9e5378eb74 | ||
|
|
d5aeef7868 | ||
|
|
25e765d6b3 | ||
|
|
ca303d8599 | ||
|
|
520e008f25 | ||
|
|
ac559d1d9a | ||
|
|
7489b6d93b | ||
|
|
06d62097c4 | ||
|
|
d88538d0db | ||
|
|
01efbb7dd4 | ||
|
|
474b8b0d47 | ||
|
|
4d54da90b8 | ||
|
|
308f75ec37 | ||
|
|
a4a9473b07 | ||
|
|
c083d78ac1 | ||
|
|
348c3b6e12 | ||
|
|
b8ba5d49b5 | ||
|
|
0f918f6b24 | ||
|
|
7e617f9c34 | ||
|
|
fc7b03fa1a | ||
|
|
f551df92cb | ||
|
|
5114e19737 | ||
|
|
ae7f3e7cfa | ||
|
|
2823a6fe3f | ||
|
|
2089b5ed97 | ||
|
|
491e4bcc85 | ||
|
|
7d26eb9341 | ||
|
|
4914490b42 | ||
|
|
e399a5bc16 | ||
|
|
09408ae800 | ||
|
|
5f74e0ce12 | ||
|
|
88f67ae992 | ||
|
|
b0ce1acb56 | ||
|
|
0fb70a9ba9 | ||
|
|
942e6b702a | ||
|
|
ab41a7ed46 | ||
|
|
f951bc6845 | ||
|
|
f8dfe184a4 | ||
|
|
7e06ae704c | ||
|
|
0db2fa7130 | ||
|
|
c6b58d60cd | ||
|
|
b7f2ad3b5f | ||
|
|
d4638278d4 | ||
|
|
c323e49451 | ||
|
|
d543ab0a89 | ||
|
|
b821607d60 | ||
|
|
ec2abe8750 | ||
|
|
956165ea6d | ||
|
|
f6cc2b2f52 | ||
|
|
8ad656624d | ||
|
|
b3cc2b2cb5 | ||
|
|
96d3c1de08 | ||
|
|
4cfc27e01e | ||
|
|
be90601801 | ||
|
|
9a67d223dc | ||
|
|
24053efeb8 | ||
|
|
220c998312 | ||
|
|
61345092f5 | ||
|
|
b409d42c96 | ||
|
|
9f1c1b1edc | ||
|
|
447a9becc8 | ||
|
|
1890ba1ca6 | ||
|
|
2156afa774 | ||
|
|
01bc8dfc26 | ||
|
|
d485e3a21d | ||
|
|
e780a1546c | ||
|
|
a05ad5fc3d | ||
|
|
6e7a263907 | ||
|
|
7d0d78c698 | ||
|
|
385d8a0027 | ||
|
|
edd65e1a2b | ||
|
|
28d1fca04b | ||
|
|
e717a0ad2c | ||
|
|
7ce9a71118 | ||
|
|
0f50e00b6c | ||
|
|
37d885d81d | ||
|
|
edee4f2e0d | ||
|
|
0f28a0cc19 | ||
|
|
1120b7b4d0 | ||
|
|
72ed06aff6 | ||
|
|
7760a8e8ca | ||
|
|
2d84be675a | ||
|
|
0cae801ba3 | ||
|
|
4086a1d324 | ||
|
|
8abee602b7 | ||
|
|
545958c2de | ||
|
|
dbaa6c6beb | ||
|
|
2b7330f48a | ||
|
|
86ab683704 | ||
|
|
ce9b431cfe | ||
|
|
7a0a5d4036 | ||
|
|
f48ad92f25 | ||
|
|
948aa93cc2 | ||
|
|
5e7243c55a | ||
|
|
4b43ecf11c | ||
|
|
2161482fdd | ||
|
|
2f6579ea88 | ||
|
|
bd63f39d02 | ||
|
|
293414953d | ||
|
|
0beef17226 | ||
|
|
051a26c7cd | ||
|
|
212bfc7ce9 | ||
|
|
613123ba64 | ||
|
|
67183d88eb | ||
|
|
88ec95968c | ||
|
|
d544a10bf1 | ||
|
|
a122a8e8a9 | ||
|
|
6da7cd087c | ||
|
|
cb88bc8495 | ||
|
|
c787f4476f | ||
|
|
5feb20754a | ||
|
|
a5da4c9a04 | ||
|
|
e610615e5f | ||
|
|
b66f2dc562 | ||
|
|
dc9b2e70c2 | ||
|
|
3bb7640cd6 | ||
|
|
a37825fd51 | ||
|
|
d296e1da17 | ||
|
|
196b6b43f4 | ||
|
|
5a488814c4 | ||
|
|
1406c291d7 | ||
|
|
1df473f49a | ||
|
|
9212edb9a3 | ||
|
|
0c15121ef0 | ||
|
|
5704d4668a | ||
|
|
8a7a4680e0 | ||
|
|
72864e6c18 | ||
|
|
c99e542111 | ||
|
|
14b1bff364 | ||
|
|
34099acd02 | ||
|
|
91609f1840 | ||
|
|
8190f18408 | ||
|
|
d63dd6a540 | ||
|
|
a1acb6ff0e | ||
|
|
50a0aeb0c3 | ||
|
|
feb60c13a1 | ||
|
|
5596e5395a | ||
|
|
ba62ff5ab9 | ||
|
|
b74db4cf7d | ||
|
|
e4f022cf46 | ||
|
|
8c660595c9 | ||
|
|
62efbd396d | ||
|
|
7db986dcf6 | ||
|
|
643f3925b9 | ||
|
|
9da47134af | ||
|
|
2daed041f9 | ||
|
|
598f73ff22 | ||
|
|
ef69b29761 | ||
|
|
5eaf38baab | ||
|
|
a93e6a3796 | ||
|
|
97fde5cdcc | ||
|
|
9e359e40f5 | ||
|
|
c1c456aca4 | ||
|
|
ededc24be4 | ||
|
|
e3c7336f03 | ||
|
|
024ffe8bb9 | ||
|
|
dc399184cf | ||
|
|
efca0b8034 | ||
|
|
47e84ced7a | ||
|
|
b7d75bfe74 | ||
|
|
54c8f95b6c | ||
|
|
018e8dac83 | ||
|
|
c11bf24d90 | ||
|
|
335fd4983c | ||
|
|
3650bff3f0 | ||
|
|
03767fb61d | ||
|
|
c69c717ed1 | ||
|
|
b64c18fc22 | ||
|
|
54e59e47b2 | ||
|
|
86fa298e04 | ||
|
|
c2da258143 | ||
|
|
9554fd0cc6 | ||
|
|
22d1c27af2 | ||
|
|
cc9196dce5 | ||
|
|
347c9490fd | ||
|
|
74b45a1775 | ||
|
|
14287cf7b4 | ||
|
|
df601fad65 | ||
|
|
83d2ad4262 | ||
|
|
a4670cb5f6 | ||
|
|
162b421c8b | ||
|
|
822a0d2647 | ||
|
|
89f268889c | ||
|
|
4ca3ac2528 | ||
|
|
74f97ecac9 | ||
|
|
98c7763ae2 | ||
|
|
93cc7fcadf | ||
|
|
88b5253e02 | ||
|
|
4cfa499127 | ||
|
|
66fa73ed24 | ||
|
|
321efcd363 | ||
|
|
2d62f51006 | ||
|
|
cc17c3f8d3 | ||
|
|
559318d615 | ||
|
|
e0b38be7e6 | ||
|
|
0f128e04a0 | ||
|
|
3d8dc99874 | ||
|
|
9c520d5e05 | ||
|
|
21abb82c76 | ||
|
|
bf8ecccbb8 | ||
|
|
8fb7687d42 | ||
|
|
9223c520b1 | ||
|
|
2599897788 | ||
|
|
cbcfc1118c | ||
|
|
9443fce984 | ||
|
|
ab1e154ab8 | ||
|
|
30c4344055 | ||
|
|
35b9af952b | ||
|
|
727e4ab4b8 | ||
|
|
78f7f34f63 | ||
|
|
5bc3511c43 | ||
|
|
8d52d8f5e3 | ||
|
|
0130f3c971 | ||
|
|
e04dcc926d | ||
|
|
a78afc314e | ||
|
|
98215b9711 | ||
|
|
23da8c686f | ||
|
|
15ef40b143 | ||
|
|
732984a45d | ||
|
|
521f8614dd | ||
|
|
6c99d32a64 | ||
|
|
4a56d57314 | ||
|
|
e5302af958 | ||
|
|
22d1e02460 | ||
|
|
8935b0cb4d | ||
|
|
e112468395 | ||
|
|
fa1a9e6728 | ||
|
|
91aa848d0b | ||
|
|
f183235b94 | ||
|
|
bafb4b801d | ||
|
|
d949783828 | ||
|
|
0ed5d5342b | ||
|
|
6e8b3357c9 | ||
|
|
a65224d39e | ||
|
|
0954a76b6a | ||
|
|
0f3a89b770 | ||
|
|
a46801daea | ||
|
|
c94c19cbe1 | ||
|
|
2f699e70c8 | ||
|
|
df5dae02d0 | ||
|
|
b2741aa276 | ||
|
|
9b573ed7c3 | ||
|
|
6f8475ad1d | ||
|
|
b2f306aee5 | ||
|
|
66b200be27 | ||
|
|
eb282de108 | ||
|
|
c2d8742138 | ||
|
|
16d26d1901 | ||
|
|
70d0374dd7 | ||
|
|
a2e0149606 | ||
|
|
31f8a67dfb | ||
|
|
7be15963d0 | ||
|
|
f0c8920da1 | ||
|
|
9318314d0c | ||
|
|
8217bb2360 | ||
|
|
495403864f | ||
|
|
03d9c2aace | ||
|
|
c63fab572f | ||
|
|
40bf5a22b0 | ||
|
|
8428f7e71c | ||
|
|
4f27fd3d23 | ||
|
|
dc85a3211a | ||
|
|
2b28822239 | ||
|
|
4b6c71354f | ||
|
|
8a23c8fa00 | ||
|
|
94e6b3da44 | ||
|
|
c258f6ec86 | ||
|
|
f7dbd4c3e0 | ||
|
|
4b7ef754c0 | ||
|
|
72d57ce118 | ||
|
|
d5a7cf0481 | ||
|
|
b625e79c48 | ||
|
|
52bc5eeffb | ||
|
|
7145e66103 | ||
|
|
dd66144a3b | ||
|
|
8c97d19330 | ||
|
|
8a6f9f2fce | ||
|
|
9927bd8217 | ||
|
|
8063a344aa | ||
|
|
36e2f6301f | ||
|
|
6599f47dcc | ||
|
|
3a44c0b065 | ||
|
|
c1587f9e46 | ||
|
|
518c1b1203 | ||
|
|
f87ec947b6 | ||
|
|
cfdb2fe829 | ||
|
|
82312b8702 | ||
|
|
c54f75a909 | ||
|
|
b91e928286 | ||
|
|
5a6a4180a0 | ||
|
|
2d8cb3ee28 | ||
|
|
13d66b537c | ||
|
|
074d024d77 | ||
|
|
e0c79f980d | ||
|
|
6225083a06 | ||
|
|
408ea473d5 | ||
|
|
386a140255 | ||
|
|
1f0a3dc28d | ||
|
|
2d7d29372c | ||
|
|
2e991da613 | ||
|
|
db5a54175c | ||
|
|
2fe00e05de | ||
|
|
71e0915c2a | ||
|
|
50a4e49452 | ||
|
|
c7e2794e56 | ||
|
|
b60b6293aa | ||
|
|
ba014df089 | ||
|
|
5b7d4b9af8 | ||
|
|
7d61ee5f83 | ||
|
|
a46adc28f9 | ||
|
|
39fb5e96a1 | ||
|
|
7803c5e1e5 | ||
|
|
f2b5385e92 | ||
|
|
1d826fe96e | ||
|
|
18452fdf1e | ||
|
|
dc6c3d70a0 | ||
|
|
1d6bbb35bf | ||
|
|
6e57178dc8 | ||
|
|
b1f0aad79e | ||
|
|
a657c9d6b2 | ||
|
|
6b11a9dadc | ||
|
|
b8e88ad1f5 | ||
|
|
16494f971e | ||
|
|
175976e796 | ||
|
|
da89d390ea | ||
|
|
053c20130e | ||
|
|
fd6d085ae5 | ||
|
|
805a7d05b3 | ||
|
|
35ab4d9492 | ||
|
|
22c99cfbfb | ||
|
|
3a39a2bf67 | ||
|
|
7e1ab2a38b | ||
|
|
96f9351fb6 | ||
|
|
91523ca6a5 | ||
|
|
dba161c42c | ||
|
|
6e688f1385 | ||
|
|
826db0baef | ||
|
|
6b481802e5 | ||
|
|
b18ec4e26d | ||
|
|
a1df11eeeb | ||
|
|
51a9ab8ff8 | ||
|
|
9ee4f7ab88 | ||
|
|
85e3dc038c | ||
|
|
d649613d2e | ||
|
|
bb6b2f6c44 | ||
|
|
4944655af9 | ||
|
|
b0fdfc5f4f | ||
|
|
bd87a14131 | ||
|
|
6af072cf66 | ||
|
|
23b6362d91 | ||
|
|
bb7bd5daab | ||
|
|
9fabf137f1 | ||
|
|
f4f28fa92f | ||
|
|
e3210f7337 | ||
|
|
0c518c4ede | ||
|
|
e9443ee48d | ||
|
|
812ffcd5a0 | ||
|
|
a0307f211d | ||
|
|
2681ca86c2 | ||
|
|
dedff14e7e | ||
|
|
e02120b6f2 | ||
|
|
e3e4059c26 | ||
|
|
e502f3ce1f | ||
|
|
6dbb9fd98a | ||
|
|
18b7923d7f | ||
|
|
5ab0f89e89 | ||
|
|
80cc3a99cf | ||
|
|
09911d5496 | ||
|
|
4b5e5d930c | ||
|
|
67a3d02c82 | ||
|
|
30801e6730 | ||
|
|
15c648d6fa | ||
|
|
bf5c2fde33 | ||
|
|
7ad83bfb63 | ||
|
|
2237d7a875 | ||
|
|
73ebb6e5bd | ||
|
|
ff89efe4fc | ||
|
|
f431d8bcda | ||
|
|
14618ac991 | ||
|
|
c7e5b68144 | ||
|
|
28dadac225 | ||
|
|
448149e60d | ||
|
|
f84d48e624 | ||
|
|
2d186afa94 | ||
|
|
46fcb1f443 | ||
|
|
99f35a11df | ||
|
|
ae219af90e | ||
|
|
cf580ae876 | ||
|
|
c82a90f054 | ||
|
|
9fce1fd083 | ||
|
|
392708dfcc | ||
|
|
cca2bf6216 | ||
|
|
99af2c02ab | ||
|
|
c29abc34e0 | ||
|
|
597a710e2b | ||
|
|
94fce9cd1f | ||
|
|
4c3b521966 | ||
|
|
cb06dd31dd | ||
|
|
297b184a11 | ||
|
|
e9ccf6b227 | ||
|
|
da2074859e | ||
|
|
6bc6c78ed7 | ||
|
|
a98a813189 | ||
|
|
1a7a3e50ed | ||
|
|
9634d95d67 | ||
|
|
76fc8084ce | ||
|
|
fd2efb3ddf | ||
|
|
c8894e7d31 | ||
|
|
6926cf8791 | ||
|
|
ff01ff5189 | ||
|
|
d25ff09bdf | ||
|
|
f6a6c23fc3 | ||
|
|
a37742193f | ||
|
|
aece911b90 | ||
|
|
1f5f052de1 | ||
|
|
a5d06bfa70 | ||
|
|
1f39a353e5 | ||
|
|
e7f61d38ee | ||
|
|
44a916b09f | ||
|
|
7abca3126b | ||
|
|
bb0f3b642d | ||
|
|
53524e8409 | ||
|
|
4976d5bca6 | ||
|
|
f0772ed6f0 | ||
|
|
9a62f9e7ed | ||
|
|
2d464df178 | ||
|
|
6eb02a8288 | ||
|
|
97fd39b1d4 | ||
|
|
b310c8ec2b | ||
|
|
84ecfac199 | ||
|
|
5275028fd6 | ||
|
|
27f0c951ad | ||
|
|
0eea88e75c | ||
|
|
8342c461da | ||
|
|
92d629758b | ||
|
|
cef439ef8b | ||
|
|
d39247a3b4 | ||
|
|
3edd25dbe8 | ||
|
|
6026e6aad5 | ||
|
|
84ebf306e2 | ||
|
|
1bc27efbba | ||
|
|
b9baf2dd78 | ||
|
|
73d0af5ac4 | ||
|
|
3b2e57edde | ||
|
|
317233be67 | ||
|
|
3537504bfc | ||
|
|
65a204022b | ||
|
|
0a246bd5bb | ||
|
|
c0b785f5f1 | ||
|
|
4801cbd3bf | ||
|
|
a8c041249c | ||
|
|
79932f5223 | ||
|
|
01f7be1d5c | ||
|
|
8e92dccd88 | ||
|
|
5f745ee03b | ||
|
|
86d4b96b7b | ||
|
|
34d48bd235 | ||
|
|
6a8b5da869 | ||
|
|
b6344da31d | ||
|
|
c9562d26c7 | ||
|
|
e81a7b281e | ||
|
|
e87ab53a8a | ||
|
|
b0ba114445 | ||
|
|
d6a55652ca | ||
|
|
77c6923765 | ||
|
|
62d68924af | ||
|
|
65d21848b3 | ||
|
|
b9af380b64 | ||
|
|
6402ad300c | ||
|
|
ea35a04b66 | ||
|
|
29044d697c | ||
|
|
46b48b1d6f | ||
|
|
617b52ac93 | ||
|
|
f0a296d97b | ||
|
|
8b30588d8f | ||
|
|
89e4da34bf | ||
|
|
85ee2167ff | ||
|
|
244852eb45 | ||
|
|
239e8007e9 | ||
|
|
a561742347 | ||
|
|
029a10f1bc | ||
|
|
e157586557 | ||
|
|
8c373d6f19 | ||
|
|
f04ca463fe | ||
|
|
5c1a9264d3 | ||
|
|
b90552d0d4 | ||
|
|
7c0b4f48bd | ||
|
|
007f7098ce | ||
|
|
b2fcd69a57 | ||
|
|
ee8bd88c96 | ||
|
|
2d9fc33835 | ||
|
|
aecdea522d | ||
|
|
770027473e | ||
|
|
0b59e273f0 | ||
|
|
5ac2dcb55b | ||
|
|
3f8fad0dbf | ||
|
|
e7643bc793 | ||
|
|
f3c3c47e73 | ||
|
|
5fe22d8635 | ||
|
|
ca6187fffc | ||
|
|
88e5cfc3d3 | ||
|
|
fd657dd9bf | ||
|
|
1b950ce0c0 | ||
|
|
7d1ec6d634 | ||
|
|
0e5836b777 | ||
|
|
10537fb942 | ||
|
|
72cbbd5494 | ||
|
|
1c5f2e1ae6 | ||
|
|
5ffd655de5 | ||
|
|
3a3b168e49 | ||
|
|
6eacdb6d1e | ||
|
|
fe98e73319 | ||
|
|
89ca26b9e6 | ||
|
|
69ff81c727 | ||
|
|
ec9944d80e | ||
|
|
c63bc137c4 | ||
|
|
290d6da0ef | ||
|
|
fc762871ff | ||
|
|
55d71c7a6d | ||
|
|
c51074d47c | ||
|
|
f97915591a | ||
|
|
aa71a9f538 | ||
|
|
1a77ca43dc | ||
|
|
c9da3eab04 | ||
|
|
e7f7f0f698 | ||
|
|
88a3d79f9c | ||
|
|
3e0efa780b | ||
|
|
d93786f4ff | ||
|
|
00a3d0c075 | ||
|
|
d13100ccea | ||
|
|
9c467020d4 | ||
|
|
f19ed761e2 | ||
|
|
541efad1ff | ||
|
|
d3393e8084 | ||
|
|
f62465419e | ||
|
|
60540f810f | ||
|
|
1cc1a41561 | ||
|
|
1f49a9b79a | ||
|
|
a00a98298a | ||
|
|
de694c6ebd | ||
|
|
766047dc07 | ||
|
|
117bd33ca0 | ||
|
|
8d6921b70d | ||
|
|
c13164dde8 | ||
|
|
58c16457cf | ||
|
|
2bed29edd0 | ||
|
|
bec9538bc9 | ||
|
|
e8941d60cd | ||
|
|
58e00e3b75 | ||
|
|
0e62dbe9ef | ||
|
|
0c34bc3689 | ||
|
|
6e46cb8f7a | ||
|
|
23928235eb | ||
|
|
d5490ebc56 | ||
|
|
1adb23f5b8 | ||
|
|
ba20e461f6 | ||
|
|
1ea1618228 | ||
|
|
541b912efe | ||
|
|
3b1a459e18 | ||
|
|
6d6b55025b | ||
|
|
113a765c14 | ||
|
|
731132e719 | ||
|
|
1aa450e112 | ||
|
|
1a434c6bcb | ||
|
|
deae9fab7c | ||
|
|
3028c6153a | ||
|
|
a4964d2742 | ||
|
|
482e8709a7 | ||
|
|
d92bc60e79 | ||
|
|
d9986db962 | ||
|
|
539df650ea | ||
|
|
7dec3bea72 | ||
|
|
371cd16e38 | ||
|
|
a32efe611f | ||
|
|
40863d5dda | ||
|
|
c8b7935329 | ||
|
|
dfdeba08bd | ||
|
|
b64e562235 | ||
|
|
749d20880f | ||
|
|
faf63b0d4b | ||
|
|
893ca3884d | ||
|
|
a4505b1408 | ||
|
|
8eadc3e6d9 | ||
|
|
42ed5b3424 | ||
|
|
9a0e59c83a | ||
|
|
dfaac069a8 | ||
|
|
e88d699ea8 | ||
|
|
8c9fbcc6f5 | ||
|
|
714292309e | ||
|
|
48117b1834 | ||
|
|
396d95f340 | ||
|
|
eff2d553f5 | ||
|
|
d8faf47801 | ||
|
|
85ffb7e1c3 | ||
|
|
6abca9b0f0 | ||
|
|
7bc0dd25d0 | ||
|
|
36ee1e6635 | ||
|
|
6161ca8d59 | ||
|
|
7aadd63cd5 | ||
|
|
57a0ab5d54 | ||
|
|
f98975ae35 | ||
|
|
72c5369b58 | ||
|
|
992b8371d1 | ||
|
|
2ea4d93c10 | ||
|
|
9c426223e9 | ||
|
|
c5f15fcd56 | ||
|
|
33ff53de1d | ||
|
|
d8a840d052 | ||
|
|
dabcf1d311 | ||
|
|
839d7eb96b | ||
|
|
cf036901bb | ||
|
|
ac859f2c17 | ||
|
|
567a24231d | ||
|
|
6637f0042e | ||
|
|
22d8001066 | ||
|
|
e2c657bf2d | ||
|
|
9be3333efb | ||
|
|
a962917db0 | ||
|
|
58d5d3e28b | ||
|
|
1c2e0ff75a | ||
|
|
85cbff7a62 | ||
|
|
29f9905b53 | ||
|
|
00b6c92a38 | ||
|
|
6f84d90f51 | ||
|
|
3905ec219a | ||
|
|
ec9b9f389d | ||
|
|
3e79d4e7a3 | ||
|
|
8698dd9570 | ||
|
|
7550e83169 | ||
|
|
0b10a51a19 | ||
|
|
bc067bafe9 | ||
|
|
f48882d446 | ||
|
|
f58813606d | ||
|
|
2dc1c0c369 | ||
|
|
a08d53bf34 | ||
|
|
31e08aeb97 | ||
|
|
f2b7a563d9 | ||
|
|
84f26a5ea5 | ||
|
|
694ebef4e3 | ||
|
|
96c6ac07d5 | ||
|
|
485c5f6442 | ||
|
|
aa9f481fbe | ||
|
|
b4013a168f | ||
|
|
191c308561 | ||
|
|
e07a393485 | ||
|
|
0b9a8a1541 | ||
|
|
882311eb5f | ||
|
|
f541e16a4d | ||
|
|
04bf0c55e4 | ||
|
|
9f58dda6d2 | ||
|
|
ccc6a10dca | ||
|
|
209d333240 | ||
|
|
78ca9dad02 | ||
|
|
30a3a85431 | ||
|
|
2e83194cb2 | ||
|
|
fd11a4d52a | ||
|
|
315c0d934f | ||
|
|
e40aa29b59 | ||
|
|
e681b4109d | ||
|
|
9a3a54c4ca | ||
|
|
abaf8a400a | ||
|
|
c4303ccfa6 | ||
|
|
b336781e9c | ||
|
|
cc72f1e748 | ||
|
|
7bf6b6c1e4 | ||
|
|
6d35eee99f | ||
|
|
32b212b83b | ||
|
|
7152054edb | ||
|
|
8cfb21203e | ||
|
|
7637446362 | ||
|
|
a028b9a628 | ||
|
|
153ff6e39d | ||
|
|
39f5190e36 | ||
|
|
17cb1a0c23 | ||
|
|
73c4a64666 | ||
|
|
ad88f5842b | ||
|
|
b14ab979e8 | ||
|
|
d013abdf4c | ||
|
|
20de9805a9 | ||
|
|
f768417753 | ||
|
|
fc8b8a9cb6 | ||
|
|
9d4688e5ed | ||
|
|
1f8df1e94c | ||
|
|
1b7a0159bb | ||
|
|
18645f4346 | ||
|
|
3db06bf661 | ||
|
|
bd357db0ac | ||
|
|
8bffcb050d | ||
|
|
f59c0793ee | ||
|
|
706d304de8 | ||
|
|
d0175c34b9 | ||
|
|
00aea60eaa | ||
|
|
dedc62f0f7 | ||
|
|
79f388af72 | ||
|
|
59cc8a8b2a | ||
|
|
2ccb18345f | ||
|
|
de14e2983a | ||
|
|
ead2f87ab7 | ||
|
|
67a8642245 | ||
|
|
3d09ce58c4 | ||
|
|
d99e8b1adf | ||
|
|
4ce87f4aa1 | ||
|
|
ce16d5f5ae | ||
|
|
a988dab361 | ||
|
|
d90f0dc9ba | ||
|
|
3649eb2c95 | ||
|
|
d3b2c90dc1 | ||
|
|
9b9d5cf430 | ||
|
|
56bde9b341 | ||
|
|
50d4801074 | ||
|
|
c9fedf3228 | ||
|
|
47accc762b | ||
|
|
c9c9bee5c6 | ||
|
|
3279835696 | ||
|
|
8f47c12450 | ||
|
|
3e857f455e | ||
|
|
7711fe29d9 | ||
|
|
c7695dd6db | ||
|
|
cc6b9df34d | ||
|
|
87c3ee55b9 | ||
|
|
16d9bba33e | ||
|
|
b62e05a312 | ||
|
|
c73c3f36e7 | ||
|
|
18c051f8ac | ||
|
|
c32a99a511 | ||
|
|
cddbc61ea0 | ||
|
|
5e8541c2a6 | ||
|
|
272a2bca67 | ||
|
|
eed41a1de1 | ||
|
|
6d9d7cff71 | ||
|
|
9bcc9b13b6 | ||
|
|
a9b629ee72 | ||
|
|
fa9d6e4aa4 | ||
|
|
986829d798 | ||
|
|
a34f3dc640 | ||
|
|
8c46ec3f6f | ||
|
|
b5596db9d3 | ||
|
|
503462508f | ||
|
|
a025954b74 | ||
|
|
cc23bc8142 | ||
|
|
8228a53d01 | ||
|
|
0c1f16455b | ||
|
|
39b82f1ebf | ||
|
|
7dd215292f | ||
|
|
da2f18e2ef | ||
|
|
6a2d2a27ab | ||
|
|
c40c63252c | ||
|
|
0b39b2bc9e | ||
|
|
a219842b5a | ||
|
|
84f934f39d | ||
|
|
e32dbbae03 | ||
|
|
e7b41d36ff | ||
|
|
c7139953f6 | ||
|
|
b1e8021821 | ||
|
|
437c8b5f20 | ||
|
|
44949d2012 | ||
|
|
169a13be2e | ||
|
|
179deb85cc | ||
|
|
a59e8ae245 | ||
|
|
23e13060e5 | ||
|
|
c0002d1e7b | ||
|
|
01bf8bea9a | ||
|
|
c0439ed6a8 | ||
|
|
ba21d5b6aa | ||
|
|
3b6cf887c8 | ||
|
|
803aeb11c3 | ||
|
|
78ba30ccc3 | ||
|
|
37dbe3a3c6 | ||
|
|
7646d4861e | ||
|
|
6bc3a38aa2 | ||
|
|
729a3748c0 | ||
|
|
3958369382 | ||
|
|
86ab9a0e8e | ||
|
|
f08313723b | ||
|
|
8df5025e9f | ||
|
|
51bbc07bf7 | ||
|
|
e220f26c1b | ||
|
|
d9075418a5 | ||
|
|
b6b1c0b78e | ||
|
|
0b7722e79c | ||
|
|
5d88dde6c4 | ||
|
|
552c2deca8 | ||
|
|
7afa380d67 | ||
|
|
983d11aace | ||
|
|
d4d34d11ff | ||
|
|
3ba275d8e4 | ||
|
|
80ef1d54a7 | ||
|
|
5c0fafa951 | ||
|
|
8615c7e04e |
84 changed files with 45811 additions and 1423 deletions
7
.dockerignore
Normal file
7
.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/build
|
||||
/help.md
|
||||
/services.md
|
||||
/APIs.md
|
||||
/README.md
|
||||
/benchmarking.cpp
|
||||
/docs
|
||||
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: an errors scope must be of CCash and not one of its connected services or
|
||||
API, if so the issue should be submitted on those repos
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description**
|
||||
* A description of the bug's effects.
|
||||
|
||||
**Reproducing Instructions**
|
||||
* Please attempt to find a way to reliably reproduce the bug, this will speed up fixing it. (optional)
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: suggestions for how to improve CCash
|
||||
title: "[IDEA]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Usage**
|
||||
How this would ideally be used / benefit
|
||||
41
.github/workflows/build.yaml
vendored
Normal file
41
.github/workflows/build.yaml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
release:
|
||||
name: Push Docker image to GitHub Packages
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Login to GitHub Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: docker.pkg.github.com
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Format repository
|
||||
run: |
|
||||
echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
|
||||
- name: Build container image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
docker.pkg.github.com/${{ env.IMAGE_REPOSITORY }}/ccash:${{ github.sha }}
|
||||
docker.pkg.github.com/${{ env.IMAGE_REPOSITORY }}/ccash:latest
|
||||
trigger-deploy:
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
curl -X POST \
|
||||
-H 'Accept: application/vnd.github.v3+json' \
|
||||
-H 'Authorization: Bearer ${{ secrets.CCASH_DEPLOY_TOKEN }}' \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/deploy.yaml/dispatches \
|
||||
-d '{"ref":"main"}'
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
.vscode
|
||||
build
|
||||
config.json
|
||||
users.json
|
||||
ccash_config.hpp
|
||||
deployment/.yamllint
|
||||
config
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -4,3 +4,6 @@
|
|||
[submodule "drogon"]
|
||||
path = third_party/drogon
|
||||
url = https://github.com/an-tao/drogon
|
||||
[submodule "third_party/base64"]
|
||||
path = third_party/base64
|
||||
url = https://github.com/aklomp/base64
|
||||
|
|
|
|||
|
|
@ -6,17 +6,98 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra -march=native")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
|
||||
find_package(Threads)
|
||||
add_executable(${PROJECT_NAME} main.cpp include/xxhash.c)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
src/bank_api.cpp
|
||||
src/bank_resp.cpp
|
||||
src/bank.cpp
|
||||
src/change_flag.cpp
|
||||
src/json_filter.cpp
|
||||
src/log.cpp
|
||||
src/simdjson.cpp
|
||||
src/str_intrusion.cpp
|
||||
src/transaction.cpp
|
||||
src/user_filter.cpp
|
||||
src/user.cpp
|
||||
src/xxhash_str.cpp
|
||||
src/xxhash.c
|
||||
|
||||
fbe/user_model/bank_dom_final_models.cpp
|
||||
fbe/user_model/bank_dom_models.cpp
|
||||
fbe/user_model/bank_dom.cpp
|
||||
fbe/user_model/fbe_final_models.cpp
|
||||
fbe/user_model/fbe_models.cpp
|
||||
fbe/user_model/fbe.cpp
|
||||
)
|
||||
|
||||
if(DEFINED USER_SAVE_LOC)
|
||||
set(USER_SAVE "\"${USER_SAVE_LOC}\"")
|
||||
else()
|
||||
set(USER_SAVE "\"../config/users.dat\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED DROGON_CONFIG_LOC)
|
||||
set(DROGON_CONFIG "\"${DROGON_CONFIG_LOC}\"")
|
||||
else()
|
||||
set(DROGON_CONFIG "\"../config/config.json\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED MAX_LOG_SIZE)
|
||||
set(MAX_LOG_SIZE_VAL ${MAX_LOG_SIZE})
|
||||
else()
|
||||
set(MAX_LOG_SIZE_VAL 100)
|
||||
endif()
|
||||
|
||||
if(DEFINED CONSERVATIVE_DISK_SAVE)
|
||||
set(CONSERVATIVE_DISK_SAVE_VAL ${CONSERVATIVE_DISK_SAVE})
|
||||
else()
|
||||
set(CONSERVATIVE_DISK_SAVE_VAL true)
|
||||
endif()
|
||||
|
||||
if(DEFINED MULTI_THREADED)
|
||||
set(MULTI_THREADED_VAL ${MULTI_THREADED})
|
||||
else()
|
||||
set(MULTI_THREADED_VAL true)
|
||||
endif()
|
||||
|
||||
if(DEFINED ADD_USER_OPEN)
|
||||
set(ADD_USER_OPEN_VAL ${ADD_USER_OPEN})
|
||||
else()
|
||||
set(ADD_USER_OPEN_VAL true)
|
||||
endif()
|
||||
|
||||
if(DEFINED RETURN_ON_DEL_NAME)
|
||||
set(RETURN_ON_DEL_VAL true)
|
||||
set(RETURN_ON_DEL_NAME_VAL "\"${RETURN_ON_DEL_NAME}\"")
|
||||
else()
|
||||
set(RETURN_ON_DEL_VAL false)
|
||||
set(RETURN_ON_DEL_NAME_VAL "\"\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED USE_DEPRECATED_ENDPOINTS)
|
||||
set(USE_DEPRECATED_ENDPOINTS_VAL ${USE_DEPRECATED_ENDPOINTS})
|
||||
else()
|
||||
set(USE_DEPRECATED_ENDPOINTS_VAL true)
|
||||
endif()
|
||||
|
||||
configure_file(ccash_config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/ccash_config.hpp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC fbe/user_model)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party/drogon/lib/inc)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC third_party/base64/include)
|
||||
|
||||
add_subdirectory(third_party/drogon)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT} )
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT} )
|
||||
|
||||
#AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/third_party/base64/lib/libbase64.o)
|
||||
|
|
|
|||
21
Dockerfile
Normal file
21
Dockerfile
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
FROM alpine:latest
|
||||
|
||||
WORKDIR /
|
||||
|
||||
RUN apk update && apk add bash git cmake g++ make protobuf jsoncpp-dev openssl libressl-dev zlib-dev util-linux-dev libtool autoconf automake python3
|
||||
|
||||
RUN git clone --recurse-submodules https://github.com/EntireTwix/CCash.git
|
||||
WORKDIR /CCash/third_party/base64/
|
||||
RUN AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
RUN mkdir /CCash/build
|
||||
WORKDIR /CCash/build
|
||||
RUN cmake -DDROGON_CONFIG_LOC="/CCash/config/config.json" -DUSER_SAVE_LOC="/CCash/config/users.dat" ..
|
||||
RUN make -j$(nproc)
|
||||
|
||||
ARG ADMIN_A=admin
|
||||
ARG SAVE_FREQ=2
|
||||
WORKDIR /
|
||||
RUN sed -i 's/\r$//' /CCash/config/ssl.sh && \
|
||||
chmod +x /CCash/config/ssl.sh
|
||||
RUN /CCash/build/bank
|
||||
CMD /CCash/config/ssl.sh && /CCash/build/bank ${ADMIN_A} ${SAVE_FREQ}
|
||||
873
LICENSE
873
LICENSE
|
|
@ -1,622 +1,281 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
NO WARRANTY
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
|
@ -628,15 +287,15 @@ free software which everyone can redistribute and change under these terms.
|
|||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
|
|
@ -644,31 +303,37 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
|
|
|||
125
README.md
125
README.md
|
|
@ -1,114 +1,17 @@
|
|||
# CCash
|
||||

|
||||
|
||||
A webserver hosting a bank system for Minecraft, able to be used from web browser or from CC/OC if you're playing modded.
|
||||
|
||||
the currency model most Minecraft Servers adopt if any, is resource based, usually diamonds, this model is fraught with issues however:
|
||||
* [problem/solution](docs/idea.md)
|
||||
* connected services
|
||||
* how to create
|
||||
* [explanation](docs/connected_services/how_to/explanation.md)
|
||||
* [API implementations](docs/connected_services/how_to/APIs.md)
|
||||
* [the API](docs/connected_services/how_to/endpoints.md)
|
||||
* [existing services](docs/connected_services/existing_services.md)
|
||||
* features
|
||||
* [user side](docs/features/user_side.md)
|
||||
* [implementation](docs/features/implementation.md)
|
||||
* [building](docs/building.md)
|
||||
* [FAQ](docs/FAQ.md)
|
||||
|
||||
- the primary issue is minecraft worlds are infinite leading to hyper inflation as everyone accrues more diamonds
|
||||
- there is no central authority minting the currency, any consumer can introduce more diamonds to the system
|
||||
- some resources are passively reapable, making the generation of currency a larger focus then of products
|
||||
- locality is required for transaction
|
||||
- theft is possible, ownership is possession based
|
||||
|
||||
CCash solves these issues and adds a level of abstraction, the main philosophy of CCash is to have fast core operations that other services build on
|
||||
|
||||
## Build
|
||||
|
||||
drogon depedencies
|
||||
|
||||
```
|
||||
sudo apt install libjsoncpp-dev
|
||||
sudo apt install uuid-dev
|
||||
sudo apt install openssl
|
||||
sudo apt install libssl-dev
|
||||
sudo apt install zlib1g-dev
|
||||
```
|
||||
|
||||
building the project
|
||||
|
||||
```
|
||||
git clone --recurse-submodule https://github.com/EntireTwix/CCash/
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j<threads>
|
||||
```
|
||||
|
||||
then edit config.json to include the paths to your certs for HTTPS (I use certbot), or just remove the listener for port 443.
|
||||
|
||||
```
|
||||
vim ../config.json
|
||||
```
|
||||
|
||||
finally, run the program
|
||||
|
||||
```
|
||||
sudo ./bank <admin password> <saving frequency in minutes> <threads>
|
||||
```
|
||||
|
||||
## Connected Services
|
||||
|
||||
Go to `{ip}/BankF/help` to see the bank's methods (also found in releases as help.html). Using the Bank's API allows (you/others) to (make/use) connected services that utilize the bank, a couple ideas are
|
||||
|
||||
### Implemented:
|
||||
|
||||
- [Web Frontend](https://github.com/Expand-sys/ccashfrontend)
|
||||

|
||||
- [CC Frontend](https://github.com/Reactified/rpm/blob/main/packages/ccash-wallet)
|
||||

|
||||
- [CC Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop)
|
||||

|
||||

|
||||
- [CC API](https://github.com/Reactified/rpm/blob/main/packages/ccash-api/api.lua)
|
||||
- [CC ATM](https://github.com/Reactified/misc/tree/main/lua/ccash-bank) an ATM for economies allowing for an initial exchange to start up
|
||||
|
||||
### In-Dev:
|
||||
|
||||
- [a Market](https://github.com/STBoyden/market-api-2.0)
|
||||
- [Ebay equivelant](https://github.com/EntireTwix/CSHBay)
|
||||
|
||||
### Ideas:
|
||||
|
||||
- Gambling
|
||||
- Shipping
|
||||
- High-level bank operations such as loans
|
||||
- Some trust based system for transactions similiar to Paypal
|
||||
|
||||
`**WARNING** : abruptly killing the program will result in data loss, use Close() method to close safely`
|
||||
|
||||
## FAQ
|
||||
|
||||
some frequently asked questions are
|
||||
|
||||
## Contributions
|
||||
|
||||
[Doggo](https://github.com/FearlessDoggo21) Logs Optimized
|
||||
|
||||
## Features
|
||||
|
||||
### Performance
|
||||
|
||||
- **NOT** written in Lua, like a OC/CC implementation
|
||||
- written in **C++**, arguably the fastest language
|
||||
- **multi-threaded**
|
||||
- **parallel hashmaps** a far [superior](https://greg7mdp.github.io/parallel-hashmap/) HashMap implementation to the STD, that also benefits from multi-threaded
|
||||
- **Drogon** is a very fast [web framework](https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=composite)
|
||||
- **Lightweight**, anecodotally I experienced 0.0% idle, <1% CPU usage on average, 7% at peak, 1000 requests in 0.85s
|
||||
|
||||
### Safety
|
||||
|
||||
- **Tamper Proof** relative to an in-game implementation
|
||||
- **Auto-Saving** and Saves on close
|
||||
- **HTTPS** (OpenSSL)
|
||||
|
||||
### Accessibility
|
||||
|
||||
- **RESTful** API for connected services like a market, gambling, or anything else you can think of
|
||||
- able to be used millions of blocks away, across dimensions, servers, **vanilla or modded**. In contrast to an in-game modded implementation that would be range limited.
|
||||
- **Logging** of all transactions, configurable in [log_consts.hpp](include/log_consts.hpp)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Parallel HashMap](https://github.com/greg7mdp/parallel-hashmap/tree/master)
|
||||
- [Drogon](https://github.com/an-tao/drogon/tree/master)
|
||||
- [XXHASH](https://github.com/Cyan4973/xxHash)
|
||||
* [Versions](docs/versioning.md)
|
||||
|
|
|
|||
105
benchmarking.cpp
Normal file
105
benchmarking.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <random>
|
||||
#include "xxhash_str.h"
|
||||
#include "bank.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
#include <ctime>
|
||||
#include <ratio>
|
||||
#include <chrono>
|
||||
|
||||
#define time_func_a(f, a, x) \
|
||||
{ \
|
||||
using namespace std::chrono; \
|
||||
uint32_t timer = 0; \
|
||||
for (int i = 0; i < x; ++i) \
|
||||
{ \
|
||||
auto t1 = high_resolution_clock::now().time_since_epoch(); \
|
||||
f; \
|
||||
auto t2 = high_resolution_clock::now().time_since_epoch(); \
|
||||
a; \
|
||||
timer += std::chrono::duration_cast<std::chrono::nanoseconds>((t2 - t1)).count(); \
|
||||
} \
|
||||
std::cout << timer / x << '\n'; \
|
||||
}
|
||||
|
||||
#define time_func(f, x) \
|
||||
{ \
|
||||
using namespace std::chrono; \
|
||||
uint32_t timer = 0; \
|
||||
for (int i = 0; i < x; ++i) \
|
||||
{ \
|
||||
auto t1 = high_resolution_clock::now().time_since_epoch(); \
|
||||
f; \
|
||||
auto t2 = high_resolution_clock::now().time_since_epoch(); \
|
||||
timer += std::chrono::duration_cast<std::chrono::nanoseconds>((t2 - t1)).count(); \
|
||||
} \
|
||||
std::cout << timer / x << '\n'; \
|
||||
}
|
||||
|
||||
#define Op_a(v, name, x, a) \
|
||||
{ \
|
||||
std::cout << name; \
|
||||
time_func_a(v, a, x); \
|
||||
}
|
||||
|
||||
#define Op(v, name, x) \
|
||||
{ \
|
||||
std::cout << name; \
|
||||
time_func(v, x); \
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
for (size_t i = 100; i < 10100; ++i)
|
||||
{
|
||||
Bank::AddUser(std::to_string(i), 0, "root");
|
||||
}
|
||||
std::cout << "added " << Bank::NumOfUsers() << " users\n";
|
||||
Bank::AddUser("twix", 0, "root");
|
||||
Bank::AddUser("jolly", 0, "root");
|
||||
Bank::admin_account = "twix";
|
||||
|
||||
const std::string data("this string is quite long which is relevant when testing the speed of a hasing function");
|
||||
Op(std::hash<std::string>{}(data), "hash<string>: ", 1000000);
|
||||
Op(xxHashStringGen{}(data), "xxHashStringGen: ", 1000000);
|
||||
|
||||
Op_a(Bank::AddUser("abc", 0, "abc"), "add user: ", 1000000, Bank::DelUser("abc"));
|
||||
Op(Bank::ImpactBal("twix", 1), "impact bal: ", 1000000);
|
||||
Op(Bank::SetBal("twix", 1000000), "set bal: ", 1000000);
|
||||
Op(Bank::SendFunds("twix", "jolly", 1), "send funds: ", 1000000);
|
||||
Op(Bank::SendFunds("", "", 1), "invalid send funds: ", 1000000);
|
||||
|
||||
Bank::AddUser("abc", 0, "abc");
|
||||
Op_a(Bank::DelUser("abc"), "del user: ", 1000000, Bank::AddUser("abc", 0, "abc"));
|
||||
Op_a(Bank::DelSelf("abc"), "del self: ", 1000000, Bank::AddUser("abc", 0, "abc"));
|
||||
Bank::DelUser("abc");
|
||||
|
||||
Op(Bank::Contains("twix"), "contains: ", 1000000);
|
||||
Op(Bank::GetBal("twix"), "get bal: ", 1000000);
|
||||
Op(Bank::VerifyPassword("twix", "root"), "verify pass: ", 1000000);
|
||||
Op(Bank::ChangePassword("twix", "root"), "change pass: ", 1000000);
|
||||
#if MAX_LOG_SIZE > 0
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
Op(Bank::GetLogs("twix"), "get logs init: ", 1);
|
||||
Op(Bank::GetLogs("twix"), "get logs cached: ", 1000000);
|
||||
#endif
|
||||
Op(Bank::GetLogsV2("twix"), "get logs init (v2): ", 1);
|
||||
Op(Bank::GetLogsV2("twix"), "get logs cached (v2): ", 1000000);
|
||||
Op(Bank::GetLogsRange("twix", 0, 100), "get logs range: ", 1000000);
|
||||
#endif
|
||||
Op(Bank::PruneUsers(0, 0), "prune users: ", 1);
|
||||
Op(Bank::Save(), "saving: ", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
ccash_config.hpp.in
Normal file
35
ccash_config.hpp.in
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
// Setting to 0 does not compile logging (useful for if disk/memory is very valuable)
|
||||
#define MAX_LOG_SIZE @MAX_LOG_SIZE_VAL@
|
||||
|
||||
// Default to minecraft usernames
|
||||
constexpr unsigned min_name_size = 3;
|
||||
constexpr unsigned max_name_size = 16;
|
||||
|
||||
constexpr const char *users_location = @USER_SAVE@;
|
||||
constexpr const char *config_location = @DROGON_CONFIG@;
|
||||
|
||||
// Returns money to an account on deletion (useful if you dont want any money to leave the economy)
|
||||
#define RETURN_ON_DEL @RETURN_ON_DEL_VAL@
|
||||
constexpr const char *return_account = @RETURN_ON_DEL_NAME_VAL@;
|
||||
|
||||
/*
|
||||
if true, when frequency is hit AND changes have happened then save
|
||||
pros
|
||||
LOW disk usage
|
||||
cons
|
||||
LOW atomic overhead
|
||||
if false, when frequency is hit save
|
||||
pros
|
||||
ZERO atomic overhead
|
||||
cons
|
||||
HIGH disk usage
|
||||
*/
|
||||
#define CONSERVATIVE_DISK_SAVE @CONSERVATIVE_DISK_SAVE_VAL@
|
||||
|
||||
#define MULTI_THREADED @MULTI_THREADED_VAL@
|
||||
|
||||
#define ADD_USER_OPEN @ADD_USER_OPEN_VAL@
|
||||
|
||||
#define USE_DEPRECATED_ENDPOINTS @USE_DEPRECATED_ENDPOINTS_VAL@
|
||||
16
config.json
16
config.json
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
16
config/config.json
Normal file
16
config/config.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "/CCash/config/cert.cert",
|
||||
"key": "/CCash/config/key.key"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
config/ssl.sh
Normal file
9
config/ssl.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
openssl genrsa -out server.pass.key 2048
|
||||
openssl rsa -in server.pass.key -out /CCash/config/key.key
|
||||
rm server.pass.key
|
||||
openssl req -new -key /CCash/config/key.key -out server.csr \
|
||||
-subj "/C=US/ST=CCashland/L=NEW CCASH/O=CCash/OU=Devs/CN=localhost"
|
||||
openssl x509 -req -days 365 -in server.csr -signkey /CCash/config/key.key -out /CCash/config/cert.cert
|
||||
BIN
config/users.dat
Normal file
BIN
config/users.dat
Normal file
Binary file not shown.
20
docs/FAQ.md
Normal file
20
docs/FAQ.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
[PREVIOUS PAGE](building.md)
|
||||
|
||||
### How do I setup a CCash instance
|
||||
You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package.
|
||||
### Why is my username invalid
|
||||
Usernames are restricted by minecraft's requirements
|
||||
* letters
|
||||
* numbers
|
||||
* _
|
||||
* length must be atleast 3 and at most 16 characters.
|
||||
### Is this crypto like krist?
|
||||
CCash isn't a crypto, simply a ledger keeping track of who owns what.
|
||||
### Why isnt this on a database?
|
||||
Because this usecase requires none of the features a database would offer.
|
||||
### People are making too many accounts maliciously to fill up space on my server!
|
||||
Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
|
||||
### My instance is taking up too much storage or RAM
|
||||
Reduce log size and/or use the prune users endpoint to remove dead accounts.
|
||||
### Why not use an economy mod
|
||||
Speed of operations, CCash being external to MC (and so compatible with any version/configuration), and the API are the main advantages to an economy mod.
|
||||
159
docs/building.md
Normal file
159
docs/building.md
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# Building
|
||||
[PREVIOUS PAGE](features/implementation.md) | [NEXT PAGE](FAQ.md)
|
||||
|
||||
## Advice
|
||||
as CCash is very lightweight it can run on practically any device but here are some tips:
|
||||
* single core machines should toggle `MULTI_THREADED` to `false`
|
||||
* if your server is sufficiently active, such that each time save frequency is met, changes having been made is highly likely then `CONSERVATIVE_DISK_SAVE` should be toggled to `false`
|
||||
* `MAX_LOG_SIZE` should be adjusted as it takes up the most memory usage/storage of the ledger's features at 139 bytes in memory and 43 bytes in disk at default settings on the current version, so 7543 logs per MB of RAM. Setting to 0 will disable logs
|
||||
* with no users memory usage is ~8.47 MB
|
||||
* saving frequency being set to 0 will disable frequency saving and only save on close
|
||||
* make backups of your save files!
|
||||
|
||||
## Docker & Ansible
|
||||
If you want to use the docker package, deploy information can be found [here](deploy.md)
|
||||
|
||||
## Drogon Depedencies
|
||||
|
||||
### Linux
|
||||
#### Debian
|
||||
```
|
||||
sudo apt install libjsoncpp-dev uuid-dev openssl libssl-dev zlib1g-dev make cmake
|
||||
```
|
||||
#### CentOS 7.5
|
||||
```
|
||||
yum install git gcc gcc-c++
|
||||
git clone https://github.com/Kitware/CMake
|
||||
cd CMake/
|
||||
./bootstrap
|
||||
make
|
||||
make install
|
||||
yum install centos-release-scl devtoolset-8
|
||||
scl enable devtoolset-8 bash
|
||||
git clone https://github.com/open-source-parsers/jsoncpp
|
||||
cd jsoncpp/
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
yum install libuuid-devel openssl-devel zlib-devel
|
||||
```
|
||||
#### Other
|
||||
anything that can download the appropriate dependencies
|
||||
```
|
||||
make & cmake
|
||||
jsoncpp
|
||||
libuuid
|
||||
openssl
|
||||
zlib
|
||||
```
|
||||
### MacOS
|
||||
```
|
||||
brew install jsoncpp ossp-uuid openssl zlib
|
||||
```
|
||||
|
||||
## Actually, building
|
||||
```
|
||||
git clone --recurse-submodule https://github.com/EntireTwix/CCash/
|
||||
cd CCash
|
||||
cd third_party/base64
|
||||
AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
cd ../..
|
||||
mkdir build
|
||||
cd build
|
||||
```
|
||||
|
||||
### CMake Variables
|
||||
there are multiple flags responsible configuring CCash:
|
||||
| name | default | description | pros | cons |
|
||||
| :----------------------- | :------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
|
||||
| USER_SAVE_LOC | "config/users.dat" | where the users are saved | `N/A` | `N/A` |
|
||||
| DROGON_CONFIG_LOC | "config/config.json" | where the config is located | `N/A` | `N/A` |
|
||||
| MAX_LOG_SIZE | 100 | max number of logs per user, last `n` transactions. If both this and pre log are toggled to 0 logs will not be compiled. | large history | higher memory usage |
|
||||
| CONSERVATIVE_DISK_SAVE | `true` | when `true` only saves when changes are made | low # of disk operations | some atomic overhead |
|
||||
| MULTI_THREADED | `true` | when `true` the program is compiled to utilize `n` threads which corresponds to how many Cores your CPU has, plus 1 for saving | speed | memory lock overhead is wasteful on single core machines |
|
||||
| RETURN_ON_DEL_NAME | `N/A` | when defined, return on delete will be toggled and any accounts deleted will send their funds to the defined account, this prevent currency destruction | prevents destruction of currency | deleting accounts is made slower |
|
||||
| ADD_USER_OPEN | `true` | anybody can make a new account, if set to false only admins can add accounts via `AdminAddUser()` | `N/A` | spamming new users |
|
||||
| USE_DEPRECATED_ENDPOINTS | `true` | some endpoints have newer versions making them obsolete but old programs might still call these endpoints so they are simply marked deprecated. | supports old programs | old endpoints can be ineffecient |
|
||||
|
||||
EXAMPLE:
|
||||
```
|
||||
cmake ..
|
||||
```
|
||||
sets these flags to their defaults, an example of setting a flag would be
|
||||
```
|
||||
cmake -DMULTI_THREADING=false ..
|
||||
```
|
||||
with `-D`
|
||||
|
||||
### Finishing building
|
||||
lastly type in
|
||||
```
|
||||
cmake <flags of your choice or none> ..
|
||||
make -j<threads>
|
||||
sudo ./bank
|
||||
```
|
||||
the last command generates a blank save file in your defined location.
|
||||
|
||||
## Certs
|
||||
make sure to edit `config.json` adding the certificate location if you're using HTTPS, I personally use [certbot](https://certbot.eff.org/).
|
||||
```json
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
editing
|
||||
```json
|
||||
"cert": "pubkey",
|
||||
"key": "privkey"
|
||||
```
|
||||
|
||||
Alternatively you can delete this entire section (Disabling HTTPS in the proccess)
|
||||
```json
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
```
|
||||
leaving
|
||||
```json
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 80,
|
||||
"https": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
You can now run the program from the build location. For example
|
||||
```
|
||||
sudo ./bank admin 5
|
||||
```
|
||||
in this example CCash will be launched with the admin account named `"admin"`, and a saving frequency of every `5` minutes; without daemon being given its default is `false`.
|
||||
|
||||
Another example
|
||||
```
|
||||
sudo ./bank Kevin 0 true
|
||||
```
|
||||
in this example CCash will be launched with the admin account named `"Kevin"`, and a saving frequency of `0` meaning the server will only save when closed; daemon is set to `true` and so will be launched in the background.
|
||||
32
docs/connected_services/existing_services.md
Normal file
32
docs/connected_services/existing_services.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[PREVIOUS PAGE](how_to/endpoints.md) | [NEXT PAGE](../features/user_side.md)
|
||||
|
||||
## Key
|
||||
| description | symbol |
|
||||
| :-----------------------: | :----------------- |
|
||||
| supported | :heavy_check_mark: |
|
||||
| uses deprecated endpoints | ⚠ |
|
||||
| uses defunt endpoints | :no_entry: |
|
||||
| in development | :hammer: |
|
||||
|
||||
## General
|
||||
| author | name | support | image |
|
||||
| :-------------------------------------- | ----------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
|
||||
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: |  | |
|
||||
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | |
|
||||
|
||||
## Minecraft
|
||||
| author | name | support | image |
|
||||
| :------------------------------------------ | ---------------------------------------------------------------------------------------- | :----------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: |  |
|
||||
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ |  |
|
||||
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: |  |
|
||||
| [Reactified](https://github.com/Reactified) | [Chunk Loader Shop](https://github.com/Reactified/rpm/tree/main/packages/forceload-shop) | :heavy_check_mark: |   |
|
||||
| [STBoyden](https://github.com/STBoyden) | [Commodities Exchange](https://github.com/STBoyden/ccash-market) | :hammer: | |
|
||||
|
||||
|
||||
## Desired
|
||||
| idea | description |
|
||||
| :-----------: | :------------------------------------------------------------- |
|
||||
| Gambling | physical or digital casino. |
|
||||
| Shipping | the infastructure to quickly send items across long distances. |
|
||||
| Mod or Plugin | a server-side mod |
|
||||
41
docs/connected_services/how_to/APIs.md
Normal file
41
docs/connected_services/how_to/APIs.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
|
||||
|
||||
CCash is backwards compatible, so even if a language API does not support the newester version it can still call the old endpoints. Only when the major version increments are deprecated features made defunct (e.g `v1.0.0` -> `v2.0.0`), check the [endpoint docs](endpoints.md) to avoid using deprecated endpoints. For more information about versioning check out [versioning docs](../../versioning.md).
|
||||
| author | language | | newest CCash supported version |
|
||||
| :-------------------------------------------------------- | :--------: | -------------------------------------------------------------------- | :----------------------------: |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | `v2.5.1` |
|
||||
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://github.com/STBoyden/ccash-rs) | `v2.5.1` |
|
||||
| [Doggo](https://github.com/ArcNyxx) | Python | [CCashPythonClient](https://github.com/ArcNyxx/ccash_python_client) | `v2.5.1` |
|
||||
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | TypeScript | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | `v1.3.0` |
|
||||
|
||||
here is a demo program for the lua API by SpaceCat
|
||||
|
||||
```lua
|
||||
local ccash = require("ccash.api")
|
||||
ccash.meta.set_server_address("https://ccashinstance.net/")
|
||||
|
||||
local cred_name = "my_account"
|
||||
local cred_pass = "my_pass"
|
||||
|
||||
math.randomseed(os.time())
|
||||
local temp_name = tostring(math.random(100, 2147483647))
|
||||
print("temp account "..temp_name)
|
||||
|
||||
print("enter target name ")
|
||||
local target_name = io.read()
|
||||
print("enter target amount ")
|
||||
local target_amount = tonumber(io.read())
|
||||
|
||||
print(ccash.register(temp_name, "root123"))
|
||||
print(ccash.send_funds(cred_name, cred_pass, temp_name, target_amount))
|
||||
print(ccash.send_funds(temp_name, "root123", target_name, target_amount))
|
||||
print(ccash.delete_self(temp_name, "root123"))
|
||||
```
|
||||
|
||||
this particular program obfuscates transactions so that the person receiving it has no way of knowing who it came from
|
||||
|
||||
```
|
||||
my_account -> temp_account -> target_account
|
||||
+100 +100
|
||||
```
|
||||
then temp_account is deleted
|
||||
BIN
docs/connected_services/how_to/connected_a.png
Normal file
BIN
docs/connected_services/how_to/connected_a.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/connected_services/how_to/connected_b.png
Normal file
BIN
docs/connected_services/how_to/connected_b.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
docs/connected_services/how_to/connected_c.png
Normal file
BIN
docs/connected_services/how_to/connected_c.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
98
docs/connected_services/how_to/endpoints.md
Normal file
98
docs/connected_services/how_to/endpoints.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# API endpoints
|
||||
[PREVIOUS PAGE](APIs.md) | [NEXT PAGE](../existing_services.md)
|
||||
|
||||
## KEY
|
||||
`Jresp` - Json Response, json must be accepted in the `Accept` header, be that via `application/json` or `*/*`, failing to do so results in error `406`
|
||||
|
||||
`Jreq` - Json Request, requires `application/json` as `content-type`, failing to do so results in error `406`
|
||||
|
||||
`U` - User, requires [basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication) in the header `Authorization`. This credential must be a valid user, failing to do so results in error `401`
|
||||
|
||||
`A` - Admin, same as `U` but in addition requires username supplied be equal to the admin account username
|
||||
|
||||
⚠ - Deprecated endpoint
|
||||
|
||||
:no_entry: - Defunct endpoint
|
||||
|
||||
## all error responses have JSON string along with them to describe
|
||||
|
||||
### Usage endpoints
|
||||
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: |
|
||||
| GetBal | `v2.3.0` | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :x: | :x: | :x: |
|
||||
| GetLogs | `v2.3.0` | retrieves the logs of a given user, length varies by server configuration (oldest to newest transactions) | `N/A` | ⚠ api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| GetLogsV2 | `v2.6.1` | retrieves the logs of a given user, length varies by server configuration (newest to oldest transactions) | `N/A` | api/v2/user/log | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| GetLogsRange | `v2.6.1` | retrieves the logs of a given user, where `{start}` is the 0-indexed first log and `{length}` is the number of logs after that index. | `N/A` | api/v1/user/log_range | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| SendFunds | `v2.3.0` | sends funds from the authenticated user to the user `"name"` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ChangePassword | `v2.3.0` | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| VerifyPassword | `v2.3.0` | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
|
||||
### Usage enpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------- | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| GetBal | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
|
||||
### Meta Usage endpoints
|
||||
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------------ | :---------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
|
||||
| AdminGetLogs | `v2.6.1` | retreives the logs of a given user `{name}`, length varies by server configuration | `N/A` | api/v1/admin/user/log?name={name} | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| AdminChangePassword | `v2.3.0` | changes the password of a given user `"name"` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| AdminVerifyAccount | `v2.3.0` | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| SetBal | `v2.3.0` | sets the balance of a given user `"name"` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| ImpactBal | `v2.3.0` | modifies the user `"name"`'s balance by `"amount"` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
||||
### Meta Usage endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------------ | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| AdminGetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminVerifyAccount | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|
||||
### Sytem Usage endpoints
|
||||
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------ | :---------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
|
||||
| Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: |
|
||||
| Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| Contains | `v2.3.0` | checks wether a given user `{name}` exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :x: |
|
||||
| PruneUsers | `v2.3.0` | deletes users with most recent transactions older then `"time"` (if logs are enabled) and have less money then `"amount"` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| ApiProperties | `v2.5.1` | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"max_log":uint64, "add_user_open":boolean, "return_on_del":string} | :heavy_check_mark: | :x: | :x: | :x: |
|
||||
|
||||
### System Usage endpoin errors
|
||||
| name | 401 | 404 | 406 |
|
||||
| :------------ | :----------------: | :----------------: | :----------------: |
|
||||
| Help | :x: | :x: | :x: |
|
||||
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ApiProperties | :x: | :x: | :x: |
|
||||
|
||||
### Username Requirements
|
||||
Valid
|
||||
* letters
|
||||
* numbers
|
||||
* _
|
||||
* Length must be atleast 3 and at most 16 characters.
|
||||
|
||||
### User Management endpoints
|
||||
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :----------- | :---------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| AddUser | `v2.3.0` | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
|
||||
| AdminAddUser | `v2.3.0` | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| AdminDelUser | `v2.3.0` | deletes a given user `"name"` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
||||
### User Management endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 | 409 |
|
||||
| :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| AddUser | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| DelSelf | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
21
docs/connected_services/how_to/explanation.md
Normal file
21
docs/connected_services/how_to/explanation.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[PREVIOUS PAGE](../../idea.md) | [NEXT PAGE](APIs.md)
|
||||
|
||||
Using the ledger's API allows (you/others) to (make/use) connected services which utilize the ledger. Below is a visual represenation of connected services:
|
||||
|
||||

|
||||
|
||||
Ideally as the ecosystem develops, connected services become inner-connected:
|
||||
|
||||

|
||||
|
||||
The aim of any of these services is to provide functionality which relies on the ground truth of ownership of currency. This information is centrally secured in CCash.
|
||||
|
||||
To browse the currently available connected services, check out [existing_services.md](../existing_services.md).
|
||||
|
||||
To make a connected service yourself, you can do so by using one of the [langauge specific APIs](APIs.md). What they do is provide a simplified in-langauge way to interface with the CCash instance.
|
||||
|
||||

|
||||
|
||||
If an API does not exist for your language, it is simple to make one. I encourage you to add it to this list if you do decide to.
|
||||
|
||||
While developing make sure to reference the list of [endpoints](endpoints.md).
|
||||
10
docs/contributors.md
Normal file
10
docs/contributors.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Contributors
|
||||
| name | work |
|
||||
| :------------------------------------------- | ---------------------------------- |
|
||||
| [Luke](https://github.com/LukeeeeBennett) | Github Actions, and JS API |
|
||||
| [React](https://github.com/Reactified) | Logo, CC Wallet/Shop/ATM |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | HTTP advice, Python API, and C CLI |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
|
||||
| [Expand](https://github.com/Expand-sys) | Docker, and Ansible |
|
||||
| [Sam](https://github.com/STBoyden) | Rust API |
|
||||
| Caesay | Restful API advice |
|
||||
47
docs/deploy.md
Normal file
47
docs/deploy.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Deploying CCash
|
||||
|
||||
CCash can deployed to a remote machine pretty simply.
|
||||
|
||||
A pre-built docker image is supplied in the repos [GitHub Packages](https://github.com/features/packages) container registry [EntireTwix/CCash](https://github.com/EntireTwix/CCash/packages/851105).
|
||||
|
||||
It can be run with docker like so:
|
||||
|
||||
```
|
||||
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ghcr.io/entiretwix/ccash/ccash:latest
|
||||
```
|
||||
|
||||
## Ansible
|
||||
Additionally CCash can be deployed to any infrastructure able to run Rocky/Alma Linux 8/9 x86_64 virtual or not, we will be eventually updating it to allow it to run on other OS's but for now RHEL is what works.
|
||||
|
||||
As CCash is intended to be run as root, the playbook is run also as root. The playbook also builds CCash from the latest github push, so there may be bugs.
|
||||
|
||||
In order to use the ansible playbook, clone the playbook to any pc with the ability to access the server through SSH and with Ansible installed, edit the inventory file to contain the IP address of the target server and run the following commands:
|
||||
```ansible-galaxy install -r deployment/requirements.yml
|
||||
```ansible-playbook -i deployment/inventory deployment/main.yml -k```
|
||||
When this is complete the server will have ccash installed to the user dir, this is customizable in the vars/default.yml file along with the admin username and save frequency.
|
||||
To start CCash run:
|
||||
```systemctl start ccash```
|
||||
To run ccash at start up run:
|
||||
```systemctl enable ccash```
|
||||
|
||||
## Build
|
||||
Previously this used GitHub Workflows, I(Expand) dont know how to do those but its not that hard to deploy stuff manually. To run the pre configured docker image run the above command and you are off to the races it will deploy a self signed certificate and use that for deployment. As this is not a user facing deployment the certificate is self signed and thus will throw an error on chrome, though this will still work if you ignore it. For production you should deploy with a reverse proxy and a correct certificate for your domain.
|
||||
|
||||
To build this manually you may download the dockerfile only, it will pull the latest repository the commands for building are
|
||||
```
|
||||
docker build --build-arg ADMIN_A=<admin-username> --build-arg SAVE_FREQ=<in minutes> -t ccash . --no-cache
|
||||
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ccash
|
||||
```
|
||||
if you have the know how you may edit the docker file and add CMAKE commands as listed in the build section of the CCash documentation.
|
||||
|
||||
## Deploy
|
||||
|
||||
You can deploy this docker image to be run on a remote machine in a few steps or you can deploy manually in this case we are using [Debian OS](https://www.debian.org/) running on the [Linode](https://www.linode.com/) cloud provider, but most OS and cloud providers will work, assuming the machine can run an SSH server.
|
||||
|
||||
Additionally, there is a dockerfile where you can build it yourself or a repository available on [dockerhub](https://hub.docker.com/r/expandsys/ccash) for you to just pull and run on any machine quickly and easily.
|
||||
|
||||
### Configure the machine
|
||||
For docker deployment there is one supported config and that is the command listed above,
|
||||
ADMIN_A = Admin account name, must be all lowercase, and the account must be created before use. To do this either use the [CCashDeploy](https://hub.docker.com/r/expandsys/ccashdeploy) docker image and use the CCashFrontend to register the account or use curl to send the raw command to the endpoint.
|
||||
SAVE_FREQ = Saving frequency in minutes, pretty simple
|
||||
|
||||
BIN
docs/external_diagram.png
Normal file
BIN
docs/external_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
47
docs/features/implementation.md
Normal file
47
docs/features/implementation.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
[PREVIOUS PAGE](user_side.md) | [NEXT PAGE](../building.md)
|
||||
|
||||
# Implementation Features
|
||||
## [Parallel Hashmap](https://github.com/greg7mdp/parallel-hashmap)
|
||||
<!-- memory vs database -->
|
||||
<!-- and while changes arent made on the basis of speed alone it does seem to fit the problem better as we only need to save every `n` minutes/on close. -->
|
||||
<!-- phmap vs std hash map -->
|
||||
#### STD vs phmap
|
||||
this parallel hashmap implementation is the basis of CCash, its where all the user data is stored, compared to the STD's `std::unordered_map<T>` its much faster, this, multi threading support, and more can be found in the [writeup](https://greg7mdp.github.io/parallel-hashmap/).
|
||||

|
||||

|
||||
## [xxHash](https://github.com/Cyan4973/xxHash)
|
||||
xxhash is used for both hashing of passwords for storage aswell as the usernames for indexing the phmap, its speed is ridiculous at faster then `memcpy` rates of Gb/s.
|
||||
| Hash Name | Width | Bandwidth (GB/s) |
|
||||
| --------------------- | ----- | ---------------- |
|
||||
| __XXH3__ (SSE2) | 64 | 31.5 GB/s |
|
||||
| _RAM sequential read_ | N/A | 28.0 GB/s |
|
||||
## [Base64](https://github.com/aklomp/base64)
|
||||
base64 decoding is required for Basic Auth so I used this clean and fast solution which uses SIMD.
|
||||

|
||||
## [Simdjson](https://github.com/simdjson/simdjson)
|
||||
simdjson was the fastest JSON parsing I could find, its used for request parsing.
|
||||

|
||||
## [Drogon webframework](https://github.com/an-tao/drogon)
|
||||
at the time of making this doc Drogon is the 3rd fastest web framework as per [this](https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=composite) sites metric of measuring web frameworks, it also has multi threading support.
|
||||
|
||||

|
||||
## Sparse saving
|
||||
#### Saving on close
|
||||
when the program is interupted with CONTROL + C it will save before closing the webserver, **it will not however save during a crash**.
|
||||
#### Auto Saving
|
||||
every `n` minutes, a configurable amount at launch, CCash will save.
|
||||
#### Changes
|
||||
for the above two cases, it will only save to disk if changes have been made since last save.
|
||||
#### [Binary Encoding](https://github.com/chronoxor/FastBinaryEncoding)
|
||||
saving is done using FBE, this slightly reduces file size compared to JSON and is much faster.
|
||||
| Protocol | Message size | Serialization time | Deserialization time |
|
||||
| :-------------------------------------------------------------------: | -----------: | -----------------: | -------------------: |
|
||||
| [Cap'n'Proto](https://capnproto.org) | 208 bytes | 558 ns | 359 ns |
|
||||
| [FastBinaryEncoding](https://github.com/chronoxor/FastBinaryEncoding) | 234 bytes | 66 ns | 82 ns |
|
||||
| [FlatBuffers](https://google.github.io/flatbuffers) | 280 bytes | 830 ns | 290 ns |
|
||||
| [Protobuf](https://developers.google.com/protocol-buffers) | 120 bytes | 628 ns | 759 ns |
|
||||
| [JSON](http://rapidjson.org) | 301 bytes | 740 ns | 500 ns |
|
||||
## Multi-threading support
|
||||
considering phmap and drogon both massively benefit from being multi-threaded it seemed obvious that the entire program should be, this is enabled by default and manually settable at `MULTI_THREADED`.
|
||||
## Backwards Compatible API
|
||||
versioning is implemented by the endpoints path, for example `api/v1/`. Breaking changes will ideally be sparse and backwards compatability will be maintained, for example ideally API `v3` instance can still run `v1` endpoints.
|
||||
33
docs/features/user_side.md
Normal file
33
docs/features/user_side.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
[PREVIOUS PAGE](../connected_services/existing_services.md) | [NEXT PAGE](implementation.md)
|
||||
|
||||
# Features
|
||||
## Performance
|
||||
#### Speed
|
||||
<!-- graphs -->
|
||||
Capable of processing thousands of requests per second, with little slow down as user size grows to the millions.
|
||||
#### Lightweight
|
||||
<!-- specs -->
|
||||
* Low memory usage at 8 MB baseline, and 139 bytes per new log.
|
||||
* Extremely low CPU usage in the single digits of %.
|
||||
* Small save files at typically a couple kb, easily shareable.
|
||||
## Accessibility
|
||||
#### Connected Services
|
||||
as explained in earlier docs a ecosystem of connected services allows you many ways to utilize CCash.
|
||||
#### APIs
|
||||
for devs who wanna make more connected services, existing APIs exist in multiple lanaguages enabling faster development/maintenance.
|
||||
#### External
|
||||
its game indepedent meaning you dont have to be in-game to use it. With support for Docker and Ansible Playbook.
|
||||
## Security
|
||||
#### HTTPS
|
||||
OpenSSL is used to secure the HTTP server.
|
||||
#### Hashed Passwords
|
||||
if the server's save file is compromised the user passwords will not be derivable.
|
||||
## Other
|
||||
#### Logs
|
||||
each transaction is logged and the last `n` logs are stored, if set to 0 logs will be disabled.
|
||||
#### Return On Delete
|
||||
by default this feature is off, but when enabled deleted account's funds will be redirected to a specified account rather then "burned"
|
||||
#### Configurable
|
||||
as you can read in [building.md](../building.md) CCash is highly configurable.
|
||||
#### Game Independent
|
||||
As CCash does not require an addition to the game in the form of a mod or plugin, it can be ran on any server.
|
||||
30
docs/idea.md
Normal file
30
docs/idea.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
[PREVIOUS PAGE](../README.md) | [NEXT PAGE](connected_services/how_to/explanation.md)
|
||||
|
||||
CCash is an external ledger for in-game economies, running on a webserver with a RESTful API, exceptionally fast and lightweight written in C++.
|
||||
|
||||
While CCash can be used for anything that can interact with its API I think minecraft is a good usecase.
|
||||
|
||||
The currency model most Minecraft Servers adopt if any, is resource based, usually diamonds. This model is fraught with issues however:
|
||||
|
||||
* The primary issue is minecraft worlds are infinite, leading to hyper inflation as everyone accrues more diamonds.
|
||||
* Some resources are passively reapable (e.g iron or gold), making the generation of currency a larger focus than that of creating value.
|
||||
* Locality is required for transactions.
|
||||
* Theft is possible; ownership is physical possession based.
|
||||
|
||||
CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on, CCash can proccess thousands of requests per second.
|
||||
|
||||
The CCash instance can be external to the game server:
|
||||
|
||||

|
||||
|
||||
Or on localhost:
|
||||
|
||||

|
||||
|
||||
Running it local to the game server reduces latency for connected services and CCash is very lightweight and so will be a tiny proportion of the server's total computation.
|
||||
|
||||
**DISCLAIMER: ComputerCraft requires you add `127.0.0.1` to its config section `allowed_domains` if you're interacting with CCash locally**
|
||||
|
||||
As CCash is just a means of keeping track of who has what, the economic system you use is entirely up to whomever hosts the instance.
|
||||
|
||||
I suggest an admin should manage the instance to lower incentive to manipulate balances.
|
||||
BIN
docs/localhost_diagram.png
Normal file
BIN
docs/localhost_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
12
docs/versioning.md
Normal file
12
docs/versioning.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Versioning
|
||||
|
||||
## Endpoint Version
|
||||
When changing an existing endpoint in a breaking way the version will increment in the path e.g `api/v1/user/log` -> `api/v2/user/log`. If the change is non-breaking then extra parameters will simply be added to the endpoint. If the older version is marked deprecated it will be documented in [endpoints.md](connected_services/how_to/endpoints.md)
|
||||
|
||||
## Release Version
|
||||
|
||||
Major changes (e.g `v1.0.0` -> `v2.0.0`) denote a breaking change as all previously deprecated endpoints will now be made defunct and wont be built with that release.
|
||||
|
||||
Minor changes (e.g `v1.0.0` -> `v1.1.0`) denote a non-breaking change that adds or changes something about CCash.
|
||||
|
||||
Patches (e.g `v1.0.0` -> `v1.0.1`) denote bug fixes or docs changes.
|
||||
27
fbe/user_model.fbe
Normal file
27
fbe/user_model.fbe
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package bank_dom
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
string counterparty = "";
|
||||
bool receiving = false;
|
||||
uint32 amount = 0;
|
||||
timestamp time;
|
||||
}
|
||||
|
||||
struct Logs
|
||||
{
|
||||
Transaction[] data;
|
||||
}
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32 balance = 0;
|
||||
uint64 password = 0;
|
||||
Logs? logs = null;
|
||||
}
|
||||
|
||||
struct Global
|
||||
{
|
||||
string[] keys;
|
||||
User[] users;
|
||||
}
|
||||
199
fbe/user_model/bank_dom.cpp
Normal file
199
fbe/user_model/bank_dom.cpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
Transaction::Transaction()
|
||||
: counterparty("")
|
||||
, receiving(false)
|
||||
, amount((uint32_t)0ull)
|
||||
, time((uint64_t)0ull)
|
||||
{}
|
||||
|
||||
Transaction::Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time)
|
||||
: counterparty(arg_counterparty)
|
||||
, receiving(arg_receiving)
|
||||
, amount(arg_amount)
|
||||
, time(arg_time)
|
||||
{}
|
||||
|
||||
bool Transaction::operator==(const Transaction& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Transaction::operator<(const Transaction& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Transaction::swap(Transaction& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(counterparty, other.counterparty);
|
||||
swap(receiving, other.receiving);
|
||||
swap(amount, other.amount);
|
||||
swap(time, other.time);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Transaction& value)
|
||||
{
|
||||
stream << "Transaction(";
|
||||
stream << "counterparty="; stream << "\"" << value.counterparty << "\"";
|
||||
stream << ",receiving="; stream << (value.receiving ? "true" : "false");
|
||||
stream << ",amount="; stream << value.amount;
|
||||
stream << ",time="; stream << value.time;
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
Logs::Logs()
|
||||
: data()
|
||||
{}
|
||||
|
||||
Logs::Logs(const std::vector<::bank_dom::Transaction>& arg_data)
|
||||
: data(arg_data)
|
||||
{}
|
||||
|
||||
bool Logs::operator==(const Logs& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Logs::operator<(const Logs& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Logs::swap(Logs& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(data, other.data);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Logs& value)
|
||||
{
|
||||
stream << "Logs(";
|
||||
{
|
||||
bool first = true;
|
||||
stream << "data=[" << value.data.size() << "][";
|
||||
for (const auto& it : value.data)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << it;
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
User::User()
|
||||
: balance((uint32_t)0ull)
|
||||
, password((uint64_t)0ull)
|
||||
, logs(std::nullopt)
|
||||
{}
|
||||
|
||||
User::User(uint32_t arg_balance, uint64_t arg_password, const std::optional<::bank_dom::Logs>& arg_logs)
|
||||
: balance(arg_balance)
|
||||
, password(arg_password)
|
||||
, logs(arg_logs)
|
||||
{}
|
||||
|
||||
bool User::operator==(const User& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool User::operator<(const User& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void User::swap(User& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(balance, other.balance);
|
||||
swap(password, other.password);
|
||||
swap(logs, other.logs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const User& value)
|
||||
{
|
||||
stream << "User(";
|
||||
stream << "balance="; stream << value.balance;
|
||||
stream << ",password="; stream << value.password;
|
||||
stream << ",logs="; if (value.logs) stream << *value.logs; else stream << "null";
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
Global::Global()
|
||||
: keys()
|
||||
, users()
|
||||
{}
|
||||
|
||||
Global::Global(const std::vector<std::string>& arg_keys, const std::vector<::bank_dom::User>& arg_users)
|
||||
: keys(arg_keys)
|
||||
, users(arg_users)
|
||||
{}
|
||||
|
||||
bool Global::operator==(const Global& other) const noexcept
|
||||
{
|
||||
return (
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bool Global::operator<(const Global& other) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Global::swap(Global& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(keys, other.keys);
|
||||
swap(users, other.users);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Global& value)
|
||||
{
|
||||
stream << "Global(";
|
||||
{
|
||||
bool first = true;
|
||||
stream << "keys=[" << value.keys.size() << "][";
|
||||
for (const auto& it : value.keys)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << "\"" << it << "\"";
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
{
|
||||
bool first = true;
|
||||
stream << ",users=[" << value.users.size() << "][";
|
||||
for (const auto& it : value.users)
|
||||
{
|
||||
stream << std::string(first ? "" : ",") << it;
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
240
fbe/user_model/bank_dom.h
Normal file
240
fbe/user_model/bank_dom.h
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace bank_dom {
|
||||
using namespace FBE;
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace FBE {
|
||||
using namespace ::bank_dom;
|
||||
} // namespace FBE
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
std::string counterparty;
|
||||
bool receiving;
|
||||
uint32_t amount;
|
||||
uint64_t time;
|
||||
|
||||
size_t fbe_type() const noexcept { return 1; }
|
||||
|
||||
Transaction();
|
||||
Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time);
|
||||
Transaction(const Transaction& other) = default;
|
||||
Transaction(Transaction&& other) = default;
|
||||
~Transaction() = default;
|
||||
|
||||
Transaction& operator=(const Transaction& other) = default;
|
||||
Transaction& operator=(Transaction&& other) = default;
|
||||
|
||||
bool operator==(const Transaction& other) const noexcept;
|
||||
bool operator!=(const Transaction& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Transaction& other) const noexcept;
|
||||
bool operator<=(const Transaction& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Transaction& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Transaction& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Transaction& value);
|
||||
|
||||
void swap(Transaction& other) noexcept;
|
||||
friend void swap(Transaction& value1, Transaction& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Transaction> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct std::hash<bank_dom::Transaction>
|
||||
{
|
||||
typedef bank_dom::Transaction argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Logs
|
||||
{
|
||||
std::vector<::bank_dom::Transaction> data;
|
||||
|
||||
size_t fbe_type() const noexcept { return 2; }
|
||||
|
||||
Logs();
|
||||
explicit Logs(const std::vector<::bank_dom::Transaction>& arg_data);
|
||||
Logs(const Logs& other) = default;
|
||||
Logs(Logs&& other) = default;
|
||||
~Logs() = default;
|
||||
|
||||
Logs& operator=(const Logs& other) = default;
|
||||
Logs& operator=(Logs&& other) = default;
|
||||
|
||||
bool operator==(const Logs& other) const noexcept;
|
||||
bool operator!=(const Logs& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Logs& other) const noexcept;
|
||||
bool operator<=(const Logs& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Logs& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Logs& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Logs& value);
|
||||
|
||||
void swap(Logs& other) noexcept;
|
||||
friend void swap(Logs& value1, Logs& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Logs> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct std::hash<bank_dom::Logs>
|
||||
{
|
||||
typedef bank_dom::Logs argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32_t balance;
|
||||
uint64_t password;
|
||||
std::optional<::bank_dom::Logs> logs;
|
||||
|
||||
size_t fbe_type() const noexcept { return 3; }
|
||||
|
||||
User();
|
||||
User(uint32_t arg_balance, uint64_t arg_password, const std::optional<::bank_dom::Logs>& arg_logs);
|
||||
User(const User& other) = default;
|
||||
User(User&& other) = default;
|
||||
~User() = default;
|
||||
|
||||
User& operator=(const User& other) = default;
|
||||
User& operator=(User&& other) = default;
|
||||
|
||||
bool operator==(const User& other) const noexcept;
|
||||
bool operator!=(const User& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const User& other) const noexcept;
|
||||
bool operator<=(const User& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const User& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const User& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const User& value);
|
||||
|
||||
void swap(User& other) noexcept;
|
||||
friend void swap(User& value1, User& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::User> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct std::hash<bank_dom::User>
|
||||
{
|
||||
typedef bank_dom::User argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Global
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
std::vector<::bank_dom::User> users;
|
||||
|
||||
size_t fbe_type() const noexcept { return 4; }
|
||||
|
||||
Global();
|
||||
Global(const std::vector<std::string>& arg_keys, const std::vector<::bank_dom::User>& arg_users);
|
||||
Global(const Global& other) = default;
|
||||
Global(Global&& other) = default;
|
||||
~Global() = default;
|
||||
|
||||
Global& operator=(const Global& other) = default;
|
||||
Global& operator=(Global&& other) = default;
|
||||
|
||||
bool operator==(const Global& other) const noexcept;
|
||||
bool operator!=(const Global& other) const noexcept { return !operator==(other); }
|
||||
bool operator<(const Global& other) const noexcept;
|
||||
bool operator<=(const Global& other) const noexcept { return operator<(other) || operator==(other); }
|
||||
bool operator>(const Global& other) const noexcept { return !operator<=(other); }
|
||||
bool operator>=(const Global& other) const noexcept { return !operator<(other); }
|
||||
|
||||
std::string string() const { std::stringstream ss; ss << *this; return ss.str(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Global& value);
|
||||
|
||||
void swap(Global& other) noexcept;
|
||||
friend void swap(Global& value1, Global& value2) noexcept { value1.swap(value2); }
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Global> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct std::hash<bank_dom::Global>
|
||||
{
|
||||
typedef bank_dom::Global argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
} // namespace bank_dom
|
||||
640
fbe/user_model/bank_dom_final_models.cpp
Normal file
640
fbe/user_model/bank_dom_final_models.cpp
Normal file
|
|
@ -0,0 +1,640 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom_final_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, counterparty(buffer, 0)
|
||||
, receiving(buffer, 0)
|
||||
, amount(buffer, 0)
|
||||
, time(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ counterparty.fbe_allocation_size(fbe_value.counterparty)
|
||||
+ receiving.fbe_allocation_size(fbe_value.receiving)
|
||||
+ amount.fbe_allocation_size(fbe_value.amount)
|
||||
+ time.fbe_allocation_size(fbe_value.time)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::get(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.get(fbe_value.counterparty);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.get(fbe_value.receiving);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.get(fbe_value.amount);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.get(fbe_value.time);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.set(fbe_value.counterparty);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.set(fbe_value.receiving);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
amount.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = amount.set(fbe_value.amount);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
time.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = time.set(fbe_value.time);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool TransactionFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t TransactionFinalModel::serialize(const ::bank_dom::Transaction& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t TransactionFinalModel::deserialize(::bank_dom::Transaction& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::Logs>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, data(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::fbe_allocation_size(const ::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ data.fbe_allocation_size(fbe_value.data)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::get(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::get_fields(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.get(fbe_value.data);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::set(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Logs>::set_fields(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
data.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = data.set(fbe_value.data);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool LogsFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t LogsFinalModel::serialize(const ::bank_dom::Logs& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t LogsFinalModel::deserialize(::bank_dom::Logs& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::User>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, balance(buffer, 0)
|
||||
, password(buffer, 0)
|
||||
, logs(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::fbe_allocation_size(const ::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ balance.fbe_allocation_size(fbe_value.balance)
|
||||
+ password.fbe_allocation_size(fbe_value.password)
|
||||
+ logs.fbe_allocation_size(fbe_value.logs)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::get(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::get_fields(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.get(fbe_value.balance);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.get(fbe_value.password);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.get(fbe_value.logs);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::set(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::User>::set_fields(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
balance.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = balance.set(fbe_value.balance);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
password.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = password.set(fbe_value.password);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
logs.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = logs.set(fbe_value.logs);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool UserFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t UserFinalModel::serialize(const ::bank_dom::User& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t UserFinalModel::deserialize(::bank_dom::User& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FinalModel<::bank_dom::Global>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, keys(buffer, 0)
|
||||
, users(buffer, 0)
|
||||
{}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::fbe_allocation_size(const ::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ keys.fbe_allocation_size(fbe_value.keys)
|
||||
+ users.fbe_allocation_size(fbe_value.users)
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::verify() const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = verify_fields();
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::verify_fields() const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
return fbe_current_offset;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::get(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = get_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::get_fields(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.get(fbe_value.keys);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.get(fbe_value.users);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::set(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
_buffer.shift(fbe_offset());
|
||||
size_t fbe_result = set_fields(fbe_value);
|
||||
_buffer.unshift(fbe_offset());
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FinalModel<::bank_dom::Global>::set_fields(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
keys.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = keys.set(fbe_value.keys);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
users.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = users.set(fbe_value.users);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
return fbe_current_size;
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool GlobalFinalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
return ((8 + _model.verify()) == fbe_struct_size);
|
||||
}
|
||||
|
||||
size_t GlobalFinalModel::serialize(const ::bank_dom::Global& value)
|
||||
{
|
||||
size_t fbe_initial_size = this->buffer().size();
|
||||
|
||||
uint32_t fbe_struct_type = (uint32_t)fbe_type();
|
||||
uint32_t fbe_struct_size = (uint32_t)(8 + _model.fbe_allocation_size(value));
|
||||
uint32_t fbe_struct_offset = (uint32_t)(this->buffer().allocate(fbe_struct_size) - this->buffer().offset());
|
||||
assert(((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + fbe_struct_offset + fbe_struct_size) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
fbe_struct_size = (uint32_t)(8 + _model.set(value));
|
||||
this->buffer().resize(fbe_initial_size + fbe_struct_size);
|
||||
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8)) = fbe_struct_size;
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4)) = fbe_struct_type;
|
||||
|
||||
return fbe_struct_size;
|
||||
}
|
||||
|
||||
size_t GlobalFinalModel::deserialize(::bank_dom::Global& value) const noexcept
|
||||
{
|
||||
assert(((this->buffer().offset() + _model.fbe_offset()) <= this->buffer().size()) && "Model is broken!");
|
||||
if ((this->buffer().offset() + _model.fbe_offset()) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_struct_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 8));
|
||||
size_t fbe_struct_type = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + _model.fbe_offset() - 4));
|
||||
assert(((fbe_struct_size > 0) && (fbe_struct_type == fbe_type())) && "Model is broken!");
|
||||
if ((fbe_struct_size == 0) || (fbe_struct_type != fbe_type()))
|
||||
return 8;
|
||||
|
||||
return 8 + _model.get(value);
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
322
fbe/user_model/bank_dom_final_models.h
Normal file
322
fbe/user_model/bank_dom_final_models.h
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe_final_models.h"
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Transaction final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Transaction>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 1; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModel<std::string> counterparty;
|
||||
FinalModel<bool> receiving;
|
||||
FinalModel<uint32_t> amount;
|
||||
FinalModel<uint64_t> time;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Transaction final model
|
||||
class TransactionFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
TransactionFinalModel() : _model(this->buffer(), 8) {}
|
||||
TransactionFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Transaction>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Transaction& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Transaction& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Transaction> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Logs final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Logs>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 2; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModelVector<::bank_dom::Transaction> data;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Logs final model
|
||||
class LogsFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
LogsFinalModel() : _model(this->buffer(), 8) {}
|
||||
LogsFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Logs>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Logs& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Logs& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Logs> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::User final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::User>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 3; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::User& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::User& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::User& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModel<uint32_t> balance;
|
||||
FinalModel<uint64_t> password;
|
||||
FinalModel<std::optional<::bank_dom::Logs>> logs;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding User final model
|
||||
class UserFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
UserFinalModel() : _model(this->buffer(), 8) {}
|
||||
UserFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::User>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::User& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::User& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::User> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Global final model
|
||||
template <>
|
||||
class FinalModel<::bank_dom::Global>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const ::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the final offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the final offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
// Get the final type
|
||||
static constexpr size_t fbe_type() noexcept { return 4; }
|
||||
|
||||
// Shift the current final offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current final offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
size_t verify() const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
size_t verify_fields() const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
size_t get(::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
size_t get_fields(::bank_dom::Global& fbe_value) const noexcept;
|
||||
|
||||
// Set the struct value
|
||||
size_t set(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
size_t set_fields(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModelVector<std::string> keys;
|
||||
FinalModelVector<::bank_dom::User> users;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Global final model
|
||||
class GlobalFinalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
GlobalFinalModel() : _model(this->buffer(), 8) {}
|
||||
GlobalFinalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), _model(this->buffer(), 8) {}
|
||||
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FinalModel<::bank_dom::Global>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Global& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Global& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { _model.fbe_shift(prev); }
|
||||
|
||||
private:
|
||||
FinalModel<::bank_dom::Global> _model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
932
fbe/user_model/bank_dom_models.cpp
Normal file
932
fbe/user_model/bank_dom_models.cpp
Normal file
|
|
@ -0,0 +1,932 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, counterparty(buffer, 4 + 4)
|
||||
, receiving(buffer, counterparty.fbe_offset() + counterparty.fbe_size())
|
||||
, amount(buffer, receiving.fbe_offset() + receiving.fbe_size())
|
||||
, time(buffer, amount.fbe_offset() + amount.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ counterparty.fbe_size()
|
||||
+ receiving.fbe_size()
|
||||
+ amount.fbe_size()
|
||||
+ time.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ counterparty.fbe_extra()
|
||||
+ receiving.fbe_extra()
|
||||
+ amount.fbe_extra()
|
||||
+ time.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Transaction>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Transaction>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + counterparty.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!counterparty.verify())
|
||||
return false;
|
||||
fbe_current_size += counterparty.fbe_size();
|
||||
|
||||
if ((fbe_current_size + receiving.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!receiving.verify())
|
||||
return false;
|
||||
fbe_current_size += receiving.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!amount.verify())
|
||||
return false;
|
||||
fbe_current_size += amount.fbe_size();
|
||||
|
||||
if ((fbe_current_size + time.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!time.verify())
|
||||
return false;
|
||||
fbe_current_size += time.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get(::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + counterparty.fbe_size()) <= fbe_struct_size)
|
||||
counterparty.get(fbe_value.counterparty, "");
|
||||
else
|
||||
fbe_value.counterparty = "";
|
||||
fbe_current_size += counterparty.fbe_size();
|
||||
|
||||
if ((fbe_current_size + receiving.fbe_size()) <= fbe_struct_size)
|
||||
receiving.get(fbe_value.receiving, false);
|
||||
else
|
||||
fbe_value.receiving = false;
|
||||
fbe_current_size += receiving.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) <= fbe_struct_size)
|
||||
amount.get(fbe_value.amount, (uint32_t)0ull);
|
||||
else
|
||||
fbe_value.amount = (uint32_t)0ull;
|
||||
fbe_current_size += amount.fbe_size();
|
||||
|
||||
if ((fbe_current_size + time.fbe_size()) <= fbe_struct_size)
|
||||
time.get(fbe_value.time);
|
||||
else
|
||||
fbe_value.time = (uint64_t)0ull;
|
||||
fbe_current_size += time.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
counterparty.set(fbe_value.counterparty);
|
||||
receiving.set(fbe_value.receiving);
|
||||
amount.set(fbe_value.amount);
|
||||
time.set(fbe_value.time);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool TransactionModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t TransactionModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t TransactionModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t TransactionModel::serialize(const ::bank_dom::Transaction& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t TransactionModel::deserialize(::bank_dom::Transaction& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::Logs>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, data(buffer, 4 + 4)
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ data.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ data.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Logs>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Logs>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + data.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!data.verify())
|
||||
return false;
|
||||
fbe_current_size += data.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get(::bank_dom::Logs& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::get_fields(::bank_dom::Logs& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + data.fbe_size()) <= fbe_struct_size)
|
||||
data.get(fbe_value.data);
|
||||
else
|
||||
fbe_value.data.clear();
|
||||
fbe_current_size += data.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Logs>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Logs>::set_fields(const ::bank_dom::Logs& fbe_value) noexcept
|
||||
{
|
||||
data.set(fbe_value.data);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool LogsModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t LogsModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t LogsModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t LogsModel::serialize(const ::bank_dom::Logs& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t LogsModel::deserialize(::bank_dom::Logs& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::User>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, balance(buffer, 4 + 4)
|
||||
, password(buffer, balance.fbe_offset() + balance.fbe_size())
|
||||
, logs(buffer, password.fbe_offset() + password.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ balance.fbe_size()
|
||||
+ password.fbe_size()
|
||||
+ logs.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ balance.fbe_extra()
|
||||
+ password.fbe_extra()
|
||||
+ logs.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::User>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::User>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + balance.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!balance.verify())
|
||||
return false;
|
||||
fbe_current_size += balance.fbe_size();
|
||||
|
||||
if ((fbe_current_size + password.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!password.verify())
|
||||
return false;
|
||||
fbe_current_size += password.fbe_size();
|
||||
|
||||
if ((fbe_current_size + logs.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!logs.verify())
|
||||
return false;
|
||||
fbe_current_size += logs.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get(::bank_dom::User& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::get_fields(::bank_dom::User& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + balance.fbe_size()) <= fbe_struct_size)
|
||||
balance.get(fbe_value.balance, (uint32_t)0ull);
|
||||
else
|
||||
fbe_value.balance = (uint32_t)0ull;
|
||||
fbe_current_size += balance.fbe_size();
|
||||
|
||||
if ((fbe_current_size + password.fbe_size()) <= fbe_struct_size)
|
||||
password.get(fbe_value.password, (uint64_t)0ull);
|
||||
else
|
||||
fbe_value.password = (uint64_t)0ull;
|
||||
fbe_current_size += password.fbe_size();
|
||||
|
||||
if ((fbe_current_size + logs.fbe_size()) <= fbe_struct_size)
|
||||
logs.get(fbe_value.logs, std::nullopt);
|
||||
else
|
||||
fbe_value.logs = std::nullopt;
|
||||
fbe_current_size += logs.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::User>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::User>::set_fields(const ::bank_dom::User& fbe_value) noexcept
|
||||
{
|
||||
balance.set(fbe_value.balance);
|
||||
password.set(fbe_value.password);
|
||||
logs.set(fbe_value.logs);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool UserModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t UserModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t UserModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t UserModel::serialize(const ::bank_dom::User& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t UserModel::deserialize(::bank_dom::User& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
FieldModel<::bank_dom::Global>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, keys(buffer, 4 + 4)
|
||||
, users(buffer, keys.fbe_offset() + keys.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ keys.fbe_size()
|
||||
+ users.fbe_size()
|
||||
;
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ keys.fbe_extra()
|
||||
+ users.fbe_extra()
|
||||
;
|
||||
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Global>::verify(bool fbe_verify_type) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return false;
|
||||
|
||||
uint32_t fbe_struct_type = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4));
|
||||
if (fbe_verify_type && (fbe_struct_type != fbe_type()))
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
bool fbe_result = verify_fields(fbe_struct_size);
|
||||
_buffer.unshift(fbe_struct_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
bool FieldModel<::bank_dom::Global>::verify_fields(size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + keys.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!keys.verify())
|
||||
return false;
|
||||
fbe_current_size += keys.fbe_size();
|
||||
|
||||
if ((fbe_current_size + users.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!users.verify())
|
||||
return false;
|
||||
fbe_current_size += users.fbe_size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::get_begin() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + 4 + 4) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + 4 + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset));
|
||||
assert((fbe_struct_size >= (4 + 4)) && "Model is broken!");
|
||||
if (fbe_struct_size < (4 + 4))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get(::bank_dom::Global& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
uint32_t fbe_struct_size = *((const uint32_t*)(_buffer.data() + _buffer.offset()));
|
||||
get_fields(fbe_value, fbe_struct_size);
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::get_fields(::bank_dom::Global& fbe_value, size_t fbe_struct_size) const noexcept
|
||||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + keys.fbe_size()) <= fbe_struct_size)
|
||||
keys.get(fbe_value.keys);
|
||||
else
|
||||
fbe_value.keys.clear();
|
||||
fbe_current_size += keys.fbe_size();
|
||||
|
||||
if ((fbe_current_size + users.fbe_size()) <= fbe_struct_size)
|
||||
users.get(fbe_value.users);
|
||||
else
|
||||
fbe_value.users.clear();
|
||||
fbe_current_size += users.fbe_size();
|
||||
}
|
||||
|
||||
size_t FieldModel<::bank_dom::Global>::set_begin()
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_struct_size = (uint32_t)fbe_body();
|
||||
uint32_t fbe_struct_offset = (uint32_t)(_buffer.allocate(fbe_struct_size) - _buffer.offset());
|
||||
assert(((fbe_struct_offset > 0) && ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_struct_offset == 0) || ((_buffer.offset() + fbe_struct_offset + fbe_struct_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_struct_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset)) = fbe_struct_size;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_struct_offset + 4)) = (uint32_t)fbe_type();
|
||||
|
||||
_buffer.shift(fbe_struct_offset);
|
||||
return fbe_struct_offset;
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
size_t fbe_begin = set_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
set_fields(fbe_value);
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
void FieldModel<::bank_dom::Global>::set_fields(const ::bank_dom::Global& fbe_value) noexcept
|
||||
{
|
||||
keys.set(fbe_value.keys);
|
||||
users.set(fbe_value.users);
|
||||
}
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
bool GlobalModel::verify()
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return false;
|
||||
|
||||
return model.verify();
|
||||
}
|
||||
|
||||
size_t GlobalModel::create_begin()
|
||||
{
|
||||
size_t fbe_begin = this->buffer().allocate(4 + model.fbe_size());
|
||||
return fbe_begin;
|
||||
}
|
||||
|
||||
size_t GlobalModel::create_end(size_t fbe_begin)
|
||||
{
|
||||
size_t fbe_end = this->buffer().size();
|
||||
uint32_t fbe_full_size = (uint32_t)(fbe_end - fbe_begin);
|
||||
*((uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4)) = fbe_full_size;
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t GlobalModel::serialize(const ::bank_dom::Global& value)
|
||||
{
|
||||
size_t fbe_begin = create_begin();
|
||||
model.set(value);
|
||||
size_t fbe_full_size = create_end(fbe_begin);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
size_t GlobalModel::deserialize(::bank_dom::Global& value) const noexcept
|
||||
{
|
||||
if ((this->buffer().offset() + model.fbe_offset() - 4) > this->buffer().size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_full_size = *((const uint32_t*)(this->buffer().data() + this->buffer().offset() + model.fbe_offset() - 4));
|
||||
assert((fbe_full_size >= model.fbe_size()) && "Model is broken!");
|
||||
if (fbe_full_size < model.fbe_size())
|
||||
return 0;
|
||||
|
||||
model.get(value);
|
||||
return fbe_full_size;
|
||||
}
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
398
fbe/user_model/bank_dom_models.h
Normal file
398
fbe/user_model/bank_dom_models.h
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe_models.h"
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Transaction field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Transaction>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 1; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Transaction& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Transaction& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Transaction& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModel<std::string> counterparty;
|
||||
FieldModel<bool> receiving;
|
||||
FieldModel<uint32_t> amount;
|
||||
FieldModel<uint64_t> time;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Transaction model
|
||||
class TransactionModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
TransactionModel() : model(this->buffer(), 4) {}
|
||||
TransactionModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Transaction>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Transaction& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Transaction& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Transaction> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Logs field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Logs>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 2; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Logs& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Logs& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Logs& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModelVector<::bank_dom::Transaction> data;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Logs model
|
||||
class LogsModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
LogsModel() : model(this->buffer(), 4) {}
|
||||
LogsModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Logs>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Logs& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Logs& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Logs> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::User field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::User>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 3; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::User& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::User& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::User& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::User& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModel<uint32_t> balance;
|
||||
FieldModel<uint64_t> password;
|
||||
FieldModel<std::optional<::bank_dom::Logs>> logs;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding User model
|
||||
class UserModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
UserModel() : model(this->buffer(), 4) {}
|
||||
UserModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::User>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::User& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::User& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::User> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
// Fast Binary Encoding ::bank_dom::Global field model
|
||||
template <>
|
||||
class FieldModel<::bank_dom::Global>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field body size
|
||||
size_t fbe_body() const noexcept;
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
// Get the field type
|
||||
static constexpr size_t fbe_type() noexcept { return 4; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify(bool fbe_verify_type = true) const noexcept;
|
||||
// Check if the struct fields are valid
|
||||
bool verify_fields(size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Get the struct value (begin phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the struct value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the struct value
|
||||
void get(::bank_dom::Global& fbe_value) const noexcept;
|
||||
// Get the struct fields values
|
||||
void get_fields(::bank_dom::Global& fbe_value, size_t fbe_struct_size) const noexcept;
|
||||
|
||||
// Set the struct value (begin phase)
|
||||
size_t set_begin();
|
||||
// Set the struct value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the struct value
|
||||
void set(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
// Set the struct fields values
|
||||
void set_fields(const ::bank_dom::Global& fbe_value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModelVector<std::string> keys;
|
||||
FieldModelVector<::bank_dom::User> users;
|
||||
};
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
// Fast Binary Encoding Global model
|
||||
class GlobalModel : public FBE::Model
|
||||
{
|
||||
public:
|
||||
GlobalModel() : model(this->buffer(), 4) {}
|
||||
GlobalModel(const std::shared_ptr<FBEBuffer>& buffer) : FBE::Model(buffer), model(this->buffer(), 4) {}
|
||||
|
||||
// Get the model size
|
||||
size_t fbe_size() const noexcept { return model.fbe_size() + model.fbe_extra(); }
|
||||
// Get the model type
|
||||
static constexpr size_t fbe_type() noexcept { return FieldModel<::bank_dom::Global>::fbe_type(); }
|
||||
|
||||
// Check if the struct value is valid
|
||||
bool verify();
|
||||
|
||||
// Create a new model (begin phase)
|
||||
size_t create_begin();
|
||||
// Create a new model (end phase)
|
||||
size_t create_end(size_t fbe_begin);
|
||||
|
||||
// Serialize the struct value
|
||||
size_t serialize(const ::bank_dom::Global& value);
|
||||
// Deserialize the struct value
|
||||
size_t deserialize(::bank_dom::Global& value) const noexcept;
|
||||
|
||||
// Move to the next struct value
|
||||
void next(size_t prev) noexcept { model.fbe_shift(prev); }
|
||||
|
||||
public:
|
||||
FieldModel<::bank_dom::Global> model;
|
||||
};
|
||||
|
||||
} // namespace bank_dom
|
||||
|
||||
} // namespace FBE
|
||||
415
fbe/user_model/fbe.cpp
Normal file
415
fbe/user_model/fbe.cpp
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <rpc.h>
|
||||
#undef DELETE
|
||||
#undef ERROR
|
||||
#undef HOST_NOT_FOUND
|
||||
#undef Yield
|
||||
#undef min
|
||||
#undef max
|
||||
#undef uuid_t
|
||||
#endif
|
||||
|
||||
namespace FBE {
|
||||
|
||||
std::string buffer_t::base64encode() const
|
||||
{
|
||||
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
std::string result;
|
||||
|
||||
int val = 0;
|
||||
int valb = -6;
|
||||
for (auto c : _data)
|
||||
{
|
||||
val = (val << 8) + c;
|
||||
valb += 8;
|
||||
while (valb >= 0)
|
||||
{
|
||||
result.push_back(base64[(val >> valb) & 0x3F]);
|
||||
valb -= 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (valb > -6)
|
||||
result.push_back(base64[((val << 8) >> (valb + 8)) & 0x3F]);
|
||||
|
||||
while (result.size() % 4)
|
||||
result.push_back('=');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
buffer_t buffer_t::base64decode(const std::string& str)
|
||||
{
|
||||
const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
buffer_t result;
|
||||
|
||||
std::vector<int> pattern(256, -1);
|
||||
for (int i = 0; i < 64; ++i)
|
||||
pattern[base64[i]] = i;
|
||||
|
||||
int val = 0;
|
||||
int valb = -8;
|
||||
for (auto c : str)
|
||||
{
|
||||
if (pattern[c] == -1)
|
||||
break;
|
||||
|
||||
val = (val << 6) + pattern[c];
|
||||
valb += 6;
|
||||
|
||||
if (valb >= 0)
|
||||
{
|
||||
result.push_back((uint8_t)((val >> valb) & 0xFF));
|
||||
valb -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t utc()
|
||||
{
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
struct timespec timestamp;
|
||||
if (clock_gettime(CLOCK_REALTIME, ×tamp) != 0)
|
||||
throw std::runtime_error("Cannot get value of CLOCK_REALTIME timer!");
|
||||
return (timestamp.tv_sec * 1000000000) + timestamp.tv_nsec;
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
FILETIME ft;
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
|
||||
ULARGE_INTEGER result;
|
||||
result.LowPart = ft.dwLowDateTime;
|
||||
result.HighPart = ft.dwHighDateTime;
|
||||
return (result.QuadPart - 116444736000000000ull) * 100;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t unhex(char ch)
|
||||
{
|
||||
if ((ch >= '0') && (ch <= '9'))
|
||||
return ch - '0';
|
||||
else if ((ch >= 'a') && (ch <= 'f'))
|
||||
return 10 + ch - 'a';
|
||||
else if ((ch >= 'A') && (ch <= 'F'))
|
||||
return 10 + ch - 'A';
|
||||
else
|
||||
return 255;
|
||||
}
|
||||
|
||||
uuid_t::uuid_t(const std::string& uuid)
|
||||
{
|
||||
char v1 = 0;
|
||||
char v2 = 0;
|
||||
bool pack = false;
|
||||
size_t index = 0;
|
||||
|
||||
// Parse UUID string
|
||||
for (auto ch : uuid)
|
||||
{
|
||||
if ((ch == '-') || (ch == '{') || (ch == '}'))
|
||||
continue;
|
||||
|
||||
if (pack)
|
||||
{
|
||||
v2 = ch;
|
||||
pack = false;
|
||||
uint8_t ui1 = unhex(v1);
|
||||
uint8_t ui2 = unhex(v2);
|
||||
if ((ui1 > 15) || (ui2 > 15))
|
||||
throw std::invalid_argument("Invalid UUID string: " + uuid);
|
||||
_data[index++] = ui1 * 16 + ui2;
|
||||
if (index >= 16)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = ch;
|
||||
pack = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill remaining data with zeros
|
||||
for (; index < 16; ++index)
|
||||
_data[index++] = 0;
|
||||
}
|
||||
|
||||
std::string uuid_t::string() const
|
||||
{
|
||||
const char* digits = "0123456789abcdef";
|
||||
|
||||
std::string result(36, '0');
|
||||
|
||||
int index = 0;
|
||||
for (auto value : _data)
|
||||
{
|
||||
result[index++] = digits[(value >> 4) & 0x0F];
|
||||
result[index++] = digits[(value >> 0) & 0x0F];
|
||||
if ((index == 8) || (index == 13) || (index == 18) || (index == 23))
|
||||
result[index++] = '-';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uuid_t uuid_t::sequential()
|
||||
{
|
||||
uuid_t result;
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
::uuid_t uuid;
|
||||
uuid_generate_time(uuid);
|
||||
result._data[0] = uuid[0];
|
||||
result._data[1] = uuid[1];
|
||||
result._data[2] = uuid[2];
|
||||
result._data[3] = uuid[3];
|
||||
result._data[4] = uuid[4];
|
||||
result._data[5] = uuid[5];
|
||||
result._data[6] = uuid[6];
|
||||
result._data[7] = uuid[7];
|
||||
result._data[8] = uuid[8];
|
||||
result._data[9] = uuid[9];
|
||||
result._data[10] = uuid[10];
|
||||
result._data[11] = uuid[11];
|
||||
result._data[12] = uuid[12];
|
||||
result._data[13] = uuid[13];
|
||||
result._data[14] = uuid[14];
|
||||
result._data[15] = uuid[15];
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
::UUID uuid;
|
||||
if (UuidCreateSequential(&uuid) != RPC_S_OK)
|
||||
throw std::runtime_error("Cannot generate sequential UUID!");
|
||||
|
||||
result._data[0] = (uuid.Data1 >> 24) & 0xFF;
|
||||
result._data[1] = (uuid.Data1 >> 16) & 0xFF;
|
||||
result._data[2] = (uuid.Data1 >> 8) & 0xFF;
|
||||
result._data[3] = (uuid.Data1 >> 0) & 0xFF;
|
||||
result._data[4] = (uuid.Data2 >> 8) & 0xFF;
|
||||
result._data[5] = (uuid.Data2 >> 0) & 0xFF;
|
||||
|
||||
result._data[6] = (uuid.Data3 >> 8) & 0xFF;
|
||||
result._data[7] = (uuid.Data3 >> 0) & 0xFF;
|
||||
|
||||
result._data[8] = uuid.Data4[0];
|
||||
result._data[9] = uuid.Data4[1];
|
||||
|
||||
result._data[10] = uuid.Data4[2];
|
||||
result._data[11] = uuid.Data4[3];
|
||||
result._data[12] = uuid.Data4[4];
|
||||
result._data[13] = uuid.Data4[5];
|
||||
result._data[14] = uuid.Data4[6];
|
||||
result._data[15] = uuid.Data4[7];
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
uuid_t uuid_t::random()
|
||||
{
|
||||
uuid_t result;
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
::uuid_t uuid;
|
||||
uuid_generate_random(uuid);
|
||||
result._data[0] = uuid[0];
|
||||
result._data[1] = uuid[1];
|
||||
result._data[2] = uuid[2];
|
||||
result._data[3] = uuid[3];
|
||||
result._data[4] = uuid[4];
|
||||
result._data[5] = uuid[5];
|
||||
result._data[6] = uuid[6];
|
||||
result._data[7] = uuid[7];
|
||||
result._data[8] = uuid[8];
|
||||
result._data[9] = uuid[9];
|
||||
result._data[10] = uuid[10];
|
||||
result._data[11] = uuid[11];
|
||||
result._data[12] = uuid[12];
|
||||
result._data[13] = uuid[13];
|
||||
result._data[14] = uuid[14];
|
||||
result._data[15] = uuid[15];
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
::UUID uuid;
|
||||
if (UuidCreate(&uuid) != RPC_S_OK)
|
||||
throw std::runtime_error("Cannot generate random UUID!");
|
||||
|
||||
result._data[0] = (uuid.Data1 >> 24) & 0xFF;
|
||||
result._data[1] = (uuid.Data1 >> 16) & 0xFF;
|
||||
result._data[2] = (uuid.Data1 >> 8) & 0xFF;
|
||||
result._data[3] = (uuid.Data1 >> 0) & 0xFF;
|
||||
result._data[4] = (uuid.Data2 >> 8) & 0xFF;
|
||||
result._data[5] = (uuid.Data2 >> 0) & 0xFF;
|
||||
|
||||
result._data[6] = (uuid.Data3 >> 8) & 0xFF;
|
||||
result._data[7] = (uuid.Data3 >> 0) & 0xFF;
|
||||
|
||||
result._data[8] = uuid.Data4[0];
|
||||
result._data[9] = uuid.Data4[1];
|
||||
|
||||
result._data[10] = uuid.Data4[2];
|
||||
result._data[11] = uuid.Data4[3];
|
||||
result._data[12] = uuid.Data4[4];
|
||||
result._data[13] = uuid.Data4[5];
|
||||
result._data[14] = uuid.Data4[6];
|
||||
result._data[15] = uuid.Data4[7];
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
CppLogging::Record& operator<<(CppLogging::Record& record, const uuid_t& uuid)
|
||||
{
|
||||
const char* digits = "0123456789abcdef";
|
||||
|
||||
std::array<char, 36> result;
|
||||
|
||||
int index = 0;
|
||||
for (auto value : uuid.data())
|
||||
{
|
||||
result[index++] = digits[(value >> 4) & 0x0F];
|
||||
result[index++] = digits[(value >> 0) & 0x0F];
|
||||
if ((index == 8) || (index == 13) || (index == 18) || (index == 23))
|
||||
result[index++] = '-';
|
||||
}
|
||||
|
||||
return record.StoreCustom(std::string_view(result.data(), result.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
void FBEBuffer::attach(const void* data, size_t size, size_t offset)
|
||||
{
|
||||
assert((data != nullptr) && "Invalid buffer!");
|
||||
if (data == nullptr)
|
||||
throw std::invalid_argument("Invalid buffer!");
|
||||
assert((size > 0) && "Invalid size!");
|
||||
if (size == 0)
|
||||
throw std::invalid_argument("Invalid size!");
|
||||
assert((offset <= size) && "Invalid offset!");
|
||||
if (offset > size)
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
_data = (uint8_t*)data;
|
||||
_capacity = 0;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::attach(const std::vector<uint8_t>& buffer, size_t offset)
|
||||
{
|
||||
assert((buffer.data() != nullptr) && "Invalid buffer!");
|
||||
if (buffer.data() == nullptr)
|
||||
throw std::invalid_argument("Invalid buffer!");
|
||||
assert((buffer.size() > 0) && "Invalid size!");
|
||||
if (buffer.size() == 0)
|
||||
throw std::invalid_argument("Invalid size!");
|
||||
assert((offset <= buffer.size()) && "Invalid offset!");
|
||||
if (offset > buffer.size())
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
_data = (uint8_t*)buffer.data();
|
||||
_capacity = 0;
|
||||
_size = buffer.size();
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::clone(const void* data, size_t size, size_t offset)
|
||||
{
|
||||
assert((offset <= size) && "Invalid offset!");
|
||||
if (offset > size)
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
reserve(size);
|
||||
std::memcpy(_data, data, size);
|
||||
_capacity = size;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::clone(const std::vector<uint8_t>& buffer, size_t offset)
|
||||
{
|
||||
assert((offset <= buffer.size()) && "Invalid offset!");
|
||||
if (offset > buffer.size())
|
||||
throw std::invalid_argument("Invalid offset!");
|
||||
|
||||
size_t size = buffer.size();
|
||||
|
||||
reserve(size);
|
||||
std::memcpy(_data, buffer.data(), size);
|
||||
_capacity = size;
|
||||
_size = size;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
size_t FBEBuffer::allocate(size_t size)
|
||||
{
|
||||
size_t offset = _size;
|
||||
|
||||
// Calculate a new buffer size
|
||||
size_t total = _size + size;
|
||||
|
||||
if (total <= _capacity)
|
||||
{
|
||||
_size = total;
|
||||
return offset;
|
||||
}
|
||||
|
||||
_capacity = std::max(total, 2 * _capacity);
|
||||
uint8_t* data = (uint8_t*)std::malloc(_capacity);
|
||||
std::memcpy(data, _data, _size);
|
||||
std::free(_data);
|
||||
_data = data;
|
||||
_size = total;
|
||||
return offset;
|
||||
}
|
||||
|
||||
void FBEBuffer::remove(size_t offset, size_t size)
|
||||
{
|
||||
assert(((offset + size) <= _size) && "Invalid offset & size!");
|
||||
if ((offset + size) > _size)
|
||||
throw std::invalid_argument("Invalid offset & size!");
|
||||
|
||||
std::memcpy(_data + offset, _data + offset + size, _size - size - offset);
|
||||
_size -= size;
|
||||
if (_offset >= (offset + size))
|
||||
_offset -= size;
|
||||
else if (_offset >= offset)
|
||||
{
|
||||
_offset -= _offset - offset;
|
||||
if (_offset > _size)
|
||||
_offset = _size;
|
||||
}
|
||||
}
|
||||
|
||||
void FBEBuffer::reserve(size_t capacity)
|
||||
{
|
||||
if (capacity > _capacity)
|
||||
{
|
||||
_capacity = std::max(capacity, 2 * _capacity);
|
||||
uint8_t* data = (uint8_t*)std::malloc(_capacity);
|
||||
std::memcpy(data, _data, _size);
|
||||
std::free(_data);
|
||||
_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
void FBEBuffer::resize(size_t size)
|
||||
{
|
||||
reserve(size);
|
||||
_size = size;
|
||||
if (_offset > _size)
|
||||
_offset = _size;
|
||||
}
|
||||
|
||||
void FBEBuffer::reset()
|
||||
{
|
||||
_size = 0;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
667
fbe/user_model/fbe.h
Normal file
667
fbe/user_model/fbe.h
Normal file
|
|
@ -0,0 +1,667 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||
#include <time.h>
|
||||
#include <uuid/uuid.h>
|
||||
#undef HOST_NOT_FOUND
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#undef DELETE
|
||||
#undef ERROR
|
||||
#undef HOST_NOT_FOUND
|
||||
#undef Yield
|
||||
#undef min
|
||||
#undef max
|
||||
#undef uuid_t
|
||||
#endif
|
||||
|
||||
namespace FBE {
|
||||
|
||||
//! Bytes buffer type
|
||||
/*!
|
||||
Represents bytes buffer which is a lightweight wrapper around std::vector<uint8_t>
|
||||
with similar interface.
|
||||
*/
|
||||
class buffer_t
|
||||
{
|
||||
public:
|
||||
typedef std::vector<uint8_t>::iterator iterator;
|
||||
typedef std::vector<uint8_t>::const_iterator const_iterator;
|
||||
typedef std::vector<uint8_t>::reverse_iterator reverse_iterator;
|
||||
typedef std::vector<uint8_t>::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
buffer_t() = default;
|
||||
buffer_t(size_t capacity) { reserve(capacity); }
|
||||
buffer_t(const std::string& str) { assign(str); }
|
||||
buffer_t(size_t size, uint8_t value) { assign(size, value); }
|
||||
buffer_t(const uint8_t* data, size_t size) { assign(data, size); }
|
||||
buffer_t(const std::vector<uint8_t>& other) : _data(other) {}
|
||||
buffer_t(std::vector<uint8_t>&& other) : _data(std::move(other)) {}
|
||||
buffer_t(const buffer_t& other) = default;
|
||||
buffer_t(buffer_t&& other) = default;
|
||||
~buffer_t() = default;
|
||||
|
||||
buffer_t& operator=(const std::string& str) { assign(str); return *this; }
|
||||
buffer_t& operator=(const std::vector<uint8_t>& other) { _data = other; return *this; }
|
||||
buffer_t& operator=(std::vector<uint8_t>&& other) { _data = std::move(other); return *this; }
|
||||
buffer_t& operator=(const buffer_t& other) = default;
|
||||
buffer_t& operator=(buffer_t&& other) = default;
|
||||
|
||||
uint8_t& operator[](size_t index) { return _data[index]; }
|
||||
const uint8_t& operator[](size_t index) const { return _data[index]; }
|
||||
|
||||
bool empty() const { return _data.empty(); }
|
||||
size_t capacity() const { return _data.capacity(); }
|
||||
size_t size() const { return _data.size(); }
|
||||
size_t max_size() const { return _data.max_size(); }
|
||||
|
||||
std::vector<uint8_t>& buffer() noexcept { return _data; }
|
||||
const std::vector<uint8_t>& buffer() const noexcept { return _data; }
|
||||
uint8_t* data() noexcept { return _data.data(); }
|
||||
const uint8_t* data() const noexcept { return _data.data(); }
|
||||
uint8_t& at(size_t index) { return _data.at(index); }
|
||||
const uint8_t& at(size_t index) const { return _data.at(index); }
|
||||
uint8_t& front() { return _data.front(); }
|
||||
const uint8_t& front() const { return _data.front(); }
|
||||
uint8_t& back() { return _data.back(); }
|
||||
const uint8_t& back() const { return _data.back(); }
|
||||
|
||||
void reserve(size_t capacity) { _data.reserve(capacity); }
|
||||
void resize(size_t size, uint8_t value = 0) { _data.resize(size, value); }
|
||||
void shrink_to_fit() { _data.shrink_to_fit(); }
|
||||
|
||||
void assign(const std::string& str) { assign((const uint8_t*)str.c_str(), str.size()); }
|
||||
void assign(const std::vector<uint8_t>& vec) { assign(vec.begin(), vec.end()); }
|
||||
void assign(size_t size, uint8_t value) { _data.assign(size, value); }
|
||||
void assign(const uint8_t* data, size_t size) { _data.assign(data, data + size); }
|
||||
template <class InputIterator>
|
||||
void assign(InputIterator first, InputIterator last) { _data.assign(first, last); }
|
||||
iterator insert(const_iterator position, uint8_t value) { return _data.insert(position, value); }
|
||||
iterator insert(const_iterator position, const std::string& str) { return insert(position, (const uint8_t*)str.c_str(), str.size()); }
|
||||
iterator insert(const_iterator position, const std::vector<uint8_t>& vec) { return insert(position, vec.begin(), vec.end()); }
|
||||
iterator insert(const_iterator position, size_t size, uint8_t value) { return _data.insert(position, size, value); }
|
||||
iterator insert(const_iterator position, const uint8_t* data, size_t size) { return _data.insert(position, data, data + size); }
|
||||
template <class InputIterator>
|
||||
iterator insert(const_iterator position, InputIterator first, InputIterator last) { return _data.insert(position, first, last); }
|
||||
iterator erase(const_iterator position) { return _data.erase(position); }
|
||||
iterator erase(const_iterator first, const_iterator last) { return _data.erase(first, last); }
|
||||
void clear() noexcept { _data.clear(); }
|
||||
|
||||
void push_back(uint8_t value) { _data.push_back(value); }
|
||||
void pop_back() { _data.pop_back(); }
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator position, Args&&... args) { return _data.emplace(position, args...); }
|
||||
template <class... Args>
|
||||
void emplace_back(Args&&... args) { _data.emplace_back(args...); }
|
||||
|
||||
iterator begin() noexcept { return _data.begin(); }
|
||||
const_iterator begin() const noexcept { return _data.begin(); }
|
||||
const_iterator cbegin() const noexcept { return _data.cbegin(); }
|
||||
reverse_iterator rbegin() noexcept { return _data.rbegin(); }
|
||||
const_reverse_iterator rbegin() const noexcept { return _data.rbegin(); }
|
||||
const_reverse_iterator crbegin() const noexcept { return _data.crbegin(); }
|
||||
iterator end() noexcept { return _data.end(); }
|
||||
const_iterator end() const noexcept { return _data.end(); }
|
||||
const_iterator cend() const noexcept { return _data.cend(); }
|
||||
reverse_iterator rend() noexcept { return _data.rend(); }
|
||||
const_reverse_iterator rend() const noexcept { return _data.rend(); }
|
||||
const_reverse_iterator crend() const noexcept { return _data.crend(); }
|
||||
|
||||
//! Get the string equivalent from the bytes buffer
|
||||
std::string string() const { return std::string(_data.begin(), _data.end()); }
|
||||
|
||||
//! Encode the Base64 string from the bytes buffer
|
||||
std::string base64encode() const;
|
||||
//! Decode the bytes buffer from the Base64 string
|
||||
static buffer_t base64decode(const std::string& str);
|
||||
|
||||
//! Swap two instances
|
||||
void swap(buffer_t& value) noexcept
|
||||
{ using std::swap; swap(_data, value._data); }
|
||||
friend void swap(buffer_t& value1, buffer_t& value2) noexcept
|
||||
{ value1.swap(value2); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
|
||||
//! Decimal type
|
||||
/*!
|
||||
Represents decimal type using double and provides basic arithmetic operations.
|
||||
*/
|
||||
class decimal_t
|
||||
{
|
||||
public:
|
||||
decimal_t() noexcept { _value = 0.0; }
|
||||
decimal_t(int8_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint8_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int16_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint16_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int32_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint32_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(int64_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(uint64_t value) noexcept { _value = (double)value; }
|
||||
decimal_t(float value) noexcept { _value = (double)value; }
|
||||
decimal_t(double value) noexcept { _value = value; }
|
||||
template <typename T>
|
||||
explicit decimal_t(const T& value) noexcept { _value = (double)value; }
|
||||
decimal_t(const decimal_t& value) noexcept = default;
|
||||
decimal_t(decimal_t&& value) noexcept = default;
|
||||
~decimal_t() noexcept = default;
|
||||
|
||||
template <typename T>
|
||||
decimal_t& operator=(const T& value) noexcept { _value = (double)value; return *this; }
|
||||
decimal_t& operator=(const decimal_t& value) noexcept = default;
|
||||
decimal_t& operator=(decimal_t&& value) noexcept = default;
|
||||
|
||||
// Arithmetic operators
|
||||
decimal_t operator+() const noexcept { return decimal_t(_value); }
|
||||
decimal_t operator-() const noexcept { return decimal_t(-_value); }
|
||||
|
||||
decimal_t& operator++() noexcept { return *this += 1; }
|
||||
decimal_t operator++(int) noexcept { decimal_t temp(*this); ++*this; return temp; }
|
||||
decimal_t& operator--() noexcept { return *this -= 1; }
|
||||
decimal_t operator--(int) noexcept { decimal_t temp(*this); --*this; return temp; }
|
||||
|
||||
decimal_t& operator+=(const decimal_t& value) noexcept { return *this = *this + value; }
|
||||
decimal_t& operator-=(const decimal_t& value) noexcept { return *this = *this - value; }
|
||||
decimal_t& operator*=(const decimal_t& value) noexcept { return *this = *this * value; }
|
||||
decimal_t& operator/=(const decimal_t& value) { return *this = *this / value; }
|
||||
|
||||
template <typename T>
|
||||
decimal_t& operator+=(const T& value) noexcept { return *this = *this + decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator-=(const T& value) noexcept { return *this = *this - decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator*=(const T& value) noexcept { return *this = *this * decimal_t(value); }
|
||||
template <typename T>
|
||||
decimal_t& operator/=(const T& value) { return *this = *this / decimal_t(value); }
|
||||
|
||||
template <typename T>
|
||||
friend T& operator+=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) + value2); }
|
||||
template <typename T>
|
||||
friend T& operator-=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) - value2); }
|
||||
template <typename T>
|
||||
friend T& operator*=(T& value1, const decimal_t& value2) noexcept { return value1 = (T)(decimal_t(value1) * value2); }
|
||||
template <typename T>
|
||||
friend T& operator/=(T& value1, const decimal_t& value2) { return value1 = (T)(decimal_t(value1) / value2); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator+(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) + value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator+(const decimal_t& value1, const T& value2) noexcept { return value1 + decimal_t(value2); }
|
||||
friend decimal_t operator+(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value + value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator-(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) - value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator-(const decimal_t& value1, const T& value2) noexcept { return value1 - decimal_t(value2); }
|
||||
friend decimal_t operator-(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value - value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator*(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) * value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator*(const decimal_t& value1, const T& value2) noexcept { return value1 * decimal_t(value2); }
|
||||
friend decimal_t operator*(const decimal_t& value1, const decimal_t& value2) noexcept { return decimal_t(value1._value * value2._value); }
|
||||
|
||||
template <typename T>
|
||||
friend decimal_t operator/(const T& value1, const decimal_t& value2) { return decimal_t(value1) / value2; }
|
||||
template <typename T>
|
||||
friend decimal_t operator/(const decimal_t& value1, const T& value2) { return value1 / decimal_t(value2); }
|
||||
friend decimal_t operator/(const decimal_t& value1, const decimal_t& value2) { return decimal_t(value1._value / value2._value); }
|
||||
|
||||
// Comparison operators
|
||||
template <typename T>
|
||||
friend bool operator==(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) == value2; }
|
||||
template <typename T>
|
||||
friend bool operator==(const decimal_t& value1, const T& value2) noexcept { return value1 == decimal_t(value2); }
|
||||
friend bool operator==(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value == value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator!=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) != value2; }
|
||||
template <typename T>
|
||||
friend bool operator!=(const decimal_t& value1, const T& value2) noexcept { return value1 != decimal_t(value2); }
|
||||
friend bool operator!=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value != value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator<(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) < value2; }
|
||||
template <typename T>
|
||||
friend bool operator<(const decimal_t& value1, const T& value2) noexcept { return value1 < decimal_t(value2); }
|
||||
friend bool operator<(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value < value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator>(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) > value2; }
|
||||
template <typename T>
|
||||
friend bool operator>(const decimal_t& value1, const T& value2) noexcept { return value1 > decimal_t(value2); }
|
||||
friend bool operator>(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value > value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator<=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) <= value2; }
|
||||
template <typename T>
|
||||
friend bool operator<=(const decimal_t& value1, const T& value2) noexcept { return value1 <= decimal_t(value2); }
|
||||
friend bool operator<=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value <= value2._value; }
|
||||
|
||||
template <typename T>
|
||||
friend bool operator>=(const T& value1, const decimal_t& value2) noexcept { return decimal_t(value1) >= value2; }
|
||||
template <typename T>
|
||||
friend bool operator>=(const decimal_t& value1, const T& value2) noexcept { return value1 >= decimal_t(value2); }
|
||||
friend bool operator>=(const decimal_t& value1, const decimal_t& value2) noexcept { return value1._value >= value2._value; }
|
||||
|
||||
// Type cast
|
||||
operator bool() const noexcept { return (_value != 0.0); }
|
||||
operator uint8_t() const noexcept { return (uint8_t)_value; }
|
||||
operator uint16_t() const noexcept { return (uint16_t)_value; }
|
||||
operator uint32_t() const noexcept { return (uint32_t)_value; }
|
||||
operator uint64_t() const noexcept { return (uint64_t)_value; }
|
||||
operator float() const noexcept { return (float)_value; }
|
||||
operator double() const noexcept { return (double)_value; }
|
||||
|
||||
//! Get string from the current decimal value
|
||||
std::string string() const { return std::to_string(_value); }
|
||||
|
||||
//! Input instance from the given input stream
|
||||
friend std::istream& operator>>(std::istream& is, decimal_t& value)
|
||||
{ is >> value._value; return is; }
|
||||
//! Output instance into the given output stream
|
||||
friend std::ostream& operator<<(std::ostream& os, const decimal_t& value)
|
||||
{ os << value.string(); return os; }
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
//! Store logging format
|
||||
friend CppLogging::Record& operator<<(CppLogging::Record& record, const decimal_t& value)
|
||||
{ return record.StoreCustom(value._value); }
|
||||
#endif
|
||||
|
||||
//! Swap two instances
|
||||
void swap(decimal_t& value) noexcept
|
||||
{ using std::swap; swap(_value, value._value); }
|
||||
friend void swap(decimal_t& value1, decimal_t& value2) noexcept
|
||||
{ value1.swap(value2); }
|
||||
|
||||
private:
|
||||
double _value;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <>
|
||||
struct fmt::formatter<FBE::decimal_t> : formatter<std::string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const FBE::decimal_t& value, FormatContext& ctx) const
|
||||
{
|
||||
return formatter<string_view>::format((double)value, ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct std::hash<FBE::decimal_t>
|
||||
{
|
||||
typedef FBE::decimal_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
result = result * 31 + std::hash<double>()((double)value);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Register a new enum-based flags macro
|
||||
#define FBE_ENUM_FLAGS(type)\
|
||||
inline FBE::Flags<type> operator|(type f1, type f2) noexcept { return FBE::Flags<type>(f1) | FBE::Flags<type>(f2); }\
|
||||
inline FBE::Flags<type> operator&(type f1, type f2) noexcept { return FBE::Flags<type>(f1) & FBE::Flags<type>(f2); }\
|
||||
inline FBE::Flags<type> operator^(type f1, type f2) noexcept { return FBE::Flags<type>(f1) ^ FBE::Flags<type>(f2); }
|
||||
|
||||
// Enum-based flags
|
||||
template <typename TEnum>
|
||||
class Flags
|
||||
{
|
||||
// Enum underlying type
|
||||
typedef typename std::make_unsigned<typename std::underlying_type<TEnum>::type>::type type;
|
||||
|
||||
public:
|
||||
Flags() noexcept : _value(0) {}
|
||||
explicit Flags(type value) noexcept : _value(value) {}
|
||||
explicit Flags(TEnum value) noexcept : _value((type)value) {}
|
||||
Flags(const Flags&) noexcept = default;
|
||||
Flags(Flags&&) noexcept = default;
|
||||
~Flags() noexcept = default;
|
||||
|
||||
Flags& operator=(type value) noexcept
|
||||
{ _value = value; return *this; }
|
||||
Flags& operator=(TEnum value) noexcept
|
||||
{ _value = (type)value; return *this; }
|
||||
Flags& operator=(const Flags&) noexcept = default;
|
||||
Flags& operator=(Flags&&) noexcept = default;
|
||||
|
||||
// Is any flag set?
|
||||
explicit operator bool() const noexcept { return isset(); }
|
||||
|
||||
// Is no flag set?
|
||||
bool operator!() const noexcept { return !isset(); }
|
||||
|
||||
// Reverse all flags
|
||||
Flags operator~() const noexcept { return Flags(~_value); }
|
||||
|
||||
// Flags logical assign operators
|
||||
Flags& operator&=(const Flags& flags) noexcept
|
||||
{ _value &= flags._value; return *this; }
|
||||
Flags& operator|=(const Flags& flags) noexcept
|
||||
{ _value |= flags._value; return *this; }
|
||||
Flags& operator^=(const Flags& flags) noexcept
|
||||
{ _value ^= flags._value; return *this; }
|
||||
|
||||
// Flags logical friend operators
|
||||
friend Flags operator&(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value & flags2._value); }
|
||||
friend Flags operator|(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value | flags2._value); }
|
||||
friend Flags operator^(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return Flags(flags1._value ^ flags2._value); }
|
||||
|
||||
// Flags comparison
|
||||
friend bool operator==(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return flags1._value == flags2._value; }
|
||||
friend bool operator!=(const Flags& flags1, const Flags& flags2) noexcept
|
||||
{ return flags1._value != flags2._value; }
|
||||
|
||||
// Convert to the enum value
|
||||
operator TEnum() const noexcept { return (TEnum)_value; }
|
||||
|
||||
//! Is any flag set?
|
||||
bool isset() const noexcept { return (_value != 0); }
|
||||
//! Is the given flag set?
|
||||
bool isset(type value) const noexcept { return (_value & value) != 0; }
|
||||
//! Is the given flag set?
|
||||
bool isset(TEnum value) const noexcept { return (_value & (type)value) != 0; }
|
||||
|
||||
// Get the enum value
|
||||
TEnum value() const noexcept { return (TEnum)_value; }
|
||||
// Get the underlying enum value
|
||||
type underlying() const noexcept { return _value; }
|
||||
// Get the bitset value
|
||||
std::bitset<sizeof(type) * 8> bitset() const noexcept { return {_value}; }
|
||||
|
||||
// Swap two instances
|
||||
void swap(Flags& flags) noexcept { using std::swap; swap(_value, flags._value); }
|
||||
template <typename UEnum>
|
||||
friend void swap(Flags<UEnum>& flags1, Flags<UEnum>& flags2) noexcept;
|
||||
|
||||
private:
|
||||
type _value;
|
||||
};
|
||||
|
||||
template <typename TEnum>
|
||||
inline void swap(Flags<TEnum>& flags1, Flags<TEnum>& flags2) noexcept
|
||||
{
|
||||
flags1.swap(flags2);
|
||||
}
|
||||
|
||||
// Get Epoch timestamp
|
||||
inline uint64_t epoch() { return 0ull; }
|
||||
// Get UTC timestamp
|
||||
uint64_t utc();
|
||||
|
||||
//! Universally unique identifier (UUID)
|
||||
/*!
|
||||
A universally unique identifier (UUID) is an identifier standard used
|
||||
in software construction. This implementation generates the following
|
||||
UUID types:
|
||||
- Nil UUID0 (all bits set to zero)
|
||||
- Sequential UUID1 (time based version)
|
||||
- Random UUID4 (randomly or pseudo-randomly generated version)
|
||||
|
||||
A UUID is simply a 128-bit value: "123e4567-e89b-12d3-a456-426655440000"
|
||||
|
||||
https://en.wikipedia.org/wiki/Universally_unique_identifier
|
||||
https://www.ietf.org/rfc/rfc4122.txt
|
||||
*/
|
||||
class uuid_t
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
uuid_t() : _data() { _data.fill(0); }
|
||||
//! Initialize UUID with a given string
|
||||
/*!
|
||||
\param uuid - UUID string
|
||||
*/
|
||||
explicit uuid_t(const std::string& uuid);
|
||||
//! Initialize UUID with a given 16 bytes data buffer
|
||||
/*!
|
||||
\param data - UUID 16 bytes data buffer
|
||||
*/
|
||||
explicit uuid_t(const std::array<uint8_t, 16>& data) : _data(data) {}
|
||||
uuid_t(const uuid_t&) = default;
|
||||
uuid_t(uuid_t&&) noexcept = default;
|
||||
~uuid_t() = default;
|
||||
|
||||
uuid_t& operator=(const std::string& uuid)
|
||||
{ _data = uuid_t(uuid).data(); return *this; }
|
||||
uuid_t& operator=(const std::array<uint8_t, 16>& data)
|
||||
{ _data = data; return *this; }
|
||||
uuid_t& operator=(const uuid_t&) = default;
|
||||
uuid_t& operator=(uuid_t&&) noexcept = default;
|
||||
|
||||
// UUID comparison
|
||||
friend bool operator==(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data == uuid2._data; }
|
||||
friend bool operator!=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data != uuid2._data; }
|
||||
friend bool operator<(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data < uuid2._data; }
|
||||
friend bool operator>(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data > uuid2._data; }
|
||||
friend bool operator<=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data <= uuid2._data; }
|
||||
friend bool operator>=(const uuid_t& uuid1, const uuid_t& uuid2)
|
||||
{ return uuid1._data >= uuid2._data; }
|
||||
|
||||
//! Check if the UUID is nil UUID0 (all bits set to zero)
|
||||
explicit operator bool() const noexcept { return *this != nil(); }
|
||||
|
||||
//! Get the UUID data buffer
|
||||
std::array<uint8_t, 16>& data() noexcept { return _data; }
|
||||
//! Get the UUID data buffer
|
||||
const std::array<uint8_t, 16>& data() const noexcept { return _data; }
|
||||
|
||||
//! Get string from the current UUID in format "00000000-0000-0000-0000-000000000000"
|
||||
std::string string() const;
|
||||
|
||||
//! Generate nil UUID0 (all bits set to zero)
|
||||
static uuid_t nil() { return uuid_t(); }
|
||||
//! Generate sequential UUID1 (time based version)
|
||||
static uuid_t sequential();
|
||||
//! Generate random UUID4 (randomly or pseudo-randomly generated version)
|
||||
static uuid_t random();
|
||||
|
||||
//! Output instance into the given output stream
|
||||
friend std::ostream& operator<<(std::ostream& os, const uuid_t& uuid)
|
||||
{ os << uuid.string(); return os; }
|
||||
|
||||
#if defined(LOGGING_PROTOCOL)
|
||||
//! Store logging format
|
||||
friend CppLogging::Record& operator<<(CppLogging::Record& record, const uuid_t& uuid);
|
||||
#endif
|
||||
|
||||
//! Swap two instances
|
||||
void swap(uuid_t& uuid) noexcept
|
||||
{ using std::swap; swap(_data, uuid._data); }
|
||||
friend void swap(uuid_t& uuid1, uuid_t& uuid2) noexcept
|
||||
{ uuid1.swap(uuid2); }
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 16> _data;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <>
|
||||
struct fmt::formatter<FBE::uuid_t> : formatter<std::string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const FBE::uuid_t& value, FormatContext& ctx) const
|
||||
{
|
||||
return formatter<string_view>::format(value.string(), ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct std::hash<FBE::uuid_t>
|
||||
{
|
||||
typedef FBE::uuid_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
||||
result_type operator() (const argument_type& value) const
|
||||
{
|
||||
result_type result = 17;
|
||||
std::hash<uint8_t> hasher;
|
||||
for (size_t i = 0; i < value.data().size(); ++i)
|
||||
result = result * 31 + hasher(value.data()[i]);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding buffer based on the dynamic byte buffer
|
||||
class FBEBuffer
|
||||
{
|
||||
public:
|
||||
FBEBuffer() : _data(nullptr), _capacity(0), _size(0), _offset(0) {}
|
||||
// Initialize the read buffer with the given byte buffer and offset
|
||||
explicit FBEBuffer(const void* data, size_t size, size_t offset = 0) { attach(data, size, offset); }
|
||||
// Initialize the read buffer with the given byte vector and offset
|
||||
explicit FBEBuffer(const std::vector<uint8_t>& buffer, size_t offset = 0) { attach(buffer, offset); }
|
||||
// Initialize the read buffer with another buffer and offset
|
||||
explicit FBEBuffer(const FBEBuffer& buffer, size_t offset = 0) { attach(buffer.data(), buffer.size(), offset); }
|
||||
// Initialize the write buffer with the given capacity
|
||||
explicit FBEBuffer(size_t capacity) : FBEBuffer() { reserve(capacity); }
|
||||
FBEBuffer(const FBEBuffer&) = delete;
|
||||
FBEBuffer(FBEBuffer&&) noexcept = delete;
|
||||
~FBEBuffer() { if (_capacity > 0) std::free(_data); }
|
||||
|
||||
FBEBuffer& operator=(const FBEBuffer&) = delete;
|
||||
FBEBuffer& operator=(FBEBuffer&&) noexcept = delete;
|
||||
|
||||
bool empty() const noexcept { return (_data == nullptr) || (_size == 0); }
|
||||
const uint8_t* data() const noexcept { return _data; }
|
||||
uint8_t* data() noexcept { return _data; }
|
||||
size_t capacity() const noexcept { return _capacity; }
|
||||
size_t size() const noexcept { return _size; }
|
||||
size_t offset() const noexcept { return _offset; }
|
||||
|
||||
// Attach the given buffer with a given offset to the current read buffer
|
||||
void attach(const void* data, size_t size, size_t offset = 0);
|
||||
// Attach the given byte vector with a given offset to the current read buffer
|
||||
void attach(const std::vector<uint8_t>& buffer, size_t offset = 0);
|
||||
|
||||
// Clone the given buffer with a given offset to the current buffer
|
||||
void clone(const void* data, size_t size, size_t offset = 0);
|
||||
// Clone the given vector with a given offset to the current buffer
|
||||
void clone(const std::vector<uint8_t>& buffer, size_t offset = 0);
|
||||
|
||||
// Allocate memory in the current write buffer and return offset to the allocated memory block
|
||||
size_t allocate(size_t size);
|
||||
// Remove some memory of the given size from the current write buffer
|
||||
void remove(size_t offset, size_t size);
|
||||
// Reserve memory of the given capacity in the current write buffer
|
||||
void reserve(size_t capacity);
|
||||
// Resize the current write buffer
|
||||
void resize(size_t size);
|
||||
// Reset the current write buffer and its offset
|
||||
void reset();
|
||||
|
||||
// Shift the current write buffer offset
|
||||
void shift(size_t offset) { _offset += offset; }
|
||||
// Unshift the current write buffer offset
|
||||
void unshift(size_t offset) { _offset -= offset; }
|
||||
|
||||
private:
|
||||
uint8_t* _data;
|
||||
size_t _capacity;
|
||||
size_t _size;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding base model
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
Model() : Model(nullptr) {}
|
||||
Model(const std::shared_ptr<FBEBuffer>& buffer) { _buffer = buffer ? buffer : std::make_shared<FBEBuffer>(); }
|
||||
Model(const Model&) = default;
|
||||
Model(Model&&) noexcept = default;
|
||||
~Model() = default;
|
||||
|
||||
Model& operator=(const Model&) = default;
|
||||
Model& operator=(Model&&) noexcept = default;
|
||||
|
||||
// Get the model buffer
|
||||
FBEBuffer& buffer() noexcept { return *_buffer; }
|
||||
const FBEBuffer& buffer() const noexcept { return *_buffer; }
|
||||
|
||||
// Attach the model buffer
|
||||
void attach(const void* data, size_t size, size_t offset = 0) { _buffer->attach(data, size, offset); }
|
||||
void attach(const std::vector<uint8_t>& buffer, size_t offset = 0) { _buffer->attach(buffer, offset); }
|
||||
void attach(const FBEBuffer& buffer, size_t offset = 0) { _buffer->attach(buffer.data(), buffer.size(), offset); }
|
||||
|
||||
// Model buffer operations
|
||||
size_t allocate(size_t size) { return _buffer->allocate(size); }
|
||||
void remove(size_t offset, size_t size) { _buffer->remove(offset, size); }
|
||||
void reserve(size_t capacity) { _buffer->reserve(capacity); }
|
||||
void resize(size_t size) { _buffer->resize(size); }
|
||||
void reset() { _buffer->reset(); }
|
||||
void shift(size_t offset) { _buffer->shift(offset); }
|
||||
void unshift(size_t offset) { _buffer->unshift(offset); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<FBEBuffer> _buffer;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
438
fbe/user_model/fbe_final_models.cpp
Normal file
438
fbe/user_model/fbe_final_models.cpp
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "fbe_final_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
uint64_t FinalModel<decimal_t>::extract(double a) noexcept
|
||||
{
|
||||
uint64_t result;
|
||||
std::memcpy(&result, &a, sizeof(double));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t FinalModel<decimal_t>::uint32x32(uint32_t a, uint32_t b) noexcept
|
||||
{
|
||||
return (uint64_t)a * (uint64_t)b;
|
||||
}
|
||||
|
||||
void FinalModel<decimal_t>::uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept
|
||||
{
|
||||
uint64_t low = uint32x32((uint32_t)a, (uint32_t)b);
|
||||
uint64_t mid = uint32x32((uint32_t)a, (uint32_t)(b >> 32));
|
||||
uint64_t high = uint32x32((uint32_t)(a >> 32), (uint32_t)(b >> 32));
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
mid = uint32x32((uint32_t)(a >> 32), (uint32_t)b);
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
if (high > 0xFFFFFFFFu)
|
||||
{
|
||||
low64 = 0;
|
||||
high32 = 0;
|
||||
}
|
||||
low64 = low;
|
||||
high32 = (uint32_t)high;
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::get(decimal_t& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
// Value taken via reverse engineering the double that corresponds to 2^64
|
||||
const double ds2to64 = 1.8446744073709552e+019;
|
||||
|
||||
// Read decimal parts
|
||||
uint64_t low = *((const uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
uint32_t high = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8));
|
||||
uint32_t flags = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12));
|
||||
|
||||
// Calculate decimal value
|
||||
double dValue = ((double)low + (double)high * ds2to64) / pow(10.0, (uint8_t)(flags >> 16));
|
||||
if (flags & 0x80000000)
|
||||
dValue = -dValue;
|
||||
|
||||
value = dValue;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<decimal_t>::set(decimal_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
// The most we can scale by is 10^28, which is just slightly more
|
||||
// than 2^93. So a float with an exponent of -94 could just
|
||||
// barely reach 0.5, but smaller exponents will always round to zero.
|
||||
const uint32_t DBLBIAS = 1022;
|
||||
|
||||
// Get exponent value
|
||||
double dValue = (double)value;
|
||||
int32_t iExp = (int32_t)(((uint32_t)(extract(dValue) >> 52) & 0x7FFu) - DBLBIAS);
|
||||
if ((iExp < -94) || (iExp > 96))
|
||||
{
|
||||
// Value too big for .NET Decimal (exponent is limited to [-94, 96])
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (dValue < 0)
|
||||
{
|
||||
dValue = -dValue;
|
||||
flags = 0x80000000;
|
||||
}
|
||||
|
||||
// Round the input to a 15-digit integer. The R8 format has
|
||||
// only 15 digits of precision, and we want to keep garbage digits
|
||||
// out of the Decimal were making.
|
||||
|
||||
// Calculate max power of 10 input value could have by multiplying
|
||||
// the exponent by log10(2). Using scaled integer multiplcation,
|
||||
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
|
||||
int32_t iPower = 14 - ((iExp * 19728) >> 16);
|
||||
|
||||
// iPower is between -14 and 43
|
||||
if (iPower >= 0)
|
||||
{
|
||||
// We have less than 15 digits, scale input up.
|
||||
if (iPower > 28)
|
||||
iPower = 28;
|
||||
|
||||
dValue *= pow(10.0, iPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((iPower != -1) || (dValue >= 1E15))
|
||||
dValue /= pow(10.0, -iPower);
|
||||
else
|
||||
iPower = 0; // didn't scale it
|
||||
}
|
||||
|
||||
assert(dValue < 1E15);
|
||||
if ((dValue < 1E14) && (iPower < 28))
|
||||
{
|
||||
dValue *= 10;
|
||||
iPower++;
|
||||
assert(dValue >= 1E14);
|
||||
}
|
||||
|
||||
// Round to int64
|
||||
uint64_t ulMant;
|
||||
ulMant = (uint64_t)(int64_t)dValue;
|
||||
dValue -= (int64_t)ulMant; // difference between input & integer
|
||||
if ((dValue > 0.5) || ((dValue == 0.5) && ((ulMant & 1) != 0)))
|
||||
ulMant++;
|
||||
|
||||
if (ulMant == 0)
|
||||
{
|
||||
// Mantissa is 0
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
if (iPower < 0)
|
||||
{
|
||||
// Add -iPower factors of 10, -iPower <= (29 - 15) = 14
|
||||
iPower = -iPower;
|
||||
if (iPower < 10)
|
||||
{
|
||||
double pow10 = (double)powl(10.0, iPower);
|
||||
uint64_t low64 = uint32x32((uint32_t)ulMant, (uint32_t)pow10);
|
||||
uint64_t high64 = uint32x32((uint32_t)(ulMant >> 32), (uint32_t)pow10);
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)low64;
|
||||
high64 += low64 >> 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4)) = (uint32_t)high64;
|
||||
high64 >>= 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = (uint32_t)high64;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have a big power of 10.
|
||||
assert(iPower <= 14);
|
||||
uint64_t low64;
|
||||
uint32_t high32;
|
||||
uint64x64(ulMant, (uint64_t)pow(10.0, iPower), low64, high32);
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = low64;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = high32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Factor out powers of 10 to reduce the scale, if possible.
|
||||
// The maximum number we could factor out would be 14. This
|
||||
// comes from the fact we have a 15-digit number, and the
|
||||
// MSD must be non-zero -- but the lower 14 digits could be
|
||||
// zero. Note also the scale factor is never negative, so
|
||||
// we can't scale by any more than the power we used to
|
||||
// get the integer.
|
||||
int lmax = iPower;
|
||||
if (lmax > 14)
|
||||
lmax = 14;
|
||||
|
||||
if ((((uint8_t)ulMant) == 0) && (lmax >= 8))
|
||||
{
|
||||
const uint32_t den = 100000000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 8;
|
||||
lmax -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 0xF) == 0) && (lmax >= 4))
|
||||
{
|
||||
const uint32_t den = 10000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 4;
|
||||
lmax -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 3) == 0) && (lmax >= 2))
|
||||
{
|
||||
const uint32_t den = 100;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 2;
|
||||
lmax -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 1) == 0) && (lmax >= 1))
|
||||
{
|
||||
const uint32_t den = 10;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower--;
|
||||
}
|
||||
}
|
||||
|
||||
flags |= (uint32_t)iPower << 16;
|
||||
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = ulMant;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = 0;
|
||||
}
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12)) = flags;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::get(uuid_t& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
std::memcpy(value.data().data(), (const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), fbe_size());
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<uuid_t>::set(uuid_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
std::memcpy((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), value.data().data(), fbe_size());
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::get(void* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_bytes_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), result);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::get(std::vector<uint8_t>& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
const char* fbe_bytes = (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4);
|
||||
value.assign(fbe_bytes, fbe_bytes + fbe_bytes_size);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<buffer_t>::set(const void* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = (uint32_t)size;
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_bytes_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), data, fbe_bytes_size);
|
||||
return 4 + fbe_bytes_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::get(char* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_string_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), result);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::get(std::string& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::set(const char* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)size;
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), data, fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
size_t FinalModel<std::string>::set(const std::string& value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)value.size();
|
||||
assert(((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4 + fbe_string_size) > _buffer.size())
|
||||
return 4;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4), value.data(), fbe_string_size);
|
||||
return 4 + fbe_string_size;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
459
fbe/user_model/fbe_final_models.h
Normal file
459
fbe/user_model/fbe_final_models.h
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding base final model
|
||||
template <typename T, typename TBase = T>
|
||||
class FinalModelBase
|
||||
{
|
||||
public:
|
||||
FinalModelBase(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(T value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return sizeof(TBase); }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the field value
|
||||
size_t get(T& value) const noexcept;
|
||||
// Set the field value
|
||||
size_t set(T value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model
|
||||
template <typename T>
|
||||
class FinalModel : public FinalModelBase<T>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<T>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model bool specialization
|
||||
template <>
|
||||
class FinalModel<bool> : public FinalModelBase<bool, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<bool, uint8_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model char specialization
|
||||
template <>
|
||||
class FinalModel<char> : public FinalModelBase<char, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<char, uint8_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model wchar specialization
|
||||
template <>
|
||||
class FinalModel<wchar_t> : public FinalModelBase<wchar_t, uint32_t>
|
||||
{
|
||||
public:
|
||||
using FinalModelBase<wchar_t, uint32_t>::FinalModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model decimal specialization
|
||||
template <>
|
||||
class FinalModel<decimal_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(decimal_t value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the decimal value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the decimal value
|
||||
size_t get(decimal_t& value) const noexcept;
|
||||
// Set the decimal value
|
||||
size_t set(decimal_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
static uint64_t extract(double a) noexcept;
|
||||
static uint64_t uint32x32(uint32_t a, uint32_t b) noexcept;
|
||||
static void uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model UUID specialization
|
||||
template <>
|
||||
class FinalModel<uuid_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(uuid_t value) const noexcept { return fbe_size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Get the final size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the UUID value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the UUID value
|
||||
size_t get(uuid_t& value) const noexcept;
|
||||
// Set the UUID value
|
||||
size_t set(uuid_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model bytes specialization
|
||||
template <>
|
||||
class FinalModel<buffer_t>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const void* data, size_t size) const noexcept { return 4 + size; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const uint8_t (&data)[N]) const noexcept { return 4 + N; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const std::array<uint8_t, N>& data) const noexcept { return 4 + N; }
|
||||
size_t fbe_allocation_size(const std::vector<uint8_t>& value) const noexcept { return 4 + value.size(); }
|
||||
size_t fbe_allocation_size(const buffer_t& value) const noexcept { return 4 + value.size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the bytes value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the bytes value
|
||||
size_t get(void* data, size_t size) const noexcept;
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(uint8_t (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(std::array<uint8_t, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the bytes value
|
||||
size_t get(std::vector<uint8_t>& value) const noexcept;
|
||||
// Get the bytes value
|
||||
size_t get(buffer_t& value) const noexcept { return get(value.buffer()); }
|
||||
|
||||
// Set the bytes value
|
||||
size_t set(const void* data, size_t size);
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
size_t set(const uint8_t (&data)[N]) { return set(data, N); }
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
size_t set(const std::array<uint8_t, N>& data) { return set(data.data(), data.size()); }
|
||||
// Set the bytes value
|
||||
size_t set(const std::vector<uint8_t>& value) { return set(value.data(), value.size()); }
|
||||
// Set the bytes value
|
||||
size_t set(const buffer_t& value) { return set(value.buffer()); }
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model string specialization
|
||||
template <>
|
||||
class FinalModel<std::string>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const char* data, size_t size) const noexcept { return 4 + size; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const char (&data)[N]) const noexcept { return 4 + N; }
|
||||
template <size_t N>
|
||||
size_t fbe_allocation_size(const std::array<char, N>& data) const noexcept { return 4 + N; }
|
||||
size_t fbe_allocation_size(const std::string& value) const noexcept { return 4 + value.size(); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the string value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the string value
|
||||
size_t get(char* data, size_t size) const noexcept;
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(char (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(std::array<char, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the string value
|
||||
size_t get(std::string& value) const noexcept;
|
||||
|
||||
// Set the string value
|
||||
size_t set(const char* data, size_t size);
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
size_t set(const char (&data)[N]) { return set(data, N); }
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
size_t set(const std::array<char, N>& data) { return set(data.data(), data.size()); }
|
||||
// Set the string value
|
||||
size_t set(const std::string& value);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model optional specialization
|
||||
template <typename T>
|
||||
class FinalModel<std::optional<T>>
|
||||
{
|
||||
public:
|
||||
FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), value(buffer, 0) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::optional<T>& opt) const noexcept { return 1 + (opt ? value.fbe_allocation_size(opt.value()) : 0); }
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
//! Is the value present?
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
// Checks if the object contains a value
|
||||
bool has_value() const noexcept;
|
||||
|
||||
// Check if the optional value is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the optional value
|
||||
size_t get(std::optional<T>& opt) const noexcept;
|
||||
// Set the optional value
|
||||
size_t set(const std::optional<T>& opt);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
// Base final model value
|
||||
FinalModel<T> value;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model array
|
||||
template <typename T, size_t N>
|
||||
class FinalModelArray
|
||||
{
|
||||
public:
|
||||
FinalModelArray(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
template <size_t S>
|
||||
size_t fbe_allocation_size(const T (&values)[S]) const noexcept;
|
||||
template <size_t S>
|
||||
size_t fbe_allocation_size(const std::array<T, S>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::vector<T>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the array is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the array as C-array
|
||||
template <size_t S>
|
||||
size_t get(T (&values)[S]) const noexcept;
|
||||
// Get the array as std::array
|
||||
template <size_t S>
|
||||
size_t get(std::array<T, S>& values) const noexcept;
|
||||
// Get the array as std::vector
|
||||
size_t get(std::vector<T>& values) const noexcept;
|
||||
|
||||
// Set the array as C-array
|
||||
template <size_t S>
|
||||
size_t set(const T (&values)[S]) noexcept;
|
||||
// Set the array as std::array
|
||||
template <size_t S>
|
||||
size_t set(const std::array<T, S>& values) noexcept;
|
||||
// Set the array as std::vector
|
||||
size_t set(const std::vector<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model vector
|
||||
template <typename T>
|
||||
class FinalModelVector
|
||||
{
|
||||
public:
|
||||
FinalModelVector(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::vector<T>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::list<T>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::set<T>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the vector is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the vector as std::vector
|
||||
size_t get(std::vector<T>& values) const noexcept;
|
||||
// Get the vector as std::list
|
||||
size_t get(std::list<T>& values) const noexcept;
|
||||
// Get the vector as std::set
|
||||
size_t get(std::set<T>& values) const noexcept;
|
||||
|
||||
// Set the vector as std::vector
|
||||
size_t set(const std::vector<T>& values) noexcept;
|
||||
// Set the vector as std::list
|
||||
size_t set(const std::list<T>& values) noexcept;
|
||||
// Set the vector as std::set
|
||||
size_t set(const std::set<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding final model map
|
||||
template <typename TKey, typename TValue>
|
||||
class FinalModelMap
|
||||
{
|
||||
public:
|
||||
FinalModelMap(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the allocation size
|
||||
size_t fbe_allocation_size(const std::map<TKey, TValue>& values) const noexcept;
|
||||
size_t fbe_allocation_size(const std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Set the field offset
|
||||
size_t fbe_offset(size_t offset) const noexcept { return _offset = offset; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the map is valid
|
||||
size_t verify() const noexcept;
|
||||
|
||||
// Get the map as std::map
|
||||
size_t get(std::map<TKey, TValue>& values) const noexcept;
|
||||
// Get the map as std::unordered_map
|
||||
size_t get(std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Set the map as std::map
|
||||
size_t set(const std::map<TKey, TValue>& values) noexcept;
|
||||
// Set the map as std::unordered_map
|
||||
size_t set(const std::unordered_map<TKey, TValue>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
mutable size_t _offset;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#include "fbe_final_models.inl"
|
||||
637
fbe/user_model/fbe_final_models.inl
Normal file
637
fbe/user_model/fbe_final_models.inl
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace FBE {
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::get(T& value) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
value = (T)(*((const TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())));
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline size_t FinalModelBase<T, TBase>::set(T value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (TBase)value;
|
||||
return fbe_size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FinalModel<std::optional<T>>::has_value() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return (fbe_has_value != 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_has_value == 0)
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
size_t fbe_result = value.verify();
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::get(std::optional<T>& opt) const noexcept
|
||||
{
|
||||
opt = std::nullopt;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 1) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
if (!has_value())
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
T temp = T();
|
||||
size_t size = value.get(temp);
|
||||
opt.emplace(temp);
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModel<std::optional<T>>::set(const std::optional<T>& opt)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 1) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 1) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint8_t fbe_has_value = opt ? 1 : 0;
|
||||
*((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_has_value;
|
||||
if (fbe_has_value == 0)
|
||||
return 1;
|
||||
|
||||
_buffer.shift(fbe_offset() + 1);
|
||||
size_t size = 0;
|
||||
if (opt)
|
||||
size = value.set(opt.value());
|
||||
_buffer.unshift(fbe_offset() + 1);
|
||||
return 1 + size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const T (&values)[S]) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const std::array<T, S>& values) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::fbe_allocation_size(const std::vector<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
size += fbe_model.fbe_allocation_size(values[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
size_t offset = fbe_model.verify();
|
||||
if (offset == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::get(T (&values)[S]) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::get(std::array<T, S>& values) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
values.reserve(N);
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::set(const T (&values)[S]) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline size_t FinalModelArray<T, N>::set(const std::array<T, S>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline size_t FinalModelArray<T, N>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
{
|
||||
size_t offset = fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::vector<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::list<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::fbe_allocation_size(const std::set<T>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
size += fbe_model.fbe_allocation_size(value);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
size_t offset = fbe_model.verify();
|
||||
if (offset == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
values.reserve(fbe_vector_size);
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::list<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::get(std::set<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
size_t offset = fbe_model.get(value);
|
||||
values.emplace(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::list<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FinalModelVector<T>::set(const std::set<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<T> fbe_model(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset = fbe_model.set(value);
|
||||
fbe_model.fbe_shift(offset);
|
||||
size += offset;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::fbe_allocation_size(const std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size += fbe_model_key.fbe_allocation_size(value.first);
|
||||
size += fbe_model_value.fbe_allocation_size(value.second);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::fbe_allocation_size(const std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size += fbe_model_key.fbe_allocation_size(value.first);
|
||||
size += fbe_model_value.fbe_allocation_size(value.second);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.verify();
|
||||
if (offset_key == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size += offset_key;
|
||||
size_t offset_value = fbe_model_value.verify();
|
||||
if (offset_value == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.get(value);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
values.emplace(key, value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_size == 0)
|
||||
return 4;
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.get(value);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
values.emplace(key, value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::set(const std::map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.set(value.first);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.set(value.second);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FinalModelMap<TKey, TValue>::set(const std::unordered_map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)values.size();
|
||||
|
||||
size_t size = 4;
|
||||
FinalModel<TKey> fbe_model_key(_buffer, fbe_offset() + 4);
|
||||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (const auto& value : values)
|
||||
{
|
||||
size_t offset_key = fbe_model_key.set(value.first);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
size_t offset_value = fbe_model_value.set(value.second);
|
||||
fbe_model_key.fbe_shift(offset_value);
|
||||
fbe_model_value.fbe_shift(offset_value);
|
||||
size += offset_key + offset_value;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
516
fbe/user_model/fbe_models.cpp
Normal file
516
fbe/user_model/fbe_models.cpp
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "fbe_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
uint64_t FieldModel<decimal_t>::extract(double a) noexcept
|
||||
{
|
||||
uint64_t result;
|
||||
std::memcpy(&result, &a, sizeof(double));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t FieldModel<decimal_t>::uint32x32(uint32_t a, uint32_t b) noexcept
|
||||
{
|
||||
return (uint64_t)a * (uint64_t)b;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept
|
||||
{
|
||||
uint64_t low = uint32x32((uint32_t)a, (uint32_t)b);
|
||||
uint64_t mid = uint32x32((uint32_t)a, (uint32_t)(b >> 32));
|
||||
uint64_t high = uint32x32((uint32_t)(a >> 32), (uint32_t)(b >> 32));
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
mid = uint32x32((uint32_t)(a >> 32), (uint32_t)b);
|
||||
high += (mid >> 32);
|
||||
low += (mid <<= 32);
|
||||
// Test for carry
|
||||
if (low < mid)
|
||||
high++;
|
||||
|
||||
if (high > 0xFFFFFFFFu)
|
||||
{
|
||||
low64 = 0;
|
||||
high32 = 0;
|
||||
}
|
||||
low64 = low;
|
||||
high32 = (uint32_t)high;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::get(decimal_t& value, decimal_t defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
// Value taken via reverse engineering the double that corresponds to 2^64
|
||||
const double ds2to64 = 1.8446744073709552e+019;
|
||||
|
||||
// Read decimal parts
|
||||
uint64_t low = *((const uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
uint32_t high = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8));
|
||||
uint32_t flags = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12));
|
||||
|
||||
// Calculate decimal value
|
||||
double dValue = ((double)low + (double)high * ds2to64) / pow(10.0, (uint8_t)(flags >> 16));
|
||||
if (flags & 0x80000000)
|
||||
dValue = -dValue;
|
||||
|
||||
value = dValue;
|
||||
}
|
||||
|
||||
void FieldModel<decimal_t>::set(decimal_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
// The most we can scale by is 10^28, which is just slightly more
|
||||
// than 2^93. So a float with an exponent of -94 could just
|
||||
// barely reach 0.5, but smaller exponents will always round to zero.
|
||||
const uint32_t DBLBIAS = 1022;
|
||||
|
||||
// Get exponent value
|
||||
double dValue = (double)value;
|
||||
int32_t iExp = (int32_t)(((uint32_t)(extract(dValue) >> 52) & 0x7FFu) - DBLBIAS);
|
||||
if ((iExp < -94) || (iExp > 96))
|
||||
{
|
||||
// Value too big for .NET Decimal (exponent is limited to [-94, 96])
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (dValue < 0)
|
||||
{
|
||||
dValue = -dValue;
|
||||
flags = 0x80000000;
|
||||
}
|
||||
|
||||
// Round the input to a 15-digit integer. The R8 format has
|
||||
// only 15 digits of precision, and we want to keep garbage digits
|
||||
// out of the Decimal were making.
|
||||
|
||||
// Calculate max power of 10 input value could have by multiplying
|
||||
// the exponent by log10(2). Using scaled integer multiplcation,
|
||||
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
|
||||
int32_t iPower = 14 - ((iExp * 19728) >> 16);
|
||||
|
||||
// iPower is between -14 and 43
|
||||
if (iPower >= 0)
|
||||
{
|
||||
// We have less than 15 digits, scale input up.
|
||||
if (iPower > 28)
|
||||
iPower = 28;
|
||||
|
||||
dValue *= pow(10.0, iPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((iPower != -1) || (dValue >= 1E15))
|
||||
dValue /= pow(10.0, -iPower);
|
||||
else
|
||||
iPower = 0; // didn't scale it
|
||||
}
|
||||
|
||||
assert(dValue < 1E15);
|
||||
if ((dValue < 1E14) && (iPower < 28))
|
||||
{
|
||||
dValue *= 10;
|
||||
iPower++;
|
||||
assert(dValue >= 1E14);
|
||||
}
|
||||
|
||||
// Round to int64
|
||||
uint64_t ulMant;
|
||||
ulMant = (uint64_t)(int64_t)dValue;
|
||||
dValue -= (int64_t)ulMant; // difference between input & integer
|
||||
if ((dValue > 0.5) || ((dValue == 0.5) && ((ulMant & 1) != 0)))
|
||||
ulMant++;
|
||||
|
||||
if (ulMant == 0)
|
||||
{
|
||||
// Mantissa is 0
|
||||
memset((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), 0, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iPower < 0)
|
||||
{
|
||||
// Add -iPower factors of 10, -iPower <= (29 - 15) = 14
|
||||
iPower = -iPower;
|
||||
if (iPower < 10)
|
||||
{
|
||||
double pow10 = (double)powl(10.0, iPower);
|
||||
uint64_t low64 = uint32x32((uint32_t)ulMant, (uint32_t)pow10);
|
||||
uint64_t high64 = uint32x32((uint32_t)(ulMant >> 32), (uint32_t)pow10);
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (uint32_t)low64;
|
||||
high64 += low64 >> 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 4)) = (uint32_t)high64;
|
||||
high64 >>= 32;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = (uint32_t)high64;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have a big power of 10.
|
||||
assert(iPower <= 14);
|
||||
uint64_t low64;
|
||||
uint32_t high32;
|
||||
uint64x64(ulMant, (uint64_t)pow(10.0, iPower), low64, high32);
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = low64;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = high32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Factor out powers of 10 to reduce the scale, if possible.
|
||||
// The maximum number we could factor out would be 14. This
|
||||
// comes from the fact we have a 15-digit number, and the
|
||||
// MSD must be non-zero -- but the lower 14 digits could be
|
||||
// zero. Note also the scale factor is never negative, so
|
||||
// we can't scale by any more than the power we used to
|
||||
// get the integer.
|
||||
int lmax = iPower;
|
||||
if (lmax > 14)
|
||||
lmax = 14;
|
||||
|
||||
if ((((uint8_t)ulMant) == 0) && (lmax >= 8))
|
||||
{
|
||||
const uint32_t den = 100000000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 8;
|
||||
lmax -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 0xF) == 0) && (lmax >= 4))
|
||||
{
|
||||
const uint32_t den = 10000;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 4;
|
||||
lmax -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 3) == 0) && (lmax >= 2))
|
||||
{
|
||||
const uint32_t den = 100;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower -= 2;
|
||||
lmax -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((uint32_t)ulMant & 1) == 0) && (lmax >= 1))
|
||||
{
|
||||
const uint32_t den = 10;
|
||||
uint64_t div = ulMant / den;
|
||||
if ((uint32_t)ulMant == (uint32_t)(div * den))
|
||||
{
|
||||
ulMant = div;
|
||||
iPower--;
|
||||
}
|
||||
}
|
||||
|
||||
flags |= (uint32_t)iPower << 16;
|
||||
|
||||
*((uint64_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = ulMant;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 8)) = 0;
|
||||
}
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 12)) = flags;
|
||||
}
|
||||
|
||||
void FieldModel<uuid_t>::get(uuid_t& value, uuid_t defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(value.data().data(), (const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), fbe_size());
|
||||
}
|
||||
|
||||
void FieldModel<uuid_t>::set(uuid_t value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
std::memcpy((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()), value.data().data(), fbe_size());
|
||||
}
|
||||
|
||||
size_t FieldModel<buffer_t>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_bytes_offset == 0) || ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
return (size_t)(4 + fbe_bytes_size);
|
||||
}
|
||||
|
||||
bool FieldModel<buffer_t>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<buffer_t>::get(void* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_bytes_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FieldModel<buffer_t>::get(std::vector<uint8_t>& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_bytes_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset));
|
||||
assert(((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
const char* fbe_bytes = (const char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4);
|
||||
value.assign(fbe_bytes, fbe_bytes + fbe_bytes_size);
|
||||
}
|
||||
|
||||
void FieldModel<buffer_t>::set(const void* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_bytes_size = (uint32_t)size;
|
||||
uint32_t fbe_bytes_offset = (uint32_t)(_buffer.allocate(4 + fbe_bytes_size) - _buffer.offset());
|
||||
assert(((fbe_bytes_offset > 0) && ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_bytes_offset == 0) || ((_buffer.offset() + fbe_bytes_offset + 4 + fbe_bytes_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_bytes_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset)) = fbe_bytes_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_bytes_offset + 4), data, fbe_bytes_size);
|
||||
}
|
||||
|
||||
size_t FieldModel<std::string>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
return (size_t)(4 + fbe_string_size);
|
||||
}
|
||||
|
||||
bool FieldModel<std::string>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_string_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FieldModel<std::string>::get(char* data, size_t size) const noexcept
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return 0;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_string_offset == 0)
|
||||
return 0;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
size_t result = std::min(size, (size_t)fbe_string_size);
|
||||
memcpy(data, (const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::get(std::string& value) const noexcept
|
||||
{
|
||||
value.clear();
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + _offset));
|
||||
if (fbe_string_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::get(std::string& value, const std::string& defaults) const noexcept
|
||||
{
|
||||
value = defaults;
|
||||
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + _offset));
|
||||
if (fbe_string_offset == 0)
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset));
|
||||
assert(((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size())
|
||||
return;
|
||||
|
||||
value.assign((const char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::set(const char* data, size_t size)
|
||||
{
|
||||
assert(((size == 0) || (data != nullptr)) && "Invalid buffer!");
|
||||
if ((size > 0) && (data == nullptr))
|
||||
return;
|
||||
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)size;
|
||||
uint32_t fbe_string_offset = (uint32_t)(_buffer.allocate(4 + fbe_string_size) - _buffer.offset());
|
||||
assert(((fbe_string_offset > 0) && ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset)) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), data, fbe_string_size);
|
||||
}
|
||||
|
||||
void FieldModel<std::string>::set(const std::string& value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
uint32_t fbe_string_size = (uint32_t)value.size();
|
||||
uint32_t fbe_string_offset = (uint32_t)(_buffer.allocate(4 + fbe_string_size) - _buffer.offset());
|
||||
assert(((fbe_string_offset > 0) && ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_string_offset == 0) || ((_buffer.offset() + fbe_string_offset + 4 + fbe_string_size) > _buffer.size()))
|
||||
return;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_string_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_string_offset)) = fbe_string_size;
|
||||
|
||||
memcpy((char*)(_buffer.data() + _buffer.offset() + fbe_string_offset + 4), value.data(), fbe_string_size);
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
471
fbe/user_model/fbe_models.h
Normal file
471
fbe/user_model/fbe_models.h
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang system_header
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC system_header
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma system_header
|
||||
#endif
|
||||
|
||||
#include "fbe.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding base field model
|
||||
template <typename T, typename TBase = T>
|
||||
class FieldModelBase
|
||||
{
|
||||
public:
|
||||
FieldModelBase(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return sizeof(TBase); }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the field value
|
||||
void get(T& value, T defaults = (T)0) const noexcept;
|
||||
// Set the field value
|
||||
void set(T value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model
|
||||
template <typename T>
|
||||
class FieldModel : public FieldModelBase<T>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<T>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model bool specialization
|
||||
template <>
|
||||
class FieldModel<bool> : public FieldModelBase<bool, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<bool, uint8_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model char specialization
|
||||
template <>
|
||||
class FieldModel<char> : public FieldModelBase<char, uint8_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<char, uint8_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model wchar specialization
|
||||
template <>
|
||||
class FieldModel<wchar_t> : public FieldModelBase<wchar_t, uint32_t>
|
||||
{
|
||||
public:
|
||||
using FieldModelBase<wchar_t, uint32_t>::FieldModelBase;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model decimal specialization
|
||||
template <>
|
||||
class FieldModel<decimal_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the decimal value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the decimal value
|
||||
void get(decimal_t& value, decimal_t defaults = decimal_t()) const noexcept;
|
||||
// Set the decimal value
|
||||
void set(decimal_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
static uint64_t extract(double a) noexcept;
|
||||
static uint64_t uint32x32(uint32_t a, uint32_t b) noexcept;
|
||||
static void uint64x64(uint64_t a, uint64_t b, uint64_t& low64, uint32_t& high32) noexcept;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model UUID specialization
|
||||
template <>
|
||||
class FieldModel<uuid_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 16; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the UUID value is valid
|
||||
bool verify() const noexcept { return true; }
|
||||
|
||||
// Get the UUID value
|
||||
void get(uuid_t& value, uuid_t defaults = uuid_t::nil()) const noexcept;
|
||||
// Set the UUID value
|
||||
void set(uuid_t value) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model bytes specialization
|
||||
template <>
|
||||
class FieldModel<buffer_t>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the bytes value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the bytes value
|
||||
size_t get(void* data, size_t size) const noexcept;
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(uint8_t (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the bytes value
|
||||
template <size_t N>
|
||||
size_t get(std::array<uint8_t, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the bytes value
|
||||
void get(std::vector<uint8_t>& value) const noexcept;
|
||||
// Get the bytes value
|
||||
void get(buffer_t& value) const noexcept { get(value.buffer()); }
|
||||
|
||||
// Set the bytes value
|
||||
void set(const void* data, size_t size);
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
void set(const uint8_t (&data)[N]) { set(data, N); }
|
||||
// Set the bytes value
|
||||
template <size_t N>
|
||||
void set(const std::array<uint8_t, N>& data) { set(data.data(), data.size()); }
|
||||
// Set the bytes value
|
||||
void set(const std::vector<uint8_t>& value) { set(value.data(), value.size()); }
|
||||
// Set the bytes value
|
||||
void set(const buffer_t& value) { set(value.buffer()); }
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model string specialization
|
||||
template <>
|
||||
class FieldModel<std::string>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Check if the string value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the string value
|
||||
size_t get(char* data, size_t size) const noexcept;
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(char (&data)[N]) const noexcept { return get(data, N); }
|
||||
// Get the string value
|
||||
template <size_t N>
|
||||
size_t get(std::array<char, N>& data) const noexcept { return get(data.data(), data.size()); }
|
||||
// Get the string value
|
||||
void get(std::string& value) const noexcept;
|
||||
// Get the string value
|
||||
void get(std::string& value, const std::string& defaults) const noexcept;
|
||||
|
||||
// Set the string value
|
||||
void set(const char* data, size_t size);
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
void set(const char (&data)[N]) { set(data, N); }
|
||||
// Set the string value
|
||||
template <size_t N>
|
||||
void set(const std::array<char, N>& data) { set(data.data(), data.size()); }
|
||||
// Set the string value
|
||||
void set(const std::string& value);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model optional specialization
|
||||
template <typename T>
|
||||
class FieldModel<std::optional<T>>
|
||||
{
|
||||
public:
|
||||
FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), value(buffer, 0) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 1 + 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
//! Is the value present?
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
// Checks if the object contains a value
|
||||
bool has_value() const noexcept;
|
||||
|
||||
// Check if the optional value is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the optional value (being phase)
|
||||
size_t get_begin() const noexcept;
|
||||
// Get the optional value (end phase)
|
||||
void get_end(size_t fbe_begin) const noexcept;
|
||||
|
||||
// Get the optional value
|
||||
void get(std::optional<T>& opt, const std::optional<T>& defaults = std::nullopt) const noexcept;
|
||||
|
||||
// Set the optional value (begin phase)
|
||||
size_t set_begin(bool has_value);
|
||||
// Set the optional value (end phase)
|
||||
void set_end(size_t fbe_begin);
|
||||
|
||||
// Set the optional value
|
||||
void set(const std::optional<T>& opt);
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
|
||||
public:
|
||||
// Base field model value
|
||||
FieldModel<T> value;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model array
|
||||
template <typename T, size_t N>
|
||||
class FieldModelArray
|
||||
{
|
||||
public:
|
||||
FieldModelArray(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset), _model(buffer, offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return N * _model.fbe_size(); }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept { return 0; }
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the array
|
||||
const uint8_t* data() const noexcept;
|
||||
// Get the array
|
||||
uint8_t* data() noexcept;
|
||||
// Get the array offset
|
||||
size_t offset() const noexcept { return 0; }
|
||||
// Get the array size
|
||||
size_t size() const noexcept { return N; }
|
||||
|
||||
// Array index operator
|
||||
FieldModel<T> operator[](size_t index) const noexcept;
|
||||
|
||||
// Check if the array is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the array as C-array
|
||||
template <size_t S>
|
||||
void get(T (&values)[S]) const noexcept;
|
||||
// Get the array as std::array
|
||||
template <size_t S>
|
||||
void get(std::array<T, S>& values) const noexcept;
|
||||
// Get the array as std::vector
|
||||
void get(std::vector<T>& values) const noexcept;
|
||||
|
||||
// Set the array as C-array
|
||||
template <size_t S>
|
||||
void set(const T (&values)[S]) noexcept;
|
||||
// Set the array as std::array
|
||||
template <size_t S>
|
||||
void set(const std::array<T, S>& values) noexcept;
|
||||
// Set the array as std::vector
|
||||
void set(const std::vector<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
FieldModel<T> _model;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model vector
|
||||
template <typename T>
|
||||
class FieldModelVector
|
||||
{
|
||||
public:
|
||||
FieldModelVector(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the vector offset
|
||||
size_t offset() const noexcept;
|
||||
// Get the vector size
|
||||
size_t size() const noexcept;
|
||||
|
||||
// Vector index operator
|
||||
FieldModel<T> operator[](size_t index) const noexcept;
|
||||
|
||||
// Resize the vector and get its first model
|
||||
FieldModel<T> resize(size_t size);
|
||||
|
||||
// Check if the vector is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the vector as std::vector
|
||||
void get(std::vector<T>& values) const noexcept;
|
||||
// Get the vector as std::list
|
||||
void get(std::list<T>& values) const noexcept;
|
||||
// Get the vector as std::set
|
||||
void get(std::set<T>& values) const noexcept;
|
||||
|
||||
// Set the vector as std::vector
|
||||
void set(const std::vector<T>& values) noexcept;
|
||||
// Set the vector as std::list
|
||||
void set(const std::list<T>& values) noexcept;
|
||||
// Set the vector as std::set
|
||||
void set(const std::set<T>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
// Fast Binary Encoding field model map
|
||||
template <typename TKey, typename TValue>
|
||||
class FieldModelMap
|
||||
{
|
||||
public:
|
||||
FieldModelMap(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) {}
|
||||
|
||||
// Get the field offset
|
||||
size_t fbe_offset() const noexcept { return _offset; }
|
||||
// Get the field size
|
||||
size_t fbe_size() const noexcept { return 4; }
|
||||
// Get the field extra size
|
||||
size_t fbe_extra() const noexcept;
|
||||
|
||||
// Shift the current field offset
|
||||
void fbe_shift(size_t size) noexcept { _offset += size; }
|
||||
// Unshift the current field offset
|
||||
void fbe_unshift(size_t size) noexcept { _offset -= size; }
|
||||
|
||||
// Get the map offset
|
||||
size_t offset() const noexcept;
|
||||
// Get the map size
|
||||
size_t size() const noexcept;
|
||||
|
||||
// Map index operator
|
||||
std::pair<FieldModel<TKey>, FieldModel<TValue>> operator[](size_t index) const noexcept;
|
||||
|
||||
// Resize the map and get its first model
|
||||
std::pair<FieldModel<TKey>, FieldModel<TValue>> resize(size_t size);
|
||||
|
||||
// Check if the map is valid
|
||||
bool verify() const noexcept;
|
||||
|
||||
// Get the map as std::map
|
||||
void get(std::map<TKey, TValue>& values) const noexcept;
|
||||
// Get the map as std::unordered_map
|
||||
void get(std::unordered_map<TKey, TValue>& values) const noexcept;
|
||||
|
||||
// Set the map as std::map
|
||||
void set(const std::map<TKey, TValue>& values) noexcept;
|
||||
// Set the map as std::unordered_map
|
||||
void set(const std::unordered_map<TKey, TValue>& values) noexcept;
|
||||
|
||||
private:
|
||||
FBEBuffer& _buffer;
|
||||
size_t _offset;
|
||||
};
|
||||
|
||||
} // namespace FBE
|
||||
|
||||
#include "fbe_models.inl"
|
||||
689
fbe/user_model/fbe_models.inl
Normal file
689
fbe/user_model/fbe_models.inl
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace FBE {
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline void FieldModelBase<T, TBase>::get(T& value, T defaults) const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
{
|
||||
value = defaults;
|
||||
return;
|
||||
}
|
||||
|
||||
value = (T)(*((const TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())));
|
||||
}
|
||||
|
||||
template <typename T, typename TBase>
|
||||
inline void FieldModelBase<T, TBase>::set(T value) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
*((TBase*)(_buffer.data() + _buffer.offset() + fbe_offset())) = (TBase)value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::fbe_extra() const noexcept
|
||||
{
|
||||
if (!has_value())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
if ((fbe_optional_offset == 0) || ((_buffer.offset() + fbe_optional_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
size_t fbe_result = value.fbe_size() + value.fbe_extra();
|
||||
_buffer.unshift(fbe_optional_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModel<std::optional<T>>::has_value() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return (fbe_has_value != 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModel<std::optional<T>>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint8_t fbe_has_value = *((const uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_has_value == 0)
|
||||
return true;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
if (fbe_optional_offset == 0)
|
||||
return false;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
bool fbe_result = value.verify();
|
||||
_buffer.unshift(fbe_optional_offset);
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::get_begin() const noexcept
|
||||
{
|
||||
if (!has_value())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1));
|
||||
assert((fbe_optional_offset > 0) && "Model is broken!");
|
||||
if (fbe_optional_offset == 0)
|
||||
return 0;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
return fbe_optional_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::get_end(size_t fbe_begin) const noexcept
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::get(std::optional<T>& opt, const std::optional<T>& defaults) const noexcept
|
||||
{
|
||||
opt = defaults;
|
||||
|
||||
size_t fbe_begin = get_begin();
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
T temp = T();
|
||||
value.get(temp);
|
||||
opt.emplace(temp);
|
||||
|
||||
get_end(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModel<std::optional<T>>::set_begin(bool has_value)
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint8_t fbe_has_value = has_value ? 1 : 0;
|
||||
*((uint8_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_has_value;
|
||||
if (fbe_has_value == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_optional_size = (uint32_t)value.fbe_size();
|
||||
uint32_t fbe_optional_offset = (uint32_t)(_buffer.allocate(fbe_optional_size) - _buffer.offset());
|
||||
assert(((fbe_optional_offset > 0) && ((_buffer.offset() + fbe_optional_offset + fbe_optional_size) <= _buffer.size())) && "Model is broken!");
|
||||
if ((fbe_optional_offset == 0) || ((_buffer.offset() + fbe_optional_offset + fbe_optional_size) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset() + 1)) = fbe_optional_offset;
|
||||
|
||||
_buffer.shift(fbe_optional_offset);
|
||||
return fbe_optional_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::set_end(size_t fbe_begin)
|
||||
{
|
||||
_buffer.unshift(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModel<std::optional<T>>::set(const std::optional<T>& opt)
|
||||
{
|
||||
size_t fbe_begin = set_begin(opt.has_value());
|
||||
if (fbe_begin == 0)
|
||||
return;
|
||||
|
||||
if (opt)
|
||||
value.set(opt.value());
|
||||
|
||||
set_end(fbe_begin);
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline const uint8_t* FieldModelArray<T, N>::data() const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
return _buffer.data() + _buffer.offset() + fbe_offset();
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline uint8_t* FieldModelArray<T, N>::data() noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
return _buffer.data() + _buffer.offset() + fbe_offset();
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline FieldModel<T> FieldModelArray<T, N>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
assert((index < N) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
fbe_model.fbe_shift(index * fbe_model.fbe_size());
|
||||
return fbe_model;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline bool FieldModelArray<T, N>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return false;
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model.verify())
|
||||
return false;
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::get(T (&values)[S]) const noexcept
|
||||
{
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::get(std::array<T, S>& values) const noexcept
|
||||
{
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.get(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline void FieldModelArray<T, N>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
values.reserve(N);
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = N; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::set(const T (&values)[S]) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
template <size_t S>
|
||||
inline void FieldModelArray<T, N>::set(const std::array<T, S>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < S) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline void FieldModelArray<T, N>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = 0; (i < values.size()) && (i < N); ++i)
|
||||
{
|
||||
fbe_model.set(values[i]);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_vector_offset == 0) || ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
|
||||
size_t fbe_result = 4;
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
fbe_result += fbe_model.fbe_size() + fbe_model.fbe_extra();
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::offset() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return fbe_vector_offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t FieldModelVector<T>::size() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_vector_offset == 0) || ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
return fbe_vector_size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline FieldModel<T> FieldModelVector<T>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_vector_offset > 0) && ((_buffer.offset() + fbe_vector_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
[[maybe_unused]] uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
assert((index < fbe_vector_size) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
fbe_model.fbe_shift(index * fbe_model.fbe_size());
|
||||
return fbe_model;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline FieldModel<T> FieldModelVector<T>::resize(size_t size)
|
||||
{
|
||||
FieldModel<T> fbe_model(_buffer, fbe_offset());
|
||||
|
||||
uint32_t fbe_vector_size = (uint32_t)(size * fbe_model.fbe_size());
|
||||
uint32_t fbe_vector_offset = (uint32_t)(_buffer.allocate(4 + fbe_vector_size) - _buffer.offset());
|
||||
assert(((fbe_vector_offset > 0) && ((_buffer.offset() + fbe_vector_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_vector_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset)) = (uint32_t)size;
|
||||
|
||||
memset((char*)(_buffer.data() + _buffer.offset() + fbe_vector_offset + 4), 0, fbe_vector_size);
|
||||
|
||||
return FieldModel<T>(_buffer, fbe_vector_offset + 4);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool FieldModelVector<T>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_vector_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_vector_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_vector_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_vector_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_vector_offset));
|
||||
|
||||
FieldModel<T> fbe_model(_buffer, fbe_vector_offset + 4);
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model.verify())
|
||||
return false;
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::vector<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
values.reserve(fbe_vector_size);
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::list<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace_back(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::get(std::set<T>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_vector_size = size();
|
||||
if (fbe_vector_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_vector_size; i-- > 0;)
|
||||
{
|
||||
T value = T();
|
||||
fbe_model.get(value);
|
||||
values.emplace(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::vector<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::list<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void FieldModelVector<T>::set(const std::set<T>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.set(value);
|
||||
fbe_model.fbe_shift(fbe_model.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::fbe_extra() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_map_offset == 0) || ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
|
||||
size_t fbe_result = 4;
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
fbe_result += fbe_model_key.fbe_size() + fbe_model_key.fbe_extra();
|
||||
fbe_model_key.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
fbe_result += fbe_model_value.fbe_size() + fbe_model_value.fbe_extra();
|
||||
fbe_model_value.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
}
|
||||
return fbe_result;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::offset() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
return fbe_map_offset;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline size_t FieldModelMap<TKey, TValue>::size() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if ((fbe_map_offset == 0) || ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size()))
|
||||
return 0;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
return fbe_map_size;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline std::pair<FieldModel<TKey>, FieldModel<TValue>> FieldModelMap<TKey, TValue>::operator[](size_t index) const noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
assert(((fbe_map_offset > 0) && ((_buffer.offset() + fbe_map_offset + 4) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
[[maybe_unused]] uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
assert((index < fbe_map_size) && "Index is out of bounds!");
|
||||
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
fbe_model_key.fbe_shift(index * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
fbe_model_value.fbe_shift(index * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
return std::make_pair(fbe_model_key, fbe_model_value);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline std::pair<FieldModel<TKey>, FieldModel<TValue>> FieldModelMap<TKey, TValue>::resize(size_t size)
|
||||
{
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_offset());
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_offset() + fbe_model_key.fbe_size());
|
||||
|
||||
uint32_t fbe_map_size = (uint32_t)(size * (fbe_model_key.fbe_size() + fbe_model_value.fbe_size()));
|
||||
uint32_t fbe_map_offset = (uint32_t)(_buffer.allocate(4 + fbe_map_size) - _buffer.offset());
|
||||
assert(((fbe_map_offset > 0) && ((_buffer.offset() + fbe_map_offset + 4 + fbe_map_size) <= _buffer.size())) && "Model is broken!");
|
||||
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset())) = fbe_map_offset;
|
||||
*((uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset)) = (uint32_t)size;
|
||||
|
||||
memset((char*)(_buffer.data() + _buffer.offset() + fbe_map_offset + 4), 0, fbe_map_size);
|
||||
|
||||
return std::make_pair(FieldModel<TKey>(_buffer, fbe_map_offset + 4), FieldModel<TValue>(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size()));
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline bool FieldModelMap<TKey, TValue>::verify() const noexcept
|
||||
{
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return true;
|
||||
|
||||
uint32_t fbe_map_offset = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_offset()));
|
||||
if (fbe_map_offset == 0)
|
||||
return true;
|
||||
|
||||
if ((_buffer.offset() + fbe_map_offset + 4) > _buffer.size())
|
||||
return false;
|
||||
|
||||
uint32_t fbe_map_size = *((const uint32_t*)(_buffer.data() + _buffer.offset() + fbe_map_offset));
|
||||
|
||||
FieldModel<TKey> fbe_model_key(_buffer, fbe_map_offset + 4);
|
||||
FieldModel<TValue> fbe_model_value(_buffer, fbe_map_offset + 4 + fbe_model_key.fbe_size());
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
if (!fbe_model_key.verify())
|
||||
return false;
|
||||
fbe_model_key.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
if (!fbe_model_value.verify())
|
||||
return false;
|
||||
fbe_model_value.fbe_shift(fbe_model_key.fbe_size() + fbe_model_value.fbe_size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_map_size = size();
|
||||
if (fbe_map_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& values) const noexcept
|
||||
{
|
||||
values.clear();
|
||||
|
||||
size_t fbe_map_size = size();
|
||||
if (fbe_map_size == 0)
|
||||
return;
|
||||
|
||||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::set(const std::map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.first.set(value.first);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.set(value.second);
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
inline void FieldModelMap<TKey, TValue>::set(const std::unordered_map<TKey, TValue>& values) noexcept
|
||||
{
|
||||
assert(((_buffer.offset() + fbe_offset() + fbe_size()) <= _buffer.size()) && "Model is broken!");
|
||||
if ((_buffer.offset() + fbe_offset() + fbe_size()) > _buffer.size())
|
||||
return;
|
||||
|
||||
auto fbe_model = resize(values.size());
|
||||
for (const auto& value : values)
|
||||
{
|
||||
fbe_model.first.set(value.first);
|
||||
fbe_model.first.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
fbe_model.second.set(value.second);
|
||||
fbe_model.second.fbe_shift(fbe_model.first.fbe_size() + fbe_model.second.fbe_size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FBE
|
||||
87
help.html
87
help.html
|
|
@ -1,87 +0,0 @@
|
|||
|
||||
|
||||
<body>
|
||||
<h1>ALL FUNCTIONS (that have args) ARE EXPECTING JSON AS DATA TYPE</h1>
|
||||
<h2>/BankF/<span style=\"color: #993300;\">admin</span>/close (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Closes and Saves the server.</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/user (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of the user being added (must be less then 50 characters)</p>
|
||||
<p><span style=\"background-color: #808080;\"> init_pass </span> - initial password for the user being added</p>
|
||||
<blockquote>
|
||||
<p>Adds a user to the bank</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of the user being added</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - admin password required to add user with balance</p>
|
||||
<p><span style=\"background-color: #808080;\"> init_bal </span> - initial balance for user being added</p>
|
||||
<p><span style=\"background-color: #808080;\"> init_pass </span> - initial password for user being added</p>
|
||||
<blockquote>
|
||||
<p>Adds a user with initial balance</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/sendfunds (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> a_name </span> - sender's name</p>
|
||||
<p><span style=\"background-color: #808080;\"> b_name </span> - reciever's name</p>
|
||||
<p><span style=\"background-color: #808080;\"> amount </span> - amount being sent</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - password of sender</p>
|
||||
<blockquote>
|
||||
<p>Sends money from one user to another</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/changepass (PATCH)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of user's password being changes</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - password of user being changed</p>
|
||||
<p><span style=\"background-color: #808080;\"> new_pass </span> - new password to replace the current user's password</p>
|
||||
<blockquote>
|
||||
<p>Changes password of a user, returns -1 if user doesnt exist</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style=\"color: #993300;\">admin</span>/{<span style=\"color: #339966;\">name</span>}/bal (PATCH)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - the name of the user being set</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - the admin password required</p>
|
||||
<p><span style=\"background-color: #808080;\"> amount </span> - the new balance of the user</p>
|
||||
<blockquote>
|
||||
<p>Sets the balance of a user</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/help (GET)</h2>
|
||||
<blockquote>
|
||||
<p>the page you're looking at right now!</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/vpass (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of user being verified</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - password being verified</p>
|
||||
<blockquote>
|
||||
<p>returns 0 or 1 based on if [attempt] is equal to the password of the user [name], or -1 if user does not exist. The intended usage for this function is for connected services</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/contains/{<span style=\"color: #339966;\">name</span>} (GET)</h2>
|
||||
<blockquote>
|
||||
<p>returns a 0 or 1 based on if the bank contains the user</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/{<span style=\"color: #339966;\">name</span>}/bal (GET)</h2>
|
||||
<blockquote>
|
||||
<p>returns the balance of a given user's name, if -1 that means the user does not exist</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style=\"color: #993300;\">admin</span>/vpass (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Verifies if password entered is admin password</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/{<span style=\"color: #339966;\">name</span>}/log (POST)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - user password</p>
|
||||
<blockquote>
|
||||
<p>returns a list of last 100 transactions, -1 if user not found, 0 if invalid password</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/user (DELETE)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of user being deleted</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - password of user being deleted</p>
|
||||
<blockquote>
|
||||
<p>Deletes a user with the password of the user as verification</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (DELETE)</h2>
|
||||
<p><span style=\"background-color: #808080;\"> name </span> - name of user being deleted</p>
|
||||
<p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Deletes a user with admin password as verification</p>
|
||||
</blockquote>
|
||||
</body>
|
||||
|
||||
74
include/bank.h
Normal file
74
include/bank.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include <parallel-hashmap/parallel_hashmap/phmap.h>
|
||||
#include "bank_resp.h"
|
||||
#include "user.h"
|
||||
|
||||
|
||||
#if (CONSERVATIVE_DISK_SAVE && MAX_LOG_SIZE < 0) && !MULTI_THREADED
|
||||
#include "change_flag.h"
|
||||
#endif
|
||||
|
||||
class Bank
|
||||
{
|
||||
#if MULTI_THREADED
|
||||
static phmap::parallel_flat_hash_map<
|
||||
std::string, User,
|
||||
xxHashStringGen,
|
||||
phmap::priv::hash_default_eq<std::string>,
|
||||
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
|
||||
4UL,
|
||||
std::mutex>
|
||||
users;
|
||||
#else
|
||||
static phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> users;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
static ChangeFlag<false> save_flag;
|
||||
#endif
|
||||
|
||||
// must grab as shared if the operation is gonna modify "users"'s size or can be caught in a intermediary state such as SendFunds()
|
||||
// must grab as unique if the operation is gonna use user iterators
|
||||
static std::shared_mutex iter_lock;
|
||||
|
||||
public:
|
||||
static std::string admin_account;
|
||||
|
||||
static size_t NumOfUsers() noexcept;
|
||||
static size_t NumOfLogs() noexcept;
|
||||
static size_t SumBal() noexcept;
|
||||
|
||||
static BankResponse GetBal(const std::string &name) noexcept;
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
static BankResponse GetLogs(const std::string &name) noexcept;
|
||||
#endif
|
||||
static BankResponse GetLogsV2(const std::string &name) noexcept;
|
||||
static BankResponse GetLogsRange(const std::string &name, size_t n, size_t m) noexcept;
|
||||
#endif
|
||||
|
||||
static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
|
||||
static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept;
|
||||
static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept;
|
||||
static BankResponse SetBal(const std::string &name, int64_t amount) noexcept;
|
||||
static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
|
||||
static bool Contains(const std::string &name) noexcept;
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept;
|
||||
#else
|
||||
static BankResponse PruneUsers(uint32_t threshold_bal) noexcept;
|
||||
#endif
|
||||
|
||||
static BankResponse AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept;
|
||||
static BankResponse DelUser(const std::string &name) noexcept;
|
||||
static void DelSelf(const std::string &name) noexcept;
|
||||
|
||||
static const char *Save();
|
||||
static void Load();
|
||||
};
|
||||
256
include/bank.hpp
256
include/bank.hpp
|
|
@ -1,256 +0,0 @@
|
|||
#pragma once
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include "xxhash.h"
|
||||
#include "parallel-hashmap/parallel_hashmap/phmap.h"
|
||||
#include "user.hpp"
|
||||
|
||||
class
|
||||
{
|
||||
private:
|
||||
phmap::parallel_flat_hash_map<
|
||||
std::string, User,
|
||||
phmap::priv::hash_default_hash<std::string>,
|
||||
phmap::priv::hash_default_eq<std::string>,
|
||||
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
|
||||
4UL,
|
||||
std::mutex>
|
||||
users;
|
||||
|
||||
/**
|
||||
* @brief size_l should be grabbed if the operation MODIFIES the size (shared), this is so that when save claims unique
|
||||
*
|
||||
*/
|
||||
std::shared_mutex size_l;
|
||||
|
||||
/**
|
||||
* @brief send_funds_l should be grabbed if balances are being MODIFIED (shared) or if an operation needs to READ without the intermediary states that sendfunds has (unique)
|
||||
*
|
||||
*/
|
||||
std::shared_mutex send_funds_l;
|
||||
|
||||
public:
|
||||
std::string admin_pass;
|
||||
|
||||
bool AddUser(const std::string &name, std::string &&init_pass)
|
||||
{
|
||||
if (name.size() > 50)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.try_emplace_l(
|
||||
name, [](User &) {}, std::move(init_pass));
|
||||
}
|
||||
bool AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass)
|
||||
{
|
||||
if (name.size() > 50)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool state = (admin_pass == attempt);
|
||||
if (state)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
state = users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
bool DelUser(const std::string &name, const std::string &attempt)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.erase_if(name, [&attempt](User &u) { return (XXH3_64bits(attempt.data(), attempt.size()) == u.password); });
|
||||
}
|
||||
bool AdminDelUser(const std::string &name, const std::string &attempt)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.erase_if(name, [this, &attempt](const User &) { return (admin_pass == attempt); });
|
||||
}
|
||||
|
||||
bool SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt)
|
||||
{
|
||||
//cant send money to self, from self or amount is 0
|
||||
if (a_name == b_name || !amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//if A exists, A can afford it, and A's password matches
|
||||
bool state = false;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l}; //because SendFunds requires 3 locking operations
|
||||
users.modify_if(a_name, [&state, amount, &attempt](User &a) {
|
||||
if (state = (a.balance >= amount) && (a.password == XXH3_64bits(attempt.data(), attempt.size())))
|
||||
{
|
||||
a.balance -= amount;
|
||||
}
|
||||
});
|
||||
|
||||
if (state)
|
||||
{
|
||||
//if B doesnt exist
|
||||
if (!users.modify_if(b_name, [amount](User &b) {
|
||||
b.balance += amount;
|
||||
}))
|
||||
{
|
||||
//attempt to refund if A exist
|
||||
users.modify_if(a_name, [amount](User &a) {
|
||||
a.balance += amount;
|
||||
});
|
||||
return false; //because had to refund transaction
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
Transaction temp(a_name, b_name, amount);
|
||||
Transaction temp2 = temp;
|
||||
users.modify_if(a_name, [&temp](User &a) {
|
||||
a.log.AddTrans(std::move(temp));
|
||||
});
|
||||
users.modify_if(b_name, [&temp2](User &b) {
|
||||
b.log.AddTrans(std::move(temp2));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
bool Contains(const std::string &name) const
|
||||
{
|
||||
return users.contains(name);
|
||||
}
|
||||
bool SetBal(const std::string &name, const std::string &attempt, uint32_t amount)
|
||||
{
|
||||
bool state = (admin_pass == attempt);
|
||||
if (state)
|
||||
{
|
||||
users.modify_if(name, [amount](User &u) {
|
||||
u.balance = amount;
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
||||
bool AdminVerifyPass(const std::string &attempt)
|
||||
{
|
||||
return admin_pass == attempt;
|
||||
}
|
||||
|
||||
int_fast64_t GetBal(const std::string &name) const
|
||||
{
|
||||
int_fast64_t res = -1;
|
||||
users.if_contains(name, [&res](const User &u) {
|
||||
res = u.balance;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
int_fast8_t VerifyPassword(const std::string &name, const std::string &attempt) const
|
||||
{
|
||||
int_fast8_t res = -1;
|
||||
users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
res = u.password == XXH3_64bits(attempt.data(), attempt.size());
|
||||
});
|
||||
return res;
|
||||
}
|
||||
int_fast8_t ChangePassword(const std::string &name, const std::string &attempt, std::string &&new_pass)
|
||||
{
|
||||
int_fast8_t res = -1;
|
||||
users.modify_if(name, [&res, &attempt, &new_pass](User &u) {
|
||||
res = (u.password == XXH3_64bits(attempt.data(), attempt.size()));
|
||||
if (res)
|
||||
{
|
||||
u.password = XXH3_64bits(new_pass.data(), new_pass.size());
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
Json::Value GetLogs(const std::string &name, const std::string &attempt)
|
||||
{
|
||||
Json::Value res;
|
||||
if (!users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Json::Value temp;
|
||||
for (uint32_t i = u.log.data.size(); i > 0; --i)
|
||||
{
|
||||
temp[i - 1]["to"] = u.log.data[u.log.data.size() - i].to;
|
||||
temp[i - 1]["from"] = u.log.data[u.log.data.size() - i].from;
|
||||
temp[i - 1]["amount"] = (Json::UInt)u.log.data[u.log.data.size() - i].amount;
|
||||
temp[i - 1]["time"] = (Json::UInt64)u.log.data[u.log.data.size() - i].time;
|
||||
}
|
||||
res = std::move(temp);
|
||||
}
|
||||
}))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Save()
|
||||
{
|
||||
Json::StreamWriterBuilder builder;
|
||||
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
|
||||
|
||||
std::ofstream user_save("../users.json");
|
||||
Json::Value temp;
|
||||
|
||||
//loading info into json temp
|
||||
{
|
||||
std::scoped_lock<std::shared_mutex, std::shared_mutex> lock{size_l, send_funds_l};
|
||||
for (const auto &u : users)
|
||||
{
|
||||
//we know it contains this key but we call this func to grab mutex
|
||||
users.if_contains(u.first, [&temp, &u](const User &u_val) {
|
||||
temp[u.first] = u_val.Serialize();
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!temp.isNull())
|
||||
{
|
||||
writer->write(temp, &user_save);
|
||||
}
|
||||
user_save.close();
|
||||
}
|
||||
|
||||
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
|
||||
void Load()
|
||||
{
|
||||
Json::CharReaderBuilder builder;
|
||||
|
||||
Json::Value temp;
|
||||
std::ifstream user_save("../users.json");
|
||||
builder["collectComments"] = true;
|
||||
JSONCPP_STRING errs;
|
||||
if (!parseFromStream(builder, user_save, &temp, &errs))
|
||||
{
|
||||
std::cerr << errs << '\n';
|
||||
throw std::invalid_argument("Parsing Failed\n");
|
||||
user_save.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
user_save.close();
|
||||
for (const auto &u : temp.getMemberNames())
|
||||
{
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
users.try_emplace(u, temp[u]["balance"].asUInt(), std::move(temp[u]["password"].asUInt64()), temp[u]["log"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
users.try_emplace(u, temp[u]["balance"].asUInt(), std::move(temp[u]["password"].asUInt64()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} bank;
|
||||
91
include/bank_api.h
Normal file
91
include/bank_api.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
#include "str_intrusion.h"
|
||||
#include "json_filter.h"
|
||||
#include "user_filter.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
#define req_args const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback
|
||||
|
||||
class api : public HttpController<api>
|
||||
{
|
||||
public:
|
||||
static void GetBal(req_args, const std::string &name);
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
static void GetLogs(req_args);
|
||||
#endif
|
||||
static void GetLogsV2(req_args);
|
||||
static void GetLogsRange(req_args, size_t start, size_t length);
|
||||
static void SendFunds(req_args);
|
||||
static void ChangePassword(req_args);
|
||||
static void VerifyPassword(req_args);
|
||||
|
||||
static void AdminGetLogs(req_args, const std::string& name);
|
||||
static void AdminChangePassword(req_args);
|
||||
static void AdminVerifyAccount(req_args);
|
||||
static void SetBal(req_args);
|
||||
static void ImpactBal(req_args);
|
||||
|
||||
static void Help(req_args);
|
||||
static void Close(req_args);
|
||||
static void Contains(req_args, const std::string &name);
|
||||
static void PruneUsers(req_args);
|
||||
static void ApiProperties(req_args);
|
||||
|
||||
static void AddUser(req_args);
|
||||
static void AdminAddUser(req_args);
|
||||
static void DelSelf(req_args);
|
||||
static void AdminDelUser(req_args);
|
||||
|
||||
METHOD_LIST_BEGIN
|
||||
|
||||
|
||||
//Usage
|
||||
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
|
||||
#endif
|
||||
|
||||
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
|
||||
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
|
||||
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>", "UserFilter<false, true>");
|
||||
#else
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
|
||||
#endif
|
||||
|
||||
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>");
|
||||
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>");
|
||||
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>");
|
||||
#endif
|
||||
|
||||
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32)
|
||||
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
|
||||
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");
|
||||
|
||||
//Meta Usage
|
||||
METHOD_ADD(api::AdminChangePassword, "/v1/admin/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["pass"](string)
|
||||
METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
|
||||
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
|
||||
|
||||
//System Usage
|
||||
METHOD_ADD(api::Help, "/help", Get, Options);
|
||||
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options, "JsonFilter<false>");
|
||||
METHOD_ADD(api::PruneUsers, "/v1/admin/prune_users", Post, "UserFilter<false, true>", "JsonFilter<true>"); //expects ["time"](int64) and ["amount"](uint32)
|
||||
METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
|
||||
|
||||
//User Managment
|
||||
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string)
|
||||
METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) ["amount"](uint32) ["pass"](string)
|
||||
METHOD_ADD(api::DelSelf, "/v1/user/delete", Delete, Options, "UserFilter<true, false>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::AdminDelUser, "/v1/admin/user/delete", Delete, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string)
|
||||
|
||||
METHOD_LIST_END
|
||||
};
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
#include "bank.hpp"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
#define req_args const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback
|
||||
#define JSON(V) callback(HttpResponse::newHttpJsonResponse(JsonReturn(V)));
|
||||
#define INLINE __attribute__((always_inline)) inline
|
||||
#define GEN_BODY \
|
||||
const auto temp_req = req->getJsonObject(); \
|
||||
const auto body = temp_req ? *temp_req : Json::Value();
|
||||
|
||||
template <typename T>
|
||||
INLINE Json::Value JsonReturn(T &&val)
|
||||
{
|
||||
Json::Value res;
|
||||
if constexpr (std::is_same_v<T, int_fast8_t>)
|
||||
{
|
||||
res["value"] = (int)val; //becuase of json lib interpreting 67 as 'A' for example
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, long>)
|
||||
{
|
||||
res["value"] = (Json::Int64)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
res["value"] = val;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
class BankF : public HttpController<BankF, false>
|
||||
{
|
||||
public:
|
||||
void Help(req_args) const
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
auto handlerInfo = app().getHandlersInfo();
|
||||
resp->setBody("<body> <h1>ALL FUNCTIONS (that have args) ARE EXPECTING JSON AS DATA TYPE</h1> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/close (POST)</h2> <p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p> <blockquote> <p>Closes and Saves the server.</p> </blockquote> <h2>/BankF/user (POST)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of the user being added (must be less then 50 characters)</p> <p><span style=\"background-color: #808080;\"> init_pass </span> - initial password for the user being added</p> <blockquote> <p>Adds a user to the bank</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (POST)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of the user being added</p> <p><span style=\"background-color: #808080;\"> attempt </span> - admin password required to add user with balance</p> <p><span style=\"background-color: #808080;\"> init_bal </span> - initial balance for user being added</p> <p><span style=\"background-color: #808080;\"> init_pass </span> - initial password for user being added</p> <blockquote> <p>Adds a user with initial balance</p> </blockquote> <h2>/BankF/sendfunds (POST)</h2> <p><span style=\"background-color: #808080;\"> a_name </span> - sender's name</p> <p><span style=\"background-color: #808080;\"> b_name </span> - reciever's name</p> <p><span style=\"background-color: #808080;\"> amount </span> - amount being sent</p> <p><span style=\"background-color: #808080;\"> attempt </span> - password of sender</p> <blockquote> <p>Sends money from one user to another</p> </blockquote> <h2>/BankF/changepass (PATCH)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of user's password being changes</p> <p><span style=\"background-color: #808080;\"> attempt </span> - password of user being changed</p> <p><span style=\"background-color: #808080;\"> new_pass </span> - new password to replace the current user's password</p> <blockquote> <p>Changes password of a user, returns -1 if user doesnt exist</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/{<span style=\"color: #339966;\">name</span>}/bal (PATCH)</h2> <p><span style=\"background-color: #808080;\"> name </span> - the name of the user being set</p> <p><span style=\"background-color: #808080;\"> attempt </span> - the admin password required</p> <p><span style=\"background-color: #808080;\"> amount </span> - the new balance of the user</p> <blockquote> <p>Sets the balance of a user</p> </blockquote> <h2>/BankF/help (GET)</h2> <blockquote> <p>the page you're looking at right now!</p> </blockquote> <h2>/BankF/vpass (POST)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of user being verified</p> <p><span style=\"background-color: #808080;\"> attempt </span> - password being verified</p> <blockquote> <p>returns 0 or 1 based on if [attempt] is equal to the password of the user [name], or -1 if user does not exist. The intended usage for this function is for connected services</p> </blockquote> <h2>/BankF/contains/{<span style=\"color: #339966;\">name</span>} (GET)</h2> <blockquote> <p>returns a 0 or 1 based on if the bank contains the user</p> </blockquote> <h2>/BankF/{<span style=\"color: #339966;\">name</span>}/bal (GET)</h2> <blockquote> <p>returns the balance of a given user's name, if -1 that means the user does not exist</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/vpass (POST)</h2><p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p> <blockquote> <p>Verifies if password entered is admin password</p> </blockquote> <h2>/BankF/{<span style=\"color: #339966;\">name</span>}/log (POST)</h2><p><span style=\"background-color: #808080;\"> attempt </span> - user password</p> <blockquote> <p>returns a list of last 100 transactions, -1 if user not found, 0 if invalid password</p> </blockquote><h2>/BankF/user (DELETE)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of user being deleted</p> <p><span style=\"background-color: #808080;\"> attempt </span> - password of user being deleted</p> <blockquote> <p>Deletes a user with the password of the user as verification</p> </blockquote> <h2>/BankF/<span style=\"color: #993300;\">admin</span>/user (DELETE)</h2> <p><span style=\"background-color: #808080;\"> name </span> - name of user being deleted</p> <p><span style=\"background-color: #808080;\"> attempt </span> - admin password</p> <blockquote> <p>Deletes a user with admin password as verification</p> </blockquote> </body>");
|
||||
resp->setExpiredTime(0);
|
||||
callback(resp);
|
||||
}
|
||||
void Close(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
bool res;
|
||||
if (body["attempt"].asCString() == bank.admin_pass)
|
||||
{
|
||||
bank.Save();
|
||||
|
||||
res = true;
|
||||
app().quit();
|
||||
}
|
||||
else
|
||||
{
|
||||
res = false;
|
||||
}
|
||||
JSON(res);
|
||||
}
|
||||
void AddUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.AddUser(body["name"].asCString(), body["init_pass"].asCString()));
|
||||
}
|
||||
void AdminAddUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.AdminAddUser(body["attempt"].asCString(), body["name"].asCString(), body["init_bal"].asUInt(), body["init_pass"].asCString()));
|
||||
}
|
||||
void DelUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.DelUser(body["name"].asCString(), body["attempt"].asCString()));
|
||||
}
|
||||
void AdminDelUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.AdminDelUser(body["name"].asCString(), body["attempt"].asCString()));
|
||||
}
|
||||
void SendFunds(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.SendFunds(body["a_name"].asCString(), body["b_name"].asCString(), body["amount"].asUInt(), body["attempt"].asCString()));
|
||||
}
|
||||
void ChangePassword(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.ChangePassword(body["name"].asCString(), body["attempt"].asCString(), body["new_pass"].asCString()));
|
||||
}
|
||||
void Contains(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.Contains(name));
|
||||
}
|
||||
void GetBal(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.GetBal(name));
|
||||
}
|
||||
void VerifyPassword(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.VerifyPassword(body["name"].asCString(), body["attempt"].asCString()));
|
||||
}
|
||||
void SetBal(req_args, const std::string &name) const
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.SetBal(name, body["attempt"].asCString(), body["amount"].asUInt()));
|
||||
}
|
||||
void AdminVerifyPass(req_args)
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.AdminVerifyPass(body["attempt"].asCString()));
|
||||
}
|
||||
void GetLog(req_args, const std::string &name)
|
||||
{
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
GEN_BODY
|
||||
JSON(bank.GetLogs(name, body["attempt"].asCString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto resp = HttpResponse::newHttpJsonResponse(JsonReturn("Logs are Disabled"));
|
||||
resp->setExpiredTime(0); //cached forever
|
||||
callback(resp);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD_LIST_BEGIN
|
||||
METHOD_ADD(BankF::Close, "/admin/close", Post, Options);
|
||||
METHOD_ADD(BankF::AddUser, "/user", Post, Options);
|
||||
METHOD_ADD(BankF::AdminAddUser, "/admin/user", Post, Options);
|
||||
METHOD_ADD(BankF::SendFunds, "/sendfunds", Post, Options);
|
||||
|
||||
METHOD_ADD(BankF::ChangePassword, "/changepass", Patch, Options);
|
||||
METHOD_ADD(BankF::SetBal, "/admin/{name}/bal", Patch, Options);
|
||||
|
||||
METHOD_ADD(BankF::Help, "/help", Get, Options);
|
||||
METHOD_ADD(BankF::VerifyPassword, "/vpass", Post, Options);
|
||||
METHOD_ADD(BankF::Contains, "/contains/{name}", Get, Options);
|
||||
METHOD_ADD(BankF::GetBal, "/{name}/bal", Get, Options);
|
||||
METHOD_ADD(BankF::AdminVerifyPass, "/admin/vpass", Post, Options);
|
||||
METHOD_ADD(BankF::GetLog, "/{name}/log", Post, Options);
|
||||
|
||||
METHOD_ADD(BankF::DelUser, "/user", Delete, Options);
|
||||
METHOD_ADD(BankF::AdminDelUser, "/admin/user", Delete, Options);
|
||||
METHOD_LIST_END
|
||||
};
|
||||
12
include/bank_resp.h
Normal file
12
include/bank_resp.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <../src/HttpResponseImpl.h>
|
||||
#include <../src/HttpAppFrameworkImpl.h>
|
||||
|
||||
using BankResponse = std::pair<drogon::HttpStatusCode, std::optional<std::string>>;
|
||||
|
||||
template <>
|
||||
drogon::HttpResponsePtr drogon::toResponse(BankResponse &&data);
|
||||
17
include/change_flag.h
Normal file
17
include/change_flag.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
template <bool init>
|
||||
class ChangeFlag
|
||||
{
|
||||
private:
|
||||
std::atomic<bool> change_flag = init; //if true changes have been made
|
||||
|
||||
public:
|
||||
ChangeFlag() noexcept;
|
||||
ChangeFlag(ChangeFlag &&) noexcept;
|
||||
|
||||
void SetChangesOn() noexcept;
|
||||
void SetChangesOff() noexcept;
|
||||
bool GetChangeState() const noexcept;
|
||||
};
|
||||
14
include/json_filter.h
Normal file
14
include/json_filter.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include "bank_resp.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
template <bool check_content_type>
|
||||
class JsonFilter : public HttpFilter<JsonFilter<check_content_type>>
|
||||
{
|
||||
public:
|
||||
virtual void doFilter(const HttpRequestPtr &,
|
||||
FilterCallback &&,
|
||||
FilterChainCallback &&) override;
|
||||
};
|
||||
31
include/log.h
Normal file
31
include/log.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include <deque>
|
||||
#include "ccash_config.hpp"
|
||||
#include "change_flag.h"
|
||||
#include "transaction.h"
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct Log
|
||||
{
|
||||
private:
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
ChangeFlag<true> log_flag;
|
||||
std::string log_snapshot = "null";
|
||||
#endif
|
||||
|
||||
ChangeFlag<true> log_flag_v2;
|
||||
std::string log_snapshot_v2 = "null";
|
||||
|
||||
public:
|
||||
std::deque<Transaction> data;
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
std::string GetLogs(const std::string& name) noexcept;
|
||||
#endif
|
||||
std::string GetLogsV2() noexcept;
|
||||
std::string GetLogsRange(size_t n, size_t m) noexcept;
|
||||
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include "log_consts.hpp"
|
||||
#include "transactions.hpp"
|
||||
|
||||
struct Log
|
||||
{
|
||||
std::vector<Transaction> data;
|
||||
void AddTrans(Transaction &&t)
|
||||
{
|
||||
if (data.size() == max_log_size) // If we hit the max size
|
||||
{
|
||||
for (uint32_t i = 1; i < data.size(); i++) // Make room at the back
|
||||
{
|
||||
std::cout << i << '\n';
|
||||
data[i - 1] = std::move(data[i]); // Shifts everything left
|
||||
}
|
||||
data[data.size() - 1] = std::move(t); // Place new in opened spot
|
||||
return;
|
||||
}
|
||||
else if (data.size() == data.capacity()) // If we haven't hit the max but hit capacity
|
||||
{
|
||||
data.reserve(data.capacity() + pre_log_size); // Reserve more memory
|
||||
}
|
||||
data.push_back(std::move(t)); // In either case we have space under max length, move to new spot
|
||||
}
|
||||
Json::Value Serialize() const
|
||||
{
|
||||
Json::Value res;
|
||||
for (uint32_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
res[i]["to"] = data[i].to;
|
||||
res[i]["from"] = data[i].from;
|
||||
res[i]["amount"] = (Json::UInt)data[i].amount;
|
||||
res[i]["time"] = (Json::UInt64)data[i].time;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// `max_log_size` must be divisible by `pre_log_size`
|
||||
constexpr unsigned max_log_size = 100; // Setting to 0 does not compile logging
|
||||
constexpr unsigned pre_log_size = 10;
|
||||
23863
include/simdjson.h
Normal file
23863
include/simdjson.h
Normal file
File diff suppressed because it is too large
Load diff
15
include/str_intrusion.h
Normal file
15
include/str_intrusion.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
The intended use of this cursed class is in violating the encapsulation of std::string this class acts like std::string_view even though its stored in a std::string.
|
||||
The reason this was needed is because sometimes we have a std::string_view instance and another library requires a const std::string& argument, forcing us to copy to a string before passing it, this copying is unnecessary.
|
||||
*/
|
||||
|
||||
struct StrFromSV_Wrapper
|
||||
{
|
||||
std::string str;
|
||||
StrFromSV_Wrapper() noexcept;
|
||||
StrFromSV_Wrapper(std::string_view sv) noexcept;
|
||||
~StrFromSV_Wrapper() noexcept;
|
||||
};
|
||||
15
include/transaction.h
Normal file
15
include/transaction.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
std::string counterparty = "";
|
||||
bool receiving = false;
|
||||
uint32_t amount = 0;
|
||||
time_t time = 0;
|
||||
|
||||
Transaction() noexcept;
|
||||
Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
|
||||
};
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
std::string from = "", to = "";
|
||||
uint32_t amount = 0;
|
||||
uint64_t time = 0;
|
||||
|
||||
Transaction() = default;
|
||||
Transaction(std::string from_str, std::string to_str, uint32_t amount, uint64_t time) : amount(amount), time(time)
|
||||
{
|
||||
from = std::move(from_str);
|
||||
to = std::move(to_str);
|
||||
}
|
||||
Transaction(std::string from_str, std::string to_str, uint32_t amount) : amount(amount)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
from = std::move(from_str);
|
||||
to = std::move(to_str);
|
||||
time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
};
|
||||
19
include/user.h
Normal file
19
include/user.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include "xxhash_str.h"
|
||||
#include "bank_dom_final_models.h"
|
||||
#include "log.h"
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32_t balance;
|
||||
XXH64_hash_t password;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
Log log;
|
||||
#endif
|
||||
|
||||
User(uint32_t init_bal, const std::string &init_pass) noexcept;
|
||||
User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept;
|
||||
User(const bank_dom::User &u) noexcept;
|
||||
|
||||
bank_dom::User Encode() const noexcept;
|
||||
};
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
#pragma once
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "log.hpp"
|
||||
|
||||
struct User
|
||||
{
|
||||
uint32_t balance = 0;
|
||||
uint64_t password;
|
||||
Log log;
|
||||
|
||||
/**
|
||||
* @brief User constructor
|
||||
*
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User(std::string &&init_pass) : password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for admins
|
||||
*
|
||||
* @param init_bal initial balance
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User(uint32_t init_bal, std::string &&init_pass) : balance(init_bal), password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for loading
|
||||
*
|
||||
* @param init_bal
|
||||
* @param init_pass
|
||||
*/
|
||||
User(uint32_t init_bal, uint64_t init_pass) : balance(init_bal), password(init_pass) {}
|
||||
User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j) : balance(init_bal), password(init_pass)
|
||||
{
|
||||
if (log_j.size())
|
||||
{
|
||||
log.data.reserve(std::min(pre_log_size * ((log_j.size() / pre_log_size) + 1), max_log_size));
|
||||
for (uint32_t i = (log_j.size() - max_log_size) * (log_j.size() > max_log_size); i < log_j.size(); i++)
|
||||
{
|
||||
log.data.push_back(std::move(Transaction(
|
||||
log_j[i]["from"].asCString(),
|
||||
log_j[i]["to"].asCString(),
|
||||
log_j[i]["amount"].asUInt(),
|
||||
log_j[i]["time"].asUInt64())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value Serialize() const
|
||||
{
|
||||
Json::Value res;
|
||||
res["balance"] = (Json::UInt)balance;
|
||||
res["password"] = (Json::UInt64)password;
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
res["log"] = log.Serialize();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
16
include/user_filter.h
Normal file
16
include/user_filter.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <libbase64.h>
|
||||
#include "str_intrusion.h"
|
||||
#include "bank.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
template <bool set_body_flag, bool require_admin>
|
||||
class UserFilter : public HttpFilter<UserFilter<set_body_flag, require_admin>>
|
||||
{
|
||||
public:
|
||||
virtual void doFilter(const HttpRequestPtr &,
|
||||
FilterCallback &&,
|
||||
FilterChainCallback &&) override;
|
||||
};
|
||||
|
|
@ -266,7 +266,7 @@ extern "C" {
|
|||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 8
|
||||
#define XXH_VERSION_RELEASE 0
|
||||
#define XXH_VERSION_RELEASE 1
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
|
||||
/*!
|
||||
|
|
@ -275,7 +275,7 @@ extern "C" {
|
|||
* This is only useful when xxHash is compiled as a shared library, as it is
|
||||
* independent of the version defined in the header.
|
||||
*
|
||||
* @return `XXH_VERSION_NUMBER` as of when the function was compiled.
|
||||
* @return `XXH_VERSION_NUMBER` as of when the libray was compiled.
|
||||
*/
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
|
@ -1920,7 +1920,7 @@ XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
|||
XXH_FORCE_INLINE xxh_u32
|
||||
XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
|
||||
{
|
||||
const xxh_u8* bEnd = input + len;
|
||||
const xxh_u8* bEnd = input ? input + len : NULL;
|
||||
xxh_u32 h32;
|
||||
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
|
|
@ -2348,7 +2348,7 @@ XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
|||
XXH_FORCE_INLINE xxh_u64
|
||||
XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
|
||||
{
|
||||
const xxh_u8* bEnd = input + len;
|
||||
const xxh_u8* bEnd = input ? input + len : NULL;
|
||||
xxh_u64 h64;
|
||||
|
||||
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||
|
|
@ -2546,7 +2546,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
|||
return XXH_readBE64(src);
|
||||
}
|
||||
|
||||
|
||||
#ifndef XXH_NO_XXH3
|
||||
|
||||
/* *********************************************************************
|
||||
* XXH3
|
||||
|
|
@ -3341,7 +3341,7 @@ XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_
|
|||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
XXH_ASSERT(secret != NULL);
|
||||
XXH_ASSERT(8 <= len && len <= 16);
|
||||
XXH_ASSERT(9 <= len && len <= 16);
|
||||
{ xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed;
|
||||
xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed;
|
||||
xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1;
|
||||
|
|
@ -5312,6 +5312,8 @@ XXH128_hashFromCanonical(const XXH128_canonical_t* src)
|
|||
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
|
||||
#endif /* XXH_NO_XXH3 */
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
9
include/xxhash_str.h
Normal file
9
include/xxhash_str.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "xxhash.h"
|
||||
|
||||
struct xxHashStringGen
|
||||
{
|
||||
XXH64_hash_t operator()(const std::string &str) const noexcept;
|
||||
XXH64_hash_t operator()(const std::string_view &str) const noexcept;
|
||||
};
|
||||
153
main.cpp
153
main.cpp
|
|
@ -1,83 +1,124 @@
|
|||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "bank_f.hpp"
|
||||
#include "bank_api.h"
|
||||
|
||||
//sig handling headers
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
//threads of cpu
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
void SaveSig(int s)
|
||||
{
|
||||
bank.Save();
|
||||
std::cout << "\nSaving on close...\n";
|
||||
std::cout << "\nSaving on close...\n"
|
||||
<< Bank::Save();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static_assert(pre_log_size <= max_log_size, "`max_log_size` must be larger than `pre_log_size`.");
|
||||
if constexpr (max_log_size && pre_log_size)
|
||||
{
|
||||
if (max_log_size % pre_log_size)
|
||||
static_assert(MAX_LOG_SIZE >= 0);
|
||||
if (argc == 1)
|
||||
{
|
||||
std::cerr << "`max_log_size` must be a multiple of `pre_log_size`.";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
std::cerr << "Usage: sudo ./bank <admin password> <saving frequency in minutes> <threads>\n";
|
||||
return 0;
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
std::cerr << "ERROR: CCash MUST be ran as root\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Loading users from users.json
|
||||
bank.Load();
|
||||
|
||||
//Sig handling
|
||||
struct sigaction sigIntHandler;
|
||||
|
||||
sigIntHandler.sa_handler = SaveSig;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
||||
|
||||
//Admin Password
|
||||
bank.admin_pass = argv[1];
|
||||
|
||||
//Auto Saving
|
||||
const unsigned long saving_freq = std::stoul(argv[2]);
|
||||
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
|
||||
{
|
||||
std::thread([saving_freq]() {
|
||||
while (1)
|
||||
std::ofstream users_save(users_location, std::ios::out | std::ios::binary);
|
||||
if (users_save.is_open())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
bank.Save();
|
||||
std::cout << "Saving " << duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() << '\n';
|
||||
uint8_t temp[16]{16, 0, 0, 0, 4};
|
||||
users_save.write((char *)temp, 16);
|
||||
users_save.close();
|
||||
std::cout << "User save file generated\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
|
||||
return 0;
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "File cannot be created (may already exist)\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (argc < 3)
|
||||
{
|
||||
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
|
||||
return -1;
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
std::cerr << "ERROR: CCash MUST be ran as root\n";
|
||||
return -1;
|
||||
}
|
||||
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
|
||||
std::cout
|
||||
<< "\nAPI : v2.6.1\n"
|
||||
<< "\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
|
||||
<< "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.1 : " << (__builtin_cpu_supports("sse4.1") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.2 : " << (__builtin_cpu_supports("sse4.2") ? "enabled" : "disabled")
|
||||
#if MULTI_THREADED
|
||||
<< "\n\nThreads : " << get_nprocs() + saving_freq
|
||||
<< "\nMulti threading : enabled";
|
||||
#else
|
||||
<< "\n\nThreads : " << 1 + saving_freq
|
||||
<< "\nMulti threading : disabled";
|
||||
#endif
|
||||
|
||||
auto API = std::make_shared<BankF>();
|
||||
app().registerPostHandlingAdvice(
|
||||
[](const drogon::HttpRequestPtr &req, const drogon::HttpResponsePtr &resp) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", "*");
|
||||
});
|
||||
app().loadConfigFile("../config.json").registerController(API).setThreadNum(std::stoul(argv[3])).run();
|
||||
//Loading users from users.dat
|
||||
Bank::Load();
|
||||
size_t num_of_logs = Bank::NumOfLogs();
|
||||
size_t num_of_users = Bank::NumOfUsers();
|
||||
std::cout << "\n\nLoaded " << num_of_users << " Users ~" << (float)(sizeof(User) * num_of_users) / 1048576 << "MB"
|
||||
<< "\nLoaded " << num_of_logs << " Logs ~" << (float)(num_of_logs * (75 + sizeof(Transaction) + max_name_size)) / 1048576 << "MB" //75:cached response per log(heap), sizeof(Transaction), max_name_size:counterparty(heap)
|
||||
<< "\nLoaded " << Bank::SumBal() << " C$H"
|
||||
<< std::endl; //flushing before EventLoop
|
||||
|
||||
//Sig handling
|
||||
struct sigaction sigIntHandler;
|
||||
sigIntHandler.sa_handler = SaveSig;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
||||
|
||||
//Admin account
|
||||
Bank::admin_account = argv[1];
|
||||
|
||||
//Auto Saving
|
||||
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
|
||||
{
|
||||
std::thread([saving_freq]()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
std::cout << "Saving " << std::time(0) << "...\n" << Bank::Save();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
if (argc == 4 && !strcmp(argv[3], "true")) { app().enableRunAsDaemon(); }
|
||||
else if (argc == 4 && strcmp(argv[3], "false"))
|
||||
{
|
||||
std::cerr << "daemon flag must be \"true\" or \"false\"\n";
|
||||
return -1;
|
||||
}
|
||||
} //destroying setup variables
|
||||
|
||||
app()
|
||||
.loadConfigFile(config_location)
|
||||
#if MULTI_THREADED
|
||||
.setThreadNum(get_nprocs())
|
||||
#endif
|
||||
.run();
|
||||
|
||||
SaveSig(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
433
src/bank.cpp
Normal file
433
src/bank.cpp
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
#include "bank.h"
|
||||
|
||||
#if MULTI_THREADED
|
||||
phmap::parallel_flat_hash_map<
|
||||
std::string, User,
|
||||
xxHashStringGen,
|
||||
phmap::priv::hash_default_eq<std::string>,
|
||||
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
|
||||
4UL,
|
||||
std::mutex>
|
||||
Bank::users;
|
||||
#else
|
||||
phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> Bank::users;
|
||||
#endif
|
||||
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
ChangeFlag<false> Bank::save_flag;
|
||||
#endif
|
||||
|
||||
std::shared_mutex Bank::iter_lock;
|
||||
std::string Bank::admin_account;
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
#define SET_CHANGES_ON save_flag.SetChangesOn()
|
||||
#else
|
||||
#define SET_CHANGES_ON
|
||||
#endif
|
||||
|
||||
inline bool ValidUsername(const std::string &name) noexcept
|
||||
{
|
||||
if (name.size() < min_name_size || name.size() > max_name_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::NumOfUsers() noexcept { return Bank::users.size(); }
|
||||
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::NumOfLogs() noexcept
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
size_t res = 0;
|
||||
for (const auto &u : users)
|
||||
{
|
||||
res += u.second.log.data.size();
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//NOT THREAD SAFE
|
||||
size_t Bank::SumBal() noexcept
|
||||
{
|
||||
size_t res = 0;
|
||||
for (const auto &u : users)
|
||||
{
|
||||
res += u.second.balance;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
BankResponse Bank::GetBal(const std::string &name) noexcept
|
||||
{
|
||||
uint32_t res = 0;
|
||||
if (!ValidUsername(name) || !Bank::users.if_contains(name, [&res](const User &u) { res = u.balance; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k200OK, std::to_string(res)};
|
||||
}
|
||||
}
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
BankResponse Bank::GetLogs(const std::string &name) noexcept
|
||||
{
|
||||
BankResponse res;
|
||||
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BankResponse Bank::GetLogsV2(const std::string &name) noexcept
|
||||
{
|
||||
BankResponse res;
|
||||
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogsV2()}; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
BankResponse Bank::GetLogsRange(const std::string &name, size_t start, size_t length) noexcept
|
||||
{
|
||||
BankResponse res;
|
||||
if (start >= MAX_LOG_SIZE)
|
||||
{
|
||||
return {k400BadRequest, "\"Invalid {start} index\""};
|
||||
}
|
||||
if (!length)
|
||||
{
|
||||
return {k400BadRequest, "\"Invalid {length}\""};
|
||||
}
|
||||
|
||||
if (!Bank::users.modify_if(name, [&name, &res, start, length](User &u) { res = {k200OK, u.log.GetLogsRange(start, length)}; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept
|
||||
{
|
||||
if (!amount)
|
||||
{
|
||||
return {k400BadRequest, "\"Amount cannot be 0\""};
|
||||
}
|
||||
if (a_name == b_name)
|
||||
{
|
||||
return {k400BadRequest, "\"Names cannot match\""};
|
||||
}
|
||||
if (!Contains(b_name))
|
||||
{
|
||||
return {k404NotFound, "\"Reciever does not exist\""};
|
||||
}
|
||||
|
||||
BankResponse res;
|
||||
std::shared_lock<std::shared_mutex> lock{iter_lock};
|
||||
#if MAX_LOG_SIZE > 0
|
||||
time_t current_time = time(NULL);
|
||||
if (!Bank::users.modify_if(a_name, [current_time, &a_name, &b_name, &res, amount](User &a)
|
||||
#else
|
||||
if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a)
|
||||
#endif
|
||||
{
|
||||
//if "A" can afford it
|
||||
if (a.balance < amount)
|
||||
{
|
||||
res = {k400BadRequest, "\"Insufficient funds\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
a.log.AddTrans(b_name, false, amount, current_time);
|
||||
#endif
|
||||
res = {k200OK, std::to_string(a.balance)};
|
||||
}
|
||||
}))
|
||||
{
|
||||
return {k404NotFound, "\"Sender does not exist\""};
|
||||
}
|
||||
if (res.first == k200OK)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
|
||||
b.balance += amount;
|
||||
b.log.AddTrans(a_name, true, amount, current_time);
|
||||
});
|
||||
#else
|
||||
Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; });
|
||||
#endif
|
||||
SET_CHANGES_ON;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
bool Bank::VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept
|
||||
{
|
||||
bool res = false;
|
||||
Bank::users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); });
|
||||
return res;
|
||||
}
|
||||
void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); });
|
||||
}
|
||||
BankResponse Bank::SetBal(const std::string &name, int64_t amount) noexcept
|
||||
{
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) {
|
||||
amount -= u.balance;
|
||||
u.balance += amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
|
||||
#endif
|
||||
}))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k204NoContent, std::nullopt}; //returns new balance
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept
|
||||
{
|
||||
if (amount == 0)
|
||||
{
|
||||
return {k400BadRequest, "\"Amount cannot be 0\""};
|
||||
}
|
||||
uint32_t bal;
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, &amount](User &u) {
|
||||
if (u.balance < (amount * -1)) { amount = -int64_t(u.balance); };
|
||||
bal = u.balance += amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
|
||||
#endif
|
||||
}))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k200OK, std::to_string(bal)}; //may return new balance
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
bool Bank::Contains(const std::string &name) noexcept
|
||||
{
|
||||
return ValidUsername(name) && Bank::users.contains(name);
|
||||
}
|
||||
#if MAX_LOG_SIZE > 0
|
||||
BankResponse Bank::PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept
|
||||
#else
|
||||
BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept
|
||||
#endif
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock{iter_lock};
|
||||
size_t deleted_count = 0;
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal = 0;
|
||||
#endif
|
||||
for (const auto &u : users)
|
||||
{
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if RETURN_ON_DEL
|
||||
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) {
|
||||
bal += u.balance;
|
||||
#else
|
||||
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) {
|
||||
#endif
|
||||
|
||||
return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal);
|
||||
#else
|
||||
|
||||
#if RETURN_ON_DEL
|
||||
if (Bank::users.erase_if(u.first, [threshold_bal, &bal, &deleted_count](User &u) {
|
||||
bal += u.balance;
|
||||
#else
|
||||
if (Bank::users.erase_if(u.first, [threshold_bal, &deleted_count](User &u) {
|
||||
#endif
|
||||
|
||||
return (u.balance < threshold_bal);
|
||||
#endif
|
||||
}))
|
||||
{
|
||||
|
||||
SET_CHANGES_ON;
|
||||
++deleted_count;
|
||||
}
|
||||
}
|
||||
#if RETURN_ON_DEL
|
||||
if (bal)
|
||||
{
|
||||
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
|
||||
}
|
||||
#endif
|
||||
return {k200OK, std::to_string(deleted_count)};
|
||||
}
|
||||
|
||||
BankResponse Bank::AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept
|
||||
{
|
||||
if (!ValidUsername(name))
|
||||
{
|
||||
return {k400BadRequest, "\"Invalid Username\""};
|
||||
}
|
||||
std::shared_lock<std::shared_mutex> lock{iter_lock};
|
||||
if (Bank::users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, init_pass))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k409Conflict, "\"User already exists\""};
|
||||
}
|
||||
}
|
||||
BankResponse Bank::DelUser(const std::string &name) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{iter_lock};
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (Bank::users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) &&
|
||||
bal)
|
||||
{
|
||||
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
|
||||
}
|
||||
#endif
|
||||
if (ValidUsername(name) && Bank::users.erase(name))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
//assumes we know name exists, unlike DelUser
|
||||
void Bank::DelSelf(const std::string &name) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{iter_lock};
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (Bank::users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) &&
|
||||
bal)
|
||||
{
|
||||
Bank::users.modify_if(return_account, [bal](User &u) { u.balance += bal; });
|
||||
}
|
||||
#endif
|
||||
SET_CHANGES_ON;
|
||||
Bank::users.erase(name);
|
||||
}
|
||||
//ONLY EVER BEING CALLED BY SAVE THREAD OR C-INTERUPT
|
||||
const char *Bank::Save()
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
if (save_flag.GetChangeState())
|
||||
{
|
||||
#endif
|
||||
std::ofstream users_save(users_location, std::ios::out | std::ios::binary);
|
||||
if (!users_save.is_open())
|
||||
{
|
||||
throw std::invalid_argument("Cannot access saving file\n");
|
||||
}
|
||||
bank_dom::Global users_copy;
|
||||
users_copy.users.reserve(Bank::users.size());
|
||||
users_copy.keys.reserve(Bank::users.size());
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock{iter_lock};
|
||||
for (const auto &u : users)
|
||||
{
|
||||
Bank::users.if_contains(u.first, [&users_copy, &u](const User &u_val) {
|
||||
users_copy.users.emplace_back(u_val.Encode());
|
||||
users_copy.keys.emplace_back(u.first);
|
||||
});
|
||||
}
|
||||
}
|
||||
FBE::bank_dom::GlobalFinalModel writer;
|
||||
writer.serialize(users_copy);
|
||||
assert(writer.verify() && "Data is corrupted!");
|
||||
const FBE::FBEBuffer &write_buffer = writer.buffer();
|
||||
users_save.write((char *)write_buffer.data(), write_buffer.size());
|
||||
users_save.close();
|
||||
if (!users_save.good())
|
||||
{
|
||||
throw std::invalid_argument("Error occurred at writing to save file\n");
|
||||
}
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
save_flag.SetChangesOff();
|
||||
return " to disk...\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
return " no changes...\n";
|
||||
}
|
||||
#else
|
||||
return " to disk...\n";
|
||||
#endif
|
||||
}
|
||||
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
|
||||
void Bank::Load()
|
||||
{
|
||||
std::ifstream users_load(users_location, std::ios::out | std::ios::binary);
|
||||
if (!users_load.is_open())
|
||||
{
|
||||
throw std::invalid_argument("Cannot find save file, to generate a new one run \"sudo ./bank\" (warning: will override file if it already exists)\n");
|
||||
}
|
||||
|
||||
uint32_t buffer_size;
|
||||
users_load.read((char *)&buffer_size, 4); //reading first 32 bits for size
|
||||
FBE::bank_dom::GlobalFinalModel reader; //declaring model
|
||||
reader.resize(buffer_size); //allocating new memory
|
||||
users_load.read((char *)reader.buffer().data() + 4, buffer_size - 4); //reading rest of file
|
||||
memcpy((char *)reader.buffer().data(), &buffer_size, 4); //copying first 32 bits back
|
||||
|
||||
if (!reader.verify())
|
||||
{
|
||||
throw std::invalid_argument("Data is corrupted\n");
|
||||
}
|
||||
bank_dom::Global users_global;
|
||||
reader.deserialize(users_global);
|
||||
|
||||
for (size_t i = 0; i < users_global.users.size(); ++i)
|
||||
{
|
||||
Bank::users.try_emplace(users_global.keys[i], users_global.users[i]);
|
||||
}
|
||||
}
|
||||
373
src/bank_api.cpp
Normal file
373
src/bank_api.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
#include "bank_api.h"
|
||||
|
||||
#define CACHE_FOREVER resp->setExpiredTime(0)
|
||||
|
||||
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
|
||||
|
||||
thread_local ondemand::parser parser;
|
||||
#define SIMD_JSON_GEN \
|
||||
simdjson::padded_string input(req->getBody()); \
|
||||
ondemand::document doc;
|
||||
|
||||
#define RESPONSE_PARSE(R) \
|
||||
auto resp = HttpResponse::newCustomHttpResponse(R); \
|
||||
CORS; \
|
||||
callback(resp)
|
||||
|
||||
#define RESPOND_TRUE \
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k204NoContent, std::nullopt}); \
|
||||
CORS; \
|
||||
CACHE_FOREVER; \
|
||||
callback(resp)
|
||||
|
||||
#define NAME_PARAM req->getParameter("name")
|
||||
|
||||
//Usage
|
||||
void api::GetBal(req_args, const std::string &name)
|
||||
{
|
||||
RESPONSE_PARSE(Bank::GetBal(name));
|
||||
}
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
void api::GetLogs(req_args)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
RESPONSE_PARSE(Bank::GetLogs(NAME_PARAM));
|
||||
#else
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void api::GetLogsV2(req_args)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
RESPONSE_PARSE(Bank::GetLogsV2(NAME_PARAM));
|
||||
#else
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void api::GetLogsRange(req_args, size_t start, size_t length)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
RESPONSE_PARSE(Bank::GetLogsRange(NAME_PARAM, start, length));
|
||||
#else
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void api::AdminGetLogs(req_args, const std::string& name)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
RESPONSE_PARSE(Bank::GetLogsV2(name));
|
||||
#else
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void api::SendFunds(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name;
|
||||
uint64_t amount; // as simdjson lacks .get(uint32_t support)
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::SendFunds(NAME_PARAM, name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::VerifyPassword(req_args) { RESPOND_TRUE; }
|
||||
|
||||
//Meta Usage
|
||||
void api::ChangePassword(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view pass;
|
||||
if (doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
Bank::ChangePassword(NAME_PARAM, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::AdminChangePassword(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name, pass;
|
||||
if (doc["name"].get(name) || doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
if (Bank::Contains(name_val.str))
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
Bank::ChangePassword(name_val.str, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = BankResponse{k404NotFound, "\"User not found\""};
|
||||
}
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::SetBal(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name;
|
||||
uint64_t amount;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::SetBal(name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::ImpactBal(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name;
|
||||
int64_t amount;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::ImpactBal(name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
|
||||
//System Usage
|
||||
void api::Help(req_args)
|
||||
{
|
||||
auto resp = HttpResponse::newRedirectionResponse("https://github.com/EntireTwix/CCash/blob/main/README.md", k301MovedPermanently);
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
void api::Close(req_args)
|
||||
{
|
||||
Bank::Save();
|
||||
RESPOND_TRUE; //filter handles admin creds
|
||||
app().quit();
|
||||
}
|
||||
void api::Contains(req_args, const std::string &name)
|
||||
{
|
||||
BankResponse res;
|
||||
if (Bank::Contains(name))
|
||||
{
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = BankResponse{k404NotFound, "\"User not found\""};
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::AdminVerifyAccount(req_args)
|
||||
{
|
||||
RESPOND_TRUE; //filter handles admin creds
|
||||
}
|
||||
void api::ApiProperties(req_args)
|
||||
{
|
||||
std::string info = "{\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"add_user_open\":" + (ADD_USER_OPEN?"true":"false") + ",\"return_on_del\":" + (RETURN_ON_DEL?'\"' + std::string(return_account) + "\"":"null") + '}';
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
void api::PruneUsers(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
int64_t time;
|
||||
if (doc["time"].get(time) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Bank::PruneUsers(time, amount);
|
||||
}
|
||||
#else
|
||||
if (doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Bank::PruneUsers(amount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
|
||||
void api::AddUser(req_args)
|
||||
{
|
||||
if constexpr (ADD_USER_OPEN)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name, pass;
|
||||
if (doc["name"].get(name) || doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
res = Bank::AddUser(name_val.str, 0, pass_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"AddUser is Disabled\""});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
callback(resp);
|
||||
}
|
||||
}
|
||||
void api::AdminAddUser(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name;
|
||||
uint64_t amount;
|
||||
std::string_view pass;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || doc["pass"].get(pass) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
res = Bank::AddUser(name_val.str, amount, pass_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
void api::DelSelf(req_args)
|
||||
{
|
||||
Bank::DelSelf(NAME_PARAM);
|
||||
RESPOND_TRUE;
|
||||
}
|
||||
void api::AdminDelUser(req_args)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view name;
|
||||
if (doc["name"].get(name))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::DelUser(name_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
26
src/bank_resp.cpp
Normal file
26
src/bank_resp.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "bank_resp.h"
|
||||
|
||||
template <>
|
||||
drogon::HttpResponsePtr drogon::toResponse(BankResponse &&data)
|
||||
{
|
||||
std::shared_ptr<HttpResponseImpl> res;
|
||||
if (data.second)
|
||||
{
|
||||
res = std::make_shared<HttpResponseImpl>(data.first, CT_APPLICATION_JSON);
|
||||
res->setBody(std::move(*data.second));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = std::make_shared<HttpResponseImpl>();
|
||||
res->setStatusCode(data.first);
|
||||
}
|
||||
const auto &advices = HttpAppFrameworkImpl::instance().getResponseCreationAdvices();
|
||||
if (!advices.empty())
|
||||
{
|
||||
for (auto &advice : advices)
|
||||
{
|
||||
advice(res);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
28
src/change_flag.cpp
Normal file
28
src/change_flag.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include "change_flag.h"
|
||||
|
||||
template <bool init>
|
||||
ChangeFlag<init>::ChangeFlag() noexcept {}
|
||||
template <bool init>
|
||||
ChangeFlag<init>::ChangeFlag(ChangeFlag &&f) noexcept
|
||||
{
|
||||
change_flag.store(f.GetChangeState(), std::memory_order_release);
|
||||
}
|
||||
|
||||
template <bool init>
|
||||
void ChangeFlag<init>::SetChangesOn() noexcept
|
||||
{
|
||||
return change_flag.store(1, std::memory_order_release);
|
||||
}
|
||||
template <bool init>
|
||||
void ChangeFlag<init>::SetChangesOff() noexcept
|
||||
{
|
||||
return change_flag.store(0, std::memory_order_release);
|
||||
}
|
||||
template <bool init>
|
||||
bool ChangeFlag<init>::GetChangeState() const noexcept
|
||||
{
|
||||
return change_flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
template class ChangeFlag<true>;
|
||||
template class ChangeFlag<false>;
|
||||
38
src/json_filter.cpp
Normal file
38
src/json_filter.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#include "json_filter.h"
|
||||
|
||||
inline bool Contains(std::string_view str, const std::string &val)
|
||||
{
|
||||
return str.find(val) != std::string::npos;
|
||||
}
|
||||
|
||||
template <bool check_content_type>
|
||||
void JsonFilter<check_content_type>::doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb)
|
||||
{
|
||||
std::string_view accept_header = req->getHeader("Accept");
|
||||
if constexpr (check_content_type)
|
||||
{
|
||||
std::string_view content_type = req->getHeader("content-type");
|
||||
if (content_type == "application/json" && (Contains(accept_header, "*/*") || Contains(accept_header, "application/json")))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
const auto &resp = HttpResponse::newCustomHttpResponse(BankResponse{k406NotAcceptable, "\"Client must Accept and have content-type of JSON\""});
|
||||
fcb(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Contains(accept_header, "*/*") || Contains(accept_header, "application/json")))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
const auto &resp = HttpResponse::newCustomHttpResponse(BankResponse{k406NotAcceptable, "\"Client must Accept JSON\""});
|
||||
fcb(resp);
|
||||
}
|
||||
}
|
||||
|
||||
template class JsonFilter<true>;
|
||||
template class JsonFilter<false>;
|
||||
168
src/log.cpp
Normal file
168
src/log.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include "log.h"
|
||||
|
||||
void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept
|
||||
{
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
log_flag.SetChangesOn();
|
||||
#endif
|
||||
log_flag_v2.SetChangesOn();
|
||||
|
||||
if (data.size() == MAX_LOG_SIZE)
|
||||
{
|
||||
data.pop_front();
|
||||
}
|
||||
data.emplace_back(counterparty_str, receiving, amount, time);
|
||||
}
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
std::string Log::GetLogs(const std::string& name) noexcept
|
||||
{
|
||||
if (log_flag.GetChangeState() && data.size()) // if there are changes
|
||||
{
|
||||
log_snapshot.resize(0);
|
||||
//re-generate snapshot
|
||||
size_t predicted_size = ((57 + (2 * max_name_size)) * data.size()) + 1;
|
||||
if (log_snapshot.capacity() < predicted_size)
|
||||
{
|
||||
log_snapshot.reserve(predicted_size);
|
||||
}
|
||||
log_snapshot = '['; //1
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
log_snapshot += "{\"to\":\""; //7
|
||||
log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
|
||||
log_snapshot += "\",\"from\":\""; //10
|
||||
log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
|
||||
log_snapshot += "\",\"amount\":"; //11
|
||||
log_snapshot += std::to_string(data[i].amount); //10?
|
||||
log_snapshot += ",\"time\":"; //8
|
||||
log_snapshot += std::to_string(data[i].time); //10?
|
||||
log_snapshot += "},"; //2
|
||||
}
|
||||
log_snapshot.back() = ']';
|
||||
log_flag.SetChangesOff();
|
||||
}
|
||||
|
||||
return log_snapshot;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string Log::GetLogsV2() noexcept
|
||||
{
|
||||
if (log_flag_v2.GetChangeState() && data.size()) // if there are changes
|
||||
{
|
||||
log_snapshot_v2.resize(0);
|
||||
//re-generate snapshot
|
||||
size_t predicted_size = ((59 + max_name_size) * data.size()) + 1;
|
||||
if (log_snapshot_v2.capacity() < predicted_size)
|
||||
{
|
||||
log_snapshot_v2.reserve(predicted_size);
|
||||
}
|
||||
log_snapshot_v2 = '['; //1
|
||||
for (size_t i = data.size(); i --> 0;)
|
||||
{
|
||||
log_snapshot_v2 += "{\"counterparty\":\""; //17
|
||||
log_snapshot_v2 += data[i].counterparty; //max_name_size?
|
||||
log_snapshot_v2 += "\",\"amount\":"; //11
|
||||
if (!data[i].receiving) { log_snapshot_v2 += '-'; } //1
|
||||
log_snapshot_v2 += std::to_string(data[i].amount); //10?
|
||||
log_snapshot_v2 += ",\"time\":"; //8
|
||||
log_snapshot_v2 += std::to_string(data[i].time); //10?
|
||||
log_snapshot_v2 += "},"; //2
|
||||
}
|
||||
log_snapshot_v2.back() = ']';
|
||||
log_flag_v2.SetChangesOff();
|
||||
}
|
||||
|
||||
return log_snapshot_v2;
|
||||
}
|
||||
|
||||
std::string Log::GetLogsRange(size_t start, size_t length) noexcept
|
||||
{
|
||||
if (start >= data.size()) { return "[]"; }
|
||||
if (start == 0 && length == MAX_LOG_SIZE) { return log_snapshot_v2; }
|
||||
if (log_flag_v2.GetChangeState() && data.size()) { GetLogsV2(); }
|
||||
|
||||
size_t log_index_n, i;
|
||||
if (start < (0.5 * MAX_LOG_SIZE))
|
||||
{
|
||||
// std::cout << "a\n";
|
||||
i = 0;
|
||||
log_index_n = 0;
|
||||
while(i < log_snapshot_v2.size())
|
||||
{
|
||||
if (log_index_n == start)
|
||||
{
|
||||
log_index_n = i;
|
||||
break;
|
||||
}
|
||||
i += (41 + min_name_size);
|
||||
while (log_snapshot_v2[i] != ',') { ++i; }
|
||||
++log_index_n;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "b\n";
|
||||
i = log_snapshot_v2.size();
|
||||
log_index_n = data.size();
|
||||
while(i --> 0)
|
||||
{
|
||||
if (log_index_n == start)
|
||||
{
|
||||
log_index_n = i + 1;
|
||||
break;
|
||||
}
|
||||
i -= (41 + min_name_size);
|
||||
while (log_snapshot_v2[i] != ',') { --i; }
|
||||
--log_index_n;
|
||||
}
|
||||
}
|
||||
|
||||
size_t log_index_m = std::string::npos;
|
||||
if ((start + length) < data.size())
|
||||
{
|
||||
if (length < (0.5 * MAX_LOG_SIZE))
|
||||
{
|
||||
// std::cout << "c\n";
|
||||
log_index_m = 0;
|
||||
while(i < log_snapshot_v2.size())
|
||||
{
|
||||
if (log_index_m == length)
|
||||
{
|
||||
log_index_m = i + 1;
|
||||
break;
|
||||
}
|
||||
i += (41 + min_name_size);
|
||||
while (log_snapshot_v2[i] != ',') { ++i; }
|
||||
++log_index_m;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "d\n";
|
||||
i = log_snapshot_v2.size();
|
||||
log_index_m = data.size();
|
||||
while(i --> 0)
|
||||
{
|
||||
if (log_index_m == length)
|
||||
{
|
||||
log_index_m = i + 1;
|
||||
break;
|
||||
}
|
||||
i -= (41 + min_name_size);
|
||||
while (log_snapshot_v2[i] != ',') { --i; }
|
||||
--log_index_m;
|
||||
}
|
||||
}
|
||||
|
||||
log_index_m -= log_index_n;
|
||||
}
|
||||
|
||||
std::string res(log_snapshot_v2.substr(log_index_n, log_index_m));
|
||||
res[0] = '[';
|
||||
res[res.size() - 1] = ']';
|
||||
// std::cout << res << '\n';
|
||||
|
||||
return res;
|
||||
}
|
||||
12032
src/simdjson.cpp
Normal file
12032
src/simdjson.cpp
Normal file
File diff suppressed because it is too large
Load diff
45
src/str_intrusion.cpp
Normal file
45
src/str_intrusion.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "str_intrusion.h"
|
||||
|
||||
//this function is horribly jank
|
||||
template <typename Tag>
|
||||
struct result
|
||||
{
|
||||
typedef typename Tag::type type;
|
||||
static type ptr;
|
||||
};
|
||||
template <typename Tag>
|
||||
typename result<Tag>::type result<Tag>::ptr;
|
||||
|
||||
template <typename Tag, typename Tag::type p>
|
||||
struct rob : result<Tag>
|
||||
{
|
||||
struct filler
|
||||
{
|
||||
filler() { result<Tag>::ptr = p; }
|
||||
};
|
||||
static filler filler_obj;
|
||||
};
|
||||
template <typename Tag, typename Tag::type p>
|
||||
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
|
||||
struct string_length
|
||||
{
|
||||
typedef void (std::string::*type)(size_t);
|
||||
};
|
||||
template class rob<string_length, &std::string::_M_length>;
|
||||
struct string_data
|
||||
{
|
||||
typedef void (std::string::*type)(char *);
|
||||
};
|
||||
template class rob<string_data, &std::string::_M_data>;
|
||||
|
||||
StrFromSV_Wrapper::StrFromSV_Wrapper() noexcept {}
|
||||
StrFromSV_Wrapper::StrFromSV_Wrapper(std::string_view sv) noexcept
|
||||
{
|
||||
(str.*result<string_data>::ptr)((char *)sv.data());
|
||||
(str.*result<string_length>::ptr)(sv.size());
|
||||
}
|
||||
StrFromSV_Wrapper::~StrFromSV_Wrapper() noexcept
|
||||
{
|
||||
(str.*result<string_data>::ptr)(nullptr);
|
||||
(str.*result<string_length>::ptr)(0);
|
||||
}
|
||||
4
src/transaction.cpp
Normal file
4
src/transaction.cpp
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#include "transaction.h"
|
||||
|
||||
Transaction::Transaction() noexcept {};
|
||||
Transaction::Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {}
|
||||
57
src/user.cpp
Normal file
57
src/user.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include "user.h"
|
||||
|
||||
/**
|
||||
* @brief User Constructor for admins
|
||||
*
|
||||
* @param init_bal initial balance
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User::User(uint32_t init_bal, const std::string &init_pass) noexcept : balance(init_bal), password(xxHashStringGen{}(init_pass)) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for loading
|
||||
*
|
||||
* @param init_bal
|
||||
* @param init_pass
|
||||
*/
|
||||
User::User(uint32_t init_bal, XXH64_hash_t init_pass) noexcept : balance(init_bal), password(init_pass) {}
|
||||
|
||||
User::User(const bank_dom::User &u) noexcept : balance(u.balance), password(u.password)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
if (u.logs)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
if (MAX_LOG_SIZE < u.logs.value().data.size())
|
||||
{
|
||||
i = (u.logs.value().data.size() - MAX_LOG_SIZE);
|
||||
}
|
||||
for (; i < u.logs.value().data.size(); ++i)
|
||||
{
|
||||
const bank_dom::Transaction &temp = u.logs.value().data[i];
|
||||
log.data.emplace_front(temp.counterparty, temp.receiving, temp.amount, temp.time);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bank_dom::User User::Encode() const noexcept
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
if (this->log.data.size())
|
||||
{
|
||||
bank_dom::Logs save_log;
|
||||
save_log.data.reserve(this->log.data.size());
|
||||
for (const Transaction &t : this->log.data)
|
||||
{
|
||||
save_log.data.emplace_back(t.counterparty, t.receiving, t.amount, t.time);
|
||||
}
|
||||
return bank_dom::User(balance, password, save_log);
|
||||
}
|
||||
else
|
||||
{
|
||||
return bank_dom::User(balance, password, std::nullopt);
|
||||
}
|
||||
#else
|
||||
return bank_dom::User(balance, password, std::nullopt);
|
||||
#endif
|
||||
}
|
||||
75
src/user_filter.cpp
Normal file
75
src/user_filter.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#include "user_filter.h"
|
||||
|
||||
inline bool ValidUsername(const std::string &name) noexcept
|
||||
{
|
||||
if (name.size() < min_name_size || name.size() > max_name_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool set_body_flag, bool require_admin>
|
||||
void UserFilter<set_body_flag, require_admin>::doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb)
|
||||
{
|
||||
std::string_view auth_header = req->getHeader("Authorization");
|
||||
if (auth_header.size() > 6 && auth_header.size() <= ((max_name_size + 256) * 4) / 3) //"Basic " + (username + ':' + password) * 4/3
|
||||
{
|
||||
if (auth_header.substr(0, 6) == "Basic ")
|
||||
{
|
||||
std::string_view input = auth_header.substr(6);
|
||||
char result_buffer[max_name_size + 256]; //(username + ':' + 255 password)
|
||||
size_t new_sz;
|
||||
base64_decode(input.data(), input.size(), result_buffer, &new_sz, 0);
|
||||
|
||||
std::string_view results_view(result_buffer, new_sz);
|
||||
std::size_t middle = results_view.find(':');
|
||||
if (middle != std::string::npos && ((new_sz - middle) <= 256))
|
||||
{
|
||||
StrFromSV_Wrapper username(results_view.substr(0, middle));
|
||||
if (ValidUsername(username.str)) //check if username is a valid attempt to avoid hashing/grabbing shared lock
|
||||
{
|
||||
if constexpr (require_admin)
|
||||
{
|
||||
if (Bank::admin_account == username.str)
|
||||
{
|
||||
StrFromSV_Wrapper password(results_view.substr(middle + 1));
|
||||
if (Bank::VerifyPassword(username.str, password.str))
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper password(results_view.substr(middle + 1));
|
||||
if (Bank::VerifyPassword(username.str, results_view.substr(middle + 1)))
|
||||
{
|
||||
if constexpr (set_body_flag)
|
||||
{
|
||||
req->setParameter("name", username.str);
|
||||
}
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fcb(HttpResponse::newCustomHttpResponse(BankResponse{k401Unauthorized, "\"Invalid Credentials\""}));
|
||||
}
|
||||
|
||||
template class UserFilter<true, false>; //user default
|
||||
template class UserFilter<false, false>; //user sparse
|
||||
template class UserFilter<false, true>; //admin
|
||||
10
src/xxhash_str.cpp
Normal file
10
src/xxhash_str.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "xxhash_str.h"
|
||||
|
||||
XXH64_hash_t xxHashStringGen::operator()(const std::string &str) const noexcept
|
||||
{
|
||||
return XXH3_64bits(str.data(), str.size());
|
||||
}
|
||||
XXH64_hash_t xxHashStringGen::operator()(const std::string_view &str) const noexcept
|
||||
{
|
||||
return XXH3_64bits(str.data(), str.size());
|
||||
}
|
||||
1
third_party/base64
vendored
Submodule
1
third_party/base64
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit eaebee8f666ea0451b0474e7be16006ad994004c
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
{
|
||||
}
|
||||
Loading…
Reference in a new issue