Compare commits
1027 Commits
v2.0.2-rc
...
1e2fd53b86
Author | SHA1 | Date | |
---|---|---|---|
1e2fd53b86 | |||
ab09407c3d | |||
9b2310a3e7 | |||
56a56e57c8 | |||
7908e7e982 | |||
92b32b838c | |||
65efa8590f | |||
d70aa968d6 | |||
591cd0ad2d | |||
1bdc78e5e0 | |||
7100708dfd | |||
08379ea622 | |||
161208a1fd | |||
3959067f22 | |||
65096f60b1 | |||
4b32664e46 | |||
cf1ee8db02 | |||
89d4b4245d | |||
1d7d221da1 | |||
b4621f6a4e | |||
c6b895ced2 | |||
5f51a9384e | |||
88736fc58a | |||
be96d79281 | |||
2a28eed7e8 | |||
443aaff217 | |||
b4d3bb083d | |||
b9ce21853f | |||
31e20e9af0 | |||
cfb7a74841 | |||
c8f2485ff0 | |||
62857e1372 | |||
ae3b592cf6 | |||
3365363d23 | |||
f480720665 | |||
d0a8f9df58 | |||
28dc153822 | |||
b265dcf73f | |||
4b9b095104 | |||
ea8eb53a34 | |||
412b807d3f | |||
14cbde2586 | |||
429751e1fc | |||
04f50f7453 | |||
3814b9797d | |||
44d810c398 | |||
c982972ee8 | |||
cfba3d3082 | |||
587527e418 | |||
bb4a3bc6cb | |||
29615d61eb | |||
86f910c865 | |||
2f6a691f65 | |||
ea59ce6dc3 | |||
3cbe39784f | |||
cb2089ccfe | |||
c2bdb884c2 | |||
7daec9d0f5 | |||
a05c642f5e | |||
4c70641d8f | |||
e1939d4d11 | |||
6da5d9f4f0 | |||
401344ac5a | |||
329ba1d5e4 | |||
7faf648919 | |||
8b5369d120 | |||
8af198f7a4 | |||
b1735ab0af | |||
1ab36272f6 | |||
86e5f0359d | |||
ff007bca7f | |||
d03e6e8201 | |||
d481aeae66 | |||
c832d4ce21 | |||
a5a0e690ce | |||
74496016f0 | |||
bb8ff0de59 | |||
c66369f302 | |||
de800f79e9 | |||
c0111d83ae | |||
596b171c2c | |||
99785c0b41 | |||
f2eafe0f14 | |||
5ea9f27645 | |||
6300270a21 | |||
2e587fd897 | |||
f022be6fb9 | |||
8ebf66a686 | |||
ee695eb738 | |||
80d8d6f32f | |||
0b7a9c6a56 | |||
54b70f99cc | |||
fe0fef2f21 | |||
1eec19c583 | |||
6b40658eac | |||
bd836b9ecb | |||
074a026d64 | |||
60864649c0 | |||
d2a26f0c09 | |||
74546807f4 | |||
d7d9199f8e | |||
77299455f9 | |||
0d5ac30e49 | |||
2c55e243f5 | |||
cb2362432e | |||
9c3e464ce4 | |||
4e8e188d24 | |||
e476b4f0c6 | |||
eec286845e | |||
c276cb8979 | |||
58107e6ed8 | |||
eb4c8c6cc0 | |||
0f7dfc6ce7 | |||
a4693f8acc | |||
fc7c6b9705 | |||
43ce2d13ec | |||
6f6f8d4d52 | |||
54fdcf6d80 | |||
fd46d3ef96 | |||
2a15d6b4a3 | |||
acdc165102 | |||
bb4e3c26f4 | |||
8e4a8f0f4b | |||
2fd6f68c97 | |||
f7ca4f8fa3 | |||
4c3d759837 | |||
04daf393d7 | |||
e62477a38e | |||
3338fcf91f | |||
136f76c575 | |||
b94c124869 | |||
1fe7b68f0e | |||
3d9ed2dfe8 | |||
c8cc0feae5 | |||
1d53cd8e8b | |||
73ec7f2252 | |||
5450ffc280 | |||
a9125196ce | |||
ab9765582a | |||
060b2b70dc | |||
739a31538f | |||
67595b4d45 | |||
c5003e0ee6 | |||
984657a5dd | |||
2930933f19 | |||
72a6f5ae08 | |||
7a96a8cbf3 | |||
0b4befd823 | |||
151b6775b0 | |||
47a6bdbcd2 | |||
20ab95380a | |||
73afdaedb9 | |||
a231c2afaf | |||
74109d1195 | |||
2bd847b833 | |||
2d74fb30de | |||
af339e6086 | |||
ae5c4a11a8 | |||
4ce7d76500 | |||
a031f9d867 | |||
2f6fa792df | |||
be0f977dc7 | |||
73efae7c2f | |||
6b67cd676d | |||
2db38a87e3 | |||
213511a77d | |||
a38a033143 | |||
619d5939b3 | |||
68a26d2bc6 | |||
2661885cf2 | |||
6a820837cc | |||
02b74402f4 | |||
3535a61844 | |||
eb4fe4ff60 | |||
793ec5b4a5 | |||
c14b637536 | |||
489d9b1960 | |||
2f60890d29 | |||
19d4b0a247 | |||
69d190e485 | |||
2df84f53ed | |||
876a1e9cd8 | |||
2945793de9 | |||
0de0e511ee | |||
c16d9f9712 | |||
0903d4b83e | |||
0bd1f72017 | |||
7bc1440b8b | |||
9562ac2c62 | |||
9da78b82f3 | |||
8018ce51a0 | |||
3871e44732 | |||
beb1058a51 | |||
259efff707 | |||
3c4a4d8976 | |||
e3ad402853 | |||
470e7b0b07 | |||
cda89d0588 | |||
f5993d472c | |||
0d01862441 | |||
ec2ff87ac7 | |||
fd16a55745 | |||
f1f9e4547d | |||
3238b6d4de | |||
43f0a4b646 | |||
c760b7328b | |||
7d9db55d5d | |||
0741e307cc | |||
38f5374e49 | |||
db1320dd3a | |||
2f8f38b6a2 | |||
0303dcf16a | |||
4c4db56a82 | |||
11c58c4afb | |||
07d0eb0616 | |||
7d74d192f9 | |||
da60c39216 | |||
5ca67b28cf | |||
8247669d3b | |||
55762f9c92 | |||
2a1a48bc68 | |||
d5b47a803c | |||
695a7b0195 | |||
ff13142093 | |||
d6aace8c51 | |||
ec2b8e1854 | |||
884d2d6890 | |||
72899173a0 | |||
79c72d1aef | |||
ab0b1b645b | |||
7eb12d09f9 | |||
ed8ec257cc | |||
c7a28ae526 | |||
c22c68ef28 | |||
d07e1f9cce | |||
158cd55b1a | |||
5fcc59434b | |||
0650790c43 | |||
55debcb643 | |||
ded55057cc | |||
7cb78cab40 | |||
468aba1399 | |||
eba242de7f | |||
fa92540bb9 | |||
b508d98dd7 | |||
4b68e5e4b7 | |||
3f6121839a | |||
5e1745ebfb | |||
b20bc6c28a | |||
9a1483377c | |||
4c97f6b098 | |||
f9af43309d | |||
a77fd75687 | |||
f5b4928818 | |||
25d61b5cd4 | |||
e65e14f796 | |||
6aea801779 | |||
21fd9fe227 | |||
948b0fdd99 | |||
b5cf2de900 | |||
18d05ca635 | |||
b8cd42e235 | |||
4e8ff7815e | |||
57b007759e | |||
8692541e7f | |||
f5b827a039 | |||
3a79cee2f9 | |||
3b68543e32 | |||
7c2a245944 | |||
56e27e3184 | |||
b7c87bed82 | |||
3cfda97c05 | |||
52df12493b | |||
6e7b030afa | |||
afeeb97f05 | |||
5f925d3e71 | |||
26e1975edc | |||
2169456d6a | |||
cca53b2d26 | |||
2a6ecf61b2 | |||
18c53fad9a | |||
84fc05acc0 | |||
c960df8f70 | |||
9d0baf30b8 | |||
312e4bc0f1 | |||
1d7f5b7ef1 | |||
08e381a307 | |||
49e518ac19 | |||
8e2ebf05b8 | |||
924b79add2 | |||
857dcc5535 | |||
7c0d583435 | |||
2b6a88f8cb | |||
fbf31c77ed | |||
9c2aa62f1f | |||
b6456abf0d | |||
5138b0d1ab | |||
0f60a5a467 | |||
982e5357a5 | |||
0ad0ff508b | |||
b4d61649cb | |||
cdfbaa47b6 | |||
211805e460 | |||
841d57cf13 | |||
bd25904371 | |||
3c001c11ae | |||
1f6036ec18 | |||
104e101158 | |||
b281b4c105 | |||
cf6a370eea | |||
8feb244dc9 | |||
f9e2e72d84 | |||
32ef8ba3c3 | |||
2fb53e34af | |||
c72dec6369 | |||
c0b0c5d397 | |||
d34ccc424d | |||
663c89ac53 | |||
414f18a518 | |||
9bfdece859 | |||
ad79c5daf5 | |||
48a1bef1ae | |||
09cb5d8f19 | |||
c216df9b73 | |||
a0a5ca3390 | |||
ae0a921ba8 | |||
3ce03dabf5 | |||
4a530c4703 | |||
c9f9c2a24c | |||
cd538566d3 | |||
f0fe0a1962 | |||
68e3f6fc00 | |||
a23adf6db6 | |||
da5752e971 | |||
40682e37c0 | |||
cbd36efd91 | |||
96c712ae9c | |||
28065c2c8e | |||
9677ebb44e | |||
172ea8bc00 | |||
d2ec6f1f10 | |||
bc7a74e432 | |||
8561278539 | |||
f932799efa | |||
67dedc3fb5 | |||
7120856407 | |||
a1b138ccd1 | |||
d192904f8c | |||
0bd7070ec5 | |||
63ca3089da | |||
39d644e115 | |||
ac89796d5d | |||
4e1250a832 | |||
4049af94dc | |||
ab40037cb4 | |||
66305c3c86 | |||
989d14072d | |||
21d4f4b78d | |||
94b7950cf1 | |||
1fe3f62be4 | |||
43df4356b6 | |||
5440dd3dac | |||
88718de96e | |||
d8d86f3f0c | |||
1ff62fb2b5 | |||
284e2a3ead | |||
3c97c2d953 | |||
196aeae11f | |||
ba2850ea21 | |||
1f4872769d | |||
24c647966b | |||
d3f3048568 | |||
ea249723f9 | |||
52a2df2576 | |||
6645b322bd | |||
7a683a46a9 | |||
cb24252286 | |||
fff3dc4685 | |||
9c01d51334 | |||
9aafb62961 | |||
891040479b | |||
55bcf082ec | |||
67053645e1 | |||
854caffea8 | |||
36e952606b | |||
eba93484c1 | |||
d09d55951d | |||
b35e100bb2 | |||
27b37eb570 | |||
92295506a7 | |||
d20ed07066 | |||
3fa16fd846 | |||
481dfd5ff5 | |||
e5a99943a5 | |||
dbaf379f19 | |||
e1bd3bb8ec | |||
ca834dd119 | |||
163549098d | |||
4800db00d9 | |||
675707b46c | |||
14ebdab034 | |||
8541e292cd | |||
9adec02640 | |||
6a97ad664b | |||
8bb291bbd9 | |||
13a55bff61 | |||
d6efc19ba8 | |||
517e603539 | |||
d144101a7e | |||
b84202a689 | |||
572351067c | |||
9a3d6e725e | |||
d6ac8cfeca | |||
e697363574 | |||
8cc6868480 | |||
37d393c1f9 | |||
ec8b7783f3 | |||
7b375eb912 | |||
ffdea97de3 | |||
7c02d79a5c | |||
46bbc4bf92 | |||
08104c97f7 | |||
8cf169849c | |||
67ac6a6c6e | |||
ef270887fc | |||
d61cb3f0f3 | |||
12d3fbe9a7 | |||
bf9d6157f5 | |||
c4d7868381 | |||
de0a88e45b | |||
fed4f40cfb | |||
d1b4aab952 | |||
072a5356b6 | |||
781278df06 | |||
42a81b1c8e | |||
3e6ed45562 | |||
366fe60e2f | |||
be30230422 | |||
a523d1ca66 | |||
62a75bcddd | |||
bd754a7ee8 | |||
ae98d199e7 | |||
95ff5dd5eb | |||
3f3e9b5735 | |||
82a48fa3b4 | |||
97ce74b798 | |||
91704df08d | |||
4add037dc7 | |||
79314a11b5 | |||
0ff87a0ac3 | |||
1aef67368b | |||
ba2a669be6 | |||
fd721c5dc4 | |||
34070bba89 | |||
1b1fc0fc09 | |||
44a1547d2e | |||
439f9cce3d | |||
9aecec2d96 | |||
26fffdd3e8 | |||
7bf69ec350 | |||
49f884bb68 | |||
a58fcc7f14 | |||
113b5e7258 | |||
5b337d4c65 | |||
0b80e82721 | |||
7e45fa9708 | |||
aa92f3d401 | |||
692c92b0df | |||
51cb2c0b9a | |||
6e52474953 | |||
35db1cd0c4 | |||
739a1103f0 | |||
bb8cbb49f5 | |||
3be29f5b73 | |||
d944569fb2 | |||
3ca27ec566 | |||
779bfc762e | |||
54828600a8 | |||
d5410b88a3 | |||
e86d9fd29b | |||
cbebcfae82 | |||
3dc16db278 | |||
e81227e5f7 | |||
fd83c263e1 | |||
9ca857c98e | |||
afcba6b086 | |||
ef50acc867 | |||
f12833f36c | |||
b26788819e | |||
f905de7c42 | |||
8466a8850f | |||
af8e2cddcb | |||
0089866142 | |||
ca892c7f11 | |||
2a33000ace | |||
bd8da9b987 | |||
5bd780ef07 | |||
25c445b889 | |||
ca4111ac77 | |||
868e8ae124 | |||
51358c7110 | |||
ad97741e1e | |||
5d281e0fd0 | |||
c1a1242398 | |||
5000215973 | |||
ceda21830f | |||
b80b7b482c | |||
8e41f71e70 | |||
72286c865f | |||
2d435457e6 | |||
cef1ff7067 | |||
393dc07de8 | |||
49f0425e56 | |||
7973e523c3 | |||
c4326520cd | |||
dfb9d78448 | |||
26714a836c | |||
59e2986080 | |||
65fc484fa4 | |||
253978bc5f | |||
4aad60f69d | |||
72f7aaf9e4 | |||
d12b5f7b05 | |||
a7239558bd | |||
9d3e4b8767 | |||
cbb99c7b47 | |||
dca0752189 | |||
760a1e4322 | |||
56bc78f63c | |||
60b89c5c08 | |||
fa0f648a0b | |||
5592c663a4 | |||
c847353baf | |||
a140f59acb | |||
b2eae73fb0 | |||
a34dc8f1f8 | |||
92e2937a6b | |||
47757f69bd | |||
b642294193 | |||
8075af364f | |||
3d7285063a | |||
232420621a | |||
a0432be819 | |||
468093227d | |||
32facdc2ff | |||
3a719272cb | |||
9ce4c5a494 | |||
15cc7b0b87 | |||
6d152181d3 | |||
97082fa42c | |||
becd137cf5 | |||
89fc0fb372 | |||
68d79c73cf | |||
d0e9ed4181 | |||
535d2f85ca | |||
5ec20fbcbd | |||
0225fb8e5d | |||
035f830b71 | |||
7a1fb4a790 | |||
4939b05ca7 | |||
2e1f0c8f5f | |||
d8ac596687 | |||
1f43ab3bcc | |||
ef9fbf775c | |||
d6ff728a4d | |||
f6ea8f077b | |||
3e96764fc4 | |||
45b21ae0af | |||
490e49406f | |||
36e7d06b39 | |||
b26b52fd2d | |||
b35041f1f3 | |||
bf7ba3991f | |||
30806c6ebd | |||
29af6e5b7c | |||
cde0e92591 | |||
85b28f7ee3 | |||
df24b99303 | |||
d659a5e04d | |||
99c0246720 | |||
c0dba76ecd | |||
e37a375c18 | |||
6718eb374d | |||
bba7f10703 | |||
df947db055 | |||
256e873e7b | |||
34bc3b759e | |||
853aa2784c | |||
4011ab8080 | |||
07eaad7226 | |||
c743d3c341 | |||
05a5645f4c | |||
7aa71fb202 | |||
6410faa5b4 | |||
a3e578240b | |||
dd492ff52d | |||
e7b576bc45 | |||
7fcc40d0e1 | |||
e6fc6093b2 | |||
73ee70a862 | |||
b647053fb9 | |||
d518e55a67 | |||
fcd38db2ef | |||
89cd8c8fd0 | |||
88c7e7f192 | |||
a00e77d554 | |||
05d5bd9fe5 | |||
e14e7e96c7 | |||
4b8ac300c8 | |||
ee9c5fffad | |||
55caf049b1 | |||
4bdaeaa30d | |||
7c58d9c569 | |||
d6b2c1d81e | |||
4a2acf99a7 | |||
3567941139 | |||
50e7fb612c | |||
03dd9ee579 | |||
2a3c6f3522 | |||
2e46f2fead | |||
b00b72d70f | |||
7dbaf9b8d9 | |||
6b463adbb9 | |||
cb819d7da6 | |||
841ba37841 | |||
7cfefbc512 | |||
9ebba7252c | |||
835c56330a | |||
3e5c70e6b4 | |||
95b88b6ac6 | |||
c1f39afaa3 | |||
1893f7204e | |||
4a062abfde | |||
fb26aa04b6 | |||
7c538b471d | |||
c4c1941fc8 | |||
0ce2be24a3 | |||
3cf60d0d26 | |||
7d33ee80d0 | |||
52ba2de51f | |||
a1b8b57d34 | |||
cf9e0a356c | |||
e66b783df8 | |||
b695200123 | |||
a383fb405e | |||
1cebaf83e1 | |||
4976825bd6 | |||
098d172f40 | |||
f4a3c52428 | |||
2d60b637ec | |||
79b16d9a34 | |||
d69f2fd321 | |||
4015c1bb6e | |||
9f76f20ea8 | |||
b399ff3291 | |||
4fafc17b90 | |||
f1bb88624b | |||
f950e3192f | |||
bef2f078e0 | |||
218053a2be | |||
baca904079 | |||
b5175cb82b | |||
39888a1ebc | |||
ffea22c71b | |||
dd15bb2205 | |||
4b53b5544f | |||
24ca2d3531 | |||
5587e3430b | |||
0c36669fef | |||
bbce86cb9d | |||
ed3a45bfc6 | |||
144fd59c1c | |||
bdc54d7115 | |||
aa04371663 | |||
78ef412516 | |||
28f7f5cb14 | |||
624b92bc97 | |||
ca799298f4 | |||
42b67a7b61 | |||
4de4386142 | |||
509eeca760 | |||
1cb9663776 | |||
26667fdcd6 | |||
681a3eec53 | |||
2a5df890f7 | |||
ae0059591c | |||
8655becf1e | |||
2a3a0aa689 | |||
ce417ec7c8 | |||
4e848a998e | |||
d89f35775e | |||
88ebf72003 | |||
9437b175a2 | |||
302d73a078 | |||
ba7c36e30e | |||
b4da43c87f | |||
f5e078ea3d | |||
8aba39c955 | |||
68a5f90715 | |||
f3dfadddfa | |||
f1ec1fd4a6 | |||
cf59db9cee | |||
e21fbe84ba | |||
1e4d675f76 | |||
e02fe870e9 | |||
9ef9250c18 | |||
2e4b9d3787 | |||
fd2b3c3239 | |||
6640394bd3 | |||
84cc726c4f | |||
5d99d21915 | |||
3b8636544a | |||
14ce60ab65 | |||
7506431b34 | |||
8621209eb3 | |||
d1fe317fb9 | |||
a5c47d3f22 | |||
267c272ce5 | |||
7a8ae32b85 | |||
921d404a5a | |||
de6a7beb5e | |||
5a928208fd | |||
92fc163341 | |||
ca1e03f3ea | |||
de8c3ad603 | |||
f7d56bdd48 | |||
afc13b45f4 | |||
11d2c3c69e | |||
356521e176 | |||
468668e518 | |||
e53dec7bab | |||
26cd6de110 | |||
d1157ca261 | |||
0d49b49482 | |||
753820bd81 | |||
2a98e44a5c | |||
9650d3f56b | |||
aff308f67d | |||
be76d663b5 | |||
160863561f | |||
de02fdb812 | |||
1dda98e337 | |||
ccc6afdfa4 | |||
6b166551af | |||
90694f816f | |||
51636fbac3 | |||
3c7aa417a9 | |||
04d560739d | |||
2c1842f06c | |||
aba487277c | |||
1b95d5dfed | |||
7590fc4f45 | |||
a409408ac0 | |||
b121c9778f | |||
d452761ff9 | |||
dbc5725779 | |||
8b6536c55b | |||
c7318b0383 | |||
26fa85e421 | |||
939742a991 | |||
6ab7386a79 | |||
a750cdc3cb | |||
2f8af0fb08 | |||
7a9802ccb7 | |||
d356d04bf5 | |||
c99c4988ff | |||
6c564eb98b | |||
786d8634cf | |||
70b5204a9f | |||
1d70309a16 | |||
b2aba8c447 | |||
8757b47b35 | |||
b1a7632536 | |||
97c73d5358 | |||
bb3f05aef1 | |||
2001ffc27c | |||
bd2dd4035e | |||
7eb793f577 | |||
b05cedb509 | |||
cd484aa7bb | |||
fbfb528adc | |||
d9cba7f4cc | |||
7d5c5e18c6 | |||
2c0935a771 | |||
5312797b97 | |||
801af6b799 | |||
b42379b519 | |||
8b328b92b1 | |||
2e6ecf8ddb | |||
12c7c48b20 | |||
732a42a073 | |||
5638d5c010 | |||
6a984ac84c | |||
c1eb6b94ed | |||
85135b9267 | |||
670c5bac17 | |||
2dab1426b4 | |||
43004b19c3 | |||
4044d95aaa | |||
c6024c06ce | |||
e56bcb6489 | |||
d9e0164080 | |||
b588cd645e | |||
2c163d7219 | |||
39c53fe903 | |||
7b12d8f9e9 | |||
4649f66c00 | |||
9648abf4b9 | |||
cc1246d0f5 | |||
726aa43a95 | |||
224f983ca8 | |||
f962884341 | |||
6f35cc8bfa | |||
c08c9bc216 | |||
239652be7c | |||
68c9ec0f82 | |||
da07122997 | |||
5fb66dc6ee | |||
0c414fc8a6 | |||
097507a2d9 | |||
466b3fcead | |||
81dc6d1269 | |||
b6c020d35d | |||
dfbe97988f | |||
cd36679a1c | |||
4d555bce96 | |||
d96c6012c5 | |||
15793e714d | |||
437cb94dda | |||
544765e408 | |||
472b1f0da1 | |||
867b2eee40 | |||
5a30b15d1e | |||
0f2c507c30 | |||
c545916332 | |||
ac81f5f624 | |||
50ae7ab558 | |||
a5e29ed745 | |||
6d29170342 | |||
410314022f | |||
815e00d389 | |||
fbf5455f89 | |||
8925704555 | |||
462365dc97 | |||
e73dd52973 | |||
881eec4e02 | |||
bcdfc73767 | |||
0520aa3d40 | |||
c562d17b78 | |||
aee68520b3 | |||
88d8bf63f5 | |||
303887ea37 | |||
51d3d33175 | |||
cdb5ea279d | |||
311e1b318a | |||
31c5b6f1db | |||
a024f81e5d | |||
4089fca87c | |||
99533a9687 | |||
d175a38ad1 | |||
28e918be18 | |||
b4403ff959 | |||
8c548bad92 | |||
6ecad9af72 | |||
df73f9a18f | |||
9b453327a8 | |||
071552ffd5 | |||
33a0b4b295 | |||
21bcd0780c | |||
f6cdf2914c | |||
7698a62c1f | |||
2ae22cdb30 | |||
7705432820 | |||
f150832676 | |||
80c9375d65 | |||
48ddff9e85 | |||
6f64fe02d5 | |||
61ab4d8d58 | |||
3bb962a266 | |||
c286dc4f5c | |||
9d36ded2b3 | |||
71686405e0 | |||
34c4a9c508 | |||
effafd3e91 | |||
5a61bdf2b0 | |||
d21fcfd1c6 | |||
fff9a27362 | |||
ad7872a0e3 | |||
f3ea2ccc21 | |||
e959a9e795 | |||
3fe5eac56d | |||
67191be78d | |||
00cfb67b64 | |||
35aa8f5a94 | |||
f44972b8b3 | |||
94675a3011 | |||
7112fbee7e | |||
ff13633962 | |||
cb93e34de0 | |||
883968f53e | |||
d6d4b579c9 | |||
0e83d84360 | |||
63a6b3bdba | |||
aafa7e112a | |||
804eb7aa5a | |||
eeba641732 | |||
932ea6cb1d | |||
dd4724e374 | |||
e652c9956e | |||
d11767776e | |||
daefa58c0c | |||
7fe7299e7c | |||
0af9c6e8b0 | |||
b9c2113d43 | |||
4fd23de9b6 | |||
3b372ebe86 | |||
d14d149a3b | |||
44acf7dace | |||
da7efdb1a8 | |||
444f39f9ff | |||
fd9c26f016 | |||
7ef9f5cd65 | |||
d3321b3c57 | |||
bbe546008f | |||
5ec91e2d20 | |||
fbe4df0251 | |||
e5c690eb89 | |||
aeedd114a6 | |||
dfa5e0e005 | |||
5911d370e5 | |||
baf769c462 | |||
33e8e0890b | |||
e2e82edefb | |||
da1b5c6953 | |||
629725e262 | |||
6ba4c0091b | |||
99d5261aab | |||
97487cf0c4 | |||
8436f2e2bb | |||
310e436163 | |||
b64477fd7e | |||
782da43114 | |||
37854b693b | |||
7360b72c7b | |||
6f68f268c0 | |||
983587aeb7 | |||
ee415d2e4a | |||
0c075d7fe4 | |||
eec3653c6b | |||
5ac2a24611 | |||
144683d7b3 | |||
9c917a9119 | |||
dc48b84191 | |||
8555d31ddf | |||
cb0dde2a80 | |||
5f5b1f751b | |||
24c5dad929 | |||
f0046fcd57 | |||
3c3e415175 | |||
00d3355f43 | |||
907a14faff | |||
4348e89f99 | |||
7a24cc54f8 | |||
80f6e3c272 | |||
edb1297c4a | |||
1ee157f943 | |||
1b2981b06e | |||
7203fefd33 | |||
d808b2dd19 | |||
ee34a1e361 | |||
1766f91697 | |||
b3aa28d085 | |||
a605d7af11 | |||
19b1a33c48 | |||
04aa511448 | |||
8dc3d4466b | |||
0716a58ff0 | |||
60052081b4 | |||
f11d49b264 | |||
103dae6d08 | |||
821ed7b25e | |||
87f83b6f30 | |||
ace81d797e | |||
57ca2c7c6d | |||
8360d9e045 | |||
560ffbbb6a | |||
72314606f3 | |||
db009b69dd | |||
3ed99dc0ce | |||
762a7c99d5 | |||
4e62156b70 | |||
cc49536755 | |||
54b844dc3b | |||
1e8ba13f66 | |||
93011cee9c | |||
a474a5c73c | |||
17b98ca99d | |||
281eedb71e | |||
1ee533591c | |||
b87e1df140 | |||
f88239a13e | |||
68476cbc00 | |||
f2c1f64f02 | |||
a7209184c8 | |||
ba59e29499 | |||
f94196d865 | |||
bb5a9f9737 | |||
4bc5cf7c64 | |||
639d14452b | |||
e7413fb741 | |||
c0e720498d | |||
383c3b4be6 | |||
e9b202f5c8 | |||
bc3005a6a4 | |||
8cf19e0594 | |||
b137b57dbc | |||
5dff8927da | |||
197e79dd07 | |||
6262aca761 | |||
c156ae704b | |||
a67979ec40 | |||
54bfc11620 | |||
d33c2cd3a2 | |||
3a5f428fb6 | |||
0331152569 | |||
1b7e854f5f | |||
12a945d863 |
@ -161,7 +161,6 @@ openssldir
|
|||||||
pkgconfig
|
pkgconfig
|
||||||
plarge_integer
|
plarge_integer
|
||||||
plex
|
plex
|
||||||
println
|
|
||||||
project_enable_fontconfig
|
project_enable_fontconfig
|
||||||
project_enable_gtkmm
|
project_enable_gtkmm
|
||||||
project_enable_libdsm
|
project_enable_libdsm
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
## v2.0.2-rc
|
## v2.0.2-rc
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* Refactored `config.json` - will need to verify configuration settings prior to mounting
|
|
||||||
|
|
||||||
### Issues
|
### Issues
|
||||||
|
|
||||||
* \#12 \[Unit Test\] Complete all providers unit tests
|
* \#12 \[Unit Test\] Complete all providers unit tests
|
||||||
@ -18,18 +14,13 @@
|
|||||||
* MSYS2 is required for building Windows binaries on Windows
|
* MSYS2 is required for building Windows binaries on Windows
|
||||||
* OS X support is temporarily disabled
|
* OS X support is temporarily disabled
|
||||||
* \#19 \[bug\] Rename file is broken for files that are existing
|
* \#19 \[bug\] Rename file is broken for files that are existing
|
||||||
* \#23 \[bug\] Incorrect file size displayed while upload is pending
|
|
||||||
* \#24 RocksDB implementations should be transactional
|
|
||||||
* \#25 Writes should block when maximum cache size is reached
|
|
||||||
* \#26 Complete ring buffer and direct download support
|
|
||||||
|
|
||||||
### Changes from v2.0.1-rc
|
### Changes from v2.0.1-rc
|
||||||
|
|
||||||
* Ability to choose between RocksDB and SQLite databases
|
|
||||||
* Added direct reads and implemented download fallback
|
|
||||||
* Corrected file times on S3 and Sia providers
|
* Corrected file times on S3 and Sia providers
|
||||||
* Corrected handling of `chown()` and `chmod()`
|
* Corrected handling of `chown()` and `chmod()`
|
||||||
* Fixed erroneous download of chunks after resize
|
* Fixed erroneous download of chunks after resize
|
||||||
|
* Comprehensive WinFSP and FUSE unit tests, including remote testing
|
||||||
|
|
||||||
## v2.0.1-rc
|
## v2.0.1-rc
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
set(BINUTILS_HASH ae9a5789e23459e59606e6714723f2d3ffc31c03174191ef0d015bdf06007450)
|
set(BINUTILS_HASH ae9a5789e23459e59606e6714723f2d3ffc31c03174191ef0d015bdf06007450)
|
||||||
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
set(BOOST_HASH 2575e74ffc3ef1cd0babac2c1ee8bdb5782a0ee672b1912da40e5b4b591ca01f)
|
||||||
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
||||||
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
|
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
|
||||||
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
|
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
if(PROJECT_ENABLE_ROCKSDB)
|
if(PROJECT_ENABLE_ROCKSDB)
|
||||||
if(PROJECT_BUILD)
|
if(PROJECT_BUILD)
|
||||||
add_definitions(-DPROJECT_ENABLE_ROCKSDB)
|
add_definitions(-DPROJECT_ENABLE_ROCKSDB)
|
||||||
|
|
||||||
find_library(ROCKSDB_LIBRARY NAMES librocksdb.a REQUIRED)
|
find_library(ROCKSDB_LIBRARY NAMES librocksdb.a REQUIRED)
|
||||||
|
|
||||||
link_libraries(${ROCKSDB_LIBRARY})
|
link_libraries(${ROCKSDB_LIBRARY})
|
||||||
elseif(NOT PROJECT_IS_MINGW OR CMAKE_HOST_WIN32)
|
elseif(NOT PROJECT_IS_MINGW OR CMAKE_HOST_WIN32)
|
||||||
ExternalProject_Add(rocksdb_project
|
ExternalProject_Add(rocksdb_project
|
||||||
@ -10,11 +12,11 @@ if(PROJECT_ENABLE_ROCKSDB)
|
|||||||
URL_HASH SHA256=${ROCKSDB_HASH}
|
URL_HASH SHA256=${ROCKSDB_HASH}
|
||||||
LIST_SEPARATOR |
|
LIST_SEPARATOR |
|
||||||
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
-DBUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS}
|
||||||
-DBUILD_STATIC_LIBS=ON
|
-DBUILD_STATIC_LIBS=ON
|
||||||
-DFAIL_ON_WARNINGS=OFF
|
-DFAIL_ON_WARNINGS=OFF
|
||||||
-DPORTABLE=1
|
-DPORTABLE=1
|
||||||
-DROCKSDB_BUILD_SHARED=OFF
|
-DROCKSDB_BUILD_SHARED=${PROJECT_BUILD_SHARED_LIBS}
|
||||||
-DROCKSDB_INSTALL_ON_WINDOWS=ON
|
-DROCKSDB_INSTALL_ON_WINDOWS=ON
|
||||||
-DWITH_BENCHMARK=OFF
|
-DWITH_BENCHMARK=OFF
|
||||||
-DWITH_BENCHMARK_TOOLS=OFF
|
-DWITH_BENCHMARK_TOOLS=OFF
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
set(BINUTILS_VERSION 2.41)
|
set(BINUTILS_VERSION 2.41)
|
||||||
|
set(BOOST_MAJOR_VERSION 1)
|
||||||
|
set(BOOST_MINOR_VERSION 86)
|
||||||
|
set(BOOST_PATCH_VERSION 0)
|
||||||
set(BOOST2_MAJOR_VERSION 1)
|
set(BOOST2_MAJOR_VERSION 1)
|
||||||
set(BOOST2_MINOR_VERSION 76)
|
set(BOOST2_MINOR_VERSION 76)
|
||||||
set(BOOST2_PATCH_VERSION 0)
|
set(BOOST2_PATCH_VERSION 0)
|
||||||
set(BOOST_MAJOR_VERSION 1)
|
|
||||||
set(BOOST_MINOR_VERSION 87)
|
|
||||||
set(BOOST_PATCH_VERSION 0)
|
|
||||||
set(CPP_HTTPLIB_VERSION 0.18.1)
|
set(CPP_HTTPLIB_VERSION 0.18.1)
|
||||||
set(CURL2_VERSION 8_11_0)
|
|
||||||
set(CURL_VERSION 8.11.0)
|
set(CURL_VERSION 8.11.0)
|
||||||
set(EXPAT2_VERSION 2_6_4)
|
set(CURL2_VERSION 8_11_0)
|
||||||
set(EXPAT_VERSION 2.6.4)
|
set(EXPAT_VERSION 2.6.4)
|
||||||
|
set(EXPAT2_VERSION 2_6_4)
|
||||||
set(GCC_VERSION 14.2.0)
|
set(GCC_VERSION 14.2.0)
|
||||||
set(GTEST_VERSION 1.15.2)
|
set(GTEST_VERSION 1.15.2)
|
||||||
set(ICU_VERSION 75-1)
|
set(ICU_VERSION 75-1)
|
||||||
@ -22,7 +22,7 @@ set(PKG_CONFIG_VERSION 0.29.2)
|
|||||||
set(PUGIXML_VERSION 1.14)
|
set(PUGIXML_VERSION 1.14)
|
||||||
set(ROCKSDB_VERSION 9.7.4)
|
set(ROCKSDB_VERSION 9.7.4)
|
||||||
set(SPDLOG_VERSION 1.15.0)
|
set(SPDLOG_VERSION 1.15.0)
|
||||||
set(SQLITE2_VERSION 3.46.1)
|
|
||||||
set(SQLITE_VERSION 3460100)
|
set(SQLITE_VERSION 3460100)
|
||||||
|
set(SQLITE2_VERSION 3.46.1)
|
||||||
set(STDUUID_VERSION 1.2.3)
|
set(STDUUID_VERSION 1.2.3)
|
||||||
set(ZLIB_VERSION 1.3.1)
|
set(ZLIB_VERSION 1.3.1)
|
||||||
|
@ -22,9 +22,10 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_APP_CONFIG_HPP_
|
#ifndef REPERTORY_INCLUDE_APP_CONFIG_HPP_
|
||||||
#define REPERTORY_INCLUDE_APP_CONFIG_HPP_
|
#define REPERTORY_INCLUDE_APP_CONFIG_HPP_
|
||||||
|
|
||||||
#include "events/event.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "types/remote.hpp"
|
#include "events/events.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/error_utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class app_config final {
|
class app_config final {
|
||||||
@ -39,7 +40,7 @@ public:
|
|||||||
default_data_directory(const provider_type &prov) -> std::string;
|
default_data_directory(const provider_type &prov) -> std::string;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto
|
||||||
default_remote_api_port(const provider_type &prov) -> std::uint16_t;
|
default_remote_port(const provider_type &prov) -> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto
|
||||||
default_rpc_port(const provider_type &prov) -> std::uint16_t;
|
default_rpc_port(const provider_type &prov) -> std::uint16_t;
|
||||||
@ -53,202 +54,406 @@ public:
|
|||||||
public:
|
public:
|
||||||
app_config(const provider_type &prov, std::string_view data_directory = "");
|
app_config(const provider_type &prov, std::string_view data_directory = "");
|
||||||
|
|
||||||
app_config() = delete;
|
|
||||||
app_config(app_config &&) = delete;
|
|
||||||
app_config(const app_config &) = delete;
|
|
||||||
|
|
||||||
~app_config() { save(); }
|
~app_config() { save(); }
|
||||||
|
|
||||||
auto operator=(const app_config &) -> app_config & = delete;
|
|
||||||
auto operator=(app_config &&) -> app_config & = delete;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
provider_type prov_;
|
provider_type prov_;
|
||||||
atomic<std::string> api_auth_;
|
std::string api_auth_;
|
||||||
std::atomic<std::uint16_t> api_port_;
|
std::uint16_t api_port_;
|
||||||
atomic<std::string> api_user_;
|
std::string api_user_;
|
||||||
std::atomic<bool> config_changed_;
|
bool config_changed_;
|
||||||
std::atomic<database_type> db_type_{database_type::rocksdb};
|
|
||||||
std::atomic<std::uint8_t> download_timeout_secs_;
|
|
||||||
std::atomic<bool> enable_download_timeout_;
|
|
||||||
std::atomic<bool> enable_drive_events_;
|
|
||||||
#if defined(_WIN32)
|
|
||||||
std::atomic<bool> enable_mount_manager_;
|
|
||||||
#endif // defined(_WIN32)
|
|
||||||
std::atomic<event_level> event_level_;
|
|
||||||
std::atomic<std::uint32_t> eviction_delay_mins_;
|
|
||||||
std::atomic<bool> eviction_uses_accessed_time_;
|
|
||||||
std::atomic<std::uint16_t> high_freq_interval_secs_;
|
|
||||||
std::atomic<std::uint16_t> low_freq_interval_secs_;
|
|
||||||
std::atomic<std::uint64_t> max_cache_size_bytes_;
|
|
||||||
std::atomic<std::uint8_t> max_upload_count_;
|
|
||||||
std::atomic<std::uint16_t> med_freq_interval_secs_;
|
|
||||||
std::atomic<std::uint16_t> online_check_retry_secs_;
|
|
||||||
std::atomic<std::uint16_t> orphaned_file_retention_days_;
|
|
||||||
std::atomic<download_type> preferred_download_type_;
|
|
||||||
std::atomic<std::uint16_t> retry_read_count_;
|
|
||||||
std::atomic<std::uint16_t> ring_buffer_file_size_;
|
|
||||||
std::atomic<std::uint16_t> task_wait_ms_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string cache_directory_;
|
|
||||||
std::string data_directory_;
|
std::string data_directory_;
|
||||||
atomic<encrypt_config> encrypt_config_;
|
std::uint8_t download_timeout_secs_;
|
||||||
atomic<host_config> host_config_;
|
bool enable_chunk_downloader_timeout_;
|
||||||
|
bool enable_comm_duration_events_;
|
||||||
|
bool enable_drive_events_;
|
||||||
|
bool enable_max_cache_size_;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
bool enable_mount_manager_;
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
bool enable_remote_mount_;
|
||||||
|
encrypt_config encrypt_config_;
|
||||||
|
event_level event_level_;
|
||||||
|
std::uint32_t eviction_delay_mins_;
|
||||||
|
bool eviction_uses_accessed_time_;
|
||||||
|
std::uint8_t high_freq_interval_secs_;
|
||||||
|
bool is_remote_mount_;
|
||||||
|
std::uint32_t low_freq_interval_secs_;
|
||||||
|
std::uint64_t max_cache_size_bytes_;
|
||||||
|
std::uint8_t max_upload_count_;
|
||||||
|
std::uint8_t min_download_timeout_secs_;
|
||||||
|
std::uint16_t online_check_retry_secs_;
|
||||||
|
std::uint16_t orphaned_file_retention_days_;
|
||||||
|
std::string preferred_download_type_;
|
||||||
|
std::uint8_t read_ahead_count_;
|
||||||
|
std::uint8_t remote_client_pool_size_;
|
||||||
|
std::string remote_host_name_or_ip_;
|
||||||
|
std::uint8_t remote_max_connections_;
|
||||||
|
std::uint16_t remote_port_;
|
||||||
|
std::uint16_t remote_receive_timeout_secs_;
|
||||||
|
std::uint16_t remote_send_timeout_secs_;
|
||||||
|
std::string remote_token_;
|
||||||
|
std::uint16_t retry_read_count_;
|
||||||
|
std::uint16_t ring_buffer_file_size_;
|
||||||
|
std::string cache_directory_;
|
||||||
|
host_config hc_;
|
||||||
|
s3_config s3_config_;
|
||||||
|
sia_config sia_config_{};
|
||||||
|
std::uint64_t version_{REPERTORY_CONFIG_VERSION};
|
||||||
std::string log_directory_;
|
std::string log_directory_;
|
||||||
mutable std::recursive_mutex read_write_mutex_;
|
mutable std::recursive_mutex read_write_mutex_;
|
||||||
atomic<remote::remote_config> remote_config_;
|
mutable std::recursive_mutex remote_mount_mutex_;
|
||||||
atomic<remote::remote_mount> remote_mount_;
|
|
||||||
atomic<s3_config> s3_config_;
|
|
||||||
atomic<sia_config> sia_config_;
|
|
||||||
std::unordered_map<std::string, std::function<std::string()>>
|
|
||||||
value_get_lookup_;
|
|
||||||
std::unordered_map<std::string,
|
|
||||||
std::function<std::string(const std::string &)>>
|
|
||||||
value_set_lookup_;
|
|
||||||
std::uint64_t version_{REPERTORY_CONFIG_VERSION};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto load() -> bool;
|
[[nodiscard]] auto load() -> bool;
|
||||||
|
|
||||||
|
template <typename dest>
|
||||||
|
auto get_value(const json &json_document, const std::string &name, dest &dst,
|
||||||
|
bool &success_flag) -> bool {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto ret{false};
|
||||||
|
try {
|
||||||
|
if (json_document.find(name) != json_document.end()) {
|
||||||
|
dst = json_document[name].get<dest>();
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
success_flag = false;
|
||||||
|
}
|
||||||
|
} catch (const json::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex, "exception occurred");
|
||||||
|
success_flag = false;
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename dest, typename source>
|
template <typename dest, typename source>
|
||||||
auto set_value(dest &dst, const source &src) -> bool;
|
auto set_value(dest &dst, const source &src) -> bool {
|
||||||
|
auto ret{false};
|
||||||
|
recur_mutex_lock lock(read_write_mutex_);
|
||||||
|
if (dst != src) {
|
||||||
|
dst = src;
|
||||||
|
config_changed_ = true;
|
||||||
|
save();
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto get_api_auth() const -> std::string;
|
[[nodiscard]] auto get_api_auth() const -> std::string { return api_auth_; }
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_port() const -> std::uint16_t;
|
[[nodiscard]] auto get_api_port() const -> std::uint16_t { return api_port_; }
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_user() const -> std::string;
|
[[nodiscard]] auto get_api_user() const -> std::string { return api_user_; }
|
||||||
|
|
||||||
[[nodiscard]] auto get_cache_directory() const -> std::string;
|
[[nodiscard]] auto get_cache_directory() const -> std::string {
|
||||||
|
return cache_directory_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_chunk_downloader_timeout_secs() const -> std::uint8_t {
|
||||||
|
return std::max(min_download_timeout_secs_, download_timeout_secs_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_config_file_path() const -> std::string;
|
[[nodiscard]] auto get_config_file_path() const -> std::string;
|
||||||
|
|
||||||
[[nodiscard]] auto get_database_type() const -> database_type;
|
[[nodiscard]] auto get_data_directory() const -> std::string {
|
||||||
|
return data_directory_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_data_directory() const -> std::string;
|
[[nodiscard]] auto get_enable_chunk_download_timeout() const -> bool {
|
||||||
|
return enable_chunk_downloader_timeout_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_download_timeout_secs() const -> std::uint8_t;
|
[[nodiscard]] auto get_enable_comm_duration_events() const -> bool {
|
||||||
|
return enable_comm_duration_events_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_enable_download_timeout() const -> bool;
|
[[nodiscard]] auto get_enable_drive_events() const -> bool {
|
||||||
|
return enable_drive_events_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_enable_drive_events() const -> bool;
|
[[nodiscard]] auto get_encrypt_config() const -> encrypt_config {
|
||||||
|
return encrypt_config_;
|
||||||
[[nodiscard]] auto get_encrypt_config() const -> encrypt_config;
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
[[nodiscard]] auto get_enable_mount_manager() const -> bool;
|
[[nodiscard]] auto get_enable_mount_manager() const -> bool {
|
||||||
#endif // defined(_WIN32)
|
return enable_mount_manager_;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto get_event_level() const -> event_level;
|
[[nodiscard]] auto get_enable_max_cache_size() const -> bool {
|
||||||
|
return enable_max_cache_size_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_eviction_delay_mins() const -> std::uint32_t;
|
[[nodiscard]] auto get_enable_remote_mount() const -> bool {
|
||||||
|
return enable_remote_mount_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_eviction_uses_accessed_time() const -> bool;
|
[[nodiscard]] auto get_event_level() const -> event_level {
|
||||||
|
return event_level_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_high_frequency_interval_secs() const -> std::uint16_t;
|
[[nodiscard]] auto get_eviction_delay_mins() const -> std::uint32_t {
|
||||||
|
return eviction_delay_mins_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_host_config() const -> host_config;
|
[[nodiscard]] auto get_eviction_uses_accessed_time() const -> bool {
|
||||||
|
return eviction_uses_accessed_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_high_frequency_interval_secs() const -> std::uint8_t {
|
||||||
|
return std::max(static_cast<std::uint8_t>(1U), high_freq_interval_secs_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_host_config() const -> host_config { return hc_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_is_remote_mount() const -> bool {
|
||||||
|
return is_remote_mount_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_json() const -> json;
|
[[nodiscard]] auto get_json() const -> json;
|
||||||
|
|
||||||
[[nodiscard]] auto get_log_directory() const -> std::string;
|
[[nodiscard]] auto get_log_directory() const -> std::string {
|
||||||
|
return log_directory_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_low_frequency_interval_secs() const -> std::uint16_t;
|
[[nodiscard]] auto get_low_frequency_interval_secs() const -> std::uint32_t {
|
||||||
|
return std::max(1U, low_freq_interval_secs_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_max_cache_size_bytes() const -> std::uint64_t;
|
[[nodiscard]] auto get_max_cache_size_bytes() const -> std::uint64_t;
|
||||||
|
|
||||||
[[nodiscard]] auto get_max_upload_count() const -> std::uint8_t;
|
[[nodiscard]] auto get_max_upload_count() const -> std::uint8_t {
|
||||||
|
return std::max(std::uint8_t(1U), max_upload_count_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_med_frequency_interval_secs() const -> std::uint16_t;
|
[[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t {
|
||||||
|
return std::max(std::uint16_t(15U), online_check_retry_secs_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t;
|
[[nodiscard]] auto get_orphaned_file_retention_days() const -> std::uint16_t {
|
||||||
|
return std::min(static_cast<std::uint16_t>(31U),
|
||||||
|
std::max(static_cast<std::uint16_t>(1U),
|
||||||
|
orphaned_file_retention_days_));
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_orphaned_file_retention_days() const -> std::uint16_t;
|
[[nodiscard]] auto get_preferred_download_type() const -> download_type {
|
||||||
|
return download_type_from_string(preferred_download_type_,
|
||||||
|
download_type::fallback);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_preferred_download_type() const -> download_type;
|
[[nodiscard]] auto get_provider_type() const -> provider_type {
|
||||||
|
return prov_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider_type() const -> provider_type;
|
[[nodiscard]] auto get_read_ahead_count() const -> std::uint8_t {
|
||||||
|
return std::max(static_cast<std::uint8_t>(1U), read_ahead_count_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_remote_config() const -> remote::remote_config;
|
[[nodiscard]] auto get_remote_client_pool_size() const -> std::uint8_t {
|
||||||
|
return std::max(static_cast<std::uint8_t>(5U), remote_client_pool_size_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_remote_mount() const -> remote::remote_mount;
|
[[nodiscard]] auto get_remote_host_name_or_ip() const -> std::string {
|
||||||
|
return remote_host_name_or_ip_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_retry_read_count() const -> std::uint16_t;
|
[[nodiscard]] auto get_remote_max_connections() const -> std::uint8_t {
|
||||||
|
return std::max(static_cast<std::uint8_t>(1U), remote_max_connections_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_ring_buffer_file_size() const -> std::uint16_t;
|
[[nodiscard]] auto get_remote_port() const -> std::uint16_t {
|
||||||
|
return remote_port_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_s3_config() const -> s3_config;
|
[[nodiscard]] auto get_remote_receive_timeout_secs() const -> std::uint16_t {
|
||||||
|
return remote_receive_timeout_secs_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_sia_config() const -> sia_config;
|
[[nodiscard]] auto get_remote_send_timeout_secs() const -> std::uint16_t {
|
||||||
|
return remote_send_timeout_secs_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
|
[[nodiscard]] auto get_remote_token() const -> std::string {
|
||||||
|
return remote_token_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_retry_read_count() const -> std::uint16_t {
|
||||||
get_value_by_name(const std::string &name) const -> std::string;
|
return std::max(std::uint16_t(2), retry_read_count_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_version() const -> std::uint64_t;
|
[[nodiscard]] auto get_ring_buffer_file_size() const -> std::uint16_t {
|
||||||
|
return std::max(
|
||||||
|
static_cast<std::uint16_t>(64U),
|
||||||
|
std::min(static_cast<std::uint16_t>(1024U), ring_buffer_file_size_));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_s3_config() const -> s3_config { return s3_config_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_sia_config() const -> sia_config {
|
||||||
|
return sia_config_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_value_by_name(const std::string &name) -> std::string;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_version() const -> std::uint64_t { return version_; }
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
void set_api_auth(const std::string &value);
|
void set_api_auth(const std::string &api_auth) {
|
||||||
|
set_value(api_auth_, api_auth);
|
||||||
|
}
|
||||||
|
|
||||||
void set_api_port(std::uint16_t value);
|
void set_api_port(std::uint16_t api_port) { set_value(api_port_, api_port); }
|
||||||
|
|
||||||
void set_api_user(const std::string &value);
|
void set_api_user(const std::string &api_user) {
|
||||||
|
set_value(api_user_, api_user);
|
||||||
|
}
|
||||||
|
|
||||||
void set_download_timeout_secs(std::uint8_t value);
|
void set_chunk_downloader_timeout_secs(
|
||||||
|
std::uint8_t chunk_downloader_timeout_secs) {
|
||||||
|
set_value(download_timeout_secs_, chunk_downloader_timeout_secs);
|
||||||
|
}
|
||||||
|
|
||||||
void set_database_type(const database_type &value);
|
void
|
||||||
|
set_enable_chunk_downloader_timeout(bool enable_chunk_downloader_timeout) {
|
||||||
|
set_value(enable_chunk_downloader_timeout_,
|
||||||
|
enable_chunk_downloader_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
void set_enable_download_timeout(bool value);
|
void set_enable_comm_duration_events(bool enable_comm_duration_events) {
|
||||||
|
set_value(enable_comm_duration_events_, enable_comm_duration_events);
|
||||||
|
}
|
||||||
|
|
||||||
void set_enable_drive_events(bool value);
|
void set_enable_drive_events(bool enable_drive_events) {
|
||||||
|
set_value(enable_drive_events_, enable_drive_events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_enable_max_cache_size(bool enable_max_cache_size) {
|
||||||
|
set_value(enable_max_cache_size_, enable_max_cache_size);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
void set_enable_mount_manager(bool value);
|
void set_enable_mount_manager(bool enable_mount_manager) {
|
||||||
#endif // defined(_WIN32)
|
set_value(enable_mount_manager_, enable_mount_manager);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void set_event_level(const event_level &value);
|
void set_enable_remote_mount(bool enable_remote_mount);
|
||||||
|
|
||||||
void set_encrypt_config(encrypt_config value);
|
void set_event_level(const event_level &level) {
|
||||||
|
if (set_value(event_level_, level)) {
|
||||||
|
event_system::instance().raise<event_level_changed>(
|
||||||
|
event_level_to_string(level));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_eviction_delay_mins(std::uint32_t value);
|
void set_eviction_delay_mins(std::uint32_t eviction_delay_mins) {
|
||||||
|
set_value(eviction_delay_mins_, eviction_delay_mins);
|
||||||
|
}
|
||||||
|
|
||||||
void set_eviction_uses_accessed_time(bool value);
|
void set_eviction_uses_accessed_time(bool eviction_uses_accessed_time) {
|
||||||
|
set_value(eviction_uses_accessed_time_, eviction_uses_accessed_time);
|
||||||
|
}
|
||||||
|
|
||||||
void set_high_frequency_interval_secs(std::uint16_t value);
|
void
|
||||||
|
set_high_frequency_interval_secs(std::uint8_t high_frequency_interval_secs) {
|
||||||
|
set_value(high_freq_interval_secs_, high_frequency_interval_secs);
|
||||||
|
}
|
||||||
|
|
||||||
void set_host_config(host_config value);
|
#if defined(PROJECT_TESTING)
|
||||||
|
void set_host_config(host_config hc) {
|
||||||
|
config_changed_ = true;
|
||||||
|
hc_ = std::move(hc);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
void set_low_frequency_interval_secs(std::uint16_t value);
|
void set_s3_config(s3_config s3) {
|
||||||
|
config_changed_ = true;
|
||||||
|
s3_config_ = std::move(s3);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
void set_max_cache_size_bytes(std::uint64_t value);
|
void set_sia_config(sia_config sia) {
|
||||||
|
config_changed_ = true;
|
||||||
|
sia_config_ = std::move(sia);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
#endif // defined(PROJECT_TESTING)
|
||||||
|
|
||||||
void set_max_upload_count(std::uint8_t value);
|
void set_is_remote_mount(bool is_remote_mount);
|
||||||
|
|
||||||
void set_med_frequency_interval_secs(std::uint16_t value);
|
void
|
||||||
|
set_low_frequency_interval_secs(std::uint32_t low_frequency_interval_secs) {
|
||||||
|
set_value(low_freq_interval_secs_, low_frequency_interval_secs);
|
||||||
|
}
|
||||||
|
|
||||||
void set_online_check_retry_secs(std::uint16_t value);
|
void set_max_cache_size_bytes(std::uint64_t max_cache_size_bytes) {
|
||||||
|
set_value(max_cache_size_bytes_, max_cache_size_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
void set_orphaned_file_retention_days(std::uint16_t value);
|
void set_max_upload_count(std::uint8_t max_upload_count) {
|
||||||
|
set_value(max_upload_count_, max_upload_count);
|
||||||
|
}
|
||||||
|
|
||||||
void set_preferred_download_type(const download_type &value);
|
void set_online_check_retry_secs(std::uint16_t online_check_retry_secs) {
|
||||||
|
set_value(online_check_retry_secs_, online_check_retry_secs);
|
||||||
|
}
|
||||||
|
|
||||||
void set_remote_config(remote::remote_config value);
|
void
|
||||||
|
set_orphaned_file_retention_days(std::uint16_t orphaned_file_retention_days) {
|
||||||
|
set_value(orphaned_file_retention_days_, orphaned_file_retention_days);
|
||||||
|
}
|
||||||
|
|
||||||
void set_remote_mount(remote::remote_mount value);
|
void set_preferred_download_type(const download_type &dt) {
|
||||||
|
set_value(preferred_download_type_, download_type_to_string(dt));
|
||||||
|
}
|
||||||
|
|
||||||
void set_retry_read_count(std::uint16_t value);
|
void set_read_ahead_count(std::uint8_t read_ahead_count) {
|
||||||
|
set_value(read_ahead_count_, read_ahead_count);
|
||||||
|
}
|
||||||
|
|
||||||
void set_ring_buffer_file_size(std::uint16_t value);
|
void set_remote_client_pool_size(std::uint8_t remote_client_pool_size) {
|
||||||
|
set_value(remote_client_pool_size_, remote_client_pool_size);
|
||||||
|
}
|
||||||
|
|
||||||
void set_s3_config(s3_config value);
|
void set_ring_buffer_file_size(std::uint16_t ring_buffer_file_size) {
|
||||||
|
set_value(ring_buffer_file_size_, ring_buffer_file_size);
|
||||||
|
}
|
||||||
|
|
||||||
void set_sia_config(sia_config value);
|
void set_remote_host_name_or_ip(const std::string &remote_host_name_or_ip) {
|
||||||
|
set_value(remote_host_name_or_ip_, remote_host_name_or_ip);
|
||||||
|
}
|
||||||
|
|
||||||
void set_task_wait_ms(std::uint16_t value);
|
void set_remote_max_connections(std::uint8_t remote_max_connections) {
|
||||||
|
set_value(remote_max_connections_, remote_max_connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_remote_port(std::uint16_t remote_port) {
|
||||||
|
set_value(remote_port_, remote_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_remote_receive_timeout_secs(std::uint16_t remote_receive_timeout_secs) {
|
||||||
|
set_value(remote_receive_timeout_secs_, remote_receive_timeout_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_remote_send_timeout_secs(std::uint16_t remote_send_timeout_secs) {
|
||||||
|
set_value(remote_send_timeout_secs_, remote_send_timeout_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_remote_token(const std::string &remote_token) {
|
||||||
|
set_value(remote_token_, remote_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_retry_read_count(std::uint16_t retry_read_count) {
|
||||||
|
set_value(retry_read_count_, retry_read_count);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto set_value_by_name(const std::string &name,
|
[[nodiscard]] auto set_value_by_name(const std::string &name,
|
||||||
const std::string &value) -> std::string;
|
const std::string &value) -> std::string;
|
||||||
|
@ -52,23 +52,23 @@ public:
|
|||||||
~packet() = default;
|
~packet() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
data_buffer buffer_{};
|
data_buffer buffer_;
|
||||||
std::size_t decode_offset_{0U};
|
std::size_t decode_offset_ = 0U;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static auto decode_json(packet &response, json &json_data)
|
[[nodiscard]] static auto decode_json(packet &response,
|
||||||
-> int;
|
json &json_data) -> int;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
[[nodiscard]] auto current_pointer() -> unsigned char * {
|
[[nodiscard]] auto current_pointer() -> unsigned char * {
|
||||||
return (decode_offset_ < buffer_.size()) ? &buffer_.at(decode_offset_)
|
return (decode_offset_ < buffer_.size()) ? &buffer_[decode_offset_]
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto current_pointer() const -> const unsigned char * {
|
[[nodiscard]] auto current_pointer() const -> const unsigned char * {
|
||||||
return (decode_offset_ < buffer_.size()) ? &buffer_.at(decode_offset_)
|
return (decode_offset_ < buffer_.size()) ? &buffer_[decode_offset_]
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ public:
|
|||||||
return static_cast<std::uint32_t>(buffer_.size());
|
return static_cast<std::uint32_t>(buffer_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_buffer(data_buffer &buffer);
|
void transfer_into(data_buffer &buffer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto operator=(const data_buffer &buffer) noexcept -> packet &;
|
auto operator=(const data_buffer &buffer) noexcept -> packet &;
|
||||||
@ -226,6 +226,8 @@ public:
|
|||||||
return buffer_.at(index);
|
return buffer_.at(index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using packet = packet;
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_COMM_PACKET_PACKET_HPP_
|
#endif // REPERTORY_INCLUDE_COMM_PACKET_PACKET_HPP_
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#define REPERTORY_INCLUDE_COMM_PACKET_PACKET_CLIENT_HPP_
|
#define REPERTORY_INCLUDE_COMM_PACKET_PACKET_CLIENT_HPP_
|
||||||
|
|
||||||
#include "comm/packet/packet.hpp"
|
#include "comm/packet/packet.hpp"
|
||||||
#include "types/remote.hpp"
|
|
||||||
|
|
||||||
using boost::asio::ip::tcp;
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
@ -37,7 +36,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
packet_client(remote::remote_config cfg);
|
packet_client(std::string host_name_or_ip, std::uint8_t max_connections,
|
||||||
|
std::uint16_t port, std::uint16_t receive_timeout,
|
||||||
|
std::uint16_t send_timeout, std::string encryption_token);
|
||||||
|
|
||||||
~packet_client();
|
~packet_client();
|
||||||
|
|
||||||
@ -48,7 +49,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
boost::asio::io_context io_context_;
|
boost::asio::io_context io_context_;
|
||||||
remote::remote_config cfg_;
|
std::string host_name_or_ip_;
|
||||||
|
std::uint8_t max_connections_;
|
||||||
|
std::uint16_t port_;
|
||||||
|
std::uint16_t receive_timeout_;
|
||||||
|
std::uint16_t send_timeout_;
|
||||||
|
std::string encryption_token_;
|
||||||
std::string unique_id_;
|
std::string unique_id_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -69,21 +75,21 @@ private:
|
|||||||
|
|
||||||
void put_client(std::shared_ptr<client> &cli);
|
void put_client(std::shared_ptr<client> &cli);
|
||||||
|
|
||||||
[[nodiscard]] auto read_packet(client &cli, packet &response)
|
[[nodiscard]] auto read_packet(client &cli,
|
||||||
-> packet::error_type;
|
packet &response) -> packet::error_type;
|
||||||
|
|
||||||
void resolve();
|
void resolve();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto send(std::string_view method, std::uint32_t &service_flags)
|
[[nodiscard]] auto send(std::string_view method,
|
||||||
-> packet::error_type;
|
std::uint32_t &service_flags) -> packet::error_type;
|
||||||
|
|
||||||
[[nodiscard]] auto send(std::string_view method, packet &request,
|
[[nodiscard]] auto send(std::string_view method, packet &request,
|
||||||
std::uint32_t &service_flags) -> packet::error_type;
|
std::uint32_t &service_flags) -> packet::error_type;
|
||||||
|
|
||||||
[[nodiscard]] auto send(std::string_view method, packet &request,
|
[[nodiscard]] auto send(std::string_view method, packet &request,
|
||||||
packet &response, std::uint32_t &service_flags)
|
packet &response,
|
||||||
-> packet::error_type;
|
std::uint32_t &service_flags) -> packet::error_type;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -52,8 +52,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct connection {
|
struct connection {
|
||||||
connection(io_context &ctx, tcp::acceptor &acceptor_)
|
connection(boost::asio::io_service &io_service, tcp::acceptor &acceptor_)
|
||||||
: socket(ctx), acceptor(acceptor_) {}
|
: socket(io_service), acceptor(acceptor_) {}
|
||||||
|
|
||||||
tcp::socket socket;
|
tcp::socket socket;
|
||||||
tcp::acceptor &acceptor;
|
tcp::acceptor &acceptor;
|
||||||
@ -68,7 +68,7 @@ private:
|
|||||||
std::string encryption_token_;
|
std::string encryption_token_;
|
||||||
closed_callback closed_;
|
closed_callback closed_;
|
||||||
message_handler_callback message_handler_;
|
message_handler_callback message_handler_;
|
||||||
io_context io_context_;
|
boost::asio::io_context io_context_;
|
||||||
std::unique_ptr<std::thread> server_thread_;
|
std::unique_ptr<std::thread> server_thread_;
|
||||||
std::vector<std::thread> service_threads_;
|
std::vector<std::thread> service_threads_;
|
||||||
std::recursive_mutex connection_mutex_;
|
std::recursive_mutex connection_mutex_;
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_FILE_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_FILE_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_file_db(const app_config &cfg)
|
|
||||||
-> std::unique_ptr<i_file_db>;
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_FILE_DB_HPP_
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_FILE_MGR_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_FILE_MGR_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_mgr_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
create_file_mgr_db(const app_config &cfg) -> std::unique_ptr<i_file_mgr_db>;
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_FILE_MGR_DB_HPP_
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class i_file_db {
|
|
||||||
INTERFACE_SETUP(i_file_db);
|
|
||||||
|
|
||||||
public:
|
|
||||||
struct file_info final {
|
|
||||||
std::string api_path;
|
|
||||||
bool directory;
|
|
||||||
std::string source_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_data final {
|
|
||||||
std::string api_path;
|
|
||||||
std::uint64_t file_size{};
|
|
||||||
std::vector<
|
|
||||||
std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
|
|
||||||
iv_list{};
|
|
||||||
std::string source_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] virtual auto add_directory(const std::string &api_path,
|
|
||||||
const std::string &source_path)
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto add_or_update_file(const file_data &data)
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
virtual void clear() = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto count() const -> std::uint64_t = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
get_directory_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
get_directory_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_file_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_file_data(const std::string &api_path,
|
|
||||||
file_data &data) const
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
get_file_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_item_list() const
|
|
||||||
-> std::vector<file_info> = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto remove_item(const std::string &api_path)
|
|
||||||
-> api_error = 0;
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class i_file_mgr_db {
|
|
||||||
INTERFACE_SETUP(i_file_mgr_db);
|
|
||||||
|
|
||||||
public:
|
|
||||||
struct resume_entry final {
|
|
||||||
std::string api_path;
|
|
||||||
std::uint64_t chunk_size{};
|
|
||||||
boost::dynamic_bitset<> read_state;
|
|
||||||
std::string source_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct upload_active_entry final {
|
|
||||||
std::string api_path;
|
|
||||||
std::string source_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct upload_entry final {
|
|
||||||
std::string api_path;
|
|
||||||
std::string source_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] virtual auto add_resume(const resume_entry &entry) -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto add_upload(const upload_entry &entry) -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto add_upload_active(const upload_active_entry &entry)
|
|
||||||
-> bool = 0;
|
|
||||||
|
|
||||||
virtual void clear() = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_next_upload() const
|
|
||||||
-> std::optional<upload_entry> = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_resume_list() const
|
|
||||||
-> std::vector<resume_entry> = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_upload(const std::string &api_path) const
|
|
||||||
-> std::optional<upload_entry> = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_upload_active_list() const
|
|
||||||
-> std::vector<upload_active_entry> = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto remove_resume(const std::string &api_path)
|
|
||||||
-> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto remove_upload(const std::string &api_path)
|
|
||||||
-> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto remove_upload_active(const std::string &api_path)
|
|
||||||
-> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto rename_resume(const std::string &from_api_path,
|
|
||||||
const std::string &to_api_path)
|
|
||||||
-> bool = 0;
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_I_FILE_MGR_DB_HPP_
|
|
@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
class rdb_file_db final : public i_file_db {
|
|
||||||
public:
|
|
||||||
rdb_file_db(const app_config &cfg);
|
|
||||||
~rdb_file_db() override;
|
|
||||||
|
|
||||||
rdb_file_db(const rdb_file_db &) = delete;
|
|
||||||
rdb_file_db(rdb_file_db &&) = delete;
|
|
||||||
auto operator=(const rdb_file_db &) -> rdb_file_db & = delete;
|
|
||||||
auto operator=(rdb_file_db &&) -> rdb_file_db & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const app_config &cfg_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<rocksdb::TransactionDB> db_{nullptr};
|
|
||||||
rocksdb::ColumnFamilyHandle *directory_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *file_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *path_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *source_family_{};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void create_or_open(bool clear);
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
|
||||||
-> std::shared_ptr<rocksdb::Iterator>;
|
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
|
||||||
perform_action(std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status()> action) -> api_error;
|
|
||||||
|
|
||||||
[[nodiscard]] auto perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action)
|
|
||||||
-> api_error;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_item(const std::string &api_path,
|
|
||||||
const std::string &source_path,
|
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto
|
|
||||||
add_directory(const std::string &api_path,
|
|
||||||
const std::string &source_path) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
add_or_update_file(const i_file_db::file_data &data) -> api_error override;
|
|
||||||
|
|
||||||
void clear() override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto count() const -> std::uint64_t override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_directory_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_file_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_file_data(const std::string &api_path,
|
|
||||||
i_file_db::file_data &data) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_file_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_item_list() const -> std::vector<i_file_db::file_info> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
get_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
remove_item(const std::string &api_path) -> api_error override;
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_MGR_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_MGR_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_mgr_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
class rdb_file_mgr_db final : public i_file_mgr_db {
|
|
||||||
public:
|
|
||||||
rdb_file_mgr_db(const app_config &cfg);
|
|
||||||
~rdb_file_mgr_db() override;
|
|
||||||
|
|
||||||
rdb_file_mgr_db(const rdb_file_mgr_db &) = delete;
|
|
||||||
rdb_file_mgr_db(rdb_file_mgr_db &&) = delete;
|
|
||||||
auto operator=(const rdb_file_mgr_db &) -> rdb_file_mgr_db & = delete;
|
|
||||||
auto operator=(rdb_file_mgr_db &&) -> rdb_file_mgr_db & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const app_config &cfg_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<rocksdb::TransactionDB> db_{nullptr};
|
|
||||||
std::atomic<std::uint64_t> id_{0U};
|
|
||||||
rocksdb::ColumnFamilyHandle *resume_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *upload_active_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *upload_family_{};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void create_or_open(bool clear);
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
|
||||||
-> std::shared_ptr<rocksdb::Iterator>;
|
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
|
||||||
perform_action(std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status()> action) -> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action) -> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_resume(const std::string &api_path,
|
|
||||||
rocksdb::Transaction *txn)
|
|
||||||
-> rocksdb::Status;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_resume(const resume_entry &entry,
|
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto add_resume(const resume_entry &entry) -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_upload(const upload_entry &entry) -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_upload_active(const upload_active_entry &entry)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
void clear() override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_next_upload() const
|
|
||||||
-> std::optional<upload_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_resume_list() const
|
|
||||||
-> std::vector<resume_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_upload(const std::string &api_path) const
|
|
||||||
-> std::optional<upload_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_upload_active_list() const
|
|
||||||
-> std::vector<upload_active_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_resume(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_upload(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_upload_active(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto rename_resume(const std::string &from_api_path,
|
|
||||||
const std::string &to_api_path)
|
|
||||||
-> bool override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_MGR_DB_HPP_
|
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_db.hpp"
|
|
||||||
#include "utils/db/sqlite/db_common.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
class sqlite_file_db final : public i_file_db {
|
|
||||||
public:
|
|
||||||
sqlite_file_db(const app_config &cfg);
|
|
||||||
~sqlite_file_db() override;
|
|
||||||
|
|
||||||
sqlite_file_db(const sqlite_file_db &) = delete;
|
|
||||||
sqlite_file_db(sqlite_file_db &&) = delete;
|
|
||||||
auto operator=(const sqlite_file_db &) -> sqlite_file_db & = delete;
|
|
||||||
auto operator=(sqlite_file_db &&) -> sqlite_file_db & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
utils::db::sqlite::db3_t db_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto add_directory(const std::string &api_path,
|
|
||||||
const std::string &source_path)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_or_update_file(const i_file_db::file_data &data)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
void clear() override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto count() const -> std::uint64_t override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_file_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_file_data(const std::string &api_path,
|
|
||||||
i_file_db::file_data &data) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_file_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_item_list() const
|
|
||||||
-> std::vector<i_file_db::file_info> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_item(const std::string &api_path)
|
|
||||||
-> api_error override;
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_
|
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_MGR_DB_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_MGR_DB_HPP_
|
|
||||||
|
|
||||||
#include "db/i_file_mgr_db.hpp"
|
|
||||||
#include "utils/db/sqlite/db_common.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
class sqlite_file_mgr_db final : public i_file_mgr_db {
|
|
||||||
public:
|
|
||||||
sqlite_file_mgr_db(const app_config &cfg);
|
|
||||||
~sqlite_file_mgr_db() override;
|
|
||||||
|
|
||||||
sqlite_file_mgr_db(const sqlite_file_mgr_db &) = delete;
|
|
||||||
sqlite_file_mgr_db(sqlite_file_mgr_db &&) = delete;
|
|
||||||
auto operator=(const sqlite_file_mgr_db &) -> sqlite_file_mgr_db & = delete;
|
|
||||||
auto operator=(sqlite_file_mgr_db &&) -> sqlite_file_mgr_db & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
utils::db::sqlite::db3_t db_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto add_resume(const resume_entry &entry) -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_upload(const upload_entry &entry) -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto add_upload_active(const upload_active_entry &entry)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
void clear() override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_next_upload() const
|
|
||||||
-> std::optional<upload_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_resume_list() const
|
|
||||||
-> std::vector<resume_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_upload(const std::string &api_path) const
|
|
||||||
-> std::optional<upload_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_upload_active_list() const
|
|
||||||
-> std::vector<upload_active_entry> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_resume(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_upload(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_upload_active(const std::string &api_path)
|
|
||||||
-> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto rename_resume(const std::string &from_api_path,
|
|
||||||
const std::string &to_api_path)
|
|
||||||
-> bool override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_MGR_DB_HPP_
|
|
@ -19,8 +19,8 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_RDB_META_DB_HPP_
|
#ifndef REPERTORY_INCLUDE_DB_RDB_META_DB_HPP_
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_RDB_META_DB_HPP_
|
#define REPERTORY_INCLUDE_DB_RDB_META_DB_HPP_
|
||||||
|
|
||||||
#include "db/i_meta_db.hpp"
|
#include "db/i_meta_db.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
@ -40,10 +40,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const app_config &cfg_;
|
const app_config &cfg_;
|
||||||
|
std::unique_ptr<rocksdb::DB> db_{nullptr};
|
||||||
private:
|
rocksdb::ColumnFamilyHandle *default_family_{};
|
||||||
std::unique_ptr<rocksdb::TransactionDB> db_{nullptr};
|
|
||||||
rocksdb::ColumnFamilyHandle *meta_family_{};
|
|
||||||
rocksdb::ColumnFamilyHandle *pinned_family_{};
|
rocksdb::ColumnFamilyHandle *pinned_family_{};
|
||||||
rocksdb::ColumnFamilyHandle *size_family_{};
|
rocksdb::ColumnFamilyHandle *size_family_{};
|
||||||
rocksdb::ColumnFamilyHandle *source_family_{};
|
rocksdb::ColumnFamilyHandle *source_family_{};
|
||||||
@ -61,21 +59,8 @@ private:
|
|||||||
perform_action(std::string_view function_name,
|
perform_action(std::string_view function_name,
|
||||||
std::function<rocksdb::Status()> action) -> api_error;
|
std::function<rocksdb::Status()> action) -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action)
|
|
||||||
-> api_error;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_api_path(const std::string &api_path,
|
|
||||||
const std::string &source_path,
|
|
||||||
rocksdb::Transaction *txn)
|
|
||||||
-> rocksdb::Status;
|
|
||||||
|
|
||||||
[[nodiscard]] auto update_item_meta(const std::string &api_path,
|
[[nodiscard]] auto update_item_meta(const std::string &api_path,
|
||||||
json json_data,
|
json json_data) -> api_error;
|
||||||
rocksdb::Transaction *base_txn = nullptr,
|
|
||||||
rocksdb::Status *status = nullptr)
|
|
||||||
-> api_error;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void clear() override;
|
void clear() override;
|
||||||
@ -124,4 +109,4 @@ public:
|
|||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_RDB_META_DB_HPP_
|
#endif // REPERTORY_INCLUDE_DB_RDB_META_DB_HPP_
|
@ -19,8 +19,8 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifndef REPERTORY_INCLUDE_DB_IMPL_SQLITE_META_DB_HPP_
|
#ifndef REPERTORY_INCLUDE_DB_SQLITE_META_DB_HPP_
|
||||||
#define REPERTORY_INCLUDE_DB_IMPL_SQLITE_META_DB_HPP_
|
#define REPERTORY_INCLUDE_DB_SQLITE_META_DB_HPP_
|
||||||
|
|
||||||
#include "db/i_meta_db.hpp"
|
#include "db/i_meta_db.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
@ -94,4 +94,4 @@ public:
|
|||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_DB_IMPL_SQLITE_META_DB_HPP_
|
#endif // REPERTORY_INCLUDE_DB_SQLITE_META_DB_HPP_
|
@ -34,7 +34,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
struct open_directory final {
|
struct open_directory final {
|
||||||
std::shared_ptr<directory_iterator> iterator;
|
std::shared_ptr<directory_iterator> iterator;
|
||||||
std::vector<std::uint64_t> handles;
|
std::vector<std::uint64_t> handles{};
|
||||||
std::chrono::system_clock::time_point last_update{
|
std::chrono::system_clock::time_point last_update{
|
||||||
std::chrono::system_clock::now()};
|
std::chrono::system_clock::now()};
|
||||||
};
|
};
|
||||||
@ -60,8 +60,8 @@ public:
|
|||||||
void execute_action(const std::string &api_path,
|
void execute_action(const std::string &api_path,
|
||||||
const execute_callback &execute);
|
const execute_callback &execute);
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory(std::uint64_t handle)
|
[[nodiscard]] auto
|
||||||
-> std::shared_ptr<directory_iterator>;
|
get_directory(std::uint64_t handle) -> std::shared_ptr<directory_iterator>;
|
||||||
|
|
||||||
[[nodiscard]] auto remove_directory(const std::string &api_path)
|
[[nodiscard]] auto remove_directory(const std::string &api_path)
|
||||||
-> std::shared_ptr<directory_iterator>;
|
-> std::shared_ptr<directory_iterator>;
|
||||||
|
@ -31,23 +31,22 @@ class i_provider;
|
|||||||
|
|
||||||
class eviction final : public single_thread_service_base {
|
class eviction final : public single_thread_service_base {
|
||||||
public:
|
public:
|
||||||
eviction(i_provider &provider, const app_config &config,
|
eviction(i_provider &provider, const app_config &config, i_file_manager &fm)
|
||||||
i_file_manager &file_mgr)
|
|
||||||
: single_thread_service_base("eviction"),
|
: single_thread_service_base("eviction"),
|
||||||
|
provider_(provider),
|
||||||
config_(config),
|
config_(config),
|
||||||
file_mgr_(file_mgr),
|
fm_(fm) {}
|
||||||
provider_(provider) {}
|
|
||||||
|
|
||||||
~eviction() override = default;
|
~eviction() override = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const app_config &config_;
|
|
||||||
i_file_manager &file_mgr_;
|
|
||||||
i_provider &provider_;
|
i_provider &provider_;
|
||||||
|
const app_config &config_;
|
||||||
|
i_file_manager &fm_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto check_minimum_requirements(const std::string &file_path)
|
[[nodiscard]] auto
|
||||||
-> bool;
|
check_minimum_requirements(const std::string &file_path) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto get_filtered_cached_files() -> std::deque<std::string>;
|
[[nodiscard]] auto get_filtered_cached_files() -> std::deque<std::string>;
|
||||||
|
|
||||||
|
@ -29,8 +29,6 @@
|
|||||||
#include "drives/fuse/remotefuse/i_remote_instance.hpp"
|
#include "drives/fuse/remotefuse/i_remote_instance.hpp"
|
||||||
#include "drives/remote/remote_open_file_table.hpp"
|
#include "drives/remote/remote_open_file_table.hpp"
|
||||||
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
|
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "types/remote.hpp"
|
#include "types/remote.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/base64.hpp"
|
#include "utils/base64.hpp"
|
||||||
@ -54,7 +52,7 @@ public:
|
|||||||
: config_(config),
|
: config_(config),
|
||||||
drive_(drv),
|
drive_(drv),
|
||||||
mount_location_(std::move(mount_location)),
|
mount_location_(std::move(mount_location)),
|
||||||
client_pool_(config.get_remote_mount().client_pool_size) {
|
client_pool_(config.get_remote_client_pool_size()) {
|
||||||
event_system::instance().raise<service_started>("remote_server_base");
|
event_system::instance().raise<service_started>("remote_server_base");
|
||||||
handler_lookup_.insert(
|
handler_lookup_.insert(
|
||||||
{"::winfsp_can_delete",
|
{"::winfsp_can_delete",
|
||||||
@ -1359,8 +1357,7 @@ public:
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
packet_server_ = std::make_unique<packet_server>(
|
packet_server_ = std::make_unique<packet_server>(
|
||||||
config_.get_remote_mount().api_port,
|
config_.get_remote_port(), config_.get_remote_token(), 10,
|
||||||
config_.get_remote_mount().encryption_token, 10,
|
|
||||||
[this](const std::string &client_id) {
|
[this](const std::string &client_id) {
|
||||||
return this->closed_handler(client_id);
|
return this->closed_handler(client_id);
|
||||||
},
|
},
|
||||||
|
@ -32,12 +32,9 @@ enum class event_level {
|
|||||||
trace,
|
trace,
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] auto
|
auto event_level_from_string(std::string level) -> event_level;
|
||||||
event_level_from_string(std::string level,
|
|
||||||
event_level default_level = event_level::info)
|
|
||||||
-> event_level;
|
|
||||||
|
|
||||||
[[nodiscard]] auto event_level_to_string(event_level level) -> std::string;
|
auto event_level_to_string(event_level level) -> std::string;
|
||||||
|
|
||||||
class event {
|
class event {
|
||||||
protected:
|
protected:
|
||||||
@ -75,18 +72,4 @@ public:
|
|||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
|
||||||
template <> struct adl_serializer<std::atomic<repertory::event_level>> {
|
|
||||||
static void to_json(json &data,
|
|
||||||
const std::atomic<repertory::event_level> &value) {
|
|
||||||
data = repertory::event_level_to_string(value.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data,
|
|
||||||
std::atomic<repertory::event_level> &value) {
|
|
||||||
value.store(repertory::event_level_from_string(data.get<std::string>()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_EVENTS_EVENT_HPP_
|
#endif // REPERTORY_INCLUDE_EVENTS_EVENT_HPP_
|
||||||
|
@ -44,7 +44,6 @@ using event_consumer = event_system::event_consumer;
|
|||||||
#define E_FROM_STRING(t) t
|
#define E_FROM_STRING(t) t
|
||||||
#define E_FROM_UINT16(t) std::to_string(t)
|
#define E_FROM_UINT16(t) std::to_string(t)
|
||||||
#define E_FROM_UINT64(t) std::to_string(t)
|
#define E_FROM_UINT64(t) std::to_string(t)
|
||||||
#define E_FROM_DOWNLOAD_TYPE(t) download_type_to_string(t)
|
|
||||||
|
|
||||||
#define E_PROP(type, name, short_name, ts) \
|
#define E_PROP(type, name, short_name, ts) \
|
||||||
private: \
|
private: \
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_CACHE_SIZE_MGR_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_CACHE_SIZE_MGR_HPP_
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class app_config;
|
|
||||||
|
|
||||||
class cache_size_mgr final {
|
|
||||||
public:
|
|
||||||
cache_size_mgr(const cache_size_mgr &) = delete;
|
|
||||||
cache_size_mgr(cache_size_mgr &&) = delete;
|
|
||||||
auto operator=(const cache_size_mgr &) -> cache_size_mgr & = delete;
|
|
||||||
auto operator=(cache_size_mgr &&) -> cache_size_mgr & = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
cache_size_mgr() = default;
|
|
||||||
|
|
||||||
~cache_size_mgr() { stop(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static cache_size_mgr instance_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
app_config *cfg_{nullptr};
|
|
||||||
std::uint64_t cache_size_{0U};
|
|
||||||
mutable std::mutex mtx_;
|
|
||||||
std::condition_variable notify_;
|
|
||||||
stop_type stop_requested_{false};
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto expand(std::uint64_t size) -> api_error;
|
|
||||||
|
|
||||||
void initialize(app_config *cfg);
|
|
||||||
|
|
||||||
[[nodiscard]] static auto instance() -> cache_size_mgr & { return instance_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto shrink(std::uint64_t size) -> api_error;
|
|
||||||
|
|
||||||
[[nodiscard]] auto size() const -> std::uint64_t;
|
|
||||||
|
|
||||||
void stop();
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_FILE_MANAGER_CACHE_SIZE_MGR_HPP_
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
|
||||||
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class i_provider;
|
|
||||||
class i_upload_manager;
|
|
||||||
|
|
||||||
class direct_open_file final : public ring_buffer_base {
|
|
||||||
public:
|
|
||||||
direct_open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider);
|
|
||||||
|
|
||||||
~direct_open_file() override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
direct_open_file() = delete;
|
|
||||||
direct_open_file(const direct_open_file &) noexcept = delete;
|
|
||||||
direct_open_file(direct_open_file &&) noexcept = delete;
|
|
||||||
auto operator=(direct_open_file &&) noexcept -> direct_open_file & = delete;
|
|
||||||
auto
|
|
||||||
operator=(const direct_open_file &) noexcept -> direct_open_file & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<data_buffer, min_ring_size> ring_data_;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] auto on_check_start() -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_chunk_downloaded(std::size_t /* chunk */,
|
|
||||||
const data_buffer & /* buffer */) -> api_error override {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto native_operation(native_operation_callback /* callback */)
|
|
||||||
-> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto native_operation(std::uint64_t /* new_file_size */,
|
|
||||||
native_operation_callback /* callback */)
|
|
||||||
-> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_FILE_MANAGER_DIRECT_OPEN_FILE_HPP_
|
|
@ -32,6 +32,23 @@ E_SIMPLE2(download_begin, info, true,
|
|||||||
std::string, dest_path, dest, E_FROM_STRING
|
std::string, dest_path, dest, E_FROM_STRING
|
||||||
);
|
);
|
||||||
|
|
||||||
|
E_SIMPLE5(download_chunk_begin, debug, true,
|
||||||
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
|
std::size_t, chunk, chunk, E_FROM_SIZE_T,
|
||||||
|
std::size_t, total, total, E_FROM_SIZE_T,
|
||||||
|
std::size_t, complete, complete, E_FROM_SIZE_T
|
||||||
|
);
|
||||||
|
|
||||||
|
E_SIMPLE6(download_chunk_end, debug, true,
|
||||||
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
|
std::size_t, chunk, chunk, E_FROM_SIZE_T,
|
||||||
|
std::size_t, total, total, E_FROM_SIZE_T,
|
||||||
|
std::size_t, complete, complete, E_FROM_SIZE_T,
|
||||||
|
api_error, result, result, E_FROM_API_FILE_ERROR
|
||||||
|
);
|
||||||
|
|
||||||
E_SIMPLE3(download_end, info, true,
|
E_SIMPLE3(download_end, info, true,
|
||||||
std::string, api_path, ap, E_FROM_STRING,
|
std::string, api_path, ap, E_FROM_STRING,
|
||||||
std::string, dest_path, dest, E_FROM_STRING,
|
std::string, dest_path, dest, E_FROM_STRING,
|
||||||
@ -74,12 +91,6 @@ E_SIMPLE2(download_resume_removed, debug, true,
|
|||||||
E_SIMPLE1(item_timeout, trace, true,
|
E_SIMPLE1(item_timeout, trace, true,
|
||||||
std::string, api_path, ap, E_FROM_STRING
|
std::string, api_path, ap, E_FROM_STRING
|
||||||
);
|
);
|
||||||
|
|
||||||
E_SIMPLE3(download_type_selected, debug, true,
|
|
||||||
std::string, api_path, ap, E_FROM_STRING,
|
|
||||||
std::string, source, src, E_FROM_STRING,
|
|
||||||
download_type, download_type, type, E_FROM_DOWNLOAD_TYPE
|
|
||||||
);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -22,14 +22,15 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
#define REPERTORY_INCLUDE_FILE_MANAGER_FILE_MANAGER_HPP_
|
||||||
|
|
||||||
#include "db/i_file_mgr_db.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/events.hpp"
|
#include "events/events.hpp"
|
||||||
#include "file_manager/i_file_manager.hpp"
|
#include "file_manager/i_file_manager.hpp"
|
||||||
#include "file_manager/i_open_file.hpp"
|
#include "file_manager/i_open_file.hpp"
|
||||||
#include "file_manager/i_upload_manager.hpp"
|
#include "file_manager/i_upload_manager.hpp"
|
||||||
#include "file_manager/upload.hpp"
|
#include "file_manager/upload.hpp"
|
||||||
|
#include "platform/platform.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/db/sqlite/db_common.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
@ -56,7 +57,7 @@ private:
|
|||||||
i_provider &provider_;
|
i_provider &provider_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<i_file_mgr_db> mgr_db_;
|
utils::db::sqlite::db3_t db_;
|
||||||
std::atomic<std::uint64_t> next_handle_{0U};
|
std::atomic<std::uint64_t> next_handle_{0U};
|
||||||
mutable std::recursive_mutex open_file_mtx_;
|
mutable std::recursive_mutex open_file_mtx_;
|
||||||
std::unordered_map<std::string, std::shared_ptr<i_closeable_open_file>>
|
std::unordered_map<std::string, std::shared_ptr<i_closeable_open_file>>
|
||||||
@ -68,7 +69,7 @@ private:
|
|||||||
std::unique_ptr<std::thread> upload_thread_;
|
std::unique_ptr<std::thread> upload_thread_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto close_all(const std::string &api_path) -> bool;
|
void close_all(const std::string &api_path);
|
||||||
|
|
||||||
void close_timed_out_files();
|
void close_timed_out_files();
|
||||||
|
|
||||||
@ -85,9 +86,6 @@ private:
|
|||||||
void queue_upload(const std::string &api_path, const std::string &source_path,
|
void queue_upload(const std::string &api_path, const std::string &source_path,
|
||||||
bool no_lock);
|
bool no_lock);
|
||||||
|
|
||||||
void remove_resume(const std::string &api_path,
|
|
||||||
const std::string &source_path, bool no_lock);
|
|
||||||
|
|
||||||
void remove_upload(const std::string &api_path, bool no_lock);
|
void remove_upload(const std::string &api_path, bool no_lock);
|
||||||
|
|
||||||
void swap_renamed_items(std::string from_api_path, std::string to_api_path,
|
void swap_renamed_items(std::string from_api_path, std::string to_api_path,
|
||||||
@ -108,11 +106,6 @@ public:
|
|||||||
void remove_resume(const std::string &api_path,
|
void remove_resume(const std::string &api_path,
|
||||||
const std::string &source_path) override;
|
const std::string &source_path) override;
|
||||||
|
|
||||||
static auto remove_source_and_shrink_cache(const std::string &api_path,
|
|
||||||
const std::string &source_path,
|
|
||||||
std::uint64_t file_size,
|
|
||||||
bool allocated) -> bool;
|
|
||||||
|
|
||||||
void remove_upload(const std::string &api_path) override;
|
void remove_upload(const std::string &api_path) override;
|
||||||
|
|
||||||
void store_resume(const i_open_file &file) override;
|
void store_resume(const i_open_file &file) override;
|
||||||
@ -139,8 +132,7 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_open_handle_count() const -> std::size_t;
|
[[nodiscard]] auto get_open_handle_count() const -> std::size_t;
|
||||||
|
|
||||||
[[nodiscard]] auto get_stored_downloads() const
|
[[nodiscard]] auto get_stored_downloads() const -> std::vector<json>;
|
||||||
-> std::vector<i_file_mgr_db::resume_entry>;
|
|
||||||
|
|
||||||
[[nodiscard]] auto has_no_open_file_handles() const -> bool override;
|
[[nodiscard]] auto has_no_open_file_handles() const -> bool override;
|
||||||
|
|
||||||
|
@ -62,12 +62,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] virtual auto get_source_path() const -> std::string = 0;
|
[[nodiscard]] virtual auto get_source_path() const -> std::string = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_complete() const -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_directory() const -> bool = 0;
|
[[nodiscard]] virtual auto is_directory() const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_write_supported() const -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto has_handle(std::uint64_t handle) const -> bool = 0;
|
[[nodiscard]] virtual auto has_handle(std::uint64_t handle) const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto
|
||||||
@ -97,8 +93,6 @@ class i_closeable_open_file : public i_open_file {
|
|||||||
public:
|
public:
|
||||||
virtual void add(std::uint64_t handle, open_file_data ofd) = 0;
|
virtual void add(std::uint64_t handle, open_file_data ofd) = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_allocated() const -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto can_close() const -> bool = 0;
|
[[nodiscard]] virtual auto can_close() const -> bool = 0;
|
||||||
|
|
||||||
virtual auto close() -> bool = 0;
|
virtual auto close() -> bool = 0;
|
||||||
@ -106,8 +100,12 @@ public:
|
|||||||
[[nodiscard]] virtual auto get_handles() const
|
[[nodiscard]] virtual auto get_handles() const
|
||||||
-> std::vector<std::uint64_t> = 0;
|
-> std::vector<std::uint64_t> = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto is_complete() const -> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto is_modified() const -> bool = 0;
|
[[nodiscard]] virtual auto is_modified() const -> bool = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto is_write_supported() const -> bool = 0;
|
||||||
|
|
||||||
virtual void remove(std::uint64_t handle) = 0;
|
virtual void remove(std::uint64_t handle) = 0;
|
||||||
|
|
||||||
virtual void remove_all() = 0;
|
virtual void remove_all() = 0;
|
||||||
|
@ -29,14 +29,14 @@ class i_upload_manager {
|
|||||||
INTERFACE_SETUP(i_upload_manager);
|
INTERFACE_SETUP(i_upload_manager);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void queue_upload(const i_open_file &file) = 0;
|
virtual void queue_upload(const i_open_file &o) = 0;
|
||||||
|
|
||||||
virtual void remove_resume(const std::string &api_path,
|
virtual void remove_resume(const std::string &api_path,
|
||||||
const std::string &source_path) = 0;
|
const std::string &source_path) = 0;
|
||||||
|
|
||||||
virtual void remove_upload(const std::string &api_path) = 0;
|
virtual void remove_upload(const std::string &api_path) = 0;
|
||||||
|
|
||||||
virtual void store_resume(const i_open_file &file) = 0;
|
virtual void store_resume(const i_open_file &o) = 0;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/types/file/i_file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
@ -68,55 +67,45 @@ private:
|
|||||||
i_upload_manager &mgr_;
|
i_upload_manager &mgr_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool allocated{false};
|
bool notified_ = false;
|
||||||
std::unique_ptr<utils::file::i_file> nf_;
|
|
||||||
bool notified_{false};
|
|
||||||
std::size_t read_chunk_{};
|
std::size_t read_chunk_{};
|
||||||
boost::dynamic_bitset<> read_state_;
|
boost::dynamic_bitset<> read_state_;
|
||||||
std::unique_ptr<std::thread> reader_thread_;
|
std::unique_ptr<std::thread> reader_thread_;
|
||||||
mutable std::recursive_mutex rw_mtx_;
|
std::unique_ptr<std::thread> download_thread_;
|
||||||
stop_type stop_requested_{false};
|
stop_type stop_requested_ = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto adjust_cache_size(std::uint64_t file_size,
|
|
||||||
bool shrink) -> api_error;
|
|
||||||
|
|
||||||
[[nodiscard]] auto check_start() -> api_error;
|
|
||||||
|
|
||||||
void download_chunk(std::size_t chunk, bool skip_active, bool should_reset);
|
void download_chunk(std::size_t chunk, bool skip_active, bool should_reset);
|
||||||
|
|
||||||
void download_range(std::size_t begin_chunk, std::size_t end_chunk,
|
void download_range(std::size_t start_chunk, std::size_t end_chunk,
|
||||||
bool should_reset);
|
bool should_reset);
|
||||||
|
|
||||||
void set_modified();
|
void set_modified();
|
||||||
|
|
||||||
void set_read_state(std::size_t chunk);
|
void update_background_reader(std::size_t read_chunk);
|
||||||
|
|
||||||
void set_read_state(boost::dynamic_bitset<> read_state);
|
protected:
|
||||||
|
auto is_download_complete() const -> bool override {
|
||||||
void update_reader(std::size_t chunk);
|
return read_state_.all();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto close() -> bool override;
|
auto close() -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_allocated() const -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto is_complete() const -> bool override;
|
[[nodiscard]] auto is_complete() const -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto is_write_supported() const -> bool override {
|
auto is_write_supported() const -> bool override { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto native_operation(native_operation_callback callback)
|
||||||
native_operation(native_operation_callback callback) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto native_operation(std::uint64_t new_file_size,
|
||||||
native_operation(std::uint64_t new_file_size,
|
native_operation_callback callback)
|
||||||
native_operation_callback callback) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
void remove(std::uint64_t handle) override;
|
void remove(std::uint64_t handle) override;
|
||||||
|
|
||||||
|
@ -24,18 +24,20 @@
|
|||||||
|
|
||||||
#include "file_manager/i_open_file.hpp"
|
#include "file_manager/i_open_file.hpp"
|
||||||
|
|
||||||
|
#include "utils/types/file/i_file.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
|
|
||||||
class open_file_base : public i_closeable_open_file {
|
class open_file_base : public i_closeable_open_file {
|
||||||
public:
|
public:
|
||||||
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi, i_provider &provider, bool disable_io);
|
filesystem_item fsi, i_provider &provider);
|
||||||
|
|
||||||
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi,
|
filesystem_item fsi,
|
||||||
std::map<std::uint64_t, open_file_data> open_data,
|
std::map<std::uint64_t, open_file_data> open_data,
|
||||||
i_provider &provider, bool disable_io);
|
i_provider &provider);
|
||||||
|
|
||||||
~open_file_base() override = default;
|
~open_file_base() override = default;
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ public:
|
|||||||
[[nodiscard]] auto get_result() -> api_error;
|
[[nodiscard]] auto get_result() -> api_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::uint64_t chunk_size_;
|
std::uint64_t chunk_size_;
|
||||||
std::uint8_t chunk_timeout_;
|
std::uint8_t chunk_timeout_;
|
||||||
filesystem_item fsi_;
|
filesystem_item fsi_;
|
||||||
@ -105,19 +107,21 @@ private:
|
|||||||
i_provider &provider_;
|
i_provider &provider_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::size_t, std::shared_ptr<download>> active_downloads_;
|
|
||||||
api_error error_{api_error::success};
|
api_error error_{api_error::success};
|
||||||
mutable std::mutex error_mtx_;
|
mutable std::mutex error_mtx_;
|
||||||
mutable std::recursive_mutex file_mtx_;
|
|
||||||
stop_type io_stop_requested_{false};
|
stop_type io_stop_requested_{false};
|
||||||
std::unique_ptr<std::thread> io_thread_;
|
std::unique_ptr<std::thread> io_thread_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unordered_map<std::size_t, std::shared_ptr<download>> active_downloads_;
|
||||||
|
mutable std::recursive_mutex file_mtx_;
|
||||||
|
std::atomic<std::chrono::system_clock::time_point> last_access_{
|
||||||
|
std::chrono::system_clock::now()};
|
||||||
|
bool modified_{false};
|
||||||
|
std::unique_ptr<utils::file::i_file> nf_;
|
||||||
mutable std::mutex io_thread_mtx_;
|
mutable std::mutex io_thread_mtx_;
|
||||||
std::condition_variable io_thread_notify_;
|
std::condition_variable io_thread_notify_;
|
||||||
std::deque<std::shared_ptr<io_item>> io_thread_queue_;
|
std::deque<std::shared_ptr<io_item>> io_thread_queue_;
|
||||||
std::atomic<std::chrono::system_clock::time_point> last_access_{
|
|
||||||
std::chrono::system_clock::now(),
|
|
||||||
};
|
|
||||||
bool modified_{false};
|
|
||||||
bool removed_{false};
|
bool removed_{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -126,42 +130,11 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto do_io(std::function<api_error()> action) -> api_error;
|
[[nodiscard]] auto do_io(std::function<api_error()> action) -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_active_downloads()
|
virtual auto is_download_complete() const -> bool = 0;
|
||||||
-> std::unordered_map<std::size_t, std::shared_ptr<download>> & {
|
|
||||||
return active_downloads_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_mutex() const -> std::recursive_mutex & {
|
|
||||||
return file_mtx_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_last_chunk_size() const -> std::size_t;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider() -> i_provider & { return provider_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider() const -> const i_provider & {
|
|
||||||
return provider_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_removed() const -> bool;
|
|
||||||
|
|
||||||
void notify_io();
|
|
||||||
|
|
||||||
void reset_timeout();
|
void reset_timeout();
|
||||||
|
|
||||||
auto set_api_error(const api_error &err) -> api_error;
|
auto set_api_error(const api_error &e) -> api_error;
|
||||||
|
|
||||||
void set_file_size(std::uint64_t size);
|
|
||||||
|
|
||||||
void set_last_chunk_size(std::size_t size);
|
|
||||||
|
|
||||||
void set_modified(bool modified);
|
|
||||||
|
|
||||||
void set_removed(bool removed);
|
|
||||||
|
|
||||||
void set_source_path(std::string source_path);
|
|
||||||
|
|
||||||
void wait_for_io(stop_type &stop_requested);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void add(std::uint64_t handle, open_file_data ofd) override;
|
void add(std::uint64_t handle, open_file_data ofd) override;
|
||||||
@ -170,8 +143,6 @@ public:
|
|||||||
|
|
||||||
auto close() -> bool override;
|
auto close() -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_allocated() const -> bool override { return false; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_error() const -> api_error;
|
[[nodiscard]] auto get_api_error() const -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_path() const -> std::string override;
|
[[nodiscard]] auto get_api_path() const -> std::string override;
|
||||||
@ -186,23 +157,27 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_handles() const -> std::vector<std::uint64_t> override;
|
[[nodiscard]] auto get_handles() const -> std::vector<std::uint64_t> override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data()
|
||||||
get_open_data() -> std::map<std::uint64_t, open_file_data> & override;
|
-> std::map<std::uint64_t, open_file_data> & override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_open_data() const
|
[[nodiscard]] auto get_open_data() const
|
||||||
-> const std::map<std::uint64_t, open_file_data> & override;
|
-> const std::map<std::uint64_t, open_file_data> & override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data(std::uint64_t handle)
|
||||||
get_open_data(std::uint64_t handle) -> open_file_data & override;
|
-> open_file_data & override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_open_data(std::uint64_t handle) const
|
||||||
get_open_data(std::uint64_t handle) const -> const open_file_data & override;
|
-> const open_file_data & override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_open_file_count() const -> std::size_t override;
|
[[nodiscard]] auto get_open_file_count() const -> std::size_t override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_source_path() const -> std::string override;
|
[[nodiscard]] auto get_source_path() const -> std::string override {
|
||||||
|
return fsi_.source_path;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto has_handle(std::uint64_t handle) const -> bool override;
|
[[nodiscard]] auto has_handle(std::uint64_t handle) const -> bool override {
|
||||||
|
return open_data_.find(handle) != open_data_.end();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto is_directory() const -> bool override {
|
[[nodiscard]] auto is_directory() const -> bool override {
|
||||||
return fsi_.directory;
|
return fsi_.directory;
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
||||||
|
|
||||||
#include "file_manager/open_file_base.hpp"
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class i_provider;
|
|
||||||
class i_upload_manager;
|
|
||||||
|
|
||||||
class ring_buffer_base : public open_file_base {
|
|
||||||
public:
|
|
||||||
ring_buffer_base(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider,
|
|
||||||
std::size_t ring_size, bool disable_io);
|
|
||||||
|
|
||||||
~ring_buffer_base() override = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ring_buffer_base() = delete;
|
|
||||||
ring_buffer_base(const ring_buffer_base &) noexcept = delete;
|
|
||||||
ring_buffer_base(ring_buffer_base &&) noexcept = delete;
|
|
||||||
auto operator=(ring_buffer_base &&) noexcept -> ring_buffer_base & = delete;
|
|
||||||
auto
|
|
||||||
operator=(const ring_buffer_base &) noexcept -> ring_buffer_base & = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr const auto min_ring_size{5U};
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::dynamic_bitset<> read_state_;
|
|
||||||
std::size_t total_chunks_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::condition_variable chunk_notify_;
|
|
||||||
mutable std::mutex chunk_mtx_;
|
|
||||||
std::mutex read_mtx_;
|
|
||||||
std::unique_ptr<std::thread> reader_thread_;
|
|
||||||
std::size_t ring_begin_{};
|
|
||||||
std::size_t ring_end_{};
|
|
||||||
std::size_t ring_pos_{};
|
|
||||||
stop_type stop_requested_{false};
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] auto check_start() -> api_error;
|
|
||||||
|
|
||||||
auto download_chunk(std::size_t chunk, bool skip_active) -> api_error;
|
|
||||||
|
|
||||||
void reader_thread();
|
|
||||||
|
|
||||||
void update_position(std::size_t count, bool is_forward);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] auto has_reader_thread() const -> bool {
|
|
||||||
return reader_thread_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_ring_size() const -> std::size_t {
|
|
||||||
return read_state_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto on_check_start() -> bool = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
on_chunk_downloaded(std::size_t chunk,
|
|
||||||
const data_buffer &buffer) -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
|
||||||
use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func) -> api_error = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
auto close() -> bool override;
|
|
||||||
|
|
||||||
void forward(std::size_t count);
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_current_chunk() const -> std::size_t {
|
|
||||||
return ring_pos_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_first_chunk() const -> std::size_t {
|
|
||||||
return ring_begin_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_last_chunk() const -> std::size_t { return ring_end_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_total_chunks() const -> std::size_t {
|
|
||||||
return total_chunks_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_complete() const -> bool override { return false; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto is_write_supported() const -> bool override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
|
||||||
data_buffer &data) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto resize(std::uint64_t /* size */) -> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reverse(std::size_t count);
|
|
||||||
|
|
||||||
void set(std::size_t first_chunk, std::size_t current_chunk);
|
|
||||||
|
|
||||||
void set_api_path(const std::string &api_path) override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
write(std::uint64_t /* write_offset */, const data_buffer & /* data */,
|
|
||||||
std::size_t & /* bytes_written */) -> api_error override {
|
|
||||||
return api_error::not_supported;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_BASE_HPP_
|
|
@ -22,17 +22,20 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
#ifndef REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
||||||
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
#define REPERTORY_INCLUDE_FILE_MANAGER_RING_BUFFER_OPEN_FILE_HPP_
|
||||||
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/file.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class i_provider;
|
class i_provider;
|
||||||
class i_upload_manager;
|
class i_upload_manager;
|
||||||
|
|
||||||
class ring_buffer_open_file final : public ring_buffer_base {
|
class ring_buffer_open_file final : public open_file_base {
|
||||||
public:
|
public:
|
||||||
|
ring_buffer_open_file(std::string buffer_directory, std::uint64_t chunk_size,
|
||||||
|
std::uint8_t chunk_timeout, filesystem_item fsi,
|
||||||
|
i_provider &provider);
|
||||||
|
|
||||||
ring_buffer_open_file(std::string buffer_directory, std::uint64_t chunk_size,
|
ring_buffer_open_file(std::string buffer_directory, std::uint64_t chunk_size,
|
||||||
std::uint8_t chunk_timeout, filesystem_item fsi,
|
std::uint8_t chunk_timeout, filesystem_item fsi,
|
||||||
i_provider &provider, std::size_t ring_size);
|
i_provider &provider, std::size_t ring_size);
|
||||||
@ -43,49 +46,85 @@ public:
|
|||||||
ring_buffer_open_file() = delete;
|
ring_buffer_open_file() = delete;
|
||||||
ring_buffer_open_file(const ring_buffer_open_file &) noexcept = delete;
|
ring_buffer_open_file(const ring_buffer_open_file &) noexcept = delete;
|
||||||
ring_buffer_open_file(ring_buffer_open_file &&) noexcept = delete;
|
ring_buffer_open_file(ring_buffer_open_file &&) noexcept = delete;
|
||||||
auto operator=(ring_buffer_open_file &&) noexcept -> ring_buffer_open_file & =
|
auto operator=(ring_buffer_open_file &&) noexcept
|
||||||
delete;
|
-> ring_buffer_open_file & = delete;
|
||||||
auto operator=(const ring_buffer_open_file &) noexcept
|
auto operator=(const ring_buffer_open_file &) noexcept
|
||||||
-> ring_buffer_open_file & = delete;
|
-> ring_buffer_open_file & = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string source_path_;
|
boost::dynamic_bitset<> ring_state_;
|
||||||
|
std::size_t total_chunks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<utils::file::i_file> nf_;
|
std::unique_ptr<std::thread> chunk_forward_thread_;
|
||||||
|
std::unique_ptr<std::thread> chunk_reverse_thread_;
|
||||||
|
std::condition_variable chunk_notify_;
|
||||||
|
mutable std::mutex chunk_mtx_;
|
||||||
|
std::size_t current_chunk_{};
|
||||||
|
std::size_t first_chunk_{};
|
||||||
|
std::size_t last_chunk_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto download_chunk(std::size_t chunk) -> api_error;
|
||||||
|
|
||||||
|
void forward_reader_thread(std::size_t count);
|
||||||
|
|
||||||
|
void reverse_reader_thread(std::size_t count);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto on_check_start() -> bool override;
|
auto is_download_complete() const -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_chunk_downloaded(std::size_t chunk,
|
|
||||||
const data_buffer &buffer) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset, data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static auto can_handle_file(std::uint64_t file_size,
|
void forward(std::size_t count);
|
||||||
std::size_t chunk_size,
|
|
||||||
std::size_t ring_size) -> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_current_chunk() const -> std::size_t {
|
||||||
native_operation(native_operation_callback callback) -> api_error override;
|
return current_chunk_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto native_operation(std::uint64_t /* new_file_size */,
|
[[nodiscard]] auto get_first_chunk() const -> std::size_t {
|
||||||
native_operation_callback /* callback */)
|
return first_chunk_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_last_chunk() const -> std::size_t {
|
||||||
|
return last_chunk_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state() const -> boost::dynamic_bitset<> override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_read_state(std::size_t chunk) const -> bool override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_total_chunks() const -> std::size_t {
|
||||||
|
return total_chunks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_complete() const -> bool override { return true; }
|
||||||
|
|
||||||
|
auto is_write_supported() const -> bool override { return false; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto native_operation(native_operation_callback callback)
|
||||||
|
-> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto native_operation(std::uint64_t, native_operation_callback)
|
||||||
-> api_error override {
|
-> api_error override {
|
||||||
return api_error::not_supported;
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_source_path() const -> std::string override {
|
[[nodiscard]] auto read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
return source_path_;
|
data_buffer &data) -> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto resize(std::uint64_t) -> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(std::size_t count);
|
||||||
|
|
||||||
|
void set(std::size_t first_chunk, std::size_t current_chunk);
|
||||||
|
|
||||||
|
void set_api_path(const std::string &api_path) override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto write(std::uint64_t, const data_buffer &, std::size_t &)
|
||||||
|
-> api_error override {
|
||||||
|
return api_error::not_supported;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -96,9 +96,7 @@ protected:
|
|||||||
return api_item_added_;
|
return api_item_added_;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_comm() -> i_http_comm & { return comm_; }
|
[[nodiscard]] auto get_comm() const -> i_http_comm & { return comm_; }
|
||||||
|
|
||||||
[[nodiscard]] auto get_comm() const -> const i_http_comm & { return comm_; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_config() -> app_config & { return config_; }
|
[[nodiscard]] auto get_config() -> app_config & { return config_; }
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#define REPERTORY_INCLUDE_PROVIDERS_ENCRYPT_ENCRYPT_PROVIDER_HPP_
|
#define REPERTORY_INCLUDE_PROVIDERS_ENCRYPT_ENCRYPT_PROVIDER_HPP_
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "db/i_file_db.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
|
#include "utils/db/sqlite/db_common.hpp"
|
||||||
#include "utils/encrypting_reader.hpp"
|
#include "utils/encrypting_reader.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
@ -45,22 +45,21 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct reader_info final {
|
struct reader_info final {
|
||||||
std::chrono::system_clock::time_point last_access_time{
|
std::chrono::system_clock::time_point last_access_time =
|
||||||
std::chrono::system_clock::now(),
|
std::chrono::system_clock::now();
|
||||||
};
|
std::unique_ptr<utils::encryption::encrypting_reader> reader{};
|
||||||
std::unique_ptr<utils::encryption::encrypting_reader> reader;
|
|
||||||
std::mutex reader_mtx;
|
std::mutex reader_mtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
app_config &config_;
|
app_config &config_;
|
||||||
encrypt_config encrypt_config_;
|
utils::db::sqlite::db3_t db_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<i_file_db> db_{nullptr};
|
i_file_manager *fm_ = nullptr;
|
||||||
i_file_manager *fm_{nullptr};
|
std::unordered_map<std::string, std::shared_ptr<reader_info>>
|
||||||
std::unordered_map<std::string, std::shared_ptr<reader_info>> reader_lookup_;
|
reader_lookup_{};
|
||||||
std::recursive_mutex reader_lookup_mtx_;
|
std::recursive_mutex reader_lookup_mtx_{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto create_api_file(const std::string &api_path, bool directory,
|
static auto create_api_file(const std::string &api_path, bool directory,
|
||||||
@ -74,10 +73,6 @@ private:
|
|||||||
const std::string &source_path)>
|
const std::string &source_path)>
|
||||||
callback) const -> api_error;
|
callback) const -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_encrypt_config() const -> const encrypt_config & {
|
|
||||||
return encrypt_config_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto process_directory_entry(const utils::file::i_fs_item &dir_entry,
|
auto process_directory_entry(const utils::file::i_fs_item &dir_entry,
|
||||||
const encrypt_config &cfg,
|
const encrypt_config &cfg,
|
||||||
std::string &api_path) const -> bool;
|
std::string &api_path) const -> bool;
|
||||||
@ -88,68 +83,62 @@ public:
|
|||||||
[[nodiscard]] auto create_directory(const std::string &api_path,
|
[[nodiscard]] auto create_directory(const std::string &api_path,
|
||||||
api_meta_map &meta) -> api_error override;
|
api_meta_map &meta) -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto create_directory_clone_source_meta(
|
||||||
create_directory_clone_source_meta(const std::string & /*source_api_path*/,
|
const std::string & /*source_api_path*/,
|
||||||
const std::string & /*api_path*/)
|
const std::string & /*api_path*/) -> api_error override {
|
||||||
-> api_error override {
|
|
||||||
return api_error::not_implemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_file(const std::string & /*api_path*/,
|
|
||||||
api_meta_map & /*meta*/)
|
|
||||||
-> api_error override {
|
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
get_api_path_from_source(const std::string & /*source_path*/,
|
create_file(const std::string & /*api_path*/,
|
||||||
std::string & /*api_path*/) const
|
api_meta_map & /*meta*/) -> api_error override {
|
||||||
-> api_error override;
|
return api_error::not_implemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_path_from_source(
|
||||||
|
const std::string & /*source_path*/,
|
||||||
|
std::string & /*api_path*/) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
||||||
-> std::uint64_t override;
|
-> std::uint64_t override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_items(const std::string &api_path,
|
[[nodiscard]] auto
|
||||||
directory_item_list &list) const
|
get_directory_items(const std::string &api_path,
|
||||||
-> api_error override;
|
directory_item_list &list) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_file(const std::string &api_path, api_file &file) const
|
[[nodiscard]] auto get_file(const std::string &api_path,
|
||||||
-> api_error override;
|
api_file &file) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_file_list(api_file_list &list,
|
|
||||||
std::string &marker) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_file_size(const std::string &api_path,
|
|
||||||
std::uint64_t &file_size) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_filesystem_item(const std::string &api_path,
|
|
||||||
bool directory,
|
|
||||||
filesystem_item &fsi) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_filesystem_item_and_file(const std::string &api_path,
|
|
||||||
api_file &file,
|
|
||||||
filesystem_item &fsi) const
|
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
get_filesystem_item_from_source_path(const std::string &source_path,
|
get_file_list(api_file_list &list,
|
||||||
filesystem_item &fsi) const
|
std::string &marker) const -> api_error override;
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_pinned_files() const
|
[[nodiscard]] auto
|
||||||
-> std::vector<std::string> override;
|
get_file_size(const std::string &api_path,
|
||||||
|
std::uint64_t &file_size) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
[[nodiscard]] auto
|
||||||
api_meta_map &meta) const
|
get_filesystem_item(const std::string &api_path, bool directory,
|
||||||
-> api_error override;
|
filesystem_item &fsi) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
[[nodiscard]] auto get_filesystem_item_and_file(
|
||||||
const std::string &key,
|
const std::string &api_path, api_file &file,
|
||||||
std::string &value) const
|
filesystem_item &fsi) const -> api_error override;
|
||||||
-> api_error override;
|
|
||||||
|
[[nodiscard]] auto get_filesystem_item_from_source_path(
|
||||||
|
const std::string &source_path,
|
||||||
|
filesystem_item &fsi) const -> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto
|
||||||
|
get_pinned_files() const -> std::vector<std::string> override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto
|
||||||
|
get_item_meta(const std::string &api_path,
|
||||||
|
api_meta_map &meta) const -> api_error override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto
|
||||||
|
get_item_meta(const std::string &api_path, const std::string &key,
|
||||||
|
std::string &value) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override;
|
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override;
|
||||||
|
|
||||||
@ -164,11 +153,11 @@ public:
|
|||||||
[[nodiscard]] auto is_directory(const std::string &api_path,
|
[[nodiscard]] auto is_directory(const std::string &api_path,
|
||||||
bool &exists) const -> api_error override;
|
bool &exists) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto is_file(const std::string &api_path, bool &exists) const
|
[[nodiscard]] auto is_file(const std::string &api_path,
|
||||||
-> api_error override;
|
bool &exists) const -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto is_file_writeable(const std::string &api_path) const
|
[[nodiscard]] auto
|
||||||
-> bool override;
|
is_file_writeable(const std::string &api_path) const -> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto is_online() const -> bool override;
|
[[nodiscard]] auto is_online() const -> bool override;
|
||||||
|
|
||||||
@ -178,44 +167,42 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto read_file_bytes(const std::string &api_path,
|
[[nodiscard]] auto
|
||||||
std::size_t size, std::uint64_t offset,
|
read_file_bytes(const std::string &api_path, std::size_t size,
|
||||||
data_buffer &data,
|
std::uint64_t offset, data_buffer &data,
|
||||||
stop_type &stop_requested)
|
stop_type &stop_requested) -> api_error override;
|
||||||
-> api_error override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto remove_directory(const std::string & /*api_path*/)
|
[[nodiscard]] auto
|
||||||
-> api_error override {
|
remove_directory(const std::string & /*api_path*/) -> api_error override {
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto remove_file(const std::string & /*api_path*/)
|
[[nodiscard]] auto
|
||||||
-> api_error override {
|
remove_file(const std::string & /*api_path*/) -> api_error override {
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto remove_item_meta(const std::string & /*api_path*/,
|
[[nodiscard]] auto
|
||||||
const std::string & /*key*/)
|
remove_item_meta(const std::string & /*api_path*/,
|
||||||
-> api_error override {
|
const std::string & /*key*/) -> api_error override {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto rename_file(const std::string & /*from_api_path*/,
|
[[nodiscard]] auto
|
||||||
const std::string & /*to_api_path*/)
|
rename_file(const std::string & /*from_api_path*/,
|
||||||
-> api_error override {
|
const std::string & /*to_api_path*/) -> api_error override {
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto set_item_meta(const std::string & /*api_path*/,
|
[[nodiscard]] auto
|
||||||
const std::string & /*key*/,
|
set_item_meta(const std::string & /*api_path*/, const std::string & /*key*/,
|
||||||
const std::string & /*value*/)
|
const std::string & /*value*/) -> api_error override {
|
||||||
-> api_error override {
|
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto set_item_meta(const std::string & /*api_path*/,
|
[[nodiscard]] auto
|
||||||
const api_meta_map & /*meta*/)
|
set_item_meta(const std::string & /*api_path*/,
|
||||||
-> api_error override {
|
const api_meta_map & /*meta*/) -> api_error override {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,10 +211,10 @@ public:
|
|||||||
|
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
[[nodiscard]] auto upload_file(const std::string & /*api_path*/,
|
[[nodiscard]] auto
|
||||||
const std::string & /*source_path*/,
|
upload_file(const std::string & /*api_path*/,
|
||||||
stop_type & /*stop_requested*/)
|
const std::string & /*source_path*/,
|
||||||
-> api_error override {
|
stop_type & /*stop_requested*/) -> api_error override {
|
||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -46,9 +46,6 @@ public:
|
|||||||
auto operator=(const s3_provider &) -> s3_provider & = delete;
|
auto operator=(const s3_provider &) -> s3_provider & = delete;
|
||||||
auto operator=(s3_provider &&) -> s3_provider & = delete;
|
auto operator=(s3_provider &&) -> s3_provider & = delete;
|
||||||
|
|
||||||
private:
|
|
||||||
s3_config s3_config_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto add_if_not_found(api_file &file,
|
[[nodiscard]] auto add_if_not_found(api_file &file,
|
||||||
const std::string &object_name) const
|
const std::string &object_name) const
|
||||||
@ -81,10 +78,6 @@ private:
|
|||||||
std::optional<std::string> token = std::nullopt) const
|
std::optional<std::string> token = std::nullopt) const
|
||||||
-> bool;
|
-> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto get_s3_config() const -> const s3_config & {
|
|
||||||
return s3_config_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
||||||
api_meta_map &meta)
|
api_meta_map &meta)
|
||||||
|
@ -45,9 +45,6 @@ public:
|
|||||||
auto operator=(const sia_provider &) -> sia_provider & = delete;
|
auto operator=(const sia_provider &) -> sia_provider & = delete;
|
||||||
auto operator=(sia_provider &&) -> sia_provider & = delete;
|
auto operator=(sia_provider &&) -> sia_provider & = delete;
|
||||||
|
|
||||||
private:
|
|
||||||
sia_config sia_config_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] auto get_object_info(const std::string &api_path,
|
[[nodiscard]] auto get_object_info(const std::string &api_path,
|
||||||
json &object_info) const -> api_error;
|
json &object_info) const -> api_error;
|
||||||
@ -55,10 +52,6 @@ private:
|
|||||||
[[nodiscard]] auto get_object_list(const std::string &api_path,
|
[[nodiscard]] auto get_object_list(const std::string &api_path,
|
||||||
nlohmann::json &object_list) const -> bool;
|
nlohmann::json &object_list) const -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto get_sia_config() const -> const auto & {
|
|
||||||
return sia_config_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
||||||
api_meta_map &meta)
|
api_meta_map &meta)
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
#ifndef REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
||||||
#define REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
#define REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
inline constexpr const auto PACKET_SERVICE_FUSE{1U};
|
inline constexpr const auto PACKET_SERVICE_FUSE{1U};
|
||||||
inline constexpr const auto PACKET_SERVICE_WINFSP{2U};
|
inline constexpr const auto PACKET_SERVICE_WINFSP{2U};
|
||||||
|
|
||||||
@ -33,67 +31,7 @@ inline constexpr const auto PACKET_SERVICE_FLAGS{PACKET_SERVICE_WINFSP};
|
|||||||
inline constexpr const auto PACKET_SERVICE_FLAGS{PACKET_SERVICE_FUSE};
|
inline constexpr const auto PACKET_SERVICE_FLAGS{PACKET_SERVICE_FUSE};
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
constexpr const auto default_remote_client_pool_size{20U};
|
|
||||||
constexpr const auto default_remote_max_connections{20U};
|
|
||||||
constexpr const auto default_remote_receive_timeout_ms{120U * 1000U};
|
|
||||||
constexpr const auto default_remote_send_timeout_ms{30U * 1000U};
|
|
||||||
|
|
||||||
namespace repertory::remote {
|
namespace repertory::remote {
|
||||||
struct remote_config final {
|
|
||||||
std::uint16_t api_port{};
|
|
||||||
std::string encryption_token;
|
|
||||||
std::string host_name_or_ip;
|
|
||||||
std::uint8_t max_connections{default_remote_max_connections};
|
|
||||||
std::uint32_t recv_timeout_ms{default_remote_receive_timeout_ms};
|
|
||||||
std::uint32_t send_timeout_ms{default_remote_send_timeout_ms};
|
|
||||||
|
|
||||||
auto operator==(const remote_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return api_port == cfg.api_port &&
|
|
||||||
encryption_token == cfg.encryption_token &&
|
|
||||||
host_name_or_ip == cfg.host_name_or_ip &&
|
|
||||||
max_connections == cfg.max_connections &&
|
|
||||||
recv_timeout_ms == cfg.recv_timeout_ms &&
|
|
||||||
send_timeout_ms == cfg.send_timeout_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator!=(const remote_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return not(cfg == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct remote_mount final {
|
|
||||||
std::uint16_t api_port{};
|
|
||||||
std::uint8_t client_pool_size{default_remote_client_pool_size};
|
|
||||||
bool enable{false};
|
|
||||||
std::string encryption_token;
|
|
||||||
|
|
||||||
auto operator==(const remote_mount &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_port == cfg.api_port &&
|
|
||||||
client_pool_size == cfg.client_pool_size && enable == cfg.enable &&
|
|
||||||
encryption_token == cfg.encryption_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator!=(const remote_mount &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg == this) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return not(cfg == *this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using block_count = std::uint64_t;
|
using block_count = std::uint64_t;
|
||||||
using block_size = std::uint32_t;
|
using block_size = std::uint32_t;
|
||||||
using file_handle = std::uint64_t;
|
using file_handle = std::uint64_t;
|
||||||
@ -222,46 +160,4 @@ create_os_open_flags(const open_flags &flags) -> std::uint32_t;
|
|||||||
#endif // !defined(_WIN32)
|
#endif // !defined(_WIN32)
|
||||||
} // namespace repertory::remote
|
} // namespace repertory::remote
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
|
||||||
template <> struct adl_serializer<repertory::remote::remote_config> {
|
|
||||||
static void to_json(json &data,
|
|
||||||
const repertory::remote::remote_config &value) {
|
|
||||||
data[repertory::JSON_API_PORT] = value.api_port;
|
|
||||||
data[repertory::JSON_ENCRYPTION_TOKEN] = value.encryption_token;
|
|
||||||
data[repertory::JSON_HOST_NAME_OR_IP] = value.host_name_or_ip;
|
|
||||||
data[repertory::JSON_MAX_CONNECTIONS] = value.max_connections;
|
|
||||||
data[repertory::JSON_RECV_TIMEOUT_MS] = value.recv_timeout_ms;
|
|
||||||
data[repertory::JSON_SEND_TIMEOUT_MS] = value.send_timeout_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data,
|
|
||||||
repertory::remote::remote_config &value) {
|
|
||||||
data.at(repertory::JSON_API_PORT).get_to(value.api_port);
|
|
||||||
data.at(repertory::JSON_ENCRYPTION_TOKEN).get_to(value.encryption_token);
|
|
||||||
data.at(repertory::JSON_HOST_NAME_OR_IP).get_to(value.host_name_or_ip);
|
|
||||||
data.at(repertory::JSON_MAX_CONNECTIONS).get_to(value.max_connections);
|
|
||||||
data.at(repertory::JSON_RECV_TIMEOUT_MS).get_to(value.recv_timeout_ms);
|
|
||||||
data.at(repertory::JSON_SEND_TIMEOUT_MS).get_to(value.send_timeout_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::remote::remote_mount> {
|
|
||||||
static void to_json(json &data,
|
|
||||||
const repertory::remote::remote_mount &value) {
|
|
||||||
data[repertory::JSON_API_PORT] = value.api_port;
|
|
||||||
data[repertory::JSON_CLIENT_POOL_SIZE] = value.client_pool_size;
|
|
||||||
data[repertory::JSON_ENABLE_REMOTE_MOUNT] = value.enable;
|
|
||||||
data[repertory::JSON_ENCRYPTION_TOKEN] = value.encryption_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data,
|
|
||||||
repertory::remote::remote_mount &value) {
|
|
||||||
data.at(repertory::JSON_API_PORT).get_to(value.api_port);
|
|
||||||
data.at(repertory::JSON_CLIENT_POOL_SIZE).get_to(value.client_pool_size);
|
|
||||||
data.at(repertory::JSON_ENABLE_REMOTE_MOUNT).get_to(value.enable);
|
|
||||||
data.at(repertory::JSON_ENCRYPTION_TOKEN).get_to(value.encryption_token);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
#endif // REPERTORY_INCLUDE_TYPES_REMOTE_HPP_
|
||||||
|
@ -23,125 +23,7 @@
|
|||||||
#define REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
#define REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
constexpr const auto default_api_auth_size{48U};
|
inline constexpr const auto max_time{std::numeric_limits<std::uint64_t>::max()};
|
||||||
constexpr const auto default_download_timeout_ces{30U};
|
|
||||||
constexpr const auto default_eviction_delay_mins{1U};
|
|
||||||
constexpr const auto default_high_freq_interval_secs{30U};
|
|
||||||
constexpr const auto default_low_freq_interval_secs{0U * 60U};
|
|
||||||
constexpr const auto default_max_cache_size_bytes{
|
|
||||||
std::uint64_t(20UL * 1024UL * 1024UL * 1024UL),
|
|
||||||
};
|
|
||||||
constexpr const auto default_max_upload_count{5U};
|
|
||||||
constexpr const auto default_med_freq_interval_secs{2U * 60U};
|
|
||||||
constexpr const auto default_online_check_retry_secs{60U};
|
|
||||||
constexpr const auto default_orphaned_file_retention_days{15U};
|
|
||||||
constexpr const auto default_retry_read_count{6U};
|
|
||||||
constexpr const auto default_ring_buffer_file_size{512U};
|
|
||||||
constexpr const auto default_task_wait_ms{100U};
|
|
||||||
constexpr const auto default_timeout_ms{60000U};
|
|
||||||
constexpr const auto max_orphaned_file_retention_days{std::uint16_t(31U)};
|
|
||||||
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
|
|
||||||
constexpr const auto min_cache_size_bytes{
|
|
||||||
std::uint64_t(100UL * 1024UL * 1024UL)};
|
|
||||||
constexpr const auto min_download_timeout_secs{std::uint8_t(5U)};
|
|
||||||
constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)};
|
|
||||||
constexpr const auto min_orphaned_file_retention_days{std::uint16_t(1U)};
|
|
||||||
constexpr const auto min_retry_read_count{std::uint16_t(2U)};
|
|
||||||
constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)};
|
|
||||||
constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
|
|
||||||
|
|
||||||
template <typename data_t> class atomic final {
|
|
||||||
public:
|
|
||||||
atomic() : mtx_(std::make_shared<std::mutex>()) {}
|
|
||||||
|
|
||||||
atomic(const atomic &at_data)
|
|
||||||
: data_(at_data.load()), mtx_(std::make_shared<std::mutex>()) {}
|
|
||||||
|
|
||||||
atomic(data_t data)
|
|
||||||
: data_(std::move(data)), mtx_(std::make_shared<std::mutex>()) {}
|
|
||||||
|
|
||||||
atomic(atomic &&) = default;
|
|
||||||
|
|
||||||
~atomic() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
data_t data_;
|
|
||||||
std::shared_ptr<std::mutex> mtx_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] auto load() const -> data_t {
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
return data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto store(data_t data) -> data_t {
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
data_ = std::move(data);
|
|
||||||
return data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator=(const atomic &at_data) -> atomic & {
|
|
||||||
if (&at_data == this) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
store(at_data.load());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator=(atomic &&) -> atomic & = default;
|
|
||||||
|
|
||||||
auto operator=(data_t data) -> atomic & {
|
|
||||||
if (&data == &data_) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
store(std::move(data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto operator==(const atomic &at_data) const -> bool {
|
|
||||||
if (&at_data == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
return at_data.load() == data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto operator==(const data_t &data) const -> bool {
|
|
||||||
if (&data == &data_) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
return data == data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto operator!=(const atomic &at_data) const -> bool {
|
|
||||||
if (&at_data == this) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
return at_data.load() != data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto operator!=(const data_t &data) const -> bool {
|
|
||||||
if (&data == &data_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock lock(*mtx_);
|
|
||||||
return data != data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] operator data_t() const { return load(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
inline constexpr const auto max_time{
|
|
||||||
std::numeric_limits<std::uint64_t>::max(),
|
|
||||||
};
|
|
||||||
|
|
||||||
inline constexpr const std::string META_ACCESSED{"accessed"};
|
inline constexpr const std::string META_ACCESSED{"accessed"};
|
||||||
inline constexpr const std::string META_ATTRIBUTES{"attributes"};
|
inline constexpr const std::string META_ATTRIBUTES{"attributes"};
|
||||||
@ -175,7 +57,6 @@ enum class api_error {
|
|||||||
bad_address,
|
bad_address,
|
||||||
buffer_overflow,
|
buffer_overflow,
|
||||||
buffer_too_small,
|
buffer_too_small,
|
||||||
cache_not_initialized,
|
|
||||||
comm_error,
|
comm_error,
|
||||||
decryption_error,
|
decryption_error,
|
||||||
directory_end_of_files,
|
directory_end_of_files,
|
||||||
@ -194,7 +75,6 @@ enum class api_error {
|
|||||||
invalid_handle,
|
invalid_handle,
|
||||||
invalid_operation,
|
invalid_operation,
|
||||||
invalid_ring_buffer_multiple,
|
invalid_ring_buffer_multiple,
|
||||||
invalid_ring_buffer_position,
|
|
||||||
invalid_ring_buffer_size,
|
invalid_ring_buffer_size,
|
||||||
invalid_version,
|
invalid_version,
|
||||||
item_exists,
|
item_exists,
|
||||||
@ -216,34 +96,19 @@ enum class api_error {
|
|||||||
|
|
||||||
[[nodiscard]] auto api_error_from_string(std::string_view str) -> api_error;
|
[[nodiscard]] auto api_error_from_string(std::string_view str) -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto api_error_to_string(const api_error &error)
|
||||||
api_error_to_string(const api_error &error) -> const std::string &;
|
-> const std::string &;
|
||||||
|
|
||||||
enum class database_type {
|
enum class download_type { direct, fallback, ring_buffer };
|
||||||
rocksdb,
|
[[nodiscard]] auto download_type_from_string(std::string type,
|
||||||
sqlite,
|
const download_type &default_type)
|
||||||
};
|
-> download_type;
|
||||||
[[nodiscard]] auto database_type_from_string(
|
|
||||||
std::string type,
|
|
||||||
database_type default_type = database_type::rocksdb) -> database_type;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto download_type_to_string(const download_type &type)
|
||||||
database_type_to_string(const database_type &type) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
enum class download_type {
|
|
||||||
default_,
|
|
||||||
direct,
|
|
||||||
ring_buffer,
|
|
||||||
};
|
|
||||||
[[nodiscard]] auto download_type_from_string(
|
|
||||||
std::string type,
|
|
||||||
download_type default_type = download_type::default_) -> download_type;
|
|
||||||
|
|
||||||
[[nodiscard]] auto
|
|
||||||
download_type_to_string(const download_type &type) -> std::string;
|
|
||||||
|
|
||||||
enum class exit_code : std::int32_t {
|
enum class exit_code : std::int32_t {
|
||||||
success = 0,
|
success,
|
||||||
communication_error = -1,
|
communication_error = -1,
|
||||||
file_creation_failed = -2,
|
file_creation_failed = -2,
|
||||||
incompatible_version = -3,
|
incompatible_version = -3,
|
||||||
@ -293,136 +158,129 @@ using open_file_data = int;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct api_file final {
|
struct api_file final {
|
||||||
std::string api_path;
|
std::string api_path{};
|
||||||
std::string api_parent;
|
std::string api_parent{};
|
||||||
std::uint64_t accessed_date{};
|
std::uint64_t accessed_date{};
|
||||||
std::uint64_t changed_date{};
|
std::uint64_t changed_date{};
|
||||||
std::uint64_t creation_date{};
|
std::uint64_t creation_date{};
|
||||||
std::uint64_t file_size{};
|
std::uint64_t file_size{};
|
||||||
std::string key;
|
std::string key{};
|
||||||
std::uint64_t modified_date{};
|
std::uint64_t modified_date{};
|
||||||
std::string source_path;
|
std::string source_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct directory_item final {
|
struct directory_item final {
|
||||||
std::string api_path;
|
std::string api_path{};
|
||||||
std::string api_parent;
|
std::string api_parent{};
|
||||||
bool directory{false};
|
bool directory{false};
|
||||||
std::uint64_t size{};
|
std::uint64_t size{};
|
||||||
api_meta_map meta;
|
api_meta_map meta{};
|
||||||
bool resolved{false};
|
bool resolved{false};
|
||||||
|
|
||||||
|
[[nodiscard]] static auto from_json(const json &item) -> directory_item {
|
||||||
|
directory_item ret{};
|
||||||
|
ret.api_path = item["path"].get<std::string>();
|
||||||
|
ret.api_parent = item["parent"].get<std::string>();
|
||||||
|
ret.directory = item["directory"].get<bool>();
|
||||||
|
ret.size = item["size"].get<std::uint64_t>();
|
||||||
|
ret.meta = item["meta"].get<api_meta_map>();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto to_json() const -> json {
|
||||||
|
return {
|
||||||
|
{"path", api_path}, {"parent", api_parent}, {"size", size},
|
||||||
|
{"directory", directory}, {"meta", meta},
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct encrypt_config final {
|
struct encrypt_config final {
|
||||||
std::string encryption_token;
|
std::string encryption_token{};
|
||||||
std::string path;
|
std::string path{};
|
||||||
|
|
||||||
auto operator==(const encrypt_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return encryption_token == cfg.encryption_token && path == cfg.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator!=(const encrypt_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return not(cfg == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct filesystem_item final {
|
struct filesystem_item final {
|
||||||
std::string api_path;
|
std::string api_path{};
|
||||||
std::string api_parent;
|
std::string api_parent{};
|
||||||
bool directory{false};
|
bool directory{false};
|
||||||
std::uint64_t size{};
|
std::uint64_t size{};
|
||||||
std::string source_path;
|
std::string source_path{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct host_config final {
|
struct host_config final {
|
||||||
std::string agent_string;
|
std::string agent_string{};
|
||||||
std::string api_password;
|
std::string api_password{};
|
||||||
std::string api_user;
|
std::string api_user{};
|
||||||
std::uint16_t api_port;
|
std::uint16_t api_port{};
|
||||||
std::string host_name_or_ip{"localhost"};
|
std::string host_name_or_ip{"localhost"};
|
||||||
std::string path;
|
std::string path{};
|
||||||
std::string protocol{"http"};
|
std::string protocol{"http"};
|
||||||
std::uint32_t timeout_ms{default_timeout_ms};
|
std::uint32_t timeout_ms{60000U};
|
||||||
|
|
||||||
auto operator==(const host_config &cfg) const noexcept -> bool {
|
auto operator==(const host_config &hc) const noexcept -> bool {
|
||||||
if (&cfg != this) {
|
if (&hc != this) {
|
||||||
return agent_string == cfg.agent_string &&
|
return agent_string == hc.agent_string &&
|
||||||
api_password == cfg.api_password && api_user == cfg.api_user &&
|
api_password == hc.api_password && api_user == hc.api_user &&
|
||||||
api_port == cfg.api_port &&
|
api_port == hc.api_port && host_name_or_ip == hc.host_name_or_ip &&
|
||||||
host_name_or_ip == cfg.host_name_or_ip && path == cfg.path &&
|
path == hc.path && protocol == hc.protocol &&
|
||||||
protocol == cfg.protocol && timeout_ms == cfg.timeout_ms;
|
timeout_ms == hc.timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator!=(const host_config &cfg) const noexcept -> bool {
|
auto operator!=(const host_config &hc) const noexcept -> bool {
|
||||||
if (&cfg != this) {
|
if (&hc != this) {
|
||||||
return not(cfg == *this);
|
return not(hc == *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__GNUG__)
|
||||||
|
__attribute__((unused))
|
||||||
|
#endif
|
||||||
|
static void
|
||||||
|
to_json(json &j, const host_config &hc) {
|
||||||
|
j = json{{"AgentString", hc.agent_string},
|
||||||
|
{"ApiPassword", hc.api_password},
|
||||||
|
{"ApiPort", hc.api_port},
|
||||||
|
{"ApiUser", hc.api_user},
|
||||||
|
{"HostNameOrIp", hc.host_name_or_ip},
|
||||||
|
{"Path", hc.path},
|
||||||
|
{"Protocol", hc.protocol},
|
||||||
|
{"TimeoutMs", hc.timeout_ms}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUG__)
|
||||||
|
__attribute__((unused))
|
||||||
|
#endif
|
||||||
|
static void
|
||||||
|
from_json(const json &j, host_config &hc) {
|
||||||
|
j.at("AgentString").get_to(hc.agent_string);
|
||||||
|
j.at("ApiPassword").get_to(hc.api_password);
|
||||||
|
j.at("ApiPort").get_to(hc.api_port);
|
||||||
|
j.at("AuthUser").get_to(hc.api_user);
|
||||||
|
j.at("HostNameOrIp").get_to(hc.host_name_or_ip);
|
||||||
|
j.at("Path").get_to(hc.path);
|
||||||
|
j.at("Protocol").get_to(hc.protocol);
|
||||||
|
j.at("TimeoutMs").get_to(hc.timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
struct s3_config final {
|
struct s3_config final {
|
||||||
std::string access_key;
|
std::string access_key{};
|
||||||
std::string bucket;
|
std::string bucket{};
|
||||||
std::string encryption_token;
|
std::string encryption_token{};
|
||||||
std::string region{"any"};
|
std::string region{"any"};
|
||||||
std::string secret_key;
|
std::string secret_key{};
|
||||||
std::uint32_t timeout_ms{default_timeout_ms};
|
std::uint32_t timeout_ms{60000U};
|
||||||
std::string url;
|
std::string url{};
|
||||||
bool use_path_style{false};
|
bool use_path_style{false};
|
||||||
bool use_region_in_url{false};
|
bool use_region_in_url{false};
|
||||||
|
|
||||||
auto operator==(const s3_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return access_key == cfg.access_key && bucket == cfg.bucket &&
|
|
||||||
encryption_token == cfg.encryption_token && region == cfg.region &&
|
|
||||||
secret_key == cfg.secret_key && timeout_ms == cfg.timeout_ms &&
|
|
||||||
url == cfg.url && use_path_style == cfg.use_path_style &&
|
|
||||||
use_region_in_url == cfg.use_region_in_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator!=(const s3_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return not(cfg == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sia_config final {
|
struct sia_config final {
|
||||||
std::string bucket;
|
std::string bucket{};
|
||||||
|
|
||||||
auto operator==(const sia_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return bucket == cfg.bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator!=(const sia_config &cfg) const noexcept -> bool {
|
|
||||||
if (&cfg != this) {
|
|
||||||
return not(cfg == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using api_file_list = std::vector<api_file>;
|
using api_file_list = std::vector<api_file>;
|
||||||
@ -430,226 +288,6 @@ using api_file_provider_callback = std::function<void(api_file &)>;
|
|||||||
using api_item_added_callback = std::function<api_error(bool, api_file &)>;
|
using api_item_added_callback = std::function<api_error(bool, api_file &)>;
|
||||||
using directory_item_list = std::vector<directory_item>;
|
using directory_item_list = std::vector<directory_item>;
|
||||||
using meta_provider_callback = std::function<void(directory_item &)>;
|
using meta_provider_callback = std::function<void(directory_item &)>;
|
||||||
|
|
||||||
inline constexpr const auto JSON_ACCESS_KEY{"AccessKey"};
|
|
||||||
inline constexpr const auto JSON_AGENT_STRING{"AgentString"};
|
|
||||||
inline constexpr const auto JSON_API_AUTH{"ApiAuth"};
|
|
||||||
inline constexpr const auto JSON_API_PARENT{"ApiParent"};
|
|
||||||
inline constexpr const auto JSON_API_PASSWORD{"ApiPassword"};
|
|
||||||
inline constexpr const auto JSON_API_PATH{"ApiPath"};
|
|
||||||
inline constexpr const auto JSON_API_PORT{"ApiPort"};
|
|
||||||
inline constexpr const auto JSON_API_USER{"ApiUser"};
|
|
||||||
inline constexpr const auto JSON_BUCKET{"Bucket"};
|
|
||||||
inline constexpr const auto JSON_CLIENT_POOL_SIZE{"ClientPoolSize"};
|
|
||||||
inline constexpr const auto JSON_DATABASE_TYPE{"DatabaseType"};
|
|
||||||
inline constexpr const auto JSON_DIRECTORY{"Directory"};
|
|
||||||
inline constexpr const auto JSON_DOWNLOAD_TIMEOUT_SECS{
|
|
||||||
"DownloadTimeoutSeconds"};
|
|
||||||
inline constexpr const auto JSON_ENABLE_DRIVE_EVENTS{"EnableDriveEvents"};
|
|
||||||
inline constexpr const auto JSON_ENABLE_DOWNLOAD_TIMEOUT{
|
|
||||||
"EnableDownloadTimeout"};
|
|
||||||
inline constexpr const auto JSON_ENABLE_MOUNT_MANAGER{"EnableMountManager"};
|
|
||||||
inline constexpr const auto JSON_ENABLE_REMOTE_MOUNT{"Enable"};
|
|
||||||
inline constexpr const auto JSON_ENCRYPTION_TOKEN{"EncryptionToken"};
|
|
||||||
inline constexpr const auto JSON_ENCRYPT_CONFIG{"EncryptConfig"};
|
|
||||||
inline constexpr const auto JSON_EVENT_LEVEL{"EventLevel"};
|
|
||||||
inline constexpr const auto JSON_EVICTION_DELAY_MINS{"EvictionDelayMinutes"};
|
|
||||||
inline constexpr const auto JSON_EVICTION_USE_ACCESS_TIME{
|
|
||||||
"EvictionUseAccessedTime"};
|
|
||||||
inline constexpr const auto JSON_HIGH_FREQ_INTERVAL_SECS{
|
|
||||||
"HighFreqIntervalSeconds"};
|
|
||||||
inline constexpr const auto JSON_HOST_CONFIG{"HostConfig"};
|
|
||||||
inline constexpr const auto JSON_HOST_NAME_OR_IP{"HostNameOrIp"};
|
|
||||||
inline constexpr const auto JSON_LOW_FREQ_INTERVAL_SECS{
|
|
||||||
"LowFreqIntervalSeconds"};
|
|
||||||
inline constexpr const auto JSON_MAX_CACHE_SIZE_BYTES{"MaxCacheSizeBytes"};
|
|
||||||
inline constexpr const auto JSON_MAX_CONNECTIONS{"MaxConnections"};
|
|
||||||
inline constexpr const auto JSON_MAX_UPLOAD_COUNT{"MaxUploadCount"};
|
|
||||||
inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
|
|
||||||
"MedFreqIntervalSeconds"};
|
|
||||||
inline constexpr const auto JSON_META{"Meta"};
|
|
||||||
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
|
|
||||||
"OnlineCheckRetrySeconds"};
|
|
||||||
inline constexpr const auto JSON_ORPHANED_FILE_RETENTION_DAYS{
|
|
||||||
"OrphanedFileRetentionDays"};
|
|
||||||
inline constexpr const auto JSON_PATH{"Path"};
|
|
||||||
inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
|
|
||||||
"PreferredDownloadType"};
|
|
||||||
inline constexpr const auto JSON_PROTOCOL{"Protocol"};
|
|
||||||
inline constexpr const auto JSON_RECV_TIMEOUT_MS{"ReceiveTimeoutMs"};
|
|
||||||
inline constexpr const auto JSON_REGION{"Region"};
|
|
||||||
inline constexpr const auto JSON_REMOTE_CONFIG{"RemoteConfig"};
|
|
||||||
inline constexpr const auto JSON_REMOTE_MOUNT{"RemoteMount"};
|
|
||||||
inline constexpr const auto JSON_RETRY_READ_COUNT{"RetryReadCount"};
|
|
||||||
inline constexpr const auto JSON_RING_BUFFER_FILE_SIZE{"RingBufferFileSize"};
|
|
||||||
inline constexpr const auto JSON_S3_CONFIG{"S3Config"};
|
|
||||||
inline constexpr const auto JSON_SECRET_KEY{"SecretKey"};
|
|
||||||
inline constexpr const auto JSON_SEND_TIMEOUT_MS{"SendTimeoutMs"};
|
|
||||||
inline constexpr const auto JSON_SIA_CONFIG{"SiaConfig"};
|
|
||||||
inline constexpr const auto JSON_SIZE{"Size"};
|
|
||||||
inline constexpr const auto JSON_TASK_WAIT_MS{"TaskWaitMs"};
|
|
||||||
inline constexpr const auto JSON_TIMEOUT_MS{"TimeoutMs"};
|
|
||||||
inline constexpr const auto JSON_URL{"URL"};
|
|
||||||
inline constexpr const auto JSON_USE_PATH_STYLE{"UsePathStyle"};
|
|
||||||
inline constexpr const auto JSON_USE_REGION_IN_URL{"UseRegionInURL"};
|
|
||||||
inline constexpr const auto JSON_VERSION{"Version"};
|
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
|
||||||
template <> struct adl_serializer<repertory::directory_item> {
|
|
||||||
static void to_json(json &data, const repertory::directory_item &value) {
|
|
||||||
data[repertory::JSON_API_PARENT] = value.api_parent;
|
|
||||||
data[repertory::JSON_API_PATH] = value.api_path;
|
|
||||||
data[repertory::JSON_DIRECTORY] = value.directory;
|
|
||||||
data[repertory::JSON_META] = value.meta;
|
|
||||||
data[repertory::JSON_SIZE] = value.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::directory_item &value) {
|
|
||||||
data.at(repertory::JSON_API_PARENT).get_to<std::string>(value.api_parent);
|
|
||||||
data.at(repertory::JSON_API_PATH).get_to<std::string>(value.api_path);
|
|
||||||
data.at(repertory::JSON_DIRECTORY).get_to<bool>(value.directory);
|
|
||||||
data.at(repertory::JSON_META).get_to<repertory::api_meta_map>(value.meta);
|
|
||||||
data.at(repertory::JSON_SIZE).get_to<std::uint64_t>(value.size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::encrypt_config> {
|
|
||||||
static void to_json(json &data, const repertory::encrypt_config &value) {
|
|
||||||
data[repertory::JSON_ENCRYPTION_TOKEN] = value.encryption_token;
|
|
||||||
data[repertory::JSON_PATH] = value.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::encrypt_config &value) {
|
|
||||||
data.at(repertory::JSON_ENCRYPTION_TOKEN).get_to(value.encryption_token);
|
|
||||||
data.at(repertory::JSON_PATH).get_to(value.path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::host_config> {
|
|
||||||
static void to_json(json &data, const repertory::host_config &value) {
|
|
||||||
data[repertory::JSON_AGENT_STRING] = value.agent_string;
|
|
||||||
data[repertory::JSON_API_PASSWORD] = value.api_password;
|
|
||||||
data[repertory::JSON_API_PORT] = value.api_port;
|
|
||||||
data[repertory::JSON_API_USER] = value.api_user;
|
|
||||||
data[repertory::JSON_HOST_NAME_OR_IP] = value.host_name_or_ip;
|
|
||||||
data[repertory::JSON_PATH] = value.path;
|
|
||||||
data[repertory::JSON_PROTOCOL] = value.protocol;
|
|
||||||
data[repertory::JSON_TIMEOUT_MS] = value.timeout_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::host_config &value) {
|
|
||||||
data.at(repertory::JSON_AGENT_STRING).get_to(value.agent_string);
|
|
||||||
data.at(repertory::JSON_API_PASSWORD).get_to(value.api_password);
|
|
||||||
data.at(repertory::JSON_API_PORT).get_to(value.api_port);
|
|
||||||
data.at(repertory::JSON_API_USER).get_to(value.api_user);
|
|
||||||
data.at(repertory::JSON_HOST_NAME_OR_IP).get_to(value.host_name_or_ip);
|
|
||||||
data.at(repertory::JSON_PATH).get_to(value.path);
|
|
||||||
data.at(repertory::JSON_PROTOCOL).get_to(value.protocol);
|
|
||||||
data.at(repertory::JSON_TIMEOUT_MS).get_to(value.timeout_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::s3_config> {
|
|
||||||
static void to_json(json &data, const repertory::s3_config &value) {
|
|
||||||
data[repertory::JSON_ACCESS_KEY] = value.access_key;
|
|
||||||
data[repertory::JSON_BUCKET] = value.bucket;
|
|
||||||
data[repertory::JSON_ENCRYPTION_TOKEN] = value.encryption_token;
|
|
||||||
data[repertory::JSON_REGION] = value.region;
|
|
||||||
data[repertory::JSON_SECRET_KEY] = value.secret_key;
|
|
||||||
data[repertory::JSON_TIMEOUT_MS] = value.timeout_ms;
|
|
||||||
data[repertory::JSON_URL] = value.url;
|
|
||||||
data[repertory::JSON_USE_PATH_STYLE] = value.use_path_style;
|
|
||||||
data[repertory::JSON_USE_REGION_IN_URL] = value.use_region_in_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::s3_config &value) {
|
|
||||||
data.at(repertory::JSON_ACCESS_KEY).get_to(value.access_key);
|
|
||||||
data.at(repertory::JSON_BUCKET).get_to(value.bucket);
|
|
||||||
data.at(repertory::JSON_ENCRYPTION_TOKEN).get_to(value.encryption_token);
|
|
||||||
data.at(repertory::JSON_REGION).get_to(value.region);
|
|
||||||
data.at(repertory::JSON_SECRET_KEY).get_to(value.secret_key);
|
|
||||||
data.at(repertory::JSON_TIMEOUT_MS).get_to(value.timeout_ms);
|
|
||||||
data.at(repertory::JSON_URL).get_to(value.url);
|
|
||||||
data.at(repertory::JSON_USE_PATH_STYLE).get_to(value.use_path_style);
|
|
||||||
data.at(repertory::JSON_USE_REGION_IN_URL).get_to(value.use_region_in_url);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::sia_config> {
|
|
||||||
static void to_json(json &data, const repertory::sia_config &value) {
|
|
||||||
data[repertory::JSON_BUCKET] = value.bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::sia_config &value) {
|
|
||||||
data.at(repertory::JSON_BUCKET).get_to(value.bucket);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename data_t> struct adl_serializer<repertory::atomic<data_t>> {
|
|
||||||
static void to_json(json &data, const repertory::atomic<data_t> &value) {
|
|
||||||
data = value.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::atomic<data_t> &value) {
|
|
||||||
value.store(data.get<data_t>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename primitive_t>
|
|
||||||
struct adl_serializer<std::atomic<primitive_t>> {
|
|
||||||
static void to_json(json &data, const std::atomic<primitive_t> &value) {
|
|
||||||
data = value.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, std::atomic<primitive_t> &value) {
|
|
||||||
value.store(data.get<primitive_t>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<std::atomic<repertory::database_type>> {
|
|
||||||
static void to_json(json &data,
|
|
||||||
const std::atomic<repertory::database_type> &value) {
|
|
||||||
data = repertory::database_type_to_string(value.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data,
|
|
||||||
std::atomic<repertory::database_type> &value) {
|
|
||||||
value.store(repertory::database_type_from_string(data.get<std::string>()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<std::atomic<repertory::download_type>> {
|
|
||||||
static void to_json(json &data,
|
|
||||||
const std::atomic<repertory::download_type> &value) {
|
|
||||||
data = repertory::download_type_to_string(value.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data,
|
|
||||||
std::atomic<repertory::download_type> &value) {
|
|
||||||
value.store(repertory::download_type_from_string(data.get<std::string>()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::database_type> {
|
|
||||||
static void to_json(json &data, const repertory::database_type &value) {
|
|
||||||
data = repertory::database_type_to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::database_type &value) {
|
|
||||||
value = repertory::database_type_from_string(data.get<std::string>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct adl_serializer<repertory::download_type> {
|
|
||||||
static void to_json(json &data, const repertory::download_type &value) {
|
|
||||||
data = repertory::download_type_to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json &data, repertory::download_type &value) {
|
|
||||||
value = repertory::download_type_from_string(data.get<std::string>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
#endif // REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
||||||
|
@ -32,9 +32,7 @@ public:
|
|||||||
enum struct frequency {
|
enum struct frequency {
|
||||||
high,
|
high,
|
||||||
low,
|
low,
|
||||||
medium,
|
|
||||||
second,
|
second,
|
||||||
size,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct polling_item final {
|
struct polling_item final {
|
||||||
@ -62,9 +60,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
app_config *config_{nullptr};
|
app_config *config_{nullptr};
|
||||||
std::array<std::unique_ptr<std::thread>,
|
std::array<std::unique_ptr<std::thread>, 3U> frequency_threads_;
|
||||||
static_cast<std::size_t>(frequency::size)>
|
|
||||||
frequency_threads_;
|
|
||||||
std::unordered_map<std::string, polling_item> items_;
|
std::unordered_map<std::string, polling_item> items_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
std::condition_variable notify_;
|
std::condition_variable notify_;
|
||||||
|
@ -22,56 +22,15 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_UTILS_TASKS_HPP_
|
#ifndef REPERTORY_INCLUDE_UTILS_TASKS_HPP_
|
||||||
#define REPERTORY_INCLUDE_UTILS_TASKS_HPP_
|
#define REPERTORY_INCLUDE_UTILS_TASKS_HPP_
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class app_config;
|
class app_config;
|
||||||
|
|
||||||
class tasks final {
|
class tasks final {
|
||||||
public:
|
public:
|
||||||
struct task final {
|
struct task_item final {
|
||||||
std::function<void(const stop_type &task_stopped)> action;
|
std::function<void(const stop_type &stop_requested)> action;
|
||||||
};
|
|
||||||
|
|
||||||
class i_task {
|
|
||||||
INTERFACE_SETUP(i_task);
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual auto wait() const -> bool = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using task_ptr = std::shared_ptr<i_task>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class task_wait final : public i_task {
|
|
||||||
public:
|
|
||||||
task_wait() = default;
|
|
||||||
task_wait(const task_wait &) = delete;
|
|
||||||
task_wait(task_wait &&) = delete;
|
|
||||||
|
|
||||||
~task_wait() override { set_result(false); }
|
|
||||||
|
|
||||||
auto operator=(const task_wait &) -> task_wait & = delete;
|
|
||||||
auto operator=(task_wait &&) -> task_wait & = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool complete{false};
|
|
||||||
mutable std::mutex mtx;
|
|
||||||
mutable std::condition_variable notify;
|
|
||||||
bool success{false};
|
|
||||||
|
|
||||||
public:
|
|
||||||
void set_result(bool result);
|
|
||||||
|
|
||||||
auto wait() const -> bool override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct scheduled_task final {
|
|
||||||
task item;
|
|
||||||
|
|
||||||
std::shared_ptr<task_wait> wait{
|
|
||||||
std::make_shared<task_wait>(),
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -93,19 +52,18 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
app_config *config_{nullptr};
|
app_config *config_{nullptr};
|
||||||
std::atomic<std::uint64_t> count_{0U};
|
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
std::condition_variable notify_;
|
std::condition_variable notify_;
|
||||||
std::mutex start_stop_mutex_;
|
std::mutex start_stop_mutex_;
|
||||||
stop_type stop_requested_{false};
|
stop_type stop_requested_{false};
|
||||||
std::vector<std::unique_ptr<std::jthread>> task_threads_;
|
std::vector<std::unique_ptr<std::jthread>> task_threads_;
|
||||||
std::deque<scheduled_task> tasks_;
|
std::deque<task_item> tasks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void task_thread();
|
void task_thread();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto schedule(task item) -> task_ptr;
|
void schedule(task_item task);
|
||||||
|
|
||||||
void start(app_config *config);
|
void start(app_config *config);
|
||||||
|
|
||||||
|
@ -24,25 +24,15 @@
|
|||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory::utils {
|
||||||
class app_config;
|
|
||||||
|
|
||||||
namespace utils {
|
|
||||||
void calculate_allocation_size(bool directory, std::uint64_t file_size,
|
void calculate_allocation_size(bool directory, std::uint64_t file_size,
|
||||||
UINT64 allocation_size,
|
UINT64 allocation_size,
|
||||||
std::string &allocation_meta_size);
|
std::string &allocation_meta_size);
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
create_rocksdb(const app_config &cfg, const std::string &name,
|
create_volume_label(const provider_type &prov) -> std::string;
|
||||||
const std::vector<rocksdb::ColumnFamilyDescriptor> &families,
|
|
||||||
std::vector<rocksdb::ColumnFamilyHandle *> &handles, bool clear)
|
|
||||||
-> std::unique_ptr<rocksdb::TransactionDB>;
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_volume_label(const provider_type &prov)
|
|
||||||
-> std::string;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD;
|
[[nodiscard]] auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD;
|
||||||
} // namespace utils
|
} // namespace repertory::utils
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_UTILS_UTILS_HPP_
|
#endif // REPERTORY_INCLUDE_UTILS_UTILS_HPP_
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ namespace repertory {
|
|||||||
void client_pool::pool::execute(
|
void client_pool::pool::execute(
|
||||||
std::uint64_t thread_id, const worker_callback &worker,
|
std::uint64_t thread_id, const worker_callback &worker,
|
||||||
const worker_complete_callback &worker_complete) {
|
const worker_complete_callback &worker_complete) {
|
||||||
auto index = thread_id % pool_queues_.size();
|
const auto index = thread_id % pool_queues_.size();
|
||||||
auto job = std::make_shared<work_item>(worker, worker_complete);
|
auto job = std::make_shared<work_item>(worker, worker_complete);
|
||||||
auto &pool_queue = pool_queues_[index];
|
auto &pool_queue = pool_queues_[index];
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ client_pool::pool::pool(std::uint8_t pool_size) {
|
|||||||
|
|
||||||
for (std::size_t i = 0U; i < pool_queues_.size(); i++) {
|
for (std::size_t i = 0U; i < pool_queues_.size(); i++) {
|
||||||
pool_threads_.emplace_back([this]() {
|
pool_threads_.emplace_back([this]() {
|
||||||
auto thread_index = thread_index_++;
|
const auto thread_index = thread_index_++;
|
||||||
|
|
||||||
auto &pool_queue = pool_queues_[thread_index];
|
auto &pool_queue = pool_queues_[thread_index];
|
||||||
auto &queue = pool_queue->queue;
|
auto &queue = pool_queue->queue;
|
||||||
@ -74,7 +74,7 @@ client_pool::pool::pool(std::uint8_t pool_size) {
|
|||||||
queue_lock.unlock();
|
queue_lock.unlock();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto result = item->work();
|
const auto result = item->work();
|
||||||
item->work_complete(result);
|
item->work_complete(result);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
item->work_complete(utils::from_api_error(api_error::error));
|
item->work_complete(utils::from_api_error(api_error::error));
|
||||||
|
@ -36,8 +36,8 @@ void packet::clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::string &data) -> packet::error_type {
|
auto packet::decode(std::string &data) -> packet::error_type {
|
||||||
const auto *str = reinterpret_cast<const char *>(&buffer_.at(decode_offset_));
|
const auto *str = reinterpret_cast<const char *>(&buffer_[decode_offset_]);
|
||||||
auto length = strnlen(str, buffer_.size() - decode_offset_);
|
const auto length = strnlen(str, buffer_.size() - decode_offset_);
|
||||||
data = std::string(str, length);
|
data = std::string(str, length);
|
||||||
decode_offset_ += (length + 1);
|
decode_offset_ += (length + 1);
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ auto packet::decode(std::string &data) -> packet::error_type {
|
|||||||
|
|
||||||
auto packet::decode(std::wstring &data) -> packet::error_type {
|
auto packet::decode(std::wstring &data) -> packet::error_type {
|
||||||
std::string utf8_string;
|
std::string utf8_string;
|
||||||
auto ret = decode(utf8_string);
|
const auto ret = decode(utf8_string);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
data = utils::string::from_utf8(utf8_string);
|
data = utils::string::from_utf8(utf8_string);
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ auto packet::decode(void *&ptr) -> packet::error_type {
|
|||||||
|
|
||||||
auto packet::decode(void *buffer, std::size_t size) -> packet::error_type {
|
auto packet::decode(void *buffer, std::size_t size) -> packet::error_type {
|
||||||
if (size != 0U) {
|
if (size != 0U) {
|
||||||
auto read_size =
|
const auto read_size =
|
||||||
utils::calculate_read_size(buffer_.size(), size, decode_offset_);
|
utils::calculate_read_size(buffer_.size(), size, decode_offset_);
|
||||||
if (read_size == size) {
|
if (read_size == size) {
|
||||||
memcpy(buffer, &buffer_[decode_offset_], size);
|
memcpy(buffer, &buffer_[decode_offset_], size);
|
||||||
@ -76,7 +76,7 @@ auto packet::decode(void *buffer, std::size_t size) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::int8_t &val) -> packet::error_type {
|
auto packet::decode(std::int8_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ auto packet::decode(std::int8_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::uint8_t &val) -> packet::error_type {
|
auto packet::decode(std::uint8_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ auto packet::decode(std::uint8_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::int16_t &val) -> packet::error_type {
|
auto packet::decode(std::int16_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ auto packet::decode(std::int16_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::uint16_t &val) -> packet::error_type {
|
auto packet::decode(std::uint16_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ auto packet::decode(std::uint16_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::int32_t &val) -> packet::error_type {
|
auto packet::decode(std::int32_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ auto packet::decode(std::int32_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::uint32_t &val) -> packet::error_type {
|
auto packet::decode(std::uint32_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ auto packet::decode(std::uint32_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::int64_t &val) -> packet::error_type {
|
auto packet::decode(std::int64_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ auto packet::decode(std::int64_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(std::uint64_t &val) -> packet::error_type {
|
auto packet::decode(std::uint64_t &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val);
|
boost::endian::big_to_native_inplace(val);
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ auto packet::decode(std::uint64_t &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(remote::setattr_x &val) -> packet::error_type {
|
auto packet::decode(remote::setattr_x &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val.acctime);
|
boost::endian::big_to_native_inplace(val.acctime);
|
||||||
boost::endian::big_to_native_inplace(val.bkuptime);
|
boost::endian::big_to_native_inplace(val.bkuptime);
|
||||||
@ -159,7 +159,7 @@ auto packet::decode(remote::setattr_x &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(remote::stat &val) -> packet::error_type {
|
auto packet::decode(remote::stat &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val.st_mode);
|
boost::endian::big_to_native_inplace(val.st_mode);
|
||||||
boost::endian::big_to_native_inplace(val.st_nlink);
|
boost::endian::big_to_native_inplace(val.st_nlink);
|
||||||
@ -179,7 +179,7 @@ auto packet::decode(remote::stat &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(remote::statfs &val) -> packet::error_type {
|
auto packet::decode(remote::statfs &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val.f_bavail);
|
boost::endian::big_to_native_inplace(val.f_bavail);
|
||||||
boost::endian::big_to_native_inplace(val.f_bfree);
|
boost::endian::big_to_native_inplace(val.f_bfree);
|
||||||
@ -200,7 +200,7 @@ auto packet::decode(remote::statfs_x &val) -> packet::error_type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet::decode(remote::file_info &val) -> packet::error_type {
|
auto packet::decode(remote::file_info &val) -> packet::error_type {
|
||||||
auto ret = decode(&val, sizeof(val));
|
const auto ret = decode(&val, sizeof(val));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
boost::endian::big_to_native_inplace(val.AllocationSize);
|
boost::endian::big_to_native_inplace(val.AllocationSize);
|
||||||
boost::endian::big_to_native_inplace(val.ChangeTime);
|
boost::endian::big_to_native_inplace(val.ChangeTime);
|
||||||
@ -268,7 +268,7 @@ void packet::encode(const void *buffer, std::size_t size, bool should_reserve) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void packet::encode(std::string_view str) {
|
void packet::encode(std::string_view str) {
|
||||||
auto len = str.size();
|
const auto len = str.size();
|
||||||
buffer_.reserve(len + 1 + buffer_.size());
|
buffer_.reserve(len + 1 + buffer_.size());
|
||||||
encode(str.data(), len, false);
|
encode(str.data(), len, false);
|
||||||
buffer_.emplace_back(0);
|
buffer_.emplace_back(0);
|
||||||
@ -401,7 +401,7 @@ void packet::encode_top(const void *buffer, std::size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void packet::encode_top(std::string_view str) {
|
void packet::encode_top(std::string_view str) {
|
||||||
auto len = str.size();
|
const auto len = str.size();
|
||||||
buffer_.reserve(len + 1U + buffer_.size());
|
buffer_.reserve(len + 1U + buffer_.size());
|
||||||
encode_top(str.data(), len, false);
|
encode_top(str.data(), len, false);
|
||||||
buffer_.insert(buffer_.begin() + static_cast<std::int32_t>(len), 0);
|
buffer_.insert(buffer_.begin() + static_cast<std::int32_t>(len), 0);
|
||||||
@ -531,7 +531,7 @@ void packet::encrypt(std::string_view token) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void packet::to_buffer(data_buffer &buffer) {
|
void packet::transfer_into(data_buffer &buffer) {
|
||||||
buffer = std::move(buffer_);
|
buffer = std::move(buffer_);
|
||||||
buffer_ = data_buffer();
|
buffer_ = data_buffer();
|
||||||
decode_offset_ = 0;
|
decode_offset_ = 0;
|
||||||
|
@ -38,8 +38,18 @@ E_SIMPLE2(packet_client_timeout, error, true,
|
|||||||
);
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
packet_client::packet_client(remote::remote_config cfg)
|
packet_client::packet_client(std::string host_name_or_ip,
|
||||||
: cfg_(std::move(cfg)), unique_id_(utils::create_uuid_string()) {}
|
std::uint8_t max_connections, std::uint16_t port,
|
||||||
|
std::uint16_t receive_timeout,
|
||||||
|
std::uint16_t send_timeout,
|
||||||
|
std::string encryption_token)
|
||||||
|
: host_name_or_ip_(std::move(host_name_or_ip)),
|
||||||
|
max_connections_(max_connections == 0U ? 20U : max_connections),
|
||||||
|
port_(port),
|
||||||
|
receive_timeout_(receive_timeout),
|
||||||
|
send_timeout_(send_timeout),
|
||||||
|
encryption_token_(std::move(encryption_token)),
|
||||||
|
unique_id_(utils::create_uuid_string()) {}
|
||||||
|
|
||||||
packet_client::~packet_client() {
|
packet_client::~packet_client() {
|
||||||
allow_connections_ = false;
|
allow_connections_ = false;
|
||||||
@ -75,7 +85,7 @@ void packet_client::connect(client &cli) {
|
|||||||
cli.socket.set_option(boost::asio::socket_base::linger(false, 0));
|
cli.socket.set_option(boost::asio::socket_base::linger(false, 0));
|
||||||
|
|
||||||
packet response;
|
packet response;
|
||||||
auto res = read_packet(cli, response);
|
const auto res = read_packet(cli, response);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
throw std::runtime_error(std::to_string(res));
|
throw std::runtime_error(std::to_string(res));
|
||||||
}
|
}
|
||||||
@ -85,27 +95,27 @@ void packet_client::connect(client &cli) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto packet_client::get_client() -> std::shared_ptr<packet_client::client> {
|
auto packet_client::get_client() -> std::shared_ptr<packet_client::client> {
|
||||||
|
std::shared_ptr<client> ret;
|
||||||
|
|
||||||
unique_mutex_lock clients_lock(clients_mutex_);
|
unique_mutex_lock clients_lock(clients_mutex_);
|
||||||
if (not allow_connections_) {
|
if (allow_connections_) {
|
||||||
return nullptr;
|
if (clients_.empty()) {
|
||||||
|
clients_lock.unlock();
|
||||||
|
ret = std::make_shared<client>(io_context_);
|
||||||
|
connect(*ret);
|
||||||
|
} else {
|
||||||
|
ret = clients_[0U];
|
||||||
|
utils::collection::remove_element(clients_, ret);
|
||||||
|
clients_lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clients_.empty()) {
|
return ret;
|
||||||
clients_lock.unlock();
|
|
||||||
|
|
||||||
auto cli = std::make_shared<client>(io_context_);
|
|
||||||
connect(*cli);
|
|
||||||
return cli;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cli = clients_.at(0U);
|
|
||||||
utils::collection::remove_element(clients_, cli);
|
|
||||||
return cli;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void packet_client::put_client(std::shared_ptr<client> &cli) {
|
void packet_client::put_client(std::shared_ptr<client> &cli) {
|
||||||
mutex_lock clientsLock(clients_mutex_);
|
mutex_lock clientsLock(clients_mutex_);
|
||||||
if (clients_.size() < cfg_.max_connections) {
|
if (clients_.size() < max_connections_) {
|
||||||
clients_.emplace_back(cli);
|
clients_.emplace_back(cli);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +126,7 @@ auto packet_client::read_packet(client &cli, packet &response)
|
|||||||
const auto read_buffer = [&]() {
|
const auto read_buffer = [&]() {
|
||||||
std::uint32_t offset{};
|
std::uint32_t offset{};
|
||||||
while (offset < buffer.size()) {
|
while (offset < buffer.size()) {
|
||||||
auto bytes_read = boost::asio::read(
|
const auto bytes_read = boost::asio::read(
|
||||||
cli.socket,
|
cli.socket,
|
||||||
boost::asio::buffer(&buffer[offset], buffer.size() - offset));
|
boost::asio::buffer(&buffer[offset], buffer.size() - offset));
|
||||||
if (bytes_read <= 0) {
|
if (bytes_read <= 0) {
|
||||||
@ -127,14 +137,14 @@ auto packet_client::read_packet(client &cli, packet &response)
|
|||||||
};
|
};
|
||||||
read_buffer();
|
read_buffer();
|
||||||
|
|
||||||
auto size = boost::endian::big_to_native(
|
const auto size = boost::endian::big_to_native(
|
||||||
*reinterpret_cast<std::uint32_t *>(buffer.data()));
|
*reinterpret_cast<std::uint32_t *>(buffer.data()));
|
||||||
buffer.resize(size);
|
buffer.resize(size);
|
||||||
|
|
||||||
read_buffer();
|
read_buffer();
|
||||||
response = std::move(buffer);
|
response = std::move(buffer);
|
||||||
|
|
||||||
auto ret = response.decrypt(cfg_.encryption_token);
|
auto ret = response.decrypt(encryption_token_);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = response.decode(cli.nonce);
|
ret = response.decode(cli.nonce);
|
||||||
}
|
}
|
||||||
@ -143,13 +153,10 @@ auto packet_client::read_packet(client &cli, packet &response)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void packet_client::resolve() {
|
void packet_client::resolve() {
|
||||||
if (not resolve_results_.empty()) {
|
if (resolve_results_.empty()) {
|
||||||
return;
|
resolve_results_ = tcp::resolver(io_context_)
|
||||||
|
.resolve({host_name_or_ip_, std::to_string(port_)});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve_results_ =
|
|
||||||
tcp::resolver(io_context_)
|
|
||||||
.resolve(cfg_.host_name_or_ip, std::to_string(cfg_.api_port));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto packet_client::send(std::string_view method, std::uint32_t &service_flags)
|
auto packet_client::send(std::string_view method, std::uint32_t &service_flags)
|
||||||
@ -177,14 +184,14 @@ auto packet_client::send(std::string_view method, packet &request,
|
|||||||
request.encode_top(PACKET_SERVICE_FLAGS);
|
request.encode_top(PACKET_SERVICE_FLAGS);
|
||||||
request.encode_top(std::string{project_get_version()});
|
request.encode_top(std::string{project_get_version()});
|
||||||
|
|
||||||
static constexpr const std::uint8_t max_attempts{5U};
|
static const std::uint8_t max_attempts{5U};
|
||||||
for (std::uint8_t i = 1U;
|
for (std::uint8_t i = 1U;
|
||||||
allow_connections_ && not success && (i <= max_attempts); i++) {
|
allow_connections_ && not success && (i <= max_attempts); i++) {
|
||||||
auto current_client = get_client();
|
auto current_client = get_client();
|
||||||
if (current_client) {
|
if (current_client) {
|
||||||
try {
|
try {
|
||||||
request.encode_top(current_client->nonce);
|
request.encode_top(current_client->nonce);
|
||||||
request.encrypt(cfg_.encryption_token);
|
request.encrypt(encryption_token_);
|
||||||
|
|
||||||
timeout request_timeout(
|
timeout request_timeout(
|
||||||
[method, current_client]() {
|
[method, current_client]() {
|
||||||
@ -192,11 +199,11 @@ auto packet_client::send(std::string_view method, packet &request,
|
|||||||
"request", std::string{method});
|
"request", std::string{method});
|
||||||
packet_client::close(*current_client);
|
packet_client::close(*current_client);
|
||||||
},
|
},
|
||||||
std::chrono::milliseconds(cfg_.send_timeout_ms));
|
std::chrono::seconds(send_timeout_));
|
||||||
|
|
||||||
std::uint32_t offset{};
|
std::uint32_t offset{};
|
||||||
while (offset < request.get_size()) {
|
while (offset < request.get_size()) {
|
||||||
auto bytes_written = boost::asio::write(
|
const auto bytes_written = boost::asio::write(
|
||||||
current_client->socket,
|
current_client->socket,
|
||||||
boost::asio::buffer(&request[offset],
|
boost::asio::buffer(&request[offset],
|
||||||
request.get_size() - offset));
|
request.get_size() - offset));
|
||||||
@ -214,7 +221,7 @@ auto packet_client::send(std::string_view method, packet &request,
|
|||||||
"response", std::string{method});
|
"response", std::string{method});
|
||||||
packet_client::close(*current_client);
|
packet_client::close(*current_client);
|
||||||
},
|
},
|
||||||
std::chrono::milliseconds(cfg_.recv_timeout_ms));
|
std::chrono::seconds(receive_timeout_));
|
||||||
|
|
||||||
ret = read_packet(*current_client, response);
|
ret = read_packet(*current_client, response);
|
||||||
response_timeout.disable();
|
response_timeout.disable();
|
||||||
|
@ -72,7 +72,7 @@ void packet_server::initialize(const uint16_t &port, uint8_t pool_size) {
|
|||||||
server_thread_ = std::make_unique<std::thread>([this, port, pool_size]() {
|
server_thread_ = std::make_unique<std::thread>([this, port, pool_size]() {
|
||||||
tcp::acceptor acceptor(io_context_);
|
tcp::acceptor acceptor(io_context_);
|
||||||
try {
|
try {
|
||||||
auto endpoint = tcp::endpoint(tcp::v4(), port);
|
const auto endpoint = tcp::endpoint(tcp::v4(), port);
|
||||||
acceptor.open(endpoint.protocol());
|
acceptor.open(endpoint.protocol());
|
||||||
acceptor.set_option(socket_base::reuse_address(true));
|
acceptor.set_option(socket_base::reuse_address(true));
|
||||||
acceptor.bind(endpoint);
|
acceptor.bind(endpoint);
|
||||||
@ -148,7 +148,7 @@ void packet_server::read_packet(std::shared_ptr<connection> conn,
|
|||||||
const auto read_buffer = [&]() {
|
const auto read_buffer = [&]() {
|
||||||
std::uint32_t offset{};
|
std::uint32_t offset{};
|
||||||
while (offset < conn->buffer.size()) {
|
while (offset < conn->buffer.size()) {
|
||||||
auto bytes_read = boost::asio::read(
|
const auto bytes_read = boost::asio::read(
|
||||||
conn->socket, boost::asio::buffer(&conn->buffer[offset],
|
conn->socket, boost::asio::buffer(&conn->buffer[offset],
|
||||||
conn->buffer.size() - offset));
|
conn->buffer.size() - offset));
|
||||||
if (bytes_read <= 0) {
|
if (bytes_read <= 0) {
|
||||||
@ -244,7 +244,7 @@ void packet_server::send_response(std::shared_ptr<connection> conn,
|
|||||||
response.encode_top(PACKET_SERVICE_FLAGS);
|
response.encode_top(PACKET_SERVICE_FLAGS);
|
||||||
response.encode_top(conn->nonce);
|
response.encode_top(conn->nonce);
|
||||||
response.encrypt(encryption_token_);
|
response.encrypt(encryption_token_);
|
||||||
response.to_buffer(conn->buffer);
|
response.transfer_into(conn->buffer);
|
||||||
|
|
||||||
boost::asio::async_write(
|
boost::asio::async_write(
|
||||||
conn->socket, boost::asio::buffer(conn->buffer),
|
conn->socket, boost::asio::buffer(conn->buffer),
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/file_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "db/impl/rdb_file_db.hpp"
|
|
||||||
#include "db/impl/sqlite_file_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
auto create_file_db(const app_config &cfg) -> std::unique_ptr<i_file_db> {
|
|
||||||
switch (cfg.get_database_type()) {
|
|
||||||
case database_type::sqlite:
|
|
||||||
return std::make_unique<sqlite_file_db>(cfg);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return std::make_unique<rdb_file_db>(cfg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/file_mgr_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "db/i_file_mgr_db.hpp"
|
|
||||||
#include "db/impl/rdb_file_mgr_db.hpp"
|
|
||||||
#include "db/impl/sqlite_file_mgr_db.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
auto create_file_mgr_db(const app_config &cfg)
|
|
||||||
-> std::unique_ptr<i_file_mgr_db> {
|
|
||||||
switch (cfg.get_database_type()) {
|
|
||||||
case database_type::sqlite:
|
|
||||||
return std::make_unique<sqlite_file_mgr_db>(cfg);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return std::make_unique<rdb_file_mgr_db>(cfg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,390 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/impl/rdb_file_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/config.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "utils/string.hpp"
|
|
||||||
#include "utils/utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
rdb_file_db::rdb_file_db(const app_config &cfg) : cfg_(cfg) {
|
|
||||||
create_or_open(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
rdb_file_db::~rdb_file_db() { db_.reset(); }
|
|
||||||
|
|
||||||
void rdb_file_db::create_or_open(bool clear) {
|
|
||||||
db_.reset();
|
|
||||||
|
|
||||||
auto families = std::vector<rocksdb::ColumnFamilyDescriptor>();
|
|
||||||
families.emplace_back(rocksdb::kDefaultColumnFamilyName,
|
|
||||||
rocksdb::ColumnFamilyOptions());
|
|
||||||
families.emplace_back("file", rocksdb::ColumnFamilyOptions());
|
|
||||||
families.emplace_back("path", rocksdb::ColumnFamilyOptions());
|
|
||||||
families.emplace_back("source", rocksdb::ColumnFamilyOptions());
|
|
||||||
|
|
||||||
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
|
||||||
db_ = utils::create_rocksdb(cfg_, "file", families, handles, clear);
|
|
||||||
|
|
||||||
std::size_t idx{};
|
|
||||||
directory_family_ = handles.at(idx++);
|
|
||||||
file_family_ = handles.at(idx++);
|
|
||||||
path_family_ = handles.at(idx++);
|
|
||||||
source_family_ = handles.at(idx++);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::add_directory(const std::string &api_path,
|
|
||||||
const std::string &source_path) -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
std::string existing_source_path;
|
|
||||||
auto result = get_directory_source_path(api_path, existing_source_path);
|
|
||||||
if (result != api_error::success &&
|
|
||||||
result != api_error::directory_not_found) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name, [&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
if (not existing_source_path.empty()) {
|
|
||||||
auto res = remove_item(api_path, existing_source_path, txn);
|
|
||||||
if (not res.ok() && not res.IsNotFound()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = txn->Put(directory_family_, api_path, source_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = txn->Put(path_family_, api_path, source_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return txn->Put(source_family_, source_path, api_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::add_or_update_file(const i_file_db::file_data &data)
|
|
||||||
-> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
std::string existing_source_path;
|
|
||||||
auto result = get_file_source_path(data.api_path, existing_source_path);
|
|
||||||
if (result != api_error::success && result != api_error::item_not_found) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name, [&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
if (not existing_source_path.empty()) {
|
|
||||||
auto res = remove_item(data.api_path, existing_source_path, txn);
|
|
||||||
if (not res.ok() && not res.IsNotFound()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json json_data = {
|
|
||||||
{"file_size", data.file_size},
|
|
||||||
{"iv", data.iv_list},
|
|
||||||
{"source_path", data.source_path},
|
|
||||||
};
|
|
||||||
|
|
||||||
auto res = txn->Put(file_family_, data.api_path, json_data.dump());
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = txn->Put(path_family_, data.api_path, data.source_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return txn->Put(source_family_, data.source_path, data.api_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void rdb_file_db::clear() { create_or_open(true); }
|
|
||||||
|
|
||||||
auto rdb_file_db::create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
|
||||||
-> std::shared_ptr<rocksdb::Iterator> {
|
|
||||||
return std::shared_ptr<rocksdb::Iterator>(
|
|
||||||
db_->NewIterator(rocksdb::ReadOptions{}, family));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::count() const -> std::uint64_t {
|
|
||||||
std::uint64_t ret{};
|
|
||||||
|
|
||||||
auto iter = create_iterator(source_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
++ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
return db_->Get(rocksdb::ReadOptions{}, source_family_, source_path,
|
|
||||||
&api_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_directory_api_path(
|
|
||||||
const std::string &source_path, std::string &api_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
auto res = db_->Get(rocksdb::ReadOptions{}, source_family_, source_path,
|
|
||||||
&api_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string value;
|
|
||||||
return db_->Get(rocksdb::ReadOptions{}, directory_family_, api_path,
|
|
||||||
&value);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result != api_error::success) {
|
|
||||||
api_path.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result == api_error::item_not_found ? api_error::directory_not_found
|
|
||||||
: result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_directory_source_path(
|
|
||||||
const std::string &api_path, std::string &source_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
return db_->Get(rocksdb::ReadOptions{}, directory_family_, api_path,
|
|
||||||
&source_path);
|
|
||||||
});
|
|
||||||
|
|
||||||
return result == api_error::item_not_found ? api_error::directory_not_found
|
|
||||||
: result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_file_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
auto res = db_->Get(rocksdb::ReadOptions{}, source_family_, source_path,
|
|
||||||
&api_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string value;
|
|
||||||
return db_->Get(rocksdb::ReadOptions{}, file_family_, api_path, &value);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result != api_error::success) {
|
|
||||||
api_path.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_file_data(const std::string &api_path,
|
|
||||||
i_file_db::file_data &data) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
std::string value;
|
|
||||||
auto res = db_->Get(rocksdb::ReadOptions{}, file_family_, api_path, &value);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto json_data = json::parse(value);
|
|
||||||
data.api_path = api_path;
|
|
||||||
data.file_size = json_data.at("file_size").get<std::uint64_t>();
|
|
||||||
data.iv_list =
|
|
||||||
json_data.at("iv")
|
|
||||||
.get<std::vector<
|
|
||||||
std::array<unsigned char,
|
|
||||||
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>>();
|
|
||||||
data.source_path = json_data.at("source_path").get<std::string>();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_file_source_path(
|
|
||||||
const std::string &api_path, std::string &source_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
std::string value;
|
|
||||||
auto res = db_->Get(rocksdb::ReadOptions{}, file_family_, api_path, &value);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto json_data = json::parse(value);
|
|
||||||
source_path = json_data.at("source_path").get<std::string>();
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_item_list() const -> std::vector<i_file_db::file_info> {
|
|
||||||
std::vector<i_file_db::file_info> ret{};
|
|
||||||
{
|
|
||||||
auto iter = create_iterator(directory_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
ret.emplace_back(i_file_db::file_info{
|
|
||||||
iter->key().ToString(),
|
|
||||||
true,
|
|
||||||
iter->value().ToString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto iter = create_iterator(file_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
auto json_data = json::parse(iter->value().ToString());
|
|
||||||
ret.emplace_back(i_file_db::file_info{
|
|
||||||
iter->key().ToString(),
|
|
||||||
true,
|
|
||||||
json_data.at("source_path").get<std::string>(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::get_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(function_name, [&]() -> rocksdb::Status {
|
|
||||||
return db_->Get(rocksdb::ReadOptions{}, path_family_, api_path,
|
|
||||||
&source_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::perform_action(std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status()> action)
|
|
||||||
-> api_error {
|
|
||||||
auto res = action();
|
|
||||||
if (res.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not res.IsNotFound()) {
|
|
||||||
utils::error::raise_error(function_name, res.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.IsNotFound() ? api_error::item_not_found : api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action)
|
|
||||||
-> api_error {
|
|
||||||
std::unique_ptr<rocksdb::Transaction> txn{
|
|
||||||
db_->BeginTransaction(rocksdb::WriteOptions{},
|
|
||||||
rocksdb::TransactionOptions{}),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto res = action(txn.get());
|
|
||||||
if (res.ok()) {
|
|
||||||
auto commit_res = txn->Commit();
|
|
||||||
if (commit_res.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb commit failed|" + res.ToString());
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb action failed|" + res.ToString());
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex,
|
|
||||||
"failed to handle rocksdb action");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rollback_res = txn->Rollback();
|
|
||||||
utils::error::raise_error(function_name, "rocksdb rollback failed|" +
|
|
||||||
rollback_res.ToString());
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::remove_item(const std::string &api_path) -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
auto res = get_source_path(api_path, source_path);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return perform_action(function_name,
|
|
||||||
[&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return remove_item(api_path, source_path, txn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_db::remove_item(const std::string &api_path,
|
|
||||||
const std::string &source_path,
|
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
auto res = txn->Delete(source_family_, source_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = txn->Delete(path_family_, api_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = txn->Delete(directory_family_, api_path);
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return txn->Delete(file_family_, api_path);
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,327 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/impl/rdb_file_mgr_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/config.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "utils/string.hpp"
|
|
||||||
#include "utils/utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
rdb_file_mgr_db::rdb_file_mgr_db(const app_config &cfg) : cfg_(cfg) {
|
|
||||||
create_or_open(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
rdb_file_mgr_db::~rdb_file_mgr_db() { db_.reset(); }
|
|
||||||
|
|
||||||
void rdb_file_mgr_db::create_or_open(bool clear) {
|
|
||||||
db_.reset();
|
|
||||||
|
|
||||||
auto families = std::vector<rocksdb::ColumnFamilyDescriptor>();
|
|
||||||
families.emplace_back(rocksdb::kDefaultColumnFamilyName,
|
|
||||||
rocksdb::ColumnFamilyOptions());
|
|
||||||
families.emplace_back("upload_active", rocksdb::ColumnFamilyOptions());
|
|
||||||
families.emplace_back("upload", rocksdb::ColumnFamilyOptions());
|
|
||||||
|
|
||||||
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
|
||||||
db_ = utils::create_rocksdb(cfg_, "file_mgr", families, handles, clear);
|
|
||||||
|
|
||||||
std::size_t idx{};
|
|
||||||
resume_family_ = handles.at(idx++);
|
|
||||||
upload_active_family_ = handles.at(idx++);
|
|
||||||
upload_family_ = handles.at(idx++);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::add_resume(const resume_entry &entry) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &entry](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return add_resume(entry, txn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::add_resume(const resume_entry &entry,
|
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto data = json({
|
|
||||||
{"chunk_size", entry.chunk_size},
|
|
||||||
{"read_state", utils::string::from_dynamic_bitset(entry.read_state)},
|
|
||||||
{"source_path", entry.source_path},
|
|
||||||
});
|
|
||||||
return txn->Put(resume_family_, entry.api_path, data.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::add_upload(const upload_entry &entry) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &entry](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return txn->Put(upload_family_,
|
|
||||||
utils::string::zero_pad(std::to_string(++id_), 20U) +
|
|
||||||
'|' + entry.api_path,
|
|
||||||
entry.source_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::add_upload_active(const upload_active_entry &entry)
|
|
||||||
-> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &entry](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return txn->Put(upload_active_family_, entry.api_path,
|
|
||||||
entry.source_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void rdb_file_mgr_db::clear() { create_or_open(true); }
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
|
||||||
-> std::shared_ptr<rocksdb::Iterator> {
|
|
||||||
return std::shared_ptr<rocksdb::Iterator>(
|
|
||||||
db_->NewIterator(rocksdb::ReadOptions(), family));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::get_next_upload() const -> std::optional<upload_entry> {
|
|
||||||
auto iter = create_iterator(upload_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
auto parts = utils::string::split(iter->key().ToString(), '|', false);
|
|
||||||
parts.erase(parts.begin());
|
|
||||||
|
|
||||||
auto api_path = utils::string::join(parts, '|');
|
|
||||||
|
|
||||||
return upload_entry{
|
|
||||||
api_path,
|
|
||||||
iter->value().ToString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::get_resume_list() const -> std::vector<resume_entry> {
|
|
||||||
std::vector<resume_entry> ret;
|
|
||||||
|
|
||||||
auto iter = create_iterator(resume_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
auto data = json::parse(iter->value().ToString());
|
|
||||||
ret.emplace_back(resume_entry{
|
|
||||||
iter->key().ToString(),
|
|
||||||
data.at("chunk_size").get<std::uint64_t>(),
|
|
||||||
utils::string::to_dynamic_bitset(
|
|
||||||
data.at("read_state").get<std::string>()),
|
|
||||||
data.at("source_path").get<std::string>(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::get_upload(const std::string &api_path) const
|
|
||||||
-> std::optional<upload_entry> {
|
|
||||||
auto iter = create_iterator(upload_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
auto parts = utils::string::split(iter->key().ToString(), '|', false);
|
|
||||||
parts.erase(parts.begin());
|
|
||||||
|
|
||||||
if (api_path != utils::string::join(parts, '|')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return upload_entry{
|
|
||||||
api_path,
|
|
||||||
iter->value().ToString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::get_upload_active_list() const
|
|
||||||
-> std::vector<upload_active_entry> {
|
|
||||||
std::vector<upload_active_entry> ret;
|
|
||||||
|
|
||||||
auto iter = create_iterator(upload_active_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
ret.emplace_back(upload_active_entry{
|
|
||||||
iter->key().ToString(),
|
|
||||||
iter->value().ToString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::perform_action(std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status()> action)
|
|
||||||
-> bool {
|
|
||||||
try {
|
|
||||||
auto res = action();
|
|
||||||
if (not res.ok()) {
|
|
||||||
utils::error::raise_error(function_name, res.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.ok();
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action) -> bool {
|
|
||||||
std::unique_ptr<rocksdb::Transaction> txn{
|
|
||||||
db_->BeginTransaction(rocksdb::WriteOptions{},
|
|
||||||
rocksdb::TransactionOptions{}),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto res = action(txn.get());
|
|
||||||
if (res.ok()) {
|
|
||||||
auto commit_res = txn->Commit();
|
|
||||||
if (commit_res.ok()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb commit failed|" + res.ToString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb action failed|" + res.ToString());
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex,
|
|
||||||
"failed to handle rocksdb action");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rollback_res = txn->Rollback();
|
|
||||||
utils::error::raise_error(function_name, "rocksdb rollback failed|" +
|
|
||||||
rollback_res.ToString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::remove_resume(const std::string &api_path) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &api_path](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return remove_resume(api_path, txn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::remove_resume(
|
|
||||||
const std::string &api_path, rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return txn->Delete(resume_family_, api_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::remove_upload(const std::string &api_path) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto iter = create_iterator(upload_family_);
|
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
||||||
auto parts = utils::string::split(iter->key().ToString(), '|', false);
|
|
||||||
parts.erase(parts.begin());
|
|
||||||
|
|
||||||
if (api_path != utils::string::join(parts, '|')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &iter](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return txn->Delete(upload_family_, iter->key());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::remove_upload_active(const std::string &api_path)
|
|
||||||
-> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
return perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &api_path](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
return txn->Delete(upload_active_family_, api_path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_file_mgr_db::rename_resume(const std::string &from_api_path,
|
|
||||||
const std::string &to_api_path) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
bool not_found{false};
|
|
||||||
std::string value;
|
|
||||||
auto res = perform_action(
|
|
||||||
function_name,
|
|
||||||
[this, &from_api_path, ¬_found, &value]() -> rocksdb::Status {
|
|
||||||
auto result = db_->Get(rocksdb::ReadOptions{}, from_api_path, &value);
|
|
||||||
not_found = result.IsNotFound();
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
if (not_found) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not res) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = json::parse(value);
|
|
||||||
resume_entry entry{
|
|
||||||
to_api_path,
|
|
||||||
data.at("chunk_size").get<std::uint64_t>(),
|
|
||||||
utils::string::to_dynamic_bitset(
|
|
||||||
data.at("read_state").get<std::string>()),
|
|
||||||
data.at("source_path").get<std::string>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return perform_action(function_name,
|
|
||||||
[this, &entry, &from_api_path](
|
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
auto txn_res = remove_resume(from_api_path, txn);
|
|
||||||
if (not txn_res.ok()) {
|
|
||||||
return txn_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return add_resume(entry, txn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,334 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/impl/sqlite_file_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/config.hpp"
|
|
||||||
#include "utils/db/sqlite/db_common.hpp"
|
|
||||||
#include "utils/db/sqlite/db_delete.hpp"
|
|
||||||
#include "utils/db/sqlite/db_insert.hpp"
|
|
||||||
#include "utils/db/sqlite/db_select.hpp"
|
|
||||||
#include "utils/db/sqlite/db_update.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "utils/string.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
const std::string file_table = "file";
|
|
||||||
const std::map<std::string, std::string> sql_create_tables = {
|
|
||||||
{
|
|
||||||
{file_table},
|
|
||||||
{"CREATE TABLE IF NOT EXISTS " + file_table +
|
|
||||||
"("
|
|
||||||
"source_path TEXT PRIMARY KEY ASC, "
|
|
||||||
"api_path TEXT UNIQUE NOT NULL, "
|
|
||||||
"iv TEXT DEFAULT '' NOT NULL, "
|
|
||||||
"directory INTEGER NOT NULL, "
|
|
||||||
"size INTEGER DEFAULT 0 NOT NULL"
|
|
||||||
");"},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
sqlite_file_db::sqlite_file_db(const app_config &cfg) {
|
|
||||||
auto db_dir = utils::path::combine(cfg.get_data_directory(), {"db"});
|
|
||||||
if (not utils::file::directory{db_dir}.create_directory()) {
|
|
||||||
throw startup_exception(
|
|
||||||
fmt::format("failed to create db directory|", db_dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
db_ = utils::db::sqlite::create_db(utils::path::combine(db_dir, {"file.db"}),
|
|
||||||
sql_create_tables);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite_file_db::~sqlite_file_db() { db_.reset(); }
|
|
||||||
|
|
||||||
auto sqlite_file_db::add_directory(const std::string &api_path,
|
|
||||||
const std::string &source_path)
|
|
||||||
-> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = utils::db::sqlite::db_insert{*db_, file_table}
|
|
||||||
.column_value("api_path", api_path)
|
|
||||||
.column_value("directory", 1)
|
|
||||||
.column_value("source_path", source_path)
|
|
||||||
.go();
|
|
||||||
if (result.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, api_path, api_error::error,
|
|
||||||
fmt::format("failed to add directory|{}", result.get_error_str()));
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::add_or_update_file(const i_file_db::file_data &data)
|
|
||||||
-> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result =
|
|
||||||
utils::db::sqlite::db_insert{*db_, file_table}
|
|
||||||
.or_replace()
|
|
||||||
.column_value("api_path", data.api_path)
|
|
||||||
.column_value("directory", 0)
|
|
||||||
.column_value("iv", json(data.iv_list).dump())
|
|
||||||
.column_value("size", static_cast<std::int64_t>(data.file_size))
|
|
||||||
.column_value("source_path", data.source_path)
|
|
||||||
.go();
|
|
||||||
if (result.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, data.api_path, api_error::error,
|
|
||||||
fmt::format("failed to add file|{}", result.get_error_str()));
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sqlite_file_db::clear() {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = utils::db::sqlite::db_delete{*db_, file_table}.go();
|
|
||||||
if (not result.ok()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
fmt::format("failed to clear file table|{}",
|
|
||||||
std::to_string(result.get_error())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::count() const -> std::uint64_t {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.count("api_path", "count")
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
return static_cast<std::uint64_t>(
|
|
||||||
row->get_column("count").get_value<std::int64_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const -> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("api_path")
|
|
||||||
.where("source_path")
|
|
||||||
.equals(source_path)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
api_path = row->get_column("api_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::item_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_directory_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("api_path")
|
|
||||||
.where("source_path")
|
|
||||||
.equals(source_path)
|
|
||||||
.and_()
|
|
||||||
.where("directory")
|
|
||||||
.equals(1)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
api_path = row->get_column("api_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::directory_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_directory_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("source_path")
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.and_()
|
|
||||||
.where("directory")
|
|
||||||
.equals(1)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
source_path = row->get_column("source_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::directory_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_file_api_path(const std::string &source_path,
|
|
||||||
std::string &api_path) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("api_path")
|
|
||||||
.where("source_path")
|
|
||||||
.equals(source_path)
|
|
||||||
.and_()
|
|
||||||
.where("directory")
|
|
||||||
.equals(0)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
api_path = row->get_column("api_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::item_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_file_data(const std::string &api_path,
|
|
||||||
i_file_db::file_data &data) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("iv")
|
|
||||||
.column("size")
|
|
||||||
.column("source_path")
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.and_()
|
|
||||||
.where("directory")
|
|
||||||
.equals(0)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
data.api_path = api_path;
|
|
||||||
data.file_size = static_cast<std::uint64_t>(
|
|
||||||
row->get_column("size").get_value<std::int64_t>());
|
|
||||||
data.source_path = row->get_column("source_path").get_value<std::string>();
|
|
||||||
|
|
||||||
auto str_data = row->get_column("iv").get_value<std::string>();
|
|
||||||
if (not str_data.empty()) {
|
|
||||||
data.iv_list =
|
|
||||||
json::parse(str_data)
|
|
||||||
.get<std::vector<
|
|
||||||
std::array<unsigned char,
|
|
||||||
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::item_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_file_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("source_path")
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.and_()
|
|
||||||
.where("directory")
|
|
||||||
.equals(0)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
source_path = row->get_column("source_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::item_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_item_list() const
|
|
||||||
-> std::vector<i_file_db::file_info> {
|
|
||||||
std::vector<i_file_db::file_info> ret;
|
|
||||||
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}.go();
|
|
||||||
while (result.has_row()) {
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
ret.emplace_back(i_file_db::file_info{
|
|
||||||
row->get_column("api_path").get_value<std::string>(),
|
|
||||||
row->get_column("directory").get_value<std::int64_t>() == 1,
|
|
||||||
row->get_column("source_path").get_value<std::string>(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
result.next_row();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::get_source_path(const std::string &api_path,
|
|
||||||
std::string &source_path) const
|
|
||||||
-> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, file_table}
|
|
||||||
.column("source_path")
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.op()
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (result.get_row(row) && row.has_value()) {
|
|
||||||
source_path = row->get_column("source_path").get_value<std::string>();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::item_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_db::remove_item(const std::string &api_path) -> api_error {
|
|
||||||
auto result = utils::db::sqlite::db_delete{*db_, file_table}
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.go();
|
|
||||||
|
|
||||||
return result.ok() ? api_error::success : api_error::error;
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,275 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "db/impl/sqlite_file_mgr_db.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/config.hpp"
|
|
||||||
#include "utils/db/sqlite/db_common.hpp"
|
|
||||||
#include "utils/db/sqlite/db_delete.hpp"
|
|
||||||
#include "utils/db/sqlite/db_insert.hpp"
|
|
||||||
#include "utils/db/sqlite/db_select.hpp"
|
|
||||||
#include "utils/db/sqlite/db_update.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "utils/string.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
const std::string resume_table = "resume";
|
|
||||||
const std::string upload_table = "upload";
|
|
||||||
const std::string upload_active_table = "upload_active";
|
|
||||||
const std::map<std::string, std::string> sql_create_tables{
|
|
||||||
{
|
|
||||||
{resume_table},
|
|
||||||
{
|
|
||||||
"CREATE TABLE IF NOT EXISTS " + resume_table +
|
|
||||||
"("
|
|
||||||
"api_path TEXT PRIMARY KEY ASC, "
|
|
||||||
"chunk_size INTEGER, "
|
|
||||||
"read_state TEXT, "
|
|
||||||
"source_path TEXT"
|
|
||||||
");",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{upload_table},
|
|
||||||
{
|
|
||||||
"CREATE TABLE IF NOT EXISTS " + upload_table +
|
|
||||||
"("
|
|
||||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
|
||||||
"api_path TEXT UNIQUE, "
|
|
||||||
"source_path TEXT"
|
|
||||||
");",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{upload_active_table},
|
|
||||||
{
|
|
||||||
"CREATE TABLE IF NOT EXISTS " + upload_active_table +
|
|
||||||
"("
|
|
||||||
"api_path TEXT PRIMARY KEY ASC, "
|
|
||||||
"source_path TEXT"
|
|
||||||
");",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
sqlite_file_mgr_db::sqlite_file_mgr_db(const app_config &cfg) {
|
|
||||||
auto db_dir = utils::path::combine(cfg.get_data_directory(), {"db"});
|
|
||||||
if (not utils::file::directory{db_dir}.create_directory()) {
|
|
||||||
throw startup_exception(
|
|
||||||
fmt::format("failed to create db directory|", db_dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
db_ = utils::db::sqlite::create_db(
|
|
||||||
utils::path::combine(db_dir, {"file_mgr.db"}), sql_create_tables);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite_file_mgr_db::~sqlite_file_mgr_db() { db_.reset(); }
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::add_resume(const resume_entry &entry) -> bool {
|
|
||||||
return utils::db::sqlite::db_insert{*db_, resume_table}
|
|
||||||
.or_replace()
|
|
||||||
.column_value("api_path", entry.api_path)
|
|
||||||
.column_value("chunk_size", static_cast<std::int64_t>(entry.chunk_size))
|
|
||||||
.column_value("read_state",
|
|
||||||
utils::string::from_dynamic_bitset(entry.read_state))
|
|
||||||
.column_value("source_path", entry.source_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::add_upload(const upload_entry &entry) -> bool {
|
|
||||||
return utils::db::sqlite::db_insert{*db_, upload_table}
|
|
||||||
.or_replace()
|
|
||||||
.column_value("api_path", entry.api_path)
|
|
||||||
.column_value("source_path", entry.source_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::add_upload_active(const upload_active_entry &entry)
|
|
||||||
-> bool {
|
|
||||||
return utils::db::sqlite::db_insert{*db_, upload_active_table}
|
|
||||||
.or_replace()
|
|
||||||
.column_value("api_path", entry.api_path)
|
|
||||||
.column_value("source_path", entry.source_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sqlite_file_mgr_db::clear() {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto result = utils::db::sqlite::db_delete{*db_, resume_table}.go();
|
|
||||||
if (not result.ok()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"failed to clear resume table|" +
|
|
||||||
std::to_string(result.get_error()));
|
|
||||||
}
|
|
||||||
|
|
||||||
result = utils::db::sqlite::db_delete{*db_, upload_active_table}.go();
|
|
||||||
if (not result.ok()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"failed to clear upload active table|" +
|
|
||||||
std::to_string(result.get_error()));
|
|
||||||
}
|
|
||||||
|
|
||||||
result = utils::db::sqlite::db_delete{*db_, upload_table}.go();
|
|
||||||
if (not result.ok()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"failed to clear upload table|" +
|
|
||||||
std::to_string(result.get_error()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::get_next_upload() const
|
|
||||||
-> std::optional<upload_entry> {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
|
||||||
.order_by("id", true)
|
|
||||||
.limit(1)
|
|
||||||
.go();
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (not result.get_row(row) || not row.has_value()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return upload_entry{
|
|
||||||
row->get_column("api_path").get_value<std::string>(),
|
|
||||||
row->get_column("source_path").get_value<std::string>(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::get_resume_list() const -> std::vector<resume_entry> {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
std::vector<resume_entry> ret;
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
|
||||||
while (result.has_row()) {
|
|
||||||
try {
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (not result.get_row(row)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (not row.has_value()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.push_back(resume_entry{
|
|
||||||
row->get_column("api_path").get_value<std::string>(),
|
|
||||||
static_cast<std::uint64_t>(
|
|
||||||
row->get_column("chunk_size").get_value<std::int64_t>()),
|
|
||||||
utils::string::to_dynamic_bitset(
|
|
||||||
row->get_column("read_state").get_value<std::string>()),
|
|
||||||
row->get_column("source_path").get_value<std::string>(),
|
|
||||||
});
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex, "query error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::get_upload(const std::string &api_path) const
|
|
||||||
-> std::optional<upload_entry> {
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.go();
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (not result.get_row(row) || not row.has_value()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return upload_entry{
|
|
||||||
row->get_column("api_path").get_value<std::string>(),
|
|
||||||
row->get_column("source_path").get_value<std::string>(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::get_upload_active_list() const
|
|
||||||
-> std::vector<upload_active_entry> {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
std::vector<upload_active_entry> ret;
|
|
||||||
auto result = utils::db::sqlite::db_select{*db_, upload_active_table}.go();
|
|
||||||
while (result.has_row()) {
|
|
||||||
try {
|
|
||||||
std::optional<utils::db::sqlite::db_result::row> row;
|
|
||||||
if (not result.get_row(row)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (not row.has_value()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.push_back(upload_active_entry{
|
|
||||||
row->get_column("api_path").get_value<std::string>(),
|
|
||||||
row->get_column("source_path").get_value<std::string>(),
|
|
||||||
});
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex, "query error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::remove_resume(const std::string &api_path) -> bool {
|
|
||||||
return utils::db::sqlite::db_delete{*db_, resume_table}
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::remove_upload(const std::string &api_path) -> bool {
|
|
||||||
return utils::db::sqlite::db_delete{*db_, upload_table}
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::remove_upload_active(const std::string &api_path)
|
|
||||||
-> bool {
|
|
||||||
return utils::db::sqlite::db_delete{*db_, upload_active_table}
|
|
||||||
.where("api_path")
|
|
||||||
.equals(api_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sqlite_file_mgr_db::rename_resume(const std::string &from_api_path,
|
|
||||||
const std::string &to_api_path) -> bool {
|
|
||||||
return utils::db::sqlite::db_update{*db_, resume_table}
|
|
||||||
.column_value("api_path", to_api_path)
|
|
||||||
.where("api_path")
|
|
||||||
.equals(from_api_path)
|
|
||||||
.go()
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -22,17 +22,11 @@
|
|||||||
#include "db/meta_db.hpp"
|
#include "db/meta_db.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "db/impl/rdb_meta_db.hpp"
|
#include "db/rdb_meta_db.hpp"
|
||||||
#include "db/impl/sqlite_meta_db.hpp"
|
#include "db/sqlite_meta_db.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto create_meta_db(const app_config &cfg) -> std::unique_ptr<i_meta_db> {
|
auto create_meta_db(const app_config &cfg) -> std::unique_ptr<i_meta_db> {
|
||||||
switch (cfg.get_database_type()) {
|
return std::make_unique<rdb_meta_db>(cfg);
|
||||||
case database_type::sqlite:
|
|
||||||
return std::make_unique<sqlite_meta_db>(cfg);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return std::make_unique<rdb_meta_db>(cfg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "db/impl/rdb_meta_db.hpp"
|
#include "db/rdb_meta_db.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
#include "types/startup_exception.hpp"
|
||||||
@ -27,7 +27,38 @@
|
|||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
#include "utils/utils.hpp"
|
|
||||||
|
namespace {
|
||||||
|
[[nodiscard]] auto
|
||||||
|
create_rocksdb(const repertory::app_config &cfg, const std::string &name,
|
||||||
|
const std::vector<rocksdb::ColumnFamilyDescriptor> &families,
|
||||||
|
std::vector<rocksdb::ColumnFamilyHandle *> &handles, bool clear)
|
||||||
|
-> std::unique_ptr<rocksdb::DB> {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto path = repertory::utils::path::combine(cfg.get_data_directory(), {name});
|
||||||
|
if (clear &&
|
||||||
|
not repertory::utils::file::directory{path}.remove_recursively()) {
|
||||||
|
repertory::utils::error::raise_error(function_name,
|
||||||
|
"failed to remove meta db|" + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
rocksdb::Options options{};
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.create_missing_column_families = true;
|
||||||
|
options.db_log_dir = cfg.get_log_directory();
|
||||||
|
options.keep_log_file_num = 10;
|
||||||
|
|
||||||
|
rocksdb::DB *ptr{};
|
||||||
|
auto status = rocksdb::DB::Open(options, path, families, &handles, &ptr);
|
||||||
|
if (not status.ok()) {
|
||||||
|
repertory::utils::error::raise_error(function_name, status.ToString());
|
||||||
|
throw repertory::startup_exception(status.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::unique_ptr<rocksdb::DB>(ptr);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
rdb_meta_db::rdb_meta_db(const app_config &cfg) : cfg_(cfg) {
|
rdb_meta_db::rdb_meta_db(const app_config &cfg) : cfg_(cfg) {
|
||||||
@ -47,13 +78,13 @@ void rdb_meta_db::create_or_open(bool clear) {
|
|||||||
families.emplace_back("source", rocksdb::ColumnFamilyOptions());
|
families.emplace_back("source", rocksdb::ColumnFamilyOptions());
|
||||||
|
|
||||||
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
||||||
db_ = utils::create_rocksdb(cfg_, "provider_meta", families, handles, clear);
|
db_ = create_rocksdb(cfg_, "provider_meta", families, handles, clear);
|
||||||
|
|
||||||
std::size_t idx{};
|
std::size_t idx{};
|
||||||
meta_family_ = handles.at(idx++);
|
default_family_ = handles[idx++];
|
||||||
pinned_family_ = handles.at(idx++);
|
pinned_family_ = handles[idx++];
|
||||||
size_family_ = handles.at(idx++);
|
size_family_ = handles[idx++];
|
||||||
source_family_ = handles.at(idx++);
|
source_family_ = handles[idx++];
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdb_meta_db::clear() { create_or_open(true); }
|
void rdb_meta_db::clear() { create_or_open(true); }
|
||||||
@ -61,7 +92,7 @@ void rdb_meta_db::clear() { create_or_open(true); }
|
|||||||
auto rdb_meta_db::create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
auto rdb_meta_db::create_iterator(rocksdb::ColumnFamilyHandle *family) const
|
||||||
-> std::shared_ptr<rocksdb::Iterator> {
|
-> std::shared_ptr<rocksdb::Iterator> {
|
||||||
return std::shared_ptr<rocksdb::Iterator>(
|
return std::shared_ptr<rocksdb::Iterator>(
|
||||||
db_->NewIterator(rocksdb::ReadOptions{}, family));
|
db_->NewIterator(rocksdb::ReadOptions(), family));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::get_api_path(const std::string &source_path,
|
auto rdb_meta_db::get_api_path(const std::string &source_path,
|
||||||
@ -73,14 +104,14 @@ auto rdb_meta_db::get_api_path(const std::string &source_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return perform_action(function_name, [&]() -> rocksdb::Status {
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, source_family_, source_path,
|
return db_->Get(rocksdb::ReadOptions(), source_family_, source_path,
|
||||||
&api_path);
|
&api_path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::get_api_path_list() const -> std::vector<std::string> {
|
auto rdb_meta_db::get_api_path_list() const -> std::vector<std::string> {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
auto iter = create_iterator(meta_family_);
|
auto iter = create_iterator(default_family_);
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||||
ret.push_back(iter->key().ToString());
|
ret.push_back(iter->key().ToString());
|
||||||
}
|
}
|
||||||
@ -98,7 +129,8 @@ auto rdb_meta_db::get_item_meta_json(const std::string &api_path,
|
|||||||
{
|
{
|
||||||
std::string value;
|
std::string value;
|
||||||
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, meta_family_, api_path, &value);
|
return db_->Get(rocksdb::ReadOptions(), default_family_, api_path,
|
||||||
|
&value);
|
||||||
});
|
});
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
@ -112,7 +144,7 @@ auto rdb_meta_db::get_item_meta_json(const std::string &api_path,
|
|||||||
{
|
{
|
||||||
std::string value;
|
std::string value;
|
||||||
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, pinned_family_, api_path,
|
return db_->Get(rocksdb::ReadOptions(), pinned_family_, api_path,
|
||||||
&value);
|
&value);
|
||||||
});
|
});
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -126,7 +158,7 @@ auto rdb_meta_db::get_item_meta_json(const std::string &api_path,
|
|||||||
{
|
{
|
||||||
std::string value;
|
std::string value;
|
||||||
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
auto res = perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, size_family_, api_path, &value);
|
return db_->Get(rocksdb::ReadOptions(), size_family_, api_path, &value);
|
||||||
});
|
});
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
@ -167,13 +199,13 @@ auto rdb_meta_db::get_item_meta(const std::string &api_path,
|
|||||||
|
|
||||||
if (key == META_PINNED) {
|
if (key == META_PINNED) {
|
||||||
return perform_action(function_name, [&]() -> rocksdb::Status {
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, pinned_family_, api_path, &value);
|
return db_->Get(rocksdb::ReadOptions(), pinned_family_, api_path, &value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == META_SIZE) {
|
if (key == META_SIZE) {
|
||||||
return perform_action(function_name, [&]() -> rocksdb::Status {
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
return db_->Get(rocksdb::ReadOptions{}, size_family_, api_path, &value);
|
return db_->Get(rocksdb::ReadOptions(), size_family_, api_path, &value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +238,7 @@ auto rdb_meta_db::get_pinned_files() const -> std::vector<std::string> {
|
|||||||
|
|
||||||
auto rdb_meta_db::get_total_item_count() const -> std::uint64_t {
|
auto rdb_meta_db::get_total_item_count() const -> std::uint64_t {
|
||||||
std::uint64_t ret{};
|
std::uint64_t ret{};
|
||||||
auto iter = create_iterator(meta_family_);
|
auto iter = create_iterator(default_family_);
|
||||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||||
++ret;
|
++ret;
|
||||||
}
|
}
|
||||||
@ -239,84 +271,21 @@ auto rdb_meta_db::perform_action(std::string_view function_name,
|
|||||||
return res.IsNotFound() ? api_error::item_not_found : api_error::error;
|
return res.IsNotFound() ? api_error::item_not_found : api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::perform_action(
|
|
||||||
std::string_view function_name,
|
|
||||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action)
|
|
||||||
-> api_error {
|
|
||||||
std::unique_ptr<rocksdb::Transaction> txn{
|
|
||||||
db_->BeginTransaction(rocksdb::WriteOptions{},
|
|
||||||
rocksdb::TransactionOptions{}),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto res = action(txn.get());
|
|
||||||
if (res.ok()) {
|
|
||||||
auto commit_res = txn->Commit();
|
|
||||||
if (commit_res.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb commit failed|" + res.ToString());
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"rocksdb action failed|" + res.ToString());
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(function_name, ex,
|
|
||||||
"failed to handle rocksdb action");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rollback_res = txn->Rollback();
|
|
||||||
utils::error::raise_error(function_name, "rocksdb rollback failed|" +
|
|
||||||
rollback_res.ToString());
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rdb_meta_db::remove_api_path(const std::string &api_path) {
|
void rdb_meta_db::remove_api_path(const std::string &api_path) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
std::string source_path;
|
std::string source_path;
|
||||||
auto res = get_item_meta(api_path, META_SOURCE, source_path);
|
[[maybe_unused]] auto res = get_item_meta(api_path, META_SOURCE, source_path);
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path, res,
|
|
||||||
"failed to get source path");
|
|
||||||
}
|
|
||||||
|
|
||||||
res = perform_action(function_name,
|
res = perform_action(
|
||||||
[this, &api_path, &source_path](
|
function_name, [this, &api_path, &source_path]() -> rocksdb::Status {
|
||||||
rocksdb::Transaction *txn) -> rocksdb::Status {
|
db_->Delete(rocksdb::WriteOptions(), pinned_family_, api_path);
|
||||||
return remove_api_path(api_path, source_path, txn);
|
db_->Delete(rocksdb::WriteOptions(), size_family_, api_path);
|
||||||
});
|
if (not source_path.empty()) {
|
||||||
if (res != api_error::success) {
|
db_->Delete(rocksdb::WriteOptions(), source_family_, source_path);
|
||||||
utils::error::raise_api_path_error(function_name, api_path, res,
|
}
|
||||||
"failed to remove api path");
|
return db_->Delete(rocksdb::WriteOptions(), default_family_, api_path);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
auto rdb_meta_db::remove_api_path(const std::string &api_path,
|
|
||||||
const std::string &source_path,
|
|
||||||
rocksdb::Transaction *txn)
|
|
||||||
-> rocksdb::Status {
|
|
||||||
auto txn_res = txn->Delete(pinned_family_, api_path);
|
|
||||||
if (not txn_res.ok()) {
|
|
||||||
return txn_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
txn_res = txn->Delete(size_family_, api_path);
|
|
||||||
if (not txn_res.ok()) {
|
|
||||||
return txn_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not source_path.empty()) {
|
|
||||||
txn_res = txn->Delete(source_family_, source_path);
|
|
||||||
if (not txn_res.ok()) {
|
|
||||||
return txn_res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return txn->Delete(meta_family_, api_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::remove_item_meta(const std::string &api_path,
|
auto rdb_meta_db::remove_item_meta(const std::string &api_path,
|
||||||
@ -340,27 +309,14 @@ auto rdb_meta_db::remove_item_meta(const std::string &api_path,
|
|||||||
auto rdb_meta_db::rename_item_meta(const std::string &from_api_path,
|
auto rdb_meta_db::rename_item_meta(const std::string &from_api_path,
|
||||||
const std::string &to_api_path)
|
const std::string &to_api_path)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
json json_data;
|
json json_data;
|
||||||
auto res = get_item_meta_json(from_api_path, json_data);
|
auto res = get_item_meta_json(from_api_path, json_data);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perform_action(
|
remove_api_path(from_api_path);
|
||||||
function_name, [&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
return update_item_meta(to_api_path, json_data);
|
||||||
auto txn_res = remove_api_path(
|
|
||||||
from_api_path, json_data[META_SOURCE].get<std::string>(), txn);
|
|
||||||
if (not txn_res.ok()) {
|
|
||||||
return txn_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
rocksdb::Status status;
|
|
||||||
[[maybe_unused]] auto api_res =
|
|
||||||
update_item_meta(to_api_path, json_data, txn, &status);
|
|
||||||
return status;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::set_item_meta(const std::string &api_path,
|
auto rdb_meta_db::set_item_meta(const std::string &api_path,
|
||||||
@ -369,17 +325,15 @@ auto rdb_meta_db::set_item_meta(const std::string &api_path,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (key == META_PINNED) {
|
if (key == META_PINNED) {
|
||||||
return perform_action(function_name,
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
[&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
return db_->Put(rocksdb::WriteOptions(), pinned_family_, api_path, value);
|
||||||
return txn->Put(pinned_family_, api_path, value);
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == META_SIZE) {
|
if (key == META_SIZE) {
|
||||||
return perform_action(function_name,
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
[&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
return db_->Put(rocksdb::WriteOptions(), size_family_, api_path, value);
|
||||||
return txn->Put(size_family_, api_path, value);
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json json_data;
|
json json_data;
|
||||||
@ -408,9 +362,8 @@ auto rdb_meta_db::set_item_meta(const std::string &api_path,
|
|||||||
return update_item_meta(api_path, json_data);
|
return update_item_meta(api_path, json_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rdb_meta_db::update_item_meta(const std::string &api_path, json json_data,
|
auto rdb_meta_db::update_item_meta(const std::string &api_path, json json_data)
|
||||||
rocksdb::Transaction *base_txn,
|
-> api_error {
|
||||||
rocksdb::Status *status) -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -440,67 +393,51 @@ auto rdb_meta_db::update_item_meta(const std::string &api_path, json json_data,
|
|||||||
json_data[META_SIZE] = std::to_string(size);
|
json_data[META_SIZE] = std::to_string(size);
|
||||||
json_data[META_SOURCE] = source_path;
|
json_data[META_SOURCE] = source_path;
|
||||||
|
|
||||||
auto should_del_source{false};
|
|
||||||
std::string orig_source_path;
|
|
||||||
if (not directory) {
|
if (not directory) {
|
||||||
|
std::string orig_source_path;
|
||||||
auto res = get_item_meta(api_path, META_SOURCE, orig_source_path);
|
auto res = get_item_meta(api_path, META_SOURCE, orig_source_path);
|
||||||
if (res != api_error::success && res != api_error::item_not_found) {
|
if (res != api_error::success && res != api_error::item_not_found) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
should_del_source =
|
if (not orig_source_path.empty() && orig_source_path != source_path) {
|
||||||
not orig_source_path.empty() && orig_source_path != source_path;
|
res = perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
|
return db_->Delete(rocksdb::WriteOptions(), source_family_,
|
||||||
|
orig_source_path);
|
||||||
|
});
|
||||||
|
if (res != api_error::success && res != api_error::item_not_found) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json_data.erase(META_PINNED);
|
json_data.erase(META_PINNED);
|
||||||
json_data.erase(META_SIZE);
|
json_data.erase(META_SIZE);
|
||||||
|
|
||||||
const auto set_status = [&status](rocksdb::Status res) -> rocksdb::Status {
|
return perform_action(function_name, [&]() -> rocksdb::Status {
|
||||||
if (status != nullptr) {
|
auto res = db_->Put(rocksdb::WriteOptions(), pinned_family_, api_path,
|
||||||
*status = res;
|
utils::string::from_bool(pinned));
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto do_transaction =
|
|
||||||
[&](rocksdb::Transaction *txn) -> rocksdb::Status {
|
|
||||||
if (should_del_source) {
|
|
||||||
auto res = set_status(txn->Delete(source_family_, orig_source_path));
|
|
||||||
if (not res.ok()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = set_status(
|
|
||||||
txn->Put(pinned_family_, api_path, utils::string::from_bool(pinned)));
|
|
||||||
if (not res.ok()) {
|
if (not res.ok()) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = set_status(txn->Put(size_family_, api_path, std::to_string(size)));
|
res = db_->Put(rocksdb::WriteOptions(), size_family_, api_path,
|
||||||
|
std::to_string(size));
|
||||||
if (not res.ok()) {
|
if (not res.ok()) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not source_path.empty()) {
|
if (not source_path.empty()) {
|
||||||
res = set_status(txn->Put(source_family_, source_path, api_path));
|
res = db_->Put(rocksdb::WriteOptions(), source_family_, source_path,
|
||||||
|
api_path);
|
||||||
if (not res.ok()) {
|
if (not res.ok()) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return set_status(txn->Put(meta_family_, api_path, json_data.dump()));
|
return db_->Put(rocksdb::WriteOptions(), default_family_, api_path,
|
||||||
};
|
json_data.dump());
|
||||||
|
});
|
||||||
if (base_txn == nullptr) {
|
|
||||||
return perform_action(function_name, do_transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = set_status(do_transaction(base_txn));
|
|
||||||
if (res.ok()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
utils::error::raise_api_path_error(function_name, api_path, e,
|
||||||
"failed to update item meta");
|
"failed to update item meta");
|
@ -19,16 +19,14 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "db/impl/sqlite_meta_db.hpp"
|
#include "db/sqlite_meta_db.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/db/sqlite/db_common.hpp"
|
#include "utils/db/sqlite/db_common.hpp"
|
||||||
#include "utils/db/sqlite/db_delete.hpp"
|
#include "utils/db/sqlite/db_delete.hpp"
|
||||||
#include "utils/db/sqlite/db_insert.hpp"
|
#include "utils/db/sqlite/db_insert.hpp"
|
||||||
#include "utils/db/sqlite/db_select.hpp"
|
#include "utils/db/sqlite/db_select.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
@ -50,14 +48,9 @@ sqlite_meta_db::sqlite_meta_db(const app_config &cfg) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto db_dir = utils::path::combine(cfg.get_data_directory(), {"db"});
|
db_ = utils::db::sqlite::create_db(
|
||||||
if (not utils::file::directory{db_dir}.create_directory()) {
|
utils::path::combine(cfg.get_data_directory(), {"provider_meta.db"}),
|
||||||
throw startup_exception(
|
sql_create_tables);
|
||||||
fmt::format("failed to create db directory|", db_dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
db_ = utils::db::sqlite::create_db(utils::path::combine(db_dir, {"meta.db"}),
|
|
||||||
sql_create_tables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite_meta_db::~sqlite_meta_db() { db_.reset(); }
|
sqlite_meta_db::~sqlite_meta_db() { db_.reset(); }
|
||||||
@ -71,8 +64,7 @@ void sqlite_meta_db::clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils::error::raise_error(function_name,
|
utils::error::raise_error(function_name,
|
||||||
"failed to clear meta db|" +
|
"failed to clear meta db|" + result.get_error());
|
||||||
std::to_string(result.get_error()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sqlite_meta_db::get_api_path(const std::string &source_path,
|
auto sqlite_meta_db::get_api_path(const std::string &source_path,
|
||||||
@ -279,12 +271,6 @@ void sqlite_meta_db::remove_api_path(const std::string &api_path) {
|
|||||||
|
|
||||||
auto sqlite_meta_db::remove_item_meta(const std::string &api_path,
|
auto sqlite_meta_db::remove_item_meta(const std::string &api_path,
|
||||||
const std::string &key) -> api_error {
|
const std::string &key) -> api_error {
|
||||||
if (key == META_DIRECTORY || key == META_PINNED || key == META_SIZE ||
|
|
||||||
key == META_SOURCE) {
|
|
||||||
// TODO log warning for unsupported attributes
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
auto res = get_item_meta(api_path, meta);
|
auto res = get_item_meta(api_path, meta);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
@ -115,7 +115,7 @@ auto directory_iterator::get_directory_item(const std::string &api_path,
|
|||||||
|
|
||||||
auto directory_iterator::get_json(std::size_t offset, json &item) -> int {
|
auto directory_iterator::get_json(std::size_t offset, json &item) -> int {
|
||||||
if (offset < items_.size()) {
|
if (offset < items_.size()) {
|
||||||
item = json(items_.at(offset));
|
item = items_[offset].to_json();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,17 +30,18 @@
|
|||||||
#include "utils/file_utils.hpp"
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
#include <spdlog/fmt/bundled/base.h>
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto eviction::check_minimum_requirements(const std::string &file_path)
|
auto eviction::check_minimum_requirements(const std::string &file_path)
|
||||||
-> bool {
|
-> bool {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto file = utils::file::file{file_path};
|
auto check_file = utils::file::file{file_path};
|
||||||
auto reference_time = file.get_time(config_.get_eviction_uses_accessed_time()
|
|
||||||
? utils::file::time_type::accessed
|
auto reference_time =
|
||||||
: utils::file::time_type::modified);
|
check_file.get_time(config_.get_eviction_uses_accessed_time()
|
||||||
|
? utils::file::time_type::accessed
|
||||||
|
: utils::file::time_type::modified);
|
||||||
|
|
||||||
if (not reference_time.has_value()) {
|
if (not reference_time.has_value()) {
|
||||||
utils::error::raise_error(function_name, utils::get_last_error_code(),
|
utils::error::raise_error(function_name, utils::get_last_error_code(),
|
||||||
@ -48,17 +49,18 @@ auto eviction::check_minimum_requirements(const std::string &file_path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto delay =
|
auto delay = (config_.get_eviction_delay_mins() * 60UL) *
|
||||||
static_cast<std::uint64_t>(config_.get_eviction_delay_mins() * 60U) *
|
utils::time::NANOS_PER_SECOND;
|
||||||
utils::time::NANOS_PER_SECOND;
|
|
||||||
return (reference_time.value() + delay) <= utils::time::get_time_now();
|
return ((reference_time.value() + static_cast<std::uint64_t>(delay)) <=
|
||||||
|
utils::time::get_time_now());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eviction::get_filtered_cached_files() -> std::deque<std::string> {
|
auto eviction::get_filtered_cached_files() -> std::deque<std::string> {
|
||||||
auto list =
|
auto list =
|
||||||
utils::file::get_directory_files(config_.get_cache_directory(), true);
|
utils::file::get_directory_files(config_.get_cache_directory(), true);
|
||||||
list.erase(std::remove_if(list.begin(), list.end(),
|
list.erase(std::remove_if(list.begin(), list.end(),
|
||||||
[this](auto &&path) -> bool {
|
[this](const std::string &path) -> bool {
|
||||||
return not this->check_minimum_requirements(path);
|
return not this->check_minimum_requirements(path);
|
||||||
}),
|
}),
|
||||||
list.end());
|
list.end());
|
||||||
@ -68,38 +70,65 @@ auto eviction::get_filtered_cached_files() -> std::deque<std::string> {
|
|||||||
void eviction::service_function() {
|
void eviction::service_function() {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto cached_files_list = get_filtered_cached_files();
|
auto should_evict = true;
|
||||||
auto was_file_evicted{false};
|
|
||||||
while (not get_stop_requested() && not cached_files_list.empty()) {
|
|
||||||
auto file_path = cached_files_list.front();
|
|
||||||
cached_files_list.pop_front();
|
|
||||||
|
|
||||||
try {
|
// Handle maximum cache size eviction
|
||||||
std::string api_path;
|
auto used_bytes =
|
||||||
auto res = provider_.get_api_path_from_source(file_path, api_path);
|
utils::file::directory{config_.get_cache_directory()}.size();
|
||||||
if (res != api_error::success) {
|
if (config_.get_enable_max_cache_size()) {
|
||||||
continue;
|
should_evict = (used_bytes > config_.get_max_cache_size_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_evict) {
|
||||||
|
// Remove cached source files that don't meet minimum requirements
|
||||||
|
auto cached_files_list = get_filtered_cached_files();
|
||||||
|
while (not get_stop_requested() && should_evict &&
|
||||||
|
not cached_files_list.empty()) {
|
||||||
|
try {
|
||||||
|
std::string api_path;
|
||||||
|
if (provider_.get_api_path_from_source(
|
||||||
|
cached_files_list.front(), api_path) == api_error::success) {
|
||||||
|
api_file file{};
|
||||||
|
filesystem_item fsi{};
|
||||||
|
if (provider_.get_filesystem_item_and_file(api_path, file, fsi) ==
|
||||||
|
api_error::success) {
|
||||||
|
// Only evict files that match expected size
|
||||||
|
auto opt_size = utils::file::file{cached_files_list.front()}.size();
|
||||||
|
if (opt_size.has_value()) {
|
||||||
|
auto file_size{opt_size.value()};
|
||||||
|
if (file_size == fsi.size) {
|
||||||
|
// Try to evict file
|
||||||
|
if (fm_.evict_file(fsi.api_path) &&
|
||||||
|
config_.get_enable_max_cache_size()) {
|
||||||
|
// Restrict number of items evicted if maximum cache size is
|
||||||
|
// enabled
|
||||||
|
used_bytes -= file_size;
|
||||||
|
should_evict =
|
||||||
|
(used_bytes > config_.get_max_cache_size_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, file.api_path, file.source_path,
|
||||||
|
utils::get_last_error_code(), "failed to get file size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex,
|
||||||
|
"failed to process cached file|sp|" +
|
||||||
|
cached_files_list.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_mgr_.evict_file(api_path)) {
|
cached_files_list.pop_front();
|
||||||
was_file_evicted = true;
|
|
||||||
}
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_error(
|
|
||||||
function_name, ex,
|
|
||||||
fmt::format("failed to process cached file|sp|{}", file_path));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_stop_requested() || was_file_evicted) {
|
if (not get_stop_requested()) {
|
||||||
return;
|
unique_mutex_lock lock(get_mutex());
|
||||||
|
if (not get_stop_requested()) {
|
||||||
|
get_notify().wait_for(lock, 30s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_mutex_lock lock(get_mutex());
|
|
||||||
if (get_stop_requested()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_notify().wait_for(lock, 30s);
|
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "initialize.hpp"
|
#include "initialize.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "utils/collection.hpp"
|
#include "utils/collection.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file_utils.hpp"
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
|
#include "utils/tasks.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
@ -81,8 +82,8 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::chown_impl(std::string api_path, uid_t uid,
|
auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||||
gid_t gid) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
@ -258,6 +259,7 @@ void fuse_drive::destroy_impl(void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
polling::instance().stop();
|
polling::instance().stop();
|
||||||
|
tasks::instance().stop();
|
||||||
|
|
||||||
if (eviction_) {
|
if (eviction_) {
|
||||||
eviction_->stop();
|
eviction_->stop();
|
||||||
@ -481,8 +483,8 @@ auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::getattr_impl(std::string api_path,
|
auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
|
||||||
struct stat *unix_st) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto parent = utils::path::get_parent_api_path(api_path);
|
auto parent = utils::path::get_parent_api_path(api_path);
|
||||||
|
|
||||||
@ -565,8 +567,8 @@ auto fuse_drive::getxtimes_impl(std::string api_path, struct timespec *bkuptime,
|
|||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto fuse_drive::init_impl(struct fuse_conn_info *conn,
|
auto fuse_drive::init_impl(struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
struct fuse_config *cfg) -> void * {
|
-> void * {
|
||||||
#else
|
#else
|
||||||
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
||||||
#endif
|
#endif
|
||||||
@ -612,7 +614,7 @@ void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
|||||||
eviction_->start();
|
eviction_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_.get_remote_mount().enable) {
|
if (config_.get_enable_remote_mount()) {
|
||||||
remote_server_ = std::make_unique<remote_fuse::remote_server>(
|
remote_server_ = std::make_unique<remote_fuse::remote_server>(
|
||||||
config_, *this, get_mount_location());
|
config_, *this, get_mount_location());
|
||||||
}
|
}
|
||||||
@ -622,6 +624,7 @@ void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
polling::instance().start(&config_);
|
polling::instance().start(&config_);
|
||||||
|
tasks::instance().start(&config_);
|
||||||
|
|
||||||
event_system::instance().raise<drive_mounted>(get_mount_location());
|
event_system::instance().raise<drive_mounted>(get_mount_location());
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
@ -800,8 +803,9 @@ auto fuse_drive::release_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::releasedir_impl(
|
auto fuse_drive::releasedir_impl(std::string /*api_path*/,
|
||||||
std::string /*api_path*/, struct fuse_file_info *file_info) -> api_error {
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error {
|
||||||
auto iter = directory_cache_->get_directory(file_info->fh);
|
auto iter = directory_cache_->get_directory(file_info->fh);
|
||||||
if (iter == nullptr) {
|
if (iter == nullptr) {
|
||||||
return api_error::invalid_handle;
|
return api_error::invalid_handle;
|
||||||
@ -819,8 +823,8 @@ auto fuse_drive::rename_directory(const std::string &from_api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::rename_file(const std::string &from_api_path,
|
auto fuse_drive::rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> int {
|
-> int {
|
||||||
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
||||||
errno = std::abs(utils::from_api_error(res));
|
errno = std::abs(utils::from_api_error(res));
|
||||||
return (res == api_error::success) ? 0 : -1;
|
return (res == api_error::success) ? 0 : -1;
|
||||||
@ -830,8 +834,8 @@ auto fuse_drive::rename_file(const std::string &from_api_path,
|
|||||||
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
||||||
unsigned int /*flags*/) -> api_error {
|
unsigned int /*flags*/) -> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::rename_impl(std::string from_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path)
|
||||||
std::string to_api_path) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -945,15 +949,15 @@ auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
|||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
||||||
char *value, size_t size,
|
char *value, size_t size, int &attribute_size)
|
||||||
int &attribute_size) -> api_error {
|
-> api_error {
|
||||||
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
||||||
int &required_size,
|
int &required_size, bool &return_size)
|
||||||
bool &return_size) -> api_error {
|
-> api_error {
|
||||||
auto check_size = (size == 0);
|
auto check_size = (size == 0);
|
||||||
|
|
||||||
auto res = check_parent_access(api_path, X_OK);
|
auto res = check_parent_access(api_path, X_OK);
|
||||||
@ -993,8 +997,8 @@ auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::removexattr_impl(std::string api_path,
|
auto fuse_drive::removexattr_impl(std::string api_path, const char *name)
|
||||||
const char *name) -> api_error {
|
-> api_error {
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
||||||
@ -1022,8 +1026,8 @@ auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
|||||||
uint32_t position) -> api_error {
|
uint32_t position) -> api_error {
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
||||||
const char *value, size_t size,
|
const char *value, size_t size, int flags)
|
||||||
int flags) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -1101,8 +1105,8 @@ void fuse_drive::set_item_meta(const std::string &api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto fuse_drive::setattr_x_impl(std::string api_path,
|
auto fuse_drive::setattr_x_impl(std::string api_path, struct setattr_x *attr)
|
||||||
struct setattr_x *attr) -> api_error {
|
-> api_error {
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto res = provider_.is_file(api_path, exists);
|
auto res = provider_.is_file(api_path, exists);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -1156,7 +1160,7 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
ts[0].tv_sec = attr->acctime.tv_sec;
|
ts[0].tv_sec = attr->acctime.tv_sec;
|
||||||
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
||||||
} else {
|
} else {
|
||||||
struct timeval tv {};
|
struct timeval tv{};
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
ts[0].tv_sec = tv.tv_sec;
|
ts[0].tv_sec = tv.tv_sec;
|
||||||
ts[0].tv_nsec = tv.tv_usec * 1000;
|
ts[0].tv_nsec = tv.tv_usec * 1000;
|
||||||
@ -1201,8 +1205,9 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::setbkuptime_impl(
|
auto fuse_drive::setbkuptime_impl(std::string api_path,
|
||||||
std::string api_path, const struct timespec *bkuptime) -> api_error {
|
const struct timespec *bkuptime)
|
||||||
|
-> api_error {
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
auto nanos = bkuptime->tv_nsec +
|
auto nanos = bkuptime->tv_nsec +
|
||||||
@ -1238,8 +1243,8 @@ auto fuse_drive::setvolname_impl(const char * /*volname*/) -> api_error {
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_x_impl(std::string /*api_path*/, struct statfs *stbuf)
|
||||||
struct statfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1264,8 +1269,8 @@ auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::statfs_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_impl(std::string /*api_path*/, struct statvfs *stbuf)
|
||||||
struct statvfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1315,10 +1320,6 @@ auto fuse_drive::truncate_impl(std::string api_path, off_t size) -> api_error {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not fm_->get_open_file(handle, true, open_file)) {
|
|
||||||
return api_error::invalid_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = open_file->resize(static_cast<std::uint64_t>(size));
|
res = open_file->resize(static_cast<std::uint64_t>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,8 +1350,8 @@ auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2],
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::utimens_impl(std::string api_path,
|
auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2])
|
||||||
const struct timespec tv[2]) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
auto res = provider_.get_item_meta(api_path, meta);
|
auto res = provider_.get_item_meta(api_path, meta);
|
||||||
|
@ -27,7 +27,12 @@
|
|||||||
|
|
||||||
namespace repertory::remote_fuse {
|
namespace repertory::remote_fuse {
|
||||||
remote_client::remote_client(const app_config &config)
|
remote_client::remote_client(const app_config &config)
|
||||||
: config_(config), packet_client_(config.get_remote_config()) {}
|
: config_(config),
|
||||||
|
packet_client_(
|
||||||
|
config.get_remote_host_name_or_ip(),
|
||||||
|
config.get_remote_max_connections(), config.get_remote_port(),
|
||||||
|
config.get_remote_receive_timeout_secs(),
|
||||||
|
config.get_remote_send_timeout_secs(), config.get_remote_token()) {}
|
||||||
|
|
||||||
auto remote_client::fuse_access(const char *path, const std::int32_t &mask)
|
auto remote_client::fuse_access(const char *path, const std::int32_t &mask)
|
||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
|
@ -47,7 +47,12 @@ E_SIMPLE3(remote_winfsp_client_event, debug, true,
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
remote_client::remote_client(const app_config &config)
|
remote_client::remote_client(const app_config &config)
|
||||||
: config_(config), packet_client_(config.get_remote_config()) {}
|
: config_(config),
|
||||||
|
packet_client_(
|
||||||
|
config.get_remote_host_name_or_ip(),
|
||||||
|
config.get_remote_max_connections(), config.get_remote_port(),
|
||||||
|
config.get_remote_receive_timeout_secs(),
|
||||||
|
config.get_remote_send_timeout_secs(), config.get_remote_token()) {}
|
||||||
|
|
||||||
auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
|
auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
|
||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
|
@ -302,27 +302,27 @@ auto remote_winfsp_drive::Overwrite(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
BOOLEAN replace_attributes,
|
BOOLEAN replace_attributes,
|
||||||
UINT64 allocation_size, FileInfo *file_info)
|
UINT64 allocation_size, FileInfo *file_info)
|
||||||
-> NTSTATUS {
|
-> NTSTATUS {
|
||||||
remote::file_info info{};
|
remote::file_info fi{};
|
||||||
auto ret = remote_instance_->winfsp_overwrite(
|
auto ret = remote_instance_->winfsp_overwrite(
|
||||||
file_desc, attributes, replace_attributes, allocation_size, &info);
|
file_desc, attributes, replace_attributes, allocation_size, &fi);
|
||||||
set_file_info(*file_info, info);
|
set_file_info(*file_info, fi);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_winfsp_drive::populate_file_info(const json &item,
|
void remote_winfsp_drive::populate_file_info(const json &item,
|
||||||
FSP_FSCTL_FILE_INFO &file_info) {
|
FSP_FSCTL_FILE_INFO &file_info) {
|
||||||
auto dir_item = item.get<directory_item>();
|
auto di = directory_item::from_json(item);
|
||||||
file_info.FileSize = dir_item.directory ? 0 : dir_item.size;
|
file_info.FileSize = di.directory ? 0 : di.size;
|
||||||
file_info.AllocationSize =
|
file_info.AllocationSize =
|
||||||
utils::divide_with_ceiling(file_info.FileSize, WINFSP_ALLOCATION_UNIT) *
|
utils::divide_with_ceiling(file_info.FileSize, WINFSP_ALLOCATION_UNIT) *
|
||||||
WINFSP_ALLOCATION_UNIT;
|
WINFSP_ALLOCATION_UNIT;
|
||||||
file_info.ChangeTime = utils::get_changed_time_from_meta(dir_item.meta);
|
file_info.ChangeTime = utils::get_changed_time_from_meta(di.meta);
|
||||||
file_info.CreationTime = utils::get_creation_time_from_meta(dir_item.meta);
|
file_info.CreationTime = utils::get_creation_time_from_meta(di.meta);
|
||||||
file_info.FileAttributes = utils::get_attributes_from_meta(dir_item.meta);
|
file_info.FileAttributes = utils::get_attributes_from_meta(di.meta);
|
||||||
file_info.HardLinks = 0;
|
file_info.HardLinks = 0;
|
||||||
file_info.IndexNumber = 0;
|
file_info.IndexNumber = 0;
|
||||||
file_info.LastAccessTime = utils::get_accessed_time_from_meta(dir_item.meta);
|
file_info.LastAccessTime = utils::get_accessed_time_from_meta(di.meta);
|
||||||
file_info.LastWriteTime = utils::get_written_time_from_meta(dir_item.meta);
|
file_info.LastWriteTime = utils::get_written_time_from_meta(di.meta);
|
||||||
file_info.ReparseTag = 0;
|
file_info.ReparseTag = 0;
|
||||||
file_info.EaSize = 0;
|
file_info.EaSize = 0;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "utils/file_utils.hpp"
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
#include "utils/tasks.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
@ -641,7 +642,7 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto mount_location = parse_mount_location(file_system_host->MountPoint());
|
auto mount_location = parse_mount_location(file_system_host->MountPoint());
|
||||||
if (config_.get_remote_mount().enable) {
|
if (config_.get_enable_remote_mount()) {
|
||||||
remote_server_ = std::make_unique<remote_winfsp::remote_server>(
|
remote_server_ = std::make_unique<remote_winfsp::remote_server>(
|
||||||
config_, *this, mount_location);
|
config_, *this, mount_location);
|
||||||
}
|
}
|
||||||
@ -652,6 +653,7 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
polling::instance().start(&config_);
|
polling::instance().start(&config_);
|
||||||
|
tasks::instance().start(&config_);
|
||||||
|
|
||||||
event_system::instance().raise<drive_mounted>(mount_location);
|
event_system::instance().raise<drive_mounted>(mount_location);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
@ -661,6 +663,7 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS {
|
|||||||
}
|
}
|
||||||
server_->stop();
|
server_->stop();
|
||||||
polling::instance().stop();
|
polling::instance().stop();
|
||||||
|
tasks::instance().stop();
|
||||||
if (eviction_) {
|
if (eviction_) {
|
||||||
eviction_->stop();
|
eviction_->stop();
|
||||||
}
|
}
|
||||||
@ -1173,6 +1176,7 @@ VOID winfsp_drive::Unmounted(PVOID host) {
|
|||||||
}
|
}
|
||||||
server_->stop();
|
server_->stop();
|
||||||
polling::instance().stop();
|
polling::instance().stop();
|
||||||
|
tasks::instance().stop();
|
||||||
if (eviction_) {
|
if (eviction_) {
|
||||||
eviction_->stop();
|
eviction_->stop();
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto event_level_from_string(std::string level, event_level default_level)
|
auto event_level_from_string(std::string level) -> event_level {
|
||||||
-> event_level {
|
|
||||||
level = utils::string::to_lower(level);
|
level = utils::string::to_lower(level);
|
||||||
if (level == "critical" || level == "event_level::critical") {
|
if (level == "critical" || level == "event_level::critical") {
|
||||||
return event_level::critical;
|
return event_level::critical;
|
||||||
@ -51,7 +50,7 @@ auto event_level_from_string(std::string level, event_level default_level)
|
|||||||
return event_level::trace;
|
return event_level::trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default_level;
|
return event_level::info;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto event_level_to_string(event_level level) -> std::string {
|
auto event_level_to_string(event_level level) -> std::string {
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "file_manager/cache_size_mgr.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "events/event.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/file_utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
// clang-format off
|
|
||||||
E_SIMPLE2(invalid_cache_size, warn, true,
|
|
||||||
std::uint64_t, cache_size, sz, E_FROM_UINT64,
|
|
||||||
std::uint64_t, by, by, E_FROM_UINT64
|
|
||||||
);
|
|
||||||
|
|
||||||
E_SIMPLE2(max_cache_size_reached, warn, true,
|
|
||||||
std::uint64_t, cache_size, sz, E_FROM_UINT64,
|
|
||||||
std::uint64_t, max_cache_size, max, E_FROM_UINT64
|
|
||||||
);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
cache_size_mgr cache_size_mgr::instance_{};
|
|
||||||
|
|
||||||
// TODO add timeout
|
|
||||||
auto cache_size_mgr::expand(std::uint64_t size) -> api_error {
|
|
||||||
if (size == 0U) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_mutex_lock lock(mtx_);
|
|
||||||
if (cfg_ == nullptr) {
|
|
||||||
return api_error::cache_not_initialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache_size_ += size;
|
|
||||||
|
|
||||||
auto max_cache_size = cfg_->get_max_cache_size_bytes();
|
|
||||||
|
|
||||||
auto cache_dir = utils::file::directory{cfg_->get_cache_directory()};
|
|
||||||
while (not stop_requested_ && cache_size_ > max_cache_size &&
|
|
||||||
cache_dir.count() > 1U) {
|
|
||||||
event_system::instance().raise<max_cache_size_reached>(cache_size_,
|
|
||||||
max_cache_size);
|
|
||||||
notify_.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
notify_.notify_all();
|
|
||||||
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cache_size_mgr::initialize(app_config *cfg) {
|
|
||||||
if (cfg == nullptr) {
|
|
||||||
throw startup_exception("app_config must not be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock lock(mtx_);
|
|
||||||
cfg_ = cfg;
|
|
||||||
|
|
||||||
stop_requested_ = false;
|
|
||||||
|
|
||||||
auto cache_dir = utils::file::directory{cfg_->get_cache_directory()};
|
|
||||||
if (not cache_dir.create_directory()) {
|
|
||||||
throw startup_exception(fmt::format("failed to create cache directory|{}",
|
|
||||||
cache_dir.get_path()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cache_size_ = cache_dir.size(false);
|
|
||||||
|
|
||||||
notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cache_size_mgr::shrink(std::uint64_t size) -> api_error {
|
|
||||||
mutex_lock lock(mtx_);
|
|
||||||
if (size == 0U) {
|
|
||||||
notify_.notify_all();
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cache_size_ >= size) {
|
|
||||||
cache_size_ -= size;
|
|
||||||
} else {
|
|
||||||
event_system::instance().raise<invalid_cache_size>(cache_size_, size);
|
|
||||||
cache_size_ = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
notify_.notify_all();
|
|
||||||
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cache_size_mgr::size() const -> std::uint64_t {
|
|
||||||
mutex_lock lock(mtx_);
|
|
||||||
return cache_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cache_size_mgr::stop() {
|
|
||||||
if (stop_requested_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_requested_ = true;
|
|
||||||
|
|
||||||
mutex_lock lock(mtx_);
|
|
||||||
notify_.notify_all();
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "file_manager/direct_open_file.hpp"
|
|
||||||
|
|
||||||
#include "file_manager/open_file_base.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
direct_open_file::direct_open_file(std::uint64_t chunk_size,
|
|
||||||
std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider)
|
|
||||||
: ring_buffer_base(chunk_size, chunk_timeout, fsi, provider,
|
|
||||||
min_ring_size, true) {}
|
|
||||||
|
|
||||||
direct_open_file::~direct_open_file() {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto direct_open_file::on_check_start() -> bool {
|
|
||||||
return (get_file_size() == 0U || has_reader_thread());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto direct_open_file::on_read_chunk(std::size_t chunk, std::size_t read_size,
|
|
||||||
std::uint64_t read_offset,
|
|
||||||
data_buffer &data,
|
|
||||||
std::size_t &bytes_read) -> api_error {
|
|
||||||
auto &buffer = ring_data_.at(chunk % get_ring_size());
|
|
||||||
auto begin =
|
|
||||||
std::next(buffer.begin(), static_cast<std::int64_t>(read_offset));
|
|
||||||
auto end = std::next(begin, static_cast<std::int64_t>(read_size));
|
|
||||||
data.insert(data.end(), begin, end);
|
|
||||||
bytes_read = read_size;
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto direct_open_file::use_buffer(std::size_t chunk,
|
|
||||||
std::function<api_error(data_buffer &)> func)
|
|
||||||
-> api_error {
|
|
||||||
return func(ring_data_.at(chunk % get_ring_size()));
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -22,42 +22,105 @@
|
|||||||
#include "file_manager/file_manager.hpp"
|
#include "file_manager/file_manager.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "db/file_mgr_db.hpp"
|
|
||||||
#include "file_manager/cache_size_mgr.hpp"
|
|
||||||
#include "file_manager/direct_open_file.hpp"
|
|
||||||
#include "file_manager/events.hpp"
|
#include "file_manager/events.hpp"
|
||||||
#include "file_manager/open_file.hpp"
|
#include "file_manager/open_file.hpp"
|
||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
#include "file_manager/ring_buffer_open_file.hpp"
|
#include "file_manager/ring_buffer_open_file.hpp"
|
||||||
#include "file_manager/upload.hpp"
|
#include "file_manager/upload.hpp"
|
||||||
#include "platform/platform.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
|
#include "utils/db/sqlite/db_common.hpp"
|
||||||
|
#include "utils/db/sqlite/db_delete.hpp"
|
||||||
|
#include "utils/db/sqlite/db_insert.hpp"
|
||||||
|
#include "utils/db/sqlite/db_select.hpp"
|
||||||
|
#include "utils/db/sqlite/db_update.hpp"
|
||||||
#include "utils/encrypting_reader.hpp"
|
#include "utils/encrypting_reader.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
|
#include "utils/time.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
[[nodiscard]] auto
|
||||||
|
create_resume_entry(const repertory::i_open_file &file) -> json {
|
||||||
|
return {
|
||||||
|
{"chunk_size", file.get_chunk_size()},
|
||||||
|
{"path", file.get_api_path()},
|
||||||
|
{"read_state",
|
||||||
|
repertory::utils::string::from_dynamic_bitset(file.get_read_state())},
|
||||||
|
{"source", file.get_source_path()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_resume_entry(const json &resume_entry, std::string &api_path,
|
||||||
|
std::size_t &chunk_size,
|
||||||
|
boost::dynamic_bitset<> &read_state,
|
||||||
|
std::string &source_path) {
|
||||||
|
api_path = resume_entry["path"].get<std::string>();
|
||||||
|
chunk_size = resume_entry["chunk_size"].get<std::size_t>();
|
||||||
|
read_state = repertory::utils::string::to_dynamic_bitset(
|
||||||
|
resume_entry["read_state"].get<std::string>());
|
||||||
|
source_path = resume_entry["source"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string resume_table = "resume";
|
||||||
|
const std::string upload_table = "upload";
|
||||||
|
const std::string upload_active_table = "upload_active";
|
||||||
|
const std::map<std::string, std::string> sql_create_tables{
|
||||||
|
{
|
||||||
|
{resume_table},
|
||||||
|
{
|
||||||
|
"CREATE TABLE IF NOT EXISTS " + resume_table +
|
||||||
|
"("
|
||||||
|
"api_path TEXT PRIMARY KEY ASC, "
|
||||||
|
"data TEXT"
|
||||||
|
");",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{upload_table},
|
||||||
|
{
|
||||||
|
"CREATE TABLE IF NOT EXISTS " + upload_table +
|
||||||
|
"("
|
||||||
|
"api_path TEXT PRIMARY KEY ASC, "
|
||||||
|
"date_time INTEGER, "
|
||||||
|
"source_path TEXT"
|
||||||
|
");",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{upload_active_table},
|
||||||
|
{
|
||||||
|
"CREATE TABLE IF NOT EXISTS " + upload_active_table +
|
||||||
|
"("
|
||||||
|
"api_path TEXT PRIMARY KEY ASC, "
|
||||||
|
"source_path TEXT"
|
||||||
|
");",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
file_manager::file_manager(app_config &config, i_provider &provider)
|
file_manager::file_manager(app_config &config, i_provider &provider)
|
||||||
: config_(config), provider_(provider) {
|
: config_(config), provider_(provider) {
|
||||||
mgr_db_ = create_file_mgr_db(config);
|
db_ = utils::db::sqlite::create_db(
|
||||||
|
utils::path::combine(config_.get_data_directory(), {"file_manager.db"}),
|
||||||
|
sql_create_tables);
|
||||||
|
|
||||||
if (provider_.is_read_only()) {
|
if (not provider_.is_read_only()) {
|
||||||
return;
|
E_SUBSCRIBE_EXACT(file_upload_completed,
|
||||||
|
[this](const file_upload_completed &completed) {
|
||||||
|
this->upload_completed(completed);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
E_SUBSCRIBE_EXACT(file_upload_completed,
|
|
||||||
[this](const file_upload_completed &completed) {
|
|
||||||
this->upload_completed(completed);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file_manager::~file_manager() {
|
file_manager::~file_manager() {
|
||||||
stop();
|
stop();
|
||||||
mgr_db_.reset();
|
db_.reset();
|
||||||
|
|
||||||
E_CONSUMER_RELEASE();
|
E_CONSUMER_RELEASE();
|
||||||
}
|
}
|
||||||
@ -73,13 +136,13 @@ void file_manager::close(std::uint64_t handle) {
|
|||||||
closeable_file->remove(handle);
|
closeable_file->remove(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::close_all(const std::string &api_path) -> bool {
|
void file_manager::close_all(const std::string &api_path) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
unique_recur_mutex_lock file_lock(open_file_mtx_);
|
unique_recur_mutex_lock file_lock(open_file_mtx_);
|
||||||
auto file_iter = open_file_lookup_.find(api_path);
|
auto file_iter = open_file_lookup_.find(api_path);
|
||||||
if (file_iter == open_file_lookup_.end()) {
|
if (file_iter == open_file_lookup_.end()) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto closeable_file = file_iter->second;
|
auto closeable_file = file_iter->second;
|
||||||
@ -88,8 +151,6 @@ auto file_manager::close_all(const std::string &api_path) -> bool {
|
|||||||
|
|
||||||
closeable_file->remove_all();
|
closeable_file->remove_all();
|
||||||
closeable_file->close();
|
closeable_file->close();
|
||||||
|
|
||||||
return closeable_file->get_allocated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::close_timed_out_files() {
|
void file_manager::close_timed_out_files() {
|
||||||
@ -104,12 +165,12 @@ void file_manager::close_timed_out_files() {
|
|||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
});
|
});
|
||||||
for (const auto &closeable_file : closeable_list) {
|
for (auto &&closeable_file : closeable_list) {
|
||||||
open_file_lookup_.erase(closeable_file->get_api_path());
|
open_file_lookup_.erase(closeable_file->get_api_path());
|
||||||
}
|
}
|
||||||
file_lock.unlock();
|
file_lock.unlock();
|
||||||
|
|
||||||
for (auto &closeable_file : closeable_list) {
|
for (auto &&closeable_file : closeable_list) {
|
||||||
closeable_file->close();
|
closeable_file->close();
|
||||||
event_system::instance().raise<item_timeout>(
|
event_system::instance().raise<item_timeout>(
|
||||||
closeable_file->get_api_path());
|
closeable_file->get_api_path());
|
||||||
@ -142,7 +203,7 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_recur_mutex_lock open_lock(open_file_mtx_);
|
recur_mutex_lock open_lock(open_file_mtx_);
|
||||||
if (is_processing(api_path)) {
|
if (is_processing(api_path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -151,18 +212,8 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
filesystem_item fsi{};
|
|
||||||
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsi.source_path.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string pinned;
|
std::string pinned;
|
||||||
res = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
auto res = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
||||||
if (res != api_error::success && res != api_error::item_not_found) {
|
if (res != api_error::success && res != api_error::item_not_found) {
|
||||||
utils::error::raise_api_path_error(std::string{function_name}, api_path,
|
utils::error::raise_api_path_error(std::string{function_name}, api_path,
|
||||||
res, "failed to get pinned status");
|
res, "failed to get pinned status");
|
||||||
@ -173,22 +224,23 @@ auto file_manager::evict_file(const std::string &api_path) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i_closeable_open_file> closeable_file;
|
std::string source_path{};
|
||||||
if (open_file_lookup_.contains(api_path)) {
|
res = provider_.get_item_meta(api_path, META_SOURCE, source_path);
|
||||||
closeable_file = open_file_lookup_.at(api_path);
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(std::string{function_name}, api_path,
|
||||||
|
res, "failed to get source path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (source_path.empty()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
open_file_lookup_.erase(api_path);
|
open_file_lookup_.erase(api_path);
|
||||||
open_lock.unlock();
|
|
||||||
|
|
||||||
auto allocated = closeable_file ? closeable_file->get_allocated() : true;
|
auto removed = utils::file::file{source_path}.remove();
|
||||||
closeable_file.reset();
|
|
||||||
|
|
||||||
auto removed = remove_source_and_shrink_cache(api_path, fsi.source_path,
|
|
||||||
fsi.size, allocated);
|
|
||||||
if (removed) {
|
if (removed) {
|
||||||
event_system::instance().raise<filesystem_item_evicted>(api_path,
|
event_system::instance().raise<filesystem_item_evicted>(api_path,
|
||||||
fsi.source_path);
|
source_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
@ -219,7 +271,7 @@ auto file_manager::get_open_file_by_handle(std::uint64_t handle) const
|
|||||||
-> std::shared_ptr<i_closeable_open_file> {
|
-> std::shared_ptr<i_closeable_open_file> {
|
||||||
auto file_iter =
|
auto file_iter =
|
||||||
std::find_if(open_file_lookup_.begin(), open_file_lookup_.end(),
|
std::find_if(open_file_lookup_.begin(), open_file_lookup_.end(),
|
||||||
[&handle](auto &&item) -> bool {
|
[&handle](const auto &item) -> bool {
|
||||||
return item.second->has_handle(handle);
|
return item.second->has_handle(handle);
|
||||||
});
|
});
|
||||||
return (file_iter == open_file_lookup_.end()) ? nullptr : file_iter->second;
|
return (file_iter == open_file_lookup_.end()) ? nullptr : file_iter->second;
|
||||||
@ -235,7 +287,7 @@ auto file_manager::get_open_file_count(const std::string &api_path) const
|
|||||||
|
|
||||||
auto file_manager::get_open_file(std::uint64_t handle, bool write_supported,
|
auto file_manager::get_open_file(std::uint64_t handle, bool write_supported,
|
||||||
std::shared_ptr<i_open_file> &file) -> bool {
|
std::shared_ptr<i_open_file> &file) -> bool {
|
||||||
unique_recur_mutex_lock open_lock(open_file_mtx_);
|
recur_mutex_lock open_lock(open_file_mtx_);
|
||||||
auto file_ptr = get_open_file_by_handle(handle);
|
auto file_ptr = get_open_file_by_handle(handle);
|
||||||
if (not file_ptr) {
|
if (not file_ptr) {
|
||||||
return false;
|
return false;
|
||||||
@ -244,8 +296,8 @@ auto file_manager::get_open_file(std::uint64_t handle, bool write_supported,
|
|||||||
if (write_supported && not file_ptr->is_write_supported()) {
|
if (write_supported && not file_ptr->is_write_supported()) {
|
||||||
auto writeable_file = std::make_shared<open_file>(
|
auto writeable_file = std::make_shared<open_file>(
|
||||||
utils::encryption::encrypting_reader::get_data_chunk_size(),
|
utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||||
config_.get_enable_download_timeout()
|
config_.get_enable_chunk_download_timeout()
|
||||||
? config_.get_download_timeout_secs()
|
? config_.get_chunk_downloader_timeout_secs()
|
||||||
: 0U,
|
: 0U,
|
||||||
file_ptr->get_filesystem_item(), file_ptr->get_open_data(), provider_,
|
file_ptr->get_filesystem_item(), file_ptr->get_open_data(), provider_,
|
||||||
*this);
|
*this);
|
||||||
@ -268,7 +320,7 @@ auto file_manager::get_open_files() const
|
|||||||
std::unordered_map<std::string, std::size_t> ret;
|
std::unordered_map<std::string, std::size_t> ret;
|
||||||
|
|
||||||
recur_mutex_lock open_lock(open_file_mtx_);
|
recur_mutex_lock open_lock(open_file_mtx_);
|
||||||
for (const auto &item : open_file_lookup_) {
|
for (auto &&item : open_file_lookup_) {
|
||||||
ret[item.first] = item.second->get_open_file_count();
|
ret[item.first] = item.second->get_open_file_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,15 +336,32 @@ auto file_manager::get_open_handle_count() const -> std::size_t {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::get_stored_downloads() const
|
auto file_manager::get_stored_downloads() const -> std::vector<json> {
|
||||||
-> std::vector<i_file_mgr_db::resume_entry> {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (provider_.is_read_only()) {
|
if (provider_.is_read_only()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return mgr_db_->get_resume_list();
|
std::vector<json> ret;
|
||||||
|
auto result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||||
|
while (result.has_row()) {
|
||||||
|
try {
|
||||||
|
std::optional<utils::db::sqlite::db_result::row> row;
|
||||||
|
if (not result.get_row(row)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (not row.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.push_back(row.value().get_column("data").get_value_as_json());
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex, "query error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::handle_file_rename(const std::string &from_api_path,
|
auto file_manager::handle_file_rename(const std::string &from_api_path,
|
||||||
@ -310,10 +379,15 @@ auto file_manager::handle_file_rename(const std::string &from_api_path,
|
|||||||
source_path = upload_lookup_.at(from_api_path)->get_source_path();
|
source_path = upload_lookup_.at(from_api_path)->get_source_path();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto upload = mgr_db_->get_upload(from_api_path);
|
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||||
should_upload = upload.has_value();
|
.column("source_path")
|
||||||
|
.where("api_path")
|
||||||
|
.equals(from_api_path)
|
||||||
|
.go();
|
||||||
|
std::optional<utils::db::sqlite::db_result::row> row;
|
||||||
|
should_upload = result.get_row(row) && row.has_value();
|
||||||
if (should_upload && source_path.empty()) {
|
if (should_upload && source_path.empty()) {
|
||||||
source_path = upload->source_path;
|
source_path = row->get_column("source_path").get_value<std::string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,24 +427,17 @@ auto file_manager::is_processing(const std::string &api_path) const -> bool {
|
|||||||
}
|
}
|
||||||
upload_lock.unlock();
|
upload_lock.unlock();
|
||||||
|
|
||||||
auto upload = mgr_db_->get_upload(api_path);
|
utils::db::sqlite::db_select query{*db_, upload_table};
|
||||||
if (upload.has_value()) {
|
if (query.where("api_path").equals(api_path).go().has_row()) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
unique_recur_mutex_lock open_lock(open_file_mtx_);
|
recur_mutex_lock open_lock(open_file_mtx_);
|
||||||
auto file_iter = open_file_lookup_.find(api_path);
|
auto file_iter = open_file_lookup_.find(api_path);
|
||||||
if (file_iter == open_file_lookup_.end()) {
|
return (file_iter == open_file_lookup_.end())
|
||||||
return false;
|
? false
|
||||||
}
|
: file_iter->second->is_modified() ||
|
||||||
|
not file_iter->second->is_complete();
|
||||||
auto closeable_file = file_iter->second;
|
|
||||||
open_lock.unlock();
|
|
||||||
|
|
||||||
return closeable_file->is_write_supported()
|
|
||||||
? closeable_file->is_modified() ||
|
|
||||||
not closeable_file->is_complete()
|
|
||||||
: false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_manager::open(const std::string &api_path, bool directory,
|
auto file_manager::open(const std::string &api_path, bool directory,
|
||||||
@ -384,8 +451,6 @@ auto file_manager::open(
|
|||||||
const std::string &api_path, bool directory, const open_file_data &ofd,
|
const std::string &api_path, bool directory, const open_file_data &ofd,
|
||||||
std::uint64_t &handle, std::shared_ptr<i_open_file> &file,
|
std::uint64_t &handle, std::shared_ptr<i_open_file> &file,
|
||||||
std::shared_ptr<i_closeable_open_file> closeable_file) -> api_error {
|
std::shared_ptr<i_closeable_open_file> closeable_file) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
const auto create_and_add_handle =
|
const auto create_and_add_handle =
|
||||||
[&](std::shared_ptr<i_closeable_open_file> cur_file) {
|
[&](std::shared_ptr<i_closeable_open_file> cur_file) {
|
||||||
handle = get_next_handle();
|
handle = get_next_handle();
|
||||||
@ -415,99 +480,21 @@ auto file_manager::open(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (not closeable_file) {
|
if (not closeable_file) {
|
||||||
auto buffer_directory{
|
closeable_file = std::make_shared<open_file>(
|
||||||
utils::path::combine(config_.get_data_directory(), {"buffer"}),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto chunk_size{
|
|
||||||
utils::encryption::encrypting_reader::get_data_chunk_size(),
|
utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||||
};
|
config_.get_enable_chunk_download_timeout()
|
||||||
|
? config_.get_chunk_downloader_timeout_secs()
|
||||||
auto chunk_timeout = config_.get_enable_download_timeout()
|
: 0U,
|
||||||
? config_.get_download_timeout_secs()
|
fsi, provider_, *this);
|
||||||
: 0U;
|
|
||||||
|
|
||||||
auto ring_buffer_file_size{
|
|
||||||
static_cast<std::uint64_t>(config_.get_ring_buffer_file_size()) *
|
|
||||||
1024UL * 1024UL,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto ring_size{ring_buffer_file_size / chunk_size};
|
|
||||||
|
|
||||||
const auto get_download_type = [&](download_type type) -> download_type {
|
|
||||||
if (directory || fsi.size == 0U || is_processing(api_path)) {
|
|
||||||
return download_type::default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == download_type::direct) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == download_type::default_) {
|
|
||||||
auto free_space =
|
|
||||||
utils::file::get_free_drive_space(config_.get_cache_directory());
|
|
||||||
if (fsi.size < free_space) {
|
|
||||||
return download_type::default_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not ring_buffer_open_file::can_handle_file(fsi.size, chunk_size,
|
|
||||||
ring_size)) {
|
|
||||||
return download_type::direct;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not utils::file::directory{buffer_directory}.create_directory()) {
|
|
||||||
utils::error::raise_error(
|
|
||||||
function_name, utils::get_last_error_code(),
|
|
||||||
fmt::format("failed to create buffer directory|sp|{}",
|
|
||||||
buffer_directory));
|
|
||||||
return download_type::direct;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto free_space = utils::file::get_free_drive_space(buffer_directory);
|
|
||||||
if (ring_buffer_file_size < free_space) {
|
|
||||||
return download_type::ring_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return download_type::direct;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto preferred_type = config_.get_preferred_download_type();
|
|
||||||
auto type = get_download_type(directory ? download_type::default_
|
|
||||||
: preferred_type == download_type::default_
|
|
||||||
? download_type::ring_buffer
|
|
||||||
: preferred_type);
|
|
||||||
if (not directory) {
|
|
||||||
event_system::instance().raise<download_type_selected>(
|
|
||||||
fsi.api_path, fsi.source_path, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case repertory::download_type::direct: {
|
|
||||||
closeable_file = std::make_shared<direct_open_file>(
|
|
||||||
chunk_size, chunk_timeout, fsi, provider_);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case repertory::download_type::ring_buffer: {
|
|
||||||
closeable_file = std::make_shared<ring_buffer_open_file>(
|
|
||||||
buffer_directory, chunk_size, chunk_timeout, fsi, provider_,
|
|
||||||
ring_size);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
closeable_file = std::make_shared<open_file>(chunk_size, chunk_timeout,
|
|
||||||
fsi, provider_, *this);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open_file_lookup_[api_path] = closeable_file;
|
open_file_lookup_[api_path] = closeable_file;
|
||||||
create_and_add_handle(closeable_file);
|
create_and_add_handle(closeable_file);
|
||||||
|
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::queue_upload(const i_open_file &file) {
|
void file_manager::queue_upload(const i_open_file &file) {
|
||||||
queue_upload(file.get_api_path(), file.get_source_path(), false);
|
return queue_upload(file.get_api_path(), file.get_source_path(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::queue_upload(const std::string &api_path,
|
void file_manager::queue_upload(const std::string &api_path,
|
||||||
@ -516,22 +503,28 @@ void file_manager::queue_upload(const std::string &api_path,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<mutex_lock> upload_lock;
|
std::unique_ptr<mutex_lock> lock;
|
||||||
if (not no_lock) {
|
if (not no_lock) {
|
||||||
upload_lock = std::make_unique<mutex_lock>(upload_mtx_);
|
lock = std::make_unique<mutex_lock>(upload_mtx_);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_upload(api_path, true);
|
remove_upload(api_path, true);
|
||||||
|
|
||||||
if (mgr_db_->add_upload(i_file_mgr_db::upload_entry{
|
auto result =
|
||||||
api_path,
|
utils::db::sqlite::db_insert{*db_, upload_table}
|
||||||
source_path,
|
.or_replace()
|
||||||
})) {
|
.column_value("api_path", api_path)
|
||||||
remove_resume(api_path, source_path, true);
|
.column_value("date_time",
|
||||||
|
static_cast<std::int64_t>(utils::time::get_time_now()))
|
||||||
|
.column_value("source_path", source_path)
|
||||||
|
.go();
|
||||||
|
if (result.ok()) {
|
||||||
|
remove_resume(api_path, source_path);
|
||||||
event_system::instance().raise<file_upload_queued>(api_path, source_path);
|
event_system::instance().raise<file_upload_queued>(api_path, source_path);
|
||||||
} else {
|
} else {
|
||||||
event_system::instance().raise<file_upload_failed>(
|
event_system::instance().raise<file_upload_failed>(
|
||||||
api_path, source_path, "failed to queue upload");
|
api_path, source_path,
|
||||||
|
std::to_string(result.get_error()) + '|' + result.get_error_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not no_lock) {
|
if (not no_lock) {
|
||||||
@ -542,90 +535,40 @@ void file_manager::queue_upload(const std::string &api_path,
|
|||||||
auto file_manager::remove_file(const std::string &api_path) -> api_error {
|
auto file_manager::remove_file(const std::string &api_path) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
recur_mutex_lock open_lock(open_file_mtx_);
|
||||||
|
|
||||||
filesystem_item fsi{};
|
filesystem_item fsi{};
|
||||||
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto allocated = close_all(api_path);
|
close_all(api_path);
|
||||||
|
|
||||||
unique_mutex_lock upload_lock(upload_mtx_);
|
|
||||||
remove_upload(api_path, true);
|
|
||||||
remove_resume(api_path, fsi.source_path, true);
|
|
||||||
upload_notify_.notify_all();
|
|
||||||
upload_lock.unlock();
|
|
||||||
|
|
||||||
recur_mutex_lock open_lock(open_file_mtx_);
|
|
||||||
|
|
||||||
res = provider_.remove_file(api_path);
|
res = provider_.remove_file(api_path);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_source_and_shrink_cache(api_path, fsi.source_path, fsi.size,
|
if (not utils::file::file{fsi.source_path}.remove()) {
|
||||||
allocated);
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, fsi.api_path, fsi.source_path,
|
||||||
|
utils::get_last_error_code(), "failed to delete source");
|
||||||
|
}
|
||||||
|
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::remove_resume(const std::string &api_path,
|
void file_manager::remove_resume(const std::string &api_path,
|
||||||
const std::string &source_path) {
|
const std::string &source_path) {
|
||||||
remove_resume(api_path, source_path, false);
|
auto result = utils::db::sqlite::db_delete{*db_, resume_table}
|
||||||
}
|
.where("api_path")
|
||||||
|
.equals(api_path)
|
||||||
void file_manager::remove_resume(const std::string &api_path,
|
.go();
|
||||||
const std::string &source_path, bool no_lock) {
|
if (result.ok()) {
|
||||||
if (provider_.is_read_only()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<mutex_lock> upload_lock;
|
|
||||||
if (not no_lock) {
|
|
||||||
upload_lock = std::make_unique<mutex_lock>(upload_mtx_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mgr_db_->remove_resume(api_path)) {
|
|
||||||
event_system::instance().raise<download_resume_removed>(api_path,
|
event_system::instance().raise<download_resume_removed>(api_path,
|
||||||
source_path);
|
source_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not no_lock) {
|
|
||||||
upload_notify_.notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto file_manager::remove_source_and_shrink_cache(
|
|
||||||
const std::string &api_path, const std::string &source_path,
|
|
||||||
std::uint64_t file_size, bool allocated) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto file = utils::file::file{source_path};
|
|
||||||
auto source_size = file.exists() ? file.size().value_or(0U) : 0U;
|
|
||||||
|
|
||||||
if (not file.remove()) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path, source_path,
|
|
||||||
utils::get_last_error_code(),
|
|
||||||
"failed to delete source");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not allocated || source_size == 0U) {
|
|
||||||
auto res = cache_size_mgr::instance().shrink(0U);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path, source_path,
|
|
||||||
res, "failed to shrink cache");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = cache_size_mgr::instance().shrink(file_size);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path, source_path,
|
|
||||||
res, "failed to shrink cache");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::remove_upload(const std::string &api_path) {
|
void file_manager::remove_upload(const std::string &api_path) {
|
||||||
@ -639,21 +582,29 @@ void file_manager::remove_upload(const std::string &api_path, bool no_lock) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<mutex_lock> upload_lock;
|
std::unique_ptr<mutex_lock> lock;
|
||||||
if (not no_lock) {
|
if (not no_lock) {
|
||||||
upload_lock = std::make_unique<mutex_lock>(upload_mtx_);
|
lock = std::make_unique<mutex_lock>(upload_mtx_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not mgr_db_->remove_upload(api_path)) {
|
auto result = utils::db::sqlite::db_delete{*db_, upload_table}
|
||||||
utils::error::raise_api_path_error(
|
.where("api_path")
|
||||||
function_name, api_path, api_error::error, "failed to remove upload");
|
.equals(api_path)
|
||||||
}
|
.go();
|
||||||
|
if (not result.ok()) {
|
||||||
auto removed = mgr_db_->remove_upload_active(api_path);
|
|
||||||
if (not removed) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path,
|
utils::error::raise_api_path_error(function_name, api_path,
|
||||||
api_error::error,
|
api_error::error,
|
||||||
"failed to remove active upload");
|
"failed to remove from upload table");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = utils::db::sqlite::db_delete{*db_, upload_active_table}
|
||||||
|
.where("api_path")
|
||||||
|
.equals(api_path)
|
||||||
|
.go();
|
||||||
|
if (not result.ok()) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, api_error::error,
|
||||||
|
"failed to remove from upload_active table");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upload_lookup_.find(api_path) != upload_lookup_.end()) {
|
if (upload_lookup_.find(api_path) != upload_lookup_.end()) {
|
||||||
@ -661,7 +612,7 @@ void file_manager::remove_upload(const std::string &api_path, bool no_lock) {
|
|||||||
upload_lookup_.erase(api_path);
|
upload_lookup_.erase(api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removed) {
|
if (result.ok()) {
|
||||||
event_system::instance().raise<file_upload_removed>(api_path);
|
event_system::instance().raise<file_upload_removed>(api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,36 +779,78 @@ void file_manager::start() {
|
|||||||
|
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
|
|
||||||
polling::instance().set_callback({
|
polling::instance().set_callback({"timed_out_close",
|
||||||
"timed_out_close",
|
polling::frequency::second,
|
||||||
polling::frequency::second,
|
[this](auto && /* stop_requested */) {
|
||||||
[this](auto && /* stop_requested */) { this->close_timed_out_files(); },
|
this->close_timed_out_files();
|
||||||
});
|
}});
|
||||||
|
|
||||||
if (provider_.is_read_only()) {
|
if (provider_.is_read_only()) {
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &entry : mgr_db_->get_upload_active_list()) {
|
struct active_item final {
|
||||||
queue_upload(entry.api_path, entry.source_path, false);
|
std::string api_path;
|
||||||
|
std::string source_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<active_item> active_items{};
|
||||||
|
|
||||||
|
auto result = utils::db::sqlite::db_select{*db_, upload_active_table}.go();
|
||||||
|
while (result.has_row()) {
|
||||||
|
try {
|
||||||
|
std::optional<utils::db::sqlite::db_result::row> row;
|
||||||
|
if (result.get_row(row) && row.has_value()) {
|
||||||
|
active_items.emplace_back(active_item{
|
||||||
|
row->get_column("api_path").get_value<std::string>(),
|
||||||
|
row->get_column("source_path").get_value<std::string>(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(function_name, ex, "query error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &entry : mgr_db_->get_resume_list()) {
|
for (auto &&active_item : active_items) {
|
||||||
|
queue_upload(active_item.api_path, active_item.source_path, false);
|
||||||
|
}
|
||||||
|
active_items.clear();
|
||||||
|
|
||||||
|
result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||||
|
if (not result.ok()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (result.has_row()) {
|
||||||
try {
|
try {
|
||||||
|
std::optional<utils::db::sqlite::db_result::row> row;
|
||||||
|
if (not(result.get_row(row) && row.has_value())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resume_entry = row.value().get_column("data").get_value_as_json();
|
||||||
|
|
||||||
|
std::string api_path;
|
||||||
|
std::string source_path;
|
||||||
|
std::size_t chunk_size{};
|
||||||
|
boost::dynamic_bitset<> read_state;
|
||||||
|
restore_resume_entry(resume_entry, api_path, chunk_size, read_state,
|
||||||
|
source_path);
|
||||||
|
|
||||||
filesystem_item fsi{};
|
filesystem_item fsi{};
|
||||||
auto res = provider_.get_filesystem_item(entry.api_path, false, fsi);
|
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
event_system::instance().raise<download_restore_failed>(
|
event_system::instance().raise<download_restore_failed>(
|
||||||
entry.api_path, entry.source_path,
|
api_path, source_path,
|
||||||
"failed to get filesystem item|" + api_error_to_string(res));
|
"failed to get filesystem item|" + api_error_to_string(res));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.source_path != fsi.source_path) {
|
if (source_path != fsi.source_path) {
|
||||||
event_system::instance().raise<download_restore_failed>(
|
event_system::instance().raise<download_restore_failed>(
|
||||||
fsi.api_path, fsi.source_path,
|
fsi.api_path, fsi.source_path,
|
||||||
"source path mismatch|expected|" + entry.source_path + "|actual|" +
|
"source path mismatch|expected|" + source_path + "|actual|" +
|
||||||
fsi.source_path);
|
fsi.source_path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -880,13 +873,13 @@ void file_manager::start() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto closeable_file =
|
auto closeable_file = std::make_shared<open_file>(
|
||||||
std::make_shared<open_file>(entry.chunk_size,
|
chunk_size,
|
||||||
config_.get_enable_download_timeout()
|
config_.get_enable_chunk_download_timeout()
|
||||||
? config_.get_download_timeout_secs()
|
? config_.get_chunk_downloader_timeout_secs()
|
||||||
: 0U,
|
: 0U,
|
||||||
fsi, provider_, entry.read_state, *this);
|
fsi, provider_, read_state, *this);
|
||||||
open_file_lookup_[entry.api_path] = closeable_file;
|
open_file_lookup_[api_path] = closeable_file;
|
||||||
event_system::instance().raise<download_restored>(fsi.api_path,
|
event_system::instance().raise<download_restored>(fsi.api_path,
|
||||||
fsi.source_path);
|
fsi.source_path);
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
@ -904,10 +897,8 @@ void file_manager::stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
event_system::instance().raise<service_shutdown_begin>("file_manager");
|
event_system::instance().raise<service_shutdown_begin>("file_manager");
|
||||||
|
|
||||||
stop_requested_ = true;
|
|
||||||
|
|
||||||
polling::instance().remove_callback("timed_out_close");
|
polling::instance().remove_callback("timed_out_close");
|
||||||
|
stop_requested_ = true;
|
||||||
|
|
||||||
unique_mutex_lock upload_lock(upload_mtx_);
|
unique_mutex_lock upload_lock(upload_mtx_);
|
||||||
upload_notify_.notify_all();
|
upload_notify_.notify_all();
|
||||||
@ -920,7 +911,7 @@ void file_manager::stop() {
|
|||||||
open_file_lookup_.clear();
|
open_file_lookup_.clear();
|
||||||
|
|
||||||
upload_lock.lock();
|
upload_lock.lock();
|
||||||
for (auto &item : upload_lookup_) {
|
for (auto &&item : upload_lookup_) {
|
||||||
item.second->stop();
|
item.second->stop();
|
||||||
}
|
}
|
||||||
upload_notify_.notify_all();
|
upload_notify_.notify_all();
|
||||||
@ -945,19 +936,21 @@ void file_manager::store_resume(const i_open_file &file) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mgr_db_->add_resume(i_file_mgr_db::resume_entry{
|
auto result = utils::db::sqlite::db_insert{*db_, resume_table}
|
||||||
file.get_api_path(),
|
.or_replace()
|
||||||
file.get_chunk_size(),
|
.column_value("api_path", file.get_api_path())
|
||||||
file.get_read_state(),
|
.column_value("data", create_resume_entry(file).dump())
|
||||||
file.get_source_path(),
|
.go();
|
||||||
})) {
|
if (result.ok()) {
|
||||||
event_system::instance().raise<download_resume_added>(
|
event_system::instance().raise<download_resume_added>(
|
||||||
file.get_api_path(), file.get_source_path());
|
file.get_api_path(), file.get_source_path());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_system::instance().raise<download_resume_add_failed>(
|
event_system::instance().raise<download_resume_add_failed>(
|
||||||
file.get_api_path(), file.get_source_path(), "failed to store resume");
|
file.get_api_path(), file.get_source_path(),
|
||||||
|
"failed to insert|" + std::to_string(result.get_error()) + '|' +
|
||||||
|
result.get_error_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::swap_renamed_items(std::string from_api_path,
|
void file_manager::swap_renamed_items(std::string from_api_path,
|
||||||
@ -966,23 +959,26 @@ void file_manager::swap_renamed_items(std::string from_api_path,
|
|||||||
|
|
||||||
auto file_iter = open_file_lookup_.find(from_api_path);
|
auto file_iter = open_file_lookup_.find(from_api_path);
|
||||||
if (file_iter != open_file_lookup_.end()) {
|
if (file_iter != open_file_lookup_.end()) {
|
||||||
auto closeable_file = std::move(open_file_lookup_[from_api_path]);
|
auto ptr = std::move(open_file_lookup_[from_api_path]);
|
||||||
open_file_lookup_.erase(from_api_path);
|
open_file_lookup_.erase(from_api_path);
|
||||||
closeable_file->set_api_path(to_api_path);
|
ptr->set_api_path(to_api_path);
|
||||||
open_file_lookup_[to_api_path] = std::move(closeable_file);
|
open_file_lookup_[to_api_path] = std::move(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directory) {
|
if (directory) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mgr_db_->rename_resume(from_api_path, to_api_path)) {
|
auto result = utils::db::sqlite::db_update{*db_, resume_table}
|
||||||
return;
|
.column_value("api_path", to_api_path)
|
||||||
|
.where("api_path")
|
||||||
|
.equals(from_api_path)
|
||||||
|
.go();
|
||||||
|
if (not result.ok()) {
|
||||||
|
utils::error::raise_api_path_error(function_name, to_api_path,
|
||||||
|
api_error::error,
|
||||||
|
"failed to update resume table");
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::error::raise_api_path_error(function_name, to_api_path,
|
|
||||||
api_error::error,
|
|
||||||
"failed to update resume table");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_manager::upload_completed(const file_upload_completed &evt) {
|
void file_manager::upload_completed(const file_upload_completed &evt) {
|
||||||
@ -993,8 +989,11 @@ void file_manager::upload_completed(const file_upload_completed &evt) {
|
|||||||
if (not utils::string::to_bool(evt.get_cancelled().get<std::string>())) {
|
if (not utils::string::to_bool(evt.get_cancelled().get<std::string>())) {
|
||||||
auto err = api_error_from_string(evt.get_result().get<std::string>());
|
auto err = api_error_from_string(evt.get_result().get<std::string>());
|
||||||
if (err == api_error::success) {
|
if (err == api_error::success) {
|
||||||
if (not mgr_db_->remove_upload_active(
|
auto result = utils::db::sqlite::db_delete{*db_, upload_active_table}
|
||||||
evt.get_api_path().get<std::string>())) {
|
.where("api_path")
|
||||||
|
.equals(evt.get_api_path().get<std::string>())
|
||||||
|
.go();
|
||||||
|
if (not result.ok()) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, evt.get_api_path().get<std::string>(),
|
function_name, evt.get_api_path().get<std::string>(),
|
||||||
evt.get_source().get<std::string>(),
|
evt.get_source().get<std::string>(),
|
||||||
@ -1035,17 +1034,25 @@ void file_manager::upload_handler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (upload_lookup_.size() < config_.get_max_upload_count()) {
|
if (upload_lookup_.size() < config_.get_max_upload_count()) {
|
||||||
|
auto result = utils::db::sqlite::db_select{*db_, upload_table}
|
||||||
|
.order_by("api_path", true)
|
||||||
|
.limit(1)
|
||||||
|
.go();
|
||||||
try {
|
try {
|
||||||
auto entry = mgr_db_->get_next_upload();
|
std::optional<utils::db::sqlite::db_result::row> row;
|
||||||
if (entry.has_value()) {
|
if (result.get_row(row) && row.has_value()) {
|
||||||
|
auto api_path = row->get_column("api_path").get_value<std::string>();
|
||||||
|
auto source_path =
|
||||||
|
row->get_column("source_path").get_value<std::string>();
|
||||||
|
|
||||||
filesystem_item fsi{};
|
filesystem_item fsi{};
|
||||||
auto res = provider_.get_filesystem_item(entry->api_path, false, fsi);
|
auto res = provider_.get_filesystem_item(api_path, false, fsi);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case api_error::item_not_found: {
|
case api_error::item_not_found: {
|
||||||
should_wait = false;
|
should_wait = false;
|
||||||
event_system::instance().raise<file_upload_not_found>(
|
event_system::instance().raise<file_upload_not_found>(api_path,
|
||||||
entry->api_path, entry->source_path);
|
source_path);
|
||||||
remove_upload(entry->api_path, true);
|
remove_upload(api_path, true);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case api_error::success: {
|
case api_error::success: {
|
||||||
@ -1053,23 +1060,28 @@ void file_manager::upload_handler() {
|
|||||||
|
|
||||||
upload_lookup_[fsi.api_path] =
|
upload_lookup_[fsi.api_path] =
|
||||||
std::make_unique<upload>(fsi, provider_);
|
std::make_unique<upload>(fsi, provider_);
|
||||||
if (mgr_db_->remove_upload(entry->api_path)) {
|
auto del_res = utils::db::sqlite::db_delete{*db_, upload_table}
|
||||||
if (not mgr_db_->add_upload_active(
|
.where("api_path")
|
||||||
i_file_mgr_db::upload_active_entry{
|
.equals(api_path)
|
||||||
entry->api_path,
|
.go();
|
||||||
entry->source_path,
|
if (del_res.ok()) {
|
||||||
})) {
|
auto ins_res =
|
||||||
|
utils::db::sqlite::db_insert{*db_, upload_active_table}
|
||||||
|
.column_value("api_path", api_path)
|
||||||
|
.column_value("source_path", source_path)
|
||||||
|
.go();
|
||||||
|
if (not ins_res.ok()) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, entry->api_path, entry->source_path,
|
function_name, api_path, source_path,
|
||||||
"failed to add to upload_active table");
|
"failed to add to upload_active table");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
event_system::instance().raise<file_upload_retry>(
|
event_system::instance().raise<file_upload_retry>(api_path,
|
||||||
entry->api_path, entry->source_path, res);
|
source_path, res);
|
||||||
queue_upload(entry->api_path, entry->source_path, true);
|
queue_upload(api_path, source_path, true);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,17 +21,18 @@
|
|||||||
*/
|
*/
|
||||||
#include "file_manager/open_file.hpp"
|
#include "file_manager/open_file.hpp"
|
||||||
|
|
||||||
#include "file_manager/cache_size_mgr.hpp"
|
|
||||||
#include "file_manager/events.hpp"
|
#include "file_manager/events.hpp"
|
||||||
#include "file_manager/file_manager.hpp"
|
|
||||||
#include "file_manager/i_upload_manager.hpp"
|
#include "file_manager/i_upload_manager.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "types/startup_exception.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
||||||
@ -60,246 +61,75 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
i_provider &provider,
|
i_provider &provider,
|
||||||
std::optional<boost::dynamic_bitset<>> read_state,
|
std::optional<boost::dynamic_bitset<>> read_state,
|
||||||
i_upload_manager &mgr)
|
i_upload_manager &mgr)
|
||||||
: open_file_base(chunk_size, chunk_timeout, fsi, open_data, provider,
|
: open_file_base(chunk_size, chunk_timeout, fsi, open_data, provider),
|
||||||
false),
|
|
||||||
mgr_(mgr) {
|
mgr_(mgr) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
if (fsi_.directory && read_state.has_value()) {
|
||||||
|
throw startup_exception("cannot resume a directory|" + fsi.api_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (fsi.directory) {
|
if (not fsi.directory) {
|
||||||
if (read_state.has_value()) {
|
nf_ = utils::file::file::open_or_create_file(fsi.source_path,
|
||||||
utils::error::raise_api_path_error(
|
provider_.is_read_only());
|
||||||
function_name, fsi.api_path, fsi.source_path,
|
set_api_error(*nf_ ? api_error::success : api_error::os_error);
|
||||||
fmt::format("cannot resume a directory|sp|", fsi.api_path));
|
if (get_api_error() == api_error::success) {
|
||||||
|
if (read_state.has_value()) {
|
||||||
|
read_state_ = read_state.value();
|
||||||
|
set_modified();
|
||||||
|
} else if (fsi_.size > 0U) {
|
||||||
|
read_state_.resize(static_cast<std::size_t>(utils::divide_with_ceiling(
|
||||||
|
fsi_.size, chunk_size)),
|
||||||
|
false);
|
||||||
|
|
||||||
|
auto file_size = nf_->size();
|
||||||
|
if (provider_.is_read_only() || file_size == fsi.size) {
|
||||||
|
read_state_.set(0U, read_state_.size(), true);
|
||||||
|
} else if (not nf_->truncate(fsi.size)) {
|
||||||
|
set_api_error(api_error::os_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_api_error() != api_error::success && *nf_) {
|
||||||
|
nf_->close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nf_ = utils::file::file::open_or_create_file(fsi.source_path,
|
|
||||||
get_provider().is_read_only());
|
|
||||||
set_api_error(*nf_ ? api_error::success : api_error::os_error);
|
|
||||||
if (get_api_error() != api_error::success) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_state.has_value()) {
|
|
||||||
read_state_ = read_state.value();
|
|
||||||
set_modified();
|
|
||||||
allocated = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsi.size == 0U) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_state_.resize(static_cast<std::size_t>(
|
|
||||||
utils::divide_with_ceiling(fsi.size, chunk_size)),
|
|
||||||
false);
|
|
||||||
|
|
||||||
auto file_size = nf_->size();
|
|
||||||
if (not file_size.has_value()) {
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, fsi.api_path, fsi.source_path,
|
|
||||||
utils::get_last_error_code(), "failed to get file size");
|
|
||||||
set_api_error(api_error::os_error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_provider().is_read_only() || file_size.value() == fsi.size) {
|
|
||||||
read_state_.set(0U, read_state_.size(), true);
|
|
||||||
allocated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_api_error() != api_error::success && *nf_) {
|
|
||||||
nf_->close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open_file::~open_file() { close(); }
|
open_file::~open_file() { close(); }
|
||||||
|
|
||||||
auto open_file::adjust_cache_size(std::uint64_t file_size,
|
|
||||||
bool shrink) -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
if (file_size == get_file_size()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_size > get_file_size()) {
|
|
||||||
auto size = file_size - get_file_size();
|
|
||||||
auto res = shrink ? cache_size_mgr::instance().shrink(size)
|
|
||||||
: cache_size_mgr::instance().expand(size);
|
|
||||||
if (res == api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, get_api_path(), get_source_path(), res,
|
|
||||||
fmt::format("failed to {} cache|size|{}",
|
|
||||||
(shrink ? "shrink" : "expand"), size));
|
|
||||||
return set_api_error(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto size = get_file_size() - file_size;
|
|
||||||
auto res = shrink ? cache_size_mgr::instance().expand(size)
|
|
||||||
: cache_size_mgr::instance().shrink(size);
|
|
||||||
if (res == api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, get_api_path(), get_source_path(), res,
|
|
||||||
fmt::format("failed to {} cache|size|{}", (shrink ? "expand" : "shrink"),
|
|
||||||
size));
|
|
||||||
return set_api_error(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file::check_start() -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
unique_recur_mutex_lock file_lock(get_mutex());
|
|
||||||
if (allocated) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto file_size = nf_->size();
|
|
||||||
if (not file_size.has_value()) {
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, get_api_path(), get_source_path(),
|
|
||||||
utils::get_last_error_code(), "failed to get file size");
|
|
||||||
return set_api_error(api_error::os_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_size.value() == get_file_size()) {
|
|
||||||
allocated = true;
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_lock.unlock();
|
|
||||||
auto res = adjust_cache_size(file_size.value(), true);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
file_lock.lock();
|
|
||||||
|
|
||||||
if (not nf_->truncate(get_file_size())) {
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, get_api_path(), get_source_path(),
|
|
||||||
utils::get_last_error_code(),
|
|
||||||
fmt::format("failed to truncate file|size|{}", get_file_size()));
|
|
||||||
return set_api_error(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
allocated = true;
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file::close() -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
if (is_directory() || stop_requested_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_requested_ = true;
|
|
||||||
|
|
||||||
notify_io();
|
|
||||||
|
|
||||||
if (reader_thread_) {
|
|
||||||
reader_thread_->join();
|
|
||||||
reader_thread_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not open_file_base::close()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto read_state = get_read_state();
|
|
||||||
auto err = get_api_error();
|
|
||||||
if (err == api_error::success || err == api_error::download_incomplete ||
|
|
||||||
err == api_error::download_stopped) {
|
|
||||||
if (is_modified() && not read_state.all()) {
|
|
||||||
set_api_error(api_error::download_incomplete);
|
|
||||||
} else if (not is_modified() && (get_file_size() > 0U) &&
|
|
||||||
not read_state.all()) {
|
|
||||||
set_api_error(api_error::download_stopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = get_api_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
nf_->close();
|
|
||||||
|
|
||||||
if (is_modified()) {
|
|
||||||
if (err == api_error::success) {
|
|
||||||
mgr_.queue_upload(*this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == api_error::download_incomplete) {
|
|
||||||
mgr_.store_resume(*this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != api_error::success || read_state.all()) {
|
|
||||||
mgr_.remove_resume(get_api_path(), get_source_path());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == api_error::success) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_manager::remove_source_and_shrink_cache(
|
|
||||||
get_api_path(), get_source_path(), get_file_size(), allocated);
|
|
||||||
|
|
||||||
auto parent = utils::path::get_parent_path(get_source_path());
|
|
||||||
set_source_path(utils::path::combine(parent, {utils::create_uuid_string()}));
|
|
||||||
|
|
||||||
auto res = get_provider().set_item_meta(get_api_path(), META_SOURCE,
|
|
||||||
get_source_path());
|
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
|
||||||
get_source_path(), res,
|
|
||||||
"failed to set new source path");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
||||||
bool should_reset) {
|
bool should_reset) {
|
||||||
if (should_reset) {
|
if (should_reset) {
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
unique_recur_mutex_lock download_lock(file_mtx_);
|
||||||
auto read_state = get_read_state();
|
if ((get_api_error() == api_error::success) && (chunk < read_state_.size()) &&
|
||||||
if ((get_api_error() == api_error::success) && (chunk < read_state.size()) &&
|
not read_state_[chunk]) {
|
||||||
not read_state[chunk]) {
|
if (active_downloads_.find(chunk) != active_downloads_.end()) {
|
||||||
if (get_active_downloads().find(chunk) != get_active_downloads().end()) {
|
if (not skip_active) {
|
||||||
if (skip_active) {
|
auto active_download = active_downloads_.at(chunk);
|
||||||
return;
|
download_lock.unlock();
|
||||||
|
|
||||||
|
active_download->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
|
||||||
rw_lock.unlock();
|
|
||||||
|
|
||||||
active_download->wait();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data_offset = chunk * get_chunk_size();
|
auto data_offset = chunk * chunk_size_;
|
||||||
auto data_size = (chunk == read_state.size() - 1U) ? get_last_chunk_size()
|
auto data_size =
|
||||||
: get_chunk_size();
|
(chunk == read_state_.size() - 1U) ? last_chunk_size_ : chunk_size_;
|
||||||
if (get_active_downloads().empty() && (read_state.count() == 0U)) {
|
if (active_downloads_.empty() && (read_state_.count() == 0U)) {
|
||||||
event_system::instance().raise<download_begin>(get_api_path(),
|
event_system::instance().raise<download_begin>(fsi_.api_path,
|
||||||
get_source_path());
|
fsi_.source_path);
|
||||||
}
|
}
|
||||||
|
event_system::instance().raise<download_chunk_begin>(
|
||||||
|
fsi_.api_path, fsi_.source_path, chunk, read_state_.size(),
|
||||||
|
read_state_.count());
|
||||||
|
|
||||||
get_active_downloads()[chunk] = std::make_shared<download>();
|
active_downloads_[chunk] = std::make_shared<download>();
|
||||||
rw_lock.unlock();
|
download_lock.unlock();
|
||||||
|
|
||||||
if (should_reset) {
|
if (should_reset) {
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
@ -308,28 +138,28 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
std::async(std::launch::async, [this, chunk, data_size, data_offset,
|
std::async(std::launch::async, [this, chunk, data_size, data_offset,
|
||||||
should_reset]() {
|
should_reset]() {
|
||||||
const auto notify_complete = [this, chunk, should_reset]() {
|
const auto notify_complete = [this, chunk, should_reset]() {
|
||||||
auto state = get_read_state();
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
auto active_download = active_downloads_.at(chunk);
|
||||||
unique_recur_mutex_lock lock(rw_mtx_);
|
active_downloads_.erase(chunk);
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
event_system::instance().raise<download_chunk_end>(
|
||||||
get_active_downloads().erase(chunk);
|
fsi_.api_path, fsi_.source_path, chunk, read_state_.size(),
|
||||||
|
read_state_.count(), get_api_error());
|
||||||
if (get_api_error() == api_error::success) {
|
if (get_api_error() == api_error::success) {
|
||||||
auto progress = (static_cast<double>(state.count()) /
|
auto progress = (static_cast<double>(read_state_.count()) /
|
||||||
static_cast<double>(state.size())) *
|
static_cast<double>(read_state_.size()) * 100.0);
|
||||||
100.0;
|
|
||||||
event_system::instance().raise<download_progress>(
|
event_system::instance().raise<download_progress>(
|
||||||
get_api_path(), get_source_path(), progress);
|
fsi_.api_path, fsi_.source_path, progress);
|
||||||
if (state.all() && not notified_) {
|
if (read_state_.all() && not notified_) {
|
||||||
notified_ = true;
|
notified_ = true;
|
||||||
event_system::instance().raise<download_end>(
|
event_system::instance().raise<download_end>(
|
||||||
get_api_path(), get_source_path(), get_api_error());
|
fsi_.api_path, fsi_.source_path, get_api_error());
|
||||||
}
|
}
|
||||||
} else if (not notified_) {
|
} else if (not notified_) {
|
||||||
notified_ = true;
|
notified_ = true;
|
||||||
event_system::instance().raise<download_end>(
|
event_system::instance().raise<download_end>(
|
||||||
get_api_path(), get_source_path(), get_api_error());
|
fsi_.api_path, fsi_.source_path, get_api_error());
|
||||||
}
|
}
|
||||||
lock.unlock();
|
file_lock.unlock();
|
||||||
|
|
||||||
active_download->notify(get_api_error());
|
active_download->notify(get_api_error());
|
||||||
|
|
||||||
@ -338,9 +168,9 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
data_buffer buffer;
|
data_buffer data;
|
||||||
auto res = get_provider().read_file_bytes(
|
auto res = provider_.read_file_bytes(get_api_path(), data_size,
|
||||||
get_api_path(), data_size, data_offset, buffer, stop_requested_);
|
data_offset, data, stop_requested_);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
set_api_error(res);
|
set_api_error(res);
|
||||||
notify_complete();
|
notify_complete();
|
||||||
@ -353,7 +183,7 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
|
|
||||||
res = do_io([&]() -> api_error {
|
res = do_io([&]() -> api_error {
|
||||||
std::size_t bytes_written{};
|
std::size_t bytes_written{};
|
||||||
if (not nf_->write(buffer, data_offset, &bytes_written)) {
|
if (not nf_->write(data, data_offset, &bytes_written)) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,50 +198,48 @@ void open_file::download_chunk(std::size_t chunk, bool skip_active,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_read_state(chunk);
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
read_state_.set(chunk);
|
||||||
|
file_lock.unlock();
|
||||||
|
|
||||||
notify_complete();
|
notify_complete();
|
||||||
}).wait();
|
}).wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::download_range(std::size_t begin_chunk, std::size_t end_chunk,
|
void open_file::download_range(std::size_t start_chunk, std::size_t end_chunk,
|
||||||
bool should_reset) {
|
bool should_reset) {
|
||||||
for (std::size_t chunk = begin_chunk;
|
for (std::size_t chunk = start_chunk; chunk <= end_chunk; ++chunk) {
|
||||||
(get_api_error() == api_error::success) && (chunk <= end_chunk);
|
|
||||||
++chunk) {
|
|
||||||
download_chunk(chunk, false, should_reset);
|
download_chunk(chunk, false, should_reset);
|
||||||
|
if (get_api_error() != api_error::success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::get_allocated() const -> bool {
|
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
|
||||||
return allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
auto open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return read_state_;
|
return read_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::get_read_state(std::size_t chunk) const -> bool {
|
auto open_file::get_read_state(std::size_t chunk) const -> bool {
|
||||||
return get_read_state()[chunk];
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
return read_state_[chunk];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::is_complete() const -> bool { return get_read_state().all(); }
|
auto open_file::is_complete() const -> bool {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
return read_state_.all();
|
||||||
|
}
|
||||||
|
|
||||||
auto open_file::native_operation(
|
auto open_file::native_operation(
|
||||||
i_open_file::native_operation_callback callback) -> api_error {
|
i_open_file::native_operation_callback callback) -> api_error {
|
||||||
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
if (stop_requested_) {
|
if (stop_requested_) {
|
||||||
return set_api_error(api_error::download_stopped);
|
return api_error::download_stopped;
|
||||||
}
|
}
|
||||||
|
file_lock.unlock();
|
||||||
|
|
||||||
auto res = check_start();
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
|
||||||
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,48 +248,38 @@ auto open_file::native_operation(
|
|||||||
i_open_file::native_operation_callback callback) -> api_error {
|
i_open_file::native_operation_callback callback) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return api_error::invalid_operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
if (stop_requested_) {
|
if (stop_requested_) {
|
||||||
return set_api_error(api_error::download_stopped);
|
return api_error::download_stopped;
|
||||||
}
|
|
||||||
|
|
||||||
auto res = check_start();
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = adjust_cache_size(new_file_size, false);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
file_lock.unlock();
|
||||||
|
|
||||||
auto is_empty_file = new_file_size == 0U;
|
auto is_empty_file = new_file_size == 0U;
|
||||||
auto last_chunk = is_empty_file
|
auto last_chunk = is_empty_file
|
||||||
? std::size_t(0U)
|
? std::size_t(0U)
|
||||||
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
: static_cast<std::size_t>(utils::divide_with_ceiling(
|
||||||
new_file_size, get_chunk_size())) -
|
new_file_size, chunk_size_)) -
|
||||||
1U;
|
1U;
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
file_lock.lock();
|
||||||
auto read_state = get_read_state();
|
if (not is_empty_file && (last_chunk < read_state_.size())) {
|
||||||
if (not is_empty_file && (last_chunk < read_state.size())) {
|
file_lock.unlock();
|
||||||
rw_lock.unlock();
|
update_background_reader(0U);
|
||||||
update_reader(0U);
|
|
||||||
|
|
||||||
download_chunk(last_chunk, false, true);
|
download_chunk(last_chunk, false, true);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
return get_api_error();
|
return get_api_error();
|
||||||
}
|
}
|
||||||
rw_lock.lock();
|
file_lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
read_state = get_read_state();
|
|
||||||
auto original_file_size = get_file_size();
|
auto original_file_size = get_file_size();
|
||||||
|
|
||||||
res = do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
auto res = do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
utils::error::raise_api_path_error(function_name, get_api_path(),
|
||||||
utils::get_last_error_code(),
|
utils::get_last_error_code(),
|
||||||
@ -470,73 +288,59 @@ auto open_file::native_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto file_size = nf_->size();
|
auto file_size = nf_->size().value_or(0U);
|
||||||
if (not file_size.has_value()) {
|
if (file_size != new_file_size) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), api_error::file_size_mismatch,
|
function_name, get_api_path(), api_error::file_size_mismatch,
|
||||||
fmt::format("failed to get file size|error|{}",
|
"allocated file size mismatch|expected|" +
|
||||||
utils::get_last_error_code()));
|
std::to_string(new_file_size) + "|actual|" +
|
||||||
return set_api_error(api_error::error);
|
std::to_string(file_size));
|
||||||
}
|
|
||||||
|
|
||||||
if (file_size.value() != new_file_size) {
|
|
||||||
utils::error::raise_api_path_error(
|
|
||||||
function_name, get_api_path(), api_error::file_size_mismatch,
|
|
||||||
fmt::format("file size mismatch|expected|{}|actual|{}", new_file_size,
|
|
||||||
file_size.value()));
|
|
||||||
return set_api_error(api_error::error);
|
return set_api_error(api_error::error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_empty_file || (read_state.size() != (last_chunk + 1U))) {
|
if (is_empty_file || (read_state_.size() != (last_chunk + 1U))) {
|
||||||
auto old_size = read_state.size();
|
auto old_size = read_state_.size();
|
||||||
read_state.resize(is_empty_file ? 0U : last_chunk + 1U);
|
read_state_.resize(is_empty_file ? 0U : last_chunk + 1U);
|
||||||
|
|
||||||
if (not is_empty_file) {
|
if (not is_empty_file) {
|
||||||
for (std::size_t chunk = old_size; chunk <= last_chunk; ++chunk) {
|
for (std::size_t chunk = old_size; chunk <= last_chunk; ++chunk) {
|
||||||
read_state.set(chunk);
|
read_state_.set(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_read_state(read_state);
|
|
||||||
|
|
||||||
set_last_chunk_size(static_cast<std::size_t>(
|
last_chunk_size_ = static_cast<std::size_t>(
|
||||||
new_file_size <= get_chunk_size() ? new_file_size
|
new_file_size <= chunk_size_ ? new_file_size
|
||||||
: (new_file_size % get_chunk_size()) == 0U
|
: (new_file_size % chunk_size_) == 0U ? chunk_size_
|
||||||
? get_chunk_size()
|
: new_file_size % chunk_size_);
|
||||||
: new_file_size % get_chunk_size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original_file_size == new_file_size) {
|
if (original_file_size != new_file_size) {
|
||||||
return res;
|
set_modified();
|
||||||
}
|
|
||||||
set_modified();
|
|
||||||
|
|
||||||
set_file_size(new_file_size);
|
fsi_.size = new_file_size;
|
||||||
auto now = std::to_string(utils::time::get_time_now());
|
auto now = std::to_string(utils::time::get_time_now());
|
||||||
res = get_provider().set_item_meta(
|
res = provider_.set_item_meta(
|
||||||
get_api_path(), {
|
fsi_.api_path, {
|
||||||
{META_CHANGED, now},
|
{META_CHANGED, now},
|
||||||
{META_MODIFIED, now},
|
{META_MODIFIED, now},
|
||||||
{META_SIZE, std::to_string(new_file_size)},
|
{META_SIZE, std::to_string(new_file_size)},
|
||||||
{META_WRITTEN, now},
|
{META_WRITTEN, now},
|
||||||
});
|
});
|
||||||
if (res == api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
||||||
|
"failed to set file meta");
|
||||||
|
return set_api_error(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
return res;
|
||||||
"failed to set file meta");
|
|
||||||
return set_api_error(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
||||||
data_buffer &data) -> api_error {
|
data_buffer &data) -> api_error {
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return api_error::invalid_operation;
|
||||||
}
|
|
||||||
|
|
||||||
if (stop_requested_) {
|
|
||||||
return set_api_error(api_error::download_stopped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read_size =
|
read_size =
|
||||||
@ -545,17 +349,12 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = check_start();
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto read_from_source = [this, &data, &read_offset,
|
const auto read_from_source = [this, &data, &read_offset,
|
||||||
&read_size]() -> api_error {
|
&read_size]() -> api_error {
|
||||||
return do_io([this, &data, &read_offset, &read_size]() -> api_error {
|
return do_io([this, &data, &read_offset, &read_size]() -> api_error {
|
||||||
if (get_provider().is_read_only()) {
|
if (provider_.is_read_only()) {
|
||||||
return get_provider().read_file_bytes(
|
return provider_.read_file_bytes(fsi_.api_path, read_size, read_offset,
|
||||||
get_api_path(), read_size, read_offset, data, stop_requested_);
|
data, stop_requested_);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.resize(read_size);
|
data.resize(read_size);
|
||||||
@ -566,48 +365,49 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (get_read_state().all()) {
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
if (read_state_.all()) {
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
return read_from_source();
|
return read_from_source();
|
||||||
}
|
}
|
||||||
|
file_lock.unlock();
|
||||||
|
|
||||||
auto begin_chunk = static_cast<std::size_t>(read_offset / get_chunk_size());
|
auto start_chunk = static_cast<std::size_t>(read_offset / chunk_size_);
|
||||||
auto end_chunk =
|
auto end_chunk =
|
||||||
static_cast<std::size_t>((read_size + read_offset) / get_chunk_size());
|
static_cast<std::size_t>((read_size + read_offset) / chunk_size_);
|
||||||
|
|
||||||
update_reader(begin_chunk);
|
update_background_reader(start_chunk);
|
||||||
|
|
||||||
download_range(begin_chunk, end_chunk, true);
|
download_range(start_chunk, end_chunk, true);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
return get_api_error();
|
return get_api_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
file_lock.lock();
|
||||||
return get_api_error() == api_error::success ? read_from_source()
|
return get_api_error() == api_error::success ? read_from_source()
|
||||||
: get_api_error();
|
: get_api_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::remove(std::uint64_t handle) {
|
void open_file::remove(std::uint64_t handle) {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
open_file_base::remove(handle);
|
open_file_base::remove(handle);
|
||||||
|
if (modified_ && read_state_.all() &&
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
|
||||||
if (is_modified() && get_read_state().all() &&
|
|
||||||
(get_api_error() == api_error::success)) {
|
(get_api_error() == api_error::success)) {
|
||||||
mgr_.queue_upload(*this);
|
mgr_.queue_upload(*this);
|
||||||
open_file_base::set_modified(false);
|
modified_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_removed() && (get_open_file_count() == 0U)) {
|
if (removed_ && (get_open_file_count() == 0U)) {
|
||||||
open_file_base::set_removed(false);
|
removed_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::remove_all() {
|
void open_file::remove_all() {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
open_file_base::remove_all();
|
open_file_base::remove_all();
|
||||||
|
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
modified_ = false;
|
||||||
open_file_base::set_modified(false);
|
removed_ = true;
|
||||||
open_file_base::set_removed(true);
|
|
||||||
|
|
||||||
mgr_.remove_upload(get_api_path());
|
mgr_.remove_upload(get_api_path());
|
||||||
|
|
||||||
@ -615,12 +415,8 @@ void open_file::remove_all() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
||||||
if (is_directory()) {
|
if (fsi_.directory) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return api_error::invalid_operation;
|
||||||
}
|
|
||||||
|
|
||||||
if (new_file_size == get_file_size()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return native_operation(
|
return native_operation(
|
||||||
@ -630,62 +426,123 @@ auto open_file::resize(std::uint64_t new_file_size) -> api_error {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto open_file::close() -> bool {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
if (fsi_.directory || stop_requested_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_requested_ = true;
|
||||||
|
|
||||||
|
unique_mutex_lock reader_lock(io_thread_mtx_);
|
||||||
|
io_thread_notify_.notify_all();
|
||||||
|
reader_lock.unlock();
|
||||||
|
|
||||||
|
if (reader_thread_) {
|
||||||
|
reader_thread_->join();
|
||||||
|
reader_thread_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not open_file_base::close()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto err = get_api_error();
|
||||||
|
if (err == api_error::success || err == api_error::download_incomplete ||
|
||||||
|
err == api_error::download_stopped) {
|
||||||
|
if (modified_ && not read_state_.all()) {
|
||||||
|
set_api_error(api_error::download_incomplete);
|
||||||
|
} else if (not modified_ && (fsi_.size > 0U) && not read_state_.all()) {
|
||||||
|
set_api_error(api_error::download_stopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = get_api_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_->close();
|
||||||
|
|
||||||
|
if (modified_) {
|
||||||
|
if (err == api_error::success) {
|
||||||
|
mgr_.queue_upload(*this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == api_error::download_incomplete) {
|
||||||
|
mgr_.store_resume(*this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == api_error::success) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr_.remove_resume(get_api_path(), get_source_path());
|
||||||
|
if (not utils::file::file(fsi_.source_path).remove()) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, get_api_path(), fsi_.source_path,
|
||||||
|
utils::get_last_error_code(), "failed to delete file");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parent = utils::path::get_parent_path(fsi_.source_path);
|
||||||
|
fsi_.source_path =
|
||||||
|
utils::path::combine(parent, {utils::create_uuid_string()});
|
||||||
|
auto res =
|
||||||
|
provider_.set_item_meta(fsi_.api_path, META_SOURCE, fsi_.source_path);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(function_name, get_api_path(),
|
||||||
|
fsi_.source_path, res,
|
||||||
|
"failed to set file meta");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void open_file::set_modified() {
|
void open_file::set_modified() {
|
||||||
if (not is_modified()) {
|
if (not modified_) {
|
||||||
open_file_base::set_modified(true);
|
modified_ = true;
|
||||||
mgr_.store_resume(*this);
|
mgr_.store_resume(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not is_removed()) {
|
if (not removed_) {
|
||||||
open_file_base::set_removed(true);
|
removed_ = true;
|
||||||
mgr_.remove_upload(get_api_path());
|
mgr_.remove_upload(get_api_path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file::set_read_state(std::size_t chunk) {
|
void open_file::update_background_reader(std::size_t read_chunk) {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
recur_mutex_lock reader_lock(file_mtx_);
|
||||||
read_state_.set(chunk);
|
read_chunk_ = read_chunk;
|
||||||
}
|
|
||||||
|
|
||||||
void open_file::set_read_state(boost::dynamic_bitset<> read_state) {
|
if (not reader_thread_ && not stop_requested_) {
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
reader_thread_ = std::make_unique<std::thread>([this]() {
|
||||||
read_state_ = std::move(read_state);
|
std::size_t next_chunk{};
|
||||||
}
|
while (not stop_requested_) {
|
||||||
|
unique_recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
if ((fsi_.size == 0U) || read_state_.all()) {
|
||||||
|
file_lock.unlock();
|
||||||
|
|
||||||
void open_file::update_reader(std::size_t chunk) {
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
recur_mutex_lock rw_lock(rw_mtx_);
|
if (not stop_requested_ && io_thread_queue_.empty()) {
|
||||||
read_chunk_ = chunk;
|
io_thread_notify_.wait(io_lock);
|
||||||
|
}
|
||||||
|
io_thread_notify_.notify_all();
|
||||||
|
io_lock.unlock();
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
next_chunk = read_chunk_ =
|
||||||
|
((read_chunk_ + 1U) >= read_state_.size()) ? 0U
|
||||||
|
: read_chunk_ + 1U;
|
||||||
|
} while ((next_chunk != 0U) && (active_downloads_.find(next_chunk) !=
|
||||||
|
active_downloads_.end()));
|
||||||
|
|
||||||
if (reader_thread_ || stop_requested_) {
|
file_lock.unlock();
|
||||||
return;
|
download_chunk(next_chunk, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reader_thread_ = std::make_unique<std::thread>([this]() {
|
|
||||||
unique_recur_mutex_lock lock(rw_mtx_);
|
|
||||||
auto next_chunk{read_chunk_};
|
|
||||||
auto read_chunk{read_chunk_};
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
while (not stop_requested_) {
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
auto read_state = get_read_state();
|
|
||||||
if ((get_file_size() == 0U) || read_state.all()) {
|
|
||||||
lock.unlock();
|
|
||||||
wait_for_io(stop_requested_);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_chunk != read_chunk_) {
|
|
||||||
next_chunk = read_chunk = read_chunk_;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_chunk = next_chunk + 1U >= read_state.size() ? 0U : next_chunk + 1U;
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
download_chunk(next_chunk, true, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
||||||
@ -694,44 +551,41 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
|
|
||||||
bytes_written = 0U;
|
bytes_written = 0U;
|
||||||
|
|
||||||
if (is_directory() || get_provider().is_read_only()) {
|
if (fsi_.directory || provider_.is_read_only()) {
|
||||||
return set_api_error(api_error::invalid_operation);
|
return api_error::invalid_operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unique_recur_mutex_lock write_lock(file_mtx_);
|
||||||
if (stop_requested_) {
|
if (stop_requested_) {
|
||||||
return set_api_error(api_error::download_stopped);
|
return api_error::download_stopped;
|
||||||
}
|
}
|
||||||
|
write_lock.unlock();
|
||||||
|
|
||||||
auto res = check_start();
|
auto start_chunk = static_cast<std::size_t>(write_offset / chunk_size_);
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin_chunk = static_cast<std::size_t>(write_offset / get_chunk_size());
|
|
||||||
auto end_chunk =
|
auto end_chunk =
|
||||||
static_cast<std::size_t>((write_offset + data.size()) / get_chunk_size());
|
static_cast<std::size_t>((write_offset + data.size()) / chunk_size_);
|
||||||
|
|
||||||
update_reader(begin_chunk);
|
update_background_reader(start_chunk);
|
||||||
|
|
||||||
download_range(begin_chunk, std::min(get_read_state().size() - 1U, end_chunk),
|
download_range(start_chunk, std::min(read_state_.size() - 1U, end_chunk),
|
||||||
true);
|
true);
|
||||||
if (get_api_error() != api_error::success) {
|
if (get_api_error() != api_error::success) {
|
||||||
return get_api_error();
|
return get_api_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_recur_mutex_lock rw_lock(rw_mtx_);
|
write_lock.lock();
|
||||||
if ((write_offset + data.size()) > get_file_size()) {
|
if ((write_offset + data.size()) > fsi_.size) {
|
||||||
res = resize(write_offset + data.size());
|
auto res = resize(write_offset + data.size());
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = do_io([&]() -> api_error {
|
auto res = do_io([&]() -> api_error {
|
||||||
if (not nf_->write(data, write_offset, &bytes_written)) {
|
if (not nf_->write(data, write_offset, &bytes_written)) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -744,11 +598,11 @@ auto open_file::write(std::uint64_t write_offset, const data_buffer &data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto now = std::to_string(utils::time::get_time_now());
|
auto now = std::to_string(utils::time::get_time_now());
|
||||||
res = get_provider().set_item_meta(get_api_path(), {
|
res = provider_.set_item_meta(fsi_.api_path, {
|
||||||
{META_CHANGED, now},
|
{META_CHANGED, now},
|
||||||
{META_MODIFIED, now},
|
{META_MODIFIED, now},
|
||||||
{META_WRITTEN, now},
|
{META_WRITTEN, now},
|
||||||
});
|
});
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
utils::error::raise_api_path_error(function_name, get_api_path(), res,
|
||||||
"failed to set file meta");
|
"failed to set file meta");
|
||||||
|
@ -35,15 +35,13 @@ void open_file_base::download::notify(const api_error &err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::download::wait() -> api_error {
|
auto open_file_base::download::wait() -> api_error {
|
||||||
if (complete_) {
|
|
||||||
return error_;
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_mutex_lock lock(mtx_);
|
|
||||||
if (not complete_) {
|
if (not complete_) {
|
||||||
notify_.wait(lock);
|
unique_mutex_lock lock(mtx_);
|
||||||
|
if (not complete_) {
|
||||||
|
notify_.wait(lock);
|
||||||
|
}
|
||||||
|
notify_.notify_all();
|
||||||
}
|
}
|
||||||
notify_.notify_all();
|
|
||||||
|
|
||||||
return error_;
|
return error_;
|
||||||
}
|
}
|
||||||
@ -67,14 +65,12 @@ auto open_file_base::io_item::get_result() -> api_error {
|
|||||||
|
|
||||||
open_file_base::open_file_base(std::uint64_t chunk_size,
|
open_file_base::open_file_base(std::uint64_t chunk_size,
|
||||||
std::uint8_t chunk_timeout, filesystem_item fsi,
|
std::uint8_t chunk_timeout, filesystem_item fsi,
|
||||||
i_provider &provider, bool disable_io)
|
i_provider &provider)
|
||||||
: open_file_base(chunk_size, chunk_timeout, fsi, {}, provider, disable_io) {
|
: open_file_base(chunk_size, chunk_timeout, fsi, {}, provider) {}
|
||||||
}
|
|
||||||
|
|
||||||
open_file_base::open_file_base(
|
open_file_base::open_file_base(
|
||||||
std::uint64_t chunk_size, std::uint8_t chunk_timeout, filesystem_item fsi,
|
std::uint64_t chunk_size, std::uint8_t chunk_timeout, filesystem_item fsi,
|
||||||
std::map<std::uint64_t, open_file_data> open_data, i_provider &provider,
|
std::map<std::uint64_t, open_file_data> open_data, i_provider &provider)
|
||||||
bool disable_io)
|
|
||||||
: chunk_size_(chunk_size),
|
: chunk_size_(chunk_size),
|
||||||
chunk_timeout_(chunk_timeout),
|
chunk_timeout_(chunk_timeout),
|
||||||
fsi_(std::move(fsi)),
|
fsi_(std::move(fsi)),
|
||||||
@ -84,7 +80,7 @@ open_file_base::open_file_base(
|
|||||||
: fsi.size % chunk_size)),
|
: fsi.size % chunk_size)),
|
||||||
open_data_(std::move(open_data)),
|
open_data_(std::move(open_data)),
|
||||||
provider_(provider) {
|
provider_(provider) {
|
||||||
if (not fsi.directory && not disable_io) {
|
if (not fsi.directory) {
|
||||||
io_thread_ = std::make_unique<std::thread>([this] { file_io_thread(); });
|
io_thread_ = std::make_unique<std::thread>([this] { file_io_thread(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +115,7 @@ auto open_file_base::can_close() const -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_complete()) {
|
if (is_download_complete()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,30 +123,12 @@ auto open_file_base::can_close() const -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::time_point last_access{last_access_};
|
const std::chrono::system_clock::time_point last_access = last_access_;
|
||||||
auto duration = std::chrono::duration_cast<std::chrono::seconds>(
|
const auto duration = std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
std::chrono::system_clock::now() - last_access);
|
std::chrono::system_clock::now() - last_access);
|
||||||
return (duration.count() >= chunk_timeout_);
|
return (duration.count() >= chunk_timeout_);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::close() -> bool {
|
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
|
||||||
if (io_stop_requested_ || not io_thread_) {
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
io_lock.unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_stop_requested_ = true;
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
io_lock.unlock();
|
|
||||||
|
|
||||||
io_thread_->join();
|
|
||||||
io_thread_.reset();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::do_io(std::function<api_error()> action) -> api_error {
|
auto open_file_base::do_io(std::function<api_error()> action) -> api_error {
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
auto item = std::make_shared<io_item>(action);
|
auto item = std::make_shared<io_item>(action);
|
||||||
@ -209,36 +187,6 @@ auto open_file_base::get_file_size() const -> std::uint64_t {
|
|||||||
return fsi_.size;
|
return fsi_.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto open_file_base::get_last_chunk_size() const -> std::size_t {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return last_chunk_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_file_size(std::uint64_t size) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
fsi_.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_last_chunk_size(std::size_t size) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
last_chunk_size_ = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_modified(bool modified) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
modified_ = modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_removed(bool removed) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
removed_ = removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::set_source_path(std::string source_path) {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
fsi_.source_path = std::move(source_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::get_filesystem_item() const -> filesystem_item {
|
auto open_file_base::get_filesystem_item() const -> filesystem_item {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return fsi_;
|
return fsi_;
|
||||||
@ -246,9 +194,8 @@ auto open_file_base::get_filesystem_item() const -> filesystem_item {
|
|||||||
|
|
||||||
auto open_file_base::get_handles() const -> std::vector<std::uint64_t> {
|
auto open_file_base::get_handles() const -> std::vector<std::uint64_t> {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
|
||||||
std::vector<std::uint64_t> ret;
|
std::vector<std::uint64_t> ret;
|
||||||
for (const auto &item : open_data_) {
|
for (auto &&item : open_data_) {
|
||||||
ret.emplace_back(item.first);
|
ret.emplace_back(item.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,31 +230,11 @@ auto open_file_base::get_open_file_count() const -> std::size_t {
|
|||||||
return open_data_.size();
|
return open_data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::get_source_path() const -> std::string {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return fsi_.source_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::has_handle(std::uint64_t handle) const -> bool {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return open_data_.find(handle) != open_data_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto open_file_base::is_modified() const -> bool {
|
auto open_file_base::is_modified() const -> bool {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
return modified_;
|
return modified_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open_file_base::is_removed() const -> bool {
|
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
|
||||||
return removed_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::notify_io() {
|
|
||||||
mutex_lock io_lock(io_thread_mtx_);
|
|
||||||
io_thread_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_file_base::remove(std::uint64_t handle) {
|
void open_file_base::remove(std::uint64_t handle) {
|
||||||
recur_mutex_lock file_lock(file_mtx_);
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
if (open_data_.find(handle) == open_data_.end()) {
|
if (open_data_.find(handle) == open_data_.end()) {
|
||||||
@ -334,7 +261,7 @@ void open_file_base::remove_all() {
|
|||||||
auto open_data = open_data_;
|
auto open_data = open_data_;
|
||||||
open_data_.clear();
|
open_data_.clear();
|
||||||
|
|
||||||
for (const auto &data : open_data) {
|
for (auto &&data : open_data) {
|
||||||
event_system::instance().raise<filesystem_item_handle_closed>(
|
event_system::instance().raise<filesystem_item_handle_closed>(
|
||||||
fsi_.api_path, data.first, fsi_.source_path, fsi_.directory, modified_);
|
fsi_.api_path, data.first, fsi_.source_path, fsi_.directory, modified_);
|
||||||
}
|
}
|
||||||
@ -349,15 +276,15 @@ void open_file_base::reset_timeout() {
|
|||||||
|
|
||||||
auto open_file_base::set_api_error(const api_error &err) -> api_error {
|
auto open_file_base::set_api_error(const api_error &err) -> api_error {
|
||||||
mutex_lock error_lock(error_mtx_);
|
mutex_lock error_lock(error_mtx_);
|
||||||
if (error_ == err) {
|
if (error_ != err) {
|
||||||
return error_;
|
return ((error_ = (error_ == api_error::success ||
|
||||||
|
error_ == api_error::download_incomplete ||
|
||||||
|
error_ == api_error::download_stopped
|
||||||
|
? err
|
||||||
|
: error_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((error_ = (error_ == api_error::success ||
|
return error_;
|
||||||
error_ == api_error::download_incomplete ||
|
|
||||||
error_ == api_error::download_stopped
|
|
||||||
? err
|
|
||||||
: error_)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file_base::set_api_path(const std::string &api_path) {
|
void open_file_base::set_api_path(const std::string &api_path) {
|
||||||
@ -366,12 +293,24 @@ void open_file_base::set_api_path(const std::string &api_path) {
|
|||||||
fsi_.api_parent = utils::path::get_parent_api_path(api_path);
|
fsi_.api_parent = utils::path::get_parent_api_path(api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_file_base::wait_for_io(stop_type &stop_requested) {
|
auto open_file_base::close() -> bool {
|
||||||
unique_mutex_lock io_lock(io_thread_mtx_);
|
unique_mutex_lock io_lock(io_thread_mtx_);
|
||||||
if (not stop_requested && io_thread_queue_.empty()) {
|
if (not fsi_.directory && not io_stop_requested_) {
|
||||||
io_thread_notify_.wait(io_lock);
|
io_stop_requested_ = true;
|
||||||
|
io_thread_notify_.notify_all();
|
||||||
|
io_lock.unlock();
|
||||||
|
|
||||||
|
if (io_thread_) {
|
||||||
|
io_thread_->join();
|
||||||
|
io_thread_.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
io_thread_notify_.notify_all();
|
io_thread_notify_.notify_all();
|
||||||
io_lock.unlock();
|
io_lock.unlock();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -1,367 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "file_manager/ring_buffer_base.hpp"
|
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "file_manager/events.hpp"
|
|
||||||
#include "file_manager/open_file_base.hpp"
|
|
||||||
#include "platform/platform.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
#include "utils/common.hpp"
|
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
ring_buffer_base::ring_buffer_base(std::uint64_t chunk_size,
|
|
||||||
std::uint8_t chunk_timeout,
|
|
||||||
filesystem_item fsi, i_provider &provider,
|
|
||||||
std::size_t ring_size, bool disable_io)
|
|
||||||
: open_file_base(chunk_size, chunk_timeout, fsi, provider, disable_io),
|
|
||||||
read_state_(ring_size),
|
|
||||||
total_chunks_(static_cast<std::size_t>(
|
|
||||||
utils::divide_with_ceiling(fsi.size, chunk_size))) {
|
|
||||||
if (disable_io) {
|
|
||||||
if (fsi.size > 0U) {
|
|
||||||
read_state_.resize(std::min(total_chunks_, read_state_.size()));
|
|
||||||
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
read_state_.set(0U, read_state_.size(), false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ring_size < min_ring_size) {
|
|
||||||
throw std::runtime_error("ring size must be greater than or equal to 5");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_end_ = std::min(total_chunks_ - 1U, ring_begin_ + ring_size - 1U);
|
|
||||||
read_state_.set(0U, ring_size, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::check_start() -> api_error {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (on_check_start()) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_system::instance().raise<download_begin>(get_api_path(),
|
|
||||||
get_source_path());
|
|
||||||
reader_thread_ =
|
|
||||||
std::make_unique<std::thread>([this]() { reader_thread(); });
|
|
||||||
return api_error::success;
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
utils::error::raise_api_path_error(function_name, get_api_path(),
|
|
||||||
get_source_path(), ex,
|
|
||||||
"failed to start");
|
|
||||||
return api_error::error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::close() -> bool {
|
|
||||||
stop_requested_ = true;
|
|
||||||
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
auto res = open_file_base::close();
|
|
||||||
|
|
||||||
if (reader_thread_) {
|
|
||||||
reader_thread_->join();
|
|
||||||
reader_thread_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::download_chunk(std::size_t chunk,
|
|
||||||
bool skip_active) -> api_error {
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
const auto unlock_and_notify = [this, &chunk_lock]() {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto unlock_and_return =
|
|
||||||
[&unlock_and_notify](api_error res) -> api_error {
|
|
||||||
unlock_and_notify();
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (chunk < ring_begin_ || chunk > ring_end_) {
|
|
||||||
return unlock_and_return(api_error::invalid_ring_buffer_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_active_downloads().find(chunk) != get_active_downloads().end()) {
|
|
||||||
if (skip_active) {
|
|
||||||
return unlock_and_return(api_error::success);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
return active_download->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_state_[chunk % read_state_.size()]) {
|
|
||||||
return unlock_and_return(api_error::success);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto active_download{std::make_shared<download>()};
|
|
||||||
get_active_downloads()[chunk] = active_download;
|
|
||||||
|
|
||||||
return use_buffer(chunk, [&](data_buffer &buffer) -> api_error {
|
|
||||||
auto data_offset{chunk * get_chunk_size()};
|
|
||||||
auto data_size{
|
|
||||||
chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
|
|
||||||
: get_chunk_size(),
|
|
||||||
};
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
auto result{
|
|
||||||
get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
|
|
||||||
buffer, stop_requested_),
|
|
||||||
};
|
|
||||||
|
|
||||||
chunk_lock.lock();
|
|
||||||
if (chunk < ring_begin_ || chunk > ring_end_) {
|
|
||||||
result = api_error::invalid_ring_buffer_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == api_error::success) {
|
|
||||||
result = on_chunk_downloaded(chunk, buffer);
|
|
||||||
if (result == api_error::success) {
|
|
||||||
read_state_[chunk % read_state_.size()] = true;
|
|
||||||
auto progress = (static_cast<double>(chunk + 1U) /
|
|
||||||
static_cast<double>(total_chunks_)) *
|
|
||||||
100.0;
|
|
||||||
event_system::instance().raise<download_progress>(
|
|
||||||
get_api_path(), get_source_path(), progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get_active_downloads().erase(chunk);
|
|
||||||
unlock_and_notify();
|
|
||||||
|
|
||||||
active_download->notify(result);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::forward(std::size_t count) {
|
|
||||||
update_position(count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::get_read_state() const -> boost::dynamic_bitset<> {
|
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
|
||||||
return read_state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::get_read_state(std::size_t chunk) const -> bool {
|
|
||||||
recur_mutex_lock file_lock(get_mutex());
|
|
||||||
return read_state_[chunk % read_state_.size()];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
|
|
||||||
data_buffer &data) -> api_error {
|
|
||||||
if (is_directory()) {
|
|
||||||
return api_error::invalid_operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
read_size =
|
|
||||||
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
|
||||||
if (read_size == 0U) {
|
|
||||||
return api_error::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin_chunk{static_cast<std::size_t>(read_offset / get_chunk_size())};
|
|
||||||
read_offset = read_offset - (begin_chunk * get_chunk_size());
|
|
||||||
|
|
||||||
unique_mutex_lock read_lock(read_mtx_);
|
|
||||||
auto res = check_start();
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t chunk = begin_chunk;
|
|
||||||
not stop_requested_ && (res == api_error::success) && (read_size > 0U);
|
|
||||||
++chunk) {
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
if (chunk > ring_pos_) {
|
|
||||||
forward(chunk - ring_pos_);
|
|
||||||
} else if (chunk < ring_pos_) {
|
|
||||||
reverse(ring_pos_ - chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = download_chunk(chunk, false);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
if (res == api_error::invalid_ring_buffer_position) {
|
|
||||||
read_lock.unlock();
|
|
||||||
|
|
||||||
// TODO limit retry
|
|
||||||
return read(read_size, read_offset, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
res = on_read_chunk(
|
|
||||||
chunk,
|
|
||||||
std::min(static_cast<std::size_t>(get_chunk_size() - read_offset),
|
|
||||||
read_size),
|
|
||||||
read_offset, data, bytes_read);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_timeout();
|
|
||||||
|
|
||||||
read_size -= bytes_read;
|
|
||||||
read_offset = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stop_requested_ ? api_error::download_stopped : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::reader_thread() {
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
auto next_chunk{ring_pos_};
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
while (not stop_requested_) {
|
|
||||||
chunk_lock.lock();
|
|
||||||
|
|
||||||
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
|
|
||||||
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
|
|
||||||
if (stop_requested_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_read_state().all()) {
|
|
||||||
chunk_notify_.wait(chunk_lock);
|
|
||||||
next_chunk = ring_pos_;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (read_state_[next_chunk % read_state_.size()]) {
|
|
||||||
check_and_wait();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
download_chunk(next_chunk, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_system::instance().raise<download_end>(
|
|
||||||
get_api_path(), get_source_path(), api_error::download_stopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::reverse(std::size_t count) {
|
|
||||||
update_position(count, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::set(std::size_t first_chunk, std::size_t current_chunk) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
if (first_chunk >= total_chunks_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
throw std::runtime_error("first chunk must be less than total chunks");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_begin_ = first_chunk;
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
|
|
||||||
if (current_chunk > ring_end_) {
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
throw std::runtime_error(
|
|
||||||
"current chunk must be less than or equal to last chunk");
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_pos_ = current_chunk;
|
|
||||||
read_state_.set(0U, read_state_.size(), true);
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::set_api_path(const std::string &api_path) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
open_file_base::set_api_path(api_path);
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ring_buffer_base::update_position(std::size_t count, bool is_forward) {
|
|
||||||
mutex_lock chunk_lock(chunk_mtx_);
|
|
||||||
|
|
||||||
if (is_forward) {
|
|
||||||
if ((ring_pos_ + count) > (total_chunks_ - 1U)) {
|
|
||||||
count = (total_chunks_ - 1U) - ring_pos_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
count = std::min(ring_pos_, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_forward ? (ring_pos_ + count) <= ring_end_
|
|
||||||
: (ring_pos_ - count) >= ring_begin_) {
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
} else {
|
|
||||||
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
|
||||||
: count - (ring_pos_ - ring_begin_);
|
|
||||||
|
|
||||||
if (delta >= read_state_.size()) {
|
|
||||||
read_state_.set(0U, read_state_.size(), false);
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
} else {
|
|
||||||
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
|
||||||
if (is_forward) {
|
|
||||||
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
|
||||||
} else {
|
|
||||||
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -21,30 +21,73 @@
|
|||||||
*/
|
*/
|
||||||
#include "file_manager/ring_buffer_open_file.hpp"
|
#include "file_manager/ring_buffer_open_file.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
#include "file_manager/events.hpp"
|
||||||
#include "file_manager/open_file_base.hpp"
|
#include "file_manager/open_file_base.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/encrypting_reader.hpp"
|
||||||
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
|
ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
||||||
|
std::uint64_t chunk_size,
|
||||||
|
std::uint8_t chunk_timeout,
|
||||||
|
filesystem_item fsi,
|
||||||
|
i_provider &provider)
|
||||||
|
: ring_buffer_open_file(std::move(buffer_directory), chunk_size,
|
||||||
|
chunk_timeout, std::move(fsi), provider,
|
||||||
|
(1024ULL * 1024ULL * 1024ULL) / chunk_size) {}
|
||||||
|
|
||||||
ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
ring_buffer_open_file::ring_buffer_open_file(std::string buffer_directory,
|
||||||
std::uint64_t chunk_size,
|
std::uint64_t chunk_size,
|
||||||
std::uint8_t chunk_timeout,
|
std::uint8_t chunk_timeout,
|
||||||
filesystem_item fsi,
|
filesystem_item fsi,
|
||||||
i_provider &provider,
|
i_provider &provider,
|
||||||
std::size_t ring_size)
|
std::size_t ring_size)
|
||||||
: ring_buffer_base(chunk_size, chunk_timeout, fsi, provider, ring_size,
|
: open_file_base(chunk_size, chunk_timeout, fsi, provider),
|
||||||
false),
|
ring_state_(ring_size),
|
||||||
source_path_(utils::path::combine(buffer_directory,
|
total_chunks_(static_cast<std::size_t>(
|
||||||
{
|
utils::divide_with_ceiling(fsi.size, chunk_size_))) {
|
||||||
utils::create_uuid_string(),
|
if ((ring_size % 2U) != 0U) {
|
||||||
})) {
|
throw std::runtime_error("ring size must be a multiple of 2");
|
||||||
if (not can_handle_file(fsi.size, chunk_size, ring_size)) {
|
}
|
||||||
|
|
||||||
|
if (ring_size < 4U) {
|
||||||
|
throw std::runtime_error("ring size must be greater than or equal to 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsi.size < (ring_state_.size() * chunk_size)) {
|
||||||
throw std::runtime_error("file size is less than ring buffer size");
|
throw std::runtime_error("file size is less than ring buffer size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_chunk_ = ring_state_.size() - 1U;
|
||||||
|
ring_state_.set(0U, ring_state_.size(), true);
|
||||||
|
|
||||||
|
buffer_directory = utils::path::absolute(buffer_directory);
|
||||||
|
if (not utils::file::directory(buffer_directory).create_directory()) {
|
||||||
|
throw std::runtime_error("failed to create buffer directory|path|" +
|
||||||
|
buffer_directory + "|err|" +
|
||||||
|
std::to_string(utils::get_last_error_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fsi_.source_path =
|
||||||
|
utils::path::combine(buffer_directory, {utils::create_uuid_string()});
|
||||||
|
nf_ = utils::file::file::open_or_create_file(fsi_.source_path);
|
||||||
|
if (not*nf_) {
|
||||||
|
throw std::runtime_error("failed to create buffer file|err|" +
|
||||||
|
std::to_string(utils::get_last_error_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not nf_->truncate(ring_state_.size() * chunk_size)) {
|
||||||
|
nf_->close();
|
||||||
|
throw std::runtime_error("failed to resize buffer file|err|" +
|
||||||
|
std::to_string(utils::get_last_error_code()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ring_buffer_open_file::~ring_buffer_open_file() {
|
ring_buffer_open_file::~ring_buffer_open_file() {
|
||||||
@ -52,24 +95,107 @@ ring_buffer_open_file::~ring_buffer_open_file() {
|
|||||||
|
|
||||||
close();
|
close();
|
||||||
|
|
||||||
if (not nf_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nf_->close();
|
nf_->close();
|
||||||
nf_.reset();
|
if (not utils::file::file(fsi_.source_path).remove()) {
|
||||||
|
|
||||||
if (not utils::file::file(source_path_).remove()) {
|
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, get_api_path(), source_path_,
|
function_name, fsi_.api_path, fsi_.source_path,
|
||||||
utils::get_last_error_code(), "failed to delete file");
|
utils::get_last_error_code(), "failed to delete file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::can_handle_file(std::uint64_t file_size,
|
auto ring_buffer_open_file::download_chunk(std::size_t chunk) -> api_error {
|
||||||
std::size_t chunk_size,
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
std::size_t ring_size) -> bool {
|
if (active_downloads_.find(chunk) != active_downloads_.end()) {
|
||||||
return file_size >= (static_cast<std::uint64_t>(ring_size) * chunk_size);
|
auto active_download = active_downloads_.at(chunk);
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
return active_download->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ring_state_[chunk % ring_state_.size()]) {
|
||||||
|
auto active_download = std::make_shared<download>();
|
||||||
|
active_downloads_[chunk] = active_download;
|
||||||
|
ring_state_[chunk % ring_state_.size()] = false;
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
data_buffer buffer((chunk == (total_chunks_ - 1U)) ? last_chunk_size_
|
||||||
|
: chunk_size_);
|
||||||
|
|
||||||
|
stop_type stop_requested = !!ring_state_[chunk % ring_state_.size()];
|
||||||
|
auto res =
|
||||||
|
provider_.read_file_bytes(fsi_.api_path, buffer.size(),
|
||||||
|
chunk * chunk_size_, buffer, stop_requested);
|
||||||
|
if (res == api_error::success) {
|
||||||
|
res = do_io([&]() -> api_error {
|
||||||
|
std::size_t bytes_written{};
|
||||||
|
if (not nf_->write(buffer, (chunk % ring_state_.size()) * chunk_size_,
|
||||||
|
&bytes_written)) {
|
||||||
|
return api_error::os_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_error::success;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
active_download->notify(res);
|
||||||
|
|
||||||
|
chunk_lock.lock();
|
||||||
|
active_downloads_.erase(chunk);
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
chunk_lock.unlock();
|
||||||
|
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::forward(std::size_t count) {
|
||||||
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
if ((current_chunk_ + count) > (total_chunks_ - 1U)) {
|
||||||
|
count = (total_chunks_ - 1U) - current_chunk_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((current_chunk_ + count) <= last_chunk_) {
|
||||||
|
current_chunk_ += count;
|
||||||
|
} else {
|
||||||
|
const auto added = count - (last_chunk_ - current_chunk_);
|
||||||
|
if (added >= ring_state_.size()) {
|
||||||
|
ring_state_.set(0U, ring_state_.size(), true);
|
||||||
|
current_chunk_ += count;
|
||||||
|
first_chunk_ += added;
|
||||||
|
last_chunk_ =
|
||||||
|
std::min(total_chunks_ - 1U, first_chunk_ + ring_state_.size() - 1U);
|
||||||
|
} else {
|
||||||
|
for (std::size_t idx = 0U; idx < added; ++idx) {
|
||||||
|
ring_state_[(first_chunk_ + idx) % ring_state_.size()] = true;
|
||||||
|
}
|
||||||
|
first_chunk_ += added;
|
||||||
|
current_chunk_ += count;
|
||||||
|
last_chunk_ =
|
||||||
|
std::min(total_chunks_ - 1U, first_chunk_ + ring_state_.size() - 1U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::get_read_state() const -> boost::dynamic_bitset<> {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
auto read_state = ring_state_;
|
||||||
|
return read_state.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::get_read_state(std::size_t chunk) const -> bool {
|
||||||
|
recur_mutex_lock file_lock(file_mtx_);
|
||||||
|
return not ring_state_[chunk % ring_state_.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ring_buffer_open_file::is_download_complete() const -> bool {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::native_operation(
|
auto ring_buffer_open_file::native_operation(
|
||||||
@ -77,75 +203,121 @@ auto ring_buffer_open_file::native_operation(
|
|||||||
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
return do_io([&]() -> api_error { return callback(nf_->get_handle()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_check_start() -> bool {
|
void ring_buffer_open_file::reverse(std::size_t count) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
if (current_chunk_ < count) {
|
||||||
if (nf_) {
|
count = current_chunk_;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buffer_directory{utils::path::get_parent_path(source_path_)};
|
if ((current_chunk_ - count) >= first_chunk_) {
|
||||||
if (not utils::file::directory(buffer_directory).create_directory()) {
|
current_chunk_ -= count;
|
||||||
throw std::runtime_error(
|
} else {
|
||||||
fmt::format("failed to create buffer directory|path|{}|err|{}",
|
const auto removed = count - (current_chunk_ - first_chunk_);
|
||||||
buffer_directory, utils::get_last_error_code()));
|
if (removed >= ring_state_.size()) {
|
||||||
|
ring_state_.set(0U, ring_state_.size(), true);
|
||||||
|
current_chunk_ -= count;
|
||||||
|
first_chunk_ = current_chunk_;
|
||||||
|
last_chunk_ =
|
||||||
|
std::min(total_chunks_ - 1U, first_chunk_ + ring_state_.size() - 1U);
|
||||||
|
} else {
|
||||||
|
for (std::size_t idx = 0U; idx < removed; ++idx) {
|
||||||
|
ring_state_[(last_chunk_ - idx) % ring_state_.size()] = true;
|
||||||
|
}
|
||||||
|
first_chunk_ -= removed;
|
||||||
|
current_chunk_ -= count;
|
||||||
|
last_chunk_ =
|
||||||
|
std::min(total_chunks_ - 1U, first_chunk_ + ring_state_.size() - 1U);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nf_ = utils::file::file::open_or_create_file(source_path_);
|
chunk_notify_.notify_all();
|
||||||
if (not nf_ || not *nf_) {
|
|
||||||
throw std::runtime_error(fmt::format("failed to create buffer file|err|{}",
|
|
||||||
utils::get_last_error_code()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not nf_->truncate(get_ring_size() * get_chunk_size())) {
|
|
||||||
nf_->close();
|
|
||||||
nf_.reset();
|
|
||||||
|
|
||||||
throw std::runtime_error(fmt::format("failed to resize buffer file|err|{}",
|
|
||||||
utils::get_last_error_code()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_chunk_downloaded(
|
auto ring_buffer_open_file::read(std::size_t read_size,
|
||||||
std::size_t chunk, const data_buffer &buffer) -> api_error {
|
std::uint64_t read_offset, data_buffer &data)
|
||||||
return do_io([&]() -> api_error {
|
-> api_error {
|
||||||
std::size_t bytes_written{};
|
if (fsi_.directory) {
|
||||||
if (nf_->write(buffer, (chunk % get_ring_size()) * get_chunk_size(),
|
return api_error::invalid_operation;
|
||||||
&bytes_written)) {
|
}
|
||||||
return api_error::success;
|
|
||||||
|
reset_timeout();
|
||||||
|
|
||||||
|
read_size = utils::calculate_read_size(fsi_.size, read_size, read_offset);
|
||||||
|
if (read_size == 0U) {
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto start_chunk_index =
|
||||||
|
static_cast<std::size_t>(read_offset / chunk_size_);
|
||||||
|
read_offset = read_offset - (start_chunk_index * chunk_size_);
|
||||||
|
data_buffer buffer(chunk_size_);
|
||||||
|
|
||||||
|
auto res = api_error::success;
|
||||||
|
for (std::size_t chunk = start_chunk_index;
|
||||||
|
(res == api_error::success) && (read_size > 0U); ++chunk) {
|
||||||
|
if (chunk > current_chunk_) {
|
||||||
|
forward(chunk - current_chunk_);
|
||||||
|
} else if (chunk < current_chunk_) {
|
||||||
|
reverse(current_chunk_ - chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return api_error::os_error;
|
reset_timeout();
|
||||||
});
|
res = download_chunk(chunk);
|
||||||
}
|
if (res == api_error::success) {
|
||||||
|
const auto to_read = std::min(
|
||||||
|
static_cast<std::size_t>(chunk_size_ - read_offset), read_size);
|
||||||
|
res = do_io([this, &buffer, &chunk, &data, read_offset,
|
||||||
|
&to_read]() -> api_error {
|
||||||
|
std::size_t bytes_read{};
|
||||||
|
auto ret =
|
||||||
|
nf_->read(buffer, ((chunk % ring_state_.size()) * chunk_size_),
|
||||||
|
&bytes_read)
|
||||||
|
? api_error::success
|
||||||
|
: api_error::os_error;
|
||||||
|
if (ret == api_error::success) {
|
||||||
|
data.insert(data.end(),
|
||||||
|
buffer.begin() + static_cast<std::int64_t>(read_offset),
|
||||||
|
buffer.begin() +
|
||||||
|
static_cast<std::int64_t>(read_offset + to_read));
|
||||||
|
reset_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::on_read_chunk(
|
return ret;
|
||||||
std::size_t chunk, std::size_t read_size, std::uint64_t read_offset,
|
});
|
||||||
data_buffer &data, std::size_t &bytes_read) -> api_error {
|
read_offset = 0U;
|
||||||
data_buffer buffer(read_size);
|
read_size -= to_read;
|
||||||
auto res = do_io([&]() -> api_error {
|
}
|
||||||
return nf_->read(
|
|
||||||
buffer,
|
|
||||||
(((chunk % get_ring_size()) * get_chunk_size()) + read_offset),
|
|
||||||
&bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.insert(data.end(), buffer.begin(), buffer.end());
|
return res;
|
||||||
return api_error::success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_open_file::use_buffer(
|
void ring_buffer_open_file::set(std::size_t first_chunk,
|
||||||
std::size_t /* chunk */,
|
std::size_t current_chunk) {
|
||||||
std::function<api_error(data_buffer &)> func) -> api_error {
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
data_buffer buffer;
|
if (first_chunk >= total_chunks_) {
|
||||||
return func(buffer);
|
chunk_notify_.notify_all();
|
||||||
|
throw std::runtime_error("first chunk must be less than total chunks");
|
||||||
|
}
|
||||||
|
|
||||||
|
first_chunk_ = first_chunk;
|
||||||
|
last_chunk_ = first_chunk_ + ring_state_.size() - 1U;
|
||||||
|
|
||||||
|
if (current_chunk > last_chunk_) {
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
throw std::runtime_error(
|
||||||
|
"current chunk must be less than or equal to last chunk");
|
||||||
|
}
|
||||||
|
|
||||||
|
current_chunk_ = current_chunk;
|
||||||
|
ring_state_.set(0U, ring_state_.size(), false);
|
||||||
|
|
||||||
|
chunk_notify_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ring_buffer_open_file::set_api_path(const std::string &api_path) {
|
||||||
|
mutex_lock chunk_lock(chunk_mtx_);
|
||||||
|
open_file_base::set_api_path(api_path);
|
||||||
|
chunk_notify_.notify_all();
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -53,8 +53,7 @@ void upload::upload_thread() {
|
|||||||
|
|
||||||
error_ =
|
error_ =
|
||||||
provider_.upload_file(fsi_.api_path, fsi_.source_path, stop_requested_);
|
provider_.upload_file(fsi_.api_path, fsi_.source_path, stop_requested_);
|
||||||
if (error_ == api_error::success &&
|
if (not utils::file::reset_modified_time(fsi_.source_path)) {
|
||||||
not utils::file::reset_modified_time(fsi_.source_path)) {
|
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
function_name, fsi_.api_path, fsi_.source_path,
|
function_name, fsi_.api_path, fsi_.source_path,
|
||||||
utils::get_last_error_code(), "failed to reset modified time");
|
utils::get_last_error_code(), "failed to reset modified time");
|
||||||
|
@ -28,8 +28,9 @@
|
|||||||
#endif // defined(PROJECT_ENABLE_OPENSSL)
|
#endif // defined(PROJECT_ENABLE_OPENSSL)
|
||||||
|
|
||||||
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
||||||
#include <cstdlib>
|
#include <filesystem>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||||
@ -43,7 +44,6 @@
|
|||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
#include "initialize.hpp"
|
#include "initialize.hpp"
|
||||||
|
|
||||||
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
#include "platform/unix_platform.hpp"
|
#include "platform/unix_platform.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
#include "types/startup_exception.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
|
@ -23,14 +23,12 @@
|
|||||||
|
|
||||||
#include "platform/win32_platform.hpp"
|
#include "platform/win32_platform.hpp"
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto lock_data::get_mount_state(const provider_type & /*pt*/,
|
auto lock_data::get_mount_state(const provider_type & /*pt*/, json &mount_state)
|
||||||
json &mount_state) -> bool {
|
-> bool {
|
||||||
const auto ret = get_mount_state(mount_state);
|
const auto ret = get_mount_state(mount_state);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
const auto mount_id =
|
const auto mount_id =
|
||||||
|
@ -25,10 +25,8 @@
|
|||||||
#include "db/meta_db.hpp"
|
#include "db/meta_db.hpp"
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/events.hpp"
|
#include "events/events.hpp"
|
||||||
#include "file_manager/cache_size_mgr.hpp"
|
|
||||||
#include "file_manager/i_file_manager.hpp"
|
#include "file_manager/i_file_manager.hpp"
|
||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file_utils.hpp"
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
@ -457,7 +455,7 @@ void base_provider::process_removed_files(std::deque<removed_item> removed_list,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto orphaned_directory =
|
auto orphaned_directory =
|
||||||
utils::path::combine(get_config().get_data_directory(), {"orphaned"});
|
utils::path::combine(config_.get_data_directory(), {"orphaned"});
|
||||||
for (const auto &item : removed_list) {
|
for (const auto &item : removed_list) {
|
||||||
if (stop_requested) {
|
if (stop_requested) {
|
||||||
return;
|
return;
|
||||||
@ -521,32 +519,30 @@ void base_provider::process_removed_items(const stop_type &stop_requested) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks::instance().schedule({
|
tasks::instance().schedule({
|
||||||
[this, api_path](auto &&task_stopped) {
|
[this, api_path](auto &&stop_requested2) {
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
if (get_item_meta(api_path, meta) != api_error::success) {
|
if (get_item_meta(api_path, meta) != api_error::success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils::string::to_bool(meta[META_DIRECTORY])) {
|
if (utils::string::to_bool(meta[META_DIRECTORY])) {
|
||||||
|
bool exists{};
|
||||||
|
if (is_directory(api_path, exists) != api_error::success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_removed_directories(
|
||||||
|
{
|
||||||
|
removed_item{api_path, true, ""},
|
||||||
|
},
|
||||||
|
stop_requested2);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// bool exists{};
|
|
||||||
// if (is_directory(api_path, exists) != api_error::success) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (exists) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // process_removed_directories(
|
|
||||||
// // {
|
|
||||||
// // removed_item{api_path, true, ""},
|
|
||||||
// // },
|
|
||||||
// // stop_requested2);
|
|
||||||
//
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool exists{};
|
bool exists{};
|
||||||
if (is_file(api_path, exists) != api_error::success) {
|
if (is_file(api_path, exists) != api_error::success) {
|
||||||
@ -561,11 +557,11 @@ void base_provider::process_removed_items(const stop_type &stop_requested) {
|
|||||||
{
|
{
|
||||||
removed_item{api_path, false, meta[META_SOURCE]},
|
removed_item{api_path, false, meta[META_SOURCE]},
|
||||||
},
|
},
|
||||||
task_stopped);
|
stop_requested2);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return not stop_requested;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,10 +667,8 @@ void base_provider::remove_unmatched_source_files(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &cfg = get_config();
|
|
||||||
|
|
||||||
auto source_list =
|
auto source_list =
|
||||||
utils::file::directory{cfg.get_cache_directory()}.get_files();
|
utils::file::directory{config_.get_cache_directory()}.get_files();
|
||||||
for (const auto &source_file : source_list) {
|
for (const auto &source_file : source_list) {
|
||||||
if (stop_requested) {
|
if (stop_requested) {
|
||||||
return;
|
return;
|
||||||
@ -687,15 +681,15 @@ void base_provider::remove_unmatched_source_files(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto reference_time =
|
auto reference_time =
|
||||||
source_file->get_time(cfg.get_eviction_uses_accessed_time()
|
source_file->get_time(config_.get_eviction_uses_accessed_time()
|
||||||
? utils::file::time_type::accessed
|
? utils::file::time_type::accessed
|
||||||
: utils::file::time_type::modified);
|
: utils::file::time_type::modified);
|
||||||
if (not reference_time.has_value()) {
|
if (not reference_time.has_value()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto delay =
|
auto delay = (config_.get_eviction_delay_mins() * 60UL) *
|
||||||
(cfg.get_eviction_delay_mins() * 60UL) * utils::time::NANOS_PER_SECOND;
|
utils::time::NANOS_PER_SECOND;
|
||||||
if ((reference_time.value() + static_cast<std::uint64_t>(delay)) >=
|
if ((reference_time.value() + static_cast<std::uint64_t>(delay)) >=
|
||||||
utils::time::get_time_now()) {
|
utils::time::get_time_now()) {
|
||||||
continue;
|
continue;
|
||||||
@ -739,19 +733,17 @@ auto base_provider::start(api_item_added_callback api_item_added,
|
|||||||
auto online{false};
|
auto online{false};
|
||||||
auto unmount_requested{false};
|
auto unmount_requested{false};
|
||||||
{
|
{
|
||||||
const auto &cfg = get_config();
|
|
||||||
|
|
||||||
repertory::event_consumer consumer(
|
repertory::event_consumer consumer(
|
||||||
"unmount_requested",
|
"unmount_requested",
|
||||||
[&unmount_requested](const event &) { unmount_requested = true; });
|
[&unmount_requested](const event &) { unmount_requested = true; });
|
||||||
for (std::uint16_t idx = 0U; not online && not unmount_requested &&
|
for (std::uint16_t idx = 0U; not online && not unmount_requested &&
|
||||||
(idx < cfg.get_online_check_retry_secs());
|
(idx < config_.get_online_check_retry_secs());
|
||||||
++idx) {
|
++idx) {
|
||||||
online = is_online();
|
online = is_online();
|
||||||
if (not online) {
|
if (not online) {
|
||||||
event_system::instance().raise<provider_offline>(
|
event_system::instance().raise<provider_offline>(
|
||||||
cfg.get_host_config().host_name_or_ip,
|
config_.get_host_config().host_name_or_ip,
|
||||||
cfg.get_host_config().api_port);
|
config_.get_host_config().api_port);
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -761,8 +753,6 @@ auto base_provider::start(api_item_added_callback api_item_added,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_size_mgr::instance().initialize(&config_);
|
|
||||||
|
|
||||||
polling::instance().set_callback({
|
polling::instance().set_callback({
|
||||||
"check_deleted",
|
"check_deleted",
|
||||||
polling::frequency::low,
|
polling::frequency::low,
|
||||||
@ -773,7 +763,6 @@ auto base_provider::start(api_item_added_callback api_item_added,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void base_provider::stop() {
|
void base_provider::stop() {
|
||||||
cache_size_mgr::instance().stop();
|
|
||||||
polling::instance().remove_callback("check_deleted");
|
polling::instance().remove_callback("check_deleted");
|
||||||
db3_.reset();
|
db3_.reset();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "comm/i_http_comm.hpp"
|
#include "comm/i_http_comm.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "file_manager/i_file_manager.hpp"
|
#include "file_manager/i_file_manager.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "types/s3.hpp"
|
#include "types/s3.hpp"
|
||||||
@ -41,7 +39,9 @@
|
|||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
|
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
|
||||||
: base_provider(config, comm) {}
|
: base_provider(config, comm) {
|
||||||
|
get_comm().enable_s3_path_style(config.get_s3_config().use_path_style);
|
||||||
|
}
|
||||||
|
|
||||||
auto s3_provider::add_if_not_found(
|
auto s3_provider::add_if_not_found(
|
||||||
api_file &file, const std::string &object_name) const -> api_error {
|
api_file &file, const std::string &object_name) const -> api_error {
|
||||||
@ -85,7 +85,7 @@ auto s3_provider::create_directory_impl(const std::string &api_path,
|
|||||||
api_meta_map &meta) -> api_error {
|
api_meta_map &meta) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
stop_type stop_requested{false};
|
stop_type stop_requested{false};
|
||||||
|
|
||||||
@ -138,8 +138,7 @@ auto s3_provider::create_file_extra(const std::string &api_path,
|
|||||||
api_meta_map &meta) -> api_error {
|
api_meta_map &meta) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
if (not get_config().get_s3_config().encryption_token.empty()) {
|
||||||
if (not cfg.encryption_token.empty()) {
|
|
||||||
std::string encrypted_file_path;
|
std::string encrypted_file_path;
|
||||||
auto res = get_item_meta(utils::path::get_parent_api_path(api_path),
|
auto res = get_item_meta(utils::path::get_parent_api_path(api_path),
|
||||||
META_KEY, encrypted_file_path);
|
META_KEY, encrypted_file_path);
|
||||||
@ -151,7 +150,7 @@ auto s3_provider::create_file_extra(const std::string &api_path,
|
|||||||
|
|
||||||
data_buffer result;
|
data_buffer result;
|
||||||
utils::encryption::encrypt_data(
|
utils::encryption::encrypt_data(
|
||||||
cfg.encryption_token,
|
get_config().get_s3_config().encryption_token,
|
||||||
*(utils::string::split(api_path, '/', false).end() - 1U), result);
|
*(utils::string::split(api_path, '/', false).end() - 1U), result);
|
||||||
|
|
||||||
meta[META_KEY] = utils::path::create_api_path(
|
meta[META_KEY] = utils::path::create_api_path(
|
||||||
@ -164,14 +163,11 @@ auto s3_provider::create_file_extra(const std::string &api_path,
|
|||||||
|
|
||||||
auto s3_provider::create_path_directories(
|
auto s3_provider::create_path_directories(
|
||||||
const std::string &api_path, const std::string &key) const -> api_error {
|
const std::string &api_path, const std::string &key) const -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
if (api_path == "/") {
|
if (api_path == "/") {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto encryption_token = get_config().get_s3_config().encryption_token;
|
||||||
auto encryption_token = cfg.encryption_token;
|
|
||||||
auto is_encrypted = not encryption_token.empty();
|
auto is_encrypted = not encryption_token.empty();
|
||||||
|
|
||||||
auto path_parts = utils::string::split(api_path, '/', false);
|
auto path_parts = utils::string::split(api_path, '/', false);
|
||||||
@ -191,43 +187,12 @@ auto s3_provider::create_path_directories(
|
|||||||
cur_path = utils::path::create_api_path(
|
cur_path = utils::path::create_api_path(
|
||||||
utils::path::combine(cur_path, {path_parts.at(idx)}));
|
utils::path::combine(cur_path, {path_parts.at(idx)}));
|
||||||
|
|
||||||
auto exists{false};
|
|
||||||
auto res = is_directory(cur_path, exists);
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not exists) {
|
|
||||||
curl::requests::http_put_file put_file{};
|
|
||||||
put_file.allow_timeout = true;
|
|
||||||
put_file.aws_service = "aws:amz:" + cfg.region + ":s3";
|
|
||||||
put_file.path = (is_encrypted ? cur_key : cur_path) + '/';
|
|
||||||
|
|
||||||
stop_type stop_requested{false};
|
|
||||||
long response_code{};
|
|
||||||
if (not get_comm().make_request(put_file, response_code,
|
|
||||||
stop_requested)) {
|
|
||||||
utils::error::raise_api_path_error(function_name, cur_path,
|
|
||||||
api_error::comm_error,
|
|
||||||
"failed to create directory object");
|
|
||||||
return api_error::comm_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response_code != http_error_codes::ok) {
|
|
||||||
utils::error::raise_api_path_error(function_name, cur_path,
|
|
||||||
response_code,
|
|
||||||
"failed to create directory object");
|
|
||||||
return api_error::comm_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
res = get_item_meta(cur_path, meta);
|
auto res = get_item_meta(cur_path, meta);
|
||||||
if (res == api_error::item_not_found) {
|
if (res == api_error::item_not_found) {
|
||||||
auto dir = create_api_file(cur_path, cur_key, 0U,
|
auto dir = create_api_file(cur_path, cur_key, 0U,
|
||||||
get_last_modified(true, cur_path));
|
get_last_modified(true, cur_path));
|
||||||
get_api_item_added()(true, dir);
|
get_api_item_added()(true, dir);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,9 +207,9 @@ auto s3_provider::create_path_directories(
|
|||||||
auto s3_provider::decrypt_object_name(std::string &object_name) const
|
auto s3_provider::decrypt_object_name(std::string &object_name) const
|
||||||
-> api_error {
|
-> api_error {
|
||||||
auto parts = utils::string::split(object_name, '/', false);
|
auto parts = utils::string::split(object_name, '/', false);
|
||||||
for (auto &part : parts) {
|
for (auto &&part : parts) {
|
||||||
if (not utils::encryption::decrypt_file_name(
|
if (not utils::encryption::decrypt_file_name(
|
||||||
get_s3_config().encryption_token, part)) {
|
get_config().get_s3_config().encryption_token, part)) {
|
||||||
return api_error::decryption_error;
|
return api_error::decryption_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +223,7 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
std::string key;
|
std::string key;
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
@ -334,7 +299,7 @@ auto s3_provider::get_directory_items_impl(
|
|||||||
const std::string &api_path, directory_item_list &list) const -> api_error {
|
const std::string &api_path, directory_item_list &list) const -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
|
|
||||||
auto ret = api_error::success;
|
auto ret = api_error::success;
|
||||||
@ -439,14 +404,14 @@ auto s3_provider::get_directory_items_impl(
|
|||||||
|
|
||||||
auto node_list =
|
auto node_list =
|
||||||
doc.select_nodes("/ListBucketResult/CommonPrefixes/Prefix");
|
doc.select_nodes("/ListBucketResult/CommonPrefixes/Prefix");
|
||||||
for (const auto &node : node_list) {
|
for (auto &&node : node_list) {
|
||||||
add_directory_item(
|
add_directory_item(
|
||||||
true, node.node().text().as_string(), 0U,
|
true, node.node().text().as_string(), 0U,
|
||||||
[](const directory_item &) -> std::uint64_t { return 0U; });
|
[](const directory_item &) -> std::uint64_t { return 0U; });
|
||||||
}
|
}
|
||||||
|
|
||||||
node_list = doc.select_nodes("/ListBucketResult/Contents");
|
node_list = doc.select_nodes("/ListBucketResult/Contents");
|
||||||
for (const auto &node : node_list) {
|
for (auto &&node : node_list) {
|
||||||
auto child_object_name = utils::path::create_api_path(
|
auto child_object_name = utils::path::create_api_path(
|
||||||
node.node().select_node("Key").node().text().as_string());
|
node.node().select_node("Key").node().text().as_string());
|
||||||
if (child_object_name == utils::path::create_api_path(prefix)) {
|
if (child_object_name == utils::path::create_api_path(prefix)) {
|
||||||
@ -551,7 +516,7 @@ auto s3_provider::get_file_list(api_file_list &list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto node_list = doc.select_nodes("/ListBucketResult/Contents");
|
auto node_list = doc.select_nodes("/ListBucketResult/Contents");
|
||||||
for (const auto &node : node_list) {
|
for (auto &&node : node_list) {
|
||||||
auto object_name =
|
auto object_name =
|
||||||
std::string{node.node().select_node("Key").node().text().as_string()};
|
std::string{node.node().select_node("Key").node().text().as_string()};
|
||||||
auto api_path{object_name};
|
auto api_path{object_name};
|
||||||
@ -559,7 +524,8 @@ auto s3_provider::get_file_list(api_file_list &list,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto is_encrypted = not get_s3_config().encryption_token.empty();
|
auto is_encrypted =
|
||||||
|
not get_config().get_s3_config().encryption_token.empty();
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
auto err = decrypt_object_name(api_path);
|
auto err = decrypt_object_name(api_path);
|
||||||
if (err != api_error::success) {
|
if (err != api_error::success) {
|
||||||
@ -609,7 +575,7 @@ auto s3_provider::get_object_info(
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
is_encrypted = not cfg.encryption_token.empty();
|
is_encrypted = not cfg.encryption_token.empty();
|
||||||
|
|
||||||
std::string key;
|
std::string key;
|
||||||
@ -660,7 +626,7 @@ auto s3_provider::get_object_list(
|
|||||||
std::optional<std::string> token) const -> bool {
|
std::optional<std::string> token) const -> bool {
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.aws_service = "aws:amz:" + get_s3_config().region + ":s3";
|
get.aws_service = "aws:amz:" + get_config().get_s3_config().region + ":s3";
|
||||||
get.path = '/';
|
get.path = '/';
|
||||||
get.query["list-type"] = "2";
|
get.query["list-type"] = "2";
|
||||||
if (delimiter.has_value() && not delimiter.value().empty()) {
|
if (delimiter.has_value() && not delimiter.value().empty()) {
|
||||||
@ -752,7 +718,7 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
std::string key;
|
std::string key;
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
@ -858,7 +824,7 @@ auto s3_provider::remove_directory_impl(const std::string &api_path)
|
|||||||
-> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
|
|
||||||
std::string key;
|
std::string key;
|
||||||
@ -900,7 +866,7 @@ auto s3_provider::remove_directory_impl(const std::string &api_path)
|
|||||||
auto s3_provider::remove_file_impl(const std::string &api_path) -> api_error {
|
auto s3_provider::remove_file_impl(const std::string &api_path) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
|
|
||||||
std::string key;
|
std::string key;
|
||||||
@ -948,8 +914,6 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */,
|
|||||||
auto s3_provider::start(api_item_added_callback api_item_added,
|
auto s3_provider::start(api_item_added_callback api_item_added,
|
||||||
i_file_manager *mgr) -> bool {
|
i_file_manager *mgr) -> bool {
|
||||||
event_system::instance().raise<service_started>("s3_provider");
|
event_system::instance().raise<service_started>("s3_provider");
|
||||||
s3_config_ = get_config().get_s3_config();
|
|
||||||
get_comm().enable_s3_path_style(s3_config_.use_path_style);
|
|
||||||
return base_provider::start(api_item_added, mgr);
|
return base_provider::start(api_item_added, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,7 +937,7 @@ auto s3_provider::upload_file_impl(const std::string &api_path,
|
|||||||
file_size = opt_size.value();
|
file_size = opt_size.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &cfg = get_s3_config();
|
auto cfg = get_config().get_s3_config();
|
||||||
auto is_encrypted = not cfg.encryption_token.empty();
|
auto is_encrypted = not cfg.encryption_token.empty();
|
||||||
|
|
||||||
std::string key;
|
std::string key;
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
[[nodiscard]] auto get_bucket(const repertory::sia_config &cfg) -> std::string {
|
[[nodiscard]] auto get_bucket(repertory::sia_config cfg) -> std::string {
|
||||||
|
repertory::utils::string::trim(cfg.bucket);
|
||||||
if (cfg.bucket.empty()) {
|
if (cfg.bucket.empty()) {
|
||||||
return "default";
|
return "default";
|
||||||
}
|
}
|
||||||
@ -67,7 +68,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
|
|||||||
curl::requests::http_put_file put_file{};
|
curl::requests::http_put_file put_file{};
|
||||||
put_file.allow_timeout = true;
|
put_file.allow_timeout = true;
|
||||||
put_file.path = "/api/worker/objects" + api_path + "/";
|
put_file.path = "/api/worker/objects" + api_path + "/";
|
||||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
put_file.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
long response_code{};
|
long response_code{};
|
||||||
stop_type stop_requested{};
|
stop_type stop_requested{};
|
||||||
@ -99,7 +100,7 @@ auto sia_provider::get_directory_item_count(const std::string &api_path) const
|
|||||||
|
|
||||||
std::uint64_t item_count{};
|
std::uint64_t item_count{};
|
||||||
if (object_list.contains("entries")) {
|
if (object_list.contains("entries")) {
|
||||||
for (const auto &entry : object_list.at("entries")) {
|
for (auto &&entry : object_list.at("entries")) {
|
||||||
try {
|
try {
|
||||||
auto name = entry.at("name").get<std::string>();
|
auto name = entry.at("name").get<std::string>();
|
||||||
auto entry_api_path = utils::path::create_api_path(name);
|
auto entry_api_path = utils::path::create_api_path(name);
|
||||||
@ -136,7 +137,7 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (object_list.contains("entries")) {
|
if (object_list.contains("entries")) {
|
||||||
for (const auto &entry : object_list.at("entries")) {
|
for (auto &&entry : object_list.at("entries")) {
|
||||||
try {
|
try {
|
||||||
auto name = entry.at("name").get<std::string>();
|
auto name = entry.at("name").get<std::string>();
|
||||||
auto entry_api_path = utils::path::create_api_path(name);
|
auto entry_api_path = utils::path::create_api_path(name);
|
||||||
@ -227,7 +228,7 @@ auto sia_provider::get_file_list(api_file_list &list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (object_list.contains("entries")) {
|
if (object_list.contains("entries")) {
|
||||||
for (const auto &entry : object_list.at("entries")) {
|
for (auto &&entry : object_list.at("entries")) {
|
||||||
auto name = entry.at("name").get<std::string>();
|
auto name = entry.at("name").get<std::string>();
|
||||||
auto entry_api_path = utils::path::create_api_path(name);
|
auto entry_api_path = utils::path::create_api_path(name);
|
||||||
|
|
||||||
@ -288,7 +289,7 @@ auto sia_provider::get_object_info(const std::string &api_path,
|
|||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/bus/objects" + api_path;
|
get.path = "/api/bus/objects" + api_path;
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
get.response_handler = [&object_info](const data_buffer &data,
|
get.response_handler = [&object_info](const data_buffer &data,
|
||||||
long response_code) {
|
long response_code) {
|
||||||
@ -329,7 +330,7 @@ auto sia_provider::get_object_list(const std::string &api_path,
|
|||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/bus/objects" + api_path + "/";
|
get.path = "/api/bus/objects" + api_path + "/";
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
get.response_handler = [&object_list](const data_buffer &data,
|
get.response_handler = [&object_list](const data_buffer &data,
|
||||||
long response_code) {
|
long response_code) {
|
||||||
@ -363,7 +364,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t {
|
|||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/autopilot/config";
|
get.path = "/api/autopilot/config";
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
json config_data{};
|
json config_data{};
|
||||||
get.response_handler = [&config_data](const data_buffer &data,
|
get.response_handler = [&config_data](const data_buffer &data,
|
||||||
@ -464,7 +465,7 @@ auto sia_provider::is_online() const -> bool {
|
|||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/bus/consensus/state";
|
get.path = "/api/bus/consensus/state";
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
json state_data{};
|
json state_data{};
|
||||||
get.response_handler = [&state_data](const data_buffer &data,
|
get.response_handler = [&state_data](const data_buffer &data,
|
||||||
@ -505,7 +506,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
|
|||||||
|
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.path = "/api/worker/objects" + api_path;
|
get.path = "/api/worker/objects" + api_path;
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
get.range = {{
|
get.range = {{
|
||||||
offset,
|
offset,
|
||||||
offset + size - 1U,
|
offset + size - 1U,
|
||||||
@ -560,7 +561,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path)
|
|||||||
curl::requests::http_delete del{};
|
curl::requests::http_delete del{};
|
||||||
del.allow_timeout = true;
|
del.allow_timeout = true;
|
||||||
del.path = "/api/bus/objects" + api_path + "/";
|
del.path = "/api/bus/objects" + api_path + "/";
|
||||||
del.query["bucket"] = get_bucket(get_sia_config());
|
del.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
long response_code{};
|
long response_code{};
|
||||||
stop_type stop_requested{};
|
stop_type stop_requested{};
|
||||||
@ -586,7 +587,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error {
|
|||||||
curl::requests::http_delete del{};
|
curl::requests::http_delete del{};
|
||||||
del.allow_timeout = true;
|
del.allow_timeout = true;
|
||||||
del.path = "/api/bus/objects" + api_path;
|
del.path = "/api/bus/objects" + api_path;
|
||||||
del.query["bucket"] = get_bucket(get_sia_config());
|
del.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
long response_code{};
|
long response_code{};
|
||||||
stop_type stop_requested{};
|
stop_type stop_requested{};
|
||||||
@ -618,7 +619,7 @@ auto sia_provider::rename_file(const std::string &from_api_path,
|
|||||||
{"mode", "single"},
|
{"mode", "single"},
|
||||||
});
|
});
|
||||||
post.path = "/api/bus/objects/rename";
|
post.path = "/api/bus/objects/rename";
|
||||||
post.query["bucket"] = get_bucket(get_sia_config());
|
post.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
|
|
||||||
long response_code{};
|
long response_code{};
|
||||||
stop_type stop_requested{};
|
stop_type stop_requested{};
|
||||||
@ -643,7 +644,6 @@ auto sia_provider::rename_file(const std::string &from_api_path,
|
|||||||
auto sia_provider::start(api_item_added_callback api_item_added,
|
auto sia_provider::start(api_item_added_callback api_item_added,
|
||||||
i_file_manager *mgr) -> bool {
|
i_file_manager *mgr) -> bool {
|
||||||
event_system::instance().raise<service_started>("sia_provider");
|
event_system::instance().raise<service_started>("sia_provider");
|
||||||
sia_config_ = get_config().get_sia_config();
|
|
||||||
return base_provider::start(api_item_added, mgr);
|
return base_provider::start(api_item_added, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,7 +660,7 @@ auto sia_provider::upload_file_impl(const std::string &api_path,
|
|||||||
|
|
||||||
curl::requests::http_put_file put_file{};
|
curl::requests::http_put_file put_file{};
|
||||||
put_file.path = "/api/worker/objects" + api_path;
|
put_file.path = "/api/worker/objects" + api_path;
|
||||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
put_file.query["bucket"] = get_bucket(get_config().get_sia_config());
|
||||||
put_file.source_path = source_path;
|
put_file.source_path = source_path;
|
||||||
|
|
||||||
long response_code{};
|
long response_code{};
|
||||||
|
@ -22,14 +22,10 @@
|
|||||||
#include "rpc/server/full_server.hpp"
|
#include "rpc/server/full_server.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "file_manager/cache_size_mgr.hpp"
|
|
||||||
#include "file_manager/i_file_manager.hpp"
|
#include "file_manager/i_file_manager.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "types/rpc.hpp"
|
#include "types/rpc.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
|
|
||||||
@ -40,20 +36,25 @@ full_server::full_server(app_config &config, i_provider &provider,
|
|||||||
|
|
||||||
void full_server::handle_get_directory_items(const httplib::Request &req,
|
void full_server::handle_get_directory_items(const httplib::Request &req,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
auto api_path = utils::path::create_api_path(req.get_param_value("api_path"));
|
const auto api_path =
|
||||||
res.set_content(json({
|
utils::path::create_api_path(req.get_param_value("api_path"));
|
||||||
{"items", fm_.get_directory_items(api_path)},
|
const auto list = fm_.get_directory_items(api_path);
|
||||||
})
|
|
||||||
.dump(),
|
json items = {{"items", std::vector<json>()}};
|
||||||
"application/json");
|
for (const auto &item : list) {
|
||||||
|
items["items"].emplace_back(item.to_json());
|
||||||
|
}
|
||||||
|
res.set_content(items.dump(), "application/json");
|
||||||
res.status = 200;
|
res.status = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
void full_server::handle_get_drive_information(const httplib::Request & /*req*/,
|
void full_server::handle_get_drive_information(const httplib::Request & /*req*/,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
|
auto dir_size =
|
||||||
|
utils::file::directory(get_config().get_cache_directory()).size();
|
||||||
res.set_content(
|
res.set_content(
|
||||||
json({
|
json({
|
||||||
{"cache_space_used", cache_size_mgr::instance().size()},
|
{"cache_space_used", dir_size},
|
||||||
{"drive_space_total", provider_.get_total_drive_space()},
|
{"drive_space_total", provider_.get_total_drive_space()},
|
||||||
{"drive_space_used", provider_.get_used_drive_space()},
|
{"drive_space_used", provider_.get_used_drive_space()},
|
||||||
{"item_count", provider_.get_total_item_count()},
|
{"item_count", provider_.get_total_item_count()},
|
||||||
@ -65,9 +66,9 @@ void full_server::handle_get_drive_information(const httplib::Request & /*req*/,
|
|||||||
|
|
||||||
void full_server::handle_get_open_files(const httplib::Request & /*req*/,
|
void full_server::handle_get_open_files(const httplib::Request & /*req*/,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
auto list = fm_.get_open_files();
|
const auto list = fm_.get_open_files();
|
||||||
|
|
||||||
json open_files;
|
json open_files = {{"items", std::vector<json>()}};
|
||||||
for (const auto &kv : list) {
|
for (const auto &kv : list) {
|
||||||
open_files["items"].emplace_back(json({
|
open_files["items"].emplace_back(json({
|
||||||
{"path", kv.first},
|
{"path", kv.first},
|
||||||
@ -80,10 +81,7 @@ void full_server::handle_get_open_files(const httplib::Request & /*req*/,
|
|||||||
|
|
||||||
void full_server::handle_get_pinned_files(const httplib::Request & /*req*/,
|
void full_server::handle_get_pinned_files(const httplib::Request & /*req*/,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
res.set_content(json({
|
res.set_content(json({{"items", provider_.get_pinned_files()}}).dump(),
|
||||||
{"items", provider_.get_pinned_files()},
|
|
||||||
})
|
|
||||||
.dump(),
|
|
||||||
"application/json");
|
"application/json");
|
||||||
res.status = 200;
|
res.status = 200;
|
||||||
}
|
}
|
||||||
@ -92,10 +90,11 @@ void full_server::handle_get_pinned_status(const httplib::Request &req,
|
|||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto api_path = utils::path::create_api_path(req.get_param_value("api_path"));
|
const auto api_path =
|
||||||
|
utils::path::create_api_path(req.get_param_value("api_path"));
|
||||||
|
|
||||||
std::string pinned;
|
std::string pinned;
|
||||||
auto result = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
const auto result = provider_.get_item_meta(api_path, META_PINNED, pinned);
|
||||||
if (result != api_error::success) {
|
if (result != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, result,
|
utils::error::raise_api_path_error(function_name, api_path, result,
|
||||||
"failed to get pinned status");
|
"failed to get pinned status");
|
||||||
@ -104,10 +103,8 @@ void full_server::handle_get_pinned_status(const httplib::Request &req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.set_content(
|
res.set_content(
|
||||||
json({
|
json(
|
||||||
{"pinned",
|
{{"pinned", pinned.empty() ? false : utils::string::to_bool(pinned)}})
|
||||||
pinned.empty() ? false : utils::string::to_bool(pinned)},
|
|
||||||
})
|
|
||||||
.dump(),
|
.dump(),
|
||||||
"application/json");
|
"application/json");
|
||||||
res.status = 200;
|
res.status = 200;
|
||||||
@ -117,7 +114,8 @@ void full_server::handle_pin_file(const httplib::Request &req,
|
|||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto api_path = utils::path::create_api_path(req.get_param_value("api_path"));
|
const auto api_path =
|
||||||
|
utils::path::create_api_path(req.get_param_value("api_path"));
|
||||||
|
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto result = provider_.is_file(api_path, exists);
|
auto result = provider_.is_file(api_path, exists);
|
||||||
@ -145,7 +143,8 @@ void full_server::handle_unpin_file(const httplib::Request &req,
|
|||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto api_path = utils::path::create_api_path(req.get_param_value("api_path"));
|
const auto api_path =
|
||||||
|
utils::path::create_api_path(req.get_param_value("api_path"));
|
||||||
|
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto result = provider_.is_file(api_path, exists);
|
auto result = provider_.is_file(api_path, exists);
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
#include "rpc/server/server.hpp"
|
#include "rpc/server/server.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "utils/base64.hpp"
|
#include "utils/base64.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
|
||||||
|
@ -25,42 +25,18 @@
|
|||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto database_type_from_string(std::string type,
|
|
||||||
database_type default_type) -> database_type {
|
|
||||||
type = utils::string::to_lower(utils::string::trim(type));
|
|
||||||
if (type == "rocksdb") {
|
|
||||||
return database_type::rocksdb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == "sqlite") {
|
|
||||||
return database_type::sqlite;
|
|
||||||
}
|
|
||||||
|
|
||||||
return default_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto database_type_to_string(const database_type &type) -> std::string {
|
|
||||||
switch (type) {
|
|
||||||
case database_type::rocksdb:
|
|
||||||
return "rocksdb";
|
|
||||||
case database_type::sqlite:
|
|
||||||
return "sqlite";
|
|
||||||
default:
|
|
||||||
return "rocksdb";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto download_type_from_string(std::string type,
|
auto download_type_from_string(std::string type,
|
||||||
download_type default_type) -> download_type {
|
const download_type &default_type)
|
||||||
|
-> download_type {
|
||||||
type = utils::string::to_lower(utils::string::trim(type));
|
type = utils::string::to_lower(utils::string::trim(type));
|
||||||
if (type == "default") {
|
|
||||||
return download_type::default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == "direct") {
|
if (type == "direct") {
|
||||||
return download_type::direct;
|
return download_type::direct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "fallback") {
|
||||||
|
return download_type::fallback;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == "ring_buffer") {
|
if (type == "ring_buffer") {
|
||||||
return download_type::ring_buffer;
|
return download_type::ring_buffer;
|
||||||
}
|
}
|
||||||
@ -70,14 +46,14 @@ auto download_type_from_string(std::string type,
|
|||||||
|
|
||||||
auto download_type_to_string(const download_type &type) -> std::string {
|
auto download_type_to_string(const download_type &type) -> std::string {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case download_type::default_:
|
|
||||||
return "default";
|
|
||||||
case download_type::direct:
|
case download_type::direct:
|
||||||
return "direct";
|
return "direct";
|
||||||
|
case download_type::fallback:
|
||||||
|
return "fallback";
|
||||||
case download_type::ring_buffer:
|
case download_type::ring_buffer:
|
||||||
return "ring_buffer";
|
return "ring_buffer";
|
||||||
default:
|
default:
|
||||||
return "default";
|
return "fallback";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +63,6 @@ static const std::unordered_map<api_error, std::string> LOOKUP = {
|
|||||||
{api_error::bad_address, "bad_address"},
|
{api_error::bad_address, "bad_address"},
|
||||||
{api_error::buffer_overflow, "buffer_overflow"},
|
{api_error::buffer_overflow, "buffer_overflow"},
|
||||||
{api_error::buffer_too_small, "buffer_too_small"},
|
{api_error::buffer_too_small, "buffer_too_small"},
|
||||||
{api_error::cache_not_initialized, "cache_not_initialized"},
|
|
||||||
{api_error::comm_error, "comm_error"},
|
{api_error::comm_error, "comm_error"},
|
||||||
{api_error::decryption_error, "decryption_error"},
|
{api_error::decryption_error, "decryption_error"},
|
||||||
{api_error::directory_end_of_files, "directory_end_of_files"},
|
{api_error::directory_end_of_files, "directory_end_of_files"},
|
||||||
@ -106,7 +81,6 @@ static const std::unordered_map<api_error, std::string> LOOKUP = {
|
|||||||
{api_error::invalid_handle, "invalid_handle"},
|
{api_error::invalid_handle, "invalid_handle"},
|
||||||
{api_error::invalid_operation, "invalid_operation"},
|
{api_error::invalid_operation, "invalid_operation"},
|
||||||
{api_error::invalid_ring_buffer_multiple, "invalid_ring_buffer_multiple"},
|
{api_error::invalid_ring_buffer_multiple, "invalid_ring_buffer_multiple"},
|
||||||
{api_error::invalid_ring_buffer_position, "invalid_ring_buffer_position"},
|
|
||||||
{api_error::invalid_ring_buffer_size, "invalid_ring_buffer_size"},
|
{api_error::invalid_ring_buffer_size, "invalid_ring_buffer_size"},
|
||||||
{api_error::invalid_version, "invalid_version"},
|
{api_error::invalid_version, "invalid_version"},
|
||||||
{api_error::item_exists, "item_exists"},
|
{api_error::item_exists, "item_exists"},
|
||||||
|
@ -45,15 +45,15 @@ void get_api_authentication_data(std::string &user, std::string &password,
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (user.empty() && password.empty()) {
|
if (user.empty() && password.empty()) {
|
||||||
password = data[JSON_API_AUTH].get<std::string>();
|
password = data["ApiAuth"].get<std::string>();
|
||||||
user = data[JSON_API_USER].get<std::string>();
|
user = data["ApiUser"].get<std::string>();
|
||||||
}
|
}
|
||||||
port = data[JSON_API_PORT].get<std::uint16_t>();
|
port = data["ApiPort"].get<std::uint16_t>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider_type_from_args(std::vector<const char *> args)
|
[[nodiscard]] auto
|
||||||
-> provider_type {
|
get_provider_type_from_args(std::vector<const char *> args) -> provider_type {
|
||||||
if (has_option(args, options::s3_option)) {
|
if (has_option(args, options::s3_option)) {
|
||||||
return provider_type::s3;
|
return provider_type::s3;
|
||||||
}
|
}
|
||||||
@ -67,8 +67,8 @@ void get_api_authentication_data(std::string &user, std::string &password,
|
|||||||
return provider_type::sia;
|
return provider_type::sia;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto has_option(std::vector<const char *> args, const std::string &option_name)
|
auto has_option(std::vector<const char *> args,
|
||||||
-> bool {
|
const std::string &option_name) -> bool {
|
||||||
return std::find_if(args.begin(), args.end(),
|
return std::find_if(args.begin(), args.end(),
|
||||||
[&option_name](const auto &value) -> bool {
|
[&option_name](const auto &value) -> bool {
|
||||||
return option_name == value;
|
return option_name == value;
|
||||||
@ -80,8 +80,8 @@ auto has_option(std::vector<const char *> args, const option &opt) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto parse_option(std::vector<const char *> args,
|
auto parse_option(std::vector<const char *> args,
|
||||||
const std::string &option_name, std::uint8_t count)
|
const std::string &option_name,
|
||||||
-> std::vector<std::string> {
|
std::uint8_t count) -> std::vector<std::string> {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
auto found{false};
|
auto found{false};
|
||||||
for (std::size_t i = 0U; not found && (i < args.size()); i++) {
|
for (std::size_t i = 0U; not found && (i < args.size()); i++) {
|
||||||
@ -119,10 +119,9 @@ auto parse_string_option(std::vector<const char *> args, const option &opt,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parse_drive_options(std::vector<const char *> args,
|
auto parse_drive_options(
|
||||||
[[maybe_unused]] provider_type &prov,
|
std::vector<const char *> args, [[maybe_unused]] provider_type &prov,
|
||||||
[[maybe_unused]] std::string &data_directory)
|
[[maybe_unused]] std::string &data_directory) -> std::vector<std::string> {
|
||||||
-> std::vector<std::string> {
|
|
||||||
// Strip out options from command line
|
// Strip out options from command line
|
||||||
const auto &option_list = options::option_list;
|
const auto &option_list = options::option_list;
|
||||||
std::vector<std::string> drive_args;
|
std::vector<std::string> drive_args;
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/events.hpp"
|
|
||||||
#include "utils/tasks.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
polling polling::instance_;
|
polling polling::instance_;
|
||||||
@ -34,34 +31,31 @@ void polling::frequency_thread(
|
|||||||
while (not stop_requested_) {
|
while (not stop_requested_) {
|
||||||
unique_mutex_lock lock(mutex_);
|
unique_mutex_lock lock(mutex_);
|
||||||
auto futures = std::accumulate(
|
auto futures = std::accumulate(
|
||||||
items_.begin(), items_.end(), std::deque<tasks::task_ptr>{},
|
items_.begin(), items_.end(), std::deque<std::future<void>>{},
|
||||||
[this, &freq](auto &&list, auto &&item) {
|
[this, &freq](auto &&list, auto &&item) {
|
||||||
if (item.second.freq != freq) {
|
if (item.second.freq != freq) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = tasks::instance().schedule({
|
list.emplace_back(
|
||||||
[this, &freq, item](auto &&task_stopped) {
|
std::async(std::launch::async, [this, &freq, item]() -> void {
|
||||||
if (config_->get_event_level() == event_level::trace ||
|
if (config_->get_event_level() == event_level::trace ||
|
||||||
freq != frequency::second) {
|
freq != frequency::second) {
|
||||||
event_system::instance().raise<polling_item_begin>(
|
event_system::instance().raise<polling_item_begin>(
|
||||||
item.first);
|
item.first);
|
||||||
}
|
}
|
||||||
item.second.action(task_stopped);
|
item.second.action(stop_requested_);
|
||||||
if (config_->get_event_level() == event_level::trace ||
|
if (config_->get_event_level() == event_level::trace ||
|
||||||
freq != frequency::second) {
|
freq != frequency::second) {
|
||||||
event_system::instance().raise<polling_item_end>(item.first);
|
event_system::instance().raise<polling_item_end>(item.first);
|
||||||
}
|
}
|
||||||
},
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
list.emplace_back(future);
|
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
while (not futures.empty()) {
|
while (not futures.empty()) {
|
||||||
futures.front()->wait();
|
futures.front().wait();
|
||||||
futures.pop_front();
|
futures.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +88,6 @@ void polling::start(app_config *config) {
|
|||||||
config_ = config;
|
config_ = config;
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
|
|
||||||
tasks::instance().start(config);
|
|
||||||
|
|
||||||
auto idx{0U};
|
auto idx{0U};
|
||||||
frequency_threads_.at(idx++) =
|
frequency_threads_.at(idx++) =
|
||||||
std::make_unique<std::thread>([this]() -> void {
|
std::make_unique<std::thread>([this]() -> void {
|
||||||
@ -105,7 +97,6 @@ void polling::start(app_config *config) {
|
|||||||
},
|
},
|
||||||
frequency::high);
|
frequency::high);
|
||||||
});
|
});
|
||||||
|
|
||||||
frequency_threads_.at(idx++) =
|
frequency_threads_.at(idx++) =
|
||||||
std::make_unique<std::thread>([this]() -> void {
|
std::make_unique<std::thread>([this]() -> void {
|
||||||
this->frequency_thread(
|
this->frequency_thread(
|
||||||
@ -114,16 +105,6 @@ void polling::start(app_config *config) {
|
|||||||
},
|
},
|
||||||
frequency::low);
|
frequency::low);
|
||||||
});
|
});
|
||||||
|
|
||||||
frequency_threads_.at(idx++) =
|
|
||||||
std::make_unique<std::thread>([this]() -> void {
|
|
||||||
this->frequency_thread(
|
|
||||||
[this]() -> std::uint32_t {
|
|
||||||
return config_->get_med_frequency_interval_secs();
|
|
||||||
},
|
|
||||||
frequency::medium);
|
|
||||||
});
|
|
||||||
|
|
||||||
frequency_threads_.at(idx++) =
|
frequency_threads_.at(idx++) =
|
||||||
std::make_unique<std::thread>([this]() -> void {
|
std::make_unique<std::thread>([this]() -> void {
|
||||||
this->frequency_thread([]() -> std::uint32_t { return 1U; },
|
this->frequency_thread([]() -> std::uint32_t { return 1U; },
|
||||||
@ -140,8 +121,6 @@ void polling::stop() {
|
|||||||
event_system::instance().raise<service_shutdown_begin>("polling");
|
event_system::instance().raise<service_shutdown_begin>("polling");
|
||||||
stop_requested_ = true;
|
stop_requested_ = true;
|
||||||
|
|
||||||
tasks::instance().stop();
|
|
||||||
|
|
||||||
unique_mutex_lock thread_lock(mutex_);
|
unique_mutex_lock thread_lock(mutex_);
|
||||||
notify_.notify_all();
|
notify_.notify_all();
|
||||||
thread_lock.unlock();
|
thread_lock.unlock();
|
||||||
|
@ -22,51 +22,21 @@
|
|||||||
#include "utils/tasks.hpp"
|
#include "utils/tasks.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
tasks tasks::instance_;
|
tasks tasks::instance_;
|
||||||
|
|
||||||
void tasks::task_wait::set_result(bool result) {
|
void tasks::schedule(task_item task) {
|
||||||
unique_mutex_lock lock(mtx);
|
|
||||||
if (complete) {
|
|
||||||
notify.notify_all();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
complete = true;
|
|
||||||
success = result;
|
|
||||||
notify.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tasks::task_wait::wait() const -> bool {
|
|
||||||
unique_mutex_lock lock(mtx);
|
|
||||||
while (not complete) {
|
|
||||||
notify.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tasks::schedule(task item) -> task_ptr {
|
|
||||||
++count_;
|
|
||||||
while (not stop_requested_ && (count_ >= task_threads_.size())) {
|
|
||||||
std::this_thread::sleep_for(
|
|
||||||
std::chrono::milliseconds(config_->get_task_wait_ms()));
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduled_task runnable{item};
|
|
||||||
|
|
||||||
unique_mutex_lock lock(mutex_);
|
unique_mutex_lock lock(mutex_);
|
||||||
if (stop_requested_) {
|
while (not stop_requested_ && tasks_.size() > (task_threads_.size() * 4U)) {
|
||||||
runnable.wait->set_result(false);
|
notify_.wait(lock);
|
||||||
notify_.notify_all();
|
}
|
||||||
return runnable.wait;
|
|
||||||
|
if (not stop_requested_) {
|
||||||
|
tasks_.push_back(std::move(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks_.push_back(runnable);
|
|
||||||
notify_.notify_all();
|
notify_.notify_all();
|
||||||
return runnable.wait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tasks::start(app_config *config) {
|
void tasks::start(app_config *config) {
|
||||||
@ -76,10 +46,7 @@ void tasks::start(app_config *config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_ = config;
|
config_ = config;
|
||||||
count_ = 0U;
|
|
||||||
stop_requested_ = false;
|
stop_requested_ = false;
|
||||||
tasks_.clear();
|
|
||||||
|
|
||||||
for (std::uint32_t idx = 0U; idx < std::thread::hardware_concurrency();
|
for (std::uint32_t idx = 0U; idx < std::thread::hardware_concurrency();
|
||||||
++idx) {
|
++idx) {
|
||||||
task_threads_.emplace_back(
|
task_threads_.emplace_back(
|
||||||
@ -100,11 +67,6 @@ void tasks::stop() {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
task_threads_.clear();
|
task_threads_.clear();
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
tasks_.clear();
|
|
||||||
notify_.notify_all();
|
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tasks::task_thread() {
|
void tasks::task_thread() {
|
||||||
@ -122,36 +84,33 @@ void tasks::task_thread() {
|
|||||||
while (not stop_requested_) {
|
while (not stop_requested_) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|
||||||
while (not stop_requested_ && tasks_.empty()) {
|
|
||||||
notify_.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop_requested_) {
|
if (stop_requested_) {
|
||||||
release();
|
release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tasks_.empty()) {
|
||||||
|
notify_.wait(lock);
|
||||||
|
if (stop_requested_) {
|
||||||
|
release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tasks_.empty()) {
|
if (tasks_.empty()) {
|
||||||
release();
|
release();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto runnable = tasks_.front();
|
auto task = tasks_.front();
|
||||||
tasks_.pop_front();
|
tasks_.pop_front();
|
||||||
release();
|
release();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runnable.item.action(stop_requested_);
|
task.action(stop_requested_);
|
||||||
runnable.wait->set_result(true);
|
|
||||||
|
|
||||||
--count_;
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
runnable.wait->set_result(false);
|
|
||||||
utils::error::raise_error(function_name, e, "failed to execute task");
|
utils::error::raise_error(function_name, e, "failed to execute task");
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -52,8 +52,6 @@ auto from_api_error(const api_error &err) -> int {
|
|||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
case api_error::file_in_use:
|
case api_error::file_in_use:
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
case api_error::invalid_handle:
|
|
||||||
return -EBADF;
|
|
||||||
case api_error::invalid_operation:
|
case api_error::invalid_operation:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case api_error::item_not_found:
|
case api_error::item_not_found:
|
||||||
|
@ -22,11 +22,7 @@
|
|||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
|
||||||
#include "utils/file.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory::utils {
|
namespace repertory::utils {
|
||||||
@ -48,42 +44,6 @@ void calculate_allocation_size(bool directory, std::uint64_t file_size,
|
|||||||
allocation_meta_size = std::to_string(allocation_size);
|
allocation_meta_size = std::to_string(allocation_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create_rocksdb(
|
|
||||||
const app_config &cfg, const std::string &name,
|
|
||||||
const std::vector<rocksdb::ColumnFamilyDescriptor> &families,
|
|
||||||
std::vector<rocksdb::ColumnFamilyHandle *> &handles,
|
|
||||||
bool clear) -> std::unique_ptr<rocksdb::TransactionDB> {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
auto db_dir = utils::path::combine(cfg.get_data_directory(), {"db"});
|
|
||||||
if (not utils::file::directory{db_dir}.create_directory()) {
|
|
||||||
throw startup_exception(
|
|
||||||
fmt::format("failed to create db directory|", db_dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto path = utils::path::combine(db_dir, {name});
|
|
||||||
if (clear && not utils::file::directory{path}.remove_recursively()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"failed to remove " + name + " db|" + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
rocksdb::Options options{};
|
|
||||||
options.create_if_missing = true;
|
|
||||||
options.create_missing_column_families = true;
|
|
||||||
options.db_log_dir = cfg.get_log_directory();
|
|
||||||
options.keep_log_file_num = 10;
|
|
||||||
|
|
||||||
rocksdb::TransactionDB *ptr{};
|
|
||||||
auto status = rocksdb::TransactionDB::Open(
|
|
||||||
options, rocksdb::TransactionDBOptions{}, path, families, &handles, &ptr);
|
|
||||||
if (not status.ok()) {
|
|
||||||
throw startup_exception(fmt::format("failed to open rocksdb|path{}|error{}",
|
|
||||||
path, status.ToString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::unique_ptr<rocksdb::TransactionDB>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto create_volume_label(const provider_type &prov) -> std::string {
|
auto create_volume_label(const provider_type &prov) -> std::string {
|
||||||
return "repertory_" + app_config::get_provider_name(prov);
|
return "repertory_" + app_config::get_provider_name(prov);
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,11 @@ mount(std::vector<const char *> args, std::string data_directory,
|
|||||||
if (generate_config) {
|
if (generate_config) {
|
||||||
app_config config(prov, data_directory);
|
app_config config(prov, data_directory);
|
||||||
if (prov == provider_type::remote) {
|
if (prov == provider_type::remote) {
|
||||||
auto cfg = config.get_remote_config();
|
config.set_enable_remote_mount(false);
|
||||||
cfg.host_name_or_ip = remote_host;
|
config.set_is_remote_mount(true);
|
||||||
cfg.api_port = remote_port;
|
config.set_remote_host_name_or_ip(remote_host);
|
||||||
config.set_remote_config(cfg);
|
config.set_remote_port(remote_port);
|
||||||
|
config.save();
|
||||||
} else if (prov == provider_type::sia &&
|
} else if (prov == provider_type::sia &&
|
||||||
config.get_sia_config().bucket.empty()) {
|
config.get_sia_config().bucket.empty()) {
|
||||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||||
@ -127,12 +128,12 @@ mount(std::vector<const char *> args, std::string data_directory,
|
|||||||
if (prov == provider_type::remote) {
|
if (prov == provider_type::remote) {
|
||||||
std::uint16_t port{0U};
|
std::uint16_t port{0U};
|
||||||
if (utils::get_next_available_port(config.get_api_port(), port)) {
|
if (utils::get_next_available_port(config.get_api_port(), port)) {
|
||||||
auto cfg = config.get_remote_config();
|
config.set_remote_host_name_or_ip(remote_host);
|
||||||
cfg.host_name_or_ip = remote_host;
|
config.set_remote_port(remote_port);
|
||||||
cfg.api_port = remote_port;
|
|
||||||
config.set_remote_config(cfg);
|
|
||||||
config.set_api_port(port);
|
config.set_api_port(port);
|
||||||
|
config.set_is_remote_mount(true);
|
||||||
|
config.set_enable_remote_mount(false);
|
||||||
|
config.save();
|
||||||
try {
|
try {
|
||||||
remote_drive drive(
|
remote_drive drive(
|
||||||
config,
|
config,
|
||||||
@ -160,6 +161,8 @@ mount(std::vector<const char *> args, std::string data_directory,
|
|||||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.set_is_remote_mount(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto provider = create_provider(prov, config);
|
auto provider = create_provider(prov, config);
|
||||||
repertory_drive drive(config, lock, *provider);
|
repertory_drive drive(config, lock, *provider);
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP
|
|
||||||
#define REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP
|
|
||||||
|
|
||||||
#include "test_common.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "db/impl/rdb_file_db.hpp"
|
|
||||||
#include "db/impl/sqlite_file_db.hpp"
|
|
||||||
#include "events/consumers/console_consumer.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
template <typename db_t> class file_db_test : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
static std::unique_ptr<app_config> config;
|
|
||||||
static console_consumer console_;
|
|
||||||
static std::unique_ptr<db_t> file_db;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void SetUpTestCase() {
|
|
||||||
static std::uint64_t idx{};
|
|
||||||
|
|
||||||
event_system::instance().start();
|
|
||||||
auto cfg_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"file_db_test",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
config = std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
|
||||||
file_db = std::make_unique<db_t>(*config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestCase() {
|
|
||||||
file_db.reset();
|
|
||||||
config.reset();
|
|
||||||
event_system::instance().stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using file_db_types = ::testing::Types<rdb_file_db, sqlite_file_db>;
|
|
||||||
|
|
||||||
template <typename db_t> std::unique_ptr<app_config> file_db_test<db_t>::config;
|
|
||||||
|
|
||||||
template <typename db_t> console_consumer file_db_test<db_t>::console_;
|
|
||||||
|
|
||||||
template <typename db_t> std::unique_ptr<db_t> file_db_test<db_t>::file_db;
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
|
||||||
#define REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
|
||||||
|
|
||||||
#include "test_common.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "db/impl/rdb_file_mgr_db.hpp"
|
|
||||||
#include "db/impl/sqlite_file_mgr_db.hpp"
|
|
||||||
#include "events/consumers/console_consumer.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
template <typename db_t> class file_mgr_db_test : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
static std::unique_ptr<app_config> config;
|
|
||||||
static console_consumer console_;
|
|
||||||
static std::unique_ptr<db_t> file_mgr_db;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void SetUpTestCase() {
|
|
||||||
static std::uint64_t idx{};
|
|
||||||
|
|
||||||
event_system::instance().start();
|
|
||||||
auto cfg_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"file_mgr_db_test",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
config = std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
|
||||||
file_mgr_db = std::make_unique<db_t>(*config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestCase() {
|
|
||||||
file_mgr_db.reset();
|
|
||||||
config.reset();
|
|
||||||
event_system::instance().stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using file_mgr_db_types = ::testing::Types<rdb_file_mgr_db, sqlite_file_mgr_db>;
|
|
||||||
|
|
||||||
template <typename db_t>
|
|
||||||
std::unique_ptr<app_config> file_mgr_db_test<db_t>::config;
|
|
||||||
|
|
||||||
template <typename db_t> console_consumer file_mgr_db_test<db_t>::console_;
|
|
||||||
|
|
||||||
template <typename db_t>
|
|
||||||
std::unique_ptr<db_t> file_mgr_db_test<db_t>::file_mgr_db;
|
|
||||||
} // namespace repertory
|
|
||||||
|
|
||||||
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_FILE_MGR_DB_FIXTURE_HPP
|
|
@ -109,11 +109,8 @@ protected:
|
|||||||
config->set_enable_drive_events(true);
|
config->set_enable_drive_events(true);
|
||||||
config->set_event_level(event_level::trace);
|
config->set_event_level(event_level::trace);
|
||||||
config->set_s3_config(src_cfg.get_s3_config());
|
config->set_s3_config(src_cfg.get_s3_config());
|
||||||
|
config->set_enable_remote_mount(true);
|
||||||
auto r_cfg = config->get_remote_mount();
|
config->set_remote_port(30000U);
|
||||||
r_cfg.enable = true;
|
|
||||||
r_cfg.api_port = 30000U;
|
|
||||||
config->set_remote_mount(r_cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive_args = std::vector<std::string>({
|
drive_args = std::vector<std::string>({
|
||||||
@ -155,11 +152,8 @@ protected:
|
|||||||
config->set_event_level(event_level::trace);
|
config->set_event_level(event_level::trace);
|
||||||
config->set_host_config(src_cfg.get_host_config());
|
config->set_host_config(src_cfg.get_host_config());
|
||||||
config->set_sia_config(src_cfg.get_sia_config());
|
config->set_sia_config(src_cfg.get_sia_config());
|
||||||
|
config->set_enable_remote_mount(true);
|
||||||
auto r_cfg = config->get_remote_mount();
|
config->set_remote_port(30000U);
|
||||||
r_cfg.enable = true;
|
|
||||||
r_cfg.api_port = 30000U;
|
|
||||||
config->set_remote_mount(r_cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive_args = std::vector<std::string>({
|
drive_args = std::vector<std::string>({
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
#include "test_common.hpp"
|
#include "test_common.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "db/impl/rdb_meta_db.hpp"
|
#include "db/rdb_meta_db.hpp"
|
||||||
#include "db/impl/sqlite_meta_db.hpp"
|
#include "db/sqlite_meta_db.hpp"
|
||||||
#include "events/consumers/console_consumer.hpp"
|
#include "events/consumers/console_consumer.hpp"
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
|
|
||||||
|
@ -99,11 +99,8 @@ protected:
|
|||||||
config->set_enable_drive_events(true);
|
config->set_enable_drive_events(true);
|
||||||
config->set_event_level(event_level::trace);
|
config->set_event_level(event_level::trace);
|
||||||
config->set_s3_config(src_cfg.get_s3_config());
|
config->set_s3_config(src_cfg.get_s3_config());
|
||||||
|
config->set_enable_remote_mount(true);
|
||||||
auto r_cfg = config->get_remote_mount();
|
config->set_remote_port(30000U);
|
||||||
r_cfg.enable = true;
|
|
||||||
r_cfg.api_port = 30000U;
|
|
||||||
config->set_remote_mount(r_cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive_args = std::vector<std::string>({
|
drive_args = std::vector<std::string>({
|
||||||
@ -141,11 +138,8 @@ protected:
|
|||||||
config->set_event_level(event_level::trace);
|
config->set_event_level(event_level::trace);
|
||||||
config->set_host_config(src_cfg.get_host_config());
|
config->set_host_config(src_cfg.get_host_config());
|
||||||
config->set_sia_config(src_cfg.get_sia_config());
|
config->set_sia_config(src_cfg.get_sia_config());
|
||||||
|
config->set_enable_remote_mount(true);
|
||||||
auto r_cfg = config->get_remote_mount();
|
config->set_remote_port(30000U);
|
||||||
r_cfg.enable = true;
|
|
||||||
r_cfg.api_port = 30000U;
|
|
||||||
config->set_remote_mount(r_cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive_args = std::vector<std::string>({
|
drive_args = std::vector<std::string>({
|
||||||
|
@ -29,13 +29,6 @@
|
|||||||
namespace repertory {
|
namespace repertory {
|
||||||
class mock_open_file : public virtual i_closeable_open_file {
|
class mock_open_file : public virtual i_closeable_open_file {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD(void, add, (std::uint64_t handle, open_file_data ofd),
|
|
||||||
(override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, can_close, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, close, (), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(std::string, get_api_path, (), (const, override));
|
MOCK_METHOD(std::string, get_api_path, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(std::size_t, get_chunk_size, (), (const, override));
|
MOCK_METHOD(std::size_t, get_chunk_size, (), (const, override));
|
||||||
@ -54,30 +47,14 @@ public:
|
|||||||
|
|
||||||
MOCK_METHOD(boost::dynamic_bitset<>, get_read_state, (), (const, override));
|
MOCK_METHOD(boost::dynamic_bitset<>, get_read_state, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, get_allocated, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(std::vector<std::uint64_t>, get_handles, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD((std::map<std::uint64_t, open_file_data> &), get_open_data, (),
|
|
||||||
(override));
|
|
||||||
|
|
||||||
MOCK_METHOD((const std::map<std::uint64_t, open_file_data> &), get_open_data,
|
|
||||||
(), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, get_read_state, (std::size_t chunk), (const, override));
|
MOCK_METHOD(bool, get_read_state, (std::size_t chunk), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(std::string, get_source_path, (), (const, override));
|
MOCK_METHOD(std::string, get_source_path, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, has_handle, (std::uint64_t handle), (const, override));
|
MOCK_METHOD(bool, has_handle, (std::uint64_t handle), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_complete, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_directory, (), (const, override));
|
MOCK_METHOD(bool, is_directory, (), (const, override));
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_modified, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
|
||||||
|
|
||||||
MOCK_METHOD(api_error, native_operation, (native_operation_callback callback),
|
MOCK_METHOD(api_error, native_operation, (native_operation_callback callback),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
@ -90,10 +67,6 @@ public:
|
|||||||
data_buffer &data),
|
data_buffer &data),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(void, remove_all, (), (override));
|
|
||||||
|
|
||||||
MOCK_METHOD(api_error, resize, (std::uint64_t new_file_size), (override));
|
MOCK_METHOD(api_error, resize, (std::uint64_t new_file_size), (override));
|
||||||
|
|
||||||
MOCK_METHOD(void, set_api_path, (const std::string &api_path), (override));
|
MOCK_METHOD(void, set_api_path, (const std::string &api_path), (override));
|
||||||
@ -102,6 +75,31 @@ public:
|
|||||||
(std::uint64_t write_offset, const data_buffer &data,
|
(std::uint64_t write_offset, const data_buffer &data,
|
||||||
std::size_t &bytes_written),
|
std::size_t &bytes_written),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, add, (std::uint64_t handle, open_file_data ofd),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, can_close, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, close, (), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(std::vector<std::uint64_t>, get_handles, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD((std::map<std::uint64_t, open_file_data> &), get_open_data, (),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD((const std::map<std::uint64_t, open_file_data> &), get_open_data,
|
||||||
|
(), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_complete, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_modified, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, remove_all, (), (override));
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "test_common.hpp"
|
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
TEST(atomic, atomic_primitive) {
|
|
||||||
atomic<std::uint16_t> value;
|
|
||||||
value = 5U;
|
|
||||||
EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
|
|
||||||
EXPECT_EQ(5U, value.load());
|
|
||||||
|
|
||||||
value.store(6U);
|
|
||||||
EXPECT_EQ(6U, static_cast<std::uint16_t>(value));
|
|
||||||
EXPECT_EQ(6U, value.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(atomic, atomic_primitive_equality) {
|
|
||||||
atomic<std::uint16_t> value1{5U};
|
|
||||||
atomic<std::uint16_t> value2{5U};
|
|
||||||
EXPECT_EQ(value1, value1);
|
|
||||||
EXPECT_EQ(value2, value2);
|
|
||||||
EXPECT_EQ(value1, value2);
|
|
||||||
EXPECT_EQ(static_cast<std::uint16_t>(value1), 5U);
|
|
||||||
EXPECT_EQ(static_cast<std::uint16_t>(value2), 5U);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(atomic, atomic_primitive_inequality) {
|
|
||||||
atomic<std::uint16_t> value1{5U};
|
|
||||||
atomic<std::uint16_t> value2{6U};
|
|
||||||
EXPECT_NE(value1, value2);
|
|
||||||
EXPECT_NE(static_cast<std::uint16_t>(value1), 6U);
|
|
||||||
EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(atomic, atomic_struct) {
|
|
||||||
atomic<encrypt_config> value{
|
|
||||||
encrypt_config{
|
|
||||||
.encryption_token = "token",
|
|
||||||
.path = "path",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
auto data = static_cast<encrypt_config>(value);
|
|
||||||
EXPECT_STREQ("token", data.encryption_token.c_str());
|
|
||||||
EXPECT_STREQ("path", data.path.c_str());
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -30,34 +30,172 @@
|
|||||||
namespace repertory {
|
namespace repertory {
|
||||||
class config_test : public ::testing::Test {
|
class config_test : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
console_consumer cs;
|
static console_consumer cs;
|
||||||
|
|
||||||
static std::atomic<std::uint64_t> idx;
|
std::string s3_directory{
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {"config_test", "s3"})};
|
||||||
|
|
||||||
std::string s3_directory;
|
std::string sia_directory{utils::path::combine(test::get_test_output_dir(),
|
||||||
std::string sia_directory;
|
{"config_test", "sia"})};
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
s3_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"config_test",
|
|
||||||
"s3",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
|
|
||||||
sia_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"config_test",
|
|
||||||
"sia",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
|
ASSERT_TRUE(
|
||||||
|
utils::file::directory(
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {"config_test"}))
|
||||||
|
.remove_recursively());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override { event_system::instance().stop(); }
|
void TearDown() override {
|
||||||
|
ASSERT_TRUE(
|
||||||
|
utils::file::directory(
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {"config_test"}))
|
||||||
|
.remove_recursively());
|
||||||
|
event_system::instance().stop();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::atomic<std::uint64_t> config_test::idx{0U};
|
const auto DEFAULT_SIA_CONFIG = "{\n"
|
||||||
|
" \"ApiAuth\": \"\",\n"
|
||||||
|
" \"ApiPort\": 10000,\n"
|
||||||
|
" \"ApiUser\": \"repertory\",\n"
|
||||||
|
" \"ChunkDownloaderTimeoutSeconds\": 30,\n"
|
||||||
|
" \"EnableChunkDownloaderTimeout\": true,\n"
|
||||||
|
" \"EnableCommDurationEvents\": false,\n"
|
||||||
|
" \"EnableDriveEvents\": false,\n"
|
||||||
|
" \"EnableMaxCacheSize\": false,\n"
|
||||||
|
#if defined(_WIN32)
|
||||||
|
" \"EnableMountManager\": false,\n"
|
||||||
|
#endif
|
||||||
|
" \"EventLevel\": \"info\",\n"
|
||||||
|
" \"EvictionDelayMinutes\": 10,\n"
|
||||||
|
" \"EvictionUsesAccessedTime\": false,\n"
|
||||||
|
" \"HighFreqIntervalSeconds\": 30,\n"
|
||||||
|
" \"HostConfig\": {\n"
|
||||||
|
" \"AgentString\": \"Sia-Agent\",\n"
|
||||||
|
" \"ApiPassword\": \"\",\n"
|
||||||
|
" \"ApiPort\": 9980,\n"
|
||||||
|
" \"HostNameOrIp\": \"localhost\",\n"
|
||||||
|
" \"TimeoutMs\": 60000\n"
|
||||||
|
" },\n"
|
||||||
|
" \"LowFreqIntervalSeconds\": 3600,\n"
|
||||||
|
" \"MaxCacheSizeBytes\": 21474836480,\n"
|
||||||
|
" \"MaxUploadCount\": 5,\n"
|
||||||
|
" \"OnlineCheckRetrySeconds\": 60,\n"
|
||||||
|
" \"OrphanedFileRetentionDays\": 15,\n"
|
||||||
|
" \"PreferredDownloadType\": \"fallback\",\n"
|
||||||
|
" \"ReadAheadCount\": 4,\n"
|
||||||
|
" \"RemoteMount\": {\n"
|
||||||
|
" \"EnableRemoteMount\": false,\n"
|
||||||
|
" \"IsRemoteMount\": false,\n"
|
||||||
|
" \"RemoteClientPoolSize\": 10,\n"
|
||||||
|
" \"RemoteHostNameOrIp\": \"\",\n"
|
||||||
|
" \"RemoteMaxConnections\": 20,\n"
|
||||||
|
" \"RemotePort\": 20000,\n"
|
||||||
|
" \"RemoteReceiveTimeoutSeconds\": 120,\n"
|
||||||
|
" \"RemoteSendTimeoutSeconds\": 30,\n"
|
||||||
|
" \"RemoteToken\": \"\"\n"
|
||||||
|
" },\n"
|
||||||
|
" \"RetryReadCount\": 6,\n"
|
||||||
|
" \"RingBufferFileSize\": 512,\n"
|
||||||
|
" \"SiaConfig\": {\n"
|
||||||
|
" \"Bucket\": \"\"\n"
|
||||||
|
" },\n"
|
||||||
|
" \"Version\": " +
|
||||||
|
std::to_string(REPERTORY_CONFIG_VERSION) +
|
||||||
|
"\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const auto DEFAULT_S3_CONFIG = "{\n"
|
||||||
|
" \"ApiAuth\": \"\",\n"
|
||||||
|
" \"ApiPort\": 10100,\n"
|
||||||
|
" \"ApiUser\": \"repertory\",\n"
|
||||||
|
" \"ChunkDownloaderTimeoutSeconds\": 30,\n"
|
||||||
|
" \"EnableChunkDownloaderTimeout\": true,\n"
|
||||||
|
" \"EnableCommDurationEvents\": false,\n"
|
||||||
|
" \"EnableDriveEvents\": false,\n"
|
||||||
|
" \"EnableMaxCacheSize\": false,\n"
|
||||||
|
#if defined(_WIN32)
|
||||||
|
" \"EnableMountManager\": false,\n"
|
||||||
|
#endif
|
||||||
|
" \"EventLevel\": \"info\",\n"
|
||||||
|
" \"EvictionDelayMinutes\": 10,\n"
|
||||||
|
" \"EvictionUsesAccessedTime\": false,\n"
|
||||||
|
" \"HighFreqIntervalSeconds\": 30,\n"
|
||||||
|
" \"LowFreqIntervalSeconds\": 3600,\n"
|
||||||
|
" \"MaxCacheSizeBytes\": 21474836480,\n"
|
||||||
|
" \"MaxUploadCount\": 5,\n"
|
||||||
|
" \"OnlineCheckRetrySeconds\": 60,\n"
|
||||||
|
" \"OrphanedFileRetentionDays\": 15,\n"
|
||||||
|
" \"PreferredDownloadType\": \"fallback\",\n"
|
||||||
|
" \"ReadAheadCount\": 4,\n"
|
||||||
|
" \"RemoteMount\": {\n"
|
||||||
|
" \"EnableRemoteMount\": false,\n"
|
||||||
|
" \"IsRemoteMount\": false,\n"
|
||||||
|
" \"RemoteClientPoolSize\": 10,\n"
|
||||||
|
" \"RemoteHostNameOrIp\": \"\",\n"
|
||||||
|
" \"RemoteMaxConnections\": 20,\n"
|
||||||
|
" \"RemotePort\": 20100,\n"
|
||||||
|
" \"RemoteReceiveTimeoutSeconds\": 120,\n"
|
||||||
|
" \"RemoteSendTimeoutSeconds\": 30,\n"
|
||||||
|
" \"RemoteToken\": \"\"\n"
|
||||||
|
" },\n"
|
||||||
|
" \"RetryReadCount\": 6,\n"
|
||||||
|
" \"RingBufferFileSize\": 512,\n"
|
||||||
|
" \"S3Config\": {\n"
|
||||||
|
" \"AccessKey\": \"\",\n"
|
||||||
|
" \"Bucket\": \"\",\n"
|
||||||
|
" \"EncryptionToken\": \"\",\n"
|
||||||
|
" \"Region\": \"any\",\n"
|
||||||
|
" \"SecretKey\": \"\",\n"
|
||||||
|
" \"TimeoutMs\": 60000,\n"
|
||||||
|
" \"URL\": \"\",\n"
|
||||||
|
" \"UsePathStyle\": false,\n"
|
||||||
|
" \"UseRegionInURL\": false\n"
|
||||||
|
" },\n"
|
||||||
|
" \"Version\": " +
|
||||||
|
std::to_string(REPERTORY_CONFIG_VERSION) +
|
||||||
|
"\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
TEST_F(config_test, sia_default_settings) {
|
||||||
|
const auto config_file = utils::path::combine(sia_directory, {"config.json"});
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
config.set_remote_token("");
|
||||||
|
config.set_api_auth("");
|
||||||
|
EXPECT_TRUE(config.set_value_by_name("HostConfig.ApiPassword", "").empty());
|
||||||
|
json data;
|
||||||
|
EXPECT_TRUE(utils::file::read_json_file(config_file, data));
|
||||||
|
EXPECT_STREQ(DEFAULT_SIA_CONFIG.c_str(), data.dump(2).c_str());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
utils::file::directory(utils::path::combine(sia_directory, {"cache"}))
|
||||||
|
.exists());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
utils::file::directory(utils::path::combine(sia_directory, {"logs"}))
|
||||||
|
.exists());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, s3_default_settings) {
|
||||||
|
const auto config_file = utils::path::combine(s3_directory, {"config.json"});
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
app_config config(provider_type::s3, s3_directory);
|
||||||
|
config.set_remote_token("");
|
||||||
|
config.set_api_auth("");
|
||||||
|
json data;
|
||||||
|
EXPECT_TRUE(utils::file::read_json_file(config_file, data));
|
||||||
|
EXPECT_STREQ(DEFAULT_S3_CONFIG.c_str(), data.dump(2).c_str());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
utils::file::directory(utils::path::combine(s3_directory, {"cache"}))
|
||||||
|
.exists());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
utils::file::directory(utils::path::combine(s3_directory, {"logs"}))
|
||||||
|
.exists());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(config_test, api_path) {
|
TEST_F(config_test, api_path) {
|
||||||
std::string original_value;
|
std::string original_value;
|
||||||
@ -110,31 +248,45 @@ TEST_F(config_test, api_user) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(config_test, download_timeout_secs) {
|
TEST_F(config_test, chunk_downloader_timeout_secs) {
|
||||||
std::uint8_t original_value{};
|
std::uint8_t original_value{};
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
original_value = config.get_download_timeout_secs();
|
original_value = config.get_chunk_downloader_timeout_secs();
|
||||||
config.set_download_timeout_secs(original_value + 5);
|
config.set_chunk_downloader_timeout_secs(original_value + 5);
|
||||||
EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_chunk_downloader_timeout_secs());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_chunk_downloader_timeout_secs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(config_test, enable_download_timeout) {
|
TEST_F(config_test, enable_chunk_download_timeout) {
|
||||||
bool original_value{};
|
bool original_value{};
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
original_value = config.get_enable_download_timeout();
|
original_value = config.get_enable_chunk_download_timeout();
|
||||||
config.set_enable_download_timeout(not original_value);
|
config.set_enable_chunk_downloader_timeout(not original_value);
|
||||||
EXPECT_EQ(not original_value, config.get_enable_download_timeout());
|
EXPECT_EQ(not original_value, config.get_enable_chunk_download_timeout());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
EXPECT_EQ(not original_value, config.get_enable_download_timeout());
|
EXPECT_EQ(not original_value, config.get_enable_chunk_download_timeout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, enable_comm_duration_events) {
|
||||||
|
bool original_value{};
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
original_value = config.get_enable_comm_duration_events();
|
||||||
|
config.set_enable_comm_duration_events(not original_value);
|
||||||
|
EXPECT_EQ(not original_value, config.get_enable_comm_duration_events());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
EXPECT_EQ(not original_value, config.get_enable_comm_duration_events());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +304,19 @@ TEST_F(config_test, enable_drive_events) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, enable_max_cache_size) {
|
||||||
|
bool original_value{};
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
original_value = config.get_enable_max_cache_size();
|
||||||
|
config.set_enable_max_cache_size(not original_value);
|
||||||
|
EXPECT_EQ(not original_value, config.get_enable_max_cache_size());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
EXPECT_EQ(not original_value, config.get_enable_max_cache_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
TEST_F(config_test, enable_mount_manager) {
|
TEST_F(config_test, enable_mount_manager) {
|
||||||
bool original_value;
|
bool original_value;
|
||||||
@ -211,44 +376,30 @@ TEST_F(config_test, eviction_uses_accessed_time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(config_test, high_frequency_interval_secs) {
|
TEST_F(config_test, high_frequency_interval_secs) {
|
||||||
std::uint16_t original_value{};
|
std::uint8_t original_value{};
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
original_value = config.get_high_frequency_interval_secs();
|
original_value = config.get_high_frequency_interval_secs();
|
||||||
config.set_high_frequency_interval_secs(original_value + 5U);
|
config.set_high_frequency_interval_secs(original_value + 5);
|
||||||
EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
|
EXPECT_EQ(original_value + 5, config.get_high_frequency_interval_secs());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
|
EXPECT_EQ(original_value + 5, config.get_high_frequency_interval_secs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(config_test, low_frequency_interval_secs) {
|
TEST_F(config_test, low_frequency_interval_secs) {
|
||||||
std::uint16_t original_value{};
|
std::uint32_t original_value{};
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
original_value = config.get_low_frequency_interval_secs();
|
original_value = config.get_low_frequency_interval_secs();
|
||||||
config.set_low_frequency_interval_secs(original_value + 5U);
|
config.set_low_frequency_interval_secs(original_value + 5);
|
||||||
EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
|
EXPECT_EQ(original_value + 5, config.get_low_frequency_interval_secs());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
|
EXPECT_EQ(original_value + 5, config.get_low_frequency_interval_secs());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, med_frequency_interval_secs) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_med_frequency_interval_secs();
|
|
||||||
config.set_med_frequency_interval_secs(original_value + 5U);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +484,20 @@ TEST_F(config_test, orphaned_file_retention_days_maximum_value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, read_ahead_count) {
|
||||||
|
std::uint8_t original_value{};
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
original_value = config.get_read_ahead_count();
|
||||||
|
config.set_read_ahead_count(original_value + 5);
|
||||||
|
EXPECT_EQ(original_value + 5, config.get_read_ahead_count());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
EXPECT_EQ(original_value + 5, config.get_read_ahead_count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(config_test, get_cache_directory) {
|
TEST_F(config_test, get_cache_directory) {
|
||||||
{
|
{
|
||||||
app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
@ -469,170 +634,167 @@ TEST_F(config_test, get_version) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, enable_remote_mount) {
|
TEST_F(config_test, enable_remote_mount) {
|
||||||
// bool original_value{};
|
bool original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_enable_remote_mount();
|
original_value = config.get_enable_remote_mount();
|
||||||
// config.set_enable_remote_mount(not original_value);
|
config.set_enable_remote_mount(not original_value);
|
||||||
// EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, is_remote_mount) {
|
TEST_F(config_test, is_remote_mount) {
|
||||||
// bool original_value{};
|
bool original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_is_remote_mount();
|
original_value = config.get_is_remote_mount();
|
||||||
// config.set_is_remote_mount(not original_value);
|
config.set_is_remote_mount(not original_value);
|
||||||
// EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, enable_remote_mount_fails_if_remote_mount_is_true) {
|
TEST_F(config_test, enable_remote_mount_fails_if_remote_mount_is_true) {
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// config.set_is_remote_mount(true);
|
config.set_is_remote_mount(true);
|
||||||
// config.set_enable_remote_mount(true);
|
config.set_enable_remote_mount(true);
|
||||||
// EXPECT_FALSE(config.get_enable_remote_mount());
|
EXPECT_FALSE(config.get_enable_remote_mount());
|
||||||
// EXPECT_TRUE(config.get_is_remote_mount());
|
EXPECT_TRUE(config.get_is_remote_mount());
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, set_is_remote_mount_fails_if_enable_remote_mount_is_true)
|
TEST_F(config_test, set_is_remote_mount_fails_if_enable_remote_mount_is_true) {
|
||||||
// {
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
config.set_enable_remote_mount(true);
|
||||||
// config.set_enable_remote_mount(true);
|
config.set_is_remote_mount(true);
|
||||||
// config.set_is_remote_mount(true);
|
EXPECT_FALSE(config.get_is_remote_mount());
|
||||||
// EXPECT_FALSE(config.get_is_remote_mount());
|
EXPECT_TRUE(config.get_enable_remote_mount());
|
||||||
// EXPECT_TRUE(config.get_enable_remote_mount());
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_host_name_or_ip) {
|
TEST_F(config_test, remote_host_name_or_ip) {
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// config.set_remote_host_name_or_ip("my.host.name");
|
config.set_remote_host_name_or_ip("my.host.name");
|
||||||
// EXPECT_STREQ("my.host.name",
|
EXPECT_STREQ("my.host.name", config.get_remote_host_name_or_ip().c_str());
|
||||||
// config.get_remote_host_name_or_ip().c_str());
|
}
|
||||||
// }
|
{
|
||||||
// {
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
EXPECT_STREQ("my.host.name", config.get_remote_host_name_or_ip().c_str());
|
||||||
// EXPECT_STREQ("my.host.name",
|
}
|
||||||
// config.get_remote_host_name_or_ip().c_str());
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_api_port) {
|
TEST_F(config_test, remote_port) {
|
||||||
// std::uint16_t original_value{};
|
std::uint16_t original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_remote_api_port();
|
original_value = config.get_remote_port();
|
||||||
// config.set_remote_api_port(original_value + 5);
|
config.set_remote_port(original_value + 5);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_api_port());
|
EXPECT_EQ(original_value + 5, config.get_remote_port());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_api_port());
|
EXPECT_EQ(original_value + 5, config.get_remote_port());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, remote_receive_timeout_secs) {
|
TEST_F(config_test, remote_receive_timeout_secs) {
|
||||||
// std::uint16_t original_value{};
|
std::uint16_t original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_remote_receive_timeout_secs();
|
original_value = config.get_remote_receive_timeout_secs();
|
||||||
// config.set_remote_receive_timeout_secs(original_value + 5);
|
config.set_remote_receive_timeout_secs(original_value + 5);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, remote_send_timeout_secs) {
|
TEST_F(config_test, remote_send_timeout_secs) {
|
||||||
// std::uint16_t original_value{};
|
std::uint16_t original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_remote_send_timeout_secs();
|
original_value = config.get_remote_send_timeout_secs();
|
||||||
// config.set_remote_send_timeout_secs(original_value + 5);
|
config.set_remote_send_timeout_secs(original_value + 5);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, remote_encryption_token) {
|
TEST_F(config_test, remote_token) {
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// config.set_remote_encryption_token("myToken");
|
config.set_remote_token("myToken");
|
||||||
// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
|
EXPECT_STREQ("myToken", config.get_remote_token().c_str());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
|
EXPECT_STREQ("myToken", config.get_remote_token().c_str());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// TEST_F(config_test, remote_client_pool_size) {
|
|
||||||
// std::uint8_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_client_pool_size();
|
|
||||||
// config.set_remote_client_pool_size(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// TEST_F(config_test, remote_client_pool_size_minimum_value) {
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_remote_client_pool_size(0);
|
|
||||||
// EXPECT_EQ(5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_max_connections) {
|
TEST_F(config_test, remote_client_pool_size) {
|
||||||
// std::uint8_t original_value{};
|
std::uint8_t original_value{};
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// original_value = config.get_remote_max_connections();
|
original_value = config.get_remote_client_pool_size();
|
||||||
// config.set_remote_max_connections(original_value + 5);
|
config.set_remote_client_pool_size(original_value + 5);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TEST_F(config_test, remote_max_connections_minimum_value) {
|
TEST_F(config_test, remote_client_pool_size_minimum_value) {
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// config.set_remote_max_connections(0);
|
config.set_remote_client_pool_size(0);
|
||||||
// EXPECT_EQ(1, config.get_remote_max_connections());
|
EXPECT_EQ(5, config.get_remote_client_pool_size());
|
||||||
// }
|
}
|
||||||
// {
|
{
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
app_config config(provider_type::sia, sia_directory);
|
||||||
// EXPECT_EQ(1, config.get_remote_max_connections());
|
EXPECT_EQ(5, config.get_remote_client_pool_size());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, remote_max_connections) {
|
||||||
|
std::uint8_t original_value{};
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
original_value = config.get_remote_max_connections();
|
||||||
|
config.set_remote_max_connections(original_value + 5);
|
||||||
|
EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(config_test, remote_max_connections_minimum_value) {
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
config.set_remote_max_connections(0);
|
||||||
|
EXPECT_EQ(1, config.get_remote_max_connections());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
EXPECT_EQ(1, config.get_remote_max_connections());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(config_test, retry_read_count) {
|
TEST_F(config_test, retry_read_count) {
|
||||||
std::uint16_t original_value{};
|
std::uint16_t original_value{};
|
||||||
@ -655,40 +817,4 @@ TEST_F(config_test, retry_read_count_minimum_value) {
|
|||||||
EXPECT_EQ(2, config.get_retry_read_count());
|
EXPECT_EQ(2, config.get_retry_read_count());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(config_test, task_wait_ms) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_task_wait_ms();
|
|
||||||
config.set_task_wait_ms(original_value + 1U);
|
|
||||||
EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, task_wait_ms_minimum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_task_wait_ms(1U);
|
|
||||||
EXPECT_EQ(50U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, can_set_database_type) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_database_type(database_type::rocksdb);
|
|
||||||
EXPECT_EQ(database_type::rocksdb, config.get_database_type());
|
|
||||||
|
|
||||||
config.set_database_type(database_type::sqlite);
|
|
||||||
EXPECT_EQ(database_type::sqlite, config.get_database_type());
|
|
||||||
|
|
||||||
config.set_database_type(database_type::rocksdb);
|
|
||||||
EXPECT_EQ(database_type::rocksdb, config.get_database_type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -1,292 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "test_common.hpp"
|
|
||||||
|
|
||||||
#include "file_manager/direct_open_file.hpp"
|
|
||||||
#include "mocks/mock_provider.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
constexpr const std::size_t test_chunk_size{1024U};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class direct_open_file_test : public ::testing::Test {
|
|
||||||
public:
|
|
||||||
console_consumer con_consumer;
|
|
||||||
mock_provider provider;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void SetUp() override { event_system::instance().start(); }
|
|
||||||
|
|
||||||
void TearDown() override { event_system::instance().stop(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(direct_open_file_test, read_full_file) {
|
|
||||||
auto &source_file = test::create_random_file(test_chunk_size * 32U);
|
|
||||||
|
|
||||||
auto dest_path = test::generate_test_file_name("direct_open_file");
|
|
||||||
|
|
||||||
EXPECT_CALL(provider, is_read_only()).WillRepeatedly(Return(false));
|
|
||||||
|
|
||||||
filesystem_item fsi;
|
|
||||||
fsi.api_path = "/test.txt";
|
|
||||||
fsi.directory = false;
|
|
||||||
fsi.size = test_chunk_size * 32U;
|
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
|
||||||
const std::string & /* api_path */, std::size_t size,
|
|
||||||
std::uint64_t offset, data_buffer &data,
|
|
||||||
stop_type &stop_requested) -> api_error {
|
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
data.resize(size);
|
|
||||||
auto ret = source_file.read(data, offset, &bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
EXPECT_EQ(bytes_read, data.size());
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
{
|
|
||||||
direct_open_file file(test_chunk_size, 30U, fsi, provider);
|
|
||||||
|
|
||||||
auto dest_file = utils::file::file::open_or_create_file(dest_path);
|
|
||||||
EXPECT_TRUE(dest_file);
|
|
||||||
|
|
||||||
auto to_read{fsi.size};
|
|
||||||
std::size_t chunk{0U};
|
|
||||||
while (to_read > 0U) {
|
|
||||||
data_buffer data{};
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
file.read(test_chunk_size, chunk * test_chunk_size, data));
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
|
||||||
EXPECT_TRUE(
|
|
||||||
dest_file->write(data, chunk * test_chunk_size, &bytes_written));
|
|
||||||
++chunk;
|
|
||||||
to_read -= data.size();
|
|
||||||
}
|
|
||||||
dest_file->close();
|
|
||||||
source_file.close();
|
|
||||||
|
|
||||||
auto hash1 = utils::file::file(source_file.get_path()).sha256();
|
|
||||||
auto hash2 = utils::file::file(dest_path).sha256();
|
|
||||||
|
|
||||||
EXPECT_TRUE(hash1.has_value());
|
|
||||||
EXPECT_TRUE(hash2.has_value());
|
|
||||||
if (hash1.has_value() && hash2.has_value()) {
|
|
||||||
EXPECT_STREQ(hash1.value().c_str(), hash2.value().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(direct_open_file_test, read_full_file_in_reverse) {
|
|
||||||
auto &source_file = test::create_random_file(test_chunk_size * 32U);
|
|
||||||
|
|
||||||
auto dest_path = test::generate_test_file_name("direct_open_file");
|
|
||||||
|
|
||||||
EXPECT_CALL(provider, is_read_only()).WillRepeatedly(Return(false));
|
|
||||||
|
|
||||||
filesystem_item fsi;
|
|
||||||
fsi.api_path = "/test.txt";
|
|
||||||
fsi.directory = false;
|
|
||||||
fsi.size = test_chunk_size * 32U;
|
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
|
||||||
const std::string & /* api_path */, std::size_t size,
|
|
||||||
std::uint64_t offset, data_buffer &data,
|
|
||||||
stop_type &stop_requested) -> api_error {
|
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
data.resize(size);
|
|
||||||
auto ret = source_file.read(data, offset, &bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
EXPECT_EQ(bytes_read, data.size());
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
{
|
|
||||||
direct_open_file file(test_chunk_size, 30U, fsi, provider);
|
|
||||||
|
|
||||||
auto dest_file = utils::file::file::open_or_create_file(dest_path);
|
|
||||||
EXPECT_TRUE(dest_file);
|
|
||||||
|
|
||||||
auto to_read{fsi.size};
|
|
||||||
std::size_t chunk{file.get_total_chunks() - 1U};
|
|
||||||
while (to_read > 0U) {
|
|
||||||
data_buffer data{};
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
file.read(test_chunk_size, chunk * test_chunk_size, data));
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
|
||||||
EXPECT_TRUE(
|
|
||||||
dest_file->write(data, chunk * test_chunk_size, &bytes_written));
|
|
||||||
--chunk;
|
|
||||||
to_read -= data.size();
|
|
||||||
}
|
|
||||||
dest_file->close();
|
|
||||||
source_file.close();
|
|
||||||
|
|
||||||
auto hash1 = utils::file::file(source_file.get_path()).sha256();
|
|
||||||
auto hash2 = utils::file::file(dest_path).sha256();
|
|
||||||
|
|
||||||
EXPECT_TRUE(hash1.has_value());
|
|
||||||
EXPECT_TRUE(hash2.has_value());
|
|
||||||
if (hash1.has_value() && hash2.has_value()) {
|
|
||||||
EXPECT_STREQ(hash1.value().c_str(), hash2.value().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(direct_open_file_test, read_full_file_in_partial_chunks) {
|
|
||||||
auto &source_file = test::create_random_file(test_chunk_size * 32U);
|
|
||||||
|
|
||||||
auto dest_path = test::generate_test_file_name("test");
|
|
||||||
|
|
||||||
EXPECT_CALL(provider, is_read_only()).WillRepeatedly(Return(false));
|
|
||||||
|
|
||||||
filesystem_item fsi;
|
|
||||||
fsi.directory = false;
|
|
||||||
fsi.api_path = "/test.txt";
|
|
||||||
fsi.size = test_chunk_size * 32U;
|
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
|
||||||
const std::string & /* api_path */, std::size_t size,
|
|
||||||
std::uint64_t offset, data_buffer &data,
|
|
||||||
stop_type &stop_requested) -> api_error {
|
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
data.resize(size);
|
|
||||||
auto ret = source_file.read(data, offset, &bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
EXPECT_EQ(bytes_read, data.size());
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
{
|
|
||||||
direct_open_file file(test_chunk_size, 30U, fsi, provider);
|
|
||||||
|
|
||||||
auto dest_file = utils::file::file::open_or_create_file(dest_path);
|
|
||||||
EXPECT_TRUE(dest_file);
|
|
||||||
|
|
||||||
auto total_read{std::uint64_t(0U)};
|
|
||||||
while (total_read < fsi.size) {
|
|
||||||
data_buffer data{};
|
|
||||||
EXPECT_EQ(api_error::success, file.read(3U, total_read, data));
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
|
||||||
EXPECT_TRUE(dest_file->write(data.data(), data.size(), total_read,
|
|
||||||
&bytes_written));
|
|
||||||
total_read += data.size();
|
|
||||||
}
|
|
||||||
dest_file->close();
|
|
||||||
source_file.close();
|
|
||||||
|
|
||||||
auto hash1 = utils::file::file(source_file.get_path()).sha256();
|
|
||||||
auto hash2 = utils::file::file(dest_path).sha256();
|
|
||||||
|
|
||||||
EXPECT_TRUE(hash1.has_value());
|
|
||||||
EXPECT_TRUE(hash2.has_value());
|
|
||||||
if (hash1.has_value() && hash2.has_value()) {
|
|
||||||
EXPECT_STREQ(hash1.value().c_str(), hash2.value().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(direct_open_file_test, read_full_file_in_partial_chunks_in_reverse) {
|
|
||||||
auto &source_file = test::create_random_file(test_chunk_size * 32U);
|
|
||||||
|
|
||||||
auto dest_path = test::generate_test_file_name("direct_open_file");
|
|
||||||
|
|
||||||
EXPECT_CALL(provider, is_read_only()).WillRepeatedly(Return(false));
|
|
||||||
|
|
||||||
filesystem_item fsi;
|
|
||||||
fsi.directory = false;
|
|
||||||
fsi.api_path = "/test.txt";
|
|
||||||
fsi.size = test_chunk_size * 32U;
|
|
||||||
|
|
||||||
std::mutex read_mtx;
|
|
||||||
EXPECT_CALL(provider, read_file_bytes)
|
|
||||||
.WillRepeatedly([&read_mtx, &source_file](
|
|
||||||
const std::string & /* api_path */, std::size_t size,
|
|
||||||
std::uint64_t offset, data_buffer &data,
|
|
||||||
stop_type &stop_requested) -> api_error {
|
|
||||||
mutex_lock lock(read_mtx);
|
|
||||||
|
|
||||||
EXPECT_FALSE(stop_requested);
|
|
||||||
std::size_t bytes_read{};
|
|
||||||
data.resize(size);
|
|
||||||
auto ret = source_file.read(data, offset, &bytes_read)
|
|
||||||
? api_error::success
|
|
||||||
: api_error::os_error;
|
|
||||||
EXPECT_EQ(bytes_read, data.size());
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
{
|
|
||||||
direct_open_file file(test_chunk_size, 30U, fsi, provider);
|
|
||||||
|
|
||||||
auto dest_file = utils::file::file::open_or_create_file(dest_path);
|
|
||||||
EXPECT_TRUE(dest_file);
|
|
||||||
|
|
||||||
std::uint64_t total_read{0U};
|
|
||||||
auto read_size{3U};
|
|
||||||
|
|
||||||
while (total_read < fsi.size) {
|
|
||||||
auto offset = fsi.size - total_read - read_size;
|
|
||||||
auto remain = fsi.size - total_read;
|
|
||||||
|
|
||||||
data_buffer data{};
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
file.read(static_cast<std::size_t>(
|
|
||||||
std::min(remain, std::uint64_t(read_size))),
|
|
||||||
(remain >= read_size) ? offset : 0U, data));
|
|
||||||
|
|
||||||
std::size_t bytes_written{};
|
|
||||||
EXPECT_TRUE(dest_file->write(data, (remain >= read_size) ? offset : 0U,
|
|
||||||
&bytes_written));
|
|
||||||
total_read += data.size();
|
|
||||||
}
|
|
||||||
dest_file->close();
|
|
||||||
source_file.close();
|
|
||||||
|
|
||||||
auto hash1 = utils::file::file(source_file.get_path()).sha256();
|
|
||||||
auto hash2 = utils::file::file(dest_path).sha256();
|
|
||||||
|
|
||||||
EXPECT_TRUE(hash1.has_value());
|
|
||||||
EXPECT_TRUE(hash2.has_value());
|
|
||||||
if (hash1.has_value() && hash2.has_value()) {
|
|
||||||
EXPECT_STREQ(hash1.value().c_str(), hash2.value().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -1,332 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fixtures/file_db_fixture.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
TYPED_TEST_CASE(file_db_test, file_db_types);
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_add_and_remove_directory) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test"));
|
|
||||||
|
|
||||||
auto list = this->file_db->get_item_list();
|
|
||||||
EXPECT_EQ(1U, list.size());
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->remove_item("/"));
|
|
||||||
|
|
||||||
list = this->file_db->get_item_list();
|
|
||||||
EXPECT_EQ(0U, list.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_add_and_remove_file) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
0U,
|
|
||||||
{},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
auto list = this->file_db->get_item_list();
|
|
||||||
EXPECT_EQ(1U, list.size());
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->remove_item("/file"));
|
|
||||||
|
|
||||||
list = this->file_db->get_item_list();
|
|
||||||
EXPECT_EQ(0U, list.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_api_path_for_directory) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test"));
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_api_path("c:\\test", api_path));
|
|
||||||
EXPECT_STREQ("/", api_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_api_path_for_file) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
0U,
|
|
||||||
{},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_api_path("c:\\test\\file.txt", api_path));
|
|
||||||
EXPECT_STREQ("/file", api_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test,
|
|
||||||
item_not_found_is_returned_for_non_existing_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::item_not_found,
|
|
||||||
this->file_db->get_api_path("c:\\test", api_path));
|
|
||||||
EXPECT_TRUE(api_path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_directory_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test"));
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_directory_api_path("c:\\test", api_path));
|
|
||||||
EXPECT_STREQ("/", api_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(
|
|
||||||
file_db_test,
|
|
||||||
directory_not_found_is_returned_for_non_existing_directory_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::directory_not_found,
|
|
||||||
this->file_db->get_directory_api_path("c:\\test", api_path));
|
|
||||||
EXPECT_TRUE(api_path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_file_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
0U,
|
|
||||||
{},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_file_api_path("c:\\test\\file.txt", api_path));
|
|
||||||
EXPECT_STREQ("/file", api_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test,
|
|
||||||
item_not_found_is_returned_for_non_existing_file_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string api_path;
|
|
||||||
EXPECT_EQ(api_error::item_not_found,
|
|
||||||
this->file_db->get_file_api_path("c:\\test", api_path));
|
|
||||||
EXPECT_TRUE(api_path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_directory_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test"));
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_directory_source_path("/", source_path));
|
|
||||||
EXPECT_STREQ("c:\\test", source_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(
|
|
||||||
file_db_test,
|
|
||||||
directory_not_found_is_returned_for_non_existing_directory_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::directory_not_found,
|
|
||||||
this->file_db->get_directory_source_path("/", source_path));
|
|
||||||
EXPECT_TRUE(source_path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_file_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
0U,
|
|
||||||
{},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_file_source_path("/file", source_path));
|
|
||||||
EXPECT_STREQ("c:\\test\\file.txt", source_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test,
|
|
||||||
item_not_found_is_returned_for_non_existing_file_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::item_not_found,
|
|
||||||
this->file_db->get_file_source_path("/file.txt", source_path));
|
|
||||||
EXPECT_TRUE(source_path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_file_data) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
i_file_db::file_data data{};
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->get_file_data("/file", data));
|
|
||||||
EXPECT_STREQ("/file", data.api_path.c_str());
|
|
||||||
EXPECT_EQ(1U, data.file_size);
|
|
||||||
EXPECT_EQ(2U, data.iv_list.size());
|
|
||||||
EXPECT_STREQ("c:\\test\\file.txt", data.source_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test,
|
|
||||||
item_not_found_is_returned_for_non_existing_file_data_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
i_file_db::file_data data{};
|
|
||||||
EXPECT_EQ(api_error::item_not_found,
|
|
||||||
this->file_db->get_file_data("/file", data));
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_update_existing_file_iv) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
i_file_db::file_data data{};
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->get_file_data("/file", data));
|
|
||||||
EXPECT_STREQ("/file", data.api_path.c_str());
|
|
||||||
EXPECT_EQ(1U, data.file_size);
|
|
||||||
EXPECT_EQ(3U, data.iv_list.size());
|
|
||||||
EXPECT_STREQ("c:\\test\\file.txt", data.source_path.c_str());
|
|
||||||
|
|
||||||
EXPECT_EQ(1U, this->file_db->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_update_existing_file_size) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
2U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
i_file_db::file_data data{};
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->get_file_data("/file", data));
|
|
||||||
EXPECT_STREQ("/file", data.api_path.c_str());
|
|
||||||
EXPECT_EQ(2U, data.file_size);
|
|
||||||
EXPECT_EQ(2U, data.iv_list.size());
|
|
||||||
EXPECT_STREQ("c:\\test\\file.txt", data.source_path.c_str());
|
|
||||||
|
|
||||||
EXPECT_EQ(1U, this->file_db->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_update_existing_file_source_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
1U,
|
|
||||||
{{}, {}},
|
|
||||||
"c:\\test\\file2.txt",
|
|
||||||
}));
|
|
||||||
|
|
||||||
i_file_db::file_data data{};
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->get_file_data("/file", data));
|
|
||||||
EXPECT_STREQ("/file", data.api_path.c_str());
|
|
||||||
EXPECT_EQ(1U, data.file_size);
|
|
||||||
EXPECT_EQ(2U, data.iv_list.size());
|
|
||||||
EXPECT_STREQ("c:\\test\\file2.txt", data.source_path.c_str());
|
|
||||||
|
|
||||||
EXPECT_EQ(1U, this->file_db->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_source_path_for_directory) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test"));
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_source_path("/", source_path));
|
|
||||||
EXPECT_STREQ("c:\\test", source_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, can_get_source_path_for_file) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({
|
|
||||||
"/file",
|
|
||||||
0U,
|
|
||||||
{},
|
|
||||||
"c:\\test\\file.txt",
|
|
||||||
}));
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::success,
|
|
||||||
this->file_db->get_source_path("/file", source_path));
|
|
||||||
EXPECT_STREQ("c:\\test\\file.txt", source_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(file_db_test, item_not_found_is_returned_for_non_existing_api_path) {
|
|
||||||
this->file_db->clear();
|
|
||||||
|
|
||||||
std::string source_path;
|
|
||||||
EXPECT_EQ(api_error::item_not_found,
|
|
||||||
this->file_db->get_source_path("/file", source_path));
|
|
||||||
EXPECT_TRUE(source_path.empty());
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user