mirror of
https://github.com/gofiber/storage.git
synced 2025-12-24 05:08:39 +08:00
Compare commits
2359 Commits
v0.0.1
...
simplify-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33e4479ce7 | ||
|
|
adea65d290 | ||
|
|
537b31756b | ||
|
|
3b91f93611 | ||
|
|
42831dcee6 | ||
|
|
89a0a97fe8 | ||
|
|
86f1b406e3 | ||
|
|
102acc252b | ||
|
|
40a6167b74 | ||
|
|
e4d46ce66c | ||
|
|
386b6f431f | ||
|
|
d2af2eb76b | ||
|
|
395f8a80da | ||
|
|
76c52119bf | ||
|
|
87c2b454f8 | ||
|
|
12ea6b4978 | ||
|
|
cce70b9e7f | ||
|
|
f8776d0233 | ||
|
|
740eed9579 | ||
|
|
baaf5c76e0 | ||
|
|
9fa1710604 | ||
|
|
674175ded7 | ||
|
|
fae399ccdc | ||
|
|
381f0c134e | ||
|
|
9013b623ea | ||
|
|
512c66712a | ||
|
|
692f78abb0 | ||
|
|
1a7044aded | ||
|
|
88906bb82b | ||
|
|
5d095dc16b | ||
|
|
a18385a6ba | ||
|
|
1da3514e71 | ||
|
|
a0d6e6df5a | ||
|
|
603305cf39 | ||
|
|
f9f9ee6734 | ||
|
|
cb106882f0 | ||
|
|
a5f954c505 | ||
|
|
53c5ec01a5 | ||
|
|
f7b7345f06 | ||
|
|
cd119d0f9e | ||
|
|
2f1c0cbba5 | ||
|
|
4a558d04d2 | ||
|
|
29406b2354 | ||
|
|
6f09eca26d | ||
|
|
304babaae6 | ||
|
|
fe56bc56be | ||
|
|
d2c20a1452 | ||
|
|
8a873c0c1d | ||
|
|
8d24b7710e | ||
|
|
2c3433f532 | ||
|
|
f35a941b18 | ||
|
|
01d0e07203 | ||
|
|
07d3b2ee60 | ||
|
|
91125ae1ff | ||
|
|
8987519886 | ||
|
|
ae1a58f409 | ||
|
|
6cd2a04347 | ||
|
|
d6045366f3 | ||
|
|
eba6a80a13 | ||
|
|
d296a7f0da | ||
|
|
30d1c4aeb1 | ||
|
|
c9bf60b822 | ||
|
|
526f70b1de | ||
|
|
46b8c41b07 | ||
|
|
920adaf9d1 | ||
|
|
33479fdf80 | ||
|
|
b8e131cbdc | ||
|
|
efae25917f | ||
|
|
87cb35a875 | ||
|
|
b54ef2f223 | ||
|
|
f0d3888c13 | ||
|
|
f6e1c398df | ||
|
|
fffd10e474 | ||
|
|
a5e5b6c392 | ||
|
|
730aba1fc4 | ||
|
|
8819ff54b7 | ||
|
|
3b5fbcdce6 | ||
|
|
9942341b72 | ||
|
|
9e27843919 | ||
|
|
7c94391d11 | ||
|
|
c3094e4ae5 | ||
|
|
5e11a89904 | ||
|
|
20c2931600 | ||
|
|
448cdd08e2 | ||
|
|
ea41c3d45e | ||
|
|
662c591519 | ||
|
|
d129128328 | ||
|
|
aa21992fd5 | ||
|
|
b02937835f | ||
|
|
7907504d75 | ||
|
|
2886d67714 | ||
|
|
eee0d7df2c | ||
|
|
60b43cf9d6 | ||
|
|
fe3cc059c4 | ||
|
|
b648905d66 | ||
|
|
69e62f0b54 | ||
|
|
ec227440cd | ||
|
|
0344cbd5f0 | ||
|
|
da28b6f39d | ||
|
|
dec716bf98 | ||
|
|
5da8c389a1 | ||
|
|
bf3ba3e751 | ||
|
|
e23626edef | ||
|
|
897a80879d | ||
|
|
2aa7735a92 | ||
|
|
2cea147aa4 | ||
|
|
920bb093a4 | ||
|
|
b5f9269fff | ||
|
|
04fb90595f | ||
|
|
8b1d41dde3 | ||
|
|
b784766b97 | ||
|
|
f520ae0b54 | ||
|
|
e38586e901 | ||
|
|
df05331a78 | ||
|
|
4ba6faaa00 | ||
|
|
76acc99239 | ||
|
|
43d47119b3 | ||
|
|
d72125bb60 | ||
|
|
e4aaaf76a8 | ||
|
|
0cc27ea7ce | ||
|
|
9524b39ca6 | ||
|
|
13a14cd6fb | ||
|
|
1fb6cd1a3f | ||
|
|
9209ae4617 | ||
|
|
cfd5f691c9 | ||
|
|
39412ce785 | ||
|
|
ea065c4ab8 | ||
|
|
337546b077 | ||
|
|
f9d76aa3d6 | ||
|
|
d2d34d8777 | ||
|
|
f25f8b8446 | ||
|
|
acb19da9e9 | ||
|
|
66c8914256 | ||
|
|
038a286c3b | ||
|
|
0701e6f1c3 | ||
|
|
e744bc09fa | ||
|
|
0228c63316 | ||
|
|
f27f7b1055 | ||
|
|
ad10412020 | ||
|
|
13e9acc454 | ||
|
|
f4bd2a5db4 | ||
|
|
5304e96e7c | ||
|
|
773d4f2e73 | ||
|
|
7c81cf0dd5 | ||
|
|
d237896b37 | ||
|
|
f7fab78724 | ||
|
|
6c59a5f1a3 | ||
|
|
662c06d9c7 | ||
|
|
b0d06ae093 | ||
|
|
88b0adfcef | ||
|
|
95d5b96b36 | ||
|
|
7fb2efee17 | ||
|
|
be0f16541b | ||
|
|
eea17d4cd7 | ||
|
|
d872a8574b | ||
|
|
6b75862f66 | ||
|
|
f4ee2db62c | ||
|
|
4311191155 | ||
|
|
78138c978a | ||
|
|
9a1f09c741 | ||
|
|
275be22a4c | ||
|
|
292cee6539 | ||
|
|
d27ee3679c | ||
|
|
bf0d8fc9d0 | ||
|
|
1f3a53a755 | ||
|
|
0887a66d65 | ||
|
|
2db9736872 | ||
|
|
492df714dd | ||
|
|
06cf69e024 | ||
|
|
7c1ec06ddc | ||
|
|
b52bac5100 | ||
|
|
7fab4c8cbb | ||
|
|
543f422b30 | ||
|
|
626ede4760 | ||
|
|
eef89b1660 | ||
|
|
895dc1f61a | ||
|
|
de58d8c006 | ||
|
|
3e9063102a | ||
|
|
c70e44944d | ||
|
|
ad436b5d82 | ||
|
|
c62c0af76c | ||
|
|
3ef00028e6 | ||
|
|
169c891474 | ||
|
|
5434d25098 | ||
|
|
f5b36b4517 | ||
|
|
e5cb562af7 | ||
|
|
17f0d6da43 | ||
|
|
25dc910491 | ||
|
|
d1087b6477 | ||
|
|
50e94bf6fe | ||
|
|
9b92a5ed83 | ||
|
|
e000f78db3 | ||
|
|
05dff2a932 | ||
|
|
41dea6c121 | ||
|
|
6c74d0b864 | ||
|
|
6f85e022d4 | ||
|
|
bbae53fb35 | ||
|
|
16f9e43d82 | ||
|
|
0231178416 | ||
|
|
4c2a305e61 | ||
|
|
fae42e4592 | ||
|
|
9b24adebf2 | ||
|
|
f1de042f2d | ||
|
|
6817772063 | ||
|
|
d91341723b | ||
|
|
9ae9f31fe9 | ||
|
|
e768b04589 | ||
|
|
f2ddd06660 | ||
|
|
ef93d8635c | ||
|
|
4ebd332f94 | ||
|
|
78b024645f | ||
|
|
2077c74abc | ||
|
|
fc586597bd | ||
|
|
cb3a645bda | ||
|
|
d2ef1c22bd | ||
|
|
cf99591f15 | ||
|
|
5991f3a5e2 | ||
|
|
b121644251 | ||
|
|
57dedb7d10 | ||
|
|
91d99c4d77 | ||
|
|
87d722a8bb | ||
|
|
78f9e38ef6 | ||
|
|
e8f8290853 | ||
|
|
0fd13ff4dd | ||
|
|
58d9dd4d40 | ||
|
|
1ab83b0150 | ||
|
|
ce553f5f1c | ||
|
|
f088e43dce | ||
|
|
800262d044 | ||
|
|
9e2901b3d4 | ||
|
|
b35dab26c8 | ||
|
|
9a0102b257 | ||
|
|
024059f926 | ||
|
|
2ce70bcb0e | ||
|
|
442c85f4ea | ||
|
|
6a9e104b0a | ||
|
|
ef7df44543 | ||
|
|
a2eb0d6b3f | ||
|
|
35c0f4bab3 | ||
|
|
cd0ee7e84d | ||
|
|
2ee9860581 | ||
|
|
7ef423aa2f | ||
|
|
ba68a75e60 | ||
|
|
6f20abd7d6 | ||
|
|
ffaa1494ed | ||
|
|
57784bac1b | ||
|
|
1291405328 | ||
|
|
271a8b8eeb | ||
|
|
0324ab518e | ||
|
|
45a3e9719c | ||
|
|
6321a10f61 | ||
|
|
bda840986b | ||
|
|
5aa5e4ea92 | ||
|
|
32c98e7637 | ||
|
|
ab57036636 | ||
|
|
49e5f016e0 | ||
|
|
99ad00fb86 | ||
|
|
72ad24d050 | ||
|
|
f94afabfbb | ||
|
|
8be98ec12f | ||
|
|
5742e6395e | ||
|
|
5e25d4abca | ||
|
|
1881da3c9e | ||
|
|
e45af13e62 | ||
|
|
697f9903d7 | ||
|
|
1e2668c44b | ||
|
|
4324fbb529 | ||
|
|
69fb880bbf | ||
|
|
273db55a3b | ||
|
|
3f5e8cf577 | ||
|
|
88206e0108 | ||
|
|
2b2f2bed62 | ||
|
|
c78f234f53 | ||
|
|
385904de72 | ||
|
|
caa8330a4a | ||
|
|
e59fb1708b | ||
|
|
9dc2b17d95 | ||
|
|
ee4532a57a | ||
|
|
2c75932d90 | ||
|
|
70636baba3 | ||
|
|
8b9db406a8 | ||
|
|
e18eaa828a | ||
|
|
12f859f2ee | ||
|
|
df5c2b3c7a | ||
|
|
92dad60f1d | ||
|
|
b8f6c0417b | ||
|
|
7473602f05 | ||
|
|
fbf4c82ee5 | ||
|
|
4a0c770dff | ||
|
|
8b6fa52653 | ||
|
|
12cac4c29e | ||
|
|
1e4e992d9e | ||
|
|
ede4c46a43 | ||
|
|
992f577828 | ||
|
|
e1784a8d41 | ||
|
|
2202ca55e5 | ||
|
|
051a869328 | ||
|
|
699b665ada | ||
|
|
bdf87e3718 | ||
|
|
11d7b5f886 | ||
|
|
ca256c013f | ||
|
|
0c53f4588b | ||
|
|
bfd7ccc79e | ||
|
|
5b35b5937b | ||
|
|
8499349011 | ||
|
|
2b8cf0f308 | ||
|
|
5e0232429e | ||
|
|
abad049ea3 | ||
|
|
44ec78f6cb | ||
|
|
812032288e | ||
|
|
946c51b77b | ||
|
|
f9aa336f93 | ||
|
|
43d9828355 | ||
|
|
1f4893bdb1 | ||
|
|
e48d3a2f68 | ||
|
|
81c33266b7 | ||
|
|
2faf1587e0 | ||
|
|
f212e66726 | ||
|
|
8585ae3988 | ||
|
|
4bdec1c00d | ||
|
|
6b1fb52cbf | ||
|
|
eeb431151d | ||
|
|
22cc9c6486 | ||
|
|
cdd09b4066 | ||
|
|
901110676d | ||
|
|
b59549eb58 | ||
|
|
f9a6291b7f | ||
|
|
de27d57cd2 | ||
|
|
d87c26eb2a | ||
|
|
324d3c7d92 | ||
|
|
25ad594682 | ||
|
|
f0cecde9de | ||
|
|
a61b434952 | ||
|
|
c3df35dacb | ||
|
|
3b83def333 | ||
|
|
3f5fda6bd8 | ||
|
|
21ac41f961 | ||
|
|
591957c96e | ||
|
|
99c099431a | ||
|
|
81b668ae40 | ||
|
|
8a64cac72f | ||
|
|
8f7781ce20 | ||
|
|
4c5f2ef1b8 | ||
|
|
de3083f492 | ||
|
|
2baf7d7e47 | ||
|
|
0054787fb2 | ||
|
|
706c8b6aa3 | ||
|
|
8c7e5acc3c | ||
|
|
8e8c619a30 | ||
|
|
8212d0317a | ||
|
|
03943a9436 | ||
|
|
79b8fb118e | ||
|
|
71bbf1ef10 | ||
|
|
1bc6b49847 | ||
|
|
873457db91 | ||
|
|
8e3d3f928f | ||
|
|
d4b1c839e3 | ||
|
|
da47a1fa62 | ||
|
|
5de7b1b072 | ||
|
|
0f8625f851 | ||
|
|
b397ca3c8e | ||
|
|
8bbaa80d22 | ||
|
|
ffeab66be3 | ||
|
|
29245c6088 | ||
|
|
5cd7843155 | ||
|
|
64ba9a2f98 | ||
|
|
de69aa6ceb | ||
|
|
b8c51d1779 | ||
|
|
efea419043 | ||
|
|
9590f1a0f0 | ||
|
|
0a5bf1359b | ||
|
|
819176ead9 | ||
|
|
3a6a27d56f | ||
|
|
5ecaadb118 | ||
|
|
f9a22ee538 | ||
|
|
1b1bc5958c | ||
|
|
7f504e3adc | ||
|
|
64b08d48dc | ||
|
|
1527f88e51 | ||
|
|
1ae7fa0a93 | ||
|
|
a5b09adaa3 | ||
|
|
73bb4f108a | ||
|
|
7e321c1339 | ||
|
|
6d5d57d92f | ||
|
|
ad8df22ea6 | ||
|
|
126df7488f | ||
|
|
235e47e230 | ||
|
|
b72e7331f3 | ||
|
|
64725d983c | ||
|
|
2c4232d7ff | ||
|
|
554fa73daf | ||
|
|
80b7b4ff71 | ||
|
|
bc9b6c3923 | ||
|
|
f0533e6b7c | ||
|
|
e63833bc5c | ||
|
|
346b2dd7bb | ||
|
|
7e0197ce31 | ||
|
|
58ff26a611 | ||
|
|
3e0c8567df | ||
|
|
d50cadeae6 | ||
|
|
cba67fb5df | ||
|
|
f4f69d7a71 | ||
|
|
d8f61c2a30 | ||
|
|
26e9d837d8 | ||
|
|
a3af67c4c0 | ||
|
|
c93cef290e | ||
|
|
68edc3ad83 | ||
|
|
93f7a52890 | ||
|
|
b85e6d0d56 | ||
|
|
d584f9ece7 | ||
|
|
7735395654 | ||
|
|
c95811231d | ||
|
|
9d3cdcebcb | ||
|
|
5ef27d1806 | ||
|
|
a5bee00bcb | ||
|
|
092fcc9317 | ||
|
|
e75d6b7eb4 | ||
|
|
65bc2797a6 | ||
|
|
92150c3054 | ||
|
|
94b3f09270 | ||
|
|
c5ec19cfc8 | ||
|
|
21ef5b1fef | ||
|
|
5d0e366e4c | ||
|
|
cfafa22e77 | ||
|
|
6b4507ad29 | ||
|
|
510d5832aa | ||
|
|
5b26a0b7ac | ||
|
|
f0076b556d | ||
|
|
959cadc5ba | ||
|
|
495c156eac | ||
|
|
033ebf7720 | ||
|
|
5e03e38c3c | ||
|
|
8ef7cd731a | ||
|
|
12eb0f16e1 | ||
|
|
fdda850e52 | ||
|
|
b8d752bd7f | ||
|
|
154e15008a | ||
|
|
a132bd42a6 | ||
|
|
8a140d7608 | ||
|
|
9f847168ec | ||
|
|
ef26f16389 | ||
|
|
9737161f16 | ||
|
|
ab3f1834a7 | ||
|
|
fe1c16e9cd | ||
|
|
5d0f193ff7 | ||
|
|
4798a58e02 | ||
|
|
f022a14091 | ||
|
|
6a5b6eb566 | ||
|
|
e541347e84 | ||
|
|
df3ac38b36 | ||
|
|
f21f9b9d7d | ||
|
|
338041533d | ||
|
|
af6af373a6 | ||
|
|
486479e620 | ||
|
|
f9471854c6 | ||
|
|
94fe279d1d | ||
|
|
8fbe3e8afb | ||
|
|
717d1afc2c | ||
|
|
e70cc58c03 | ||
|
|
e3862929db | ||
|
|
a6be2f6d15 | ||
|
|
3f10692020 | ||
|
|
4798bc4522 | ||
|
|
6c08ac408d | ||
|
|
65172b14fc | ||
|
|
bbf49af5ac | ||
|
|
65db3caad6 | ||
|
|
1c65d386dd | ||
|
|
01d6a9481e | ||
|
|
796363eb5a | ||
|
|
19be481dfc | ||
|
|
398c18391e | ||
|
|
e9bd7e9c55 | ||
|
|
c83d7f8201 | ||
|
|
5f53fa0ea0 | ||
|
|
7a7807bed1 | ||
|
|
cc2ea9a4f3 | ||
|
|
551373a086 | ||
|
|
115d2902a3 | ||
|
|
7410373fad | ||
|
|
d6e0360de6 | ||
|
|
8028341b13 | ||
|
|
85133f679a | ||
|
|
c424c6688a | ||
|
|
5817eafd81 | ||
|
|
8b6245bc97 | ||
|
|
adad63a053 | ||
|
|
79a9ae2870 | ||
|
|
c49806a515 | ||
|
|
6fa3ab028a | ||
|
|
40639065e8 | ||
|
|
84fc9ab2cc | ||
|
|
6a1f24af86 | ||
|
|
390f795dc8 | ||
|
|
4bd11fe45b | ||
|
|
e71ff2f2ae | ||
|
|
4dc463c32a | ||
|
|
53cc0c9fc2 | ||
|
|
e8b41f1b5d | ||
|
|
f38d256f3e | ||
|
|
630632b4a4 | ||
|
|
84ec050527 | ||
|
|
05d1237cb6 | ||
|
|
2680f18e3f | ||
|
|
92cd02fdbf | ||
|
|
2eb0ca23ac | ||
|
|
d942a697eb | ||
|
|
c2811fa897 | ||
|
|
a35fdd9a21 | ||
|
|
91880179cb | ||
|
|
f8d5157db3 | ||
|
|
1b6f22b6e1 | ||
|
|
b137356bde | ||
|
|
b4d8ba6b8c | ||
|
|
6c0585b30f | ||
|
|
795caf4e83 | ||
|
|
2c1132bac8 | ||
|
|
18b7ad8164 | ||
|
|
77f6a457fd | ||
|
|
fe44ce07d4 | ||
|
|
4ce7c1490d | ||
|
|
e8c9451a23 | ||
|
|
7cf6c951e8 | ||
|
|
66a63322aa | ||
|
|
02a8aa1f23 | ||
|
|
cda699da02 | ||
|
|
af7e046cb2 | ||
|
|
85161572c1 | ||
|
|
2b083ca3ec | ||
|
|
5e4c65a751 | ||
|
|
23df74bba9 | ||
|
|
41f417cfd5 | ||
|
|
1f82fff0d5 | ||
|
|
f3a26d385c | ||
|
|
1761a1900a | ||
|
|
2a95425c30 | ||
|
|
7c2d6950a0 | ||
|
|
2adb980fbb | ||
|
|
b4e65c7dae | ||
|
|
1bcb639dd6 | ||
|
|
f4d9f05806 | ||
|
|
fb037eb56b | ||
|
|
21a2ad89f2 | ||
|
|
fc05d5dc68 | ||
|
|
11266c42d9 | ||
|
|
576833a40a | ||
|
|
b1a63d49a6 | ||
|
|
3e3817a0a8 | ||
|
|
3869224b60 | ||
|
|
e9d3cdeec3 | ||
|
|
53b5e83522 | ||
|
|
3a71d5875a | ||
|
|
39246dbede | ||
|
|
1a954ac3c9 | ||
|
|
41b309803c | ||
|
|
4a01aa697c | ||
|
|
48d5b3ee2d | ||
|
|
d590afc2d0 | ||
|
|
3cde0a68aa | ||
|
|
fe0a0e8cf7 | ||
|
|
827533dabf | ||
|
|
8c7253050e | ||
|
|
d411170b49 | ||
|
|
e954b447ff | ||
|
|
603841077f | ||
|
|
9c91986a77 | ||
|
|
f24b3aef10 | ||
|
|
4422abc0c4 | ||
|
|
d40ab65298 | ||
|
|
2cd4fafbe9 | ||
|
|
0daac61d8c | ||
|
|
6eca202fa2 | ||
|
|
1d5616a514 | ||
|
|
f8729ba507 | ||
|
|
3f2dfd2a5d | ||
|
|
80972cf738 | ||
|
|
2412e2d057 | ||
|
|
2ae1b64f64 | ||
|
|
87558e15bd | ||
|
|
aee383f947 | ||
|
|
22a3948985 | ||
|
|
7487122ea3 | ||
|
|
5f50f78581 | ||
|
|
cc71a706e1 | ||
|
|
9eed243a8e | ||
|
|
1d3e45a078 | ||
|
|
b10d57786a | ||
|
|
c2b44e5773 | ||
|
|
5fda7d2a02 | ||
|
|
89bb451dd8 | ||
|
|
016f3a20fb | ||
|
|
df1713cfa1 | ||
|
|
bb14a6b3f1 | ||
|
|
0898eda7a3 | ||
|
|
90157b80b7 | ||
|
|
028aedcd5e | ||
|
|
ad8da667cc | ||
|
|
57ca55901a | ||
|
|
7479b8518e | ||
|
|
d48fad222c | ||
|
|
0c81547457 | ||
|
|
5d519ab279 | ||
|
|
02cc537182 | ||
|
|
13956638ee | ||
|
|
759abf2809 | ||
|
|
fb8f2b1820 | ||
|
|
a3ce73c537 | ||
|
|
d21a27f61e | ||
|
|
e077459d24 | ||
|
|
b0a0d8bee6 | ||
|
|
2cf98d41d6 | ||
|
|
dd59d75d51 | ||
|
|
d1145aff90 | ||
|
|
95cdfde50e | ||
|
|
645ba84182 | ||
|
|
f6aa03a2bc | ||
|
|
3d07c48b6d | ||
|
|
ae1276d3e7 | ||
|
|
007dd98afb | ||
|
|
9d537bbfea | ||
|
|
b639546b9d | ||
|
|
9ce94ab4e7 | ||
|
|
dc2f4ca575 | ||
|
|
b02ce7473f | ||
|
|
4fdfb5a7de | ||
|
|
ce06f5a85c | ||
|
|
31c5d1b216 | ||
|
|
bfccc3aeee | ||
|
|
3f4ef82c5e | ||
|
|
6c6f2f5371 | ||
|
|
7026c1458f | ||
|
|
f131ae5e0c | ||
|
|
dc6681b640 | ||
|
|
2462c722a8 | ||
|
|
fa2dd6cd14 | ||
|
|
bc38f922ba | ||
|
|
29ff72356a | ||
|
|
c5a192e7b9 | ||
|
|
5f10c814f8 | ||
|
|
53273f679b | ||
|
|
27cfef507e | ||
|
|
71ee1929c2 | ||
|
|
8f4e626dd0 | ||
|
|
4022a5c88f | ||
|
|
689f428ba0 | ||
|
|
2a398b0769 | ||
|
|
c54814ba55 | ||
|
|
8832c250af | ||
|
|
f2bbb2b75c | ||
|
|
cec55d37c4 | ||
|
|
d30f343489 | ||
|
|
1cd2f10ffb | ||
|
|
1efdb40a04 | ||
|
|
07452245d6 | ||
|
|
fa7ea2335f | ||
|
|
1d6a12bcab | ||
|
|
1e017301cd | ||
|
|
15578f8457 | ||
|
|
d914ebac16 | ||
|
|
a595ff24fb | ||
|
|
01f0fed13f | ||
|
|
e08e9c922e | ||
|
|
d8ed3a54e1 | ||
|
|
1978a96699 | ||
|
|
6b1d1f2164 | ||
|
|
0ec2813118 | ||
|
|
331f8df8c0 | ||
|
|
c96e1e0e0d | ||
|
|
c8d717eee1 | ||
|
|
ef6a7efdaf | ||
|
|
3df42f8a8e | ||
|
|
33133f9a4a | ||
|
|
e30e98aeff | ||
|
|
1d6fef324c | ||
|
|
520e6eecd1 | ||
|
|
999511813e | ||
|
|
64dc43c35a | ||
|
|
9e30af648e | ||
|
|
59646e5027 | ||
|
|
55a3cd018e | ||
|
|
c8ff803127 | ||
|
|
0d3ad13763 | ||
|
|
f6a0831fab | ||
|
|
4666ba0eea | ||
|
|
65d4028a4d | ||
|
|
0ff34ecdab | ||
|
|
f20cc2af2b | ||
|
|
a4ca8cde26 | ||
|
|
10e80655da | ||
|
|
3ccb4c9d90 | ||
|
|
4159aa7e6e | ||
|
|
b544a21f5f | ||
|
|
57e9fe0d0b | ||
|
|
dec6423afc | ||
|
|
3f5e85a62b | ||
|
|
febffbf336 | ||
|
|
ef3471c646 | ||
|
|
2fe2a2c80c | ||
|
|
715c4816f5 | ||
|
|
c80fa8f0c7 | ||
|
|
0b3aad8e47 | ||
|
|
1462ac6d32 | ||
|
|
0269cc3e32 | ||
|
|
cbc49f1b58 | ||
|
|
df24227d5f | ||
|
|
9f15dc52c5 | ||
|
|
ecdb64bd76 | ||
|
|
c23ca6a4e3 | ||
|
|
0efc33fa43 | ||
|
|
3d8fb4feca | ||
|
|
80e3b4bd2c | ||
|
|
e2af951ffa | ||
|
|
a3379769c0 | ||
|
|
625fa333ea | ||
|
|
5b08f9c1aa | ||
|
|
cd5fc39a6e | ||
|
|
ac14688c28 | ||
|
|
7640998245 | ||
|
|
a169af358f | ||
|
|
b990514f0d | ||
|
|
fa302c9068 | ||
|
|
6f1d9a0592 | ||
|
|
bd98cd9daa | ||
|
|
50a1ec1c52 | ||
|
|
8e1daa81ea | ||
|
|
38d97c9383 | ||
|
|
2a071f41a3 | ||
|
|
ce5b30cb31 | ||
|
|
d450353239 | ||
|
|
4494a85ba6 | ||
|
|
f551593ca8 | ||
|
|
6666314227 | ||
|
|
0c42e5041f | ||
|
|
849af16d7a | ||
|
|
630cca3264 | ||
|
|
c4328fb322 | ||
|
|
13e2fff9ea | ||
|
|
76ac34db9c | ||
|
|
5803e4e47b | ||
|
|
85090e3196 | ||
|
|
c1f08c43fd | ||
|
|
ca67bc9e9a | ||
|
|
f69c312116 | ||
|
|
c01a6df6ab | ||
|
|
bb135369ed | ||
|
|
43ea011495 | ||
|
|
cfe400f668 | ||
|
|
1c2c0c207e | ||
|
|
c9f0d0fce1 | ||
|
|
a8e190e78a | ||
|
|
257feaa392 | ||
|
|
1481762085 | ||
|
|
0e47aa13a1 | ||
|
|
a1f3be3afd | ||
|
|
b9fbd362d9 | ||
|
|
6606f5725a | ||
|
|
a6bcf4f574 | ||
|
|
eb27b6bd76 | ||
|
|
3b1b1ba88e | ||
|
|
d472b1018e | ||
|
|
ec9bd7f5a4 | ||
|
|
d5a8b4ff6b | ||
|
|
da21fbfec5 | ||
|
|
b949d4a261 | ||
|
|
5067f45a83 | ||
|
|
c3d011b5be | ||
|
|
302cd1b322 | ||
|
|
d5fe78b891 | ||
|
|
d7873c3668 | ||
|
|
816a8405d9 | ||
|
|
c55cb093f9 | ||
|
|
a02e23b674 | ||
|
|
3c8fea1b4b | ||
|
|
295f514108 | ||
|
|
913c81b5d9 | ||
|
|
1f2db3a559 | ||
|
|
114b6f30b4 | ||
|
|
b0b7cfbaa5 | ||
|
|
7f600ab680 | ||
|
|
0ccdd645bc | ||
|
|
9ace74979e | ||
|
|
9649b7ab48 | ||
|
|
d2d410527d | ||
|
|
f48f922416 | ||
|
|
377a7bb219 | ||
|
|
d2ffe89a4d | ||
|
|
3c0019ab86 | ||
|
|
21636bce53 | ||
|
|
0b3e29b453 | ||
|
|
650c2f14e6 | ||
|
|
25a45e1eba | ||
|
|
1f7f41a1ab | ||
|
|
c4b52471d7 | ||
|
|
3554e65fda | ||
|
|
58ad817c74 | ||
|
|
55efa84cb8 | ||
|
|
7c78d51856 | ||
|
|
7df9fb3ead | ||
|
|
4fe9ec778f | ||
|
|
708f4d3ba2 | ||
|
|
64cdfc8a7c | ||
|
|
9be3b94fb8 | ||
|
|
a348828e17 | ||
|
|
bd626856ee | ||
|
|
ad37acae04 | ||
|
|
4101a01624 | ||
|
|
c1f21d6a9e | ||
|
|
0274593c1a | ||
|
|
c4b0384ec6 | ||
|
|
e8b74fb4fa | ||
|
|
bf58427578 | ||
|
|
d595e35d0a | ||
|
|
199f089acc | ||
|
|
1a62adf8c9 | ||
|
|
c8329a9079 | ||
|
|
1840d50c51 | ||
|
|
1984d794bd | ||
|
|
98e9960b8a | ||
|
|
1b17ebe75e | ||
|
|
615ffff3ca | ||
|
|
7d8c54b7b9 | ||
|
|
37cac945d7 | ||
|
|
ed111a8863 | ||
|
|
b6cb0e033a | ||
|
|
8274bf6bcf | ||
|
|
844d792a9a | ||
|
|
fb7298cbc7 | ||
|
|
792e73cd50 | ||
|
|
1c4c7b5d41 | ||
|
|
9fea419c52 | ||
|
|
c78b5ddf0d | ||
|
|
2b1b3095d1 | ||
|
|
9f09db82df | ||
|
|
a29a7f441b | ||
|
|
99e0744cde | ||
|
|
64cf5fce96 | ||
|
|
aea5de6571 | ||
|
|
9c5739619e | ||
|
|
eea44a49a2 | ||
|
|
ea88338da0 | ||
|
|
857b7f7752 | ||
|
|
9368c6496f | ||
|
|
a801d63db5 | ||
|
|
871e126509 | ||
|
|
a6206de18a | ||
|
|
8960007c0c | ||
|
|
e019db9fdb | ||
|
|
7bd7b9128a | ||
|
|
de2dbe02e6 | ||
|
|
4b12896f89 | ||
|
|
0937e7de78 | ||
|
|
d23c74a8be | ||
|
|
fcaab92837 | ||
|
|
fb335f7824 | ||
|
|
acb0ac9333 | ||
|
|
04ab11df63 | ||
|
|
eed3f4f839 | ||
|
|
73bd368b66 | ||
|
|
6f5e3d0829 | ||
|
|
18ce1361ef | ||
|
|
db7b26f315 | ||
|
|
7770b17ee7 | ||
|
|
4a07c8cdb9 | ||
|
|
c144ab7857 | ||
|
|
73765194e1 | ||
|
|
f674c88870 | ||
|
|
6b097d5f9e | ||
|
|
44b5e1342e | ||
|
|
3705547f92 | ||
|
|
545555c06c | ||
|
|
b246201e6b | ||
|
|
729be9aea6 | ||
|
|
99205e09cb | ||
|
|
0ec0680779 | ||
|
|
1f646e2b61 | ||
|
|
2b6f037031 | ||
|
|
62d73cb2cf | ||
|
|
d8c4365480 | ||
|
|
a707767170 | ||
|
|
b904c404bb | ||
|
|
9ca3516d39 | ||
|
|
58fa288158 | ||
|
|
38f87f38c2 | ||
|
|
42afe64eb3 | ||
|
|
2a09efbde3 | ||
|
|
7685bbbdf4 | ||
|
|
da12c5512d | ||
|
|
6b7bed5376 | ||
|
|
30da7363a0 | ||
|
|
748f85b33f | ||
|
|
9190b12c2e | ||
|
|
6d1348bb3e | ||
|
|
3e2823bd18 | ||
|
|
4b89c87336 | ||
|
|
fc7438bcda | ||
|
|
44604ef0ee | ||
|
|
69c06f820e | ||
|
|
dcc5fa9451 | ||
|
|
5bcfa0af15 | ||
|
|
748df3e75a | ||
|
|
43a6e9526e | ||
|
|
05d962c004 | ||
|
|
daaf02865e | ||
|
|
947d230e20 | ||
|
|
adb9923f11 | ||
|
|
28865821d5 | ||
|
|
34ee199967 | ||
|
|
1d5440541f | ||
|
|
248aec6d41 | ||
|
|
63b5368640 | ||
|
|
15d83baed9 | ||
|
|
1afcddd49d | ||
|
|
9b70c8a1d1 | ||
|
|
0c037083a9 | ||
|
|
5d13964200 | ||
|
|
4a697a1eb3 | ||
|
|
35c1f8a24b | ||
|
|
f3cab378cc | ||
|
|
362bbc1e22 | ||
|
|
87cf90e892 | ||
|
|
0e30a8fd34 | ||
|
|
6ad19f9a74 | ||
|
|
41db66d6fc | ||
|
|
c3897e2922 | ||
|
|
2e1212029e | ||
|
|
5b6559e084 | ||
|
|
32a3153566 | ||
|
|
b6cf4057d0 | ||
|
|
d5968313b3 | ||
|
|
7638e00caa | ||
|
|
25737614cf | ||
|
|
ffe12feafa | ||
|
|
71c101a0fa | ||
|
|
a00477e510 | ||
|
|
c3b4b6e96c | ||
|
|
ae8f210306 | ||
|
|
139b0f4870 | ||
|
|
8749583563 | ||
|
|
54fa28a305 | ||
|
|
ca5ced95d7 | ||
|
|
5c018e302d | ||
|
|
716f5a4878 | ||
|
|
464c871e79 | ||
|
|
56a8596fe9 | ||
|
|
8ba0110b24 | ||
|
|
75ce232c9c | ||
|
|
602deafe0a | ||
|
|
07fab67bb1 | ||
|
|
6b21d0af38 | ||
|
|
9c99c74835 | ||
|
|
05c797f133 | ||
|
|
894f364785 | ||
|
|
b607828b9d | ||
|
|
32c87e29aa | ||
|
|
ee8aa518e5 | ||
|
|
aebce6444e | ||
|
|
3ee7537cc8 | ||
|
|
7091428842 | ||
|
|
6d79796597 | ||
|
|
fbf0bbef5c | ||
|
|
50bea20332 | ||
|
|
22f4401661 | ||
|
|
0e92f332da | ||
|
|
7921dc7e37 | ||
|
|
0b9f4aebc8 | ||
|
|
2143a67c8d | ||
|
|
3b5d81397c | ||
|
|
af89d59508 | ||
|
|
74f7e9b4c9 | ||
|
|
ddac78a1dd | ||
|
|
0591ba2589 | ||
|
|
f602540e53 | ||
|
|
05194dded6 | ||
|
|
957cba4743 | ||
|
|
2a41f5c60f | ||
|
|
f6eab90d0b | ||
|
|
f415c93d8b | ||
|
|
cf8e97a71b | ||
|
|
ac0c464e5b | ||
|
|
4457e96f9b | ||
|
|
ddb765f758 | ||
|
|
cd80e17ce8 | ||
|
|
edb77f865f | ||
|
|
a2e3e4fced | ||
|
|
c3431ff1af | ||
|
|
62ebac1d4f | ||
|
|
3f4bff91cd | ||
|
|
fc00b7501c | ||
|
|
2ba3adef60 | ||
|
|
fba0b33855 | ||
|
|
f33ba7493c | ||
|
|
1a9f3e144e | ||
|
|
0732a00253 | ||
|
|
2f5ae09380 | ||
|
|
1d0a80e362 | ||
|
|
7e70887486 | ||
|
|
99e619ca77 | ||
|
|
875a5f3081 | ||
|
|
23cac43c89 | ||
|
|
6e44e3c729 | ||
|
|
8a2be493cb | ||
|
|
b5a1f8aec4 | ||
|
|
d7b4cc8c6c | ||
|
|
318be60fa9 | ||
|
|
56cbe84675 | ||
|
|
91db8c2e5d | ||
|
|
e02ca45688 | ||
|
|
f864d67dbc | ||
|
|
863767bc9f | ||
|
|
dca7968160 | ||
|
|
2fd96adf12 | ||
|
|
ec64c27225 | ||
|
|
0dd355a984 | ||
|
|
495f9835f2 | ||
|
|
eb70c9cef1 | ||
|
|
93c051e1a7 | ||
|
|
e86e48703c | ||
|
|
145a7fe255 | ||
|
|
ba555c5a34 | ||
|
|
b2f5e6ceb7 | ||
|
|
5eb19f802b | ||
|
|
23131b83cc | ||
|
|
2ec67be1e9 | ||
|
|
e0807d0fb3 | ||
|
|
25c0384af3 | ||
|
|
a10c5eb812 | ||
|
|
5cb28ee173 | ||
|
|
b486d160a8 | ||
|
|
afd4517c53 | ||
|
|
dc9461d2cc | ||
|
|
433533050c | ||
|
|
f9e45829b1 | ||
|
|
d4e50f8263 | ||
|
|
6b04025154 | ||
|
|
17f8641ece | ||
|
|
3780da9230 | ||
|
|
5f6130f3d0 | ||
|
|
a5acb4cc84 | ||
|
|
27086258a6 | ||
|
|
83194711c3 | ||
|
|
d809bc6240 | ||
|
|
51a3d39536 | ||
|
|
c2a09a1e85 | ||
|
|
11ea30d1ed | ||
|
|
8f916fde3c | ||
|
|
26aac40a50 | ||
|
|
9f2fbc07fa | ||
|
|
502cb1dd74 | ||
|
|
c92df2a45b | ||
|
|
f0b304a0c6 | ||
|
|
9ad80e96c2 | ||
|
|
3e53b6f96f | ||
|
|
d18325dea7 | ||
|
|
46c9ec665a | ||
|
|
d77dda57c2 | ||
|
|
133e1b134b | ||
|
|
bdf3fafbac | ||
|
|
a8098ce577 | ||
|
|
807d903176 | ||
|
|
0c546d9a05 | ||
|
|
6939eda25d | ||
|
|
be00cc356c | ||
|
|
5fd61e7460 | ||
|
|
a82ac381aa | ||
|
|
a0500b170a | ||
|
|
0bc7d51380 | ||
|
|
eb86e00a79 | ||
|
|
d33d3cae34 | ||
|
|
e410768f7f | ||
|
|
421b7f81fd | ||
|
|
747f025819 | ||
|
|
66e0f69437 | ||
|
|
4b59c5aa07 | ||
|
|
f7dbcd1fca | ||
|
|
499d8aa343 | ||
|
|
aeb7a24789 | ||
|
|
946562e2a5 | ||
|
|
558ec79281 | ||
|
|
f113998db1 | ||
|
|
f39724354c | ||
|
|
db1dd2bf6a | ||
|
|
36dd674d93 | ||
|
|
55eca1c7b2 | ||
|
|
d17795a9a9 | ||
|
|
68d59280d8 | ||
|
|
f8afad537f | ||
|
|
468d82d9f7 | ||
|
|
54245b2520 | ||
|
|
1af49ff41d | ||
|
|
a21d4daae0 | ||
|
|
7825d579b4 | ||
|
|
2e4b0128fa | ||
|
|
a19da2b7c9 | ||
|
|
57e79dffb1 | ||
|
|
8c18ced1a7 | ||
|
|
8dd8253afb | ||
|
|
29370b8740 | ||
|
|
4501c4f5cd | ||
|
|
192b1a1bd1 | ||
|
|
abc64d7e19 | ||
|
|
6c47c82c78 | ||
|
|
edb86a96cc | ||
|
|
0f229274e6 | ||
|
|
78cfcf3206 | ||
|
|
e41f3e4131 | ||
|
|
0170bdc737 | ||
|
|
d38f0f35f9 | ||
|
|
c1055478ef | ||
|
|
88ce7d5d82 | ||
|
|
7eec5856a3 | ||
|
|
e357a9c813 | ||
|
|
967b2258b9 | ||
|
|
f5c4a78fb1 | ||
|
|
7e2c6a3e62 | ||
|
|
89c473aac7 | ||
|
|
c9efab145d | ||
|
|
89be8f9d56 | ||
|
|
a5b0a78828 | ||
|
|
6be213707b | ||
|
|
0e55883f05 | ||
|
|
033c8f432d | ||
|
|
dc9bb23ade | ||
|
|
629c25208d | ||
|
|
bf6aa0132c | ||
|
|
4dfe51aa01 | ||
|
|
e735c69371 | ||
|
|
ae41d2f5c1 | ||
|
|
dc00bab703 | ||
|
|
d06fbfc7f3 | ||
|
|
e09d83368c | ||
|
|
1ddcc7b3fc | ||
|
|
db6c457d5c | ||
|
|
1e3b3f6a5e | ||
|
|
26c755f312 | ||
|
|
095dbdbf59 | ||
|
|
f9a87273bb | ||
|
|
b6dbad7d88 | ||
|
|
8400db5161 | ||
|
|
2e2f6ca4de | ||
|
|
04d063e759 | ||
|
|
e50171cdf4 | ||
|
|
ffd79887c1 | ||
|
|
994023df1e | ||
|
|
e8756d084b | ||
|
|
919f7f5ae7 | ||
|
|
f98f6ff9e0 | ||
|
|
b70ea3d72a | ||
|
|
6eba76bd26 | ||
|
|
fee5f98406 | ||
|
|
551552f67f | ||
|
|
6cff923227 | ||
|
|
1399f55ed4 | ||
|
|
79fdc2ef78 | ||
|
|
f4a12a2a3b | ||
|
|
edf7bf23e3 | ||
|
|
1887a32ca2 | ||
|
|
a1405af086 | ||
|
|
de487d56be | ||
|
|
5fd9819f5f | ||
|
|
b86255479c | ||
|
|
67218b0d19 | ||
|
|
cdad22386e | ||
|
|
cb6a705473 | ||
|
|
e0523db53d | ||
|
|
c49bca76d7 | ||
|
|
3d598445e3 | ||
|
|
949c597508 | ||
|
|
ca32702aa0 | ||
|
|
0ccc5d3faa | ||
|
|
4c8f4dcdfc | ||
|
|
d64fa185db | ||
|
|
cd33dc926f | ||
|
|
fd63105282 | ||
|
|
dda7fcf987 | ||
|
|
b597a36454 | ||
|
|
b2636aa4c1 | ||
|
|
b3fe37dd3d | ||
|
|
d62aeb54b9 | ||
|
|
dab578a096 | ||
|
|
42ff8d51c0 | ||
|
|
68fe393de4 | ||
|
|
4493457cfa | ||
|
|
5b49d3629c | ||
|
|
244330f96e | ||
|
|
7f002b3158 | ||
|
|
d3d3a58f6e | ||
|
|
bec8bb64e1 | ||
|
|
580a711cb1 | ||
|
|
23de4dd79e | ||
|
|
21eb34fec7 | ||
|
|
4248a8dadd | ||
|
|
5ac0392c81 | ||
|
|
10e4f45ac0 | ||
|
|
52531187b6 | ||
|
|
91238492d9 | ||
|
|
cd048ea1e4 | ||
|
|
72a1732d4f | ||
|
|
3c4d46ec33 | ||
|
|
ef8b444526 | ||
|
|
cb5c20b678 | ||
|
|
9a076a7d97 | ||
|
|
b3bc9aa5a8 | ||
|
|
ae0bd1f240 | ||
|
|
2f08be65dd | ||
|
|
1276f80f98 | ||
|
|
dc747fad0b | ||
|
|
bbbf496e55 | ||
|
|
0be0639df2 | ||
|
|
aa41235bb1 | ||
|
|
67e0819a58 | ||
|
|
c34cb47590 | ||
|
|
3bad978a1a | ||
|
|
eb9a8113a3 | ||
|
|
bceeafc8fd | ||
|
|
7ce64c3b69 | ||
|
|
e567a01fec | ||
|
|
41ad317a6d | ||
|
|
9ca7b53525 | ||
|
|
63dc8d573e | ||
|
|
5d97bb6ee7 | ||
|
|
9d99e7dd5b | ||
|
|
1a8785d923 | ||
|
|
b8ff60572a | ||
|
|
e197f1da4f | ||
|
|
2d528c3c8d | ||
|
|
dc20615b37 | ||
|
|
047ac39af8 | ||
|
|
4c1b8b2c6f | ||
|
|
861ed0de56 | ||
|
|
97864349cc | ||
|
|
e8fd10468f | ||
|
|
332e9e8a34 | ||
|
|
cf1a09c9a7 | ||
|
|
146884c135 | ||
|
|
b875ca4ec9 | ||
|
|
9570205b8a | ||
|
|
947221b4fb | ||
|
|
0579065c4c | ||
|
|
df27520950 | ||
|
|
aacefe5192 | ||
|
|
62a7e09e0d | ||
|
|
a6d0384463 | ||
|
|
dc81749d44 | ||
|
|
11423e276a | ||
|
|
4ca664384d | ||
|
|
287ddc84da | ||
|
|
5c80a1463b | ||
|
|
943166ff54 | ||
|
|
ff142d955f | ||
|
|
8d2fbb7eb6 | ||
|
|
d91fcfedd7 | ||
|
|
ffc4ad7fd3 | ||
|
|
fe8f993a09 | ||
|
|
2e0424da1b | ||
|
|
4b24a4110d | ||
|
|
d732f1fc51 | ||
|
|
c0cc07ca93 | ||
|
|
32af1f92eb | ||
|
|
d2e42fb3ee | ||
|
|
96f78dabcc | ||
|
|
7b58635b7a | ||
|
|
a638b6d4f2 | ||
|
|
9291b82212 | ||
|
|
c338ddedc1 | ||
|
|
02d809987a | ||
|
|
2779bfdf01 | ||
|
|
1cfebe3f24 | ||
|
|
c08ed0777d | ||
|
|
7378b389fe | ||
|
|
68c7f58148 | ||
|
|
9e70dd7aea | ||
|
|
9afd1a7e2a | ||
|
|
67893bd836 | ||
|
|
c9d759856f | ||
|
|
52575a7a8c | ||
|
|
cbd74dfa4b | ||
|
|
cc1606c4f0 | ||
|
|
34a3d09c10 | ||
|
|
53b7ad097a | ||
|
|
c06825e675 | ||
|
|
9913f90294 | ||
|
|
7c47f7c73b | ||
|
|
8cacec6c93 | ||
|
|
600279ff2b | ||
|
|
8b678034a2 | ||
|
|
b846e12cee | ||
|
|
c739918a1d | ||
|
|
ca369ed8d1 | ||
|
|
b3ebd57893 | ||
|
|
b88fd4b669 | ||
|
|
acf5d5e908 | ||
|
|
b04c6f55ab | ||
|
|
7aac904d3c | ||
|
|
77f2925eb3 | ||
|
|
a90bf53050 | ||
|
|
e1a47955c4 | ||
|
|
1c64281504 | ||
|
|
4f767a442f | ||
|
|
d8196abb41 | ||
|
|
efd18a5221 | ||
|
|
c13002a7cf | ||
|
|
16297b41e4 | ||
|
|
9efee1f3fd | ||
|
|
97801c76d1 | ||
|
|
f0c98a8d8a | ||
|
|
9a68dda690 | ||
|
|
9703f07095 | ||
|
|
e3348774d5 | ||
|
|
5b6ee8d932 | ||
|
|
c226e12e98 | ||
|
|
02a2c19bf6 | ||
|
|
7d3e9bd163 | ||
|
|
5e68bddd6b | ||
|
|
1d3b96559f | ||
|
|
65350fb284 | ||
|
|
882dfc4741 | ||
|
|
83671bae11 | ||
|
|
f38613bb8d | ||
|
|
43daa3c38f | ||
|
|
f3982278e6 | ||
|
|
d214e31e38 | ||
|
|
ce198b356f | ||
|
|
aa3e354dd5 | ||
|
|
cd50c3984e | ||
|
|
7780bb0835 | ||
|
|
5e41163c09 | ||
|
|
e2dbf474d8 | ||
|
|
9bc2d17db3 | ||
|
|
f09e7dd6b3 | ||
|
|
171768b257 | ||
|
|
2ba75947e3 | ||
|
|
6ec8ea5fe1 | ||
|
|
d6d4099b08 | ||
|
|
7d20c7c120 | ||
|
|
a422c6c644 | ||
|
|
9737e2d4ed | ||
|
|
a3d7a1a2ed | ||
|
|
2290b36a60 | ||
|
|
758db5b001 | ||
|
|
399f853aa9 | ||
|
|
9cd1c62ffa | ||
|
|
e3d9a2c985 | ||
|
|
498f5148a1 | ||
|
|
8640390354 | ||
|
|
56e6944f92 | ||
|
|
e47c2094dd | ||
|
|
1adda1a865 | ||
|
|
356396f6c3 | ||
|
|
5ef6847c83 | ||
|
|
155170e061 | ||
|
|
13685e4388 | ||
|
|
0be3deac04 | ||
|
|
3729e3401a | ||
|
|
de5476b910 | ||
|
|
ba2542e0c2 | ||
|
|
6efab9994b | ||
|
|
6984822651 | ||
|
|
7e1e44dc62 | ||
|
|
59b17408c6 | ||
|
|
4cc0f4f2f4 | ||
|
|
d0d7be2983 | ||
|
|
f5c7691e7a | ||
|
|
cbca7ba17a | ||
|
|
e460e37927 | ||
|
|
782c77def0 | ||
|
|
3d3cecf34d | ||
|
|
c67907f872 | ||
|
|
7f45922477 | ||
|
|
b75a6767e8 | ||
|
|
0150f5f926 | ||
|
|
98bebea186 | ||
|
|
56a4cbfc19 | ||
|
|
60220b5b83 | ||
|
|
304146395d | ||
|
|
a5635a782f | ||
|
|
df66fb784c | ||
|
|
9a9a1ce716 | ||
|
|
5c3a1ca3eb | ||
|
|
95226eed34 | ||
|
|
33a61daca9 | ||
|
|
6c71397839 | ||
|
|
9fba60d754 | ||
|
|
a115ee2fba | ||
|
|
31e2d80802 | ||
|
|
bbbd3e8ad1 | ||
|
|
9edc233ee7 | ||
|
|
c030fac063 | ||
|
|
36401996a5 | ||
|
|
c4a57d2fbe | ||
|
|
f0e4fda91b | ||
|
|
d95d8e93b9 | ||
|
|
2ce3ae15bf | ||
|
|
c592c8b549 | ||
|
|
9f8afc3ce9 | ||
|
|
2b4e7abe21 | ||
|
|
3c0ea943b0 | ||
|
|
9757af64f1 | ||
|
|
b24255db5e | ||
|
|
5aa726f723 | ||
|
|
e42a4816ac | ||
|
|
4137501136 | ||
|
|
f72d263ecb | ||
|
|
41bc99cc17 | ||
|
|
e71c5057ac | ||
|
|
4190ba4790 | ||
|
|
1f1e7edd2a | ||
|
|
b4151987ad | ||
|
|
6fbb923377 | ||
|
|
1743f57c9c | ||
|
|
4c06b1802d | ||
|
|
5c222a8684 | ||
|
|
ad837a4f68 | ||
|
|
8f9884ade2 | ||
|
|
8ae4fed70a | ||
|
|
349820a7d1 | ||
|
|
5bbdaaf114 | ||
|
|
455eb537ac | ||
|
|
a37efaa61b | ||
|
|
3a98e867cb | ||
|
|
15d7b9ed6d | ||
|
|
cc87dce84d | ||
|
|
c651866df3 | ||
|
|
e19782fb04 | ||
|
|
17d0b6dd0b | ||
|
|
201e025ee8 | ||
|
|
448c43ff43 | ||
|
|
cd292b687f | ||
|
|
19ee2e65b8 | ||
|
|
a276545019 | ||
|
|
b892818d23 | ||
|
|
28b8432101 | ||
|
|
772f808741 | ||
|
|
cdd6008fbb | ||
|
|
e1214a9ccc | ||
|
|
426e8266c5 | ||
|
|
821232a3c4 | ||
|
|
6a8f254286 | ||
|
|
1af4aa7ac9 | ||
|
|
b031cab8df | ||
|
|
56a60b7f0a | ||
|
|
1e6d856921 | ||
|
|
53ecdac6f1 | ||
|
|
3b6636b0ef | ||
|
|
5102a5d757 | ||
|
|
869d99ce0f | ||
|
|
2d2739c33a | ||
|
|
b7bd9bd90e | ||
|
|
b7954d8a33 | ||
|
|
7b7c79acb3 | ||
|
|
4b76119c68 | ||
|
|
10b721602f | ||
|
|
21297be965 | ||
|
|
85f3189476 | ||
|
|
cf1a4a6345 | ||
|
|
9294e3e676 | ||
|
|
85c4df40cd | ||
|
|
62e0250560 | ||
|
|
cd72744191 | ||
|
|
c38fc91d9d | ||
|
|
b76d1302b1 | ||
|
|
bbbcbd2b23 | ||
|
|
6c53b6664f | ||
|
|
6f49a10c0c | ||
|
|
ad190e72fe | ||
|
|
259782bc5e | ||
|
|
98ed2982ec | ||
|
|
27dd8f698e | ||
|
|
0bb88f2eda | ||
|
|
0886756196 | ||
|
|
1232a9d64c | ||
|
|
a0ef0d32fe | ||
|
|
96d14d009d | ||
|
|
1fcc337ab7 | ||
|
|
0f2c58a7cc | ||
|
|
f4c8d08849 | ||
|
|
5effaf1761 | ||
|
|
940432bfee | ||
|
|
3fa3b411f6 | ||
|
|
59aaa96760 | ||
|
|
f07e3fd77f | ||
|
|
0fdcdfd35b | ||
|
|
ed3de3f984 | ||
|
|
f1840c82ae | ||
|
|
b1ae386d8f | ||
|
|
55d0e8bf1e | ||
|
|
d5ffdf4330 | ||
|
|
08b47b0ba7 | ||
|
|
bae367bf31 | ||
|
|
d7e05cabb9 | ||
|
|
7cf8aa2e57 | ||
|
|
8225ee4fc6 | ||
|
|
ae72763b86 | ||
|
|
2653a66f19 | ||
|
|
0272238cb6 | ||
|
|
87bb8a408c | ||
|
|
38c7d87300 | ||
|
|
544251e681 | ||
|
|
79079a1588 | ||
|
|
c90677d575 | ||
|
|
544eab8907 | ||
|
|
9b8fbbe710 | ||
|
|
3cf40177fb | ||
|
|
3a9b0d3b4f | ||
|
|
30046f9723 | ||
|
|
1944178657 | ||
|
|
aa82816129 | ||
|
|
ae6582d8c7 | ||
|
|
d865a554b1 | ||
|
|
a5b87a0d48 | ||
|
|
56366d252e | ||
|
|
40d0bbcd04 | ||
|
|
337863256a | ||
|
|
d536bf88ec | ||
|
|
5a94b0cafc | ||
|
|
d50dbef8b0 | ||
|
|
6c22baa03c | ||
|
|
7e6c59b984 | ||
|
|
1e53c43669 | ||
|
|
e1d6198d07 | ||
|
|
3e95f45a26 | ||
|
|
932bb5bb7c | ||
|
|
bc217cf94d | ||
|
|
9cd63043c7 | ||
|
|
d574b31723 | ||
|
|
f9f90a78aa | ||
|
|
2751b27d8e | ||
|
|
763cd2a116 | ||
|
|
e35c881c60 | ||
|
|
5ddd49417e | ||
|
|
a536aeb484 | ||
|
|
d556f0600c | ||
|
|
86a070ba95 | ||
|
|
8b43d65db7 | ||
|
|
a442a10435 | ||
|
|
0f19d7e7a3 | ||
|
|
40b55f8623 | ||
|
|
f0a9cb7eb5 | ||
|
|
baf1cd6f6f | ||
|
|
363da11e66 | ||
|
|
a6ed269baf | ||
|
|
bdd345a093 | ||
|
|
c5ebba6a5f | ||
|
|
f22219bc24 | ||
|
|
b2c586c124 | ||
|
|
d4e2e3855a | ||
|
|
c14486d19c | ||
|
|
59b965453e | ||
|
|
7202c98a32 | ||
|
|
4216da2c74 | ||
|
|
f095be3ebf | ||
|
|
6581ab3f07 | ||
|
|
c8ef22ea1f | ||
|
|
bd32283899 | ||
|
|
ef180673e3 | ||
|
|
50b0432d75 | ||
|
|
7de9b3831a | ||
|
|
cca505e8d7 | ||
|
|
dc1a243d40 | ||
|
|
a905829b4b | ||
|
|
b02409072e | ||
|
|
b4a187a288 | ||
|
|
afcdf55278 | ||
|
|
57009f9900 | ||
|
|
30088827f8 | ||
|
|
3cb256e558 | ||
|
|
cc387a31a8 | ||
|
|
255d499dd1 | ||
|
|
035e220e4a | ||
|
|
12ef109fb1 | ||
|
|
7d72f76698 | ||
|
|
33e4902051 | ||
|
|
5bbdf2fba6 | ||
|
|
6f259cefd2 | ||
|
|
8ab3b8216d | ||
|
|
e93f03c1e4 | ||
|
|
38c207c315 | ||
|
|
2bdc69ea0b | ||
|
|
6daf9a2b07 | ||
|
|
9f6ffa3b2e | ||
|
|
e0d5aef2a3 | ||
|
|
b61bc913ca | ||
|
|
2ac08c9d70 | ||
|
|
9e37910ee5 | ||
|
|
0b8805bc3d | ||
|
|
eadf410bbe | ||
|
|
b735c4a72a | ||
|
|
98f78cf864 | ||
|
|
7d726253df | ||
|
|
91824ad6c8 | ||
|
|
55dc0cf6e0 | ||
|
|
808cf6778b | ||
|
|
d1c3493765 | ||
|
|
85c11d850d | ||
|
|
10680abda7 | ||
|
|
200738a370 | ||
|
|
6a8b73a2f3 | ||
|
|
a66b7764f6 | ||
|
|
0be1c37af5 | ||
|
|
afe52a9cf8 | ||
|
|
6ef0db07d1 | ||
|
|
960163ea48 | ||
|
|
ec9d4c1f18 | ||
|
|
7f67534357 | ||
|
|
f411b856f8 | ||
|
|
e37cc98b6d | ||
|
|
ac5787fa65 | ||
|
|
e7e03c2743 | ||
|
|
106c5f8f5c | ||
|
|
83edce7155 | ||
|
|
dff02a2998 | ||
|
|
7769513ca5 | ||
|
|
6014de4ee7 | ||
|
|
73aedd8a72 | ||
|
|
ec921b81ba | ||
|
|
6c22afe293 | ||
|
|
efb747ae43 | ||
|
|
5028696803 | ||
|
|
ae3ec197df | ||
|
|
2970f04de9 | ||
|
|
9d95878f07 | ||
|
|
0c9ddbbfc5 | ||
|
|
49733e1be3 | ||
|
|
c648e063d0 | ||
|
|
3822d8810c | ||
|
|
0e286885a9 | ||
|
|
15dc8460b4 | ||
|
|
bb1d9165e4 | ||
|
|
b3ad7dfa6d | ||
|
|
3cc51b29df | ||
|
|
78849085f0 | ||
|
|
e3320c4084 | ||
|
|
22e48de898 | ||
|
|
7e6ede5392 | ||
|
|
5a120d6807 | ||
|
|
ca239f0353 | ||
|
|
6a614f832e | ||
|
|
163223d2ae | ||
|
|
5e4f21998b | ||
|
|
afa1845884 | ||
|
|
c5dcdeeeb9 | ||
|
|
0a28808076 | ||
|
|
681addbc44 | ||
|
|
3070b92a1a | ||
|
|
3bc82f8ba2 | ||
|
|
182dffbb2b | ||
|
|
e6e9899fde | ||
|
|
0c8ae83437 | ||
|
|
12304b6c69 | ||
|
|
d4821f4081 | ||
|
|
f1db2b938a | ||
|
|
62a2237b12 | ||
|
|
5b601650c1 | ||
|
|
4fff115484 | ||
|
|
2030d6bedc | ||
|
|
188183f268 | ||
|
|
cc594845f2 | ||
|
|
c2fc6d75f2 | ||
|
|
1ab2060f49 | ||
|
|
91a8c49b97 | ||
|
|
8978d06c91 | ||
|
|
91c14686eb | ||
|
|
ba8724cf5a | ||
|
|
2d85619f08 | ||
|
|
051a214db7 | ||
|
|
1003347044 | ||
|
|
b53ab6b5c6 | ||
|
|
df72ed55f2 | ||
|
|
08795be652 | ||
|
|
ec0e35123a | ||
|
|
07725d6663 | ||
|
|
83285cb60e | ||
|
|
1435bb3c45 | ||
|
|
3860aa554d | ||
|
|
f9f4ab050a | ||
|
|
8488eb63a7 | ||
|
|
8a0fa4c063 | ||
|
|
47ed4c56f3 | ||
|
|
4e342e03f0 | ||
|
|
f63b41b577 | ||
|
|
20890304d0 | ||
|
|
eff3d26529 | ||
|
|
43b0074e9f | ||
|
|
6aae9b8202 | ||
|
|
1d9f2399f1 | ||
|
|
59c66e6c28 | ||
|
|
ef3d4e20a4 | ||
|
|
27ced8e41c | ||
|
|
2441f85244 | ||
|
|
c1aaef52f7 | ||
|
|
f07e641c06 | ||
|
|
14d989aaab | ||
|
|
57f18bb17e | ||
|
|
5627741945 | ||
|
|
dd9a30caed | ||
|
|
478527cfe6 | ||
|
|
94187f16f7 | ||
|
|
166e7afc35 | ||
|
|
b63e2ec1f4 | ||
|
|
6427b9ec4c | ||
|
|
3928e84760 | ||
|
|
d7d4596fff | ||
|
|
277b986d51 | ||
|
|
70fee34609 | ||
|
|
1d9548f814 | ||
|
|
7236d3072e | ||
|
|
ccb994294b | ||
|
|
496fe74085 | ||
|
|
54de76d0a0 | ||
|
|
536652e4dc | ||
|
|
dd26802d13 | ||
|
|
e8d52cf39d | ||
|
|
f805f4b19d | ||
|
|
2d57c82700 | ||
|
|
ca00466318 | ||
|
|
826b9999b3 | ||
|
|
83bf2fcdd6 | ||
|
|
596f2b300a | ||
|
|
f2a9a240e0 | ||
|
|
4c99d651ea | ||
|
|
a003309f46 | ||
|
|
8556d05651 | ||
|
|
3db4eca735 | ||
|
|
a0b639e2b6 | ||
|
|
c807ce6226 | ||
|
|
5201b1530f | ||
|
|
d9a1c49d7f | ||
|
|
7c6f5f13e4 | ||
|
|
36cad8502f | ||
|
|
cfe24e69a0 | ||
|
|
f27ab7a48b | ||
|
|
009e37321d | ||
|
|
fa0e18f327 | ||
|
|
c522db57a9 | ||
|
|
8d052559ca | ||
|
|
4dd8d829c6 | ||
|
|
ffd98aafb7 | ||
|
|
a4a3651e5a | ||
|
|
c7383c18b7 | ||
|
|
213df74971 | ||
|
|
7c94731cb5 | ||
|
|
fe32c2d972 | ||
|
|
f6dce5b285 | ||
|
|
7898136626 | ||
|
|
0eaa59c008 | ||
|
|
508b537916 | ||
|
|
86018220ee | ||
|
|
bdf971b980 | ||
|
|
7690419d07 | ||
|
|
80c93464df | ||
|
|
bdc7ea2b51 | ||
|
|
adb76e1a32 | ||
|
|
d6eda44a04 | ||
|
|
84686dc330 | ||
|
|
45666e1a97 | ||
|
|
ca875bcec4 | ||
|
|
d63d73fe8f | ||
|
|
399c740564 | ||
|
|
2175a47ef1 | ||
|
|
d677d04dd3 | ||
|
|
22312727ef | ||
|
|
18428bba82 | ||
|
|
0f6b4b5d10 | ||
|
|
d711f6a262 | ||
|
|
8709adfb27 | ||
|
|
d36b6eaa23 | ||
|
|
7682132e74 | ||
|
|
b66e5d19eb | ||
|
|
4a3e5f2feb | ||
|
|
4566bbe5d9 | ||
|
|
41a84b36b5 | ||
|
|
448ff1e6b3 | ||
|
|
8b182c107d | ||
|
|
0c37d458df | ||
|
|
242972c94c | ||
|
|
e663012926 | ||
|
|
dc5d77e7a6 | ||
|
|
568e3226a9 | ||
|
|
006093ad61 | ||
|
|
223fa616d3 | ||
|
|
04b2bc9d80 | ||
|
|
172c454082 | ||
|
|
56599be5ff | ||
|
|
c29f5aa8f5 | ||
|
|
c1630600c0 | ||
|
|
fc891e01f9 | ||
|
|
5cf74ff83e | ||
|
|
b1f8fb4b57 | ||
|
|
601106e52b | ||
|
|
c8f27bc351 | ||
|
|
6e9449e32c | ||
|
|
6fff337734 | ||
|
|
59fb944039 | ||
|
|
3e99cfdf88 | ||
|
|
df5b685ba1 | ||
|
|
fe97f748c4 | ||
|
|
cf328af225 | ||
|
|
da8b861fdb | ||
|
|
33a9110500 | ||
|
|
9f2f01d3b0 | ||
|
|
c788e78feb | ||
|
|
9f1cae4adb | ||
|
|
d46ce172d6 | ||
|
|
e2e0a1014a | ||
|
|
03cf8de059 | ||
|
|
bb8d53b553 | ||
|
|
f83618fee1 | ||
|
|
cfd6533fef | ||
|
|
47f8893094 | ||
|
|
1de1a76184 | ||
|
|
3e5aaa96f7 | ||
|
|
d728e60fd7 | ||
|
|
d28eb6c162 | ||
|
|
5b5080204d | ||
|
|
d4edec3521 | ||
|
|
a641361687 | ||
|
|
22f3428ac3 | ||
|
|
6adb265745 | ||
|
|
bf4e3420c1 | ||
|
|
d1792557ee | ||
|
|
4a1b164135 | ||
|
|
798b44be93 | ||
|
|
63079db33b | ||
|
|
6e97f151e2 | ||
|
|
ceb5847dd5 | ||
|
|
9e2b1ea9d3 | ||
|
|
6da4c48255 | ||
|
|
35ee4cb1fc | ||
|
|
ef1f92b9b5 | ||
|
|
6f932f8aad | ||
|
|
9df2c6bd86 | ||
|
|
204ce4415d | ||
|
|
b7331cd76e | ||
|
|
03958a9b57 | ||
|
|
6e1cdd3254 | ||
|
|
f1cc39884e | ||
|
|
bec6880d52 | ||
|
|
10fa3a6c89 | ||
|
|
482370ea0c | ||
|
|
fecc0623c5 | ||
|
|
f50746a25a | ||
|
|
4d9108e34d | ||
|
|
f681dcebfb | ||
|
|
9425ec7dff | ||
|
|
7e7d4f371b | ||
|
|
bf28559433 | ||
|
|
8915ac5932 | ||
|
|
fd4fac3adf | ||
|
|
8aa8fbeefc | ||
|
|
bf983c20f9 | ||
|
|
13e08cef5a | ||
|
|
c1af83c69d | ||
|
|
b68751d060 | ||
|
|
6c4deabb76 | ||
|
|
77503ea5d8 | ||
|
|
d89901cc12 | ||
|
|
335fab6bdf | ||
|
|
0f10913b8b | ||
|
|
26a210373f | ||
|
|
213f994147 | ||
|
|
588a599ecb | ||
|
|
c08a1ff422 | ||
|
|
a21499405c | ||
|
|
43150c5fea | ||
|
|
41bbe83912 | ||
|
|
4b6d204e22 | ||
|
|
1190344d37 | ||
|
|
0ab3d410b2 | ||
|
|
4a7266f166 | ||
|
|
866bd8730b | ||
|
|
4f5088e8da | ||
|
|
50cf5a78b1 | ||
|
|
aee8189852 | ||
|
|
c906c8ae1c | ||
|
|
3c69d1c1da | ||
|
|
cc691bdbd6 | ||
|
|
f8ddd21b97 | ||
|
|
1a3961f00d | ||
|
|
6c0e70cefb | ||
|
|
accf8d2c15 | ||
|
|
9677f3549e | ||
|
|
2f911653ec | ||
|
|
bc8bb06e3c | ||
|
|
d19802b57a | ||
|
|
cbfbd984d3 | ||
|
|
a3b1139001 | ||
|
|
5a40e781c1 | ||
|
|
e819b50e03 | ||
|
|
57394e68cd | ||
|
|
959e491679 | ||
|
|
84a36d2015 | ||
|
|
d004699f2d | ||
|
|
5622ef89d5 | ||
|
|
9a88efd8df | ||
|
|
7793d2a375 | ||
|
|
d6f24b53b6 | ||
|
|
fb038e2f23 | ||
|
|
ff49c86eea | ||
|
|
20885d936c | ||
|
|
0380c686df | ||
|
|
f0840fb5c8 | ||
|
|
2bb1e01c17 | ||
|
|
396549add5 | ||
|
|
164dbec004 | ||
|
|
63f3884abb | ||
|
|
55fb9917ff | ||
|
|
2bba6b2afd | ||
|
|
df568c139f | ||
|
|
a4c75f4d23 | ||
|
|
ab96148ba7 | ||
|
|
3a2dcee0b3 | ||
|
|
42a0064a70 | ||
|
|
668c9cc6ad | ||
|
|
aa1d482357 | ||
|
|
f450f56bf3 | ||
|
|
9222956861 | ||
|
|
d8ee898ba0 | ||
|
|
9d6194668c | ||
|
|
2a795ed473 | ||
|
|
117838fd0e | ||
|
|
318b2fc04c | ||
|
|
0aa08303bc | ||
|
|
a1556f322a | ||
|
|
6c27f7f186 | ||
|
|
ee54c946b0 | ||
|
|
0b9349c8bd | ||
|
|
24611ce162 | ||
|
|
1469483e15 | ||
|
|
5eba92a47b | ||
|
|
999159cfb7 | ||
|
|
da27e01fe6 | ||
|
|
155991d08b | ||
|
|
8e7e1286be | ||
|
|
4b273b74cb | ||
|
|
b9f4a4fada | ||
|
|
533803d845 | ||
|
|
c790bf75df | ||
|
|
c15a219ee8 | ||
|
|
1fc6144cc0 | ||
|
|
90e5588e5d | ||
|
|
c57db8ae34 | ||
|
|
634e4f7bbb | ||
|
|
4f9889ce48 | ||
|
|
155e4d36f7 | ||
|
|
b4dea997f0 | ||
|
|
bc92dbd3c3 | ||
|
|
dcc812364e | ||
|
|
ae0c3cfe6f | ||
|
|
d5342ec28a | ||
|
|
f7239431b3 | ||
|
|
800e2db645 | ||
|
|
420291805e | ||
|
|
cdaf9129ee | ||
|
|
125ee5f155 | ||
|
|
c752b57508 | ||
|
|
a63192c702 | ||
|
|
c790785827 | ||
|
|
25bf058c15 | ||
|
|
debea836ad | ||
|
|
4ba1e265d9 | ||
|
|
82a7c7c87e | ||
|
|
4791605f49 | ||
|
|
fb2da5d153 | ||
|
|
9f74d3e4a8 | ||
|
|
e2196eb28a | ||
|
|
f23189e030 | ||
|
|
a37e0cc3b0 | ||
|
|
8cd43b2951 | ||
|
|
fd6f711788 | ||
|
|
b48047ea41 | ||
|
|
939d9b0eeb | ||
|
|
4da7a8a588 | ||
|
|
6d96c2fe32 | ||
|
|
a04596a8b5 | ||
|
|
23d0362d9b | ||
|
|
35acbea01c | ||
|
|
f201d3a103 | ||
|
|
43ac34f7f3 | ||
|
|
9006b23eef | ||
|
|
d8daf4eb86 | ||
|
|
42106d8ab4 | ||
|
|
934395fb24 | ||
|
|
caca820b8c | ||
|
|
98413e412a | ||
|
|
c8041d6397 | ||
|
|
dca8f183e4 | ||
|
|
659ab6b298 | ||
|
|
08e41d81a0 | ||
|
|
4b651548b3 | ||
|
|
d43a56df50 | ||
|
|
c3e230d024 | ||
|
|
987a93083e | ||
|
|
368027dc04 | ||
|
|
55e5545d5b | ||
|
|
8922818463 | ||
|
|
4711dd9713 | ||
|
|
b886afa98f | ||
|
|
b10af3a02c | ||
|
|
1f2c29fd9a | ||
|
|
66d62ec7cb | ||
|
|
e3e1f7a5ed | ||
|
|
98c27d105b | ||
|
|
84e6895b43 | ||
|
|
5e419ced93 | ||
|
|
fa82c71195 | ||
|
|
47b223f56a | ||
|
|
fe408d135e | ||
|
|
501fd5d574 | ||
|
|
954b019951 | ||
|
|
4b0b7156c8 | ||
|
|
0ca08d620b | ||
|
|
4b33392dfb | ||
|
|
d6a1b45f1f | ||
|
|
6f502bb885 | ||
|
|
c920e92115 | ||
|
|
2998ca898b | ||
|
|
01c4e9fa39 | ||
|
|
9a830af2d8 | ||
|
|
4cdb9c09a1 | ||
|
|
922fbd8dd1 | ||
|
|
d58b2097ce | ||
|
|
d8f916f077 | ||
|
|
d379039ef4 | ||
|
|
a53bde5913 | ||
|
|
21b2e44742 | ||
|
|
6ef891d8a0 | ||
|
|
23be295830 | ||
|
|
6ded9c0f75 | ||
|
|
dd752c6046 | ||
|
|
20ba96f664 | ||
|
|
e8a33f952c | ||
|
|
c850eaff51 | ||
|
|
2bd20cfa5a | ||
|
|
2ee234e829 | ||
|
|
1137fb9036 | ||
|
|
a9dc413939 | ||
|
|
825eb938c2 | ||
|
|
e5eb169055 | ||
|
|
1914d5fb39 | ||
|
|
98df5fc473 | ||
|
|
4e6f1c95ff | ||
|
|
c010712741 | ||
|
|
161724ceae | ||
|
|
6627d9d1ee | ||
|
|
d533947dca | ||
|
|
595b1917f3 | ||
|
|
f112c6ddff | ||
|
|
070dec8c74 | ||
|
|
8125d5ae39 | ||
|
|
45e450a3d8 | ||
|
|
737624d914 | ||
|
|
1401f6b804 | ||
|
|
8c679bf3a2 | ||
|
|
fc7eb4fd27 | ||
|
|
7486445385 | ||
|
|
dfdfd7fbf3 | ||
|
|
87862b1ac6 | ||
|
|
bbfc356c01 | ||
|
|
d8d446b1a5 | ||
|
|
6ba900f18c | ||
|
|
dc7bef5d10 | ||
|
|
dff3b2aa26 | ||
|
|
560664ab5a | ||
|
|
68c1b99eac | ||
|
|
998df25440 | ||
|
|
b59617e2a6 | ||
|
|
c6162ed666 | ||
|
|
31f94813cf | ||
|
|
1f256f5391 | ||
|
|
a299404c1b | ||
|
|
72b47afe1e | ||
|
|
ce744287b7 | ||
|
|
9f14918a5a | ||
|
|
11aacc8bd1 | ||
|
|
01da118ae2 | ||
|
|
94d968b7f7 | ||
|
|
57c24a378b | ||
|
|
fdea0f9267 | ||
|
|
58364534e9 | ||
|
|
bc10416921 | ||
|
|
c30115270c | ||
|
|
2c315e1ce7 | ||
|
|
ff64bffed1 | ||
|
|
34200e124b | ||
|
|
20a6c8a79b | ||
|
|
d2569fbe93 | ||
|
|
bf76d31f6c | ||
|
|
551c37101c | ||
|
|
23f59994f8 | ||
|
|
109c6b6f4f | ||
|
|
fc6b3c841b | ||
|
|
0b3e720b84 | ||
|
|
7bcf46ac24 | ||
|
|
0b31353707 | ||
|
|
872f038e0b | ||
|
|
b08cc03b22 | ||
|
|
328c5ce28f | ||
|
|
3e54ad6cac | ||
|
|
7990d6d708 | ||
|
|
95f32bf522 | ||
|
|
95f98b0c41 | ||
|
|
b0af7b2d2e | ||
|
|
51f7507c86 | ||
|
|
0965ae08a9 | ||
|
|
2e6aade129 | ||
|
|
7d29b5bbf0 | ||
|
|
6666191087 | ||
|
|
43b37e9b7e | ||
|
|
6c53e5e46e | ||
|
|
d178fca7df | ||
|
|
230c3a6c5b | ||
|
|
9b85e40cc6 | ||
|
|
e38e2dcbba | ||
|
|
a5d0a37b49 | ||
|
|
808d103448 | ||
|
|
30e0b8afa8 | ||
|
|
da887624a4 | ||
|
|
5eb8d57c09 | ||
|
|
89493b1be0 | ||
|
|
7ad1f0f105 | ||
|
|
ffa78322a4 | ||
|
|
ad9cf6da5d | ||
|
|
a5a18bb80b | ||
|
|
81764f4072 | ||
|
|
327c871825 | ||
|
|
4126450357 | ||
|
|
8e81d7cded | ||
|
|
94977c4028 | ||
|
|
278f9d748a | ||
|
|
d5f9d825aa | ||
|
|
3a4eb3934d | ||
|
|
d0b6aa2131 | ||
|
|
310758fc7a | ||
|
|
c1ab36765b | ||
|
|
f24af60e42 | ||
|
|
7d0bbde770 | ||
|
|
efffcc135b | ||
|
|
1b233673bb | ||
|
|
07bde5f757 | ||
|
|
ce174aed64 | ||
|
|
cff33471cf | ||
|
|
e211b33874 | ||
|
|
05c149e84f | ||
|
|
bf50899345 | ||
|
|
b2f8339751 | ||
|
|
e0435cd1a0 | ||
|
|
d03bf4584c | ||
|
|
e40f7b86df | ||
|
|
3a8b8d4f71 | ||
|
|
c38c925975 | ||
|
|
d27ddd4739 | ||
|
|
0aec65bb77 | ||
|
|
671a3e4a04 | ||
|
|
cbc4d3d251 | ||
|
|
fe8cc5f97c | ||
|
|
af3630ee22 | ||
|
|
602260698d | ||
|
|
ad27e8bcbb | ||
|
|
d4ddc46c29 | ||
|
|
ac29a7e86c | ||
|
|
daa2dc7ee4 | ||
|
|
1e822400d5 | ||
|
|
57f7bb86d5 | ||
|
|
ba65508bc9 | ||
|
|
30e23d86d0 | ||
|
|
7c79c78623 | ||
|
|
caf28d82f7 | ||
|
|
28ae1f71fb | ||
|
|
bdea86b669 | ||
|
|
2ec5a2cf70 | ||
|
|
841d5eaedd | ||
|
|
9ee4838edf | ||
|
|
12203cbbe8 | ||
|
|
e2ce496727 | ||
|
|
4c11a63573 | ||
|
|
725abe0123 | ||
|
|
81c40a28df | ||
|
|
2465b14c41 | ||
|
|
d002c1076e | ||
|
|
c3e5299489 | ||
|
|
2d113619b3 | ||
|
|
2fdd8600ad | ||
|
|
dbc7a0636d | ||
|
|
382fd19d57 | ||
|
|
364ffb1dda | ||
|
|
b787cedd82 | ||
|
|
2dd7251e59 | ||
|
|
b6574fdbfa | ||
|
|
adcd9c09c3 | ||
|
|
e8a6d1b229 | ||
|
|
6d96fb56af | ||
|
|
6fd94ebd5a | ||
|
|
0c0027d11d | ||
|
|
07d3c6b7c1 | ||
|
|
8be14c8950 | ||
|
|
2f13554ac3 | ||
|
|
3d96c04300 | ||
|
|
debcd26997 | ||
|
|
96284ee8b7 | ||
|
|
a1f5f8b1b0 | ||
|
|
ae951cdfcc | ||
|
|
a567590b51 | ||
|
|
6ea9ef03b5 | ||
|
|
663d7da0e7 | ||
|
|
3432c9df7b | ||
|
|
46d63d36ec | ||
|
|
035b445a98 | ||
|
|
ef2bde0f4a | ||
|
|
b2e9530bc7 | ||
|
|
bd65618ff5 | ||
|
|
6420cf2823 | ||
|
|
2f656df41c | ||
|
|
83339bc156 | ||
|
|
e464f894c6 | ||
|
|
a5b31b013b | ||
|
|
0dd7781663 | ||
|
|
771b96b211 | ||
|
|
aeda350995 | ||
|
|
551f99d5d2 | ||
|
|
2aa051f366 | ||
|
|
7d95149519 | ||
|
|
1c100fe50a | ||
|
|
395ea51b28 | ||
|
|
d327e9b0dd | ||
|
|
5cbf98de49 | ||
|
|
22444f8aa9 | ||
|
|
cc5ccf062b | ||
|
|
315f14ce58 | ||
|
|
f9eaa6ae4d | ||
|
|
2be6e0cc10 | ||
|
|
5b444c36df | ||
|
|
61fa9709f2 | ||
|
|
45cc6b9dcd | ||
|
|
e76d7e56b6 | ||
|
|
6d004c4bca | ||
|
|
e7293b3841 | ||
|
|
69b0b5a26f | ||
|
|
edb920dc05 | ||
|
|
df9fdcbaf9 | ||
|
|
1883d62d06 | ||
|
|
ff1db4e2a4 | ||
|
|
5048d2480c | ||
|
|
d75a723f55 | ||
|
|
864b9a01e0 | ||
|
|
b866b0b30a | ||
|
|
842a366c10 | ||
|
|
2728ec3c02 | ||
|
|
4a3096149e | ||
|
|
726ef21f76 | ||
|
|
3d9778b4da | ||
|
|
c2fa94c9f4 | ||
|
|
ff033d0e0e | ||
|
|
f815ac6561 | ||
|
|
bab82c9802 | ||
|
|
73a941a879 | ||
|
|
868c89fd7e | ||
|
|
c050ff8e3d | ||
|
|
1fec873770 | ||
|
|
877dae612d | ||
|
|
5bf7da2074 | ||
|
|
9c850f5235 | ||
|
|
bd837d91ab | ||
|
|
c4e1c722b1 | ||
|
|
85e612ec79 | ||
|
|
f0233feaea | ||
|
|
2e2ed658fd | ||
|
|
fe9649ddfb | ||
|
|
6004253367 | ||
|
|
d93f683d40 | ||
|
|
d3c4120740 | ||
|
|
9fe7fada49 | ||
|
|
1619377fd7 | ||
|
|
1761413f2b | ||
|
|
ccd2f0bbd6 | ||
|
|
d6fbde4b32 | ||
|
|
36af0e2d7b | ||
|
|
0c07206571 | ||
|
|
7bbbc01f84 | ||
|
|
b94d9ecf40 | ||
|
|
ae3553dac9 | ||
|
|
b9b7ed25ca | ||
|
|
61a72fd587 | ||
|
|
be29dff25d | ||
|
|
d62b0bb95f | ||
|
|
40a44d5655 | ||
|
|
6a0f72c350 | ||
|
|
aedc03b9c3 | ||
|
|
3397275612 | ||
|
|
6afe536cce | ||
|
|
53f888504d | ||
|
|
2760d0e29e | ||
|
|
48d48cfd7e | ||
|
|
a83ebb0aac | ||
|
|
7cfce7a88b | ||
|
|
8b66d2ff33 | ||
|
|
feaf977424 | ||
|
|
935434a940 | ||
|
|
4d84709369 | ||
|
|
8a84698537 | ||
|
|
f69705a65d | ||
|
|
ae99c04c93 | ||
|
|
d0fe287cd7 | ||
|
|
79bb924d44 | ||
|
|
39d7f4ff11 | ||
|
|
d9a333fb56 | ||
|
|
d227c71a3f | ||
|
|
4cc4c1cba8 | ||
|
|
7856af3a73 | ||
|
|
b8491b9f1e | ||
|
|
e29def7754 | ||
|
|
9dbfd131e1 | ||
|
|
547993882d | ||
|
|
3b18a59438 | ||
|
|
383e132ba7 | ||
|
|
4a20c75be6 | ||
|
|
b89c397b15 | ||
|
|
725b5720cb | ||
|
|
3db5081ec0 | ||
|
|
0f037bd33f | ||
|
|
0a89d904ed | ||
|
|
a66230ef17 | ||
|
|
9829073dd7 | ||
|
|
ea23fabafa | ||
|
|
e5d9b064ca | ||
|
|
1d00ff6dd8 | ||
|
|
0db60a3462 | ||
|
|
5e88deb97d | ||
|
|
30ecb3762a | ||
|
|
a8531fbd67 | ||
|
|
5fb75c133b | ||
|
|
b9c23a2736 | ||
|
|
2fc023c798 | ||
|
|
4e9dcd8d12 | ||
|
|
a956dc9144 | ||
|
|
9b7d6b130f | ||
|
|
a24dd2827c | ||
|
|
bb4a08411c | ||
|
|
0fb6a23e53 | ||
|
|
e71db29b3a | ||
|
|
59487036e9 | ||
|
|
d79b8fe8e0 | ||
|
|
2e02bda8a1 | ||
|
|
0c0949c777 | ||
|
|
4611bdac86 | ||
|
|
f3768e816f | ||
|
|
d304cb36a9 | ||
|
|
3f5230b6e5 | ||
|
|
3058c5ea7b | ||
|
|
ce566e078c | ||
|
|
b16d9d6ace | ||
|
|
9a9ea7d242 | ||
|
|
ab94351a60 | ||
|
|
fd56bd28da | ||
|
|
ddef41c2ee | ||
|
|
52621660fe | ||
|
|
deb10fb2a7 | ||
|
|
366ce02b88 | ||
|
|
c57c524007 | ||
|
|
e0f4b3ef34 | ||
|
|
c0fabf16eb |
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @gofiber/maintainers
|
||||
79
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
Normal file
79
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: "\U0001F41B Bug Report"
|
||||
title: "\U0001F41B [Bug]: "
|
||||
description: Create a bug report to help us fix it.
|
||||
labels: ["☢️ Bug"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
id: notice
|
||||
attributes:
|
||||
value: |
|
||||
### Notice
|
||||
- Dont't forget you can ask your questions on our [Discord server](https://gofiber.io/discord).
|
||||
- If you think Fiber storage don't have a nice feature that you think, open the issue with **✏️ Feature Request** template.
|
||||
- Write your issue with clear and understandable English.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Bug Description"
|
||||
description: "A clear and detailed description of what the bug is."
|
||||
placeholder: "Explain your problem as clear and detailed."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: how-to-reproduce
|
||||
attributes:
|
||||
label: How to Reproduce
|
||||
description: "Steps to reproduce the behavior and what should be observed in the end."
|
||||
placeholder: "Tell us step by step how we can replicate your problem and what we should see in the end."
|
||||
value: |
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '....'
|
||||
2. Click on '....'
|
||||
3. Do '....'
|
||||
4. See '....'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: "A clear and detailed description of what you think should happens."
|
||||
placeholder: "Tell us what storage should normally do."
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: "Storage package Version"
|
||||
description: "Some bugs may be fixed in future storage releases, so we have to know your storage package version."
|
||||
placeholder: "Write your storage version. (v1.0.0, v1.1.0...)"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: snippet
|
||||
attributes:
|
||||
label: "Code Snippet (optional)"
|
||||
description: "For some issues, we need to know some parts of your code."
|
||||
placeholder: "Share a code you think related to the issue."
|
||||
render: go
|
||||
value: |
|
||||
package main
|
||||
|
||||
import "github.com/gofiber/storage/%package%"
|
||||
|
||||
func main() {
|
||||
// Steps to reproduce
|
||||
}
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: "Checklist:"
|
||||
description: "By submitting this issue, you confirm that:"
|
||||
options:
|
||||
- label: "I agree to follow Fiber's [Code of Conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md)."
|
||||
required: true
|
||||
- label: "I have checked for existing issues that describe my problem prior to opening this one."
|
||||
required: true
|
||||
- label: "I understand that improperly formatted bug reports may be closed without explanation."
|
||||
required: true
|
||||
55
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
55
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: "\U0001F680 Feature Request"
|
||||
title: "\U0001F680 [Feature]: "
|
||||
description: Suggest an idea to improve this project.
|
||||
labels: ["✏️ Feature"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
id: notice
|
||||
attributes:
|
||||
value: |
|
||||
### Notice
|
||||
- Dont't forget you can ask your questions on our [Discord server](https://gofiber.io/discord).
|
||||
- If you think this is just a bug, open the issue with **☢️ Bug Report** template.
|
||||
- Write your issue with clear and understandable English.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Feature Description"
|
||||
description: "A clear and detailed description of the feature we need to do."
|
||||
placeholder: "Explain your feature as clear and detailed."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: "Additional Context (optional)"
|
||||
description: "If you have something else to describe, write them here."
|
||||
placeholder: "Write here what you can describe differently."
|
||||
- type: textarea
|
||||
id: snippet
|
||||
attributes:
|
||||
label: "Code Snippet (optional)"
|
||||
description: "Code snippet may be really helpful to describe some features."
|
||||
placeholder: "Share a code to explain the feature better."
|
||||
render: go
|
||||
value: |
|
||||
package main
|
||||
|
||||
import "github.com/gofiber/storage/%package%"
|
||||
|
||||
func main() {
|
||||
// Steps to reproduce
|
||||
}
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: "Checklist:"
|
||||
description: "By submitting this issue, you confirm that:"
|
||||
options:
|
||||
- label: "I agree to follow Fiber's [Code of Conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md)."
|
||||
required: true
|
||||
- label: "I have checked for existing issues that describe my suggestion prior to opening this one."
|
||||
required: true
|
||||
- label: "I understand that improperly formatted feature requests may be closed without explanation."
|
||||
required: true
|
||||
50
.github/ISSUE_TEMPLATE/question.yaml
vendored
Normal file
50
.github/ISSUE_TEMPLATE/question.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: "🤔 Question"
|
||||
title: "\U0001F917 [Question]: "
|
||||
description: Ask a question so we can help you easily.
|
||||
labels: ["🤔 Question"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
id: notice
|
||||
attributes:
|
||||
value: |
|
||||
### Notice
|
||||
- Dont't forget you can ask your questions on our [Discord server](https://gofiber.io/discord).
|
||||
- If you think this is just a bug, open the issue with **☢️ Bug Report** template.
|
||||
- If you think Fiber storage don't have a nice feature that you think, open the issue with **✏️ Feature Request** template.
|
||||
- Write your issue with clear and understandable English.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Question Description"
|
||||
description: "A clear and detailed description of the question."
|
||||
placeholder: "Explain your question as clear and detailed."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: snippet
|
||||
attributes:
|
||||
label: "Code Snippet (optional)"
|
||||
description: "Code snippet may be really helpful to describe some features."
|
||||
placeholder: "Share a code to explain the feature better."
|
||||
render: go
|
||||
value: |
|
||||
package main
|
||||
|
||||
import "github.com/gofiber/storage/%package%"
|
||||
|
||||
func main() {
|
||||
// Steps to reproduce
|
||||
}
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: "Checklist:"
|
||||
description: "By submitting this issue, you confirm that:"
|
||||
options:
|
||||
- label: "I agree to follow Fiber's [Code of Conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md)."
|
||||
required: true
|
||||
- label: "I have checked for existing issues that describe my questions prior to opening this one."
|
||||
required: true
|
||||
- label: "I understand that improperly formatted questions may be closed without explanation."
|
||||
required: true
|
||||
56
.github/README.md
vendored
56
.github/README.md
vendored
@@ -1,56 +0,0 @@
|
||||
|
||||
<p align="center">
|
||||
<!-- <a href="https://gofiber.io">
|
||||
<img alt="Fiber" height="125" src="https://raw.githubusercontent.com/gofiber/docs/master/static/fiber_v2_logo.svg">
|
||||
</a>
|
||||
<br> -->
|
||||
|
||||
# 📦 Storage
|
||||
|
||||
<a href="https://pkg.go.dev/github.com/gofiber/storage?tab=doc">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%93%9A%20godoc-pkg-00ACD7.svg?color=00ACD7&style=flat">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/gofiber/storage">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%93%9D%20goreport-A%2B-75C46B">
|
||||
</a>
|
||||
<a href="https://gocover.io/github.com/gofiber/storage">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%94%8E%20gocover-97.8%25-75C46B.svg?style=flat">
|
||||
</a>
|
||||
<a href="https://gofiber.io/discord">
|
||||
<img src="https://img.shields.io/discord/704680098577514527?style=flat&label=%F0%9F%92%AC%20discord&color=00ACD7">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
Premade storage drivers that implement [`fiber.Storage`](https://github.com/gofiber/fiber/blob/ba08653c92f86bc69956b23714f919b705d9381e/app.go#L39-L50), to be used with various Fiber middlewares.
|
||||
|
||||
## 📑 Storage Implementations
|
||||
|
||||
|
||||
* [Badger](/badger) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Local+Storage%22">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Local%20Storage?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [Memcache](/memcache) <a href="https://github.com/gofiber/storage/actions?query=workflow%3AMemcache">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Memcache?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [Memory](/memory) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Local+Storage%22">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Local%20Storage?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [MongoDB](/mongodb) <a href="https://github.com/gofiber/storage/actions?query=workflow%3AMongoDB">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/MongoDB?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [MySQL](/mysql) <a href="https://github.com/gofiber/storage/actions?query=workflow%3AMySQL">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/MySQL?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [Postgres](/postgres) <a href="https://github.com/gofiber/storage/actions?query=workflow%3APostgres">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Postgres?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [Redis](/redis) <a href="https://github.com/gofiber/storage/actions?query=workflow%3ARedis">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Redis?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
* [SQLite3](/sqlite3) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Local+Storage%22">
|
||||
<img src="https://img.shields.io/github/workflow/status/gofiber/storage/Local%20Storage?label=%F0%9F%A7%AA%20&style=flat&color=75C46B">
|
||||
</a>
|
||||
|
||||
## 🤔 Something missing?
|
||||
|
||||
If you've got a custom storage driver you made that's not listed here, why not submit a [PR](https://github.com/gofiber/storage/pulls) to add it?
|
||||
24
.github/dependabot.yml
vendored
Normal file
24
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#directories
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
labels:
|
||||
- "🤖 Dependencies"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "gomod"
|
||||
directories:
|
||||
- "**/*"
|
||||
labels:
|
||||
- "🤖 Dependencies"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/clickhouse/" # Location of package manifests
|
||||
labels:
|
||||
- "🤖 Dependencies"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
20
.github/labeler.yml
vendored
Normal file
20
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
version: v1
|
||||
labels:
|
||||
- label: '📒 Documentation'
|
||||
matcher:
|
||||
title: '\b(docs|doc:|\[doc\]|README|typos|comment|documentation)\b'
|
||||
- label: '☢️ Bug'
|
||||
matcher:
|
||||
title: '\b(fix|race|bug|missing|correct)\b'
|
||||
- label: '🧹 Updates'
|
||||
matcher:
|
||||
title: '\b(improve|update|refactor|deprecated|remove|unused|test)\b'
|
||||
- label: '🤖 Dependencies'
|
||||
matcher:
|
||||
title: '\b(bumb|bdependencies)\b'
|
||||
- label: '✏️ Feature'
|
||||
matcher:
|
||||
title: '\b(feature|create|implement|add)\b'
|
||||
- label: '🤔 Question'
|
||||
matcher:
|
||||
title: '\b(question|how)\b'
|
||||
9
.github/logo-dark.svg
vendored
Normal file
9
.github/logo-dark.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 14 KiB |
9
.github/logo.svg
vendored
Normal file
9
.github/logo.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 14 KiB |
50
.github/release-drafter-template.yml
vendored
Normal file
50
.github/release-drafter-template.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name-template: '{{FOLDER}} - v$RESOLVED_VERSION'
|
||||
tag-template: '{{FOLDER}}/v$RESOLVED_VERSION'
|
||||
tag-prefix: {{FOLDER}}/v
|
||||
include-paths:
|
||||
- {{FOLDER}}
|
||||
categories:
|
||||
- title: '❗ Breaking Changes'
|
||||
labels:
|
||||
- '❗ BreakingChange'
|
||||
- title: '🚀 New'
|
||||
labels:
|
||||
- '✏️ Feature'
|
||||
- title: '🧹 Updates'
|
||||
labels:
|
||||
- '🧹 Updates'
|
||||
- '🤖 Dependencies'
|
||||
- title: '🐛 Fixes'
|
||||
labels:
|
||||
- '☢️ Bug'
|
||||
- title: '📚 Documentation'
|
||||
labels:
|
||||
- '📒 Documentation'
|
||||
change-template: '- $TITLE (#$NUMBER)'
|
||||
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
|
||||
exclude-contributors:
|
||||
- dependabot
|
||||
- dependabot[bot]
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- 'major'
|
||||
- '❗ BreakingChange'
|
||||
minor:
|
||||
labels:
|
||||
- 'minor'
|
||||
- '✏️ Feature'
|
||||
patch:
|
||||
labels:
|
||||
- 'patch'
|
||||
- '📒 Documentation'
|
||||
- '☢️ Bug'
|
||||
- '🤖 Dependencies'
|
||||
- '🧹 Updates'
|
||||
default: patch
|
||||
template: |
|
||||
$CHANGES
|
||||
|
||||
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...{{FOLDER}}/v$RESOLVED_VERSION
|
||||
|
||||
Thank you $CONTRIBUTORS for making this update possible.
|
||||
63
.github/scripts/gen-test-certs.sh
vendored
Executable file
63
.github/scripts/gen-test-certs.sh
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Generate some test certificates which are used by the regression test suite:
|
||||
#
|
||||
# ./tls/ca.{crt,key} Self signed CA certificate.
|
||||
# ./tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
|
||||
# ./tls/client.{crt,key} A certificate restricted for SSL client usage.
|
||||
# ./tls/server.{crt,key} A certificate restricted for SSL server usage.
|
||||
|
||||
set -e
|
||||
|
||||
generate_cert() {
|
||||
local name=$1
|
||||
local cn="$2"
|
||||
local opts="$3"
|
||||
|
||||
local keyfile=./tls/${name}.key
|
||||
local certfile=./tls/${name}.crt
|
||||
|
||||
[ -f $keyfile ] || openssl genrsa -out $keyfile 2048
|
||||
openssl req \
|
||||
-new -sha256 \
|
||||
-subj "/O=Redis Test/CN=$cn" \
|
||||
-key $keyfile | \
|
||||
openssl x509 \
|
||||
-req -sha256 \
|
||||
-CA ./tls/ca.crt \
|
||||
-CAkey ./tls/ca.key \
|
||||
-CAserial ./tls/ca.txt \
|
||||
-CAcreateserial \
|
||||
-days 365 \
|
||||
$opts \
|
||||
-out $certfile
|
||||
}
|
||||
|
||||
mkdir -p ./tls
|
||||
[ -f ./tls/ca.key ] || openssl genrsa -out ./tls/ca.key 4096
|
||||
openssl req \
|
||||
-x509 -new -nodes -sha256 \
|
||||
-key ./tls/ca.key \
|
||||
-days 3650 \
|
||||
-subj '/O=Redis Test/CN=Certificate Authority' \
|
||||
-out ./tls/ca.crt
|
||||
|
||||
cat > ./tls/openssl.cnf <<_END_
|
||||
[ server_cert ]
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
nsCertType = server
|
||||
subjectAltName = DNS:localhost"
|
||||
|
||||
[ client_cert ]
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
nsCertType = client
|
||||
_END_
|
||||
|
||||
generate_cert server "Server-only" "-extfile ./tls/openssl.cnf -extensions server_cert"
|
||||
generate_cert client "Client-only" "-extfile ./tls/openssl.cnf -extensions client_cert"
|
||||
generate_cert redis "localhost" "-extfile ./tls/openssl.cnf -extensions server_cert"
|
||||
generate_cert valkey "localhost" "-extfile ./tls/openssl.cnf -extensions server_cert"
|
||||
|
||||
# List generated certs
|
||||
ls -la ./tls
|
||||
echo "$PWD"
|
||||
107
.github/scripts/initialize-wrangler.sh
vendored
Executable file
107
.github/scripts/initialize-wrangler.sh
vendored
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
# generate cloudflarekv/index.ts
|
||||
cat <<EOF > cloudflarekv/index.ts
|
||||
export default { async fetch(Request, env) {
|
||||
|
||||
const namespace = env.TEST_NAMESPACE1;
|
||||
|
||||
if (Request.url === "http://localhost:8787/health") {
|
||||
return new Response("Success");
|
||||
}
|
||||
|
||||
if (Request.url === "http://localhost:8787/writeworkerskvkeyvaluepair") {
|
||||
const res = await Request.json();
|
||||
const { key, val } = res;
|
||||
WriteWorkersKVKeyValuePair(namespace, key, val);
|
||||
return new Response("Success");
|
||||
}
|
||||
|
||||
else if (Request.url === "http://localhost:8787/listworkerskvkeys") {
|
||||
const resp = await Request.json();
|
||||
const { limit, prefix, cursor } = resp;
|
||||
const list = await ListWorkersKVKeys(namespace, limit, prefix, cursor);
|
||||
return new Response(list);
|
||||
}
|
||||
|
||||
else if (Request.url === "http://localhost:8787/deleteworkerskvpairbykey") {
|
||||
const res = await Request.json();
|
||||
const { key } = res;
|
||||
await DeleteWorkersKVPairByKey(namespace, key);
|
||||
|
||||
return new Response(key)
|
||||
}
|
||||
|
||||
else if (Request.url === "http://localhost:8787/getworkerskvvaluebykey") {
|
||||
const key = (await Request.json()).key;
|
||||
const res = await GetWorkersKVValueByKey(namespace, key);
|
||||
|
||||
return new Response(res);
|
||||
}
|
||||
|
||||
else if (Request.url === "http://localhost:8787/deleteworkerskventries") {
|
||||
const res = await Request.json();
|
||||
const { keys } = res;
|
||||
const newKeys = keys.filter(x => x.length > 0);
|
||||
await DeleteWorkersKVEntries(namespace, newKeys);
|
||||
|
||||
return new Response("Success")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const GetWorkersKVValueByKey = async (NAMESPACE, key) => {
|
||||
const val = await NAMESPACE.get(key);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
const WriteWorkersKVKeyValuePair = async (NAMESPACE, key, val) => {
|
||||
await NAMESPACE.put(key, val);
|
||||
|
||||
return "Wrote Successfully"
|
||||
}
|
||||
|
||||
const DeleteWorkersKVPairByKey = async (NAMESPACE, key) => {
|
||||
await NAMESPACE.delete(key);
|
||||
|
||||
return "Delete Successfully"
|
||||
}
|
||||
|
||||
const ListWorkersKVKeys = async (NAMESPACE, limit, prefix, cursor) => {
|
||||
const resp = await NAMESPACE.list({ limit, prefix, cursor });
|
||||
|
||||
return JSON.stringify(resp.keys);
|
||||
}
|
||||
|
||||
const DeleteWorkersKVEntries = async (NAMESPACE, keys) => {
|
||||
for (let key of keys) {
|
||||
await NAMESPACE.delete(key);
|
||||
}
|
||||
|
||||
return "Delete Successfully"
|
||||
}
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
echo "index.ts generated"
|
||||
|
||||
# generate cloudflarekv/wrangler.toml
|
||||
cat <<EOF > cloudflarekv/wrangler.toml
|
||||
main = "index.ts"
|
||||
|
||||
kv_namespaces = [
|
||||
{ binding = "TEST_NAMESPACE1", id = "hello", preview_id = "world" },
|
||||
]
|
||||
|
||||
workers_dev = true
|
||||
|
||||
compatibility_date = "2024-03-20"
|
||||
|
||||
[dev]
|
||||
port = 8787
|
||||
local_protocol = "http"
|
||||
EOF
|
||||
|
||||
echo "wrangler.toml generated"
|
||||
84
.github/scripts/sync_docs.sh
vendored
Executable file
84
.github/scripts/sync_docs.sh
vendored
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Some env variables
|
||||
BRANCH="main"
|
||||
REPO_URL="github.com/gofiber/docs.git"
|
||||
AUTHOR_EMAIL="github-actions[bot]@users.noreply.github.com"
|
||||
AUTHOR_USERNAME="github-actions[bot]"
|
||||
VERSION_FILE="storage_versions.json"
|
||||
REPO_DIR="storage"
|
||||
COMMIT_URL="https://github.com/gofiber/storage"
|
||||
DOCUSAURUS_COMMAND="npm run docusaurus -- docs:version:storage"
|
||||
|
||||
# Set commit author
|
||||
git config --global user.email "${AUTHOR_EMAIL}"
|
||||
git config --global user.name "${AUTHOR_USERNAME}"
|
||||
|
||||
git clone https://${TOKEN}@${REPO_URL} fiber-docs
|
||||
|
||||
# Handle push event
|
||||
if [ "$EVENT" == "push" ]; then
|
||||
latest_commit=$(git rev-parse --short HEAD)
|
||||
|
||||
for f in $(find . -type f -name "*.md" -not -path "./fiber-docs/*"); do
|
||||
log_output=$(git log --oneline "${BRANCH}" HEAD~1..HEAD --name-status -- "${f}")
|
||||
|
||||
if [[ $log_output != "" || ! -f "fiber-docs/docs/${REPO_DIR}/$f" ]]; then
|
||||
mkdir -p fiber-docs/docs/${REPO_DIR}/$(dirname $f)
|
||||
cp "${f}" fiber-docs/docs/${REPO_DIR}/$f
|
||||
fi
|
||||
done
|
||||
|
||||
# Handle release event
|
||||
elif [ "$EVENT" == "release" ]; then
|
||||
# Extract package name from tag
|
||||
package_name="${TAG_NAME%/*}"
|
||||
major_version="${TAG_NAME#*/}"
|
||||
major_version="${major_version%%.*}"
|
||||
|
||||
# Form new version name
|
||||
new_version="${package_name}_${major_version}.x.x"
|
||||
|
||||
cd fiber-docs/ || true
|
||||
npm ci
|
||||
|
||||
# Check if contrib_versions.json exists and modify it if required
|
||||
if [[ -f $VERSION_FILE ]]; then
|
||||
jq --arg new_version "$new_version" 'del(.[] | select(. == $new_version))' $VERSION_FILE > temp.json && mv temp.json $VERSION_FILE
|
||||
fi
|
||||
|
||||
# Run docusaurus versioning command
|
||||
$DOCUSAURUS_COMMAND "${new_version}"
|
||||
|
||||
if [[ -f $VERSION_FILE ]]; then
|
||||
jq 'sort | reverse' ${VERSION_FILE} > temp.json && mv temp.json ${VERSION_FILE}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Push changes
|
||||
cd fiber-docs/ || true
|
||||
git add .
|
||||
if [[ $EVENT == "push" ]]; then
|
||||
git commit -m "Add docs from ${COMMIT_URL}/commit/${latest_commit}"
|
||||
elif [[ $EVENT == "release" ]]; then
|
||||
git commit -m "Sync docs for release ${COMMIT_URL}/releases/tag/${TAG_NAME}"
|
||||
fi
|
||||
|
||||
MAX_RETRIES=5
|
||||
DELAY=5
|
||||
retry=0
|
||||
|
||||
while ((retry < MAX_RETRIES))
|
||||
do
|
||||
git push https://${TOKEN}@${REPO_URL} && break
|
||||
retry=$((retry + 1))
|
||||
git pull --rebase
|
||||
sleep $DELAY
|
||||
done
|
||||
|
||||
if ((retry == MAX_RETRIES))
|
||||
then
|
||||
echo "Failed to push after $MAX_RETRIES attempts. Exiting with 1."
|
||||
exit 1
|
||||
fi
|
||||
22
.github/workflows/auto-labeler.yml
vendored
Normal file
22
.github/workflows/auto-labeler.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Auto labeler
|
||||
on:
|
||||
issues:
|
||||
types: [ opened, edited, milestoned ]
|
||||
pull_request_target:
|
||||
types: [ opened ]
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
checks: write
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor != 'dependabot[bot]' }}
|
||||
steps:
|
||||
- name: Check Labels
|
||||
id: labeler
|
||||
uses: fuxingloh/multi-labeler@v4
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
186
.github/workflows/benchmark.yml
vendored
Normal file
186
.github/workflows/benchmark.yml
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- "**"
|
||||
- "!**.md"
|
||||
pull_request:
|
||||
paths:
|
||||
- "**"
|
||||
- "!**.md"
|
||||
|
||||
permissions:
|
||||
deployments: write
|
||||
contents: write
|
||||
|
||||
name: Benchmark
|
||||
jobs:
|
||||
Compare:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
arangodb:
|
||||
image: 'arangodb:latest'
|
||||
env:
|
||||
ARANGO_NO_AUTH: 1
|
||||
ports:
|
||||
- '8529:8529'
|
||||
dynamodb:
|
||||
image: 'amazon/dynamodb-local:latest'
|
||||
ports:
|
||||
- '8000:8000'
|
||||
memcached:
|
||||
image: 'memcached:latest'
|
||||
ports:
|
||||
- '11211:11211'
|
||||
mongo:
|
||||
image: 'mongo:latest'
|
||||
ports:
|
||||
- '27017:27017'
|
||||
mssql:
|
||||
image: 'mcmoe/mssqldocker:latest'
|
||||
ports:
|
||||
- '1433:1433'
|
||||
env:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: MsSql!1234
|
||||
MSSQL_DB: master
|
||||
MSSQL_USER: sa
|
||||
MSSQL_PASSWORD: MsSql!1234
|
||||
options: >-
|
||||
--health-cmd "/opt/mssql-tools/bin/sqlcmd -U sa -P $SA_PASSWORD -Q 'select 1' -b -o /dev/null"
|
||||
--health-interval 1s
|
||||
--health-timeout 30s
|
||||
--health-start-period 10s
|
||||
--health-retries 20
|
||||
mysql:
|
||||
image: 'mysql:latest'
|
||||
env:
|
||||
MYSQL_DATABASE: fiber
|
||||
MYSQL_USER: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
ports:
|
||||
- '3306:3306'
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping" --health-interval 10s --health-timeout
|
||||
5s --health-retries 5
|
||||
postgres:
|
||||
image: 'postgres:latest'
|
||||
ports:
|
||||
- '5432:5432'
|
||||
env:
|
||||
POSTGRES_DB: fiber
|
||||
POSTGRES_USER: username
|
||||
POSTGRES_PASSWORD: "pass#w%rd"
|
||||
options: >-
|
||||
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
# NOTE: Keep this in sync with the version from go.mod
|
||||
go-version: "1.21.x"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install Azurite
|
||||
run: |
|
||||
docker run -d -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-blob --blobHost 0.0.0.0 --blobPort 10000
|
||||
|
||||
- name: Install Cloudflare Worker
|
||||
run : |
|
||||
.github/scripts/initialize-wrangler.sh
|
||||
cd cloudflarekv && npx wrangler dev &
|
||||
npx wait-on tcp:8787
|
||||
|
||||
- name: Install Coherence
|
||||
run: |
|
||||
docker run -d -p 1408:1408 -p 30000:30000 ghcr.io/oracle/coherence-ce:22.06.5
|
||||
sleep 30
|
||||
|
||||
- name: Install etcd
|
||||
run: |
|
||||
docker run -d --name Etcd-server \
|
||||
--publish 2379:2379 \
|
||||
--publish 2380:2380 \
|
||||
--env ALLOW_NONE_AUTHENTICATION=yes \
|
||||
--env ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 \
|
||||
bitnami/etcd:latest
|
||||
|
||||
- name: Install ScyllaDb
|
||||
run: |
|
||||
docker run --name scylladb -p 9042:9042 -p 19042:19042 -p 9160:9160 -p 7000:7000 -p 7001:7001 -p 7199:7199 -p 9180:9180 -d scylladb/scylla:latest --broadcast-address 127.0.0.1 --listen-address 0.0.0.0 --broadcast-rpc-address 127.0.0.1
|
||||
sleep 15 # Wait for ScyllaDb to initialize
|
||||
|
||||
- name: Setup Redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: '7.x'
|
||||
auto-start: 'false'
|
||||
|
||||
- name: Run Redis
|
||||
run: |
|
||||
redis-server --port 6379 &
|
||||
|
||||
- name: Run NATS
|
||||
run: |
|
||||
./.github/scripts/gen-test-certs.sh
|
||||
docker run -d --name nats-jetstream -p 4443:4443 -v ./nats/testdata:/testdata -v ./tls:/tls nats:latest --jetstream -c /testdata/nats-tls.conf
|
||||
sleep 2
|
||||
|
||||
- name: Run Benchmarks
|
||||
run: |
|
||||
set -o pipefail
|
||||
for d in */ ; do
|
||||
[[ $d == "tls/" ]] && continue
|
||||
[[ $d == "node_modules/" ]] && continue
|
||||
|
||||
cd "$d"
|
||||
echo "Bench dir: $d"
|
||||
go test ./... -benchmem -run=^$ -bench . | tee -a ../output.txt
|
||||
cd ..
|
||||
done
|
||||
shell: bash
|
||||
env:
|
||||
MSSQL_DATABASE: master
|
||||
MSSQL_USERNAME: sa
|
||||
MSSQL_PASSWORD: MsSql!1234
|
||||
MYSQL_USERNAME: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_DATABASE: fiber
|
||||
POSTGRES_DATABASE: fiber
|
||||
POSTGRES_USERNAME: username
|
||||
POSTGRES_PASSWORD: "pass#w%rd"
|
||||
TEST_CLICKHOUSE_IMAGE: "clickhouse/clickhouse-server:23-alpine"
|
||||
TEST_COUCHBASE_IMAGE: "couchbase:enterprise-7.1.1"
|
||||
TEST_MINIO_IMAGE: "docker.io/minio/minio:RELEASE.2024-08-17T01-24-54Z"
|
||||
|
||||
- name: Get Previous Benchmark Results
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./cache
|
||||
key: ${{ runner.os }}-benchmark
|
||||
|
||||
- name: Save Benchmark Results
|
||||
uses: benchmark-action/github-action-benchmark@v1.20.4
|
||||
with:
|
||||
tool: "go"
|
||||
output-file-path: output.txt
|
||||
github-token: ${{ secrets.BENCHMARK_TOKEN }}
|
||||
benchmark-data-dir-path: "benchmarks"
|
||||
alert-threshold: "300%"
|
||||
fail-on-alert: true
|
||||
comment-on-alert: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||
#summary-always: ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' }}
|
||||
auto-push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||
save-data-file: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||
54
.github/workflows/codeql-analysis.yml
vendored
54
.github/workflows/codeql-analysis.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 3 * * 6'
|
||||
|
||||
jobs:
|
||||
analyse:
|
||||
name: Analyse
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: go
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
41
.github/workflows/dependabot_automerge.yml
vendored
Normal file
41
.github/workflows/dependabot_automerge.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Dependabot auto-merge
|
||||
on:
|
||||
pull_request
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
wait_for_checks:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- name: Wait for check is finished
|
||||
uses: lewagon/wait-on-check-action@v1.3.4
|
||||
id: wait_for_checks
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
running-workflow-name: wait_for_checks
|
||||
check-regexp: Tests
|
||||
repo-token: ${{ secrets.PR_TOKEN }}
|
||||
wait-interval: 10
|
||||
dependabot:
|
||||
needs: [wait_for_checks]
|
||||
name: Dependabot auto-merge
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v2.2.0
|
||||
with:
|
||||
github-token: "${{ secrets.PR_TOKEN }}"
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
|
||||
run: |
|
||||
gh pr review --approve "$PR_URL"
|
||||
gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.PR_TOKEN}}
|
||||
68
.github/workflows/golangci-lint.yml
vendored
Normal file
68
.github/workflows/golangci-lint.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
name: Golangci-Lint Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "main"
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- LICENSE
|
||||
- ".github/ISSUE_TEMPLATE/*.yml"
|
||||
- ".github/dependabot.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- LICENSE
|
||||
- ".github/ISSUE_TEMPLATE/*.yml"
|
||||
- ".github/dependabot.yml"
|
||||
|
||||
jobs:
|
||||
generate-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: set-matrix
|
||||
run: |
|
||||
# Determine the base and head commits for diff based on the event type
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before }}"
|
||||
HEAD_SHA="${{ github.event.pull_request.head.sha || github.event.after }}"
|
||||
|
||||
# Extract directories from changed files, only include those with go.mod files
|
||||
GO_MOD_DIRECTORIES=()
|
||||
FILES=$(git diff --name-only $BASE_SHA $HEAD_SHA | grep -vE '/\.')
|
||||
DIRECTORIES=$(echo "$FILES" | xargs -L1 dirname | sort -u)
|
||||
|
||||
for dir in $DIRECTORIES; do
|
||||
if [[ -f "$dir/go.mod" ]]; then
|
||||
GO_MOD_DIRECTORIES+=("$dir")
|
||||
fi
|
||||
done
|
||||
|
||||
# Export the JSON array
|
||||
JSON_ARRAY=$(printf '%s\n' "${GO_MOD_DIRECTORIES[@]}" | jq -R -s -c 'split("\n")[:-1]')
|
||||
echo "matrix=${JSON_ARRAY}" >> $GITHUB_OUTPUT
|
||||
|
||||
lint:
|
||||
needs: generate-matrix
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
modules: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Run golangci-lint
|
||||
uses: reviewdog/action-golangci-lint@v2
|
||||
with:
|
||||
golangci_lint_flags: "--tests=false --timeout=5m"
|
||||
workdir: ${{ matrix.modules }}
|
||||
fail_on_error: true
|
||||
filter_mode: nofilter
|
||||
12
.github/workflows/linter.yml
vendored
12
.github/workflows/linter.yml
vendored
@@ -1,12 +0,0 @@
|
||||
on: [push, pull_request]
|
||||
name: Linter
|
||||
jobs:
|
||||
Golint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Golint
|
||||
uses: reviewdog/action-golangci-lint@v1
|
||||
with:
|
||||
golangci_lint_flags: "--tests=false"
|
||||
56
.github/workflows/release-drafter.yml
vendored
Normal file
56
.github/workflows/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Release Drafter (All)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate filters
|
||||
id: filter-setup
|
||||
run: |
|
||||
filters=$(find . -maxdepth 1 -type d ! -path ./.git ! -path . -exec basename {} \; | grep -v '^\.' | awk '{printf "%s=%s/**\n", $1, $1}')
|
||||
echo "filters=$(echo \"$filters\")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- name: Filter changes
|
||||
id: filter
|
||||
uses: dorny/paths-filter@v3
|
||||
with:
|
||||
filters: ${{ steps.filter-setup.outputs.filters }}
|
||||
|
||||
outputs:
|
||||
packages: ${{ steps.filter.outputs.changes }}
|
||||
|
||||
release-drafter:
|
||||
needs: changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
strategy:
|
||||
matrix:
|
||||
package: ${{ fromJSON(needs.changes.outputs.packages) }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate dynamic config from template
|
||||
run: |
|
||||
folder="${{ matrix.package }}"
|
||||
sed "s|{{FOLDER}}|$folder|g" .github/release-drafter-template.yml > .github/release-drafter-$folder.yml
|
||||
echo "Generated config for folder: $folder"
|
||||
cat .github/release-drafter-$folder.yml
|
||||
|
||||
- name: Use dynamic release-drafter configuration
|
||||
uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: release-drafter-${{ matrix.package }}.yml
|
||||
12
.github/workflows/security.yml
vendored
12
.github/workflows/security.yml
vendored
@@ -1,12 +0,0 @@
|
||||
on: [push, pull_request]
|
||||
name: Security
|
||||
jobs:
|
||||
Gosec:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Gosec
|
||||
uses: securego/gosec@master
|
||||
with:
|
||||
args: -exclude-dir=internal/*/ ./...
|
||||
11
.github/workflows/snyk.yml
vendored
11
.github/workflows/snyk.yml
vendored
@@ -1,11 +0,0 @@
|
||||
on: [push, pull_request_target]
|
||||
name: Snyk security
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run Snyk to check for vulnerabilities
|
||||
uses: snyk/actions/golang@master
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
38
.github/workflows/sync-docs.yml
vendored
Normal file
38
.github/workflows/sync-docs.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: 'Sync docs'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- '**/*.md'
|
||||
release:
|
||||
types: [published]
|
||||
branches:
|
||||
- '*/v[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
sync-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install JQ
|
||||
run: sudo apt-get install jq
|
||||
|
||||
- name: Sync docs
|
||||
run: ./.github/scripts/sync_docs.sh
|
||||
env:
|
||||
EVENT: ${{ github.event_name }}
|
||||
TAG_NAME: ${{ github.ref_name }}
|
||||
TOKEN: ${{ secrets.DOC_SYNC_TOKEN }}
|
||||
36
.github/workflows/test-arangodb.yml
vendored
Normal file
36
.github/workflows/test-arangodb.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'arangodb/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'arangodb/**'
|
||||
name: "Tests ArangoDB"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
arangodb:
|
||||
image: 'arangodb:latest'
|
||||
env:
|
||||
ARANGO_NO_AUTH: 1
|
||||
ports:
|
||||
- '8529:8529'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./arangodb && go test ./... -v -race
|
||||
32
.github/workflows/test-azureblob.yml
vendored
Normal file
32
.github/workflows/test-azureblob.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'azureblob/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'azureblob/**'
|
||||
name: "Tests Azure Blob"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Install Azurite
|
||||
run: |
|
||||
docker run -d -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-blob --blobHost 0.0.0.0 --blobPort 10000
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./azureblob && go test ./... -v -race
|
||||
29
.github/workflows/test-badger.yml
vendored
Normal file
29
.github/workflows/test-badger.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'badger/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'badger/**'
|
||||
name: "Tests Badger"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Test Badger
|
||||
run: cd ./badger && go test ./... -v -race
|
||||
29
.github/workflows/test-bbolt.yml
vendored
Normal file
29
.github/workflows/test-bbolt.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'bbolt/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'bbolt/**'
|
||||
name: "Tests Bbolt"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./bbolt && go test ./... -v -race
|
||||
30
.github/workflows/test-clickhouse.yml
vendored
Normal file
30
.github/workflows/test-clickhouse.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'clickhouse/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clickhouse/**'
|
||||
name: 'Tests Clickhouse'
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
env:
|
||||
TEST_CLICKHOUSE_IMAGE: clickhouse/clickhouse-server:23-alpine
|
||||
run: cd ./clickhouse && go clean -testcache && go test ./... -v -race
|
||||
43
.github/workflows/test-cloudflarekv.yml
vendored
Normal file
43
.github/workflows/test-cloudflarekv.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Tests CloudflareKV
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'cloudflarekv/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'cloudflarekv/**'
|
||||
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Start Wrangler Dev
|
||||
run: |
|
||||
.github/scripts/initialize-wrangler.sh
|
||||
cd cloudflarekv && npx wrangler dev &
|
||||
npx wait-on tcp:8787
|
||||
|
||||
- name: Run Go Tests
|
||||
run: cd cloudflarekv && go test ./... -v -race
|
||||
34
.github/workflows/test-coherence.yml
vendored
Normal file
34
.github/workflows/test-coherence.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'coherence/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'coherence/**'
|
||||
name: "Tests Coherence"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Startup Coherence
|
||||
run: |
|
||||
docker run -d -p 1408:1408 -p 30000:30000 ghcr.io/oracle/coherence-ce:24.09
|
||||
sleep 30
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./coherence && COHERENCE_SESSION_DEBUG=true go clean -testcache && go test ./... -v -race
|
||||
31
.github/workflows/test-couchbase.yml
vendored
Normal file
31
.github/workflows/test-couchbase.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'couchbase/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'couchbase/**'
|
||||
name: "Tests Couchbase"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
- 1.23.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
env:
|
||||
TEST_COUCHBASE_IMAGE: couchbase:enterprise-7.1.1
|
||||
run: cd ./couchbase && go test ./... -v -race
|
||||
34
.github/workflows/test-dynamodb.yml
vendored
Normal file
34
.github/workflows/test-dynamodb.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'dynamodb/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'dynamodb/**'
|
||||
name: "Tests DynamoDB"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: 'amazon/dynamodb-local:latest'
|
||||
ports:
|
||||
- '8000:8000'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./dynamodb && go test ./... -v -race
|
||||
38
.github/workflows/test-etcd.yml
vendored
Normal file
38
.github/workflows/test-etcd.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'etcd/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'etcd/**'
|
||||
name: "Tests Etcd"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install etcd
|
||||
run: |
|
||||
docker run -d --name Etcd-server \
|
||||
--publish 2379:2379 \
|
||||
--publish 2380:2380 \
|
||||
--env ALLOW_NONE_AUTHENTICATION=yes \
|
||||
--env ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 \
|
||||
bitnami/etcd:latest
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./etcd && go test ./... -v -race
|
||||
61
.github/workflows/test-memcache.yml
vendored
61
.github/workflows/test-memcache.yml
vendored
@@ -1,29 +1,34 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: Memcache
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'memcache/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'memcache/**'
|
||||
name: "Tests Memcache"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: 'memcached:latest'
|
||||
ports:
|
||||
- '11211:11211'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: cd ./memcache && go test ./... -v -race
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: 'memcached:latest'
|
||||
ports:
|
||||
- '11211:11211'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./memcache && go test ./... -v -race
|
||||
|
||||
29
.github/workflows/test-memory.yml
vendored
Normal file
29
.github/workflows/test-memory.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'memory/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'memory/**'
|
||||
name: "Tests Local Storage"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Test Memory
|
||||
run: cd ./memory && go test ./... -v -race
|
||||
31
.github/workflows/test-minio.yml
vendored
Normal file
31
.github/workflows/test-minio.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'minio/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'minio/**'
|
||||
name: "Tests Minio"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
- 1.23.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
env:
|
||||
TEST_MINIO_IMAGE: docker.io/minio/minio:RELEASE.2024-08-17T01-24-54Z
|
||||
run: cd ./minio && go test ./... -v -race
|
||||
28
.github/workflows/test-mockstorage.yml
vendored
Normal file
28
.github/workflows/test-mockstorage.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'mockstorage/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mockstorage/**'
|
||||
name: "Tests Local Storage"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Test Mockstorage
|
||||
run: cd ./mockstorage && go test ./... -v -race
|
||||
62
.github/workflows/test-mongodb.yml
vendored
62
.github/workflows/test-mongodb.yml
vendored
@@ -1,29 +1,35 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: MongoDB
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'mongodb/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mongodb/**'
|
||||
name: "Tests Mongodb"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: 'mongo:latest'
|
||||
ports:
|
||||
- '27017:27017'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: cd ./mongodb && go test ./... -v -race
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: 'mongo:latest'
|
||||
ports:
|
||||
- '27017:27017'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./mongodb && go test ./... -v -race
|
||||
|
||||
|
||||
50
.github/workflows/test-mssql.yml
vendored
Normal file
50
.github/workflows/test-mssql.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'mssql/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mssql/**'
|
||||
name: "Tests MSSQL"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mssql:
|
||||
image: 'mcmoe/mssqldocker:latest'
|
||||
ports:
|
||||
- '1433:1433'
|
||||
env:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: MsSql!1234
|
||||
MSSQL_DB: master
|
||||
MSSQL_USER: sa
|
||||
MSSQL_PASSWORD: MsSql!1234
|
||||
options: >-
|
||||
--health-cmd "/opt/mssql-tools/bin/sqlcmd -U sa -P $SA_PASSWORD -Q 'select 1' -b -o /dev/null"
|
||||
--health-interval 1s
|
||||
--health-timeout 30s
|
||||
--health-start-period 10s
|
||||
--health-retries 20
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./mssql && go test ./... -v -race
|
||||
env:
|
||||
MSSQL_DATABASE: master
|
||||
MSSQL_USERNAME: sa
|
||||
MSSQL_PASSWORD: MsSql!1234
|
||||
85
.github/workflows/test-mysql.yml
vendored
85
.github/workflows/test-mysql.yml
vendored
@@ -1,41 +1,46 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: MySQL
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'mysql/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'mysql/**'
|
||||
name: "Tests MySQL"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
image: 'mysql:latest'
|
||||
env:
|
||||
MYSQL_DATABASE: fiber
|
||||
MYSQL_USER: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
ports:
|
||||
- '3306:3306'
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping" --health-interval 10s --health-timeout
|
||||
5s --health-retries 5
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: cd ./mysql && go test ./... -v -race
|
||||
env:
|
||||
MYSQL_USERNAME: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_DATABASE: fiber
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mysql:
|
||||
image: 'mysql:latest'
|
||||
env:
|
||||
MYSQL_DATABASE: fiber
|
||||
MYSQL_USER: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
ports:
|
||||
- '3306:3306'
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping" --health-interval 10s --health-timeout
|
||||
5s --health-retries 5
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./mysql && go test ./... -v -race
|
||||
env:
|
||||
MYSQL_USERNAME: username
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_DATABASE: fiber
|
||||
|
||||
35
.github/workflows/test-nats.yml
vendored
Normal file
35
.github/workflows/test-nats.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'nats/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nats/**'
|
||||
name: "Tests Nats Driver"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Generate config
|
||||
run: ./.github/scripts/gen-test-certs.sh
|
||||
- name: Run NATS
|
||||
run: |
|
||||
docker run -d --name nats-jetstream -p 4443:4443 -v ./nats/testdata:/testdata -v ./tls:/tls nats:latest --jetstream -c /testdata/nats-tls.conf
|
||||
sleep 5
|
||||
- name: Test Nats
|
||||
run: cd ./nats && go test ./... -v -race
|
||||
29
.github/workflows/test-pebble.yml
vendored
Normal file
29
.github/workflows/test-pebble.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- "pebble/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "pebble/**"
|
||||
name: "Tests pebble"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Test Pebble
|
||||
run: cd ./pebble && go test ./... -v -race
|
||||
83
.github/workflows/test-postgres.yml
vendored
83
.github/workflows/test-postgres.yml
vendored
@@ -1,40 +1,45 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: Postgres
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'postgres/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'postgres/**'
|
||||
name: "Tests Postgres"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: 'postgres:latest'
|
||||
ports:
|
||||
- '5432:5432'
|
||||
env:
|
||||
POSTGRES_DB: fiber
|
||||
POSTGRES_USER: username
|
||||
POSTGRES_PASSWORD: password
|
||||
options: >-
|
||||
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
|
||||
--health-retries 5
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: cd ./postgres && go test ./... -v -race
|
||||
env:
|
||||
POSTGRES_DATABASE: fiber
|
||||
POSTGRES_USERNAME: username
|
||||
POSTGRES_PASSWORD: password
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: 'postgres:latest'
|
||||
ports:
|
||||
- '5432:5432'
|
||||
env:
|
||||
POSTGRES_DB: fiber
|
||||
POSTGRES_USER: username
|
||||
POSTGRES_PASSWORD: "pass#w%rd"
|
||||
options: >-
|
||||
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
|
||||
--health-retries 5
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
- 1.22.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./postgres && go test ./... -v -race
|
||||
env:
|
||||
POSTGRES_DATABASE: fiber
|
||||
POSTGRES_USERNAME: username
|
||||
POSTGRES_PASSWORD: "pass#w%rd"
|
||||
|
||||
105
.github/workflows/test-redis.yml
vendored
105
.github/workflows/test-redis.yml
vendored
@@ -1,29 +1,78 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: Redis
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'redis/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'redis/**'
|
||||
name: "Tests Redis"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
redis:
|
||||
image: 'redis:latest'
|
||||
ports:
|
||||
- '6379:6379'
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run Test
|
||||
run: cd ./redis && go test ./... -v -race
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
redis:
|
||||
- '6.x'
|
||||
- '7.x'
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate TLS certs
|
||||
run: ./.github/scripts/gen-test-certs.sh
|
||||
|
||||
- name: Add Custom CA cert
|
||||
run: sudo cp /home/runner/work/storage/storage/tls/ca.crt /usr/local/share/ca-certificates/custom.crt
|
||||
|
||||
- name: Trust Custom CA Cert
|
||||
run: sudo update-ca-certificates
|
||||
|
||||
- name: Setup Redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
auto-start: 'false'
|
||||
|
||||
- name: Run Redis
|
||||
run: |
|
||||
redis-server --tls-port 6380 --port 6379 \
|
||||
--tls-cert-file /home/runner/work/storage/storage/tls/redis.crt \
|
||||
--tls-key-file /home/runner/work/storage/storage/tls/redis.key \
|
||||
--tls-ca-cert-file /home/runner/work/storage/storage/tls/ca.crt &
|
||||
|
||||
- name: Run Redis instance with MTLS disabled
|
||||
run: |
|
||||
redis-server --tls-port 16380 --port 16379 \
|
||||
--tls-cert-file /home/runner/work/storage/storage/tls/redis.crt \
|
||||
--tls-key-file /home/runner/work/storage/storage/tls/redis.key \
|
||||
--tls-ca-cert-file /home/runner/work/storage/storage/tls/ca.crt \
|
||||
--tls-auth-clients no &
|
||||
|
||||
- name: Setup Redis Cluster
|
||||
uses: vishnudxb/redis-cluster@1.0.9
|
||||
with:
|
||||
master1-port: 7000
|
||||
master2-port: 7001
|
||||
master3-port: 7002
|
||||
slave1-port: 7003
|
||||
slave2-port: 7004
|
||||
slave3-port: 7005
|
||||
sleep-duration: 10
|
||||
|
||||
- name: Wait for Redis to Start
|
||||
run: sleep 15
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
|
||||
- name: Run Test
|
||||
run: cd ./redis && go test ./... -v -race
|
||||
|
||||
29
.github/workflows/test-ristretto.yml
vendored
Normal file
29
.github/workflows/test-ristretto.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'ristretto/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'ristretto/**'
|
||||
name: "Tests Ristretto"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./ristretto && go test ./... -v -race
|
||||
62
.github/workflows/test-rueidis.yml
vendored
Normal file
62
.github/workflows/test-rueidis.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'rueidis/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'rueidis/**'
|
||||
name: "Tests Rueidis"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
redis:
|
||||
- '6.x'
|
||||
- '7.x'
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate TLS certs
|
||||
run: ./.github/scripts/gen-test-certs.sh
|
||||
|
||||
- name: Setup Redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
auto-start: 'false'
|
||||
redis-port: '6379'
|
||||
redis-tls-port: '6380'
|
||||
|
||||
- name: Run Redis
|
||||
run: |
|
||||
redis-server --tls-port 6380 --port 6379 \
|
||||
--tls-cert-file /home/runner/work/storage/storage/tls/redis.crt \
|
||||
--tls-key-file /home/runner/work/storage/storage/tls/redis.key \
|
||||
--tls-ca-cert-file /home/runner/work/storage/storage/tls/ca.crt &
|
||||
|
||||
- name: Setup Redis Cluster
|
||||
uses: vishnudxb/redis-cluster@1.0.9
|
||||
with:
|
||||
master1-port: 7000
|
||||
master2-port: 7001
|
||||
master3-port: 7002
|
||||
slave1-port: 7003
|
||||
slave2-port: 7004
|
||||
slave3-port: 7005
|
||||
sleep-duration: 10
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
|
||||
- name: Run Test
|
||||
run: cd ./rueidis && go test ./... -v -race
|
||||
31
.github/workflows/test-s3.yml
vendored
Normal file
31
.github/workflows/test-s3.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 's3/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 's3/**'
|
||||
name: "Tests S3"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
steps:
|
||||
- name: Install MinIO
|
||||
run: docker run -d --restart always -p 9000:9000 --name storage-minio -e MINIO_ROOT_USER='minio-user' -e MINIO_ROOT_PASSWORD='minio-password' minio/minio server /data
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Run Test
|
||||
run: cd ./s3 && go test ./... -v -race
|
||||
39
.github/workflows/test-scylladb.yml
vendored
Normal file
39
.github/workflows/test-scylladb.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'scylladb/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'scylladb/**'
|
||||
|
||||
name: "Tests ScyllaDb"
|
||||
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run ScyllaDb
|
||||
run: |
|
||||
docker run --name scylladb -p 9042:9042 -p 19042:19042 -p 9160:9160 -p 10000:10000 -p 7000:7000 -p 7001:7001 -p 7199:7199 -p 9180:9180 -d scylladb/scylla:latest --broadcast-address 127.0.0.1 --listen-address 0.0.0.0 --broadcast-rpc-address 127.0.0.1
|
||||
sleep 30 # Wait for ScyllaDb to initialize
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
|
||||
- name: Run Test
|
||||
run: cd ./scylladb && go test ./... -v -race
|
||||
33
.github/workflows/test-sqlite3.yml
vendored
Normal file
33
.github/workflows/test-sqlite3.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'sqlite3/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'sqlite3/**'
|
||||
name: "Tests Sqlite3"
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.21.x
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Test SQLite3 - with -race check
|
||||
if: runner.os != 'Windows'
|
||||
run: cd ./sqlite3 && go test ./... -v -race
|
||||
- name: Test SQLite3 - without -race check
|
||||
if: runner.os == 'Windows'
|
||||
run: cd ./sqlite3 && go test ./... -v
|
||||
63
.github/workflows/test-valkey.yml
vendored
Normal file
63
.github/workflows/test-valkey.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- 'valkey/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'valkey/**'
|
||||
- '.github/workflows/test-valkey.yml'
|
||||
name: "Tests Valkey"
|
||||
jobs:
|
||||
Tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.23.x
|
||||
valkey:
|
||||
- '7.x'
|
||||
- '8.x'
|
||||
steps:
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate TLS certs
|
||||
run: ./.github/scripts/gen-test-certs.sh
|
||||
|
||||
- name: Setup Valkey
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
distribution: 'valkey'
|
||||
redis-version: ${{ matrix.valkey }}
|
||||
auto-start: 'false'
|
||||
redis-port: '6379'
|
||||
redis-tls-port: '6380'
|
||||
|
||||
- name: Run Valkey
|
||||
run: |
|
||||
valkey-server --tls-port 6380 --port 6379 \
|
||||
--tls-cert-file /home/runner/work/storage/storage/tls/valkey.crt \
|
||||
--tls-key-file /home/runner/work/storage/storage/tls/valkey.key \
|
||||
--tls-ca-cert-file /home/runner/work/storage/storage/tls/ca.crt &
|
||||
|
||||
- name: Setup Valkey Cluster
|
||||
uses: vishnudxb/redis-cluster@1.0.9
|
||||
with:
|
||||
master1-port: 7000
|
||||
master2-port: 7001
|
||||
master3-port: 7002
|
||||
slave1-port: 7003
|
||||
slave2-port: 7004
|
||||
slave3-port: 7005
|
||||
sleep-duration: 10
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
|
||||
- name: Run Test
|
||||
run: cd ./valkey && go test ./... -v -race
|
||||
28
.github/workflows/test.yml
vendored
28
.github/workflows/test.yml
vendored
@@ -1,28 +0,0 @@
|
||||
'on':
|
||||
- push
|
||||
- pull_request
|
||||
name: Local Storage
|
||||
jobs:
|
||||
Tests:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
runs-on: '${{ matrix.platform }}'
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '${{ matrix.go-version }}'
|
||||
- name: Fetch Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Test Badger
|
||||
run: cd ./badger && go test ./... -v -race
|
||||
- name: Test Memory
|
||||
run: cd ./memory && go test ./... -v -race
|
||||
- name: Test SQLite3
|
||||
run: cd ./sqlite3 && go test ./... -v -race
|
||||
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
*.tmp
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# IDE files
|
||||
.vscode
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
# Misc
|
||||
*.fiber.gz
|
||||
*.fasthttp.gz
|
||||
*.pprof
|
||||
*.workspace
|
||||
|
||||
# Dependencies
|
||||
/vendor/
|
||||
vendor/
|
||||
vendor
|
||||
/Godeps/
|
||||
node_modules/
|
||||
|
||||
# Go specific
|
||||
go.work*
|
||||
78
README.md
Normal file
78
README.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: 👋 Welcome
|
||||
description: 📦 Premade storage drivers for 🚀 Fiber.
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img height="125" alt="Fiber" src="https://raw.githubusercontent.com/gofiber/storage/master/.github/logo-dark.svg#gh-dark-mode-only" />
|
||||
<img height="125" alt="Fiber" src="https://raw.githubusercontent.com/gofiber/storage/master/.github/logo.svg#gh-light-mode-only" />
|
||||
<br/>
|
||||
|
||||
<a href="https://pkg.go.dev/github.com/gofiber/storage?tab=doc">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%93%9A%20godoc-pkg-00ACD7.svg?color=00ACD7&style=flat"/>
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/gofiber/storage">
|
||||
<img src="https://img.shields.io/badge/%F0%9F%93%9D%20goreport-A%2B-75C46B"/>
|
||||
</a>
|
||||
<a href="https://gofiber.io/discord">
|
||||
<img src="https://img.shields.io/discord/704680098577514527?style=flat&label=%F0%9F%92%AC%20discord&color=00ACD7"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
Premade storage drivers that implement the [`Storage`](https://github.com/gofiber/storage/blob/main/storage.go) interface, designed to be used with various [Fiber middlewares](https://github.com/gofiber/fiber/tree/master/middleware).
|
||||
|
||||
```go
|
||||
// Storage interface for communicating with different database/key-value
|
||||
// providers. Visit https://github.com/gofiber/storage for more info.
|
||||
type Storage interface {
|
||||
// Get gets the value for the given key.
|
||||
// `nil, nil` is returned when the key does not exist
|
||||
Get(key string) ([]byte, error)
|
||||
|
||||
// Set stores the given value for the given key along
|
||||
// with an expiration value, 0 means no expiration.
|
||||
// Empty key or value will be ignored without an error.
|
||||
Set(key string, val []byte, exp time.Duration) error
|
||||
|
||||
// Delete deletes the value for the given key.
|
||||
// It returns no error if the storage does not contain the key,
|
||||
Delete(key string) error
|
||||
|
||||
// Reset resets the storage and delete all keys.
|
||||
Reset() error
|
||||
|
||||
// Close closes the storage and will stop any running garbage
|
||||
// collectors and open connections.
|
||||
Close() error
|
||||
}
|
||||
```
|
||||
|
||||
## 📑 Storage Implementations
|
||||
|
||||
- [ArangoDB](./arangodb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+ArangoDB%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-arangodb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [AzureBlob](./azureblob/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Azure+Blob%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-azureblob.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Badger](./badger/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Badger%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-badger.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Bbolt](./bbolt) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Bbolt%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-bbolt.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [CloudflareKV](./cloudflarekv/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+CloudflareKV%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-cloudflarekv.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Coherence](./coherence/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Coherence%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-coherence.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Couchbase](./couchbase/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Couchbase%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-couchbase.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [DynamoDB](./dynamodb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+DynamoDB%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-dynamodb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Etcd](./etcd/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Etcd%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-etcd.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Memcache](./memcache/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Memcache%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-memcache.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Memory](./memory/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Local+Storage%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-memory.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Minio](./minio/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Minio%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-minio.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [MockStorage](./mockstorage/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+MockStorage%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-mockstorage.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [MongoDB](./mongodb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Mongodb%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-mongodb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [MSSQL](./mssql/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+MSSQL%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-mssql.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [MySQL](./mysql/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+MySQL%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-mysql.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [NATS](./nats/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests%20Nats%20Driver%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-nats.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Pebble](./pebble/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Pebble%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-pebble.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Postgres](./postgres/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Postgres%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-postgres.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Redis](./redis/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Redis%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-redis.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Rueidis](./rueidis/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+rueidis%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-rueidis.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [S3](./s3/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+S3%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-s3.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [ScyllaDB](./scylladb/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+scylladb%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-scylladb.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [SQLite3](./sqlite3/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Sqlite3%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-sqlite3.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [ClickHouse](./clickhouse/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+Clickhouse%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-clickhouse.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
- [Valkey](./valkey/README.md) <a href="https://github.com/gofiber/storage/actions?query=workflow%3A%22Tests+valkey%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/storage/test-valkey.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" /> </a>
|
||||
120
arangodb/README.md
Normal file
120
arangodb/README.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
id: arangodb
|
||||
title: ArangoDB
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
A ArangoDB storage driver using `arangodb/go-driver` and [arangodb/go-driver](https://github.com/arangodb/go-driver).
|
||||
|
||||
**Note: Requires Go 1.19 and above**
|
||||
|
||||
### Table of Contents
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() driver.Client
|
||||
```
|
||||
### Installation
|
||||
ArangoDB is tested on the 2 last (1.14/1.15) [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
And then install the mysql implementation:
|
||||
```bash
|
||||
go get github.com/gofiber/storage/arangodb/v2
|
||||
```
|
||||
|
||||
### Examples
|
||||
Import the storage package.
|
||||
```go
|
||||
import "github.com/gofiber/storage/arangodb/v2"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
```go
|
||||
// Initialize default config
|
||||
store := arangodb.New()
|
||||
|
||||
// Initialize custom config
|
||||
store := arangodb.New(arangodb.Config{
|
||||
Host: "http://127.0.0.1",
|
||||
Port: 8529,
|
||||
Database: "fiber",
|
||||
Collection: "fiber_storage",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
```go
|
||||
type Config struct {
|
||||
// Host name where the DB is hosted
|
||||
//
|
||||
// Optional. Default is "http://127.0.0.1"
|
||||
Host string
|
||||
|
||||
// Port where the DB is listening on
|
||||
//
|
||||
// Optional. Default is 8529
|
||||
Port int
|
||||
|
||||
// Server username
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
|
||||
// Server password
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// Database name
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// Collection name
|
||||
//
|
||||
// Optional. Default is "fiber_storage"
|
||||
Collection string
|
||||
|
||||
// Reset clears any existing keys in existing collection
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
Used only for optional fields
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Host: "http://127.0.0.1",
|
||||
Port: 8529,
|
||||
Database: "fiber",
|
||||
Collection: "fiber_storage",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
}
|
||||
```
|
||||
253
arangodb/arangodb.go
Normal file
253
arangodb/arangodb.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/arangodb/go-driver/http"
|
||||
"github.com/gofiber/utils/v2"
|
||||
)
|
||||
|
||||
// Storage interface that is implemented by storage providers
|
||||
type Storage struct {
|
||||
db driver.Database
|
||||
gcInterval time.Duration
|
||||
done chan struct{}
|
||||
|
||||
// Arango mandatory fields
|
||||
connection driver.Connection
|
||||
client driver.Client
|
||||
collection driver.Collection
|
||||
bindingParams map[string]interface{}
|
||||
config Config
|
||||
// AQL query used to remove expired keys
|
||||
aqlRemoveGC string
|
||||
}
|
||||
|
||||
type model struct {
|
||||
// respect key format field name for ArangoDB
|
||||
Key string `json:"_key"`
|
||||
Val string `json:"val"`
|
||||
Exp int64 `json:"exp"`
|
||||
}
|
||||
|
||||
// New creates a new storage
|
||||
func New(config ...Config) *Storage {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// create connection object to arango
|
||||
conn, err := http.NewConnection(http.ConnectionConfig{
|
||||
Endpoints: []string{fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// instantiate client after the connection is started
|
||||
client, err := driver.NewClient(driver.ClientConfig{
|
||||
Connection: conn,
|
||||
Authentication: driver.BasicAuthentication(cfg.Username, cfg.Password),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// check if the database exists
|
||||
// if not create it
|
||||
// (it works only with admin privilege user)
|
||||
exists, err := client.DatabaseExists(context.Background(), cfg.Database)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !exists {
|
||||
_, err = client.CreateDatabase(context.Background(), cfg.Database, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
database, err := client.Database(context.Background(), cfg.Database)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
found, _ := database.CollectionExists(context.Background(), cfg.Collection)
|
||||
|
||||
// Create the collection if not exists
|
||||
var collection driver.Collection
|
||||
if !found {
|
||||
// Create
|
||||
collection, err = database.CreateCollection(context.Background(), cfg.Collection, &driver.CreateCollectionOptions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
// Get the collection
|
||||
collection, err = database.Collection(context.Background(), cfg.Collection)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate collection if Reset set to true
|
||||
if cfg.Reset {
|
||||
err = collection.Truncate(context.Background())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create storage
|
||||
store := &Storage{
|
||||
gcInterval: cfg.GCInterval,
|
||||
db: database,
|
||||
collection: collection,
|
||||
client: client,
|
||||
connection: conn,
|
||||
config: cfg,
|
||||
done: make(chan struct{}),
|
||||
aqlRemoveGC: fmt.Sprintf("FOR doc IN %s\n FILTER doc.exp <= @exp \n REMOVE { _key: doc._key } IN %s", collection.Name(), collection.Name()),
|
||||
}
|
||||
|
||||
// Start garbage collector
|
||||
go store.gc()
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
// Get value by key
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
if len(key) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Check if the document exists
|
||||
// to avoid errors later
|
||||
exists, err := s.collection.DocumentExists(ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// instead of returning an error if not exists
|
||||
// return nil
|
||||
if !exists {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// result model
|
||||
var model model
|
||||
_, err = s.collection.ReadDocument(ctx, key, &model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If the expiration time has already passed, then return nil
|
||||
if model.Exp != 0 && model.Exp <= time.Now().Unix() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return utils.UnsafeBytes(model.Val), nil
|
||||
}
|
||||
|
||||
// Set key with value
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||
// Ain't Nobody Got Time For That
|
||||
if len(key) <= 0 || len(val) <= 0 {
|
||||
return nil
|
||||
}
|
||||
var expireAt int64
|
||||
if exp != 0 {
|
||||
expireAt = time.Now().Add(exp).Unix()
|
||||
}
|
||||
valStr := utils.UnsafeString(val)
|
||||
|
||||
// create the structure for the storage
|
||||
data := model{
|
||||
Key: key,
|
||||
Val: valStr,
|
||||
Exp: expireAt,
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
// Arango does not support documents with the same key
|
||||
// So we need to check if the document exists
|
||||
exists, err := s.collection.DocumentExists(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update the document if exists
|
||||
if exists {
|
||||
_, err = s.collection.UpdateDocument(ctx, key, data)
|
||||
return err
|
||||
}
|
||||
// Otherwise create it
|
||||
_, err = s.collection.CreateDocument(ctx, data)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete value by key
|
||||
func (s *Storage) Delete(key string) error {
|
||||
// Ain't Nobody Got Time For That
|
||||
if len(key) <= 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := s.collection.RemoveDocument(context.Background(), key)
|
||||
return err
|
||||
}
|
||||
|
||||
// Reset all keys
|
||||
// truncate the collection
|
||||
func (s *Storage) Reset() error {
|
||||
return s.collection.Truncate(context.Background())
|
||||
}
|
||||
|
||||
// Close the database
|
||||
// Arango does not provide a method to close the connection
|
||||
// more info @https://github.com/arangodb/go-driver/issues/43
|
||||
func (s *Storage) Close() error {
|
||||
// Stop gc
|
||||
s.done <- struct{}{}
|
||||
// reset connection params
|
||||
s.db = nil
|
||||
s.collection = nil
|
||||
s.connection = nil
|
||||
s.bindingParams = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// execute query
|
||||
func (s *Storage) exec(query string) error {
|
||||
// execute query
|
||||
_, err := s.db.Query(context.Background(), query, s.bindingParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// reset binding params
|
||||
s.bindingParams = map[string]interface{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Garbage collector to delete expired keys
|
||||
func (s *Storage) gc() {
|
||||
ticker := time.NewTicker(s.gcInterval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-s.done:
|
||||
return
|
||||
case t := <-ticker.C:
|
||||
// set the expiration
|
||||
s.bindingParams["exp"] = t.Unix()
|
||||
_ = s.exec(s.aqlRemoveGC)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return database client
|
||||
func (s *Storage) Conn() driver.Client {
|
||||
return s.client
|
||||
}
|
||||
172
arangodb/arangodb_test.go
Normal file
172
arangodb/arangodb_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testStore = New(Config{
|
||||
Reset: true,
|
||||
})
|
||||
|
||||
func Test_ArangoDB_Set(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Upsert(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Get(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, val, result)
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Set_Expiration(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
exp = 1 * time.Second
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, exp)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(1100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Get_Expired(t *testing.T) {
|
||||
key := "john"
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Get_NotExist(t *testing.T) {
|
||||
result, err := testStore.Get("notexist")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Delete(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Reset(t *testing.T) {
|
||||
val := []byte("doe")
|
||||
|
||||
err := testStore.Set("john1", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set("john2", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Reset()
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get("john1")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
|
||||
result, err = testStore.Get("john2")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Non_UTF8(t *testing.T) {
|
||||
val := []byte("0xF5")
|
||||
|
||||
err := testStore.Set("0xF6", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get("0xF6")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, val, result)
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Close(t *testing.T) {
|
||||
require.Nil(t, testStore.Close())
|
||||
}
|
||||
|
||||
func Test_ArangoDB_Conn(t *testing.T) {
|
||||
require.True(t, testStore.Conn() != nil)
|
||||
}
|
||||
|
||||
func Benchmark_ArangoDB_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_ArangoDB_Get(b *testing.B) {
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_ArangoDB_SetAndDelete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
92
arangodb/config.go
Normal file
92
arangodb/config.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package arangodb
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Host name where the DB is hosted
|
||||
//
|
||||
// Optional. Default is "http://127.0.0.1"
|
||||
Host string
|
||||
|
||||
// Port where the DB is listening on
|
||||
//
|
||||
// Optional. Default is 8529
|
||||
Port int
|
||||
|
||||
// Server username
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Username string
|
||||
|
||||
// Server password
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Password string
|
||||
|
||||
// Database name
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
Database string
|
||||
|
||||
// Collection name
|
||||
//
|
||||
// Optional. Default is "fiber_storage"
|
||||
Collection string
|
||||
|
||||
// Reset clears any existing keys in existing collection
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
// Time before deleting expired keys
|
||||
//
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Host: "http://127.0.0.1",
|
||||
Port: 8529,
|
||||
Database: "fiber",
|
||||
Collection: "fiber_storage",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Host == "" {
|
||||
cfg.Host = ConfigDefault.Host
|
||||
} else {
|
||||
if !strings.HasPrefix(cfg.Host, "http") {
|
||||
panic("Host should start with `http://` or `https://`")
|
||||
}
|
||||
}
|
||||
if cfg.Port <= 0 {
|
||||
cfg.Port = ConfigDefault.Port
|
||||
}
|
||||
if cfg.Database == "" {
|
||||
cfg.Database = ConfigDefault.Database
|
||||
}
|
||||
if cfg.Collection == "" {
|
||||
cfg.Collection = ConfigDefault.Collection
|
||||
}
|
||||
|
||||
if int(cfg.GCInterval.Seconds()) <= 0 {
|
||||
cfg.GCInterval = ConfigDefault.GCInterval
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
18
arangodb/go.mod
Normal file
18
arangodb/go.mod
Normal file
@@ -0,0 +1,18 @@
|
||||
module github.com/gofiber/storage/arangodb/v2
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/arangodb/go-driver v1.6.2
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
24
arangodb/go.sum
Normal file
24
arangodb/go.sum
Normal file
@@ -0,0 +1,24 @@
|
||||
github.com/arangodb/go-driver v1.6.2 h1:3o4inejwR7VMmsKvQJ6hepx4au9sUT6C/RDrXykuD1g=
|
||||
github.com/arangodb/go-driver v1.6.2/go.mod h1:2BCE6y3DNSLqIXnDvf4CR6WdzZZloYudEy+sasimLiQ=
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g=
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3 h1:pfOhUDDVjBJpkWv6C5jaDyYLvpui7zQ97zpyFFsUOKw=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3/go.mod h1:jsl17+MsKfwJjM3ONCE9Rzji/j8XNbwjhUVTjzgfDCo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
112
azureblob/README.md
Normal file
112
azureblob/README.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
id: azureblob
|
||||
title: Azure Blob
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
[Azure Blob storage](https://azure.microsoft.com/en-us/products/storage/blobs/#overview) is Microsoft's object storage solution for the cloud.
|
||||
|
||||
**Note: Requires Go 1.19 and above**
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *azblob.Client
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
Azure blob storage driver is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
|
||||
And then install the azure blob implementation:
|
||||
|
||||
```bash
|
||||
go get github.com/gofiber/storage/azureblob/v2
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Import the storage package.
|
||||
|
||||
```go
|
||||
import "github.com/gofiber/storage/azureblob/v2"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
store := azureblob.New()
|
||||
|
||||
// Initialize custom config
|
||||
store := azureblob.New(azureblob.Config{
|
||||
Account: "test",
|
||||
Container: "test",
|
||||
Credentials: Credentials{
|
||||
Account: "test",
|
||||
Key: "YXp1cml0ZWtleQo=",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
// Storage account name.
|
||||
Account string
|
||||
// Container name.
|
||||
Container string
|
||||
// Storage endpoint.
|
||||
// Optional. Default: "https://STORAGEACCOUNTNAME.blob.core.windows.net"
|
||||
Endpoint string
|
||||
// Request timeout.
|
||||
// Optional. Default is 0 (no timeout)
|
||||
RequestTimeout time.Duration
|
||||
// Reset clears any existing keys in existing container.
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
// Credentials overrides AWS access key and AWS secret access key. Not recommended.
|
||||
// Optional. Default is Credentials{}
|
||||
Credentials Credentials
|
||||
// The maximum number of times requests that encounter retryable failures should be attempted.
|
||||
// Optional. Default is 3
|
||||
MaxAttempts int
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Account: "",
|
||||
Container: "",
|
||||
Endpoint: "",
|
||||
RequestTimeout: 0,
|
||||
Reset: false,
|
||||
MaxAttempts: 3,
|
||||
}
|
||||
```
|
||||
138
azureblob/azureblob.go
Normal file
138
azureblob/azureblob.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package azureblob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
|
||||
)
|
||||
|
||||
// Storage interface that is implemented by storage providers
|
||||
type Storage struct {
|
||||
client *azblob.Client
|
||||
container string
|
||||
requestTimeout time.Duration
|
||||
}
|
||||
|
||||
// New creates a new storage
|
||||
func New(config ...Config) *Storage {
|
||||
// Set default config
|
||||
cfg := configure(config...)
|
||||
// Set the azure credentials
|
||||
cred, err := azblob.NewSharedKeyCredential(cfg.Credentials.Account, cfg.Credentials.Key)
|
||||
handleError(err)
|
||||
client, err := azblob.NewClientWithSharedKeyCredential(cfg.Endpoint, cred, nil)
|
||||
handleError(err)
|
||||
_, err = client.CreateContainer(context.TODO(), cfg.Container, nil)
|
||||
if err != nil {
|
||||
if !bloberror.HasCode(err, bloberror.ContainerAlreadyExists) {
|
||||
panic(fmt.Sprintf("invalid config:, %v", err))
|
||||
}
|
||||
}
|
||||
storage := &Storage{
|
||||
client: client,
|
||||
container: cfg.Container,
|
||||
requestTimeout: cfg.RequestTimeout,
|
||||
}
|
||||
|
||||
// Reset all entries if set to true
|
||||
if cfg.Reset {
|
||||
if err := storage.Reset(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
// Get value by key
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
if len(key) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ctx, cancel := s.requestContext()
|
||||
defer cancel()
|
||||
resp, err := s.client.DownloadStream(ctx, s.container, key, nil)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
return data, err
|
||||
}
|
||||
|
||||
// Set key with value
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||
if len(key) <= 0 {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := s.requestContext()
|
||||
defer cancel()
|
||||
_, err := s.client.UploadBuffer(ctx, s.container, key, val, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete entry by key
|
||||
func (s *Storage) Delete(key string) error {
|
||||
if len(key) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := s.requestContext()
|
||||
defer cancel()
|
||||
_, err := s.client.DeleteBlob(ctx, s.container, key, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Reset all entries
|
||||
func (s *Storage) Reset() error {
|
||||
ctx, cancel := s.requestContext()
|
||||
defer cancel()
|
||||
//_, err := s.client.DeleteContainer(ctx, s.container, nil)
|
||||
//return err
|
||||
pager := s.client.NewListBlobsFlatPager(s.container, nil)
|
||||
errCounter := 0
|
||||
for pager.More() {
|
||||
resp, err := pager.NextPage(ctx)
|
||||
if err != nil {
|
||||
errCounter = errCounter + 1
|
||||
}
|
||||
for _, v := range resp.Segment.BlobItems {
|
||||
_, err = s.client.DeleteBlob(ctx, s.container, *v.Name, nil)
|
||||
if err != nil {
|
||||
errCounter = errCounter + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if errCounter > 0 {
|
||||
return fmt.Errorf("%d errors occured while resetting", errCounter)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conn returns storage client
|
||||
func (s *Storage) Conn() *azblob.Client {
|
||||
return s.client
|
||||
}
|
||||
|
||||
// Close the storage connextion
|
||||
func (s *Storage) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Context for making requests will timeout if a non-zero timeout is configured
|
||||
func (s *Storage) requestContext() (context.Context, context.CancelFunc) {
|
||||
if s.requestTimeout > 0 {
|
||||
return context.WithTimeout(context.Background(), s.requestTimeout)
|
||||
}
|
||||
return context.Background(), func() {}
|
||||
}
|
||||
|
||||
// handleError is a helper to panic on error
|
||||
func handleError(err error) {
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("invalid config:, %v", err))
|
||||
}
|
||||
}
|
||||
177
azureblob/azureblob_test.go
Normal file
177
azureblob/azureblob_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package azureblob
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testStore = New(Config{
|
||||
Account: "devstoreaccount1",
|
||||
Container: "test",
|
||||
Endpoint: "http://127.0.0.1:10000/devstoreaccount1",
|
||||
Credentials: Credentials{
|
||||
Account: "devstoreaccount1",
|
||||
Key: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==",
|
||||
},
|
||||
Reset: true,
|
||||
})
|
||||
|
||||
code := m.Run()
|
||||
|
||||
_ = testStore.Close()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Get(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, val, result)
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Set(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Delete(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
if err != nil {
|
||||
if bloberror.HasCode(err, bloberror.BlobNotFound) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Override(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Get_NotExist(t *testing.T) {
|
||||
result, err := testStore.Get("notexist")
|
||||
if err != nil {
|
||||
if bloberror.HasCode(err, bloberror.BlobNotFound) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Reset(t *testing.T) {
|
||||
val := []byte("doe")
|
||||
|
||||
err := testStore.Set("john1", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set("john2", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Reset()
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get("john1")
|
||||
if err != nil {
|
||||
if bloberror.HasCode(err, bloberror.BlobNotFound) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
|
||||
result, err = testStore.Get("john2")
|
||||
if err != nil {
|
||||
if bloberror.HasCode(err, bloberror.BlobNotFound) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_S3_Conn(t *testing.T) {
|
||||
require.True(t, testStore.Conn() != nil)
|
||||
}
|
||||
|
||||
func Test_AzureBlob_Close(t *testing.T) {
|
||||
require.Nil(t, testStore.Close())
|
||||
}
|
||||
|
||||
func Benchmark_AzureBlob_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_AzureBlob_Get(b *testing.B) {
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_AzureBlob_SetAndDelete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
80
azureblob/config.go
Normal file
80
azureblob/config.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package azureblob
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Storage account name.
|
||||
Account string
|
||||
// Container name.
|
||||
Container string
|
||||
// Storage endpoint.
|
||||
// Optional. Default: "https://STORAGEACCOUNTNAME.blob.core.windows.net"
|
||||
Endpoint string
|
||||
// Request timeout.
|
||||
// Optional. Default is 0 (no timeout)
|
||||
RequestTimeout time.Duration
|
||||
// Reset clears any existing keys in existing container.
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
// Credentials overrides AWS access key and AWS secret access key. Not recommended.
|
||||
// Optional. Default is Credentials{}
|
||||
Credentials Credentials
|
||||
// The maximum number of times requests that encounter retryable failures should be attempted.
|
||||
// Optional. Default is 3
|
||||
MaxAttempts int
|
||||
}
|
||||
|
||||
// Credentials are the azure storage account access keys
|
||||
type Credentials struct {
|
||||
Account string
|
||||
Key string
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Account: "",
|
||||
Container: "",
|
||||
Endpoint: "",
|
||||
RequestTimeout: 0,
|
||||
Reset: false,
|
||||
MaxAttempts: 3,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configure(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
valid, err := validateConfig(cfg)
|
||||
if err != nil || !valid {
|
||||
panic(fmt.Sprintf("invalid config:, %v", err))
|
||||
}
|
||||
if cfg.Endpoint == "" {
|
||||
cfg.Endpoint = "https://" + cfg.Account + ".blob.core.windows.net"
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func validateConfig(config Config) (bool, error) {
|
||||
if config.Credentials.Account == "" || config.Credentials.Key == "" {
|
||||
err := errors.New("credentials must not be empty")
|
||||
return false, err
|
||||
}
|
||||
if config.Account == "" || config.Container == "" {
|
||||
err := errors.New("invalid account information provided")
|
||||
return false, err
|
||||
}
|
||||
if config.Account != config.Credentials.Account {
|
||||
err := errors.New("account configuration mismatch")
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
18
azureblob/go.mod
Normal file
18
azureblob/go.mod
Normal file
@@ -0,0 +1,18 @@
|
||||
module github.com/gofiber/storage/azureblob/v2
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
32
azureblob/go.sum
Normal file
32
azureblob/go.sum
Normal file
@@ -0,0 +1,32 @@
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 h1:Be6KInmFEKV81c0pOAEbRYehLMwmmGI1exuFj248AMk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0/go.mod h1:WCPBHsOXfBVnivScjs2ypRfimjEW0qPVLGgJkZlrIOA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
3
badger/.gitignore
vendored
Normal file
3
badger/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
fiber.badger/
|
||||
fiber.config.badger/
|
||||
fiber.with_options.badger/
|
||||
@@ -1,45 +1,62 @@
|
||||
# Badger
|
||||
---
|
||||
id: badger
|
||||
title: Badger
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
A fast key-value DB using [dgraph-io/badger](https://github.com/dgraph-io/badger)
|
||||
|
||||
**Note: Requires Go 1.19 and above**
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
|
||||
### Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
|
||||
var ErrNotExist = errors.New("key does not exist")
|
||||
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *badger.DB
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
Badger is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
|
||||
And then install the badger implementation:
|
||||
|
||||
```bash
|
||||
go get github.com/gofiber/storage/badger
|
||||
go get github.com/gofiber/storage/badger/v2
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Import the storage package.
|
||||
|
||||
```go
|
||||
import "github.com/gofiber/storage/badger"
|
||||
import "github.com/gofiber/storage/badger/v2"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
store := badger.New()
|
||||
@@ -53,6 +70,7 @@ store := badger.New(badger.Config{
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
// Database name
|
||||
@@ -69,14 +87,33 @@ type Config struct {
|
||||
//
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
|
||||
// BadgerOptions is a way to set options in badger
|
||||
//
|
||||
// Optional. Default is badger.DefaultOptions("./fiber.badger")
|
||||
BadgerOptions badger.Options
|
||||
|
||||
// Logger is the default logger used by badger
|
||||
//
|
||||
// Optional. Default is nil
|
||||
Logger badger.Logger
|
||||
|
||||
// UseLogger define if any logger will be used
|
||||
//
|
||||
// Optional. Default is false
|
||||
UseLogger bool
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Database: "./fiber.badger",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
Database: "./fiber.badger",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
BadgerOptions: badger.DefaultOptions("./fiber.badger").WithLogger(nil),
|
||||
Logger: nil,
|
||||
UseLogger: false,
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package badger
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger"
|
||||
"github.com/gofiber/utils"
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
"github.com/gofiber/utils/v2"
|
||||
)
|
||||
|
||||
// Storage interface that is implemented by storage providers
|
||||
@@ -15,16 +14,13 @@ type Storage struct {
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// Common storage errors
|
||||
var ErrNotExist = errors.New("key does not exist")
|
||||
|
||||
// New creates a new memory storage
|
||||
func New(config ...Config) *Storage {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Set options
|
||||
opt := badger.DefaultOptions(cfg.Database).WithTruncate(true).WithLogger(nil)
|
||||
opt := cfg.BadgerOptions
|
||||
|
||||
// Open database
|
||||
db, err := badger.Open(opt)
|
||||
@@ -53,6 +49,9 @@ func New(config ...Config) *Storage {
|
||||
|
||||
// Get value by key
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
if len(key) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var data []byte
|
||||
err := s.db.View(func(txn *badger.Txn) error {
|
||||
item, err := txn.Get([]byte(key))
|
||||
@@ -68,7 +67,7 @@ func (s *Storage) Get(key string) ([]byte, error) {
|
||||
})
|
||||
// If no value was found return false
|
||||
if err == badger.ErrKeyNotFound {
|
||||
return data, ErrNotExist
|
||||
return nil, nil
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
@@ -124,3 +123,8 @@ func (s *Storage) gc() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return database client
|
||||
func (s *Storage) Conn() *badger.DB {
|
||||
return s.db
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testStore = New()
|
||||
var testStore = New(Config{
|
||||
Reset: true,
|
||||
})
|
||||
|
||||
func Test_Badger_Set(t *testing.T) {
|
||||
var (
|
||||
@@ -16,7 +18,7 @@ func Test_Badger_Set(t *testing.T) {
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Badger_Set_Override(t *testing.T) {
|
||||
@@ -26,10 +28,10 @@ func Test_Badger_Set_Override(t *testing.T) {
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Badger_Get(t *testing.T) {
|
||||
@@ -39,11 +41,11 @@ func Test_Badger_Get(t *testing.T) {
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, val, result)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Badger_Set_Expiration(t *testing.T) {
|
||||
@@ -54,26 +56,23 @@ func Test_Badger_Set_Expiration(t *testing.T) {
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, exp)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(1100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func Test_Badger_Get_Expired(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
)
|
||||
key := "john"
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Badger_Get_NotExist(t *testing.T) {
|
||||
|
||||
result, err := testStore.Get("notexist")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Badger_Delete(t *testing.T) {
|
||||
@@ -83,39 +82,80 @@ func Test_Badger_Delete(t *testing.T) {
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Badger_Reset(t *testing.T) {
|
||||
var (
|
||||
val = []byte("doe")
|
||||
)
|
||||
val := []byte("doe")
|
||||
|
||||
err := testStore.Set("john1", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set("john2", val, 0)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Reset()
|
||||
utils.AssertEqual(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get("john1")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
|
||||
result, err = testStore.Get("john2")
|
||||
utils.AssertEqual(t, ErrNotExist, err)
|
||||
utils.AssertEqual(t, true, len(result) == 0)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Badger_Close(t *testing.T) {
|
||||
utils.AssertEqual(t, nil, testStore.Close())
|
||||
require.Nil(t, testStore.Close())
|
||||
}
|
||||
|
||||
func Test_Badger_Conn(t *testing.T) {
|
||||
require.True(t, testStore.Conn() != nil)
|
||||
}
|
||||
|
||||
func Benchmark_Badger_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Badger_Get(b *testing.B) {
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Badger_SetAndDelete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package badger
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
)
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
@@ -18,13 +22,33 @@ type Config struct {
|
||||
//
|
||||
// Optional. Default is 10 * time.Second
|
||||
GCInterval time.Duration
|
||||
|
||||
// BadgerOptions is a way to set options in badger
|
||||
//
|
||||
// Optional. Default is badger.DefaultOptions("./fiber.badger")
|
||||
BadgerOptions badger.Options
|
||||
|
||||
// Logger is the default logger used by badger
|
||||
//
|
||||
// Optional. Default is nil
|
||||
Logger badger.Logger
|
||||
|
||||
// UseLogger define if any logger will be used
|
||||
//
|
||||
// Optional. Default is false
|
||||
UseLogger bool
|
||||
}
|
||||
|
||||
const defaultDatabase = "./fiber.badger"
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Database: "./fiber.badger",
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
Database: defaultDatabase,
|
||||
Reset: false,
|
||||
GCInterval: 10 * time.Second,
|
||||
BadgerOptions: badger.DefaultOptions(defaultDatabase).WithLogger(nil),
|
||||
Logger: nil,
|
||||
UseLogger: false,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
@@ -41,8 +65,23 @@ func configDefault(config ...Config) Config {
|
||||
if cfg.Database == "" {
|
||||
cfg.Database = ConfigDefault.Database
|
||||
}
|
||||
if int(cfg.GCInterval) == 0 {
|
||||
if int(cfg.GCInterval.Seconds()) <= 0 {
|
||||
cfg.GCInterval = ConfigDefault.GCInterval
|
||||
}
|
||||
overrideLogger := false
|
||||
// Detecting if no default Badger option was given
|
||||
// Also detects when a default badger option is given with a custom database name
|
||||
if cfg.BadgerOptions.ValueLogFileSize <= 0 || cfg.BadgerOptions.Dir == "" || cfg.BadgerOptions.ValueDir == "" ||
|
||||
(cfg.BadgerOptions.Dir == defaultDatabase && cfg.BadgerOptions.Dir != cfg.Database) {
|
||||
cfg.BadgerOptions = badger.DefaultOptions(cfg.Database)
|
||||
overrideLogger = true
|
||||
}
|
||||
if overrideLogger {
|
||||
if cfg.UseLogger && cfg.Logger != nil {
|
||||
cfg.BadgerOptions = cfg.BadgerOptions.WithLogger(cfg.Logger)
|
||||
} else if !cfg.UseLogger {
|
||||
cfg.BadgerOptions = cfg.BadgerOptions.WithLogger(nil)
|
||||
}
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
37
badger/config_test.go
Normal file
37
badger/config_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package badger
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func assertRecoveryPanic(t *testing.T) {
|
||||
err := recover()
|
||||
require.Nil(t, nil, err)
|
||||
}
|
||||
|
||||
func Test_Badger_Only_Name(t *testing.T) {
|
||||
defer assertRecoveryPanic(t)
|
||||
testDB := New(Config{
|
||||
Database: "fiber.config.badger",
|
||||
UseLogger: false,
|
||||
})
|
||||
require.Nil(t, testDB.Close())
|
||||
}
|
||||
|
||||
func Test_Badger_Options(t *testing.T) {
|
||||
defer assertRecoveryPanic(t)
|
||||
testDB := New(Config{
|
||||
BadgerOptions: badger.DefaultOptions("fiber.with_options.badger"),
|
||||
UseLogger: false,
|
||||
})
|
||||
require.Nil(t, testDB.Close())
|
||||
}
|
||||
|
||||
func Test_Empty_Config(t *testing.T) {
|
||||
defer assertRecoveryPanic(t)
|
||||
testDB := New(Config{})
|
||||
require.Nil(t, testDB.Close())
|
||||
}
|
||||
@@ -1,9 +1,32 @@
|
||||
module github.com/gofiber/storage/badger
|
||||
module github.com/gofiber/storage/badger/v2
|
||||
|
||||
go 1.15
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/dgraph-io/badger v1.6.2
|
||||
github.com/gofiber/utils v0.1.2
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.1.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/flatbuffers v23.5.26+incompatible // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
183
badger/go.sum
183
badger/go.sum
@@ -1,42 +1,104 @@
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
|
||||
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
|
||||
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
|
||||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
|
||||
github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3 h1:pfOhUDDVjBJpkWv6C5jaDyYLvpui7zQ97zpyFFsUOKw=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3/go.mod h1:jsl17+MsKfwJjM3ONCE9Rzji/j8XNbwjhUVTjzgfDCo=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
@@ -45,22 +107,105 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
104
bbolt/README.md
Normal file
104
bbolt/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
id: bbolt
|
||||
title: Bbolt
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
A Bbolt storage driver using [etcd-io/bbolt](https://github.com/etcd-io/bbolt). Bolt is a pure Go key/value store inspired by [Howard Chu's](https://twitter.com/hyc_symas) [LMDB project](https://www.symas.com/symas-embedded-database-lmdb). The goal of the project is to provide a simple, fast, and reliable database for projects that don't require a full database server such as Postgres or MySQL.
|
||||
|
||||
**Note: Requires Go 1.19 and above**
|
||||
|
||||
### Table of Contents
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *bbolt.DB
|
||||
```
|
||||
### Installation
|
||||
Bbolt is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
And then install the s3 implementation:
|
||||
```bash
|
||||
go get github.com/gofiber/storage/bbolt/v2
|
||||
```
|
||||
|
||||
### Examples
|
||||
Import the storage package.
|
||||
```go
|
||||
import "github.com/gofiber/storage/bbolt/v2"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
```go
|
||||
// Initialize default config
|
||||
store := bbolt.New()
|
||||
|
||||
// Initialize custom config
|
||||
store := bbolt.New(bbolt.Config{
|
||||
Database: "my_database.db",
|
||||
Bucket: "my-bucket",
|
||||
Reset: false,
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
```go
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Database path
|
||||
//
|
||||
// Optional. Default is "fiber.db"
|
||||
Database string
|
||||
|
||||
// Bbolt bucket name
|
||||
//
|
||||
// Optional. Default is "fiber_storage"
|
||||
Bucket string
|
||||
|
||||
// Timeout is the amount of time to wait to obtain a file lock.
|
||||
// Only available on Darwin and Linux.
|
||||
//
|
||||
// Optional. Default is 60 * time.Second.
|
||||
Timeout time.Duration
|
||||
|
||||
// Open database in read-only mode.
|
||||
//
|
||||
// Optional. Default is false
|
||||
ReadOnly bool
|
||||
|
||||
// Reset clears any existing keys in existing Bucket
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
```go
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Database: "fiber.db",
|
||||
Bucket: "fiber_storage",
|
||||
Timeout: 60 * time.Second,
|
||||
ReadOnly: false,
|
||||
Reset: false,
|
||||
}
|
||||
```
|
||||
110
bbolt/bbolt.go
Normal file
110
bbolt/bbolt.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package bbolt
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/utils/v2"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
// Storage interface that is implemented by storage providers
|
||||
type Storage struct {
|
||||
conn *bbolt.DB
|
||||
bucket string
|
||||
}
|
||||
|
||||
// New creates a new storage
|
||||
func New(config ...Config) *Storage {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
conn, err := bbolt.Open(cfg.Database, 0o666, &bbolt.Options{
|
||||
Timeout: cfg.Timeout,
|
||||
ReadOnly: cfg.ReadOnly,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Reset bucket if field selected
|
||||
if cfg.Reset {
|
||||
if err := removeBucket(cfg, conn); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create bucket if not exists
|
||||
if err := createBucket(cfg, conn); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &Storage{
|
||||
conn: conn,
|
||||
bucket: cfg.Bucket,
|
||||
}
|
||||
}
|
||||
|
||||
// Get value by key
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
if len(key) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var value []byte
|
||||
|
||||
err := s.conn.View(func(tx *bbolt.Tx) error {
|
||||
b := tx.Bucket(utils.UnsafeBytes(s.bucket))
|
||||
value = b.Get(utils.UnsafeBytes(key))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return value, err
|
||||
}
|
||||
|
||||
// Set key with value
|
||||
func (s *Storage) Set(key string, value []byte, exp time.Duration) error {
|
||||
if len(key) <= 0 || len(value) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.conn.Update(func(tx *bbolt.Tx) error {
|
||||
b := tx.Bucket(utils.UnsafeBytes(s.bucket))
|
||||
|
||||
return b.Put(utils.UnsafeBytes(key), value)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete entry by key
|
||||
func (s *Storage) Delete(key string) error {
|
||||
if len(key) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.conn.Update(func(tx *bbolt.Tx) error {
|
||||
b := tx.Bucket(utils.UnsafeBytes(s.bucket))
|
||||
|
||||
return b.Delete(utils.UnsafeBytes(key))
|
||||
})
|
||||
}
|
||||
|
||||
// Reset all entries
|
||||
func (s *Storage) Reset() error {
|
||||
return s.conn.Update(func(tx *bbolt.Tx) error {
|
||||
b := tx.Bucket(utils.UnsafeBytes(s.bucket))
|
||||
|
||||
return b.ForEach(func(k, _ []byte) error {
|
||||
return b.Delete(k)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Close the database
|
||||
func (s *Storage) Close() error {
|
||||
return s.conn.Close()
|
||||
}
|
||||
|
||||
// Return database client
|
||||
func (s *Storage) Conn() *bbolt.DB {
|
||||
return s.conn
|
||||
}
|
||||
150
bbolt/bbolt_test.go
Normal file
150
bbolt/bbolt_test.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package bbolt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testStore = New(Config{
|
||||
Bucket: "fiber-bucket",
|
||||
Reset: true,
|
||||
})
|
||||
|
||||
code := m.Run()
|
||||
|
||||
_ = testStore.Close()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func Test_Bbolt_Set(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Bbolt_Set_Override(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Bbolt_Get(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, val, result)
|
||||
}
|
||||
|
||||
func Test_Bbolt_Get_NotExist(t *testing.T) {
|
||||
result, err := testStore.Get("notexist")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Bbolt_Delete(t *testing.T) {
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Bbolt_Reset(t *testing.T) {
|
||||
val := []byte("doe")
|
||||
|
||||
err := testStore.Set("john1", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set("john2", val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Reset()
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testStore.Get("john1")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
|
||||
result, err = testStore.Get("john2")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, len(result))
|
||||
}
|
||||
|
||||
func Test_Bbolt_Close(t *testing.T) {
|
||||
require.Nil(t, testStore.Close())
|
||||
}
|
||||
|
||||
func Test_Bbolt_Conn(t *testing.T) {
|
||||
require.True(t, testStore.Conn() != nil)
|
||||
}
|
||||
|
||||
func Benchmark_Bbolt_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Bbolt_Get(b *testing.B) {
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Bbolt_SetAndDelete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
63
bbolt/config.go
Normal file
63
bbolt/config.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package bbolt
|
||||
|
||||
import "time"
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
// Database path
|
||||
//
|
||||
// Optional. Default is "fiber.db"
|
||||
Database string
|
||||
|
||||
// Bbolt bucket name
|
||||
//
|
||||
// Optional. Default is "fiber_storage"
|
||||
Bucket string
|
||||
|
||||
// Timeout is the amount of time to wait to obtain a file lock.
|
||||
// Only available on Darwin and Linux.
|
||||
//
|
||||
// Optional. Default is set to 60 * time.Second.
|
||||
Timeout time.Duration
|
||||
|
||||
// Open database in read-only mode.
|
||||
//
|
||||
// Optional. Default is false
|
||||
ReadOnly bool
|
||||
|
||||
// Reset clears any existing keys in existing Bucket
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Database: "fiber.db",
|
||||
Bucket: "fiber_storage",
|
||||
Timeout: 60 * time.Second,
|
||||
ReadOnly: false,
|
||||
Reset: false,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Database == "" {
|
||||
cfg.Database = ConfigDefault.Database
|
||||
}
|
||||
|
||||
if cfg.Bucket == "" {
|
||||
cfg.Bucket = ConfigDefault.Bucket
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
17
bbolt/go.mod
Normal file
17
bbolt/go.mod
Normal file
@@ -0,0 +1,17 @@
|
||||
module github.com/gofiber/storage/bbolt/v2
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.etcd.io/bbolt v1.3.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
19
bbolt/go.sum
Normal file
19
bbolt/go.sum
Normal file
@@ -0,0 +1,19 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3 h1:pfOhUDDVjBJpkWv6C5jaDyYLvpui7zQ97zpyFFsUOKw=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.3/go.mod h1:jsl17+MsKfwJjM3ONCE9Rzji/j8XNbwjhUVTjzgfDCo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
26
bbolt/utils.go
Normal file
26
bbolt/utils.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package bbolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gofiber/utils/v2"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
func createBucket(cfg Config, conn *bbolt.DB) error {
|
||||
return conn.Update(func(tx *bbolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(utils.UnsafeBytes(cfg.Bucket))
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func removeBucket(cfg Config, conn *bbolt.DB) error {
|
||||
return conn.Update(func(tx *bbolt.Tx) error {
|
||||
err := tx.DeleteBucket(utils.UnsafeBytes(cfg.Bucket))
|
||||
if errors.Is(err, bbolt.ErrBucketNotFound) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
123
clickhouse/README.md
Normal file
123
clickhouse/README.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Clickhouse
|
||||
|
||||
A Clickhouse storage driver using [https://github.com/ClickHouse/clickhouse-go](https://github.com/ClickHouse/clickhouse-go).
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) (*Storage, error)
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *Session
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
Clickhouse is supported on the latest two versions of Go:
|
||||
|
||||
Install the clickhouse implementation:
|
||||
```bash
|
||||
go get github.com/gofiber/storage/clickhouse
|
||||
```
|
||||
|
||||
### Running the tests
|
||||
|
||||
This module uses [Testcontainers for Go](https://github.com/testcontainers/testcontainers-go/) to run integration tests, which will start a local instance of Clickhouse as a Docker container under the hood. To run the tests, you must have Docker (or another container runtime 100% compatible with the Docker APIs) installed on your machine.
|
||||
|
||||
### Local development
|
||||
|
||||
Before running this implementation, you must ensure a Clickhouse cluster is available.
|
||||
For local development, we recommend using the Clickhouse Docker image; it contains everything
|
||||
necessary for the client to operate correctly.
|
||||
|
||||
To start Clickhouse using Docker, issue the following:
|
||||
|
||||
```bash
|
||||
docker run -d -p 9000:9000 --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server
|
||||
```
|
||||
|
||||
After running this command you're ready to start using the storage and connecting to the database.
|
||||
|
||||
### Examples
|
||||
|
||||
You can use the following options to create a clickhouse storage driver:
|
||||
```go
|
||||
import "github.com/gofiber/storage/clickhouse"
|
||||
|
||||
// Initialize default config, to connect to localhost:9000 using the memory engine and with a clean table.
|
||||
store, err := clickhouse.New(clickhouse.Config{
|
||||
Host: "localhost",
|
||||
Port: 9000,
|
||||
Clean: true,
|
||||
})
|
||||
|
||||
// Initialize custom config to connect to a different host/port and use custom engine and with clean table.
|
||||
store, err := clickhouse.New(clickhouse.Config{
|
||||
Host: "some-ip-address",
|
||||
Port: 9000,
|
||||
Engine: clickhouse.MergeTree,
|
||||
Clean: true,
|
||||
})
|
||||
|
||||
// Initialize to connect with TLS enabled with your own tls.Config and with clean table.
|
||||
tlsConfig := config := &tls.Config{...}
|
||||
|
||||
store, err := clickhouse.New(clickhouse.Config{
|
||||
Host: "some-ip-address",
|
||||
Port: 9000,
|
||||
Clean: true,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
// Config defines configuration options for Clickhouse connection.
|
||||
type Config struct {
|
||||
// The host of the database. Ex: 127.0.0.1
|
||||
Host string
|
||||
// The port where the database is supposed to listen to. Ex: 9000
|
||||
Port int
|
||||
// The database that the connection should authenticate from
|
||||
Database string
|
||||
// The username to be used in the authentication
|
||||
Username string
|
||||
// The password to be used in the authentication
|
||||
Password string
|
||||
// The name of the table that will store the data
|
||||
Table string
|
||||
// The engine that should be used in the table
|
||||
Engine string
|
||||
// Should start a clean table, default false
|
||||
Clean bool
|
||||
// TLS configuration, default nil
|
||||
TLSConfig *tls.Config
|
||||
// Should the connection be in debug mode, default false
|
||||
Debug bool
|
||||
// The function to use with the debug config, default print function. It only works when debug is true
|
||||
Debugf func(format string, v ...any)
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
var DefaultConfig = Config{
|
||||
Host: "localhost",
|
||||
Port: 9000,
|
||||
Engine: "Memory",
|
||||
Clean: false,
|
||||
}
|
||||
```
|
||||
126
clickhouse/clickhouse.go
Normal file
126
clickhouse/clickhouse.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
driver "github.com/ClickHouse/clickhouse-go/v2"
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
session driver.Conn
|
||||
context context.Context
|
||||
table string
|
||||
}
|
||||
|
||||
// New returns a new [*Storage] given a [Config].
|
||||
func New(configuration Config) (*Storage, error) {
|
||||
cfg, engine, err := defaultConfig(configuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn, err := driver.Open(&cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
queryWithEngine := fmt.Sprintf(createTableString, engine)
|
||||
if err := conn.Exec(ctx, queryWithEngine, driver.Named("table", configuration.Table)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if configuration.Clean {
|
||||
if err := conn.Exec(ctx, resetDataString, driver.Named("table", configuration.Table)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := conn.Ping(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Storage{
|
||||
session: conn,
|
||||
context: ctx,
|
||||
table: configuration.Table,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Storage) Set(key string, value []byte, expiration time.Duration) error {
|
||||
if len(key) <= 0 || len(value) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
exp := time.Time{}
|
||||
if expiration != 0 {
|
||||
exp = time.Now().Add(expiration).UTC()
|
||||
}
|
||||
|
||||
return s.
|
||||
session.
|
||||
Exec(
|
||||
s.context,
|
||||
insertDataString,
|
||||
driver.Named("table", s.table),
|
||||
driver.Named("key", key),
|
||||
driver.Named("value", string(value)),
|
||||
driver.Named("expiration", exp.Format("2006-01-02 15:04:05")),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
var result schema
|
||||
|
||||
row := s.session.QueryRow(
|
||||
s.context,
|
||||
selectDataString,
|
||||
driver.Named("table", s.table),
|
||||
driver.Named("key", key),
|
||||
)
|
||||
if row.Err() != nil {
|
||||
return []byte{}, row.Err()
|
||||
}
|
||||
|
||||
if err := row.ScanStruct(&result); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
// The result.Expiration.IsZero() was returning a false value even when the time was
|
||||
// set to be the zero value of the time.Time struct (Jan 1st 1970, 00:00:00 UTC)
|
||||
// so we had to change the comparison
|
||||
if !time.Unix(0, 0).Equal(result.Expiration) && result.Expiration.Before(time.Now().UTC()) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
return []byte(result.Value), nil
|
||||
}
|
||||
|
||||
func (s *Storage) Delete(key string) error {
|
||||
if len(key) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.session.Exec(s.context, deleteDataString, driver.Named("table", s.table), driver.Named("key", key))
|
||||
}
|
||||
|
||||
func (s *Storage) Reset() error {
|
||||
return s.session.Exec(s.context, resetDataString, driver.Named("table", s.table))
|
||||
}
|
||||
|
||||
func (s *Storage) Close() error {
|
||||
return s.session.Close()
|
||||
}
|
||||
255
clickhouse/clickhouse_test.go
Normal file
255
clickhouse/clickhouse_test.go
Normal file
@@ -0,0 +1,255 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/testcontainers/testcontainers-go/modules/clickhouse"
|
||||
)
|
||||
|
||||
const (
|
||||
// clickhouseImage is the default image used for running clickhouse in tests.
|
||||
clickhouseImage = "clickhouse/clickhouse-server:23-alpine"
|
||||
clickhouseImageEnvVar string = "TEST_CLICKHOUSE_IMAGE"
|
||||
clickhouseUser string = "default"
|
||||
clickhousePass string = "password"
|
||||
clickhouseDB string = "fiber"
|
||||
)
|
||||
|
||||
func getTestConnection(t testing.TB, cfg Config) (*Storage, error) {
|
||||
t.Helper()
|
||||
|
||||
img := clickhouseImage
|
||||
if imgFromEnv := os.Getenv(clickhouseImageEnvVar); imgFromEnv != "" {
|
||||
img = imgFromEnv
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := clickhouse.Run(ctx,
|
||||
img,
|
||||
clickhouse.WithUsername(clickhouseUser),
|
||||
clickhouse.WithPassword(clickhousePass),
|
||||
clickhouse.WithDatabase(clickhouseDB),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hostPort, err := c.ConnectionHost(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pair := strings.Split(hostPort, ":")
|
||||
port, err := strconv.Atoi(pair[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// configure the client for the testcontainers clickhouse instance
|
||||
cfg.Host = pair[0]
|
||||
cfg.Port = port
|
||||
cfg.Username = clickhouseUser
|
||||
cfg.Password = clickhousePass
|
||||
cfg.Database = clickhouseDB
|
||||
|
||||
client, err := New(cfg)
|
||||
|
||||
return client, err
|
||||
}
|
||||
|
||||
func Test_Connection(t *testing.T) {
|
||||
_, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Set(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("somekey", []byte("somevalue"), 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Set_With_Exp(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("setsomekeywithexp", []byte("somevalue"), time.Second*1)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_Get(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("somekey", []byte("somevalue"), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, err := client.Get("somekey")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, value)
|
||||
assert.Equal(t, "somevalue", string(value))
|
||||
}
|
||||
|
||||
func Test_Get_With_Exp(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("getsomekeywithexp", []byte("somevalue"), time.Second*2)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, err := client.Get("getsomekeywithexp")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, value)
|
||||
assert.Equal(t, "somevalue", string(value))
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
value, err = client.Get("getsomekeywithexp")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{}, value)
|
||||
}
|
||||
|
||||
func Test_Delete(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("somekeytodelete", []byte("somevalue"), time.Second*5)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.Delete("somekeytodelete")
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
value, err := client.Get("somekeytodelete")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{}, value)
|
||||
}
|
||||
|
||||
func Test_Reset(t *testing.T) {
|
||||
client, err := getTestConnection(t, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("testkey", []byte("somevalue"), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.Reset()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
value, err := client.Get("testkey")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte{}, value)
|
||||
}
|
||||
|
||||
func Benchmark_Clickhouse_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
client, err := getTestConnection(b, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(b, err)
|
||||
|
||||
defer client.Close()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = client.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Clickhouse_Get(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
client, err := getTestConnection(b, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
require.NoError(b, err)
|
||||
|
||||
defer client.Close()
|
||||
|
||||
err = client.Set("john", []byte("doe"), 0)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = client.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Clickhouse_Set_And_Delete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
client, err := getTestConnection(b, Config{
|
||||
Engine: Memory,
|
||||
Table: "test_table",
|
||||
Clean: true,
|
||||
})
|
||||
|
||||
require.NoError(b, err)
|
||||
defer client.Close()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = client.Set("john", []byte("doe"), 0)
|
||||
err = client.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
116
clickhouse/config.go
Normal file
116
clickhouse/config.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
driver "github.com/ClickHouse/clickhouse-go/v2"
|
||||
)
|
||||
|
||||
type ClickhouseEngine string
|
||||
|
||||
type schema struct {
|
||||
Value string `ch:"value"`
|
||||
Expiration time.Time `ch:"expiration"`
|
||||
}
|
||||
|
||||
const (
|
||||
Memory ClickhouseEngine = "Memory"
|
||||
MergeTree ClickhouseEngine = "MergeTree"
|
||||
StripeLog ClickhouseEngine = "StripeLog"
|
||||
TinyLog ClickhouseEngine = "TinyLog"
|
||||
Log ClickhouseEngine = "Log"
|
||||
)
|
||||
|
||||
// Config defines configuration options for Clickhouse connection.
|
||||
type Config struct {
|
||||
// The host of the database. Ex: 127.0.0.1
|
||||
Host string
|
||||
// The port where the database is supposed to listen to. Ex: 9000
|
||||
Port int
|
||||
// The database that the connection should authenticate from
|
||||
Database string
|
||||
// The username to be used in the authentication
|
||||
Username string
|
||||
// The password to be used in the authentication
|
||||
Password string
|
||||
// The name of the table that will store the data
|
||||
Table string
|
||||
// The engine that should be used in the table
|
||||
Engine ClickhouseEngine
|
||||
// Should start a clean table, default false
|
||||
Clean bool
|
||||
// TLS configuration, default nil
|
||||
TLSConfig *tls.Config
|
||||
// Should the connection be in debug mode, default false
|
||||
Debug bool
|
||||
// The function to use with the debug config, default print function. It only works when debug is true
|
||||
Debugf func(format string, v ...any)
|
||||
}
|
||||
|
||||
func defaultConfig(configuration Config) (driver.Options, ClickhouseEngine, error) {
|
||||
if configuration.Table == "" {
|
||||
return driver.Options{}, "", errors.New("table name not provided")
|
||||
}
|
||||
|
||||
if configuration.Host == "" {
|
||||
configuration.Host = "localhost"
|
||||
}
|
||||
|
||||
if configuration.Port == 0 {
|
||||
configuration.Port = 9000
|
||||
}
|
||||
|
||||
if configuration.Engine == "" {
|
||||
configuration.Engine = Memory
|
||||
}
|
||||
|
||||
config := driver.Options{
|
||||
Addr: []string{fmt.Sprintf("%s:%d", configuration.Host, configuration.Port)},
|
||||
}
|
||||
|
||||
if configuration.Username != "" && configuration.Password != "" {
|
||||
config.Auth = driver.Auth{
|
||||
Database: configuration.Database,
|
||||
Username: configuration.Username,
|
||||
Password: configuration.Password,
|
||||
}
|
||||
}
|
||||
|
||||
if configuration.TLSConfig != nil {
|
||||
config.TLS = configuration.TLSConfig
|
||||
}
|
||||
|
||||
if configuration.Debug && config.Debugf == nil {
|
||||
config.Debugf = log.Printf
|
||||
}
|
||||
|
||||
return config, configuration.Engine, nil
|
||||
}
|
||||
|
||||
const resetDataString = `
|
||||
TRUNCATE TABLE {table:Identifier}
|
||||
`
|
||||
|
||||
const deleteDataString = `
|
||||
ALTER TABLE {table:Identifier} DELETE WHERE key = {key:String}
|
||||
`
|
||||
|
||||
const selectDataString = `
|
||||
SELECT value, expiration FROM {table:Identifier} WHERE key = {key:String}
|
||||
`
|
||||
|
||||
const insertDataString = `
|
||||
INSERT INTO {table:Identifier} (*) VALUES ({key:String}, {value:String}, {expiration:Datetime})
|
||||
`
|
||||
|
||||
const createTableString = `
|
||||
CREATE TABLE IF NOT EXISTS {table:Identifier} (
|
||||
key String CODEC(ZSTD(1))
|
||||
, value String CODEC(ZSTD(1))
|
||||
, expiration Datetime CODEC(ZSTD(1))
|
||||
) ENGINE=%s
|
||||
`
|
||||
67
clickhouse/go.mod
Normal file
67
clickhouse/go.mod
Normal file
@@ -0,0 +1,67 @@
|
||||
module github.com/gofiber/storage/clickhouse
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.26.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/testcontainers/testcontainers-go/modules/clickhouse v0.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/ClickHouse/ch-go v0.61.5 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/containerd/containerd v1.7.18 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.7.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/user v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/paulmach/orb v0.11.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/testcontainers/testcontainers-go v0.33.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
238
clickhouse/go.sum
Normal file
238
clickhouse/go.sum
Normal file
@@ -0,0 +1,238 @@
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4=
|
||||
github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.26.0 h1:j4/y6NYaCcFkJwN/TU700ebW+nmsIy34RmUAAcZKy9w=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.26.0/go.mod h1:iDTViXk2Fgvf1jn2dbJd1ys+fBkdD1UMRnXlwmhijhQ=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao=
|
||||
github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
|
||||
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
|
||||
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
|
||||
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
|
||||
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
|
||||
github.com/testcontainers/testcontainers-go/modules/clickhouse v0.33.0 h1:YbB5DBkpgY+GlGPFqTSV1hzWPm3ZHirEyooZrj+ZXK0=
|
||||
github.com/testcontainers/testcontainers-go/modules/clickhouse v0.33.0/go.mod h1:qJuMPl9yWIWasmdBILM2uDk1Ny1kdeigcKMJ6A8PZz0=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
|
||||
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
2
cloudflarekv/.gitignore
vendored
Normal file
2
cloudflarekv/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
index.ts
|
||||
wrangler.toml
|
||||
114
cloudflarekv/README.md
Normal file
114
cloudflarekv/README.md
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
id: cloudflarekv
|
||||
title: Cloudflare KV
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
A Cloudflare KV storage driver using [cloudflare/cloudflare-go](https://github.com/cloudflare/cloudflare-go).
|
||||
|
||||
**Note: Requires Go 1.21 and above**
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *cloudflare.API
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
|
||||
And then install the Cloudflare KV implementation:
|
||||
|
||||
```bash
|
||||
go get github.com/gofiber/storage/cloudflarekv
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Import the storage package.
|
||||
|
||||
```go
|
||||
import "github.com/gofiber/storage/cloudflarekv"
|
||||
```
|
||||
|
||||
You can use the following methods to create storage. The Key must be an API Token generated with at least `Account.Workers KV Storage` permission. Check the [Create API Token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) documentation to generate one.
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
store := cloudflarekv.New()
|
||||
|
||||
store := cloudflarekv.New(cloudflarekv.Config{
|
||||
Key: "",
|
||||
Email: "",
|
||||
AccountID: "fiber",
|
||||
NamespaceID: "fiber",
|
||||
Reset: false,
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
|
||||
// Cloudflare Auth Token
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Key string
|
||||
|
||||
// Cloudflare Email
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Email string
|
||||
|
||||
// Account id
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
AccountID string
|
||||
|
||||
// Namespace id
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
NamespaceID string
|
||||
|
||||
// Reset clears any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Key: "",
|
||||
Email: "",
|
||||
AccountID: "fiber",
|
||||
NamespaceID: "fiber",
|
||||
Reset: false,
|
||||
}
|
||||
```
|
||||
149
cloudflarekv/cloudflarekv.go
Normal file
149
cloudflarekv/cloudflarekv.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package cloudflarekv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
)
|
||||
|
||||
type APIInterface interface {
|
||||
DeleteWorkersKVEntries(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.DeleteWorkersKVEntriesParams) (cloudflare.Response, error)
|
||||
DeleteWorkersKVEntry(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.DeleteWorkersKVEntryParams) (cloudflare.Response, error)
|
||||
GetWorkersKV(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.GetWorkersKVParams) ([]byte, error)
|
||||
ListWorkersKVKeys(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.ListWorkersKVsParams) (cloudflare.ListStorageKeysResponse, error)
|
||||
WriteWorkersKVEntry(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.WriteWorkersKVEntryParams) (cloudflare.Response, error)
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
api APIInterface
|
||||
email string
|
||||
accountID string
|
||||
namespaceID string
|
||||
}
|
||||
|
||||
func New(config ...Config) *Storage {
|
||||
cfg := configDefault(config...)
|
||||
if cfg.Key == "test" {
|
||||
api := &TestModule{
|
||||
baseUrl: "http://localhost:8787",
|
||||
}
|
||||
|
||||
storage := &Storage{
|
||||
api: api,
|
||||
email: "example@cloudflare.org",
|
||||
accountID: "dummy-ID",
|
||||
namespaceID: "dummy-ID",
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
api, err := cloudflare.NewWithAPIToken(cfg.Key)
|
||||
if err != nil {
|
||||
log.Panicf("error with cloudflare api initialization: %v", err)
|
||||
}
|
||||
|
||||
storage := &Storage{
|
||||
api: api,
|
||||
email: cfg.Email,
|
||||
accountID: cfg.AccountID,
|
||||
namespaceID: cfg.NamespaceID,
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
resp, err := s.api.GetWorkersKV(context.Background(), cloudflare.AccountIdentifier(s.accountID), cloudflare.GetWorkersKVParams{NamespaceID: s.namespaceID, Key: key})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occur in GetWorkersKV: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||
_, err := s.api.WriteWorkersKVEntry(context.Background(), cloudflare.AccountIdentifier(s.accountID), cloudflare.WriteWorkersKVEntryParams{
|
||||
NamespaceID: s.namespaceID,
|
||||
Key: key,
|
||||
Value: val,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occur in WriteWorkersKVEntry: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Delete(key string) error {
|
||||
_, err := s.api.DeleteWorkersKVEntry(context.Background(), cloudflare.AccountIdentifier(s.accountID), cloudflare.DeleteWorkersKVEntryParams{
|
||||
NamespaceID: s.namespaceID,
|
||||
Key: key,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occur in DeleteWorkersKVEntry: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Reset() error {
|
||||
var (
|
||||
cursor string
|
||||
keys []string
|
||||
)
|
||||
|
||||
for {
|
||||
resp, err := s.api.ListWorkersKVKeys(context.Background(), cloudflare.AccountIdentifier(s.accountID), cloudflare.ListWorkersKVsParams{
|
||||
NamespaceID: s.namespaceID,
|
||||
Cursor: cursor,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occur in ListWorkersKVKeys: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
keys = make([]string, len(resp.Result))
|
||||
|
||||
for _, element := range resp.Result {
|
||||
name := element.Name
|
||||
keys = append(keys, name)
|
||||
}
|
||||
|
||||
_, err = s.api.DeleteWorkersKVEntries(context.Background(), cloudflare.AccountIdentifier(s.accountID), cloudflare.DeleteWorkersKVEntriesParams{
|
||||
NamespaceID: s.namespaceID,
|
||||
Keys: keys,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error occur in DeleteWorker: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.Cursor) == 0 {
|
||||
log.Println("No keys left in the namespace")
|
||||
break
|
||||
}
|
||||
|
||||
cursor = resp.Cursor
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Conn() APIInterface {
|
||||
return s.api
|
||||
}
|
||||
209
cloudflarekv/cloudflarekv_test.go
Normal file
209
cloudflarekv/cloudflarekv_test.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package cloudflarekv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
code := m.Run()
|
||||
|
||||
_ = testStore.Close()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func Test_CloudflareKV_Get(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
_ = testStore.Set(key, val, 0)
|
||||
|
||||
result, err := testStore.Get(key)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
result, err = testStore.Get(key)
|
||||
if bytes.NewBuffer(result).String() == "" {
|
||||
_ = testStore.Set(key, val, 0)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, bytes.NewBuffer(val).String(), bytes.NewBuffer(result).String())
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Test_CloudflareKV_Set(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Test_CloudflareKV_Delete(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
var (
|
||||
key = "john"
|
||||
val = []byte("doe")
|
||||
)
|
||||
|
||||
err := testStore.Set(key, val, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key)
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Test_CloudflareKV_Reset(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
err := testStore.Reset()
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
func Test_CloudflareKV_Close(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
require.Nil(t, testStore.Close())
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Test_CloudflareKV_Conn(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
require.NotNil(t, testStore.Conn())
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Benchmark_CloudflareKV_Set(b *testing.B) {
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Benchmark_CloudflareKV_Get(b *testing.B) {
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
|
||||
func Benchmark_CloudflareKV_SetAndDelete(b *testing.B) {
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
testStore = New(Config{
|
||||
Key: "test",
|
||||
})
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
|
||||
_ = testStore.Close()
|
||||
}
|
||||
66
cloudflarekv/config.go
Normal file
66
cloudflarekv/config.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package cloudflarekv
|
||||
|
||||
// Config defines the config for storage.
|
||||
type Config struct {
|
||||
|
||||
// Cloudflare Auth Token
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Key string
|
||||
|
||||
// Cloudflare Email
|
||||
//
|
||||
// Optional. Default is ""
|
||||
Email string
|
||||
|
||||
// Account id
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
AccountID string
|
||||
|
||||
// Namespace id
|
||||
//
|
||||
// Optional. Default is "fiber"
|
||||
NamespaceID string
|
||||
|
||||
// Reset clears any existing keys in existing Table
|
||||
//
|
||||
// Optional. Default is false
|
||||
Reset bool
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Key: "",
|
||||
Email: "",
|
||||
AccountID: "fiber",
|
||||
NamespaceID: "fiber",
|
||||
Reset: false,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Key == "" {
|
||||
cfg.Key = ConfigDefault.Key
|
||||
}
|
||||
if cfg.Email == "" {
|
||||
cfg.Email = ConfigDefault.Email
|
||||
}
|
||||
if cfg.AccountID == "" {
|
||||
cfg.AccountID = ConfigDefault.AccountID
|
||||
}
|
||||
if cfg.NamespaceID == "" {
|
||||
cfg.NamespaceID = ConfigDefault.NamespaceID
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
20
cloudflarekv/go.mod
Normal file
20
cloudflarekv/go.mod
Normal file
@@ -0,0 +1,20 @@
|
||||
module github.com/gofiber/storage/cloudflarekv
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/cloudflare/cloudflare-go v0.102.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
34
cloudflarekv/go.sum
Normal file
34
cloudflarekv/go.sum
Normal file
@@ -0,0 +1,34 @@
|
||||
github.com/cloudflare/cloudflare-go v0.102.0 h1:+0MGbkirM/yzVLOYpWMgW7CDdKzesSbdwA2Y+rABrWI=
|
||||
github.com/cloudflare/cloudflare-go v0.102.0/go.mod h1:BOB41tXf31ti/qtBO9paYhyapotQbGRDbQoLOAF7pSg=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
251
cloudflarekv/test_module.go
Normal file
251
cloudflarekv/test_module.go
Normal file
@@ -0,0 +1,251 @@
|
||||
package cloudflarekv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
)
|
||||
|
||||
type getWorkersKVBody struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type writeWorkersKVBody struct {
|
||||
Key string `json:"key"`
|
||||
Val string `json:"val"`
|
||||
}
|
||||
|
||||
type deleteworkerskvpairbykeyBody struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type listworkerskvkeysBody struct {
|
||||
Limit string `json:"limit"`
|
||||
Prefix string `json:"prefix"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type deleteworkerskventriesBody struct {
|
||||
Keys []string `json:"keys"`
|
||||
}
|
||||
|
||||
type TestModule struct {
|
||||
baseUrl string
|
||||
}
|
||||
|
||||
func (t *TestModule) GetWorkersKV(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.GetWorkersKVParams) ([]byte, error) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
jsonBody := getWorkersKVBody{
|
||||
Key: params.Key,
|
||||
}
|
||||
|
||||
marshalledBody, err := json.Marshal(jsonBody)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error in marshalling")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, t.baseUrl+"/getworkerskvvaluebykey", bytes.NewReader(marshalledBody))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /getworkerskvvaluebykey > making http call")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /getworkerskvvaluebykey > operating http call")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
str := string(respBody)
|
||||
println(str)
|
||||
}
|
||||
|
||||
return respBody, nil
|
||||
}
|
||||
|
||||
func (t *TestModule) WriteWorkersKVEntry(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.WriteWorkersKVEntryParams) (cloudflare.Response, error) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
jsonBody := writeWorkersKVBody{
|
||||
Key: params.Key,
|
||||
Val: string(params.Value),
|
||||
}
|
||||
|
||||
marshalledBody, err := json.Marshal(jsonBody)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error in marshalling")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, t.baseUrl+"/writeworkerskvkeyvaluepair", bytes.NewReader(marshalledBody))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /writeworkerskvkeyvaluepair > making http call")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /writeworkerskvkeyvaluepair > operating http call")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
return cloudflare.Response{
|
||||
Success: true,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (t *TestModule) DeleteWorkersKVEntry(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.DeleteWorkersKVEntryParams) (cloudflare.Response, error) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
jsonBody := deleteworkerskvpairbykeyBody{
|
||||
Key: params.Key,
|
||||
}
|
||||
|
||||
marshalledBody, err := json.Marshal(jsonBody)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error in marshalling")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, t.baseUrl+"/deleteworkerskvpairbykey", bytes.NewReader(marshalledBody))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /deleteworkerskvpairbykey > making http call")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /deleteworkerskvpairbykey > operating http call")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
return cloudflare.Response{
|
||||
Success: true,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (t *TestModule) ListWorkersKVKeys(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.ListWorkersKVsParams) (cloudflare.ListStorageKeysResponse, error) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
jsonBody := listworkerskvkeysBody{
|
||||
Limit: fmt.Sprint(params.Limit),
|
||||
Prefix: params.Prefix,
|
||||
Cursor: params.Cursor,
|
||||
}
|
||||
|
||||
marshalledBody, err := json.Marshal(jsonBody)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error in marshalling")
|
||||
return cloudflare.ListStorageKeysResponse{}, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, t.baseUrl+"/listworkerskvkeys", bytes.NewReader(marshalledBody))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /listworkerskvkeys > making http call")
|
||||
return cloudflare.ListStorageKeysResponse{}, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /listworkerskvkeys > operating http call")
|
||||
return cloudflare.ListStorageKeysResponse{}, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
result := []cloudflare.StorageKey{}
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
str := string(respBody)
|
||||
println(str)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(respBody, &result); err != nil {
|
||||
log.Println("Error with parsing response body")
|
||||
return cloudflare.ListStorageKeysResponse{}, nil
|
||||
}
|
||||
|
||||
return cloudflare.ListStorageKeysResponse{
|
||||
Result: result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *TestModule) DeleteWorkersKVEntries(ctx context.Context, rc *cloudflare.ResourceContainer, params cloudflare.DeleteWorkersKVEntriesParams) (cloudflare.Response, error) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
jsonBody := deleteworkerskventriesBody{
|
||||
Keys: params.Keys,
|
||||
}
|
||||
|
||||
marshalledBody, err := json.Marshal(jsonBody)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error in marshalling")
|
||||
return cloudflare.Response{}, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, t.baseUrl+"/deleteworkerskventries", bytes.NewReader(marshalledBody))
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occur in /deleteworkerskventries > making new request")
|
||||
return cloudflare.Response{
|
||||
Errors: []cloudflare.ResponseInfo{},
|
||||
}, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
_, err = client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error occuer in /deleteworkerskventries > operating http call")
|
||||
return cloudflare.Response{
|
||||
Errors: []cloudflare.ResponseInfo{},
|
||||
}, err
|
||||
}
|
||||
|
||||
return cloudflare.Response{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
138
coherence/README.md
Normal file
138
coherence/README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Coherence
|
||||
<!-- Copyright © 2023, 2025 Oracle and/or its affiliates. -->
|
||||
A Coherence storage driver using [https://github.com/oracle/coherence-go-client](https://github.com/oracle/coherence-go-client).
|
||||
|
||||
### Table of Contents
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
```go
|
||||
func New(config ...Config) (*Storage, error)
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *Session
|
||||
```
|
||||
|
||||
### Installation
|
||||
Coherence is supported on Go versions 1.19 and above:
|
||||
|
||||
Install the coherence implementation:
|
||||
```bash
|
||||
go get github.com/gofiber/storage/coherence
|
||||
```
|
||||
|
||||
Before running or testing this implementation, you must ensure a Coherence cluster is available.
|
||||
For local development, we recommend using the Coherence CE Docker image; it contains everything
|
||||
necessary for the client to operate correctly.
|
||||
|
||||
To start a Coherence cluster using Docker, issue the following:
|
||||
|
||||
```bash
|
||||
docker run -d -p 1408:1408 ghcr.io/oracle/coherence-ce:24.09
|
||||
```
|
||||
|
||||
See the documentation [here](https://pkg.go.dev/github.com/oracle/coherence-go-client/v2@v2.0.0/coherence#hdr-Obtaining_a_Session) on connection options
|
||||
when creating a Coherence session.
|
||||
|
||||
### Examples
|
||||
Import the storage package.
|
||||
```go
|
||||
import "github.com/gofiber/storage/coherence"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
```go
|
||||
// Initialize default config, to connect to localhost:1408 using plain text
|
||||
store, err := coherence.New()
|
||||
|
||||
// Initialize custom config to connect to a different host/port and use plain text and expiry of 5 minutes.
|
||||
store, err := coherence.New(coherence.Config{
|
||||
Address: "my-host:myport",
|
||||
Expiration: time.Duration(300) * time.Second, // 5 minutes
|
||||
})
|
||||
|
||||
// Initialize to connect with TLS enabled with your own tls.Config
|
||||
tlsConfig := config := &tls.Config{...}
|
||||
|
||||
store, err := coherence.New(coherence.Config{
|
||||
Address: "my-host:myport",
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
```
|
||||
|
||||
> Note: If you create two stores using `coherence.New()` they will effectivity be identical.
|
||||
> If you wish to have two separate stores, then you can use:
|
||||
> ```go
|
||||
> store1, err := coherence.New(Config{ScopeName: "scope1"})
|
||||
> store2, err := coherence.New(Config{ScopeName: "scope2"})
|
||||
> ```
|
||||
|
||||
**Near Caches**
|
||||
|
||||
The latest version of the Coherence Go client introduces near cache support
|
||||
to cache frequently accessed data in the Go client to avoid sending requests across the network.
|
||||
|
||||
This is particularly useful if you are using sticky sessions via a LBR as this will cache
|
||||
the session in the Go process and the `Get()` operations will be much quicker.
|
||||
|
||||
When the session is expired on the server it will automatically be removed from the near cache.
|
||||
|
||||
To enable this for you session, you can set the `NearCacheTimeout` to a duration less than the expiry.
|
||||
|
||||
```go
|
||||
// Initialize default config, to connect to localhost:1408 using plain text
|
||||
store, err := coherence.New()
|
||||
|
||||
// Use plain text with default expiry of 5 minutes, and a near cache expiry of 2 minutes
|
||||
store, err := coherence.New(coherence.Config{
|
||||
Address: "my-host:myport",
|
||||
Expiration: time.Duration(300) * time.Second, // 5 minutes
|
||||
NearCacheTimeout: time.Duration(120) * time.Second, // 2 minutes
|
||||
})
|
||||
```
|
||||
> Note: You must ensure your near cache timeout is less that the session timeout.
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
// Config defines configuration options for Coherence connection.
|
||||
type Config struct {
|
||||
// Address to connect to, defaults to "localhost:1408"
|
||||
Address string
|
||||
|
||||
// Timeout is the default session timeout to connect to Coherence, defaults to 30s
|
||||
Timeout time.Duration
|
||||
|
||||
// ScopeName defines a scope allowing for multiple storage sessions
|
||||
ScopeName string
|
||||
|
||||
// Reset indicates if the store should be reset after being created
|
||||
Reset bool
|
||||
|
||||
// TLSConfig specifies tls.Config to use when connecting, if nil then plain text is used
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// NearCacheTimeout defines the timeout for a near cache. Is this is set, then a near cache
|
||||
// with the timeout is created. Note: this must be less than the session timeout or any timeout you specify
|
||||
// when using Set().
|
||||
NearCacheTimeout time.Duration
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
```go
|
||||
var DefaultConfig = Config{
|
||||
Address: "localhost:1408",
|
||||
Timeout: time.Duration(120) * time.Seconds,
|
||||
ScopeName: defaultScopeName,
|
||||
Reset: false,
|
||||
NearCacheTimeout: time.Duration(60) * time.Seconds,
|
||||
}
|
||||
```
|
||||
179
coherence/coherence.go
Normal file
179
coherence/coherence.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package coherence
|
||||
|
||||
/*
|
||||
* Copyright © 2023, 2025 Oracle and/or its affiliates.
|
||||
*/
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
coh "github.com/oracle/coherence-go-client/v2/coherence"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultScopeName = "default-store"
|
||||
defaultTimeout = time.Duration(30) * time.Second
|
||||
defaultAddress = "localhost:1408"
|
||||
)
|
||||
|
||||
// Storage represents an implementation of Coherence storage provider.
|
||||
type Storage struct {
|
||||
session *coh.Session
|
||||
namedCache coh.NamedCache[string, []byte]
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Config defines configuration options for Coherence connection.
|
||||
type Config struct {
|
||||
// Address to connect to, defaults to "localhost:1408"
|
||||
Address string
|
||||
|
||||
// Timeout is the default session timeout to connect to Coherence, defaults to 30s
|
||||
Timeout time.Duration
|
||||
|
||||
// ScopeName defines a scope allowing for multiple storage sessions
|
||||
ScopeName string
|
||||
|
||||
// Reset indicates if the store should be reset after being created
|
||||
Reset bool
|
||||
|
||||
// TLSConfig specifies tls.Config to use when connecting, if nil then plain text is used
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// NearCacheTimeout defines the timeout for a near cache. Is this is set, then a near cache
|
||||
// with the timeout is created. Note: this must be less than the session timeout or any timeout you specify
|
||||
// when using Set().
|
||||
NearCacheTimeout time.Duration
|
||||
}
|
||||
|
||||
// DefaultConfig defines default options.
|
||||
var DefaultConfig = Config{
|
||||
Address: defaultAddress,
|
||||
Timeout: defaultTimeout,
|
||||
ScopeName: defaultScopeName,
|
||||
Reset: false,
|
||||
}
|
||||
|
||||
// New returns a new [Storage] given a [Config].
|
||||
func New(config ...Config) (*Storage, error) {
|
||||
var (
|
||||
cfg = setupConfig(config...)
|
||||
options = make([]func(session *coh.SessionOptions), 0)
|
||||
)
|
||||
|
||||
// apply any config values as Coherence options
|
||||
options = append(options, coh.WithAddress(cfg.Address))
|
||||
|
||||
if cfg.TLSConfig != nil {
|
||||
options = append(options, coh.WithTLSConfig(cfg.TLSConfig))
|
||||
} else {
|
||||
options = append(options, coh.WithPlainText())
|
||||
}
|
||||
|
||||
options = append(options, coh.WithRequestTimeout(cfg.Timeout))
|
||||
|
||||
// validate near cache options
|
||||
if cfg.NearCacheTimeout != 0 {
|
||||
if cfg.NearCacheTimeout > cfg.Timeout {
|
||||
return nil, fmt.Errorf("you cannot set the near cache timeout (%v) to less than session timeout (%v)",
|
||||
cfg.NearCacheTimeout, cfg.Timeout)
|
||||
}
|
||||
}
|
||||
|
||||
// create the Coherence session
|
||||
session, err := coh.NewSession(context.Background(), options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store, err := newCoherenceStorage(session, cfg.ScopeName, cfg.NearCacheTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if Reset is true then reset the store
|
||||
if cfg.Reset {
|
||||
return store, store.Reset()
|
||||
}
|
||||
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// setupConfig sets the default config.
|
||||
func setupConfig(config ...Config) Config {
|
||||
// if nothing provided then use the default config values
|
||||
if len(config) == 0 {
|
||||
return DefaultConfig
|
||||
}
|
||||
|
||||
cfg := config[0]
|
||||
|
||||
// Check for any invalid default values and overwrite them
|
||||
if cfg.Address == "" {
|
||||
cfg.Address = DefaultConfig.Address
|
||||
}
|
||||
if cfg.ScopeName == "" {
|
||||
cfg.ScopeName = DefaultConfig.ScopeName
|
||||
}
|
||||
if cfg.Timeout == 0 {
|
||||
cfg.Timeout = DefaultConfig.Timeout
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// newCoherenceStorage returns a new Coherence [Storage].
|
||||
func newCoherenceStorage(session *coh.Session, cacheName string, nearCacheTimeout time.Duration) (*Storage, error) {
|
||||
cacheOptions := make([]func(cache *coh.CacheOptions), 0)
|
||||
|
||||
// configure a near cache if the nearCacheTimeout is set
|
||||
if nearCacheTimeout != 0 {
|
||||
nearCacheOptions := coh.NearCacheOptions{TTL: nearCacheTimeout}
|
||||
cacheOptions = append(cacheOptions, coh.WithNearCache(&nearCacheOptions))
|
||||
}
|
||||
|
||||
nc, err := coh.GetNamedCache[string, []byte](session, "fiber$"+cacheName, cacheOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Storage{
|
||||
session: session,
|
||||
namedCache: nc,
|
||||
ctx: context.Background(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Storage) Get(key string) ([]byte, error) {
|
||||
v, err := s.namedCache.Get(s.ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return *v, nil
|
||||
}
|
||||
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||
_, err := s.namedCache.PutWithExpiry(s.ctx, key, val, exp)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Storage) Delete(key string) error {
|
||||
_, err := s.namedCache.Remove(s.ctx, key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Storage) Reset() error {
|
||||
return s.namedCache.Truncate(s.ctx)
|
||||
}
|
||||
|
||||
func (s *Storage) Close() error {
|
||||
s.session.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Conn() *coh.Session {
|
||||
return s.namedCache.GetSession()
|
||||
}
|
||||
230
coherence/coherence_test.go
Normal file
230
coherence/coherence_test.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package coherence
|
||||
|
||||
/*
|
||||
* Copyright © 2023, 2024 Oracle and/or its affiliates.
|
||||
*/
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
key1 = "key1"
|
||||
key2 = "key2"
|
||||
missingKey = "missing-key"
|
||||
value1 = []byte("value1")
|
||||
value2 = []byte("value2")
|
||||
)
|
||||
|
||||
var testStore *Storage
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testStore, _ = New(Config{
|
||||
Reset: true,
|
||||
NearCacheTimeout: time.Duration(4) * time.Second,
|
||||
})
|
||||
|
||||
code := m.Run()
|
||||
|
||||
_ = testStore.Close()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// newTestStore returns a new Coherence Store and ensures it is reset.
|
||||
func newTestStore(t testing.TB, config ...Config) (*Storage, error) {
|
||||
t.Helper()
|
||||
|
||||
testStore, err := New(config...)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Reset()
|
||||
|
||||
return testStore, err
|
||||
}
|
||||
|
||||
func Test_Coherence_Set_And_Get(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
err := testStore.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value1, val)
|
||||
|
||||
require.NotNil(t, testStore.Conn())
|
||||
}
|
||||
|
||||
func Test_Coherence_Set_Override(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
err := testStore.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key1, value2, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value2, val)
|
||||
}
|
||||
|
||||
func Test_Coherence_Set_With_Reset(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
err := testStore.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value1, val)
|
||||
|
||||
// get a new store but reset it, so the subsequent Get will return nil
|
||||
testStore2, err := newTestStore(t, Config{Reset: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err = testStore2.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
|
||||
require.Equal(t, nil, testStore2.Close())
|
||||
}
|
||||
|
||||
func Test_Coherence_Set_With_Expiry(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
// set with an expiry of 5 seconds
|
||||
err := testStore.Set(key1, value1, time.Duration(5)*time.Second)
|
||||
require.NoError(t, err)
|
||||
time.Sleep(time.Duration(6) * time.Second)
|
||||
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
}
|
||||
|
||||
func Test_Coherence_Get_Missing(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
val, err := testStore.Get(missingKey)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
}
|
||||
|
||||
func Test_Coherence_Reset(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
err := testStore.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Set(key2, value2, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check the keys exist
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value1, val)
|
||||
|
||||
val, err = testStore.Get(key2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value2, val)
|
||||
|
||||
// reset the store, this should remove both entries
|
||||
err = testStore.Reset()
|
||||
|
||||
// check the keys have expired
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
|
||||
val, err = testStore.Get(key2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
}
|
||||
|
||||
func Test_Coherence_Set_And_Delete(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
err := testStore.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore.Delete(key1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure the key has gone
|
||||
val, err = testStore.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(val) == 0)
|
||||
}
|
||||
|
||||
// TestCoherenceWithScope ensures we can create multiple session stores with multiple scopes.
|
||||
func Test_Coherence_With_Scope(t *testing.T) {
|
||||
var val []byte
|
||||
|
||||
// create two session stores with different scopes
|
||||
testStore1, err := newTestStore(t, Config{ScopeName: "scope1"})
|
||||
require.NoError(t, err)
|
||||
|
||||
testStore2, err := newTestStore(t, Config{ScopeName: "scope2"})
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure we can put the same key with different values in each scope
|
||||
err = testStore1.Set(key1, value1, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testStore2.Set(key1, value2, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure the value of "key1" is different for each store
|
||||
val, err = testStore1.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value1, val)
|
||||
|
||||
val, err = testStore2.Get(key1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value2, val)
|
||||
|
||||
require.NoError(t, testStore1.Close())
|
||||
require.NoError(t, testStore2.Close())
|
||||
}
|
||||
|
||||
func Benchmark_Coherence_Set(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
err = testStore.Set("john", []byte("doe"), 0)
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Coherence_Get(b *testing.B) {
|
||||
err := testStore.Set("john", []byte("doe"), 0)
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = testStore.Get("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
func Benchmark_Coherence_SetAndDelete(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = testStore.Set("john", []byte("doe"), 0)
|
||||
err = testStore.Delete("john")
|
||||
}
|
||||
|
||||
require.NoError(b, err)
|
||||
}
|
||||
28
coherence/go.mod
Normal file
28
coherence/go.mod
Normal file
@@ -0,0 +1,28 @@
|
||||
module github.com/gofiber/storage/coherence
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/oracle/coherence-go-client/v2 v2.0.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
google.golang.org/grpc v1.58.3 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
)
|
||||
44
coherence/go.sum
Normal file
44
coherence/go.sum
Normal file
@@ -0,0 +1,44 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/oracle/coherence-go-client/v2 v2.0.0 h1:epRtq50pHgW0Wbl7piSPdDbwE3JVe+9XFyTS+j0YmEI=
|
||||
github.com/oracle/coherence-go-client/v2 v2.0.0/go.mod h1:tiCK6dVyBf/GVabOPY73Cl6+eKoLtStx/uWEEdJfpKg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
|
||||
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
94
couchbase/README.md
Normal file
94
couchbase/README.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
id: couchbase
|
||||
title: Couchbase
|
||||
---
|
||||
|
||||

|
||||
[](https://gofiber.io/discord)
|
||||

|
||||

|
||||

|
||||
|
||||
A Couchbase storage driver using [couchbase/gocb](https://github.com/couchbase/gocb).
|
||||
|
||||
**Note: Requires Go 1.19 and above**
|
||||
|
||||
### Table of Contents
|
||||
- [Signatures](#signatures)
|
||||
- [Installation](#installation)
|
||||
- [Examples](#examples)
|
||||
- [Config](#config)
|
||||
- [Default Config](#default-config)
|
||||
|
||||
### Signatures
|
||||
```go
|
||||
func New(config ...Config) Storage
|
||||
func (s *Storage) Get(key string) ([]byte, error)
|
||||
func (s *Storage) Set(key string, val []byte, exp time.Duration) error
|
||||
func (s *Storage) Delete(key string) error
|
||||
func (s *Storage) Reset() error
|
||||
func (s *Storage) Close() error
|
||||
func (s *Storage) Conn() *gocb.Cluster
|
||||
```
|
||||
### Installation
|
||||
Couchbase is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
|
||||
```bash
|
||||
go mod init github.com/<user>/<repo>
|
||||
```
|
||||
And then install the Couchbase implementation:
|
||||
```bash
|
||||
go get github.com/gofiber/storage/couchbase/v2
|
||||
```
|
||||
|
||||
### Examples
|
||||
Import the storage package.
|
||||
```go
|
||||
import "github.com/gofiber/storage/couchbase/v2"
|
||||
```
|
||||
|
||||
You can use the following possibilities to create a storage:
|
||||
```go
|
||||
// Initialize default config
|
||||
store := couchbase.New()
|
||||
|
||||
// Initialize Couchbase storage with custom config
|
||||
store := couchbase.New(couchbase.Config{
|
||||
Host: "127.0.0.1:8091",
|
||||
Username: "",
|
||||
Password: "",
|
||||
Bucket: 0,
|
||||
ConnectionTimeout: 3* time.Second,
|
||||
KVTimeout: 1* time.Second,
|
||||
})
|
||||
```
|
||||
|
||||
### Config
|
||||
```go
|
||||
type Config struct {
|
||||
// The application username to Connect to the Couchbase cluster
|
||||
Username string
|
||||
// The application password to Connect to the Couchbase cluster
|
||||
Password string
|
||||
// The connection string for the Couchbase cluster
|
||||
Host string
|
||||
// The name of the bucket to Connect to
|
||||
Bucket string
|
||||
// The timeout for connecting to the Couchbase cluster
|
||||
ConnectionTimeout time.Duration
|
||||
// The timeout for performing operations on the Couchbase cluster
|
||||
KVTimeout time.Duration
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
```go
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Host: "127.0.0.1:8091",
|
||||
Username: "admin",
|
||||
Password: "123456",
|
||||
Bucket: "fiber_storage",
|
||||
ConnectionTimeout: 3 * time.Second,
|
||||
KVTimeout: 1 * time.Second,
|
||||
}
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user