Compare commits
727 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70c2854f7c | ||
|
|
e9381ddeb2 | ||
|
|
9cc8eec773 | ||
|
|
0b45535061 | ||
|
|
95973ba3e8 | ||
|
|
ac64731d55 | ||
|
|
5dc064e971 | ||
|
|
c24732ed4e | ||
|
|
ba710bee86 | ||
|
|
c20392ca80 | ||
|
|
8eb05d0950 | ||
|
|
0f94e2c0c3 | ||
|
|
a25508b98d | ||
|
|
e825433a38 | ||
|
|
d1c08889fe | ||
|
|
0b82b5a0d6 | ||
|
|
a33d0d4fb6 | ||
|
|
ba42334d36 | ||
|
|
2e62641aa4 | ||
|
|
dad460dcfc | ||
|
|
3ae23b6a54 | ||
|
|
97126f18b1 | ||
|
|
3838d222c2 | ||
|
|
96c3292210 | ||
|
|
b0fd92cb3f | ||
|
|
6276c55cc9 | ||
|
|
afa6ff7c4b | ||
|
|
c6c8e5d70c | ||
|
|
fa354ec8d9 | ||
|
|
d0375f697d | ||
|
|
33c8257d25 | ||
|
|
f389bc33c3 | ||
|
|
4d5dca71ce | ||
|
|
a9c44a1b9c | ||
|
|
4144f800a1 | ||
|
|
6ef9a81017 | ||
|
|
8c6722f3c5 | ||
|
|
40e138627b | ||
|
|
a470dda4e6 | ||
|
|
b725410623 | ||
|
|
a9dfb33126 | ||
|
|
8b848770dc | ||
|
|
94629edb9b | ||
|
|
2a3f2ca28d | ||
|
|
8ab1e7d432 | ||
|
|
b2ba6a0c85 | ||
|
|
cca5421aed | ||
|
|
799d9a73e6 | ||
|
|
b0781622b2 | ||
|
|
0d0eec6345 | ||
|
|
1af79f7960 | ||
|
|
15b570bbdd | ||
|
|
7aa5599cc2 | ||
|
|
676293ec42 | ||
|
|
abc4fb81b1 | ||
|
|
53a16f354f | ||
|
|
6ab1ecd836 | ||
|
|
e7b16e7b47 | ||
|
|
14804f81a8 | ||
|
|
9a61b8d77d | ||
|
|
f42c2763d5 | ||
|
|
98d4e0e1b5 | ||
|
|
9156633baf | ||
|
|
bcf4f836b4 | ||
|
|
dbc1d70f99 | ||
|
|
78bc190a85 | ||
|
|
02855d7fed | ||
|
|
6fdd5d32be | ||
|
|
d7f32b105b | ||
|
|
0ac480a0bd | ||
|
|
417996de02 | ||
|
|
6c2d60cec2 | ||
|
|
743bd6c917 | ||
|
|
ab61aa41d9 | ||
|
|
36396ae29e | ||
|
|
749e083e6e | ||
|
|
67b9cf9e82 | ||
|
|
27fb20f3ab | ||
|
|
1c71b274f0 | ||
|
|
fcd20b63fe | ||
|
|
8ec344ac1b | ||
|
|
df966a9ac6 | ||
|
|
f634666dc6 | ||
|
|
e2f9f5d7e5 | ||
|
|
d078b0d143 | ||
|
|
0ccdea3cd8 | ||
|
|
df54b47cd0 | ||
|
|
2e595830b3 | ||
|
|
96fbcc9a5a | ||
|
|
6283801981 | ||
|
|
9a3214d46e | ||
|
|
9eb7c8344f | ||
|
|
4140bbb1f7 | ||
|
|
ea44497136 | ||
|
|
07737c6e5b | ||
|
|
98d5eefc86 | ||
|
|
4f2d93bb65 | ||
|
|
a5df3f1747 | ||
|
|
7f5f73887d | ||
|
|
91ce7807b9 | ||
|
|
d26fae9875 | ||
|
|
60bdc79ec4 | ||
|
|
253ddf2998 | ||
|
|
9fa15b390a | ||
|
|
e7d6fe6c8b | ||
|
|
9650b1aa70 | ||
|
|
eafa6f960f | ||
|
|
c62ccf4870 | ||
|
|
ef34439a79 | ||
|
|
b328ec2462 | ||
|
|
60f27178b8 | ||
|
|
e3fbb83ad0 | ||
|
|
28b70a7b9a | ||
|
|
dcdc341d0f | ||
|
|
fce77c9372 | ||
|
|
a360c481c2 | ||
|
|
c72db5fa5f | ||
|
|
fc9a23d6d4 | ||
|
|
167f4666e2 | ||
|
|
1cbcc7be21 | ||
|
|
8053598069 | ||
|
|
7cfac1a91a | ||
|
|
192cdd028e | ||
|
|
029c143922 | ||
|
|
00298cc68c | ||
|
|
d9c7db51af | ||
|
|
f12b15d22b | ||
|
|
409b8bac00 | ||
|
|
28b09bde4b | ||
|
|
2f6af906f4 | ||
|
|
628e3ac1eb | ||
|
|
fbf5785e35 | ||
|
|
eeea2b1ff8 | ||
|
|
32062e439f | ||
|
|
930a0beaf1 | ||
|
|
4a49fefdd9 | ||
|
|
8e792855e0 | ||
|
|
69f5c6987a | ||
|
|
85fc9e4ecf | ||
|
|
d5c3f0c9cf | ||
|
|
a48120e675 | ||
|
|
36f8e4f2ad | ||
|
|
1084a39a45 | ||
|
|
86df482842 | ||
|
|
b0d47ebcc6 | ||
|
|
fffdf1dfba | ||
|
|
3273ed2616 | ||
|
|
aa7b0a31b0 | ||
|
|
fb0d44d403 | ||
|
|
cd8ec89cbb | ||
|
|
252f271dc5 | ||
|
|
62d400c3a9 | ||
|
|
f9aa3e0da5 | ||
|
|
685fe5b0fb | ||
|
|
5180e71a0d | ||
|
|
55637f7508 | ||
|
|
7d72dfe0be | ||
|
|
02529a0fc2 | ||
|
|
b44974677e | ||
|
|
d4fd5e4fce | ||
|
|
30123eaa4a | ||
|
|
454ec97d51 | ||
|
|
c2ac331e78 | ||
|
|
be4a35af11 | ||
|
|
445b29ad0d | ||
|
|
64d0f7fffd | ||
|
|
baf0d09455 | ||
|
|
08a81a0ab9 | ||
|
|
31110c7fd9 | ||
|
|
0e1dd92d9b | ||
|
|
a3204a4df7 | ||
|
|
2288ab48b9 | ||
|
|
670401884c | ||
|
|
37181c341e | ||
|
|
be7e677448 | ||
|
|
b2eeb49a45 | ||
|
|
9aa040d917 | ||
|
|
c2043a223b | ||
|
|
f24e859f17 | ||
|
|
737b33f9d1 | ||
|
|
00791d2151 | ||
|
|
b141598f9b | ||
|
|
d1618d79b0 | ||
|
|
00c84dfe5c | ||
|
|
95f31b98a8 | ||
|
|
10d74ed100 | ||
|
|
8a7f612d5b | ||
|
|
0829ee9234 | ||
|
|
b22e33444b | ||
|
|
d115a12cbe | ||
|
|
b7b744de94 | ||
|
|
68e46e406a | ||
|
|
a46ae4efec | ||
|
|
62777a794e | ||
|
|
329a969761 | ||
|
|
30170bc394 | ||
|
|
f193302e15 | ||
|
|
7c4870d641 | ||
|
|
8b84a76d5d | ||
|
|
a4cd761372 | ||
|
|
63d2cfd6ba | ||
|
|
bb44bdd047 | ||
|
|
6904e66384 | ||
|
|
fbffe2367e | ||
|
|
e442a2846d | ||
|
|
f6985586ea | ||
|
|
2bae5b0959 | ||
|
|
1e58809fcc | ||
|
|
6b1d213cc2 | ||
|
|
42bec13a83 | ||
|
|
4415a179b3 | ||
|
|
5d42604efd | ||
|
|
b134b7d3f6 | ||
|
|
788219fe05 | ||
|
|
9a7f66cfe9 | ||
|
|
daa4d16e61 | ||
|
|
cf05f87795 | ||
|
|
c2f2f83b7c | ||
|
|
b30b2a523f | ||
|
|
150a3810a8 | ||
|
|
ac0eaa912b | ||
|
|
05a04aa801 | ||
|
|
e37d4043f6 | ||
|
|
d073425b44 | ||
|
|
825b18cf71 | ||
|
|
549ad3204f | ||
|
|
35f9499b67 | ||
|
|
db82c35c17 | ||
|
|
73c74f753c | ||
|
|
a38fb2a5dc | ||
|
|
38e99e01f9 | ||
|
|
a1f46e84b8 | ||
|
|
6540804571 | ||
|
|
ffe6707595 | ||
|
|
9b21740c9f | ||
|
|
bd12e2ab95 | ||
|
|
bffb5ef8b4 | ||
|
|
e4c9822d78 | ||
|
|
73187d8832 | ||
|
|
8101154d5e | ||
|
|
c02937fd6f | ||
|
|
3430be4075 | ||
|
|
3f2b6f771f | ||
|
|
6e39b49cc2 | ||
|
|
71c34ed4e0 | ||
|
|
477178675c | ||
|
|
dbdf68b248 | ||
|
|
2fd139b307 | ||
|
|
a6c2657062 | ||
|
|
78a0bc0e2c | ||
|
|
d7116d6867 | ||
|
|
edc15b9fa2 | ||
|
|
93d4b73b2f | ||
|
|
8e3849e591 | ||
|
|
acaa1098f7 | ||
|
|
c1a5e88752 | ||
|
|
74b99014d2 | ||
|
|
9cba944d21 | ||
|
|
8c1c2f5d05 | ||
|
|
bf0fa8c562 | ||
|
|
3e1fc9ba6c | ||
|
|
4ceba603e4 | ||
|
|
6591c21ace | ||
|
|
e8d03c7b9b | ||
|
|
6fbce4c2f7 | ||
|
|
c168d54495 | ||
|
|
2cce22052b | ||
|
|
4e19d5f625 | ||
|
|
5b667da526 | ||
|
|
f9fc9a3518 | ||
|
|
e005cfd70e | ||
|
|
feb997481c | ||
|
|
2c8e90c9d8 | ||
|
|
ec96d5afa0 | ||
|
|
8be8853c33 | ||
|
|
c228f5a244 | ||
|
|
d4c8b4e3ac | ||
|
|
6564f6c164 | ||
|
|
1e37a5509c | ||
|
|
1e9503deaa | ||
|
|
ab1f36c565 | ||
|
|
5a212cd626 | ||
|
|
856fd9d69f | ||
|
|
4606d99951 | ||
|
|
dbd75169e5 | ||
|
|
f5b39ee911 | ||
|
|
db5d52b4b2 | ||
|
|
dfeb9967b8 | ||
|
|
673e860c18 | ||
|
|
9deae34b20 | ||
|
|
ec92344fb4 | ||
|
|
44c68d6174 | ||
|
|
5b7f172d03 | ||
|
|
65125eac87 | ||
|
|
761902864a | ||
|
|
af24d541d1 | ||
|
|
3ad68a617e | ||
|
|
9e1a6589d4 | ||
|
|
da8ceed07e | ||
|
|
35935adc98 | ||
|
|
5b4a501f68 | ||
|
|
5425a90f16 | ||
|
|
7eaca149c1 | ||
|
|
4b5fd95657 | ||
|
|
96dedf553e | ||
|
|
23219f2662 | ||
|
|
af78ed608e | ||
|
|
51dc59e019 | ||
|
|
afc102e90a | ||
|
|
fc560179e0 | ||
|
|
d26241de0e | ||
|
|
00310f4f10 | ||
|
|
8caae219cf | ||
|
|
2264ae9247 | ||
|
|
29225bbe75 | ||
|
|
4b5625fd59 | ||
|
|
7c0c2419f7 | ||
|
|
5f59282ba1 | ||
|
|
db03ce939c | ||
|
|
68bcbbb701 | ||
|
|
8bdf7b3983 | ||
|
|
4ab427d315 | ||
|
|
9a0a434dd8 | ||
|
|
33d1dda954 | ||
|
|
8e9efb4ceb | ||
|
|
8835af11d5 | ||
|
|
cfb6b678f1 | ||
|
|
365500da98 | ||
|
|
f14d75e798 | ||
|
|
0f71b4a378 | ||
|
|
b651e0146d | ||
|
|
a0dbbb2d84 | ||
|
|
a85fbf69e0 | ||
|
|
92b8c7961b | ||
|
|
225f8ac12f | ||
|
|
1161511207 | ||
|
|
ca8eda412e | ||
|
|
ec4ec48fb8 | ||
|
|
c0b69e8ef7 | ||
|
|
4241dbb600 | ||
|
|
f54280aaad | ||
|
|
6069400538 | ||
|
|
616be1d76c | ||
|
|
8e91ce67c5 | ||
|
|
c1ecd661c3 | ||
|
|
b27e2aad07 | ||
|
|
5ce508e09d | ||
|
|
3cfa5a41b1 | ||
|
|
6c072f37ef | ||
|
|
dbd993ed2b | ||
|
|
45b5c4ba7a | ||
|
|
7933e5d1f9 | ||
|
|
01e52e6f9f | ||
|
|
40a955e192 | ||
|
|
a8296f7301 | ||
|
|
590c3b876b | ||
|
|
6dfc805eaa | ||
|
|
5ce6068df5 | ||
|
|
bf9b8f4d1b | ||
|
|
d618581060 | ||
|
|
2936bbfae8 | ||
|
|
47b08bfc02 | ||
|
|
da4f77ca1f | ||
|
|
1c0a75d467 | ||
|
|
659cf0c221 | ||
|
|
430229fd84 | ||
|
|
81699a0971 | ||
|
|
c54aff74b3 | ||
|
|
7f43ab9097 | ||
|
|
d78f740250 | ||
|
|
cd1bd18a49 | ||
|
|
f81b084448 | ||
|
|
02d9c77402 | ||
|
|
a0c903c68c | ||
|
|
6aa325d3da | ||
|
|
041f874d4c | ||
|
|
526ecd6a81 | ||
|
|
d373054fc4 | ||
|
|
b6d9f1d4b2 | ||
|
|
3fef916972 | ||
|
|
89a51e5b91 | ||
|
|
f87a6ccc7a | ||
|
|
f65cea66ef | ||
|
|
4239880acb | ||
|
|
1dcd06a1c1 | ||
|
|
0f30191d10 | ||
|
|
8fb9d5daaa | ||
|
|
ed3c942ff1 | ||
|
|
80436d4a8b | ||
|
|
cfc702c766 | ||
|
|
88ae15ea8e | ||
|
|
6bafca7386 | ||
|
|
379e842080 | ||
|
|
c41ce469d0 | ||
|
|
a1ca68473d | ||
|
|
3345d03433 | ||
|
|
81a426608a | ||
|
|
2ad6f0a65e | ||
|
|
ee8bd8ddae | ||
|
|
319ac14e7d | ||
|
|
0215a7400d | ||
|
|
79db0ca7a6 | ||
|
|
1a7eafb699 | ||
|
|
81a06ea6cd | ||
|
|
de4be649ab | ||
|
|
d90ec5f06c | ||
|
|
32065ced6e | ||
|
|
b5224a2227 | ||
|
|
c55777738f | ||
|
|
c72dff5a24 | ||
|
|
6b09e49c08 | ||
|
|
413218c4c4 | ||
|
|
16c04b50ee | ||
|
|
56c18f7768 | ||
|
|
22ca13bc78 | ||
|
|
4c7fd18230 | ||
|
|
39730fc13e | ||
|
|
889c0a0d0f | ||
|
|
624a803955 | ||
|
|
9f5c21f80e | ||
|
|
a3fe089367 | ||
|
|
85d5cd3118 | ||
|
|
61006e626d | ||
|
|
15aad1cb24 | ||
|
|
95c1c5f54e | ||
|
|
c65fb91878 | ||
|
|
d5a7e1331e | ||
|
|
04bcd93ba3 | ||
|
|
f97ef7039a | ||
|
|
9160b46c1e | ||
|
|
aa4b116498 | ||
|
|
612bb71165 | ||
|
|
5c67f99ef9 | ||
|
|
101a4808a0 | ||
|
|
1d38671f5e | ||
|
|
7f25d88f02 | ||
|
|
be830d3dad | ||
|
|
5bc949d70f | ||
|
|
43817bd722 | ||
|
|
61623d6d75 | ||
|
|
9aad60f56d | ||
|
|
e7cf3e8084 | ||
|
|
e024e7c2ec | ||
|
|
6fc136ae9a | ||
|
|
2b69ded1ea | ||
|
|
8dd799aa6f | ||
|
|
7230ef41ee | ||
|
|
a86f0a743c | ||
|
|
af75b55ef7 | ||
|
|
9ecb37dd4f | ||
|
|
2e3784a914 | ||
|
|
019c1af435 | ||
|
|
5322955f2b | ||
|
|
a8ea4ce283 | ||
|
|
c12862f60d | ||
|
|
e889183fc5 | ||
|
|
7be695c6bd | ||
|
|
956901ae02 | ||
|
|
d562c5b2d5 | ||
|
|
d7b054c3f6 | ||
|
|
901ccad0cf | ||
|
|
b9454e0f0c | ||
|
|
26181907fc | ||
|
|
8368798ad2 | ||
|
|
ed597e5e99 | ||
|
|
2c88c15f7f | ||
|
|
af7cd3cc04 | ||
|
|
9552551f9a | ||
|
|
1c73a0f649 | ||
|
|
e3698b2a07 | ||
|
|
c841f8b360 | ||
|
|
50f9b68d61 | ||
|
|
27b48bc16e | ||
|
|
bccdbaed2b | ||
|
|
398095a667 | ||
|
|
80095824b9 | ||
|
|
d91c1f96cc | ||
|
|
1c005a0292 | ||
|
|
c7ced496ac | ||
|
|
d4ff18834c | ||
|
|
f86d9fd626 | ||
|
|
854604f724 | ||
|
|
cfd3642cb1 | ||
|
|
f493590604 | ||
|
|
8c084a3de8 | ||
|
|
985aa803a4 | ||
|
|
9e319d7bd6 | ||
|
|
a122e176d7 | ||
|
|
88a6f2931e | ||
|
|
54f3a83e25 | ||
|
|
0955c0d8d3 | ||
|
|
6bb5be5216 | ||
|
|
c9cd7e4be0 | ||
|
|
ce2cecf046 | ||
|
|
6e934ee6a1 | ||
|
|
723d7d1263 | ||
|
|
298572893e | ||
|
|
405f6f7368 | ||
|
|
648ccc7c17 | ||
|
|
f5afe0587f | ||
|
|
91a227a475 | ||
|
|
4b905fe9ff | ||
|
|
0f409b7bec | ||
|
|
295c8de858 | ||
|
|
e5252f90af | ||
|
|
c2276155bf | ||
|
|
dbe49bcd87 | ||
|
|
7b936de32c | ||
|
|
9eb34f542c | ||
|
|
194304e544 | ||
|
|
c59fc332d5 | ||
|
|
b43832fe57 | ||
|
|
c24a497a23 | ||
|
|
4096fcd1bf | ||
|
|
9a0e806f78 | ||
|
|
20c9632996 | ||
|
|
65a628ca88 | ||
|
|
d82dbba096 | ||
|
|
58547f6997 | ||
|
|
e6f4eedb1e | ||
|
|
c5b963141f | ||
|
|
5df40bd746 | ||
|
|
403f15dc48 | ||
|
|
704d7451a0 | ||
|
|
fa11071443 | ||
|
|
87351c8a0c | ||
|
|
2f5fb1e68e | ||
|
|
96e1ec6d31 | ||
|
|
ac3cf05f1a | ||
|
|
6335e34395 | ||
|
|
02c2029ac1 | ||
|
|
6914aa3e27 | ||
|
|
f4fcb1cc9a | ||
|
|
b6eec21ec0 | ||
|
|
0ce3aeb189 | ||
|
|
713c8efcbe | ||
|
|
9fa5e39872 | ||
|
|
ace53fa405 | ||
|
|
3c06980107 | ||
|
|
1f26fbb5af | ||
|
|
84c6622122 | ||
|
|
63f099f2f6 | ||
|
|
373ce72984 | ||
|
|
4cf29455e4 | ||
|
|
07db5d497c | ||
|
|
f1bb0afc4e | ||
|
|
d791fe3013 | ||
|
|
c16e22a5c6 | ||
|
|
db7a720445 | ||
|
|
6c09a02099 | ||
|
|
1b3356cafd | ||
|
|
5869902f2c | ||
|
|
28898031f0 | ||
|
|
1ce0f94638 | ||
|
|
f876ad973f | ||
|
|
6014b13234 | ||
|
|
3e9c702c47 | ||
|
|
3ff919ccf1 | ||
|
|
8dc0844c79 | ||
|
|
a2764b68ca | ||
|
|
bbbae072ea | ||
|
|
b4735b5931 | ||
|
|
418638ad16 | ||
|
|
9fb09d3109 | ||
|
|
d7e08f96a5 | ||
|
|
4d49d272eb | ||
|
|
faa6890950 | ||
|
|
9c390f6da4 | ||
|
|
6842277977 | ||
|
|
ddf68d464d | ||
|
|
b2f19e8dc6 | ||
|
|
5714b42975 | ||
|
|
c4e9c49c10 | ||
|
|
9210efb051 | ||
|
|
b9f1b05625 | ||
|
|
828c2e3c71 | ||
|
|
10150a7352 | ||
|
|
baaa45f8c7 | ||
|
|
322af30d6a | ||
|
|
206efbf30d | ||
|
|
a96dee85d2 | ||
|
|
d307568cbc | ||
|
|
0ee27b143c | ||
|
|
7bfb4a9ba5 | ||
|
|
110c73fc8d | ||
|
|
424d9b8385 | ||
|
|
1b48ccc868 | ||
|
|
fac82204b6 | ||
|
|
61f114e655 | ||
|
|
24410bf1bb | ||
|
|
aa24969eee | ||
|
|
a5297d13c4 | ||
|
|
b06bdb83cb | ||
|
|
d06092212f | ||
|
|
914778eae1 | ||
|
|
e14c700c60 | ||
|
|
0848e348bb | ||
|
|
3d5ae42660 | ||
|
|
f207b6b4c9 | ||
|
|
ed2c5078ad | ||
|
|
aec792f5b8 | ||
|
|
17d64de3d5 | ||
|
|
f6bea08535 | ||
|
|
feab6c39b3 | ||
|
|
e999c76882 | ||
|
|
686cc599a2 | ||
|
|
92983556a0 | ||
|
|
837872c3f3 | ||
|
|
55222dc5d1 | ||
|
|
adce6ae851 | ||
|
|
9dc32cb791 | ||
|
|
23dc08c925 | ||
|
|
488a44b88e | ||
|
|
530bdf975e | ||
|
|
d7a6627a1f | ||
|
|
d6066183b9 | ||
|
|
3e2c3ba035 | ||
|
|
e24cba8c35 | ||
|
|
a23013abc1 | ||
|
|
27a4f44de5 | ||
|
|
4e07dbbefc | ||
|
|
dcf4ad2c21 | ||
|
|
04dd861fe3 | ||
|
|
c8ee6c6f6d | ||
|
|
a57e4263d7 | ||
|
|
3d58f0d941 | ||
|
|
a52c9232c4 | ||
|
|
7a059c7a73 | ||
|
|
506910147f | ||
|
|
cf3eb24eb0 | ||
|
|
d965b23b2a | ||
|
|
f660743065 | ||
|
|
4559bd9030 | ||
|
|
3ac98fb101 | ||
|
|
aff52db289 | ||
|
|
ea27dfe08d | ||
|
|
27620af1bf | ||
|
|
bf116308d4 | ||
|
|
3fb27d98ab | ||
|
|
7e45c17730 | ||
|
|
626533d4a7 | ||
|
|
39719f4c17 | ||
|
|
526bd88dc4 | ||
|
|
37201ecaa6 | ||
|
|
02ed879837 | ||
|
|
8b881d3a77 | ||
|
|
f25456ce25 | ||
|
|
dfb1db4ab3 | ||
|
|
4362cb660b | ||
|
|
1aa0749ba8 | ||
|
|
c7f1f6a91f | ||
|
|
888a3fec21 | ||
|
|
8514b88974 | ||
|
|
724ec46129 | ||
|
|
4f1d1d2a8a | ||
|
|
39a387b54c | ||
|
|
2b0034667d | ||
|
|
98202c56ae | ||
|
|
1e06ddf13c | ||
|
|
560071bb68 | ||
|
|
2e49ec47a3 | ||
|
|
e70d618aff | ||
|
|
3e4cf426bd | ||
|
|
3f10924594 | ||
|
|
f8182c335a | ||
|
|
1d8d6a6d68 | ||
|
|
69fccdf5c6 | ||
|
|
27e8d44a56 | ||
|
|
72bc4ebf37 | ||
|
|
353f32e6af | ||
|
|
9bbaa9a2ae | ||
|
|
096fcefae9 | ||
|
|
0f1e292e34 | ||
|
|
195957a7cc | ||
|
|
eb122f45f9 | ||
|
|
c51ac9d6da | ||
|
|
97c9d02c43 | ||
|
|
0c06939f38 | ||
|
|
5db677d74d | ||
|
|
251ce4efbc | ||
|
|
386eabb61f | ||
|
|
b35eabe161 | ||
|
|
9ad9845d69 | ||
|
|
74eb25f9b5 | ||
|
|
044f390fe0 | ||
|
|
06d6e4901e | ||
|
|
3ca9646329 | ||
|
|
4b3e629dfd | ||
|
|
568fae9878 | ||
|
|
a844026f6b | ||
|
|
b677cacb8c | ||
|
|
1d66169ef1 | ||
|
|
74653e57e6 | ||
|
|
29d1d5f062 | ||
|
|
d8e8693d9a | ||
|
|
be737e0047 | ||
|
|
83ef06748d | ||
|
|
5a93f9991a | ||
|
|
8b0602a582 | ||
|
|
eb24ca6def | ||
|
|
22af79606a | ||
|
|
bee12fb89d | ||
|
|
1a9fbab165 | ||
|
|
9a4b9aa69f | ||
|
|
227043e51f | ||
|
|
db3a387224 | ||
|
|
0075f36bbc | ||
|
|
52f45669d1 | ||
|
|
294a13d653 | ||
|
|
eed66894db | ||
|
|
1434695c47 | ||
|
|
390ea65e15 | ||
|
|
6f2bcc6fb0 | ||
|
|
66a762d504 | ||
|
|
aaabec0b55 | ||
|
|
6339800946 | ||
|
|
a3e4a34021 | ||
|
|
6fcf3fedb6 | ||
|
|
34cbb26e47 | ||
|
|
07d0379edd | ||
|
|
96e8cddfc2 | ||
|
|
3c5e4e440b | ||
|
|
5ffcbb9b65 | ||
|
|
ec0fe312af | ||
|
|
3025d8611b | ||
|
|
98612a7cd6 | ||
|
|
6e428054ef |
2
.gitattributes
vendored
@@ -1,5 +1,5 @@
|
||||
# Set default behaviour, in case users don't have core.autocrlf set.
|
||||
* text=auto
|
||||
#* text=auto
|
||||
|
||||
# These annoying files
|
||||
rippled.1 binary
|
||||
|
||||
1
.gitignore
vendored
@@ -19,6 +19,7 @@
|
||||
*.o
|
||||
build
|
||||
tags
|
||||
TAGS
|
||||
bin/rippled
|
||||
Debug/*.*
|
||||
Release/*.*
|
||||
|
||||
28
.travis.yml
@@ -6,12 +6,10 @@ before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq python-software-properties
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:boost-latest/ppa
|
||||
- sudo add-apt-repository -y ppa:afrank/boost
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq g++-4.8
|
||||
- sudo apt-get install -qq libboost1.55-all-dev
|
||||
# We want debug symbols for boost as we install gdb later
|
||||
- sudo apt-get install -qq libboost1.55-dbg
|
||||
- sudo apt-get install -qq libboost1.57-all-dev
|
||||
- sudo apt-get install -qq mlocate
|
||||
- sudo updatedb
|
||||
- sudo locate libboost | grep /lib | grep -e ".a$"
|
||||
@@ -27,23 +25,35 @@ before_install:
|
||||
# What versions are we ACTUALLY running?
|
||||
- g++ -v
|
||||
- clang -v
|
||||
# Avoid `spurious errors` caused by ~/.npm permission issues
|
||||
# Does it already exist? Who owns? What permissions?
|
||||
- ls -lah ~/.npm || mkdir ~/.npm
|
||||
# Make sure we own it
|
||||
- sudo chown -R $USER ~/.npm
|
||||
|
||||
script:
|
||||
# Set so any failing command will abort the build
|
||||
- set -e
|
||||
# If only we could do -j12 ;)
|
||||
- scons
|
||||
# $CC will be either `clang` or `gcc` (If only we could do -j12 ;)
|
||||
- scons $CC.debug
|
||||
# We can be sure we're using the build/$CC.debug variant (-f so never err)
|
||||
- rm -f build/rippled
|
||||
- export RIPPLED_PATH="$PWD/build/$CC.debug/rippled"
|
||||
# See what we've actually built
|
||||
- ldd ./build/rippled
|
||||
- ldd $RIPPLED_PATH
|
||||
# Run unittests (under gdb)
|
||||
- | # create gdb script
|
||||
echo "set env MALLOC_CHECK_=3" > script.gdb
|
||||
echo "run" >> script.gdb
|
||||
echo "backtrace full" >> script.gdb
|
||||
# gdb --help
|
||||
- cat script.gdb | gdb --ex 'set print thread-events off' --return-child-result --args ./build/rippled --unittest
|
||||
# Run integration tests
|
||||
- cat script.gdb | gdb --ex 'set print thread-events off' --return-child-result --args $RIPPLED_PATH --unittest
|
||||
- npm install
|
||||
# Use build/(gcc|clang).debug/rippled
|
||||
- |
|
||||
echo "exports.default_server_config = {\"rippled_path\" : \"$RIPPLED_PATH\"};" > test/config.js
|
||||
|
||||
# Run integration tests
|
||||
- npm test
|
||||
notifications:
|
||||
email:
|
||||
|
||||
30
Builds/Docker/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
# rippled
|
||||
|
||||
# use the ubuntu base image
|
||||
FROM ubuntu
|
||||
MAINTAINER Roberto Catini roberto.catini@gmail.com
|
||||
|
||||
# make sure the package repository is up to date
|
||||
RUN apt-get update
|
||||
RUN apt-get -y upgrade
|
||||
|
||||
# install the dependencies
|
||||
RUN apt-get -y install git scons pkg-config protobuf-compiler libprotobuf-dev libssl-dev libboost1.55-all-dev
|
||||
|
||||
# download source code from official repository
|
||||
RUN git clone https://github.com/ripple/rippled.git src; cd src/; git checkout master
|
||||
|
||||
# compile
|
||||
RUN cd src/; scons build/rippled
|
||||
|
||||
# move to root directory and strip
|
||||
RUN cp src/build/rippled rippled; strip rippled
|
||||
|
||||
# copy default config
|
||||
RUN cp src/doc/rippled-example.cfg rippled.cfg
|
||||
|
||||
# clean source
|
||||
RUN rm -r src
|
||||
|
||||
# launch rippled when launching the container
|
||||
ENTRYPOINT ./rippled
|
||||
@@ -62,42 +62,42 @@ UI_HEADERS_DIR += ../../src/ripple_basics
|
||||
# New style
|
||||
#
|
||||
SOURCES += \
|
||||
../../src/ripple/beast/ripple_beast.cpp \
|
||||
../../src/ripple/beast/ripple_beast.unity.cpp \
|
||||
../../src/ripple/beast/ripple_beastc.c \
|
||||
../../src/ripple/common/ripple_common.cpp \
|
||||
../../src/ripple/http/ripple_http.cpp \
|
||||
../../src/ripple/json/ripple_json.cpp \
|
||||
../../src/ripple/peerfinder/ripple_peerfinder.cpp \
|
||||
../../src/ripple/radmap/ripple_radmap.cpp \
|
||||
../../src/ripple/resource/ripple_resource.cpp \
|
||||
../../src/ripple/sitefiles/ripple_sitefiles.cpp \
|
||||
../../src/ripple/sslutil/ripple_sslutil.cpp \
|
||||
../../src/ripple/testoverlay/ripple_testoverlay.cpp \
|
||||
../../src/ripple/types/ripple_types.cpp \
|
||||
../../src/ripple/validators/ripple_validators.cpp
|
||||
../../src/ripple/common/ripple_common.unity.cpp \
|
||||
../../src/ripple/http/ripple_http.unity.cpp \
|
||||
../../src/ripple/json/ripple_json.unity.cpp \
|
||||
../../src/ripple/peerfinder/ripple_peerfinder.unity.cpp \
|
||||
../../src/ripple/radmap/ripple_radmap.unity.cpp \
|
||||
../../src/ripple/resource/ripple_resource.unity.cpp \
|
||||
../../src/ripple/sitefiles/ripple_sitefiles.unity.cpp \
|
||||
../../src/ripple/sslutil/ripple_sslutil.unity.cpp \
|
||||
../../src/ripple/testoverlay/ripple_testoverlay.unity.cpp \
|
||||
../../src/ripple/types/ripple_types.unity.cpp \
|
||||
../../src/ripple/validators/ripple_validators.unity.cpp
|
||||
|
||||
# ---------
|
||||
# Old style
|
||||
#
|
||||
SOURCES += \
|
||||
../../src/ripple_app/ripple_app.cpp \
|
||||
../../src/ripple_app/ripple_app_pt1.cpp \
|
||||
../../src/ripple_app/ripple_app_pt2.cpp \
|
||||
../../src/ripple_app/ripple_app_pt3.cpp \
|
||||
../../src/ripple_app/ripple_app_pt4.cpp \
|
||||
../../src/ripple_app/ripple_app_pt5.cpp \
|
||||
../../src/ripple_app/ripple_app_pt6.cpp \
|
||||
../../src/ripple_app/ripple_app_pt7.cpp \
|
||||
../../src/ripple_app/ripple_app_pt8.cpp \
|
||||
../../src/ripple_basics/ripple_basics.cpp \
|
||||
../../src/ripple_core/ripple_core.cpp \
|
||||
../../src/ripple_data/ripple_data.cpp \
|
||||
../../src/ripple_hyperleveldb/ripple_hyperleveldb.cpp \
|
||||
../../src/ripple_leveldb/ripple_leveldb.cpp \
|
||||
../../src/ripple_net/ripple_net.cpp \
|
||||
../../src/ripple_overlay/ripple_overlay.cpp \
|
||||
../../src/ripple_rpc/ripple_rpc.cpp \
|
||||
../../src/ripple_websocket/ripple_websocket.cpp
|
||||
../../src/ripple_app/ripple_app.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt1.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt2.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt3.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt4.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt5.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt6.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt7.unity.cpp \
|
||||
../../src/ripple_app/ripple_app_pt8.unity.cpp \
|
||||
../../src/ripple_basics/ripple_basics.unity.cpp \
|
||||
../../src/ripple_core/ripple_core.unity.cpp \
|
||||
../../src/ripple_data/ripple_data.unity.cpp \
|
||||
../../src/ripple_hyperleveldb/ripple_hyperleveldb.unity.cpp \
|
||||
../../src/ripple_leveldb/ripple_leveldb.unity.cpp \
|
||||
../../src/ripple_net/ripple_net.unity.cpp \
|
||||
../../src/ripple_overlay/ripple_overlay.unity.cpp \
|
||||
../../src/ripple_rpc/ripple_rpc.unity.cpp \
|
||||
../../src/ripple_websocket/ripple_websocket.unity.cpp
|
||||
|
||||
LIBS += \
|
||||
-lboost_date_time-mt\
|
||||
|
||||
4
Builds/VisualStudio2013/.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
RippleD.vcxproj -text
|
||||
RippleD.vcxproj.filters -text
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<RepoDir>..\..</RepoDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(RepoDir)\build\VisualStudio2013\$(Configuration).$(Platform)\</OutDir>
|
||||
<IntDir>$(RepoDir)\build\obj\VisualStudio2013\$(Configuration).$(Platform)\</IntDir>
|
||||
<TargetName>rippled</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_VARIADIC_MAX=10;_WIN32_WINNT=0x0600;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(RepoDir)\src\protobuf\src;$(RepoDir)\src\protobuf\vsprojects;$(RepoDir)\src\leveldb;$(RepoDir)\src\leveldb\include;$(RepoDir)\build\proto;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<DisableSpecificWarnings>4018;4244</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SpecifySectionAttributes>
|
||||
</SpecifySectionAttributes>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<BuildMacro Include="RepoDir">
|
||||
<Value>$(RepoDir)</Value>
|
||||
</BuildMacro>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
@@ -1,11 +1,9 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Express 2013 for Windows Desktop
|
||||
VisualStudioVersion = 12.0.30110.0
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "beast", "..\..\src\beast\Builds\VisualStudio2013\beast.vcxproj", "{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RippleD", "RippleD.vcxproj", "{B7F39ECD-473C-484D-BC34-31F8362506A5}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RippleD", "RippleD.vcxproj", "{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -15,22 +13,14 @@ Global
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.Build.0 = Debug|x64
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.Build.0 = Release|Win32
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.ActiveCfg = Release|x64
|
||||
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.Build.0 = Release|x64
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|x64.Build.0 = Debug|x64
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|Win32.Build.0 = Release|Win32
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|x64.ActiveCfg = Release|x64
|
||||
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|x64.Build.0 = Release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|Win32.ActiveCfg = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|Win32.Build.0 = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|x64.ActiveCfg = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|x64.Build.0 = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|Win32.ActiveCfg = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|Win32.Build.0 = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|x64.ActiveCfg = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|x64.Build.0 = release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings>4018;4244;4267</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rippled
|
||||
Version: 0.23.0
|
||||
Version: 0.27.3
|
||||
Release: 1%{?dist}
|
||||
Summary: Ripple peer-to-peer network daemon
|
||||
|
||||
@@ -50,4 +50,3 @@ rm -rf %{buildroot}
|
||||
/usr/bin/rippled
|
||||
/usr/share/rippled/LICENSE
|
||||
/etc/rippled/rippled-example.cfg
|
||||
|
||||
|
||||
13
Builds/travis/clang.boost.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
--- /usr/include/boost/config/compiler/clang.hpp 2013-07-20 13:17:10.000000000 -0400
|
||||
+++ /usr/include/boost/config/compiler/clang.rippled.hpp 2014-03-11 16:40:51.000000000 -0400
|
||||
@@ -39,6 +39,10 @@
|
||||
// Clang supports "long long" in all compilation modes.
|
||||
#define BOOST_HAS_LONG_LONG
|
||||
|
||||
+#if defined(__SIZEOF_INT128__)
|
||||
+# define BOOST_HAS_INT128
|
||||
+#endif
|
||||
+
|
||||
//
|
||||
// Dynamic shared object (DSO) and dynamic-link library (DLL) support
|
||||
//
|
||||
10
Builds/travis/static_error.boost.patch
Normal file
@@ -0,0 +1,10 @@
|
||||
--- /usr/include/boost/bimap/detail/debug/static_error.hpp 2008-03-22 17:45:55.000000000 -0400
|
||||
+++ /usr/include/boost/bimap/detail/debug/static_error.rippled.hpp 2014-03-12 19:40:05.000000000 -0400
|
||||
@@ -25,7 +25,6 @@
|
||||
// a static error.
|
||||
/*===========================================================================*/
|
||||
#define BOOST_BIMAP_STATIC_ERROR(MESSAGE,VARIABLES) \
|
||||
- struct BOOST_PP_CAT(BIMAP_STATIC_ERROR__,MESSAGE) {}; \
|
||||
BOOST_MPL_ASSERT_MSG(false, \
|
||||
BOOST_PP_CAT(BIMAP_STATIC_ERROR__,MESSAGE), \
|
||||
VARIABLES)
|
||||
82
README.md
@@ -1,3 +1,77 @@
|
||||

|
||||
|
||||
#The World’s Fastest and Most Secure Payment System
|
||||
|
||||
**What is Ripple?**
|
||||
|
||||
Ripple is the open-source, distributed payment protocol that enables instant
|
||||
payments with low fees, no chargebacks, and currency flexibility (for example
|
||||
dollars, yen, euros, bitcoins, or even loyalty points). Businesses of any size
|
||||
can easily build payment solutions such as banking or remittance apps, and
|
||||
accelerate the movement of money. Ripple enables the world to move value the
|
||||
way it moves information on the Internet.
|
||||
|
||||

|
||||
|
||||
**What is a Gateway?**
|
||||
|
||||
Ripple works with gateways: independent businesses which hold customer
|
||||
deposits in various currencies such as U.S. dollars (USD) or Euros (EUR),
|
||||
in exchange for providing cryptographically-signed issuances that users can
|
||||
send and trade with one another in seconds on the Ripple network. Within the
|
||||
protocol, exchanges between multiple currencies can occur atomically without
|
||||
any central authority to monitor them. Later, customers can withdraw their
|
||||
Ripple balances from the gateways that created those issuances.
|
||||
|
||||
**How do Ripple payments work?**
|
||||
|
||||
A sender specifies the amount and currency the recipient should receive and
|
||||
Ripple automatically converts the sender’s available currencies using the
|
||||
distributed order books integrated into the Ripple protocol. Independent third
|
||||
parties acting as market makers provide liquidity in these order books.
|
||||
|
||||
Ripple uses a pathfinding algorithm that considers currency pairs when
|
||||
converting from the source to the destination currency. This algorithm searches
|
||||
for a series of currency swaps that gives the user the lowest cost. Since
|
||||
anyone can participate as a market maker, market forces drive fees to the
|
||||
lowest practical level.
|
||||
|
||||
**What can you do with Ripple?**
|
||||
|
||||
The protocol is entirely open-source and the network’s shared ledger is public
|
||||
information, so no central authority prevents anyone from participating.Anyone
|
||||
can become a market maker, create a wallet or a gateway, or monitor network
|
||||
behavior. Competition drives down spreads and fees, making the network useful
|
||||
to everyone.
|
||||
|
||||
|
||||
###Key Protocol Features
|
||||
1. XRP is Ripple’s native [cryptocurrency]
|
||||
(http://en.wikipedia.org/wiki/Cryptocurrency) with a fixed supply that
|
||||
decreases slowly over time, with no mining. XRP acts as a bridge currency, and
|
||||
pays for transaction fees that protect the network against spam
|
||||

|
||||
|
||||
2. Pathfinding discovers cheap and efficient payment paths through multiple
|
||||
[order books](https://www.ripplecharts.com) allowing anyone to [trade](https://www.rippletrade.com) anything. When two accounts aren’t linked by relationships of trust, the Ripple pathfinding engine considers intermediate links and order books to produce a set of possible paths the transaction can take. When the payment is processed, the liquidity along these paths is iteratively consumed in best-first order.
|
||||

|
||||
|
||||
3. [Consensus](https://www.youtube.com/watch?v=pj1QVb1vlC0) confirms
|
||||
transactions in an atomic fashion, without mining, ensuring efficient use of
|
||||
resources.
|
||||
|
||||
[transact]: https://ripple.com/files/ripple-FIs.pdf
|
||||
[build]: https://ripple.com/build/
|
||||
|
||||
[transact.png]: /images/transact.png
|
||||
[build.png]: /images/build.png
|
||||
[contribute.png]: /images/contribute.png
|
||||
|
||||
###Join The Ripple Community
|
||||
|![Transact][transact.png]|![Build][build.png]|![Contribute][contribute.png]|
|
||||
|:-----------------------:|:-----------------:|:---------------------------:|
|
||||
|[Transact on the fastest payment infrastructure][transact]|[Build Imaginative Apps][build]|Contribute to the Ripple Protocol Implementation|
|
||||
|
||||
#rippled - Ripple P2P server
|
||||
|
||||
##[](https://travis-ci.org/ripple/rippled)
|
||||
@@ -37,5 +111,9 @@ Ripple is open source and permissively licensed under the ISC license. See the
|
||||
LICENSE file for more details.
|
||||
|
||||
###For more information:
|
||||
* https://ripple.com
|
||||
* https://ripple.com/wiki
|
||||
* Ripple Wiki - https://ripple.com/wiki/
|
||||
* Ripple Primer - https://ripple.com/ripple_primer.pdf
|
||||
* Ripple Primer (Market Making) - https://ripple.com/ripple-mm.pdf
|
||||
* Ripple Gateway Primer - https://ripple.com/ripple-gateways.pdf
|
||||
* Consensus - https://wiki.ripple.com/Consensus
|
||||
|
||||
|
||||
1164
SConstruct
77
appveyor.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
# Set environment variables.
|
||||
environment:
|
||||
PYTHON: C:/Python27-x64
|
||||
|
||||
# We bundle up protoc.exe and only the parts of boost and openssl we need so
|
||||
# that it's a small download. We also use appveyor's free cache, avoiding fees
|
||||
# downloading from S3 each time.
|
||||
# TODO: script to create this package.
|
||||
RIPPLED_DEPS_URL: https://s3-ap-northeast-1.amazonaws.com/history-replay/rippled_deps.zip
|
||||
|
||||
# Other dependencies we just download each time.
|
||||
PIP_URL: https://bootstrap.pypa.io/get-pip.py
|
||||
PYWIN32_URL: https://downloads.sourceforge.net/project/pywin32/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe
|
||||
|
||||
# Scons honours these environment variables, setting the include/lib paths.
|
||||
BOOST_ROOT: C:/rippled_deps/boost
|
||||
OPENSSL_ROOT: C:/rippled_deps/openssl
|
||||
|
||||
# At the end of each successful build we cache this directory. It must be less
|
||||
# than 100MB total compressed.
|
||||
cache:
|
||||
- 'C:\\rippled_deps'
|
||||
|
||||
# This means we'll download a zip of the branch we want, rather than the full
|
||||
# history.
|
||||
shallow_clone: true
|
||||
|
||||
install:
|
||||
# We want easy_install, python and protoc.exe on PATH.
|
||||
- SET PATH=%PYTHON%;%PYTHON%/Scripts;C:/rippled_deps;%PATH%
|
||||
|
||||
# `ps` prefix means the command is executed by powershell.
|
||||
- ps: Start-FileDownload $env:PIP_URL
|
||||
- ps: Start-FileDownload $env:PYWIN32_URL
|
||||
|
||||
# Installing pip will install setuptools/easy_install.
|
||||
- python get-pip.py
|
||||
|
||||
# Pip has some problems installing scons on windows so we use easy install.
|
||||
- easy_install scons
|
||||
|
||||
# Scons has problems with parallel builds on windows without pywin32.
|
||||
- easy_install pywin32-219.win-amd64-py2.7.exe
|
||||
# (easy_install can do headless installs of .exe wizards)
|
||||
|
||||
# Download dependencies if appveyor didn't restore them from the cache.
|
||||
# Use 7zip to unzip.
|
||||
- ps: |
|
||||
if (-not(Test-Path 'C:/rippled_deps')) {
|
||||
Start-FileDownload "$env:RIPPLED_DEPS_URL"
|
||||
7z x rippled_deps.zip -oC:\ -y > $null
|
||||
}
|
||||
|
||||
# TODO: This is giving me grief
|
||||
# artifacts:
|
||||
# # Save rippled.exe in the cloud after each build.
|
||||
# - path: "build\\rippled.exe"
|
||||
|
||||
build_script:
|
||||
# We set the environment variables needed to put compilers on the PATH.
|
||||
- '"%VS120COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64'
|
||||
# Show which version of the compiler we are using.
|
||||
- cl
|
||||
- scons msvc.debug -j%NUMBER_OF_PROCESSORS%
|
||||
|
||||
after_build:
|
||||
# Put our executable in a place where npm test can find it.
|
||||
- ps: cp build/msvc.debug/rippled.exe build
|
||||
- ps: ls build
|
||||
|
||||
test_script:
|
||||
# Run the unit tests
|
||||
- build\\rippled --unittest
|
||||
|
||||
# Run the integration tests
|
||||
- npm install
|
||||
- npm test
|
||||
24
bin/LedgerTool.py
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from ripple.ledger import Server
|
||||
from ripple.ledger.commands import Cache, Info, Print
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Log
|
||||
from ripple.util.CommandList import CommandList
|
||||
|
||||
_COMMANDS = CommandList(Cache, Info, Print)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
server = Server.Server()
|
||||
args = list(ARGS.command)
|
||||
_COMMANDS.run_safe(args.pop(0), server, *args)
|
||||
except Exception as e:
|
||||
if ARGS.verbose:
|
||||
print(traceback.format_exc(), sys.stderr)
|
||||
Log.error(e)
|
||||
8
bin/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Unit Tests
|
||||
==========
|
||||
|
||||
To run the Python unit tests, execute:
|
||||
|
||||
python -m unittest discover
|
||||
|
||||
from this directory.
|
||||
251
bin/decorator.py
Normal file
@@ -0,0 +1,251 @@
|
||||
########################## LICENCE ###############################
|
||||
|
||||
# Copyright (c) 2005-2012, Michele Simionato
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# Redistributions in bytecode form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
# DAMAGE.
|
||||
|
||||
"""
|
||||
Decorator module, see http://pypi.python.org/pypi/decorator
|
||||
for the documentation.
|
||||
"""
|
||||
|
||||
__version__ = '3.4.0'
|
||||
|
||||
__all__ = ["decorator", "FunctionMaker", "contextmanager"]
|
||||
|
||||
import sys, re, inspect
|
||||
if sys.version >= '3':
|
||||
from inspect import getfullargspec
|
||||
def get_init(cls):
|
||||
return cls.__init__
|
||||
else:
|
||||
class getfullargspec(object):
|
||||
"A quick and dirty replacement for getfullargspec for Python 2.X"
|
||||
def __init__(self, f):
|
||||
self.args, self.varargs, self.varkw, self.defaults = \
|
||||
inspect.getargspec(f)
|
||||
self.kwonlyargs = []
|
||||
self.kwonlydefaults = None
|
||||
def __iter__(self):
|
||||
yield self.args
|
||||
yield self.varargs
|
||||
yield self.varkw
|
||||
yield self.defaults
|
||||
def get_init(cls):
|
||||
return cls.__init__.im_func
|
||||
|
||||
DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
|
||||
|
||||
# basic functionality
|
||||
class FunctionMaker(object):
|
||||
"""
|
||||
An object with the ability to create functions with a given signature.
|
||||
It has attributes name, doc, module, signature, defaults, dict and
|
||||
methods update and make.
|
||||
"""
|
||||
def __init__(self, func=None, name=None, signature=None,
|
||||
defaults=None, doc=None, module=None, funcdict=None):
|
||||
self.shortsignature = signature
|
||||
if func:
|
||||
# func can be a class or a callable, but not an instance method
|
||||
self.name = func.__name__
|
||||
if self.name == '<lambda>': # small hack for lambda functions
|
||||
self.name = '_lambda_'
|
||||
self.doc = func.__doc__
|
||||
self.module = func.__module__
|
||||
if inspect.isfunction(func):
|
||||
argspec = getfullargspec(func)
|
||||
self.annotations = getattr(func, '__annotations__', {})
|
||||
for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
|
||||
'kwonlydefaults'):
|
||||
setattr(self, a, getattr(argspec, a))
|
||||
for i, arg in enumerate(self.args):
|
||||
setattr(self, 'arg%d' % i, arg)
|
||||
if sys.version < '3': # easy way
|
||||
self.shortsignature = self.signature = \
|
||||
inspect.formatargspec(
|
||||
formatvalue=lambda val: "", *argspec)[1:-1]
|
||||
else: # Python 3 way
|
||||
allargs = list(self.args)
|
||||
allshortargs = list(self.args)
|
||||
if self.varargs:
|
||||
allargs.append('*' + self.varargs)
|
||||
allshortargs.append('*' + self.varargs)
|
||||
elif self.kwonlyargs:
|
||||
allargs.append('*') # single star syntax
|
||||
for a in self.kwonlyargs:
|
||||
allargs.append('%s=None' % a)
|
||||
allshortargs.append('%s=%s' % (a, a))
|
||||
if self.varkw:
|
||||
allargs.append('**' + self.varkw)
|
||||
allshortargs.append('**' + self.varkw)
|
||||
self.signature = ', '.join(allargs)
|
||||
self.shortsignature = ', '.join(allshortargs)
|
||||
self.dict = func.__dict__.copy()
|
||||
# func=None happens when decorating a caller
|
||||
if name:
|
||||
self.name = name
|
||||
if signature is not None:
|
||||
self.signature = signature
|
||||
if defaults:
|
||||
self.defaults = defaults
|
||||
if doc:
|
||||
self.doc = doc
|
||||
if module:
|
||||
self.module = module
|
||||
if funcdict:
|
||||
self.dict = funcdict
|
||||
# check existence required attributes
|
||||
assert hasattr(self, 'name')
|
||||
if not hasattr(self, 'signature'):
|
||||
raise TypeError('You are decorating a non function: %s' % func)
|
||||
|
||||
def update(self, func, **kw):
|
||||
"Update the signature of func with the data in self"
|
||||
func.__name__ = self.name
|
||||
func.__doc__ = getattr(self, 'doc', None)
|
||||
func.__dict__ = getattr(self, 'dict', {})
|
||||
func.func_defaults = getattr(self, 'defaults', ())
|
||||
func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
|
||||
func.__annotations__ = getattr(self, 'annotations', None)
|
||||
callermodule = sys._getframe(3).f_globals.get('__name__', '?')
|
||||
func.__module__ = getattr(self, 'module', callermodule)
|
||||
func.__dict__.update(kw)
|
||||
|
||||
def make(self, src_templ, evaldict=None, addsource=False, **attrs):
|
||||
"Make a new function from a given template and update the signature"
|
||||
src = src_templ % vars(self) # expand name and signature
|
||||
evaldict = evaldict or {}
|
||||
mo = DEF.match(src)
|
||||
if mo is None:
|
||||
raise SyntaxError('not a valid function template\n%s' % src)
|
||||
name = mo.group(1) # extract the function name
|
||||
names = set([name] + [arg.strip(' *') for arg in
|
||||
self.shortsignature.split(',')])
|
||||
for n in names:
|
||||
if n in ('_func_', '_call_'):
|
||||
raise NameError('%s is overridden in\n%s' % (n, src))
|
||||
if not src.endswith('\n'): # add a newline just for safety
|
||||
src += '\n' # this is needed in old versions of Python
|
||||
try:
|
||||
code = compile(src, '<string>', 'single')
|
||||
# print >> sys.stderr, 'Compiling %s' % src
|
||||
exec code in evaldict
|
||||
except:
|
||||
print >> sys.stderr, 'Error in generated code:'
|
||||
print >> sys.stderr, src
|
||||
raise
|
||||
func = evaldict[name]
|
||||
if addsource:
|
||||
attrs['__source__'] = src
|
||||
self.update(func, **attrs)
|
||||
return func
|
||||
|
||||
@classmethod
|
||||
def create(cls, obj, body, evaldict, defaults=None,
|
||||
doc=None, module=None, addsource=True, **attrs):
|
||||
"""
|
||||
Create a function from the strings name, signature and body.
|
||||
evaldict is the evaluation dictionary. If addsource is true an attribute
|
||||
__source__ is added to the result. The attributes attrs are added,
|
||||
if any.
|
||||
"""
|
||||
if isinstance(obj, str): # "name(signature)"
|
||||
name, rest = obj.strip().split('(', 1)
|
||||
signature = rest[:-1] #strip a right parens
|
||||
func = None
|
||||
else: # a function
|
||||
name = None
|
||||
signature = None
|
||||
func = obj
|
||||
self = cls(func, name, signature, defaults, doc, module)
|
||||
ibody = '\n'.join(' ' + line for line in body.splitlines())
|
||||
return self.make('def %(name)s(%(signature)s):\n' + ibody,
|
||||
evaldict, addsource, **attrs)
|
||||
|
||||
def decorator(caller, func=None):
|
||||
"""
|
||||
decorator(caller) converts a caller function into a decorator;
|
||||
decorator(caller, func) decorates a function using a caller.
|
||||
"""
|
||||
if func is not None: # returns a decorated function
|
||||
evaldict = func.func_globals.copy()
|
||||
evaldict['_call_'] = caller
|
||||
evaldict['_func_'] = func
|
||||
return FunctionMaker.create(
|
||||
func, "return _call_(_func_, %(shortsignature)s)",
|
||||
evaldict, undecorated=func, __wrapped__=func)
|
||||
else: # returns a decorator
|
||||
if inspect.isclass(caller):
|
||||
name = caller.__name__.lower()
|
||||
callerfunc = get_init(caller)
|
||||
doc = 'decorator(%s) converts functions/generators into ' \
|
||||
'factories of %s objects' % (caller.__name__, caller.__name__)
|
||||
fun = getfullargspec(callerfunc).args[1] # second arg
|
||||
elif inspect.isfunction(caller):
|
||||
name = '_lambda_' if caller.__name__ == '<lambda>' \
|
||||
else caller.__name__
|
||||
callerfunc = caller
|
||||
doc = caller.__doc__
|
||||
fun = getfullargspec(callerfunc).args[0] # first arg
|
||||
else: # assume caller is an object with a __call__ method
|
||||
name = caller.__class__.__name__.lower()
|
||||
callerfunc = caller.__call__.im_func
|
||||
doc = caller.__call__.__doc__
|
||||
fun = getfullargspec(callerfunc).args[1] # second arg
|
||||
evaldict = callerfunc.func_globals.copy()
|
||||
evaldict['_call_'] = caller
|
||||
evaldict['decorator'] = decorator
|
||||
return FunctionMaker.create(
|
||||
'%s(%s)' % (name, fun),
|
||||
'return decorator(_call_, %s)' % fun,
|
||||
evaldict, undecorated=caller, __wrapped__=caller,
|
||||
doc=doc, module=caller.__module__)
|
||||
|
||||
######################### contextmanager ########################
|
||||
|
||||
def __call__(self, func):
|
||||
'Context manager decorator'
|
||||
return FunctionMaker.create(
|
||||
func, "with _self_: return _func_(%(shortsignature)s)",
|
||||
dict(_self_=self, _func_=func), __wrapped__=func)
|
||||
|
||||
try: # Python >= 3.2
|
||||
|
||||
from contextlib import _GeneratorContextManager
|
||||
ContextManager = type(
|
||||
'ContextManager', (_GeneratorContextManager,), dict(__call__=__call__))
|
||||
|
||||
except ImportError: # Python >= 2.5
|
||||
|
||||
from contextlib import GeneratorContextManager
|
||||
def __init__(self, f, *a, **k):
|
||||
return GeneratorContextManager.__init__(self, f(*a, **k))
|
||||
ContextManager = type(
|
||||
'ContextManager', (GeneratorContextManager,),
|
||||
dict(__call__=__call__, __init__=__init__))
|
||||
|
||||
contextmanager = decorator(ContextManager)
|
||||
4
bin/jsonpath_rw/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .jsonpath import *
|
||||
from .parser import parse
|
||||
|
||||
__version__ = '1.3.0'
|
||||
510
bin/jsonpath_rw/jsonpath.py
Normal file
@@ -0,0 +1,510 @@
|
||||
from __future__ import unicode_literals, print_function, absolute_import, division, generators, nested_scopes
|
||||
import logging
|
||||
import six
|
||||
from six.moves import xrange
|
||||
from itertools import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Turn on/off the automatic creation of id attributes
|
||||
# ... could be a kwarg pervasively but uses are rare and simple today
|
||||
auto_id_field = None
|
||||
|
||||
class JSONPath(object):
|
||||
"""
|
||||
The base class for JSONPath abstract syntax; those
|
||||
methods stubbed here are the interface to supported
|
||||
JSONPath semantics.
|
||||
"""
|
||||
|
||||
def find(self, data):
|
||||
"""
|
||||
All `JSONPath` types support `find()`, which returns an iterable of `DatumInContext`s.
|
||||
They keep track of the path followed to the current location, so if the calling code
|
||||
has some opinion about that, it can be passed in here as a starting point.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def update(self, data, val):
|
||||
"Returns `data` with the specified path replaced by `val`"
|
||||
raise NotImplementedError()
|
||||
|
||||
def child(self, child):
|
||||
"""
|
||||
Equivalent to Child(self, next) but with some canonicalization
|
||||
"""
|
||||
if isinstance(self, This) or isinstance(self, Root):
|
||||
return child
|
||||
elif isinstance(child, This):
|
||||
return self
|
||||
elif isinstance(child, Root):
|
||||
return child
|
||||
else:
|
||||
return Child(self, child)
|
||||
|
||||
def make_datum(self, value):
|
||||
if isinstance(value, DatumInContext):
|
||||
return value
|
||||
else:
|
||||
return DatumInContext(value, path=Root(), context=None)
|
||||
|
||||
class DatumInContext(object):
|
||||
"""
|
||||
Represents a datum along a path from a context.
|
||||
|
||||
Essentially a zipper but with a structure represented by JsonPath,
|
||||
and where the context is more of a parent pointer than a proper
|
||||
representation of the context.
|
||||
|
||||
For quick-and-dirty work, this proxies any non-special attributes
|
||||
to the underlying datum, but the actual datum can (and usually should)
|
||||
be retrieved via the `value` attribute.
|
||||
|
||||
To place `datum` within another, use `datum.in_context(context=..., path=...)`
|
||||
which extends the path. If the datum already has a context, it places the entire
|
||||
context within that passed in, so an object can be built from the inside
|
||||
out.
|
||||
"""
|
||||
@classmethod
|
||||
def wrap(cls, data):
|
||||
if isinstance(data, cls):
|
||||
return data
|
||||
else:
|
||||
return cls(data)
|
||||
|
||||
def __init__(self, value, path=None, context=None):
|
||||
self.value = value
|
||||
self.path = path or This()
|
||||
self.context = None if context is None else DatumInContext.wrap(context)
|
||||
|
||||
def in_context(self, context, path):
|
||||
context = DatumInContext.wrap(context)
|
||||
|
||||
if self.context:
|
||||
return DatumInContext(value=self.value, path=self.path, context=context.in_context(path=path, context=context))
|
||||
else:
|
||||
return DatumInContext(value=self.value, path=path, context=context)
|
||||
|
||||
@property
|
||||
def full_path(self):
|
||||
return self.path if self.context is None else self.context.full_path.child(self.path)
|
||||
|
||||
@property
|
||||
def id_pseudopath(self):
|
||||
"""
|
||||
Looks like a path, but with ids stuck in when available
|
||||
"""
|
||||
try:
|
||||
pseudopath = Fields(str(self.value[auto_id_field]))
|
||||
except (TypeError, AttributeError, KeyError): # This may not be all the interesting exceptions
|
||||
pseudopath = self.path
|
||||
|
||||
if self.context:
|
||||
return self.context.id_pseudopath.child(pseudopath)
|
||||
else:
|
||||
return pseudopath
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(value=%r, path=%r, context=%r)' % (self.__class__.__name__, self.value, self.path, self.context)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, DatumInContext) and other.value == self.value and other.path == self.path and self.context == other.context
|
||||
|
||||
class AutoIdForDatum(DatumInContext):
|
||||
"""
|
||||
This behaves like a DatumInContext, but the value is
|
||||
always the path leading up to it, not including the "id",
|
||||
and with any "id" fields along the way replacing the prior
|
||||
segment of the path
|
||||
|
||||
For example, it will make "foo.bar.id" return a datum
|
||||
that behaves like DatumInContext(value="foo.bar", path="foo.bar.id").
|
||||
|
||||
This is disabled by default; it can be turned on by
|
||||
settings the `auto_id_field` global to a value other
|
||||
than `None`.
|
||||
"""
|
||||
|
||||
def __init__(self, datum, id_field=None):
|
||||
"""
|
||||
Invariant is that datum.path is the path from context to datum. The auto id
|
||||
will either be the id in the datum (if present) or the id of the context
|
||||
followed by the path to the datum.
|
||||
|
||||
The path to this datum is always the path to the context, the path to the
|
||||
datum, and then the auto id field.
|
||||
"""
|
||||
self.datum = datum
|
||||
self.id_field = id_field or auto_id_field
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return str(self.datum.id_pseudopath)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self.id_field
|
||||
|
||||
@property
|
||||
def context(self):
|
||||
return self.datum
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (self.__class__.__name__, self.datum)
|
||||
|
||||
def in_context(self, context, path):
|
||||
return AutoIdForDatum(self.datum.in_context(context=context, path=path))
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, AutoIdForDatum) and other.datum == self.datum and self.id_field == other.id_field
|
||||
|
||||
|
||||
class Root(JSONPath):
|
||||
"""
|
||||
The JSONPath referring to the "root" object. Concrete syntax is '$'.
|
||||
The root is the topmost datum without any context attached.
|
||||
"""
|
||||
|
||||
def find(self, data):
|
||||
if not isinstance(data, DatumInContext):
|
||||
return [DatumInContext(data, path=Root(), context=None)]
|
||||
else:
|
||||
if data.context is None:
|
||||
return [DatumInContext(data.value, context=None, path=Root())]
|
||||
else:
|
||||
return Root().find(data.context)
|
||||
|
||||
def update(self, data, val):
|
||||
return val
|
||||
|
||||
def __str__(self):
|
||||
return '$'
|
||||
|
||||
def __repr__(self):
|
||||
return 'Root()'
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Root)
|
||||
|
||||
class This(JSONPath):
|
||||
"""
|
||||
The JSONPath referring to the current datum. Concrete syntax is '@'.
|
||||
"""
|
||||
|
||||
def find(self, datum):
|
||||
return [DatumInContext.wrap(datum)]
|
||||
|
||||
def update(self, data, val):
|
||||
return val
|
||||
|
||||
def __str__(self):
|
||||
return '`this`'
|
||||
|
||||
def __repr__(self):
|
||||
return 'This()'
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, This)
|
||||
|
||||
class Child(JSONPath):
|
||||
"""
|
||||
JSONPath that first matches the left, then the right.
|
||||
Concrete syntax is <left> '.' <right>
|
||||
"""
|
||||
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def find(self, datum):
|
||||
"""
|
||||
Extra special case: auto ids do not have children,
|
||||
so cut it off right now rather than auto id the auto id
|
||||
"""
|
||||
|
||||
return [submatch
|
||||
for subdata in self.left.find(datum)
|
||||
if not isinstance(subdata, AutoIdForDatum)
|
||||
for submatch in self.right.find(subdata)]
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Child) and self.left == other.left and self.right == other.right
|
||||
|
||||
def __str__(self):
|
||||
return '%s.%s' % (self.left, self.right)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r)' % (self.__class__.__name__, self.left, self.right)
|
||||
|
||||
class Parent(JSONPath):
|
||||
"""
|
||||
JSONPath that matches the parent node of the current match.
|
||||
Will crash if no such parent exists.
|
||||
Available via named operator `parent`.
|
||||
"""
|
||||
|
||||
def find(self, datum):
|
||||
datum = DatumInContext.wrap(datum)
|
||||
return [datum.context]
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Parent)
|
||||
|
||||
def __str__(self):
|
||||
return '`parent`'
|
||||
|
||||
def __repr__(self):
|
||||
return 'Parent()'
|
||||
|
||||
|
||||
class Where(JSONPath):
|
||||
"""
|
||||
JSONPath that first matches the left, and then
|
||||
filters for only those nodes that have
|
||||
a match on the right.
|
||||
|
||||
WARNING: Subject to change. May want to have "contains"
|
||||
or some other better word for it.
|
||||
"""
|
||||
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def find(self, data):
|
||||
return [subdata for subdata in self.left.find(data) if self.right.find(data)]
|
||||
|
||||
def __str__(self):
|
||||
return '%s where %s' % (self.left, self.right)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Where) and other.left == self.left and other.right == self.right
|
||||
|
||||
class Descendants(JSONPath):
|
||||
"""
|
||||
JSONPath that matches first the left expression then any descendant
|
||||
of it which matches the right expression.
|
||||
"""
|
||||
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def find(self, datum):
|
||||
# <left> .. <right> ==> <left> . (<right> | *..<right> | [*]..<right>)
|
||||
#
|
||||
# With with a wonky caveat that since Slice() has funky coercions
|
||||
# we cannot just delegate to that equivalence or we'll hit an
|
||||
# infinite loop. So right here we implement the coercion-free version.
|
||||
|
||||
# Get all left matches into a list
|
||||
left_matches = self.left.find(datum)
|
||||
if not isinstance(left_matches, list):
|
||||
left_matches = [left_matches]
|
||||
|
||||
def match_recursively(datum):
|
||||
right_matches = self.right.find(datum)
|
||||
|
||||
# Manually do the * or [*] to avoid coercion and recurse just the right-hand pattern
|
||||
if isinstance(datum.value, list):
|
||||
recursive_matches = [submatch
|
||||
for i in range(0, len(datum.value))
|
||||
for submatch in match_recursively(DatumInContext(datum.value[i], context=datum, path=Index(i)))]
|
||||
|
||||
elif isinstance(datum.value, dict):
|
||||
recursive_matches = [submatch
|
||||
for field in datum.value.keys()
|
||||
for submatch in match_recursively(DatumInContext(datum.value[field], context=datum, path=Fields(field)))]
|
||||
|
||||
else:
|
||||
recursive_matches = []
|
||||
|
||||
return right_matches + list(recursive_matches)
|
||||
|
||||
# TODO: repeatable iterator instead of list?
|
||||
return [submatch
|
||||
for left_match in left_matches
|
||||
for submatch in match_recursively(left_match)]
|
||||
|
||||
def is_singular():
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return '%s..%s' % (self.left, self.right)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Descendants) and self.left == other.left and self.right == other.right
|
||||
|
||||
class Union(JSONPath):
|
||||
"""
|
||||
JSONPath that returns the union of the results of each match.
|
||||
This is pretty shoddily implemented for now. The nicest semantics
|
||||
in case of mismatched bits (list vs atomic) is to put
|
||||
them all in a list, but I haven't done that yet.
|
||||
|
||||
WARNING: Any appearance of this being the _concatenation_ is
|
||||
coincidence. It may even be a bug! (or laziness)
|
||||
"""
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def is_singular(self):
|
||||
return False
|
||||
|
||||
def find(self, data):
|
||||
return self.left.find(data) + self.right.find(data)
|
||||
|
||||
class Intersect(JSONPath):
|
||||
"""
|
||||
JSONPath for bits that match *both* patterns.
|
||||
|
||||
This can be accomplished a couple of ways. The most
|
||||
efficient is to actually build the intersected
|
||||
AST as in building a state machine for matching the
|
||||
intersection of regular languages. The next
|
||||
idea is to build a filtered data and match against
|
||||
that.
|
||||
"""
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def is_singular(self):
|
||||
return False
|
||||
|
||||
def find(self, data):
|
||||
raise NotImplementedError()
|
||||
|
||||
class Fields(JSONPath):
|
||||
"""
|
||||
JSONPath referring to some field of the current object.
|
||||
Concrete syntax ix comma-separated field names.
|
||||
|
||||
WARNING: If '*' is any of the field names, then they will
|
||||
all be returned.
|
||||
"""
|
||||
|
||||
def __init__(self, *fields):
|
||||
self.fields = fields
|
||||
|
||||
def get_field_datum(self, datum, field):
|
||||
if field == auto_id_field:
|
||||
return AutoIdForDatum(datum)
|
||||
else:
|
||||
try:
|
||||
field_value = datum.value[field] # Do NOT use `val.get(field)` since that confuses None as a value and None due to `get`
|
||||
return DatumInContext(value=field_value, path=Fields(field), context=datum)
|
||||
except (TypeError, KeyError, AttributeError):
|
||||
return None
|
||||
|
||||
def reified_fields(self, datum):
|
||||
if '*' not in self.fields:
|
||||
return self.fields
|
||||
else:
|
||||
try:
|
||||
fields = tuple(datum.value.keys())
|
||||
return fields if auto_id_field is None else fields + (auto_id_field,)
|
||||
except AttributeError:
|
||||
return ()
|
||||
|
||||
def find(self, datum):
|
||||
datum = DatumInContext.wrap(datum)
|
||||
|
||||
return [field_datum
|
||||
for field_datum in [self.get_field_datum(datum, field) for field in self.reified_fields(datum)]
|
||||
if field_datum is not None]
|
||||
|
||||
def __str__(self):
|
||||
return ','.join(self.fields)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (self.__class__.__name__, ','.join(map(repr, self.fields)))
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Fields) and tuple(self.fields) == tuple(other.fields)
|
||||
|
||||
|
||||
class Index(JSONPath):
|
||||
"""
|
||||
JSONPath that matches indices of the current datum, or none if not large enough.
|
||||
Concrete syntax is brackets.
|
||||
|
||||
WARNING: If the datum is not long enough, it will not crash but will not match anything.
|
||||
NOTE: For the concrete syntax of `[*]`, the abstract syntax is a Slice() with no parameters (equiv to `[:]`
|
||||
"""
|
||||
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
|
||||
def find(self, datum):
|
||||
datum = DatumInContext.wrap(datum)
|
||||
|
||||
if len(datum.value) > self.index:
|
||||
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
|
||||
else:
|
||||
return []
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Index) and self.index == other.index
|
||||
|
||||
def __str__(self):
|
||||
return '[%i]' % self.index
|
||||
|
||||
class Slice(JSONPath):
|
||||
"""
|
||||
JSONPath matching a slice of an array.
|
||||
|
||||
Because of a mismatch between JSON and XML when schema-unaware,
|
||||
this always returns an iterable; if the incoming data
|
||||
was not a list, then it returns a one element list _containing_ that
|
||||
data.
|
||||
|
||||
Consider these two docs, and their schema-unaware translation to JSON:
|
||||
|
||||
<a><b>hello</b></a> ==> {"a": {"b": "hello"}}
|
||||
<a><b>hello</b><b>goodbye</b></a> ==> {"a": {"b": ["hello", "goodbye"]}}
|
||||
|
||||
If there were a schema, it would be known that "b" should always be an
|
||||
array (unless the schema were wonky, but that is too much to fix here)
|
||||
so when querying with JSON if the one writing the JSON knows that it
|
||||
should be an array, they can write a slice operator and it will coerce
|
||||
a non-array value to an array.
|
||||
|
||||
This may be a bit unfortunate because it would be nice to always have
|
||||
an iterator, but dictionaries and other objects may also be iterable,
|
||||
so this is the compromise.
|
||||
"""
|
||||
def __init__(self, start=None, end=None, step=None):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.step = step
|
||||
|
||||
def find(self, datum):
|
||||
datum = DatumInContext.wrap(datum)
|
||||
|
||||
# Here's the hack. If it is a dictionary or some kind of constant,
|
||||
# put it in a single-element list
|
||||
if (isinstance(datum.value, dict) or isinstance(datum.value, six.integer_types) or isinstance(datum.value, six.string_types)):
|
||||
return self.find(DatumInContext([datum.value], path=datum.path, context=datum.context))
|
||||
|
||||
# Some iterators do not support slicing but we can still
|
||||
# at least work for '*'
|
||||
if self.start == None and self.end == None and self.step == None:
|
||||
return [DatumInContext(datum.value[i], path=Index(i), context=datum) for i in xrange(0, len(datum.value))]
|
||||
else:
|
||||
return [DatumInContext(datum.value[i], path=Index(i), context=datum) for i in range(0, len(datum.value))[self.start:self.end:self.step]]
|
||||
|
||||
def __str__(self):
|
||||
if self.start == None and self.end == None and self.step == None:
|
||||
return '[*]'
|
||||
else:
|
||||
return '[%s%s%s]' % (self.start or '',
|
||||
':%d'%self.end if self.end else '',
|
||||
':%d'%self.step if self.step else '')
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(start=%r,end=%r,step=%r)' % (self.__class__.__name__, self.start, self.end, self.step)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Slice) and other.start == self.start and self.end == other.end and other.step == self.step
|
||||
171
bin/jsonpath_rw/lexer.py
Normal file
@@ -0,0 +1,171 @@
|
||||
from __future__ import unicode_literals, print_function, absolute_import, division, generators, nested_scopes
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import ply.lex
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class JsonPathLexerError(Exception):
|
||||
pass
|
||||
|
||||
class JsonPathLexer(object):
|
||||
'''
|
||||
A Lexical analyzer for JsonPath.
|
||||
'''
|
||||
|
||||
def __init__(self, debug=False):
|
||||
self.debug = debug
|
||||
if self.__doc__ == None:
|
||||
raise JsonPathLexerError('Docstrings have been removed! By design of PLY, jsonpath-rw requires docstrings. You must not use PYTHONOPTIMIZE=2 or python -OO.')
|
||||
|
||||
def tokenize(self, string):
|
||||
'''
|
||||
Maps a string to an iterator over tokens. In other words: [char] -> [token]
|
||||
'''
|
||||
|
||||
new_lexer = ply.lex.lex(module=self, debug=self.debug, errorlog=logger)
|
||||
new_lexer.latest_newline = 0
|
||||
new_lexer.string_value = None
|
||||
new_lexer.input(string)
|
||||
|
||||
while True:
|
||||
t = new_lexer.token()
|
||||
if t is None: break
|
||||
t.col = t.lexpos - new_lexer.latest_newline
|
||||
yield t
|
||||
|
||||
if new_lexer.string_value is not None:
|
||||
raise JsonPathLexerError('Unexpected EOF in string literal or identifier')
|
||||
|
||||
# ============== PLY Lexer specification ==================
|
||||
#
|
||||
# This probably should be private but:
|
||||
# - the parser requires access to `tokens` (perhaps they should be defined in a third, shared dependency)
|
||||
# - things like `literals` might be a legitimate part of the public interface.
|
||||
#
|
||||
# Anyhow, it is pythonic to give some rope to hang oneself with :-)
|
||||
|
||||
literals = ['*', '.', '[', ']', '(', ')', '$', ',', ':', '|', '&']
|
||||
|
||||
reserved_words = { 'where': 'WHERE' }
|
||||
|
||||
tokens = ['DOUBLEDOT', 'NUMBER', 'ID', 'NAMED_OPERATOR'] + list(reserved_words.values())
|
||||
|
||||
states = [ ('singlequote', 'exclusive'),
|
||||
('doublequote', 'exclusive'),
|
||||
('backquote', 'exclusive') ]
|
||||
|
||||
# Normal lexing, rather easy
|
||||
t_DOUBLEDOT = r'\.\.'
|
||||
t_ignore = ' \t'
|
||||
|
||||
def t_ID(self, t):
|
||||
r'[a-zA-Z_@][a-zA-Z0-9_@\-]*'
|
||||
t.type = self.reserved_words.get(t.value, 'ID')
|
||||
return t
|
||||
|
||||
def t_NUMBER(self, t):
|
||||
r'-?\d+'
|
||||
t.value = int(t.value)
|
||||
return t
|
||||
|
||||
|
||||
# Single-quoted strings
|
||||
t_singlequote_ignore = ''
|
||||
def t_singlequote(self, t):
|
||||
r"'"
|
||||
t.lexer.string_start = t.lexer.lexpos
|
||||
t.lexer.string_value = ''
|
||||
t.lexer.push_state('singlequote')
|
||||
|
||||
def t_singlequote_content(self, t):
|
||||
r"[^'\\]+"
|
||||
t.lexer.string_value += t.value
|
||||
|
||||
def t_singlequote_escape(self, t):
|
||||
r'\\.'
|
||||
t.lexer.string_value += t.value[1]
|
||||
|
||||
def t_singlequote_end(self, t):
|
||||
r"'"
|
||||
t.value = t.lexer.string_value
|
||||
t.type = 'ID'
|
||||
t.lexer.string_value = None
|
||||
t.lexer.pop_state()
|
||||
return t
|
||||
|
||||
def t_singlequote_error(self, t):
|
||||
raise JsonPathLexerError('Error on line %s, col %s while lexing singlequoted field: Unexpected character: %s ' % (t.lexer.lineno, t.lexpos - t.lexer.latest_newline, t.value[0]))
|
||||
|
||||
|
||||
# Double-quoted strings
|
||||
t_doublequote_ignore = ''
|
||||
def t_doublequote(self, t):
|
||||
r'"'
|
||||
t.lexer.string_start = t.lexer.lexpos
|
||||
t.lexer.string_value = ''
|
||||
t.lexer.push_state('doublequote')
|
||||
|
||||
def t_doublequote_content(self, t):
|
||||
r'[^"\\]+'
|
||||
t.lexer.string_value += t.value
|
||||
|
||||
def t_doublequote_escape(self, t):
|
||||
r'\\.'
|
||||
t.lexer.string_value += t.value[1]
|
||||
|
||||
def t_doublequote_end(self, t):
|
||||
r'"'
|
||||
t.value = t.lexer.string_value
|
||||
t.type = 'ID'
|
||||
t.lexer.string_value = None
|
||||
t.lexer.pop_state()
|
||||
return t
|
||||
|
||||
def t_doublequote_error(self, t):
|
||||
raise JsonPathLexerError('Error on line %s, col %s while lexing doublequoted field: Unexpected character: %s ' % (t.lexer.lineno, t.lexpos - t.lexer.latest_newline, t.value[0]))
|
||||
|
||||
|
||||
# Back-quoted "magic" operators
|
||||
t_backquote_ignore = ''
|
||||
def t_backquote(self, t):
|
||||
r'`'
|
||||
t.lexer.string_start = t.lexer.lexpos
|
||||
t.lexer.string_value = ''
|
||||
t.lexer.push_state('backquote')
|
||||
|
||||
def t_backquote_escape(self, t):
|
||||
r'\\.'
|
||||
t.lexer.string_value += t.value[1]
|
||||
|
||||
def t_backquote_content(self, t):
|
||||
r"[^`\\]+"
|
||||
t.lexer.string_value += t.value
|
||||
|
||||
def t_backquote_end(self, t):
|
||||
r'`'
|
||||
t.value = t.lexer.string_value
|
||||
t.type = 'NAMED_OPERATOR'
|
||||
t.lexer.string_value = None
|
||||
t.lexer.pop_state()
|
||||
return t
|
||||
|
||||
def t_backquote_error(self, t):
|
||||
raise JsonPathLexerError('Error on line %s, col %s while lexing backquoted operator: Unexpected character: %s ' % (t.lexer.lineno, t.lexpos - t.lexer.latest_newline, t.value[0]))
|
||||
|
||||
|
||||
# Counting lines, handling errors
|
||||
def t_newline(self, t):
|
||||
r'\n'
|
||||
t.lexer.lineno += 1
|
||||
t.lexer.latest_newline = t.lexpos
|
||||
|
||||
def t_error(self, t):
|
||||
raise JsonPathLexerError('Error on line %s, col %s: Unexpected character: %s ' % (t.lexer.lineno, t.lexpos - t.lexer.latest_newline, t.value[0]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
lexer = JsonPathLexer(debug=True)
|
||||
for token in lexer.tokenize(sys.stdin.read()):
|
||||
print('%-20s%s' % (token.value, token.type))
|
||||
187
bin/jsonpath_rw/parser.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from __future__ import print_function, absolute_import, division, generators, nested_scopes
|
||||
import sys
|
||||
import os.path
|
||||
import logging
|
||||
|
||||
import ply.yacc
|
||||
|
||||
from jsonpath_rw.jsonpath import *
|
||||
from jsonpath_rw.lexer import JsonPathLexer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def parse(string):
|
||||
return JsonPathParser().parse(string)
|
||||
|
||||
class JsonPathParser(object):
|
||||
'''
|
||||
An LALR-parser for JsonPath
|
||||
'''
|
||||
|
||||
tokens = JsonPathLexer.tokens
|
||||
|
||||
def __init__(self, debug=False, lexer_class=None):
|
||||
if self.__doc__ == None:
|
||||
raise Exception('Docstrings have been removed! By design of PLY, jsonpath-rw requires docstrings. You must not use PYTHONOPTIMIZE=2 or python -OO.')
|
||||
|
||||
self.debug = debug
|
||||
self.lexer_class = lexer_class or JsonPathLexer # Crufty but works around statefulness in PLY
|
||||
|
||||
def parse(self, string, lexer = None):
|
||||
lexer = lexer or self.lexer_class()
|
||||
return self.parse_token_stream(lexer.tokenize(string))
|
||||
|
||||
def parse_token_stream(self, token_iterator, start_symbol='jsonpath'):
|
||||
|
||||
# Since PLY has some crufty aspects and dumps files, we try to keep them local
|
||||
# However, we need to derive the name of the output Python file :-/
|
||||
output_directory = os.path.dirname(__file__)
|
||||
try:
|
||||
module_name = os.path.splitext(os.path.split(__file__)[1])[0]
|
||||
except:
|
||||
module_name = __name__
|
||||
|
||||
parsing_table_module = '_'.join([module_name, start_symbol, 'parsetab'])
|
||||
|
||||
# And we regenerate the parse table every time; it doesn't actually take that long!
|
||||
new_parser = ply.yacc.yacc(module=self,
|
||||
debug=self.debug,
|
||||
tabmodule = parsing_table_module,
|
||||
outputdir = output_directory,
|
||||
write_tables=0,
|
||||
start = start_symbol,
|
||||
errorlog = logger)
|
||||
|
||||
return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
|
||||
|
||||
# ===================== PLY Parser specification =====================
|
||||
|
||||
precedence = [
|
||||
('left', ','),
|
||||
('left', 'DOUBLEDOT'),
|
||||
('left', '.'),
|
||||
('left', '|'),
|
||||
('left', '&'),
|
||||
('left', 'WHERE'),
|
||||
]
|
||||
|
||||
def p_error(self, t):
|
||||
raise Exception('Parse error at %s:%s near token %s (%s)' % (t.lineno, t.col, t.value, t.type))
|
||||
|
||||
def p_jsonpath_binop(self, p):
|
||||
"""jsonpath : jsonpath '.' jsonpath
|
||||
| jsonpath DOUBLEDOT jsonpath
|
||||
| jsonpath WHERE jsonpath
|
||||
| jsonpath '|' jsonpath
|
||||
| jsonpath '&' jsonpath"""
|
||||
op = p[2]
|
||||
|
||||
if op == '.':
|
||||
p[0] = Child(p[1], p[3])
|
||||
elif op == '..':
|
||||
p[0] = Descendants(p[1], p[3])
|
||||
elif op == 'where':
|
||||
p[0] = Where(p[1], p[3])
|
||||
elif op == '|':
|
||||
p[0] = Union(p[1], p[3])
|
||||
elif op == '&':
|
||||
p[0] = Intersect(p[1], p[3])
|
||||
|
||||
def p_jsonpath_fields(self, p):
|
||||
"jsonpath : fields_or_any"
|
||||
p[0] = Fields(*p[1])
|
||||
|
||||
def p_jsonpath_named_operator(self, p):
|
||||
"jsonpath : NAMED_OPERATOR"
|
||||
if p[1] == 'this':
|
||||
p[0] = This()
|
||||
elif p[1] == 'parent':
|
||||
p[0] = Parent()
|
||||
else:
|
||||
raise Exception('Unknown named operator `%s` at %s:%s' % (p[1], p.lineno(1), p.lexpos(1)))
|
||||
|
||||
def p_jsonpath_root(self, p):
|
||||
"jsonpath : '$'"
|
||||
p[0] = Root()
|
||||
|
||||
def p_jsonpath_idx(self, p):
|
||||
"jsonpath : '[' idx ']'"
|
||||
p[0] = p[2]
|
||||
|
||||
def p_jsonpath_slice(self, p):
|
||||
"jsonpath : '[' slice ']'"
|
||||
p[0] = p[2]
|
||||
|
||||
def p_jsonpath_fieldbrackets(self, p):
|
||||
"jsonpath : '[' fields ']'"
|
||||
p[0] = Fields(*p[2])
|
||||
|
||||
def p_jsonpath_child_fieldbrackets(self, p):
|
||||
"jsonpath : jsonpath '[' fields ']'"
|
||||
p[0] = Child(p[1], Fields(*p[3]))
|
||||
|
||||
def p_jsonpath_child_idxbrackets(self, p):
|
||||
"jsonpath : jsonpath '[' idx ']'"
|
||||
p[0] = Child(p[1], p[3])
|
||||
|
||||
def p_jsonpath_child_slicebrackets(self, p):
|
||||
"jsonpath : jsonpath '[' slice ']'"
|
||||
p[0] = Child(p[1], p[3])
|
||||
|
||||
def p_jsonpath_parens(self, p):
|
||||
"jsonpath : '(' jsonpath ')'"
|
||||
p[0] = p[2]
|
||||
|
||||
# Because fields in brackets cannot be '*' - that is reserved for array indices
|
||||
def p_fields_or_any(self, p):
|
||||
"""fields_or_any : fields
|
||||
| '*' """
|
||||
if p[1] == '*':
|
||||
p[0] = ['*']
|
||||
else:
|
||||
p[0] = p[1]
|
||||
|
||||
def p_fields_id(self, p):
|
||||
"fields : ID"
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_fields_comma(self, p):
|
||||
"fields : fields ',' fields"
|
||||
p[0] = p[1] + p[3]
|
||||
|
||||
def p_idx(self, p):
|
||||
"idx : NUMBER"
|
||||
p[0] = Index(p[1])
|
||||
|
||||
def p_slice_any(self, p):
|
||||
"slice : '*'"
|
||||
p[0] = Slice()
|
||||
|
||||
def p_slice(self, p): # Currently does not support `step`
|
||||
"slice : maybe_int ':' maybe_int"
|
||||
p[0] = Slice(start=p[1], end=p[3])
|
||||
|
||||
def p_maybe_int(self, p):
|
||||
"""maybe_int : NUMBER
|
||||
| empty"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_empty(self, p):
|
||||
'empty :'
|
||||
p[0] = None
|
||||
|
||||
class IteratorToTokenStream(object):
|
||||
def __init__(self, iterator):
|
||||
self.iterator = iterator
|
||||
|
||||
def token(self):
|
||||
try:
|
||||
return next(self.iterator)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
parser = JsonPathParser(debug=True)
|
||||
print(parser.parse(sys.stdin.read()))
|
||||
4
bin/ply/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# PLY package
|
||||
# Author: David Beazley (dave@dabeaz.com)
|
||||
|
||||
__all__ = ['lex','yacc']
|
||||
898
bin/ply/cpp.py
Normal file
@@ -0,0 +1,898 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# cpp.py
|
||||
#
|
||||
# Author: David Beazley (http://www.dabeaz.com)
|
||||
# Copyright (C) 2007
|
||||
# All rights reserved
|
||||
#
|
||||
# This module implements an ANSI-C style lexical preprocessor for PLY.
|
||||
# -----------------------------------------------------------------------------
|
||||
from __future__ import generators
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Default preprocessor lexer definitions. These tokens are enough to get
|
||||
# a basic preprocessor working. Other modules may import these if they want
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
tokens = (
|
||||
'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT', 'CPP_POUND','CPP_DPOUND'
|
||||
)
|
||||
|
||||
literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\""
|
||||
|
||||
# Whitespace
|
||||
def t_CPP_WS(t):
|
||||
r'\s+'
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
return t
|
||||
|
||||
t_CPP_POUND = r'\#'
|
||||
t_CPP_DPOUND = r'\#\#'
|
||||
|
||||
# Identifier
|
||||
t_CPP_ID = r'[A-Za-z_][\w_]*'
|
||||
|
||||
# Integer literal
|
||||
def CPP_INTEGER(t):
|
||||
r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU]|[lL]|[uU][lL]|[lL][uU])?)'
|
||||
return t
|
||||
|
||||
t_CPP_INTEGER = CPP_INTEGER
|
||||
|
||||
# Floating literal
|
||||
t_CPP_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
|
||||
|
||||
# String literal
|
||||
def t_CPP_STRING(t):
|
||||
r'\"([^\\\n]|(\\(.|\n)))*?\"'
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
return t
|
||||
|
||||
# Character constant 'c' or L'c'
|
||||
def t_CPP_CHAR(t):
|
||||
r'(L)?\'([^\\\n]|(\\(.|\n)))*?\''
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
return t
|
||||
|
||||
# Comment
|
||||
def t_CPP_COMMENT(t):
|
||||
r'(/\*(.|\n)*?\*/)|(//.*?\n)'
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
return t
|
||||
|
||||
def t_error(t):
|
||||
t.type = t.value[0]
|
||||
t.value = t.value[0]
|
||||
t.lexer.skip(1)
|
||||
return t
|
||||
|
||||
import re
|
||||
import copy
|
||||
import time
|
||||
import os.path
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# trigraph()
|
||||
#
|
||||
# Given an input string, this function replaces all trigraph sequences.
|
||||
# The following mapping is used:
|
||||
#
|
||||
# ??= #
|
||||
# ??/ \
|
||||
# ??' ^
|
||||
# ??( [
|
||||
# ??) ]
|
||||
# ??! |
|
||||
# ??< {
|
||||
# ??> }
|
||||
# ??- ~
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
_trigraph_pat = re.compile(r'''\?\?[=/\'\(\)\!<>\-]''')
|
||||
_trigraph_rep = {
|
||||
'=':'#',
|
||||
'/':'\\',
|
||||
"'":'^',
|
||||
'(':'[',
|
||||
')':']',
|
||||
'!':'|',
|
||||
'<':'{',
|
||||
'>':'}',
|
||||
'-':'~'
|
||||
}
|
||||
|
||||
def trigraph(input):
|
||||
return _trigraph_pat.sub(lambda g: _trigraph_rep[g.group()[-1]],input)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Macro object
|
||||
#
|
||||
# This object holds information about preprocessor macros
|
||||
#
|
||||
# .name - Macro name (string)
|
||||
# .value - Macro value (a list of tokens)
|
||||
# .arglist - List of argument names
|
||||
# .variadic - Boolean indicating whether or not variadic macro
|
||||
# .vararg - Name of the variadic parameter
|
||||
#
|
||||
# When a macro is created, the macro replacement token sequence is
|
||||
# pre-scanned and used to create patch lists that are later used
|
||||
# during macro expansion
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
class Macro(object):
|
||||
def __init__(self,name,value,arglist=None,variadic=False):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.arglist = arglist
|
||||
self.variadic = variadic
|
||||
if variadic:
|
||||
self.vararg = arglist[-1]
|
||||
self.source = None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Preprocessor object
|
||||
#
|
||||
# Object representing a preprocessor. Contains macro definitions,
|
||||
# include directories, and other information
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
class Preprocessor(object):
|
||||
def __init__(self,lexer=None):
|
||||
if lexer is None:
|
||||
lexer = lex.lexer
|
||||
self.lexer = lexer
|
||||
self.macros = { }
|
||||
self.path = []
|
||||
self.temp_path = []
|
||||
|
||||
# Probe the lexer for selected tokens
|
||||
self.lexprobe()
|
||||
|
||||
tm = time.localtime()
|
||||
self.define("__DATE__ \"%s\"" % time.strftime("%b %d %Y",tm))
|
||||
self.define("__TIME__ \"%s\"" % time.strftime("%H:%M:%S",tm))
|
||||
self.parser = None
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# tokenize()
|
||||
#
|
||||
# Utility function. Given a string of text, tokenize into a list of tokens
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def tokenize(self,text):
|
||||
tokens = []
|
||||
self.lexer.input(text)
|
||||
while True:
|
||||
tok = self.lexer.token()
|
||||
if not tok: break
|
||||
tokens.append(tok)
|
||||
return tokens
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# error()
|
||||
#
|
||||
# Report a preprocessor error/warning of some kind
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def error(self,file,line,msg):
|
||||
print("%s:%d %s" % (file,line,msg))
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# lexprobe()
|
||||
#
|
||||
# This method probes the preprocessor lexer object to discover
|
||||
# the token types of symbols that are important to the preprocessor.
|
||||
# If this works right, the preprocessor will simply "work"
|
||||
# with any suitable lexer regardless of how tokens have been named.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def lexprobe(self):
|
||||
|
||||
# Determine the token type for identifiers
|
||||
self.lexer.input("identifier")
|
||||
tok = self.lexer.token()
|
||||
if not tok or tok.value != "identifier":
|
||||
print("Couldn't determine identifier type")
|
||||
else:
|
||||
self.t_ID = tok.type
|
||||
|
||||
# Determine the token type for integers
|
||||
self.lexer.input("12345")
|
||||
tok = self.lexer.token()
|
||||
if not tok or int(tok.value) != 12345:
|
||||
print("Couldn't determine integer type")
|
||||
else:
|
||||
self.t_INTEGER = tok.type
|
||||
self.t_INTEGER_TYPE = type(tok.value)
|
||||
|
||||
# Determine the token type for strings enclosed in double quotes
|
||||
self.lexer.input("\"filename\"")
|
||||
tok = self.lexer.token()
|
||||
if not tok or tok.value != "\"filename\"":
|
||||
print("Couldn't determine string type")
|
||||
else:
|
||||
self.t_STRING = tok.type
|
||||
|
||||
# Determine the token type for whitespace--if any
|
||||
self.lexer.input(" ")
|
||||
tok = self.lexer.token()
|
||||
if not tok or tok.value != " ":
|
||||
self.t_SPACE = None
|
||||
else:
|
||||
self.t_SPACE = tok.type
|
||||
|
||||
# Determine the token type for newlines
|
||||
self.lexer.input("\n")
|
||||
tok = self.lexer.token()
|
||||
if not tok or tok.value != "\n":
|
||||
self.t_NEWLINE = None
|
||||
print("Couldn't determine token for newlines")
|
||||
else:
|
||||
self.t_NEWLINE = tok.type
|
||||
|
||||
self.t_WS = (self.t_SPACE, self.t_NEWLINE)
|
||||
|
||||
# Check for other characters used by the preprocessor
|
||||
chars = [ '<','>','#','##','\\','(',')',',','.']
|
||||
for c in chars:
|
||||
self.lexer.input(c)
|
||||
tok = self.lexer.token()
|
||||
if not tok or tok.value != c:
|
||||
print("Unable to lex '%s' required for preprocessor" % c)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# add_path()
|
||||
#
|
||||
# Adds a search path to the preprocessor.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def add_path(self,path):
|
||||
self.path.append(path)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# group_lines()
|
||||
#
|
||||
# Given an input string, this function splits it into lines. Trailing whitespace
|
||||
# is removed. Any line ending with \ is grouped with the next line. This
|
||||
# function forms the lowest level of the preprocessor---grouping into text into
|
||||
# a line-by-line format.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def group_lines(self,input):
|
||||
lex = self.lexer.clone()
|
||||
lines = [x.rstrip() for x in input.splitlines()]
|
||||
for i in xrange(len(lines)):
|
||||
j = i+1
|
||||
while lines[i].endswith('\\') and (j < len(lines)):
|
||||
lines[i] = lines[i][:-1]+lines[j]
|
||||
lines[j] = ""
|
||||
j += 1
|
||||
|
||||
input = "\n".join(lines)
|
||||
lex.input(input)
|
||||
lex.lineno = 1
|
||||
|
||||
current_line = []
|
||||
while True:
|
||||
tok = lex.token()
|
||||
if not tok:
|
||||
break
|
||||
current_line.append(tok)
|
||||
if tok.type in self.t_WS and '\n' in tok.value:
|
||||
yield current_line
|
||||
current_line = []
|
||||
|
||||
if current_line:
|
||||
yield current_line
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# tokenstrip()
|
||||
#
|
||||
# Remove leading/trailing whitespace tokens from a token list
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def tokenstrip(self,tokens):
|
||||
i = 0
|
||||
while i < len(tokens) and tokens[i].type in self.t_WS:
|
||||
i += 1
|
||||
del tokens[:i]
|
||||
i = len(tokens)-1
|
||||
while i >= 0 and tokens[i].type in self.t_WS:
|
||||
i -= 1
|
||||
del tokens[i+1:]
|
||||
return tokens
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# collect_args()
|
||||
#
|
||||
# Collects comma separated arguments from a list of tokens. The arguments
|
||||
# must be enclosed in parenthesis. Returns a tuple (tokencount,args,positions)
|
||||
# where tokencount is the number of tokens consumed, args is a list of arguments,
|
||||
# and positions is a list of integers containing the starting index of each
|
||||
# argument. Each argument is represented by a list of tokens.
|
||||
#
|
||||
# When collecting arguments, leading and trailing whitespace is removed
|
||||
# from each argument.
|
||||
#
|
||||
# This function properly handles nested parenthesis and commas---these do not
|
||||
# define new arguments.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def collect_args(self,tokenlist):
|
||||
args = []
|
||||
positions = []
|
||||
current_arg = []
|
||||
nesting = 1
|
||||
tokenlen = len(tokenlist)
|
||||
|
||||
# Search for the opening '('.
|
||||
i = 0
|
||||
while (i < tokenlen) and (tokenlist[i].type in self.t_WS):
|
||||
i += 1
|
||||
|
||||
if (i < tokenlen) and (tokenlist[i].value == '('):
|
||||
positions.append(i+1)
|
||||
else:
|
||||
self.error(self.source,tokenlist[0].lineno,"Missing '(' in macro arguments")
|
||||
return 0, [], []
|
||||
|
||||
i += 1
|
||||
|
||||
while i < tokenlen:
|
||||
t = tokenlist[i]
|
||||
if t.value == '(':
|
||||
current_arg.append(t)
|
||||
nesting += 1
|
||||
elif t.value == ')':
|
||||
nesting -= 1
|
||||
if nesting == 0:
|
||||
if current_arg:
|
||||
args.append(self.tokenstrip(current_arg))
|
||||
positions.append(i)
|
||||
return i+1,args,positions
|
||||
current_arg.append(t)
|
||||
elif t.value == ',' and nesting == 1:
|
||||
args.append(self.tokenstrip(current_arg))
|
||||
positions.append(i+1)
|
||||
current_arg = []
|
||||
else:
|
||||
current_arg.append(t)
|
||||
i += 1
|
||||
|
||||
# Missing end argument
|
||||
self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments")
|
||||
return 0, [],[]
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# macro_prescan()
|
||||
#
|
||||
# Examine the macro value (token sequence) and identify patch points
|
||||
# This is used to speed up macro expansion later on---we'll know
|
||||
# right away where to apply patches to the value to form the expansion
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def macro_prescan(self,macro):
|
||||
macro.patch = [] # Standard macro arguments
|
||||
macro.str_patch = [] # String conversion expansion
|
||||
macro.var_comma_patch = [] # Variadic macro comma patch
|
||||
i = 0
|
||||
while i < len(macro.value):
|
||||
if macro.value[i].type == self.t_ID and macro.value[i].value in macro.arglist:
|
||||
argnum = macro.arglist.index(macro.value[i].value)
|
||||
# Conversion of argument to a string
|
||||
if i > 0 and macro.value[i-1].value == '#':
|
||||
macro.value[i] = copy.copy(macro.value[i])
|
||||
macro.value[i].type = self.t_STRING
|
||||
del macro.value[i-1]
|
||||
macro.str_patch.append((argnum,i-1))
|
||||
continue
|
||||
# Concatenation
|
||||
elif (i > 0 and macro.value[i-1].value == '##'):
|
||||
macro.patch.append(('c',argnum,i-1))
|
||||
del macro.value[i-1]
|
||||
continue
|
||||
elif ((i+1) < len(macro.value) and macro.value[i+1].value == '##'):
|
||||
macro.patch.append(('c',argnum,i))
|
||||
i += 1
|
||||
continue
|
||||
# Standard expansion
|
||||
else:
|
||||
macro.patch.append(('e',argnum,i))
|
||||
elif macro.value[i].value == '##':
|
||||
if macro.variadic and (i > 0) and (macro.value[i-1].value == ',') and \
|
||||
((i+1) < len(macro.value)) and (macro.value[i+1].type == self.t_ID) and \
|
||||
(macro.value[i+1].value == macro.vararg):
|
||||
macro.var_comma_patch.append(i-1)
|
||||
i += 1
|
||||
macro.patch.sort(key=lambda x: x[2],reverse=True)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# macro_expand_args()
|
||||
#
|
||||
# Given a Macro and list of arguments (each a token list), this method
|
||||
# returns an expanded version of a macro. The return value is a token sequence
|
||||
# representing the replacement macro tokens
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def macro_expand_args(self,macro,args):
|
||||
# Make a copy of the macro token sequence
|
||||
rep = [copy.copy(_x) for _x in macro.value]
|
||||
|
||||
# Make string expansion patches. These do not alter the length of the replacement sequence
|
||||
|
||||
str_expansion = {}
|
||||
for argnum, i in macro.str_patch:
|
||||
if argnum not in str_expansion:
|
||||
str_expansion[argnum] = ('"%s"' % "".join([x.value for x in args[argnum]])).replace("\\","\\\\")
|
||||
rep[i] = copy.copy(rep[i])
|
||||
rep[i].value = str_expansion[argnum]
|
||||
|
||||
# Make the variadic macro comma patch. If the variadic macro argument is empty, we get rid
|
||||
comma_patch = False
|
||||
if macro.variadic and not args[-1]:
|
||||
for i in macro.var_comma_patch:
|
||||
rep[i] = None
|
||||
comma_patch = True
|
||||
|
||||
# Make all other patches. The order of these matters. It is assumed that the patch list
|
||||
# has been sorted in reverse order of patch location since replacements will cause the
|
||||
# size of the replacement sequence to expand from the patch point.
|
||||
|
||||
expanded = { }
|
||||
for ptype, argnum, i in macro.patch:
|
||||
# Concatenation. Argument is left unexpanded
|
||||
if ptype == 'c':
|
||||
rep[i:i+1] = args[argnum]
|
||||
# Normal expansion. Argument is macro expanded first
|
||||
elif ptype == 'e':
|
||||
if argnum not in expanded:
|
||||
expanded[argnum] = self.expand_macros(args[argnum])
|
||||
rep[i:i+1] = expanded[argnum]
|
||||
|
||||
# Get rid of removed comma if necessary
|
||||
if comma_patch:
|
||||
rep = [_i for _i in rep if _i]
|
||||
|
||||
return rep
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# expand_macros()
|
||||
#
|
||||
# Given a list of tokens, this function performs macro expansion.
|
||||
# The expanded argument is a dictionary that contains macros already
|
||||
# expanded. This is used to prevent infinite recursion.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def expand_macros(self,tokens,expanded=None):
|
||||
if expanded is None:
|
||||
expanded = {}
|
||||
i = 0
|
||||
while i < len(tokens):
|
||||
t = tokens[i]
|
||||
if t.type == self.t_ID:
|
||||
if t.value in self.macros and t.value not in expanded:
|
||||
# Yes, we found a macro match
|
||||
expanded[t.value] = True
|
||||
|
||||
m = self.macros[t.value]
|
||||
if not m.arglist:
|
||||
# A simple macro
|
||||
ex = self.expand_macros([copy.copy(_x) for _x in m.value],expanded)
|
||||
for e in ex:
|
||||
e.lineno = t.lineno
|
||||
tokens[i:i+1] = ex
|
||||
i += len(ex)
|
||||
else:
|
||||
# A macro with arguments
|
||||
j = i + 1
|
||||
while j < len(tokens) and tokens[j].type in self.t_WS:
|
||||
j += 1
|
||||
if tokens[j].value == '(':
|
||||
tokcount,args,positions = self.collect_args(tokens[j:])
|
||||
if not m.variadic and len(args) != len(m.arglist):
|
||||
self.error(self.source,t.lineno,"Macro %s requires %d arguments" % (t.value,len(m.arglist)))
|
||||
i = j + tokcount
|
||||
elif m.variadic and len(args) < len(m.arglist)-1:
|
||||
if len(m.arglist) > 2:
|
||||
self.error(self.source,t.lineno,"Macro %s must have at least %d arguments" % (t.value, len(m.arglist)-1))
|
||||
else:
|
||||
self.error(self.source,t.lineno,"Macro %s must have at least %d argument" % (t.value, len(m.arglist)-1))
|
||||
i = j + tokcount
|
||||
else:
|
||||
if m.variadic:
|
||||
if len(args) == len(m.arglist)-1:
|
||||
args.append([])
|
||||
else:
|
||||
args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1]
|
||||
del args[len(m.arglist):]
|
||||
|
||||
# Get macro replacement text
|
||||
rep = self.macro_expand_args(m,args)
|
||||
rep = self.expand_macros(rep,expanded)
|
||||
for r in rep:
|
||||
r.lineno = t.lineno
|
||||
tokens[i:j+tokcount] = rep
|
||||
i += len(rep)
|
||||
del expanded[t.value]
|
||||
continue
|
||||
elif t.value == '__LINE__':
|
||||
t.type = self.t_INTEGER
|
||||
t.value = self.t_INTEGER_TYPE(t.lineno)
|
||||
|
||||
i += 1
|
||||
return tokens
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# evalexpr()
|
||||
#
|
||||
# Evaluate an expression token sequence for the purposes of evaluating
|
||||
# integral expressions.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def evalexpr(self,tokens):
|
||||
# tokens = tokenize(line)
|
||||
# Search for defined macros
|
||||
i = 0
|
||||
while i < len(tokens):
|
||||
if tokens[i].type == self.t_ID and tokens[i].value == 'defined':
|
||||
j = i + 1
|
||||
needparen = False
|
||||
result = "0L"
|
||||
while j < len(tokens):
|
||||
if tokens[j].type in self.t_WS:
|
||||
j += 1
|
||||
continue
|
||||
elif tokens[j].type == self.t_ID:
|
||||
if tokens[j].value in self.macros:
|
||||
result = "1L"
|
||||
else:
|
||||
result = "0L"
|
||||
if not needparen: break
|
||||
elif tokens[j].value == '(':
|
||||
needparen = True
|
||||
elif tokens[j].value == ')':
|
||||
break
|
||||
else:
|
||||
self.error(self.source,tokens[i].lineno,"Malformed defined()")
|
||||
j += 1
|
||||
tokens[i].type = self.t_INTEGER
|
||||
tokens[i].value = self.t_INTEGER_TYPE(result)
|
||||
del tokens[i+1:j+1]
|
||||
i += 1
|
||||
tokens = self.expand_macros(tokens)
|
||||
for i,t in enumerate(tokens):
|
||||
if t.type == self.t_ID:
|
||||
tokens[i] = copy.copy(t)
|
||||
tokens[i].type = self.t_INTEGER
|
||||
tokens[i].value = self.t_INTEGER_TYPE("0L")
|
||||
elif t.type == self.t_INTEGER:
|
||||
tokens[i] = copy.copy(t)
|
||||
# Strip off any trailing suffixes
|
||||
tokens[i].value = str(tokens[i].value)
|
||||
while tokens[i].value[-1] not in "0123456789abcdefABCDEF":
|
||||
tokens[i].value = tokens[i].value[:-1]
|
||||
|
||||
expr = "".join([str(x.value) for x in tokens])
|
||||
expr = expr.replace("&&"," and ")
|
||||
expr = expr.replace("||"," or ")
|
||||
expr = expr.replace("!"," not ")
|
||||
try:
|
||||
result = eval(expr)
|
||||
except StandardError:
|
||||
self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression")
|
||||
result = 0
|
||||
return result
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# parsegen()
|
||||
#
|
||||
# Parse an input string/
|
||||
# ----------------------------------------------------------------------
|
||||
def parsegen(self,input,source=None):
|
||||
|
||||
# Replace trigraph sequences
|
||||
t = trigraph(input)
|
||||
lines = self.group_lines(t)
|
||||
|
||||
if not source:
|
||||
source = ""
|
||||
|
||||
self.define("__FILE__ \"%s\"" % source)
|
||||
|
||||
self.source = source
|
||||
chunk = []
|
||||
enable = True
|
||||
iftrigger = False
|
||||
ifstack = []
|
||||
|
||||
for x in lines:
|
||||
for i,tok in enumerate(x):
|
||||
if tok.type not in self.t_WS: break
|
||||
if tok.value == '#':
|
||||
# Preprocessor directive
|
||||
|
||||
for tok in x:
|
||||
if tok in self.t_WS and '\n' in tok.value:
|
||||
chunk.append(tok)
|
||||
|
||||
dirtokens = self.tokenstrip(x[i+1:])
|
||||
if dirtokens:
|
||||
name = dirtokens[0].value
|
||||
args = self.tokenstrip(dirtokens[1:])
|
||||
else:
|
||||
name = ""
|
||||
args = []
|
||||
|
||||
if name == 'define':
|
||||
if enable:
|
||||
for tok in self.expand_macros(chunk):
|
||||
yield tok
|
||||
chunk = []
|
||||
self.define(args)
|
||||
elif name == 'include':
|
||||
if enable:
|
||||
for tok in self.expand_macros(chunk):
|
||||
yield tok
|
||||
chunk = []
|
||||
oldfile = self.macros['__FILE__']
|
||||
for tok in self.include(args):
|
||||
yield tok
|
||||
self.macros['__FILE__'] = oldfile
|
||||
self.source = source
|
||||
elif name == 'undef':
|
||||
if enable:
|
||||
for tok in self.expand_macros(chunk):
|
||||
yield tok
|
||||
chunk = []
|
||||
self.undef(args)
|
||||
elif name == 'ifdef':
|
||||
ifstack.append((enable,iftrigger))
|
||||
if enable:
|
||||
if not args[0].value in self.macros:
|
||||
enable = False
|
||||
iftrigger = False
|
||||
else:
|
||||
iftrigger = True
|
||||
elif name == 'ifndef':
|
||||
ifstack.append((enable,iftrigger))
|
||||
if enable:
|
||||
if args[0].value in self.macros:
|
||||
enable = False
|
||||
iftrigger = False
|
||||
else:
|
||||
iftrigger = True
|
||||
elif name == 'if':
|
||||
ifstack.append((enable,iftrigger))
|
||||
if enable:
|
||||
result = self.evalexpr(args)
|
||||
if not result:
|
||||
enable = False
|
||||
iftrigger = False
|
||||
else:
|
||||
iftrigger = True
|
||||
elif name == 'elif':
|
||||
if ifstack:
|
||||
if ifstack[-1][0]: # We only pay attention if outer "if" allows this
|
||||
if enable: # If already true, we flip enable False
|
||||
enable = False
|
||||
elif not iftrigger: # If False, but not triggered yet, we'll check expression
|
||||
result = self.evalexpr(args)
|
||||
if result:
|
||||
enable = True
|
||||
iftrigger = True
|
||||
else:
|
||||
self.error(self.source,dirtokens[0].lineno,"Misplaced #elif")
|
||||
|
||||
elif name == 'else':
|
||||
if ifstack:
|
||||
if ifstack[-1][0]:
|
||||
if enable:
|
||||
enable = False
|
||||
elif not iftrigger:
|
||||
enable = True
|
||||
iftrigger = True
|
||||
else:
|
||||
self.error(self.source,dirtokens[0].lineno,"Misplaced #else")
|
||||
|
||||
elif name == 'endif':
|
||||
if ifstack:
|
||||
enable,iftrigger = ifstack.pop()
|
||||
else:
|
||||
self.error(self.source,dirtokens[0].lineno,"Misplaced #endif")
|
||||
else:
|
||||
# Unknown preprocessor directive
|
||||
pass
|
||||
|
||||
else:
|
||||
# Normal text
|
||||
if enable:
|
||||
chunk.extend(x)
|
||||
|
||||
for tok in self.expand_macros(chunk):
|
||||
yield tok
|
||||
chunk = []
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# include()
|
||||
#
|
||||
# Implementation of file-inclusion
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def include(self,tokens):
|
||||
# Try to extract the filename and then process an include file
|
||||
if not tokens:
|
||||
return
|
||||
if tokens:
|
||||
if tokens[0].value != '<' and tokens[0].type != self.t_STRING:
|
||||
tokens = self.expand_macros(tokens)
|
||||
|
||||
if tokens[0].value == '<':
|
||||
# Include <...>
|
||||
i = 1
|
||||
while i < len(tokens):
|
||||
if tokens[i].value == '>':
|
||||
break
|
||||
i += 1
|
||||
else:
|
||||
print("Malformed #include <...>")
|
||||
return
|
||||
filename = "".join([x.value for x in tokens[1:i]])
|
||||
path = self.path + [""] + self.temp_path
|
||||
elif tokens[0].type == self.t_STRING:
|
||||
filename = tokens[0].value[1:-1]
|
||||
path = self.temp_path + [""] + self.path
|
||||
else:
|
||||
print("Malformed #include statement")
|
||||
return
|
||||
for p in path:
|
||||
iname = os.path.join(p,filename)
|
||||
try:
|
||||
data = open(iname,"r").read()
|
||||
dname = os.path.dirname(iname)
|
||||
if dname:
|
||||
self.temp_path.insert(0,dname)
|
||||
for tok in self.parsegen(data,filename):
|
||||
yield tok
|
||||
if dname:
|
||||
del self.temp_path[0]
|
||||
break
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
print("Couldn't find '%s'" % filename)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# define()
|
||||
#
|
||||
# Define a new macro
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def define(self,tokens):
|
||||
if isinstance(tokens,(str,unicode)):
|
||||
tokens = self.tokenize(tokens)
|
||||
|
||||
linetok = tokens
|
||||
try:
|
||||
name = linetok[0]
|
||||
if len(linetok) > 1:
|
||||
mtype = linetok[1]
|
||||
else:
|
||||
mtype = None
|
||||
if not mtype:
|
||||
m = Macro(name.value,[])
|
||||
self.macros[name.value] = m
|
||||
elif mtype.type in self.t_WS:
|
||||
# A normal macro
|
||||
m = Macro(name.value,self.tokenstrip(linetok[2:]))
|
||||
self.macros[name.value] = m
|
||||
elif mtype.value == '(':
|
||||
# A macro with arguments
|
||||
tokcount, args, positions = self.collect_args(linetok[1:])
|
||||
variadic = False
|
||||
for a in args:
|
||||
if variadic:
|
||||
print("No more arguments may follow a variadic argument")
|
||||
break
|
||||
astr = "".join([str(_i.value) for _i in a])
|
||||
if astr == "...":
|
||||
variadic = True
|
||||
a[0].type = self.t_ID
|
||||
a[0].value = '__VA_ARGS__'
|
||||
variadic = True
|
||||
del a[1:]
|
||||
continue
|
||||
elif astr[-3:] == "..." and a[0].type == self.t_ID:
|
||||
variadic = True
|
||||
del a[1:]
|
||||
# If, for some reason, "." is part of the identifier, strip off the name for the purposes
|
||||
# of macro expansion
|
||||
if a[0].value[-3:] == '...':
|
||||
a[0].value = a[0].value[:-3]
|
||||
continue
|
||||
if len(a) > 1 or a[0].type != self.t_ID:
|
||||
print("Invalid macro argument")
|
||||
break
|
||||
else:
|
||||
mvalue = self.tokenstrip(linetok[1+tokcount:])
|
||||
i = 0
|
||||
while i < len(mvalue):
|
||||
if i+1 < len(mvalue):
|
||||
if mvalue[i].type in self.t_WS and mvalue[i+1].value == '##':
|
||||
del mvalue[i]
|
||||
continue
|
||||
elif mvalue[i].value == '##' and mvalue[i+1].type in self.t_WS:
|
||||
del mvalue[i+1]
|
||||
i += 1
|
||||
m = Macro(name.value,mvalue,[x[0].value for x in args],variadic)
|
||||
self.macro_prescan(m)
|
||||
self.macros[name.value] = m
|
||||
else:
|
||||
print("Bad macro definition")
|
||||
except LookupError:
|
||||
print("Bad macro definition")
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# undef()
|
||||
#
|
||||
# Undefine a macro
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def undef(self,tokens):
|
||||
id = tokens[0].value
|
||||
try:
|
||||
del self.macros[id]
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# parse()
|
||||
#
|
||||
# Parse input text.
|
||||
# ----------------------------------------------------------------------
|
||||
def parse(self,input,source=None,ignore={}):
|
||||
self.ignore = ignore
|
||||
self.parser = self.parsegen(input,source)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# token()
|
||||
#
|
||||
# Method to return individual tokens
|
||||
# ----------------------------------------------------------------------
|
||||
def token(self):
|
||||
try:
|
||||
while True:
|
||||
tok = next(self.parser)
|
||||
if tok.type not in self.ignore: return tok
|
||||
except StopIteration:
|
||||
self.parser = None
|
||||
return None
|
||||
|
||||
if __name__ == '__main__':
|
||||
import ply.lex as lex
|
||||
lexer = lex.lex()
|
||||
|
||||
# Run a preprocessor
|
||||
import sys
|
||||
f = open(sys.argv[1])
|
||||
input = f.read()
|
||||
|
||||
p = Preprocessor(lexer)
|
||||
p.parse(input,sys.argv[1])
|
||||
while True:
|
||||
tok = p.token()
|
||||
if not tok: break
|
||||
print(p.source, tok)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
133
bin/ply/ctokens.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# ctokens.py
|
||||
#
|
||||
# Token specifications for symbols in ANSI C and C++. This file is
|
||||
# meant to be used as a library in other tokenizers.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Reserved words
|
||||
|
||||
tokens = [
|
||||
# Literals (identifier, integer constant, float constant, string constant, char const)
|
||||
'ID', 'TYPEID', 'ICONST', 'FCONST', 'SCONST', 'CCONST',
|
||||
|
||||
# Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=)
|
||||
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD',
|
||||
'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT',
|
||||
'LOR', 'LAND', 'LNOT',
|
||||
'LT', 'LE', 'GT', 'GE', 'EQ', 'NE',
|
||||
|
||||
# Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=)
|
||||
'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL',
|
||||
'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL',
|
||||
|
||||
# Increment/decrement (++,--)
|
||||
'PLUSPLUS', 'MINUSMINUS',
|
||||
|
||||
# Structure dereference (->)
|
||||
'ARROW',
|
||||
|
||||
# Ternary operator (?)
|
||||
'TERNARY',
|
||||
|
||||
# Delimeters ( ) [ ] { } , . ; :
|
||||
'LPAREN', 'RPAREN',
|
||||
'LBRACKET', 'RBRACKET',
|
||||
'LBRACE', 'RBRACE',
|
||||
'COMMA', 'PERIOD', 'SEMI', 'COLON',
|
||||
|
||||
# Ellipsis (...)
|
||||
'ELLIPSIS',
|
||||
]
|
||||
|
||||
# Operators
|
||||
t_PLUS = r'\+'
|
||||
t_MINUS = r'-'
|
||||
t_TIMES = r'\*'
|
||||
t_DIVIDE = r'/'
|
||||
t_MODULO = r'%'
|
||||
t_OR = r'\|'
|
||||
t_AND = r'&'
|
||||
t_NOT = r'~'
|
||||
t_XOR = r'\^'
|
||||
t_LSHIFT = r'<<'
|
||||
t_RSHIFT = r'>>'
|
||||
t_LOR = r'\|\|'
|
||||
t_LAND = r'&&'
|
||||
t_LNOT = r'!'
|
||||
t_LT = r'<'
|
||||
t_GT = r'>'
|
||||
t_LE = r'<='
|
||||
t_GE = r'>='
|
||||
t_EQ = r'=='
|
||||
t_NE = r'!='
|
||||
|
||||
# Assignment operators
|
||||
|
||||
t_EQUALS = r'='
|
||||
t_TIMESEQUAL = r'\*='
|
||||
t_DIVEQUAL = r'/='
|
||||
t_MODEQUAL = r'%='
|
||||
t_PLUSEQUAL = r'\+='
|
||||
t_MINUSEQUAL = r'-='
|
||||
t_LSHIFTEQUAL = r'<<='
|
||||
t_RSHIFTEQUAL = r'>>='
|
||||
t_ANDEQUAL = r'&='
|
||||
t_OREQUAL = r'\|='
|
||||
t_XOREQUAL = r'^='
|
||||
|
||||
# Increment/decrement
|
||||
t_INCREMENT = r'\+\+'
|
||||
t_DECREMENT = r'--'
|
||||
|
||||
# ->
|
||||
t_ARROW = r'->'
|
||||
|
||||
# ?
|
||||
t_TERNARY = r'\?'
|
||||
|
||||
# Delimeters
|
||||
t_LPAREN = r'\('
|
||||
t_RPAREN = r'\)'
|
||||
t_LBRACKET = r'\['
|
||||
t_RBRACKET = r'\]'
|
||||
t_LBRACE = r'\{'
|
||||
t_RBRACE = r'\}'
|
||||
t_COMMA = r','
|
||||
t_PERIOD = r'\.'
|
||||
t_SEMI = r';'
|
||||
t_COLON = r':'
|
||||
t_ELLIPSIS = r'\.\.\.'
|
||||
|
||||
# Identifiers
|
||||
t_ID = r'[A-Za-z_][A-Za-z0-9_]*'
|
||||
|
||||
# Integer literal
|
||||
t_INTEGER = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
|
||||
|
||||
# Floating literal
|
||||
t_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
|
||||
|
||||
# String literal
|
||||
t_STRING = r'\"([^\\\n]|(\\.))*?\"'
|
||||
|
||||
# Character constant 'c' or L'c'
|
||||
t_CHARACTER = r'(L)?\'([^\\\n]|(\\.))*?\''
|
||||
|
||||
# Comment (C-Style)
|
||||
def t_COMMENT(t):
|
||||
r'/\*(.|\n)*?\*/'
|
||||
t.lexer.lineno += t.value.count('\n')
|
||||
return t
|
||||
|
||||
# Comment (C++-Style)
|
||||
def t_CPPCOMMENT(t):
|
||||
r'//.*\n'
|
||||
t.lexer.lineno += 1
|
||||
return t
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1058
bin/ply/lex.py
Normal file
3276
bin/ply/yacc.py
Normal file
187
bin/ripple/ledger/Args.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import importlib
|
||||
import os
|
||||
|
||||
from ripple.ledger import LedgerNumber
|
||||
from ripple.util import File
|
||||
from ripple.util import Log
|
||||
from ripple.util import PrettyPrint
|
||||
from ripple.util import Range
|
||||
from ripple.util.Function import Function
|
||||
|
||||
NAME = 'LedgerTool'
|
||||
VERSION = '0.1'
|
||||
NONE = '(none)'
|
||||
|
||||
_parser = argparse.ArgumentParser(
|
||||
prog=NAME,
|
||||
description='Retrieve and process Ripple ledgers.',
|
||||
epilog=LedgerNumber.HELP,
|
||||
)
|
||||
|
||||
# Positional arguments.
|
||||
_parser.add_argument(
|
||||
'command',
|
||||
nargs='*',
|
||||
help='Command to execute.'
|
||||
)
|
||||
|
||||
# Flag arguments.
|
||||
_parser.add_argument(
|
||||
'--binary',
|
||||
action='store_true',
|
||||
help='If true, searches are binary - by default linear search is used.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--cache',
|
||||
default='~/.local/share/ripple/ledger',
|
||||
help='The cache directory.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--complete',
|
||||
action='store_true',
|
||||
help='If set, only match complete ledgers.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--condition', '-c',
|
||||
help='The name of a condition function used to match ledgers.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--config',
|
||||
help='The rippled configuration file name.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--database', '-d',
|
||||
nargs='*',
|
||||
default=NONE,
|
||||
help='Specify a database.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--display',
|
||||
help='Specify a function to display ledgers.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--full', '-f',
|
||||
action='store_true',
|
||||
help='If true, request full ledgers.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--indent', '-i',
|
||||
type=int,
|
||||
default=2,
|
||||
help='How many spaces to indent when display in JSON.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--offline', '-o',
|
||||
action='store_true',
|
||||
help='If true, work entirely from cache, do not try to contact the server.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--position', '-p',
|
||||
choices=['all', 'first', 'last'],
|
||||
default='last',
|
||||
help='Select which ledgers to display.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--rippled', '-r',
|
||||
help='The filename of a rippled binary for retrieving ledgers.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--server', '-s',
|
||||
help='IP address of a rippled JSON server.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--utc', '-u',
|
||||
action='store_true',
|
||||
help='If true, display times in UTC rather than local time.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--validations',
|
||||
default=3,
|
||||
help='The number of validations needed before considering a ledger valid.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--version',
|
||||
action='version',
|
||||
version='%(prog)s ' + VERSION,
|
||||
help='Print the current version of %(prog)s',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--verbose', '-v',
|
||||
action='store_true',
|
||||
help='If true, give status messages on stderr.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--window', '-w',
|
||||
type=int,
|
||||
default=0,
|
||||
help='How many ledgers to display around the matching ledger.',
|
||||
)
|
||||
|
||||
_parser.add_argument(
|
||||
'--yes', '-y',
|
||||
action='store_true',
|
||||
help='If true, don\'t ask for confirmation on large commands.',
|
||||
)
|
||||
|
||||
# Read the arguments from the command line.
|
||||
ARGS = _parser.parse_args()
|
||||
ARGS.NONE = NONE
|
||||
|
||||
Log.VERBOSE = ARGS.verbose
|
||||
|
||||
# Now remove any items that look like ledger numbers from the command line.
|
||||
_command = ARGS.command
|
||||
_parts = (ARGS.command, ARGS.ledgers) = ([], [])
|
||||
|
||||
for c in _command:
|
||||
_parts[Range.is_range(c, *LedgerNumber.LEDGERS)].append(c)
|
||||
|
||||
ARGS.command = ARGS.command or ['print' if ARGS.ledgers else 'info']
|
||||
|
||||
ARGS.cache = File.normalize(ARGS.cache)
|
||||
|
||||
if not ARGS.ledgers:
|
||||
if ARGS.condition:
|
||||
Log.warn('--condition needs a range of ledgers')
|
||||
if ARGS.display:
|
||||
Log.warn('--display needs a range of ledgers')
|
||||
|
||||
ARGS.condition = Function(
|
||||
ARGS.condition or 'all_ledgers', 'ripple.ledger.conditions')
|
||||
ARGS.display = Function(
|
||||
ARGS.display or 'ledger_number', 'ripple.ledger.displays')
|
||||
|
||||
if ARGS.window < 0:
|
||||
raise ValueError('Window cannot be negative: --window=%d' %
|
||||
ARGS.window)
|
||||
|
||||
PrettyPrint.INDENT = (ARGS.indent * ' ')
|
||||
|
||||
_loaders = (ARGS.database != NONE) + bool(ARGS.rippled) + bool(ARGS.server)
|
||||
|
||||
if not _loaders:
|
||||
ARGS.rippled = 'rippled'
|
||||
|
||||
elif _loaders > 1:
|
||||
raise ValueError('At most one of --database, --rippled and --server '
|
||||
'may be specified')
|
||||
78
bin/ripple/ledger/DatabaseReader.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import ConfigFile
|
||||
from ripple.util import Database
|
||||
from ripple.util import File
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
|
||||
LEDGER_QUERY = """
|
||||
SELECT
|
||||
L.*, count(1) validations
|
||||
FROM
|
||||
(select LedgerHash, LedgerSeq from Ledgers ORDER BY LedgerSeq DESC) L
|
||||
JOIN Validations V
|
||||
ON (V.LedgerHash = L.LedgerHash)
|
||||
GROUP BY L.LedgerHash
|
||||
HAVING validations >= {validation_quorum}
|
||||
ORDER BY 2;
|
||||
"""
|
||||
|
||||
COMPLETE_QUERY = """
|
||||
SELECT
|
||||
L.LedgerSeq, count(*) validations
|
||||
FROM
|
||||
(select LedgerHash, LedgerSeq from Ledgers ORDER BY LedgerSeq) L
|
||||
JOIN Validations V
|
||||
ON (V.LedgerHash = L.LedgerHash)
|
||||
GROUP BY L.LedgerHash
|
||||
HAVING validations >= :validation_quorum
|
||||
ORDER BY 2;
|
||||
"""
|
||||
|
||||
_DATABASE_NAME = 'ledger.db'
|
||||
|
||||
USE_PLACEHOLDERS = False
|
||||
|
||||
class DatabaseReader(object):
|
||||
def __init__(self, config):
|
||||
assert ARGS.database != ARGS.NONE
|
||||
database = ARGS.database or config['database_path']
|
||||
if not database.endswith(_DATABASE_NAME):
|
||||
database = os.path.join(database, _DATABASE_NAME)
|
||||
if USE_PLACEHOLDERS:
|
||||
cursor = Database.fetchall(
|
||||
database, COMPLETE_QUERY, config)
|
||||
else:
|
||||
cursor = Database.fetchall(
|
||||
database, LEDGER_QUERY.format(**config), {})
|
||||
self.complete = [c[1] for c in cursor]
|
||||
|
||||
def name_to_ledger_index(self, ledger_name, is_full=False):
|
||||
if not self.complete:
|
||||
return None
|
||||
if ledger_name == 'closed':
|
||||
return self.complete[-1]
|
||||
if ledger_name == 'current':
|
||||
return None
|
||||
if ledger_name == 'validated':
|
||||
return self.complete[-1]
|
||||
|
||||
def get_ledger(self, name, is_full=False):
|
||||
cmd = ['ledger', str(name)]
|
||||
if is_full:
|
||||
cmd.append('full')
|
||||
response = self._command(*cmd)
|
||||
result = response.get('ledger')
|
||||
if result:
|
||||
return result
|
||||
error = response['error']
|
||||
etext = _ERROR_TEXT.get(error)
|
||||
if etext:
|
||||
error = '%s (%s)' % (etext, error)
|
||||
Log.fatal(_ERROR_TEXT.get(error, error))
|
||||
18
bin/ripple/ledger/LedgerNumber.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util import Range
|
||||
|
||||
FIRST_EVER = 32570
|
||||
|
||||
LEDGERS = {
|
||||
'closed': 'the most recently closed ledger',
|
||||
'current': 'the current ledger',
|
||||
'first': 'the first complete ledger on this server',
|
||||
'last': 'the last complete ledger on this server',
|
||||
'validated': 'the most recently validated ledger',
|
||||
}
|
||||
|
||||
HELP = """
|
||||
Ledgers are either represented by a number, or one of the special ledgers;
|
||||
""" + ',\n'.join('%s, %s' % (k, v) for k, v in sorted(LEDGERS.items())
|
||||
)
|
||||
68
bin/ripple/ledger/RippledReader.py
Normal file
@@ -0,0 +1,68 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import File
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
|
||||
_ERROR_CODE_REASON = {
|
||||
62: 'No rippled server is running.',
|
||||
}
|
||||
|
||||
_ERROR_TEXT = {
|
||||
'lgrNotFound': 'The ledger you requested was not found.',
|
||||
'noCurrent': 'The server has no current ledger.',
|
||||
'noNetwork': 'The server did not respond to your request.',
|
||||
}
|
||||
|
||||
_DEFAULT_ERROR_ = "Couldn't connect to server."
|
||||
|
||||
class RippledReader(object):
|
||||
def __init__(self, config):
|
||||
fname = File.normalize(ARGS.rippled)
|
||||
if not os.path.exists(fname):
|
||||
raise Exception('No rippled found at %s.' % fname)
|
||||
self.cmd = [fname]
|
||||
if ARGS.config:
|
||||
self.cmd.extend(['--conf', File.normalize(ARGS.config)])
|
||||
self.info = self._command('server_info')['info']
|
||||
c = self.info.get('complete_ledgers')
|
||||
if c == 'empty':
|
||||
self.complete = []
|
||||
else:
|
||||
self.complete = sorted(Range.from_string(c))
|
||||
|
||||
def name_to_ledger_index(self, ledger_name, is_full=False):
|
||||
return self.get_ledger(ledger_name, is_full)['ledger_index']
|
||||
|
||||
def get_ledger(self, name, is_full=False):
|
||||
cmd = ['ledger', str(name)]
|
||||
if is_full:
|
||||
cmd.append('full')
|
||||
response = self._command(*cmd)
|
||||
result = response.get('ledger')
|
||||
if result:
|
||||
return result
|
||||
error = response['error']
|
||||
etext = _ERROR_TEXT.get(error)
|
||||
if etext:
|
||||
error = '%s (%s)' % (etext, error)
|
||||
Log.fatal(_ERROR_TEXT.get(error, error))
|
||||
|
||||
def _command(self, *cmds):
|
||||
cmd = self.cmd + list(cmds)
|
||||
try:
|
||||
data = subprocess.check_output(cmd, stderr=subprocess.PIPE)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise Exception(_ERROR_CODE_REASON.get(
|
||||
e.returncode, _DEFAULT_ERROR_))
|
||||
|
||||
part = json.loads(data)
|
||||
try:
|
||||
return part['result']
|
||||
except:
|
||||
raise ValueError(part.get('error', 'unknown error'))
|
||||
24
bin/ripple/ledger/SearchLedgers.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
from ripple.util import Search
|
||||
|
||||
def search(server):
|
||||
"""Yields a stream of ledger numbers that match the given condition."""
|
||||
condition = lambda number: ARGS.condition(server, number)
|
||||
ledgers = server.ledgers
|
||||
if ARGS.binary:
|
||||
try:
|
||||
position = Search.FIRST if ARGS.position == 'first' else Search.LAST
|
||||
yield Search.binary_search(
|
||||
ledgers[0], ledgers[-1], condition, position)
|
||||
except:
|
||||
Log.fatal('No ledgers matching condition "%s".' % condition,
|
||||
file=sys.stderr)
|
||||
else:
|
||||
for x in Search.linear_search(ledgers, condition):
|
||||
yield x
|
||||
55
bin/ripple/ledger/Server.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from ripple.ledger import DatabaseReader, RippledReader
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util.FileCache import FileCache
|
||||
from ripple.util import ConfigFile
|
||||
from ripple.util import File
|
||||
from ripple.util import Range
|
||||
|
||||
class Server(object):
|
||||
def __init__(self):
|
||||
cfg_file = File.normalize(ARGS.config or 'rippled.cfg')
|
||||
self.config = ConfigFile.read(open(cfg_file))
|
||||
if ARGS.database != ARGS.NONE:
|
||||
reader = DatabaseReader.DatabaseReader(self.config)
|
||||
else:
|
||||
reader = RippledReader.RippledReader(self.config)
|
||||
|
||||
self.reader = reader
|
||||
self.complete = reader.complete
|
||||
|
||||
names = {
|
||||
'closed': reader.name_to_ledger_index('closed'),
|
||||
'current': reader.name_to_ledger_index('current'),
|
||||
'validated': reader.name_to_ledger_index('validated'),
|
||||
'first': self.complete[0] if self.complete else None,
|
||||
'last': self.complete[-1] if self.complete else None,
|
||||
}
|
||||
self.__dict__.update(names)
|
||||
self.ledgers = sorted(Range.join_ranges(*ARGS.ledgers, **names))
|
||||
|
||||
def make_cache(is_full):
|
||||
name = 'full' if is_full else 'summary'
|
||||
filepath = os.path.join(ARGS.cache, name)
|
||||
creator = lambda n: reader.get_ledger(n, is_full)
|
||||
return FileCache(filepath, creator)
|
||||
self._caches = [make_cache(False), make_cache(True)]
|
||||
|
||||
def info(self):
|
||||
return self.reader.info
|
||||
|
||||
def cache(self, is_full):
|
||||
return self._caches[is_full]
|
||||
|
||||
def get_ledger(self, number, is_full=False):
|
||||
num = int(number)
|
||||
save_in_cache = num in self.complete
|
||||
can_create = (not ARGS.offline and
|
||||
self.complete and
|
||||
self.complete[0] <= num - 1)
|
||||
cache = self.cache(is_full)
|
||||
return cache.get_data(number, save_in_cache, can_create)
|
||||
5
bin/ripple/ledger/ServerReader.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
class ServerReader(object):
|
||||
def __init__(self, config):
|
||||
raise ValueError('Direct server connections are not yet implemented.')
|
||||
34
bin/ripple/ledger/commands/Cache.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
from ripple.util.PrettyPrint import pretty_print
|
||||
|
||||
SAFE = True
|
||||
|
||||
HELP = """cache
|
||||
return server_info"""
|
||||
|
||||
def cache(server, clear=False):
|
||||
cache = server.cache(ARGS.full)
|
||||
name = ['summary', 'full'][ARGS.full]
|
||||
files = cache.file_count()
|
||||
if not files:
|
||||
Log.error('No files in %s cache.' % name)
|
||||
|
||||
elif clear:
|
||||
if not clear.strip() == 'clear':
|
||||
raise Exception("Don't understand 'clear %s'." % clear)
|
||||
if not ARGS.yes:
|
||||
yes = raw_input('OK to clear %s cache? (y/N) ' % name)
|
||||
if not yes.lower().startswith('y'):
|
||||
Log.out('Cancelled.')
|
||||
return
|
||||
cache.clear(ARGS.full)
|
||||
Log.out('%s cache cleared - %d file%s deleted.' %
|
||||
(name.capitalize(), files, '' if files == 1 else 's'))
|
||||
|
||||
else:
|
||||
caches = (int(c) for c in cache.cache_list())
|
||||
Log.out(Range.to_string(caches))
|
||||
21
bin/ripple/ledger/commands/Info.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
from ripple.util.PrettyPrint import pretty_print
|
||||
|
||||
SAFE = True
|
||||
|
||||
HELP = 'info - return server_info'
|
||||
|
||||
def info(server):
|
||||
Log.out('first =', server.first)
|
||||
Log.out('last =', server.last)
|
||||
Log.out('closed =', server.closed)
|
||||
Log.out('current =', server.current)
|
||||
Log.out('validated =', server.validated)
|
||||
Log.out('complete =', Range.to_string(server.complete))
|
||||
|
||||
if ARGS.full:
|
||||
Log.out(pretty_print(server.info()))
|
||||
15
bin/ripple/ledger/commands/Print.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.ledger import SearchLedgers
|
||||
|
||||
import json
|
||||
|
||||
SAFE = True
|
||||
|
||||
HELP = """print
|
||||
|
||||
Print the ledgers to stdout. The default command."""
|
||||
|
||||
def run_print(server):
|
||||
ARGS.display(print, server, SearchLedgers.search(server))
|
||||
4
bin/ripple/ledger/conditions/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
def all_ledgers(server, ledger_number):
|
||||
return True
|
||||
89
bin/ripple/ledger/displays/__init__.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from functools import wraps
|
||||
|
||||
import jsonpath_rw
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Dict
|
||||
from ripple.util import Log
|
||||
from ripple.util import Range
|
||||
from ripple.util.Decimal import Decimal
|
||||
from ripple.util.PrettyPrint import pretty_print, Streamer
|
||||
|
||||
TRANSACT_FIELDS = (
|
||||
'accepted',
|
||||
'close_time_human',
|
||||
'closed',
|
||||
'ledger_index',
|
||||
'total_coins',
|
||||
'transactions',
|
||||
)
|
||||
|
||||
LEDGER_FIELDS = (
|
||||
'accepted',
|
||||
'accountState',
|
||||
'close_time_human',
|
||||
'closed',
|
||||
'ledger_index',
|
||||
'total_coins',
|
||||
'transactions',
|
||||
)
|
||||
|
||||
def _dict_filter(d, keys):
|
||||
return dict((k, v) for (k, v) in d.items() if k in keys)
|
||||
|
||||
def ledger_number(print, server, numbers):
|
||||
print(Range.to_string(numbers))
|
||||
|
||||
def display(f):
|
||||
@wraps(f)
|
||||
def wrapper(printer, server, numbers, *args):
|
||||
streamer = Streamer(printer=printer)
|
||||
for number in numbers:
|
||||
ledger = server.get_ledger(number, ARGS.full)
|
||||
if ledger:
|
||||
streamer.add(number, f(ledger, *args))
|
||||
streamer.finish()
|
||||
return wrapper
|
||||
|
||||
def extractor(f):
|
||||
@wraps(f)
|
||||
def wrapper(printer, server, numbers, *paths):
|
||||
try:
|
||||
find = jsonpath_rw.parse('|'.join(paths)).find
|
||||
except:
|
||||
raise ValueError("Can't understand jsonpath '%s'." % path)
|
||||
def fn(ledger, *args):
|
||||
return f(find(ledger), *args)
|
||||
display(fn)(printer, server, numbers)
|
||||
return wrapper
|
||||
|
||||
@display
|
||||
def ledger(ledger, full=False):
|
||||
if ARGS.full:
|
||||
if full:
|
||||
return ledger
|
||||
|
||||
ledger = Dict.prune(ledger, 1, False)
|
||||
|
||||
return _dict_filter(ledger, LEDGER_FIELDS)
|
||||
|
||||
@display
|
||||
def prune(ledger, level=1):
|
||||
return Dict.prune(ledger, level, False)
|
||||
|
||||
@display
|
||||
def transact(ledger):
|
||||
return _dict_filter(ledger, TRANSACT_FIELDS)
|
||||
|
||||
@extractor
|
||||
def extract(finds):
|
||||
return dict((str(f.full_path), str(f.value)) for f in finds)
|
||||
|
||||
@extractor
|
||||
def sum(finds):
|
||||
d = Decimal()
|
||||
for f in finds:
|
||||
d.accumulate(f.value)
|
||||
return [str(d), len(finds)]
|
||||
40
bin/ripple/util/Cache.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
class Cache(object):
|
||||
def __init__(self):
|
||||
self._value_to_index = {}
|
||||
self._index_to_value = []
|
||||
|
||||
def value_to_index(self, value, **kwds):
|
||||
index = self._value_to_index.get(value, None)
|
||||
if index is None:
|
||||
index = len(self._index_to_value)
|
||||
self._index_to_value.append((value, kwds))
|
||||
self._value_to_index[value] = index
|
||||
return index
|
||||
|
||||
def index_to_value(self, index):
|
||||
return self._index_to_value[index]
|
||||
|
||||
def NamedCache():
|
||||
return defaultdict(Cache)
|
||||
|
||||
def cache_by_key(d, keyfunc=None, exclude=None):
|
||||
cache = defaultdict(Cache)
|
||||
exclude = exclude or None
|
||||
keyfunc = keyfunc or (lambda x: x)
|
||||
|
||||
def visit(item):
|
||||
if isinstance(item, list):
|
||||
for i, x in enumerate(item):
|
||||
item[i] = visit(x)
|
||||
|
||||
elif isinstance(item, dict):
|
||||
for k, v in item.items():
|
||||
item[k] = visit(v)
|
||||
|
||||
return item
|
||||
|
||||
return cache
|
||||
77
bin/ripple/util/CommandList.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
# Code taken from github/rec/grit.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from ripple.ledger.Args import ARGS
|
||||
from ripple.util import Log
|
||||
|
||||
Command = namedtuple('Command', 'function help safe')
|
||||
|
||||
def make_command(module):
|
||||
name = module.__name__.split('.')[-1].lower()
|
||||
return name, Command(getattr(module, name, None) or
|
||||
getattr(module, 'run_' + name),
|
||||
getattr(module, 'HELP'),
|
||||
getattr(module, 'SAFE', False))
|
||||
|
||||
class CommandList(object):
|
||||
def __init__(self, *args, **kwds):
|
||||
self.registry = {}
|
||||
self.register(*args, **kwds)
|
||||
|
||||
def register(self, *modules, **kwds):
|
||||
for module in modules:
|
||||
name, command = make_command(module)
|
||||
self.registry[name] = command
|
||||
|
||||
for k, v in kwds.items():
|
||||
if not isinstance(v, (list, tuple)):
|
||||
v = [v]
|
||||
self.register_one(k, *v)
|
||||
|
||||
def keys(self):
|
||||
return self.registry.keys()
|
||||
|
||||
def register_one(self, name, function, help='', safe=False):
|
||||
assert name not in self.registry
|
||||
self.registry[name] = Command(function, help, safe)
|
||||
|
||||
def _get(self, command):
|
||||
command = command.lower()
|
||||
c = self.registry.get(command)
|
||||
if c:
|
||||
return command, c
|
||||
commands = [c for c in self.registry if c.startswith(command)]
|
||||
if len(commands) == 1:
|
||||
command = commands[0]
|
||||
return command, self.registry[command]
|
||||
if not commands:
|
||||
raise ValueError('No such command: %s. Commands are %s.' %
|
||||
(command, ', '.join(sorted(self.registry))))
|
||||
if len(commands) > 1:
|
||||
raise ValueError('Command %s was ambiguous: %s.' %
|
||||
(command, ', '.join(commands)))
|
||||
|
||||
def get(self, command):
|
||||
return self._get(command)[1]
|
||||
|
||||
def run(self, command, *args):
|
||||
return self.get(command).function(*args)
|
||||
|
||||
def run_safe(self, command, *args):
|
||||
name, cmd = self._get(command)
|
||||
if not (ARGS.yes or cmd.safe):
|
||||
confirm = raw_input('OK to execute "rl %s %s"? (y/N) ' %
|
||||
(name, ' '.join(args)))
|
||||
if not confirm.lower().startswith('y'):
|
||||
Log.error('Cancelled.')
|
||||
return
|
||||
cmd.function(*args)
|
||||
|
||||
def help(self, command):
|
||||
return self.get(command).help()
|
||||
54
bin/ripple/util/ConfigFile.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
"""Ripple has a proprietary format for their .cfg files, so we need a reader for
|
||||
them."""
|
||||
|
||||
def read(lines):
|
||||
sections = []
|
||||
section = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if (not line) or line[0] == '#':
|
||||
continue
|
||||
if line.startswith('['):
|
||||
if section:
|
||||
sections.append(section)
|
||||
section = []
|
||||
section.append(line)
|
||||
if section:
|
||||
sections.append(section)
|
||||
|
||||
result = {}
|
||||
for section in sections:
|
||||
option = section.pop(0)
|
||||
assert section, ('No value for option "%s".' % option)
|
||||
assert option.startswith('[') and option.endswith(']'), (
|
||||
'No option name in block "%s"' % p[0])
|
||||
option = option[1:-1]
|
||||
assert option not in result, 'Duplicate option "%s".' % option
|
||||
|
||||
subdict = {}
|
||||
items = []
|
||||
for part in section:
|
||||
if '=' in part:
|
||||
assert not items, 'Dictionary mixed with list.'
|
||||
k, v = part.split('=', 1)
|
||||
assert k not in subdict, 'Repeated dictionary entry ' + k
|
||||
subdict[k] = v
|
||||
else:
|
||||
assert not subdict, 'List mixed with dictionary.'
|
||||
if part.startswith('{'):
|
||||
items.append(json.loads(part))
|
||||
else:
|
||||
words = part.split()
|
||||
if len(words) > 1:
|
||||
items.append(words)
|
||||
else:
|
||||
items.append(part)
|
||||
if len(items) == 1:
|
||||
result[option] = items[0]
|
||||
else:
|
||||
result[option] = items or subdict
|
||||
return result
|
||||
12
bin/ripple/util/Database.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import sqlite3
|
||||
|
||||
def fetchall(database, query, kwds):
|
||||
conn = sqlite3.connect(database)
|
||||
try:
|
||||
cursor = conn.execute(query, kwds)
|
||||
return cursor.fetchall()
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
46
bin/ripple/util/Decimal.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
"""Fixed point numbers."""
|
||||
|
||||
POSITIONS = 10
|
||||
POSITIONS_SHIFT = 10 ** POSITIONS
|
||||
|
||||
class Decimal(object):
|
||||
def __init__(self, desc='0'):
|
||||
if isinstance(desc, int):
|
||||
self.value = desc
|
||||
return
|
||||
if desc.startswith('-'):
|
||||
sign = -1
|
||||
desc = desc[1:]
|
||||
else:
|
||||
sign = 1
|
||||
parts = desc.split('.')
|
||||
if len(parts) == 1:
|
||||
parts.append('0')
|
||||
elif len(parts) > 2:
|
||||
raise Exception('Too many decimals in "%s"' % desc)
|
||||
number, decimal = parts
|
||||
# Fix the number of positions.
|
||||
decimal = (decimal + POSITIONS * '0')[:POSITIONS]
|
||||
self.value = sign * int(number + decimal)
|
||||
|
||||
def accumulate(self, item):
|
||||
if not isinstance(item, Decimal):
|
||||
item = Decimal(item)
|
||||
self.value += item.value
|
||||
|
||||
def __str__(self):
|
||||
if self.value >= 0:
|
||||
sign = ''
|
||||
value = self.value
|
||||
else:
|
||||
sign = '-'
|
||||
value = -self.value
|
||||
number = value // POSITIONS_SHIFT
|
||||
decimal = (value % POSITIONS_SHIFT) * POSITIONS_SHIFT
|
||||
|
||||
if decimal:
|
||||
return '%s%s.%s' % (sign, number, str(decimal).rstrip('0'))
|
||||
else:
|
||||
return '%s%s' % (sign, number)
|
||||
33
bin/ripple/util/Dict.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
def count_all_subitems(x):
|
||||
"""Count the subitems of a Python object, including the object itself."""
|
||||
if isinstance(x, list):
|
||||
return 1 + sum(count_all_subitems(i) for i in x)
|
||||
if isinstance(x, dict):
|
||||
return 1 + sum(count_all_subitems(i) for i in x.itervalues())
|
||||
return 1
|
||||
|
||||
def prune(item, level, count_recursively=True):
|
||||
def subitems(x):
|
||||
i = count_all_subitems(x) - 1 if count_recursively else len(x)
|
||||
return '1 subitem' if i == 1 else '%d subitems' % i
|
||||
|
||||
assert level >= 0
|
||||
if not item:
|
||||
return item
|
||||
|
||||
if isinstance(item, list):
|
||||
if level:
|
||||
return [prune(i, level - 1, count_recursively) for i in item]
|
||||
else:
|
||||
return '[list with %s]' % subitems(item)
|
||||
|
||||
if isinstance(item, dict):
|
||||
if level:
|
||||
return dict((k, prune(v, level - 1, count_recursively))
|
||||
for k, v in item.iteritems())
|
||||
else:
|
||||
return '{dict with %s}' % subitems(item)
|
||||
|
||||
return item
|
||||
7
bin/ripple/util/File.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
def normalize(f):
|
||||
f = os.path.join(*f.split('/')) # For Windows users.
|
||||
return os.path.abspath(os.path.expanduser(f))
|
||||
56
bin/ripple/util/FileCache.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import gzip
|
||||
import json
|
||||
import os
|
||||
|
||||
_NONE = object()
|
||||
|
||||
class FileCache(object):
|
||||
"""A two-level cache, which stores expensive results in memory and on disk.
|
||||
"""
|
||||
def __init__(self, cache_directory, creator, open=gzip.open, suffix='.gz'):
|
||||
self.cache_directory = cache_directory
|
||||
self.creator = creator
|
||||
self.open = open
|
||||
self.suffix = suffix
|
||||
self.cached_data = {}
|
||||
if not os.path.exists(self.cache_directory):
|
||||
os.makedirs(self.cache_directory)
|
||||
|
||||
def get_file_data(self, name):
|
||||
if os.path.exists(filename):
|
||||
return json.load(self.open(filename))
|
||||
|
||||
result = self.creator(name)
|
||||
return result
|
||||
|
||||
def get_data(self, name, save_in_cache, can_create, default=None):
|
||||
name = str(name)
|
||||
result = self.cached_data.get(name, _NONE)
|
||||
if result is _NONE:
|
||||
filename = os.path.join(self.cache_directory, name) + self.suffix
|
||||
if os.path.exists(filename):
|
||||
result = json.load(self.open(filename)) or _NONE
|
||||
if result is _NONE and can_create:
|
||||
result = self.creator(name)
|
||||
if save_in_cache:
|
||||
json.dump(result, self.open(filename, 'w'))
|
||||
return default if result is _NONE else result
|
||||
|
||||
def _files(self):
|
||||
return os.listdir(self.cache_directory)
|
||||
|
||||
def cache_list(self):
|
||||
for f in self._files():
|
||||
if f.endswith(self.suffix):
|
||||
yield f[:-len(self.suffix)]
|
||||
|
||||
def file_count(self):
|
||||
return len(self._files())
|
||||
|
||||
def clear(self):
|
||||
"""Clears both local files and memory."""
|
||||
self.cached_data = {}
|
||||
for f in self._files():
|
||||
os.remove(os.path.join(self.cache_directory, f))
|
||||
82
bin/ripple/util/Function.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
"""A function that can be specified at the command line, with an argument."""
|
||||
|
||||
import importlib
|
||||
import re
|
||||
import tokenize
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
MATCHER = re.compile(r'([\w.]+)(.*)')
|
||||
|
||||
REMAPPINGS = {
|
||||
'false': False,
|
||||
'true': True,
|
||||
'null': None,
|
||||
'False': False,
|
||||
'True': True,
|
||||
'None': None,
|
||||
}
|
||||
|
||||
def eval_arguments(args):
|
||||
args = args.strip()
|
||||
if not args or (args == '()'):
|
||||
return ()
|
||||
tokens = list(tokenize.generate_tokens(StringIO(args).readline))
|
||||
def remap():
|
||||
for type, name, _, _, _ in tokens:
|
||||
if type == tokenize.NAME and name not in REMAPPINGS:
|
||||
yield tokenize.STRING, '"%s"' % name
|
||||
else:
|
||||
yield type, name
|
||||
untok = tokenize.untokenize(remap())
|
||||
if untok[1:-1].strip():
|
||||
untok = untok[:-1] + ',)' # Force a tuple.
|
||||
try:
|
||||
return eval(untok, REMAPPINGS)
|
||||
except Exception as e:
|
||||
raise ValueError('Couldn\'t evaluate expression "%s" (became "%s"), '
|
||||
'error "%s"' % (args, untok, str(e)))
|
||||
|
||||
class Function(object):
|
||||
def __init__(self, desc='', default_path=''):
|
||||
self.desc = desc.strip()
|
||||
if not self.desc:
|
||||
# Make an empty function that does nothing.
|
||||
self.args = ()
|
||||
self.function = lambda *args, **kwds: None
|
||||
return
|
||||
|
||||
m = MATCHER.match(desc)
|
||||
if not m:
|
||||
raise ValueError('"%s" is not a function' % desc)
|
||||
self.function, self.args = (g.strip() for g in m.groups())
|
||||
self.args = eval_arguments(self.args)
|
||||
|
||||
if '.' not in self.function:
|
||||
if default_path and not default_path.endswith('.'):
|
||||
default_path += '.'
|
||||
self.function = default_path + self.function
|
||||
p, m = self.function.rsplit('.', 1)
|
||||
mod = importlib.import_module(p)
|
||||
# Errors in modules are swallowed here.
|
||||
# except:
|
||||
# raise ValueError('Can\'t find Python module "%s"' % p)
|
||||
|
||||
try:
|
||||
self.function = getattr(mod, m)
|
||||
except:
|
||||
raise ValueError('No function "%s" in module "%s"' % (m, p))
|
||||
|
||||
def __str__(self):
|
||||
return self.desc
|
||||
|
||||
def __call__(self, *args, **kwds):
|
||||
return self.function(*(args + self.args), **kwds)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.function == other.function and self.args == other.args
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
21
bin/ripple/util/Log.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
VERBOSE = False
|
||||
|
||||
def out(*args, **kwds):
|
||||
kwds.get('print', print)(*args, file=sys.stdout, **kwds)
|
||||
|
||||
def info(*args, **kwds):
|
||||
if VERBOSE:
|
||||
out(*args, **kwds)
|
||||
|
||||
def warn(*args, **kwds):
|
||||
out('WARNING:', *args, **kwds)
|
||||
|
||||
def error(*args, **kwds):
|
||||
out('ERROR:', *args, **kwds)
|
||||
|
||||
def fatal(*args, **kwds):
|
||||
raise Exception('FATAL: ' + ' '.join(str(a) for a in args))
|
||||
42
bin/ripple/util/PrettyPrint.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from functools import wraps
|
||||
import json
|
||||
|
||||
SEPARATORS = ',', ': '
|
||||
INDENT = ' '
|
||||
|
||||
def pretty_print(item):
|
||||
return json.dumps(item,
|
||||
sort_keys=True,
|
||||
indent=len(INDENT),
|
||||
separators=SEPARATORS)
|
||||
|
||||
class Streamer(object):
|
||||
def __init__(self, printer=print):
|
||||
# No automatic spacing or carriage returns.
|
||||
self.printer = lambda *args: printer(*args, end='', sep='')
|
||||
self.first_key = True
|
||||
|
||||
def add(self, key, value):
|
||||
if self.first_key:
|
||||
self.first_key = False
|
||||
self.printer('{')
|
||||
else:
|
||||
self.printer(',')
|
||||
|
||||
self.printer('\n', INDENT, '"', str(key), '": ')
|
||||
|
||||
pp = pretty_print(value).splitlines()
|
||||
if len(pp) > 1:
|
||||
for i, line in enumerate(pp):
|
||||
if i > 0:
|
||||
self.printer('\n', INDENT)
|
||||
self.printer(line)
|
||||
else:
|
||||
self.printer(pp[0])
|
||||
|
||||
def finish(self):
|
||||
if not self.first_key:
|
||||
self.first_key = True
|
||||
self.printer('\n}')
|
||||
53
bin/ripple/util/Range.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
"""
|
||||
Convert a discontiguous range of integers to and from a human-friendly form.
|
||||
|
||||
Real world example is the server_info.complete_ledgers:
|
||||
8252899-8403772,8403824,8403827-8403830,8403834-8403876
|
||||
|
||||
"""
|
||||
|
||||
def from_string(desc, **aliases):
|
||||
if not desc:
|
||||
return []
|
||||
result = set()
|
||||
for d in desc.split(','):
|
||||
nums = [int(aliases.get(x) or x) for x in d.split('-')]
|
||||
if len(nums) == 1:
|
||||
result.add(nums[0])
|
||||
elif len(nums) == 2:
|
||||
result.update(range(nums[0], nums[1] + 1))
|
||||
return result
|
||||
|
||||
def to_string(r):
|
||||
groups = []
|
||||
next_group = []
|
||||
for i, x in enumerate(sorted(r)):
|
||||
if next_group and (x - next_group[-1]) > 1:
|
||||
groups.append(next_group)
|
||||
next_group = []
|
||||
next_group.append(x)
|
||||
if next_group:
|
||||
groups.append(next_group)
|
||||
|
||||
def display(g):
|
||||
if len(g) == 1:
|
||||
return str(g[0])
|
||||
else:
|
||||
return '%s-%s' % (g[0], g[-1])
|
||||
|
||||
return ','.join(display(g) for g in groups)
|
||||
|
||||
def is_range(desc, *names):
|
||||
try:
|
||||
from_string(desc, **dict((n, 1) for n in names))
|
||||
return True;
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def join_ranges(*ranges, **aliases):
|
||||
result = set()
|
||||
for r in ranges:
|
||||
result.update(from_string(r, **aliases))
|
||||
return result
|
||||
46
bin/ripple/util/Search.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
FIRST, LAST = range(2)
|
||||
|
||||
def binary_search(begin, end, condition, location=FIRST):
|
||||
"""Search for an i in the interval [begin, end] where condition(i) is true.
|
||||
If location is FIRST, return the first such i.
|
||||
If location is LAST, return the last such i.
|
||||
If there is no such i, then throw an exception.
|
||||
"""
|
||||
b = condition(begin)
|
||||
e = condition(end)
|
||||
if b and e:
|
||||
return begin if location == FIRST else end
|
||||
|
||||
if not (b or e):
|
||||
raise ValueError('%d/%d' % (begin, end))
|
||||
|
||||
if b and location is FIRST:
|
||||
return begin
|
||||
|
||||
if e and location is LAST:
|
||||
return end
|
||||
|
||||
width = end - begin + 1
|
||||
if width == 1:
|
||||
if not b:
|
||||
raise ValueError('%d/%d' % (begin, end))
|
||||
return begin
|
||||
if width == 2:
|
||||
return begin if b else end
|
||||
|
||||
mid = (begin + end) // 2
|
||||
m = condition(mid)
|
||||
|
||||
if m == b:
|
||||
return binary_search(mid, end, condition, location)
|
||||
else:
|
||||
return binary_search(begin, mid, condition, location)
|
||||
|
||||
def linear_search(items, condition):
|
||||
"""Yields each i in the interval [begin, end] where condition(i) is true.
|
||||
"""
|
||||
for i in items:
|
||||
if condition(i):
|
||||
yield i
|
||||
21
bin/ripple/util/Time.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
# Format for human-readable dates in rippled
|
||||
_DATE_FORMAT = '%Y-%b-%d'
|
||||
_TIME_FORMAT = '%H:%M:%S'
|
||||
_DATETIME_FORMAT = '%s %s' % (_DATE_FORMAT, _TIME_FORMAT)
|
||||
|
||||
_FORMATS = _DATE_FORMAT, _TIME_FORMAT, _DATETIME_FORMAT
|
||||
|
||||
def parse_datetime(desc):
|
||||
for fmt in _FORMATS:
|
||||
try:
|
||||
return datetime.date.strptime(desc, fmt)
|
||||
except:
|
||||
pass
|
||||
raise ValueError("Can't understand date '%s'." % date)
|
||||
|
||||
def format_datetime(dt):
|
||||
return dt.strftime(_DATETIME_FORMAT)
|
||||
12
bin/ripple/util/test_Cache.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util.Cache import NamedCache
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_Cache(TestCase):
|
||||
def setUp(self):
|
||||
self.cache = NamedCache()
|
||||
|
||||
def test_trivial(self):
|
||||
pass
|
||||
163
bin/ripple/util/test_ConfigFile.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util import ConfigFile
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_ConfigFile(TestCase):
|
||||
def test_trivial(self):
|
||||
self.assertEquals(ConfigFile.read(''), {})
|
||||
|
||||
def test_full(self):
|
||||
self.assertEquals(ConfigFile.read(FULL.splitlines()), RESULT)
|
||||
|
||||
RESULT = {
|
||||
'websocket_port': '6206',
|
||||
'database_path': '/development/alpha/db',
|
||||
'sntp_servers':
|
||||
['time.windows.com', 'time.apple.com', 'time.nist.gov', 'pool.ntp.org'],
|
||||
'validation_seed': 'sh1T8T9yGuV7Jb6DPhqSzdU2s5LcV',
|
||||
'node_size': 'medium',
|
||||
'rpc_startup': {
|
||||
'command': 'log_level',
|
||||
'severity': 'debug'},
|
||||
'ips': ['r.ripple.com', '51235'],
|
||||
'node_db': {
|
||||
'file_size_mult': '2',
|
||||
'file_size_mb': '8',
|
||||
'cache_mb': '256',
|
||||
'path': '/development/alpha/db/rocksdb',
|
||||
'open_files': '2000',
|
||||
'type': 'RocksDB',
|
||||
'filter_bits': '12'},
|
||||
'peer_port': '53235',
|
||||
'ledger_history': 'full',
|
||||
'rpc_ip': '127.0.0.1',
|
||||
'websocket_public_ip': '0.0.0.0',
|
||||
'rpc_allow_remote': '0',
|
||||
'validators':
|
||||
[['n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7', 'RL1'],
|
||||
['n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj', 'RL2'],
|
||||
['n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C', 'RL3'],
|
||||
['n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS', 'RL4'],
|
||||
['n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA', 'RL5']],
|
||||
'debug_logfile': '/development/alpha/debug.log',
|
||||
'websocket_public_port': '5206',
|
||||
'peer_ip': '0.0.0.0',
|
||||
'rpc_port': '5205',
|
||||
'validation_quorum': '3',
|
||||
'websocket_ip': '127.0.0.1'}
|
||||
|
||||
FULL = """
|
||||
[ledger_history]
|
||||
full
|
||||
|
||||
# Allow other peers to connect to this server.
|
||||
#
|
||||
[peer_ip]
|
||||
0.0.0.0
|
||||
|
||||
[peer_port]
|
||||
53235
|
||||
|
||||
# Allow untrusted clients to connect to this server.
|
||||
#
|
||||
[websocket_public_ip]
|
||||
0.0.0.0
|
||||
|
||||
[websocket_public_port]
|
||||
5206
|
||||
|
||||
# Provide trusted websocket ADMIN access to the localhost.
|
||||
#
|
||||
[websocket_ip]
|
||||
127.0.0.1
|
||||
|
||||
[websocket_port]
|
||||
6206
|
||||
|
||||
# Provide trusted json-rpc ADMIN access to the localhost.
|
||||
#
|
||||
[rpc_ip]
|
||||
127.0.0.1
|
||||
|
||||
[rpc_port]
|
||||
5205
|
||||
|
||||
[rpc_allow_remote]
|
||||
0
|
||||
|
||||
[node_size]
|
||||
medium
|
||||
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found here: https://ripple.com/wiki/NodeBackEnd
|
||||
[node_db]
|
||||
type=RocksDB
|
||||
path=/development/alpha/db/rocksdb
|
||||
open_files=2000
|
||||
filter_bits=12
|
||||
cache_mb=256
|
||||
file_size_mb=8
|
||||
file_size_mult=2
|
||||
|
||||
[database_path]
|
||||
/development/alpha/db
|
||||
|
||||
# This needs to be an absolute directory reference, not a relative one.
|
||||
# Modify this value as required.
|
||||
[debug_logfile]
|
||||
/development/alpha/debug.log
|
||||
|
||||
[sntp_servers]
|
||||
time.windows.com
|
||||
time.apple.com
|
||||
time.nist.gov
|
||||
pool.ntp.org
|
||||
|
||||
# Where to find some other servers speaking the Ripple protocol.
|
||||
#
|
||||
[ips]
|
||||
r.ripple.com 51235
|
||||
|
||||
# The latest validators can be obtained from
|
||||
# https://ripple.com/ripple.txt
|
||||
#
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
# Ditto.
|
||||
[validation_quorum]
|
||||
3
|
||||
|
||||
[validation_seed]
|
||||
sh1T8T9yGuV7Jb6DPhqSzdU2s5LcV
|
||||
|
||||
# Turn down default logging to save disk space in the long run.
|
||||
# Valid values here are trace, debug, info, warning, error, and fatal
|
||||
[rpc_startup]
|
||||
{ "command": "log_level", "severity": "debug" }
|
||||
|
||||
# Configure SSL for WebSockets. Not enabled by default because not everybody
|
||||
# has an SSL cert on their server, but if you uncomment the following lines and
|
||||
# set the path to the SSL certificate and private key the WebSockets protocol
|
||||
# will be protected by SSL/TLS.
|
||||
#[websocket_secure]
|
||||
#1
|
||||
|
||||
#[websocket_ssl_cert]
|
||||
#/etc/ssl/certs/server.crt
|
||||
|
||||
#[websocket_ssl_key]
|
||||
#/etc/ssl/private/server.key
|
||||
|
||||
# Defaults to 0 ("no") so that you can use self-signed SSL certificates for
|
||||
# development, or internally.
|
||||
#[ssl_verify]
|
||||
#0
|
||||
""".strip()
|
||||
20
bin/ripple/util/test_Decimal.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util.Decimal import Decimal
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_Decimal(TestCase):
|
||||
def test_construct(self):
|
||||
self.assertEquals(str(Decimal('')), '0')
|
||||
self.assertEquals(str(Decimal('0')), '0')
|
||||
self.assertEquals(str(Decimal('0.2')), '0.2')
|
||||
self.assertEquals(str(Decimal('-0.2')), '-0.2')
|
||||
self.assertEquals(str(Decimal('3.1416')), '3.1416')
|
||||
|
||||
def test_accumulate(self):
|
||||
d = Decimal()
|
||||
d.accumulate('0.5')
|
||||
d.accumulate('3.1416')
|
||||
d.accumulate('-23.34234')
|
||||
self.assertEquals(str(d), '-19.70074')
|
||||
56
bin/ripple/util/test_Dict.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util import Dict
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_Dict(TestCase):
|
||||
def test_count_all_subitems(self):
|
||||
self.assertEquals(Dict.count_all_subitems({}), 1)
|
||||
self.assertEquals(Dict.count_all_subitems({'a': {}}), 2)
|
||||
self.assertEquals(Dict.count_all_subitems([1]), 2)
|
||||
self.assertEquals(Dict.count_all_subitems([1, 2]), 3)
|
||||
self.assertEquals(Dict.count_all_subitems([1, {2: 3}]), 4)
|
||||
self.assertEquals(Dict.count_all_subitems([1, {2: [3]}]), 5)
|
||||
self.assertEquals(Dict.count_all_subitems([1, {2: [3, 4]}]), 6)
|
||||
|
||||
def test_prune(self):
|
||||
self.assertEquals(Dict.prune({}, 0), {})
|
||||
self.assertEquals(Dict.prune({}, 1), {})
|
||||
|
||||
self.assertEquals(Dict.prune({1: 2}, 0), '{dict with 1 subitem}')
|
||||
self.assertEquals(Dict.prune({1: 2}, 1), {1: 2})
|
||||
self.assertEquals(Dict.prune({1: 2}, 2), {1: 2})
|
||||
|
||||
self.assertEquals(Dict.prune([1, 2, 3], 0), '[list with 3 subitems]')
|
||||
self.assertEquals(Dict.prune([1, 2, 3], 1), [1, 2, 3])
|
||||
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 0),
|
||||
'[list with 4 subitems]')
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 1),
|
||||
['{dict with 3 subitems}'])
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 2),
|
||||
[{1: u'[list with 2 subitems]'}])
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 3),
|
||||
[{1: [2, 3]}])
|
||||
|
||||
def test_prune_nosub(self):
|
||||
self.assertEquals(Dict.prune({}, 0, False), {})
|
||||
self.assertEquals(Dict.prune({}, 1, False), {})
|
||||
|
||||
self.assertEquals(Dict.prune({1: 2}, 0, False), '{dict with 1 subitem}')
|
||||
self.assertEquals(Dict.prune({1: 2}, 1, False), {1: 2})
|
||||
self.assertEquals(Dict.prune({1: 2}, 2, False), {1: 2})
|
||||
|
||||
self.assertEquals(Dict.prune([1, 2, 3], 0, False),
|
||||
'[list with 3 subitems]')
|
||||
self.assertEquals(Dict.prune([1, 2, 3], 1, False), [1, 2, 3])
|
||||
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 0, False),
|
||||
'[list with 1 subitem]')
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 1, False),
|
||||
['{dict with 1 subitem}'])
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 2, False),
|
||||
[{1: u'[list with 2 subitems]'}])
|
||||
self.assertEquals(Dict.prune([{1: [2, 3]}], 3, False),
|
||||
[{1: [2, 3]}])
|
||||
37
bin/ripple/util/test_Function.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util.Function import Function, MATCHER
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
def FN(*args, **kwds):
|
||||
return args, kwds
|
||||
|
||||
class test_Function(TestCase):
|
||||
def match_test(self, item, *results):
|
||||
self.assertEquals(MATCHER.match(item).groups(), results)
|
||||
|
||||
def test_simple(self):
|
||||
self.match_test('function', 'function', '')
|
||||
self.match_test('f(x)', 'f', '(x)')
|
||||
|
||||
def test_empty_function(self):
|
||||
self.assertEquals(Function()(), None)
|
||||
|
||||
def test_empty_args(self):
|
||||
f = Function('ripple.util.test_Function.FN()')
|
||||
self.assertEquals(f(), ((), {}))
|
||||
|
||||
def test_function(self):
|
||||
f = Function('ripple.util.test_Function.FN(True, {1: 2}, None)')
|
||||
self.assertEquals(f(), ((True, {1: 2}, None), {}))
|
||||
self.assertEquals(f('hello', foo='bar'),
|
||||
(('hello', True, {1: 2}, None), {'foo':'bar'}))
|
||||
self.assertEquals(
|
||||
f, Function('ripple.util.test_Function.FN(true, {1: 2}, null)'))
|
||||
|
||||
def test_quoting(self):
|
||||
f = Function('ripple.util.test_Function.FN(testing)')
|
||||
self.assertEquals(f(), (('testing',), {}))
|
||||
f = Function('ripple.util.test_Function.FN(testing, true, false, null)')
|
||||
self.assertEquals(f(), (('testing', True, False, None), {}))
|
||||
56
bin/ripple/util/test_PrettyPrint.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util import PrettyPrint
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_PrettyPrint(TestCase):
|
||||
def setUp(self):
|
||||
self._results = []
|
||||
self.printer = PrettyPrint.Streamer(printer=self.printer)
|
||||
|
||||
def printer(self, *args, **kwds):
|
||||
self._results.extend(args)
|
||||
|
||||
def run_test(self, expected, *args):
|
||||
for i in range(0, len(args), 2):
|
||||
self.printer.add(args[i], args[i + 1])
|
||||
self.printer.finish()
|
||||
self.assertEquals(''.join(self._results), expected)
|
||||
|
||||
def test_simple_printer(self):
|
||||
self.run_test(
|
||||
'{\n "foo": "bar"\n}',
|
||||
'foo', 'bar')
|
||||
|
||||
def test_multiple_lines(self):
|
||||
self.run_test(
|
||||
'{\n "foo": "bar",\n "baz": 5\n}',
|
||||
'foo', 'bar', 'baz', 5)
|
||||
|
||||
def test_multiple_lines(self):
|
||||
self.run_test(
|
||||
"""
|
||||
{
|
||||
"foo": {
|
||||
"bar": 1,
|
||||
"baz": true
|
||||
},
|
||||
"bang": "bing"
|
||||
}
|
||||
""".strip(), 'foo', {'bar': 1, 'baz': True}, 'bang', 'bing')
|
||||
|
||||
def test_multiple_lines_with_list(self):
|
||||
self.run_test(
|
||||
"""
|
||||
{
|
||||
"foo": [
|
||||
"bar",
|
||||
1
|
||||
],
|
||||
"baz": [
|
||||
23,
|
||||
42
|
||||
]
|
||||
}
|
||||
""".strip(), 'foo', ['bar', 1], 'baz', [23, 42])
|
||||
28
bin/ripple/util/test_Range.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util import Range
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_Range(TestCase):
|
||||
def round_trip(self, s, *items):
|
||||
self.assertEquals(Range.from_string(s), set(items))
|
||||
self.assertEquals(Range.to_string(items), s)
|
||||
|
||||
def test_complete(self):
|
||||
self.round_trip('10,19', 10, 19)
|
||||
self.round_trip('10', 10)
|
||||
self.round_trip('10-12', 10, 11, 12)
|
||||
self.round_trip('10,19,42-45', 10, 19, 42, 43, 44, 45)
|
||||
|
||||
def test_names(self):
|
||||
self.assertEquals(
|
||||
Range.from_string('first,last,current', first=1, last=3, current=5),
|
||||
set([1, 3, 5]))
|
||||
|
||||
def test_is_range(self):
|
||||
self.assertTrue(Range.is_range(''))
|
||||
self.assertTrue(Range.is_range('10'))
|
||||
self.assertTrue(Range.is_range('10,12'))
|
||||
self.assertFalse(Range.is_range('10,12,fred'))
|
||||
self.assertTrue(Range.is_range('10,12,fred', 'fred'))
|
||||
44
bin/ripple/util/test_Search.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from ripple.util.Search import binary_search, linear_search, FIRST, LAST
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
class test_Search(TestCase):
|
||||
def condition(self, i):
|
||||
return 10 <= i < 15;
|
||||
|
||||
def test_linear_full(self):
|
||||
self.assertEquals(list(linear_search(range(21), self.condition)),
|
||||
[10, 11, 12, 13, 14])
|
||||
|
||||
def test_linear_partial(self):
|
||||
self.assertEquals(list(linear_search(range(8, 14), self.condition)),
|
||||
[10, 11, 12, 13])
|
||||
self.assertEquals(list(linear_search(range(11, 14), self.condition)),
|
||||
[11, 12, 13])
|
||||
self.assertEquals(list(linear_search(range(12, 18), self.condition)),
|
||||
[12, 13, 14])
|
||||
|
||||
def test_linear_empty(self):
|
||||
self.assertEquals(list(linear_search(range(1, 4), self.condition)), [])
|
||||
|
||||
def test_binary_first(self):
|
||||
self.assertEquals(binary_search(0, 14, self.condition, FIRST), 10)
|
||||
self.assertEquals(binary_search(10, 19, self.condition, FIRST), 10)
|
||||
self.assertEquals(binary_search(14, 14, self.condition, FIRST), 14)
|
||||
self.assertEquals(binary_search(14, 15, self.condition, FIRST), 14)
|
||||
self.assertEquals(binary_search(13, 15, self.condition, FIRST), 13)
|
||||
|
||||
def test_binary_last(self):
|
||||
self.assertEquals(binary_search(10, 20, self.condition, LAST), 14)
|
||||
self.assertEquals(binary_search(0, 14, self.condition, LAST), 14)
|
||||
self.assertEquals(binary_search(14, 14, self.condition, LAST), 14)
|
||||
self.assertEquals(binary_search(14, 15, self.condition, LAST), 14)
|
||||
self.assertEquals(binary_search(13, 15, self.condition, LAST), 14)
|
||||
|
||||
def test_binary_throws(self):
|
||||
self.assertRaises(
|
||||
ValueError, binary_search, 0, 20, self.condition, LAST)
|
||||
self.assertRaises(
|
||||
ValueError, binary_search, 0, 20, self.condition, FIRST)
|
||||
747
bin/six.py
Normal file
@@ -0,0 +1,747 @@
|
||||
"""Utilities for writing code that runs on Python 2 and 3"""
|
||||
|
||||
# Copyright (c) 2010-2014 Benjamin Peterson
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import functools
|
||||
import operator
|
||||
import sys
|
||||
import types
|
||||
|
||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||
__version__ = "1.7.3"
|
||||
|
||||
|
||||
# Useful for very coarse version differentiation.
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
string_types = str,
|
||||
integer_types = int,
|
||||
class_types = type,
|
||||
text_type = str
|
||||
binary_type = bytes
|
||||
|
||||
MAXSIZE = sys.maxsize
|
||||
else:
|
||||
string_types = basestring,
|
||||
integer_types = (int, long)
|
||||
class_types = (type, types.ClassType)
|
||||
text_type = unicode
|
||||
binary_type = str
|
||||
|
||||
if sys.platform.startswith("java"):
|
||||
# Jython always uses 32 bits.
|
||||
MAXSIZE = int((1 << 31) - 1)
|
||||
else:
|
||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||
class X(object):
|
||||
def __len__(self):
|
||||
return 1 << 31
|
||||
try:
|
||||
len(X())
|
||||
except OverflowError:
|
||||
# 32-bit
|
||||
MAXSIZE = int((1 << 31) - 1)
|
||||
else:
|
||||
# 64-bit
|
||||
MAXSIZE = int((1 << 63) - 1)
|
||||
del X
|
||||
|
||||
|
||||
def _add_doc(func, doc):
|
||||
"""Add documentation to a function."""
|
||||
func.__doc__ = doc
|
||||
|
||||
|
||||
def _import_module(name):
|
||||
"""Import module, returning the module after the last dot."""
|
||||
__import__(name)
|
||||
return sys.modules[name]
|
||||
|
||||
|
||||
class _LazyDescr(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, obj, tp):
|
||||
result = self._resolve()
|
||||
setattr(obj, self.name, result) # Invokes __set__.
|
||||
# This is a bit ugly, but it avoids running this again.
|
||||
delattr(obj.__class__, self.name)
|
||||
return result
|
||||
|
||||
|
||||
class MovedModule(_LazyDescr):
|
||||
|
||||
def __init__(self, name, old, new=None):
|
||||
super(MovedModule, self).__init__(name)
|
||||
if PY3:
|
||||
if new is None:
|
||||
new = name
|
||||
self.mod = new
|
||||
else:
|
||||
self.mod = old
|
||||
|
||||
def _resolve(self):
|
||||
return _import_module(self.mod)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
_module = self._resolve()
|
||||
value = getattr(_module, attr)
|
||||
setattr(self, attr, value)
|
||||
return value
|
||||
|
||||
|
||||
class _LazyModule(types.ModuleType):
|
||||
|
||||
def __init__(self, name):
|
||||
super(_LazyModule, self).__init__(name)
|
||||
self.__doc__ = self.__class__.__doc__
|
||||
|
||||
def __dir__(self):
|
||||
attrs = ["__doc__", "__name__"]
|
||||
attrs += [attr.name for attr in self._moved_attributes]
|
||||
return attrs
|
||||
|
||||
# Subclasses should override this
|
||||
_moved_attributes = []
|
||||
|
||||
|
||||
class MovedAttribute(_LazyDescr):
|
||||
|
||||
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
||||
super(MovedAttribute, self).__init__(name)
|
||||
if PY3:
|
||||
if new_mod is None:
|
||||
new_mod = name
|
||||
self.mod = new_mod
|
||||
if new_attr is None:
|
||||
if old_attr is None:
|
||||
new_attr = name
|
||||
else:
|
||||
new_attr = old_attr
|
||||
self.attr = new_attr
|
||||
else:
|
||||
self.mod = old_mod
|
||||
if old_attr is None:
|
||||
old_attr = name
|
||||
self.attr = old_attr
|
||||
|
||||
def _resolve(self):
|
||||
module = _import_module(self.mod)
|
||||
return getattr(module, self.attr)
|
||||
|
||||
|
||||
class _SixMetaPathImporter(object):
|
||||
"""
|
||||
A meta path importer to import six.moves and its submodules.
|
||||
|
||||
This class implements a PEP302 finder and loader. It should be compatible
|
||||
with Python 2.5 and all existing versions of Python3
|
||||
"""
|
||||
def __init__(self, six_module_name):
|
||||
self.name = six_module_name
|
||||
self.known_modules = {}
|
||||
|
||||
def _add_module(self, mod, *fullnames):
|
||||
for fullname in fullnames:
|
||||
self.known_modules[self.name + "." + fullname] = mod
|
||||
|
||||
def _get_module(self, fullname):
|
||||
return self.known_modules[self.name + "." + fullname]
|
||||
|
||||
def find_module(self, fullname, path=None):
|
||||
if fullname in self.known_modules:
|
||||
return self
|
||||
return None
|
||||
|
||||
def __get_module(self, fullname):
|
||||
try:
|
||||
return self.known_modules[fullname]
|
||||
except KeyError:
|
||||
raise ImportError("This loader does not know module " + fullname)
|
||||
|
||||
def load_module(self, fullname):
|
||||
try:
|
||||
# in case of a reload
|
||||
return sys.modules[fullname]
|
||||
except KeyError:
|
||||
pass
|
||||
mod = self.__get_module(fullname)
|
||||
if isinstance(mod, MovedModule):
|
||||
mod = mod._resolve()
|
||||
else:
|
||||
mod.__loader__ = self
|
||||
sys.modules[fullname] = mod
|
||||
return mod
|
||||
|
||||
def is_package(self, fullname):
|
||||
"""
|
||||
Return true, if the named module is a package.
|
||||
|
||||
We need this method to get correct spec objects with
|
||||
Python 3.4 (see PEP451)
|
||||
"""
|
||||
return hasattr(self.__get_module(fullname), "__path__")
|
||||
|
||||
def get_code(self, fullname):
|
||||
"""Return None
|
||||
|
||||
Required, if is_package is implemented"""
|
||||
self.__get_module(fullname) # eventually raises ImportError
|
||||
return None
|
||||
get_source = get_code # same as get_code
|
||||
|
||||
_importer = _SixMetaPathImporter(__name__)
|
||||
|
||||
|
||||
class _MovedItems(_LazyModule):
|
||||
"""Lazy loading of moved objects"""
|
||||
__path__ = [] # mark as package
|
||||
|
||||
|
||||
_moved_attributes = [
|
||||
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
||||
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
||||
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
||||
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
|
||||
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||
MovedAttribute("StringIO", "StringIO", "io"),
|
||||
MovedAttribute("UserDict", "UserDict", "collections"),
|
||||
MovedAttribute("UserList", "UserList", "collections"),
|
||||
MovedAttribute("UserString", "UserString", "collections"),
|
||||
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||
|
||||
MovedModule("builtins", "__builtin__"),
|
||||
MovedModule("configparser", "ConfigParser"),
|
||||
MovedModule("copyreg", "copy_reg"),
|
||||
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
||||
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
|
||||
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||
MovedModule("http_client", "httplib", "http.client"),
|
||||
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
||||
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
||||
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
||||
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
||||
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
||||
MovedModule("cPickle", "cPickle", "pickle"),
|
||||
MovedModule("queue", "Queue"),
|
||||
MovedModule("reprlib", "repr"),
|
||||
MovedModule("socketserver", "SocketServer"),
|
||||
MovedModule("_thread", "thread", "_thread"),
|
||||
MovedModule("tkinter", "Tkinter"),
|
||||
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
||||
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||
"tkinter.colorchooser"),
|
||||
MovedModule("tkinter_commondialog", "tkCommonDialog",
|
||||
"tkinter.commondialog"),
|
||||
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||
"tkinter.simpledialog"),
|
||||
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
||||
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
||||
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
||||
MovedModule("winreg", "_winreg"),
|
||||
]
|
||||
for attr in _moved_attributes:
|
||||
setattr(_MovedItems, attr.name, attr)
|
||||
if isinstance(attr, MovedModule):
|
||||
_importer._add_module(attr, "moves." + attr.name)
|
||||
del attr
|
||||
|
||||
_MovedItems._moved_attributes = _moved_attributes
|
||||
|
||||
moves = _MovedItems(__name__ + ".moves")
|
||||
_importer._add_module(moves, "moves")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_parse(_LazyModule):
|
||||
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
||||
|
||||
|
||||
_urllib_parse_moved_attributes = [
|
||||
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("quote", "urllib", "urllib.parse"),
|
||||
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
||||
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
||||
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
||||
]
|
||||
for attr in _urllib_parse_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
||||
"moves.urllib_parse", "moves.urllib.parse")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_error(_LazyModule):
|
||||
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
||||
|
||||
|
||||
_urllib_error_moved_attributes = [
|
||||
MovedAttribute("URLError", "urllib2", "urllib.error"),
|
||||
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
|
||||
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
|
||||
]
|
||||
for attr in _urllib_error_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
||||
"moves.urllib_error", "moves.urllib.error")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_request(_LazyModule):
|
||||
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
||||
|
||||
|
||||
_urllib_request_moved_attributes = [
|
||||
MovedAttribute("urlopen", "urllib2", "urllib.request"),
|
||||
MovedAttribute("install_opener", "urllib2", "urllib.request"),
|
||||
MovedAttribute("build_opener", "urllib2", "urllib.request"),
|
||||
MovedAttribute("pathname2url", "urllib", "urllib.request"),
|
||||
MovedAttribute("url2pathname", "urllib", "urllib.request"),
|
||||
MovedAttribute("getproxies", "urllib", "urllib.request"),
|
||||
MovedAttribute("Request", "urllib2", "urllib.request"),
|
||||
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
|
||||
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
|
||||
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
||||
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
||||
]
|
||||
for attr in _urllib_request_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
||||
"moves.urllib_request", "moves.urllib.request")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_response(_LazyModule):
|
||||
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
||||
|
||||
|
||||
_urllib_response_moved_attributes = [
|
||||
MovedAttribute("addbase", "urllib", "urllib.response"),
|
||||
MovedAttribute("addclosehook", "urllib", "urllib.response"),
|
||||
MovedAttribute("addinfo", "urllib", "urllib.response"),
|
||||
MovedAttribute("addinfourl", "urllib", "urllib.response"),
|
||||
]
|
||||
for attr in _urllib_response_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
||||
"moves.urllib_response", "moves.urllib.response")
|
||||
|
||||
|
||||
class Module_six_moves_urllib_robotparser(_LazyModule):
|
||||
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
||||
|
||||
|
||||
_urllib_robotparser_moved_attributes = [
|
||||
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
|
||||
]
|
||||
for attr in _urllib_robotparser_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
||||
del attr
|
||||
|
||||
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
||||
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
||||
|
||||
|
||||
class Module_six_moves_urllib(types.ModuleType):
|
||||
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
||||
__path__ = [] # mark as package
|
||||
parse = _importer._get_module("moves.urllib_parse")
|
||||
error = _importer._get_module("moves.urllib_error")
|
||||
request = _importer._get_module("moves.urllib_request")
|
||||
response = _importer._get_module("moves.urllib_response")
|
||||
robotparser = _importer._get_module("moves.urllib_robotparser")
|
||||
|
||||
def __dir__(self):
|
||||
return ['parse', 'error', 'request', 'response', 'robotparser']
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
||||
"moves.urllib")
|
||||
|
||||
|
||||
def add_move(move):
|
||||
"""Add an item to six.moves."""
|
||||
setattr(_MovedItems, move.name, move)
|
||||
|
||||
|
||||
def remove_move(name):
|
||||
"""Remove item from six.moves."""
|
||||
try:
|
||||
delattr(_MovedItems, name)
|
||||
except AttributeError:
|
||||
try:
|
||||
del moves.__dict__[name]
|
||||
except KeyError:
|
||||
raise AttributeError("no such move, %r" % (name,))
|
||||
|
||||
|
||||
if PY3:
|
||||
_meth_func = "__func__"
|
||||
_meth_self = "__self__"
|
||||
|
||||
_func_closure = "__closure__"
|
||||
_func_code = "__code__"
|
||||
_func_defaults = "__defaults__"
|
||||
_func_globals = "__globals__"
|
||||
else:
|
||||
_meth_func = "im_func"
|
||||
_meth_self = "im_self"
|
||||
|
||||
_func_closure = "func_closure"
|
||||
_func_code = "func_code"
|
||||
_func_defaults = "func_defaults"
|
||||
_func_globals = "func_globals"
|
||||
|
||||
|
||||
try:
|
||||
advance_iterator = next
|
||||
except NameError:
|
||||
def advance_iterator(it):
|
||||
return it.next()
|
||||
next = advance_iterator
|
||||
|
||||
|
||||
try:
|
||||
callable = callable
|
||||
except NameError:
|
||||
def callable(obj):
|
||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||
|
||||
|
||||
if PY3:
|
||||
def get_unbound_function(unbound):
|
||||
return unbound
|
||||
|
||||
create_bound_method = types.MethodType
|
||||
|
||||
Iterator = object
|
||||
else:
|
||||
def get_unbound_function(unbound):
|
||||
return unbound.im_func
|
||||
|
||||
def create_bound_method(func, obj):
|
||||
return types.MethodType(func, obj, obj.__class__)
|
||||
|
||||
class Iterator(object):
|
||||
|
||||
def next(self):
|
||||
return type(self).__next__(self)
|
||||
|
||||
callable = callable
|
||||
_add_doc(get_unbound_function,
|
||||
"""Get the function out of a possibly unbound function""")
|
||||
|
||||
|
||||
get_method_function = operator.attrgetter(_meth_func)
|
||||
get_method_self = operator.attrgetter(_meth_self)
|
||||
get_function_closure = operator.attrgetter(_func_closure)
|
||||
get_function_code = operator.attrgetter(_func_code)
|
||||
get_function_defaults = operator.attrgetter(_func_defaults)
|
||||
get_function_globals = operator.attrgetter(_func_globals)
|
||||
|
||||
|
||||
if PY3:
|
||||
def iterkeys(d, **kw):
|
||||
return iter(d.keys(**kw))
|
||||
|
||||
def itervalues(d, **kw):
|
||||
return iter(d.values(**kw))
|
||||
|
||||
def iteritems(d, **kw):
|
||||
return iter(d.items(**kw))
|
||||
|
||||
def iterlists(d, **kw):
|
||||
return iter(d.lists(**kw))
|
||||
else:
|
||||
def iterkeys(d, **kw):
|
||||
return iter(d.iterkeys(**kw))
|
||||
|
||||
def itervalues(d, **kw):
|
||||
return iter(d.itervalues(**kw))
|
||||
|
||||
def iteritems(d, **kw):
|
||||
return iter(d.iteritems(**kw))
|
||||
|
||||
def iterlists(d, **kw):
|
||||
return iter(d.iterlists(**kw))
|
||||
|
||||
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
||||
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
||||
_add_doc(iteritems,
|
||||
"Return an iterator over the (key, value) pairs of a dictionary.")
|
||||
_add_doc(iterlists,
|
||||
"Return an iterator over the (key, [values]) pairs of a dictionary.")
|
||||
|
||||
|
||||
if PY3:
|
||||
def b(s):
|
||||
return s.encode("latin-1")
|
||||
def u(s):
|
||||
return s
|
||||
unichr = chr
|
||||
if sys.version_info[1] <= 1:
|
||||
def int2byte(i):
|
||||
return bytes((i,))
|
||||
else:
|
||||
# This is about 2x faster than the implementation above on 3.2+
|
||||
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
||||
byte2int = operator.itemgetter(0)
|
||||
indexbytes = operator.getitem
|
||||
iterbytes = iter
|
||||
import io
|
||||
StringIO = io.StringIO
|
||||
BytesIO = io.BytesIO
|
||||
else:
|
||||
def b(s):
|
||||
return s
|
||||
# Workaround for standalone backslash
|
||||
def u(s):
|
||||
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
||||
unichr = unichr
|
||||
int2byte = chr
|
||||
def byte2int(bs):
|
||||
return ord(bs[0])
|
||||
def indexbytes(buf, i):
|
||||
return ord(buf[i])
|
||||
def iterbytes(buf):
|
||||
return (ord(byte) for byte in buf)
|
||||
import StringIO
|
||||
StringIO = BytesIO = StringIO.StringIO
|
||||
_add_doc(b, """Byte literal""")
|
||||
_add_doc(u, """Text literal""")
|
||||
|
||||
|
||||
if PY3:
|
||||
exec_ = getattr(moves.builtins, "exec")
|
||||
|
||||
|
||||
def reraise(tp, value, tb=None):
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
|
||||
else:
|
||||
def exec_(_code_, _globs_=None, _locs_=None):
|
||||
"""Execute code in a namespace."""
|
||||
if _globs_ is None:
|
||||
frame = sys._getframe(1)
|
||||
_globs_ = frame.f_globals
|
||||
if _locs_ is None:
|
||||
_locs_ = frame.f_locals
|
||||
del frame
|
||||
elif _locs_ is None:
|
||||
_locs_ = _globs_
|
||||
exec("""exec _code_ in _globs_, _locs_""")
|
||||
|
||||
|
||||
exec_("""def reraise(tp, value, tb=None):
|
||||
raise tp, value, tb
|
||||
""")
|
||||
|
||||
|
||||
print_ = getattr(moves.builtins, "print", None)
|
||||
if print_ is None:
|
||||
def print_(*args, **kwargs):
|
||||
"""The new-style print function for Python 2.4 and 2.5."""
|
||||
fp = kwargs.pop("file", sys.stdout)
|
||||
if fp is None:
|
||||
return
|
||||
def write(data):
|
||||
if not isinstance(data, basestring):
|
||||
data = str(data)
|
||||
# If the file has an encoding, encode unicode with it.
|
||||
if (isinstance(fp, file) and
|
||||
isinstance(data, unicode) and
|
||||
fp.encoding is not None):
|
||||
errors = getattr(fp, "errors", None)
|
||||
if errors is None:
|
||||
errors = "strict"
|
||||
data = data.encode(fp.encoding, errors)
|
||||
fp.write(data)
|
||||
want_unicode = False
|
||||
sep = kwargs.pop("sep", None)
|
||||
if sep is not None:
|
||||
if isinstance(sep, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(sep, str):
|
||||
raise TypeError("sep must be None or a string")
|
||||
end = kwargs.pop("end", None)
|
||||
if end is not None:
|
||||
if isinstance(end, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(end, str):
|
||||
raise TypeError("end must be None or a string")
|
||||
if kwargs:
|
||||
raise TypeError("invalid keyword arguments to print()")
|
||||
if not want_unicode:
|
||||
for arg in args:
|
||||
if isinstance(arg, unicode):
|
||||
want_unicode = True
|
||||
break
|
||||
if want_unicode:
|
||||
newline = unicode("\n")
|
||||
space = unicode(" ")
|
||||
else:
|
||||
newline = "\n"
|
||||
space = " "
|
||||
if sep is None:
|
||||
sep = space
|
||||
if end is None:
|
||||
end = newline
|
||||
for i, arg in enumerate(args):
|
||||
if i:
|
||||
write(sep)
|
||||
write(arg)
|
||||
write(end)
|
||||
|
||||
_add_doc(reraise, """Reraise an exception.""")
|
||||
|
||||
if sys.version_info[0:2] < (3, 4):
|
||||
def wraps(wrapped):
|
||||
def wrapper(f):
|
||||
f = functools.wraps(wrapped)(f)
|
||||
f.__wrapped__ = wrapped
|
||||
return f
|
||||
return wrapper
|
||||
else:
|
||||
wraps = functools.wraps
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""Create a base class with a metaclass."""
|
||||
# This requires a bit of explanation: the basic idea is to make a dummy
|
||||
# metaclass for one level of class instantiation that replaces itself with
|
||||
# the actual metaclass.
|
||||
class metaclass(meta):
|
||||
def __new__(cls, name, this_bases, d):
|
||||
return meta(name, bases, d)
|
||||
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||
|
||||
|
||||
def add_metaclass(metaclass):
|
||||
"""Class decorator for creating a class with a metaclass."""
|
||||
def wrapper(cls):
|
||||
orig_vars = cls.__dict__.copy()
|
||||
orig_vars.pop('__dict__', None)
|
||||
orig_vars.pop('__weakref__', None)
|
||||
slots = orig_vars.get('__slots__')
|
||||
if slots is not None:
|
||||
if isinstance(slots, str):
|
||||
slots = [slots]
|
||||
for slots_var in slots:
|
||||
orig_vars.pop(slots_var)
|
||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||
return wrapper
|
||||
|
||||
# Complete the moves implementation.
|
||||
# This code is at the end of this module to speed up module loading.
|
||||
# Turn this module into a package.
|
||||
__path__ = [] # required for PEP 302 and PEP 451
|
||||
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
||||
if globals().get("__spec__") is not None:
|
||||
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
||||
# Remove other six meta path importers, since they cause problems. This can
|
||||
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
||||
# this for some reason.)
|
||||
if sys.meta_path:
|
||||
for i, importer in enumerate(sys.meta_path):
|
||||
# Here's some real nastiness: Another "instance" of the six module might
|
||||
# be floating around. Therefore, we can't use isinstance() to check for
|
||||
# the six meta path importer, since the other six instance will have
|
||||
# inserted an importer with different class.
|
||||
if (type(importer).__name__ == "_SixMetaPathImporter" and
|
||||
importer.name == __name__):
|
||||
del sys.meta_path[i]
|
||||
break
|
||||
del i, importer
|
||||
# Finally, add the importer to the meta path import hook.
|
||||
sys.meta_path.append(_importer)
|
||||
133
bin/stop-test.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/* -------------------------------- REQUIRES -------------------------------- */
|
||||
|
||||
var child = require("child_process");
|
||||
var assert = require("assert");
|
||||
|
||||
/* --------------------------------- CONFIG --------------------------------- */
|
||||
|
||||
if (process.argv[2] == null) {
|
||||
[
|
||||
'Usage: ',
|
||||
'',
|
||||
' `node bin/stop-test.js i,j [rippled_path] [rippled_conf]`',
|
||||
'',
|
||||
' Launch rippled and stop it after n seconds for all n in [i, j}',
|
||||
' For all even values of n launch rippled with `--fg`',
|
||||
' For values of n where n % 3 == 0 launch rippled with `--fg`\n',
|
||||
'Examples: ',
|
||||
'',
|
||||
' $ node bin/stop-test.js 5,10',
|
||||
(' $ node bin/stop-test.js 1,4 ' +
|
||||
'build/clang.debug/rippled $HOME/.confs/rippled.cfg')
|
||||
]
|
||||
.forEach(function(l){console.log(l)});
|
||||
|
||||
process.exit();
|
||||
} else {
|
||||
var testRange = process.argv[2].split(',').map(Number);
|
||||
var rippledPath = process.argv[3] || 'build/rippled'
|
||||
var rippledConf = process.argv[4] || 'rippled.cfg'
|
||||
}
|
||||
|
||||
var options = {
|
||||
env: process.env,
|
||||
stdio: 'ignore' // we could dump the child io when it fails abnormally
|
||||
};
|
||||
|
||||
// default args
|
||||
var conf_args = ['--conf='+rippledConf];
|
||||
var start_args = conf_args.concat([/*'--net'*/])
|
||||
var stop_args = conf_args.concat(['stop']);
|
||||
|
||||
/* --------------------------------- HELPERS -------------------------------- */
|
||||
|
||||
function start(args) {
|
||||
return child.spawn(rippledPath, args, options);
|
||||
}
|
||||
function stop(rippled) { child.execFile(rippledPath, stop_args, options)}
|
||||
function secs_l8r(ms, f) {setTimeout(f, ms * 1000); }
|
||||
|
||||
function show_results_and_exit(results) {
|
||||
console.log(JSON.stringify(results, undefined, 2));
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var timeTakes = function (range) {
|
||||
function sumRange(n) {return (n+1) * n /2}
|
||||
var ret = sumRange(range[1]);
|
||||
if (range[0] > 1) {
|
||||
ret = ret - sumRange(range[0] - 1)
|
||||
}
|
||||
var stopping = (range[1] - range[0]) * 0.5;
|
||||
return ret + stopping;
|
||||
}
|
||||
|
||||
/* ---------------------------------- TEST ---------------------------------- */
|
||||
|
||||
console.log("Test will take ~%s seconds", timeTakes(testRange));
|
||||
|
||||
(function oneTest(n /* seconds */, results) {
|
||||
if (n >= testRange[1]) {
|
||||
// show_results_and_exit(results);
|
||||
console.log(JSON.stringify(results, undefined, 2));
|
||||
oneTest(testRange[0], []);
|
||||
return;
|
||||
}
|
||||
|
||||
var args = start_args;
|
||||
if (n % 2 == 0) {args = args.concat(['--fg'])}
|
||||
if (n % 3 == 0) {args = args.concat(['--net'])}
|
||||
|
||||
var result = {args: args, alive_for: n};
|
||||
results.push(result);
|
||||
|
||||
console.log("\nLaunching `%s` with `%s` for %d seconds",
|
||||
rippledPath, JSON.stringify(args), n);
|
||||
|
||||
rippled = start(args);
|
||||
console.log("Rippled pid: %d", rippled.pid);
|
||||
|
||||
// defaults
|
||||
var b4StopSent = false;
|
||||
var stopSent = false;
|
||||
var stop_took = null;
|
||||
|
||||
rippled.once('exit', function(){
|
||||
if (!stopSent && !b4StopSent) {
|
||||
console.warn('\nRippled exited itself b4 stop issued');
|
||||
process.exit();
|
||||
};
|
||||
|
||||
// The io handles close AFTER exit, may have implications for
|
||||
// `stdio:'inherit'` option to `child.spawn`.
|
||||
rippled.once('close', function() {
|
||||
result.stop_took = (+new Date() - stop_took) / 1000; // seconds
|
||||
console.log("Stopping after %d seconds took %s seconds",
|
||||
n, result.stop_took);
|
||||
oneTest(n+1, results);
|
||||
});
|
||||
});
|
||||
|
||||
secs_l8r(n, function(){
|
||||
console.log("Stopping rippled after %d seconds", n);
|
||||
|
||||
// possible race here ?
|
||||
// seems highly unlikely, but I was having issues at one point
|
||||
b4StopSent=true;
|
||||
stop_took = (+new Date());
|
||||
// when does `exit` actually get sent?
|
||||
stop();
|
||||
stopSent=true;
|
||||
|
||||
// Sometimes we want to attach with a debugger.
|
||||
if (process.env.ABORT_TESTS_ON_STALL != null) {
|
||||
// We wait 30 seconds, and if it hasn't stopped, we abort the process
|
||||
secs_l8r(30, function() {
|
||||
if (result.stop_took == null) {
|
||||
console.log("rippled has stalled");
|
||||
process.exit();
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
}(testRange[0], []));
|
||||
@@ -2,14 +2,38 @@
|
||||
|
||||
# Coding Standards
|
||||
|
||||
Coding standards used here are extreme strict and consistent. The style
|
||||
evolved gradually over the years, incorporating generally acknowledged
|
||||
best-practice C++ advice, experience, and personal preference.
|
||||
Coding standards used here gradually evolve and propagate through
|
||||
code reviews. Some aspects are enforced more strictly than others.
|
||||
|
||||
## Don't Repeat Yourself!
|
||||
## Rules
|
||||
|
||||
The [Don't Repeat Yourself][1] principle summarises the essence of what it
|
||||
means to write good code, in all languages, at all levels.
|
||||
These rules only apply to our own code. We can't enforce any sort of
|
||||
style on the external repositories and libraries we include. The best
|
||||
guideline is to maintain the standards that are used in those libraries.
|
||||
|
||||
* Tab inserts 4 spaces. No tab characters.
|
||||
* Braces are indented in the [Allman style][1].
|
||||
* Modern C++ principles. No naked ```new``` or ```delete```.
|
||||
* Line lengths limited to 80 characters. Exceptions limited to data and tables.
|
||||
|
||||
## Guidelines
|
||||
|
||||
If you want to do something contrary to these guidelines, understand
|
||||
why you're doing it. Think, use common sense, and consider that this
|
||||
your changes will probably need to be maintained long after you've
|
||||
moved on to other projects.
|
||||
|
||||
* Use white space and blank lines to guide the eye and keep your intent clear.
|
||||
* Put private data members at the top of a class, and the 6 public special
|
||||
members immediately after, in the following order:
|
||||
* Destructor
|
||||
* Default constructor
|
||||
* Copy constructor
|
||||
* Copy assignment
|
||||
* Move constructor
|
||||
* Move assignment
|
||||
* Don't over-inline by defining large functions within the class
|
||||
declaration, not even for template classes.
|
||||
|
||||
## Formatting
|
||||
|
||||
@@ -17,9 +41,6 @@ The goal of source code formatting should always be to make things as easy to
|
||||
read as possible. White space is used to guide the eye so that details are not
|
||||
overlooked. Blank lines are used to separate code into "paragraphs."
|
||||
|
||||
* No tab characters please.
|
||||
* Tab stops are set to 4 spaces.
|
||||
* Braces are indented in the [Allman style][2].
|
||||
* Always place a space before and after all binary operators,
|
||||
especially assignments (`operator=`).
|
||||
* The `!` operator should always be followed by a space.
|
||||
@@ -62,156 +83,4 @@ overlooked. Blank lines are used to separate code into "paragraphs."
|
||||
* Always place a space in between the template angle brackets and the type
|
||||
name. Template code is already hard enough to read!
|
||||
|
||||
## Naming conventions
|
||||
|
||||
* Member variables and method names are written with camel-case, and never
|
||||
begin with a capital letter.
|
||||
* Class names are also written in camel-case, but always begin with a capital
|
||||
letter.
|
||||
* For global variables... well, you shouldn't have any, so it doesn't matter.
|
||||
* Class data members begin with `m_`, static data members begin with `s_`.
|
||||
Global variables begin with `g_`. This is so the scope of the corresponding
|
||||
declaration can be easily determined.
|
||||
* Avoid underscores in your names, especially leading or trailing underscores.
|
||||
In particular, leading underscores should be avoided, as these are often used
|
||||
in standard library code, so to use them in your own code looks quite jarring.
|
||||
* If you really have to write a macro for some reason, then make it all caps,
|
||||
with underscores to separate the words. And obviously make sure that its name
|
||||
is unlikely to clash with symbols used in other libraries or 3rd party code.
|
||||
|
||||
## Types, const-correctness
|
||||
|
||||
* If a method can (and should!) be const, make it const!
|
||||
* If a method definitely doesn't throw an exception (be careful!), mark it as
|
||||
`noexcept`
|
||||
* When returning a temporary object, e.g. a String, the returned object should
|
||||
be non-const, so that if the class has a C++11 move operator, it can be used.
|
||||
* If a local variable can be const, then make it const!
|
||||
* Remember that pointers can be const as well as primitives; For example, if
|
||||
you have a `char*` whose contents are going to be altered, you may still be
|
||||
able to make the pointer itself const, e.g. `char* const foobar = getFoobar();`.
|
||||
* Do not declare all your local variables at the top of a function or method
|
||||
(i.e. in the old-fashioned C-style). Declare them at the last possible moment,
|
||||
and give them as small a scope as possible.
|
||||
* Object parameters should be passed as `const&` wherever possible. Only
|
||||
pass a parameter as a copy-by-value object if you really need to mutate
|
||||
a local copy inside the method, and if making a local copy inside the method
|
||||
would be difficult.
|
||||
* Use portable `for()` loop variable scoping (i.e. do not have multiple for
|
||||
loops in the same scope that each re-declare the same variable name, as
|
||||
this fails on older compilers)
|
||||
* When you're testing a pointer to see if it's null, never write
|
||||
`if (myPointer)`. Always avoid that implicit cast-to-bool by writing it more
|
||||
fully: `if (myPointer != nullptr)`. And likewise, never ever write
|
||||
`if (! myPointer)`, instead always write `if (myPointer == nullptr)`.
|
||||
It is more readable that way.
|
||||
* Avoid C-style casts except when converting between primitive numeric types.
|
||||
Some people would say "avoid C-style casts altogether", but `static_cast` is
|
||||
a bit unreadable when you just want to cast an `int` to a `float`. But
|
||||
whenever a pointer is involved, or a non-primitive object, always use
|
||||
`static_cast`. And when you're reinterpreting data, always use
|
||||
`reinterpret_cast`.
|
||||
* Until C++ gets a universal 64-bit primitive type (part of the C++11
|
||||
standard), it's best to stick to the `int64` and `uint64` typedefs.
|
||||
|
||||
## Object lifetime and ownership
|
||||
|
||||
* Absolutely do NOT use `delete`, `deleteAndZero`, etc. There are very very few
|
||||
situations where you can't use a `ScopedPointer` or some other automatic
|
||||
lifetime management class.
|
||||
* Do not use `new` unless there's no alternative. Whenever you type `new`, always
|
||||
treat it as a failure to find a better solution. If a local variable can be
|
||||
allocated on the stack rather than the heap, then always do so.
|
||||
* Do not ever use `new` or `malloc` to allocate a C++ array. Always use a
|
||||
`HeapBlock` instead.
|
||||
* And just to make it doubly clear: Never use `malloc` or `calloc`.
|
||||
* If a parent object needs to create and own some kind of child object, always
|
||||
use composition as your first choice. If that's not possible (e.g. if the
|
||||
child needs a pointer to the parent for its constructor), then use a
|
||||
`ScopedPointer`.
|
||||
* If possible, pass an object as a reference rather than a pointer. If possible,
|
||||
make it a `const` reference.
|
||||
* Obviously avoid static and global values. Sometimes there's no alternative,
|
||||
but if there is an alternative, then use it, no matter how much effort it
|
||||
involves.
|
||||
* If allocating a local POD structure (e.g. an operating-system structure in
|
||||
native code), and you need to initialise it with zeros, use the `= { 0 };`
|
||||
syntax as your first choice for doing this. If for some reason that's not
|
||||
appropriate, use the `zerostruct()` function, or in case that isn't suitable,
|
||||
use `zeromem()`. Don't use `memset()`.
|
||||
|
||||
## Classes
|
||||
|
||||
* Declare a class's public section first, and put its constructors and
|
||||
destructor first. Any protected items come next, and then private ones.
|
||||
* Use the most restrictive access-specifier possible for each member. Prefer
|
||||
`private` over `protected`, and `protected` over `public`. Don't expose
|
||||
things unnecessarily.
|
||||
* Preferred positioning for any inherited classes is to put them to the right
|
||||
of the class name, vertically aligned, e.g.:
|
||||
class Thing : public Foo,
|
||||
private Bar
|
||||
{
|
||||
}
|
||||
* Put a class's member variables (which should almost always be private, of course),
|
||||
after all the public and protected method declarations.
|
||||
* Any private methods can go towards the end of the class, after the member
|
||||
variables.
|
||||
* If your class does not have copy-by-value semantics, derive the class from
|
||||
`Uncopyable`.
|
||||
* If your class is likely to be leaked, then derive your class from
|
||||
`LeakChecked<>`.
|
||||
* Constructors that take a single parameter should be default be marked
|
||||
`explicit`. Obviously there are cases where you do want implicit conversion,
|
||||
but always think about it carefully before writing a non-explicit constructor.
|
||||
* Do not use `NULL`, `null`, or 0 for a null-pointer. And especially never use
|
||||
'0L', which is particulary burdensome. Use `nullptr` instead - this is the
|
||||
C++2011 standard, so get used to it. There's a fallback definition for `nullptr`
|
||||
in Beast, so it's always possible to use it even if your compiler isn't yet
|
||||
C++2011 compliant.
|
||||
* All the C++ 'guru' books and articles are full of excellent and detailed advice
|
||||
on when it's best to use inheritance vs composition. If you're not already
|
||||
familiar with the received wisdom in these matters, then do some reading!
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
* `goto` statements should not be used at all, even if the alternative is
|
||||
more verbose code. The only exception is when implementing an algorithm in
|
||||
a function as a state machine.
|
||||
* Don't use macros! OK, obviously there are many situations where they're the
|
||||
right tool for the job, but treat them as a last resort. Certainly don't ever
|
||||
use a macro just to hold a constant value or to perform any kind of function
|
||||
that could have been done as a real inline function. And it goes without saying
|
||||
that you should give them names which aren't going to clash with other code.
|
||||
And `#undef` them after you've used them, if possible.
|
||||
* When using the `++` or `--` operators, never use post-increment if
|
||||
pre-increment could be used instead. Although it doesn't matter for
|
||||
primitive types, it's good practice to pre-increment since this can be
|
||||
much more efficient for more complex objects. In particular, if you're
|
||||
writing a for loop, always use pre-increment,
|
||||
e.g. `for (int = 0; i < 10; ++i)`
|
||||
* Never put an "else" statement after a "return"! This is well-explained in the
|
||||
LLVM coding standards...and a couple of other very good pieces of advice from
|
||||
the LLVM standards are in there as well.
|
||||
* When getting a possibly-null pointer and using it only if it's non-null, limit
|
||||
the scope of the pointer as much as possible - e.g. Do NOT do this:
|
||||
|
||||
Foo* f = getFoo ();
|
||||
if (f != nullptr)
|
||||
f->doSomething ();
|
||||
// other code
|
||||
f->doSomething (); // oops! f may be null!
|
||||
|
||||
..instead, prefer to write it like this, which reduces the scope of the
|
||||
pointer, making it impossible to write code that accidentally uses a null
|
||||
pointer:
|
||||
|
||||
if (Foo* f = getFoo ())
|
||||
f->doSomethingElse ();
|
||||
|
||||
// f is out-of-scope here, so impossible to use it if it's null
|
||||
|
||||
(This also results in smaller, cleaner code)
|
||||
|
||||
[1]: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
|
||||
[2]: http://en.wikipedia.org/wiki/Indent_style#Allman_style
|
||||
[1]: http://en.wikipedia.org/wiki/Indent_style#Allman_style
|
||||
|
||||
2702
doc/Doxyfile
63
doc/HeapProfiling.md
Normal file
@@ -0,0 +1,63 @@
|
||||
## Heap profiling of rippled with jemalloc
|
||||
|
||||
The jemalloc library provides a good API for doing heap analysis,
|
||||
including a mechanism to dump a description of the heap from within the
|
||||
running application via a function call. Details on how to perform this
|
||||
activity in general, as well as how to acquire the software, are available on
|
||||
the jemalloc site:
|
||||
[https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling](https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling)
|
||||
|
||||
jemalloc is acquired separately from rippled, and is not affiliated
|
||||
with Ripple Labs. If you compile and install jemalloc from the
|
||||
source release with default options, it will install the library and header
|
||||
under `/usr/local/lib` and `/usr/local/include`, respectively. Heap
|
||||
profiling has been tested with rippled on a Linux platform. It should
|
||||
work on platforms on which both rippled and jemalloc are available.
|
||||
|
||||
To link rippled with jemalloc, the argument
|
||||
`profile-jemalloc=<jemalloc_dir>` is provided after the optional target.
|
||||
The `<jemalloc_dir>` argument should be the same as that of the
|
||||
`--prefix` parameter passed to the jemalloc configure script when building.
|
||||
|
||||
## Examples:
|
||||
|
||||
Build rippled with jemalloc library under /usr/local/lib and
|
||||
header under /usr/local/include:
|
||||
|
||||
$ scons profile-jemalloc=/usr/local
|
||||
|
||||
Build rippled using clang with the jemalloc library under /opt/local/lib
|
||||
and header under /opt/local/include:
|
||||
|
||||
$ scons clang profile-jemalloc=/opt/local
|
||||
|
||||
----------------------
|
||||
|
||||
## Using the jemalloc library from within the code
|
||||
|
||||
The `profile-jemalloc` parameter enables a macro definition called
|
||||
`PROFILE_JEMALLOC`. Include the jemalloc header file as
|
||||
well as the api call(s) that you wish to make within preprocessor
|
||||
conditional groups, such as:
|
||||
|
||||
In global scope:
|
||||
|
||||
#ifdef PROFILE_JEMALLOC
|
||||
#include <jemalloc/jemalloc.h>
|
||||
#endif
|
||||
|
||||
And later, within a function scope:
|
||||
|
||||
#ifdef PROFILE_JEMALLOC
|
||||
mallctl("prof.dump", NULL, NULL, NULL, 0);
|
||||
#endif
|
||||
|
||||
Fuller descriptions of how to acquire and use jemalloc's api to do memory
|
||||
analysis are available at the [jemalloc
|
||||
site.](http://www.canonware.com/jemalloc/)
|
||||
|
||||
Linking against the jemalloc library will override
|
||||
the system's default `malloc()` and related functions with jemalloc's
|
||||
implementation. This is the case even if the code is not instrumented
|
||||
to use jemalloc's specific API.
|
||||
|
||||
@@ -6,33 +6,35 @@
|
||||
#
|
||||
# Contents
|
||||
#
|
||||
# 1. Peer Networking
|
||||
# 1. Server
|
||||
#
|
||||
# 2. Websocket Networking
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
# 3. RPC Networking
|
||||
# 3. SMS Gateway
|
||||
#
|
||||
# 4. SMS Gateway
|
||||
# 4. Ripple Protocol
|
||||
#
|
||||
# 5. Ripple Protcol
|
||||
# 5. HTTPS Client
|
||||
#
|
||||
# 6. HTTPS Client
|
||||
# 6. Database
|
||||
#
|
||||
# 7. Database
|
||||
# 7. Diagnostics
|
||||
#
|
||||
# 8. Diagnostics
|
||||
# 8. Voting
|
||||
#
|
||||
# 9. Example Settings
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# This file documents and provides examples of all rippled server process
|
||||
# configuration options. When the rippled server instance is lanched, it looks
|
||||
# for a file with the following name:
|
||||
# configuration options. When the rippled server instance is launched, it
|
||||
# looks for a file with the following name:
|
||||
#
|
||||
# rippled.cfg
|
||||
#
|
||||
# For more information on where the rippled serer instance searches for
|
||||
# For more information on where the rippled server instance searches for
|
||||
# the file please visit the Ripple wiki. Specifically, the section explaining
|
||||
# the --conf command line option:
|
||||
#
|
||||
@@ -42,19 +44,235 @@
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
# Notation
|
||||
#
|
||||
# In this document a simple BNF notation is used. Angle brackets denote
|
||||
# required elements, square brackets denote optional elements, and single
|
||||
# quotes indicate string literals. A vertical bar separating 1 or more
|
||||
# elements is a logical "or"; Any one of the elements may be chosen.
|
||||
# Parenthesis are notational only, and used to group elements, they are not
|
||||
# part of the syntax unless they appear in quotes. White space may always
|
||||
# appear between elements, it has no effect on values.
|
||||
#
|
||||
# <key> A required identifier
|
||||
# '=' The equals sign character
|
||||
# | Logical "or"
|
||||
# ( ) Used for grouping
|
||||
#
|
||||
#
|
||||
# An identifier is a string of upper or lower case letters, digits, or
|
||||
# underscores subject to the requirement that the first character of an
|
||||
# identifier must be a letter. Identifiers are not case sensitive (but
|
||||
# values may be).
|
||||
#
|
||||
# Some configuration sections contain key/value pairs. A line containing
|
||||
# a key/value pair has this syntax:
|
||||
#
|
||||
# <identifier> '=' <value>
|
||||
#
|
||||
# Depending on the section and key, different value types are possible:
|
||||
#
|
||||
# <integer> A signed integer
|
||||
# <unsigned> An unsigned integer
|
||||
# <flag> A boolean. 1 = true/yes/on, 0 = false/no/off.
|
||||
#
|
||||
# Consult the documentation on the key in question to determine the possible
|
||||
# value types.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 1. Peer Networking
|
||||
# 1. Server
|
||||
#
|
||||
#-------------------
|
||||
#----------
|
||||
#
|
||||
#
|
||||
#
|
||||
# rippled offers various server protocols to clients making inbound
|
||||
# connections. The listening ports rippled uses are "universal" ports
|
||||
# which may be configured to handshake in one or more of the available
|
||||
# supported protocols. These universal ports simplify administration:
|
||||
# A single open port can be used for multiple protocols.
|
||||
#
|
||||
# NOTE At least one server port must be defined in order
|
||||
# to accept incoming network connections.
|
||||
#
|
||||
#
|
||||
# [server]
|
||||
#
|
||||
# A list of port names and key/value pairs. A port name must start with a
|
||||
# letter and contain only letters and numbers. The name is not case-sensitive.
|
||||
# For each name in this list, rippled will look for a configuration file
|
||||
# section with the same name and use it to create a listening port. The
|
||||
# name is informational only; the choice of name does not affect the function
|
||||
# of the listening port.
|
||||
#
|
||||
# Key/value pairs specified in this section are optional, and apply to all
|
||||
# listening ports unless the port overrides the value in its section. They
|
||||
# may be considered default values.
|
||||
#
|
||||
# Suggestion:
|
||||
#
|
||||
# To avoid a conflict with port names and future configuration sections,
|
||||
# we recommend prepending "port_" to the port name. This prefix is not
|
||||
# required, but suggested.
|
||||
#
|
||||
# This example defines two ports with different port numbers and settings:
|
||||
#
|
||||
# [server]
|
||||
# port_public
|
||||
# port_private
|
||||
# port = 80
|
||||
#
|
||||
# [port_public]
|
||||
# ip=0.0.0.0
|
||||
# port = 443
|
||||
# protocol=peer,https
|
||||
#
|
||||
# [port_private]
|
||||
# ip=127.0.0.1
|
||||
# protocol=http
|
||||
#
|
||||
# When rippled is used as a command line client (for example, issuing a
|
||||
# server stop command), the first port advertising the http or https
|
||||
# protocol will be used to make the connection.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [<name>]
|
||||
#
|
||||
# A series of key/value pairs that define the settings for the port with
|
||||
# the corresponding name. These keys are possible:
|
||||
#
|
||||
# ip = <IP-address>
|
||||
#
|
||||
# Required. Determines the IP address of the network interface to bind
|
||||
# to. To bind to all available interfaces, uses 0.0.0.0
|
||||
#
|
||||
# port = <number>
|
||||
#
|
||||
# Required. Sets the port number to use for this port.
|
||||
#
|
||||
# protocol = [ http, https, peer ]
|
||||
#
|
||||
# Required. A comma-separated list of protocols to support:
|
||||
#
|
||||
# http JSON-RPC over HTTP
|
||||
# https JSON-RPC over HTTPS
|
||||
# ws Websockets
|
||||
# wss Secure Websockets
|
||||
# peer Peer Protocol
|
||||
#
|
||||
# Restrictions:
|
||||
#
|
||||
# Only one port may be configured to support the peer protocol.
|
||||
# A port cannot have websocket and non websocket protocols at the
|
||||
# same time. It is possible have both Websockets and Secure Websockets
|
||||
# together in one port.
|
||||
#
|
||||
# NOTE If no ports support the peer protocol, rippled cannot
|
||||
# receive incoming peer connections or become a superpeer.
|
||||
#
|
||||
# user = <text>
|
||||
# password = <text>
|
||||
#
|
||||
# When set, these credentials will be required on HTTP/S requests.
|
||||
# The credentials must be provided using HTTP's Basic Authentication
|
||||
# headers. If either or both fields are empty, then no credentials are
|
||||
# required. IP address restrictions, if any, will be checked in addition
|
||||
# to the credentials specified here.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# using HTTP's Basic Authentication headers when making outbound HTTP/S
|
||||
# requests.
|
||||
#
|
||||
# admin = no | allow
|
||||
#
|
||||
# Controls whether or not administrative commands are allowed. These
|
||||
# commands may be issued over http, https, ws, or wss if configured
|
||||
# on the port. If unspecified, the default is to not allow
|
||||
# administrative commands.
|
||||
#
|
||||
# admin_user = <text>
|
||||
# admin_password = <text>
|
||||
#
|
||||
# When set, clients must provide these credentials in the submitted
|
||||
# JSON for any administrative command requests submitted to the HTTP/S,
|
||||
# WS, or WSS protocol interfaces. If administrative commands are
|
||||
# disabled for a port, these credentials have no effect.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# in the submitted JSON for any administrative command requests when
|
||||
# invoking JSON-RPC commands on remote servers.
|
||||
#
|
||||
# ssl_key = <filename>
|
||||
# ssl_cert = <filename>
|
||||
# ssl_chain = <filename>
|
||||
#
|
||||
# Use the specified files when configuring SSL on the port.
|
||||
#
|
||||
# NOTE If no files are specified and secure protocols are selected,
|
||||
# rippled will generate an internal self-signed certificate.
|
||||
#
|
||||
# The files have these meanings:
|
||||
#
|
||||
# ssl_key
|
||||
#
|
||||
# Specifies the filename holding the SSL key in PEM format.
|
||||
#
|
||||
# ssl_cert
|
||||
#
|
||||
# Specifies the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
# ssl_chain
|
||||
#
|
||||
# If you need a certificate chain, specify the path to the
|
||||
# certificate chain here. The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_allow]
|
||||
#
|
||||
# Specify a list of IP addresses allowed to have admin access. One per line.
|
||||
# If you want to test the output of non-admin commands add this section and
|
||||
# just put an ip address not under your control.
|
||||
# Defaults to 127.0.0.1.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ping_frequency]
|
||||
#
|
||||
# <number>
|
||||
#
|
||||
# The amount of time to wait in seconds, before sending a websocket 'ping'
|
||||
# message. Ping messages are used to determine if the remote end of the
|
||||
# connection is no longer available.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
#-----------------
|
||||
#
|
||||
# These settings control security and access attributes of the Peer to Peer
|
||||
# server section of the rippled process. Peer Networking implements the
|
||||
# server section of the rippled process. Peer Protocol implements the
|
||||
# Ripple Payment protocol. It is over peer connections that transactions
|
||||
# and validations are passed from to machine to machine, to make up the
|
||||
# components of closed ledgers.
|
||||
# and validations are passed from to machine to machine, to determine the
|
||||
# contents of validated ledgers.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -93,40 +311,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
# Defaults to not binding, which disallows external connections from peers.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_port]
|
||||
#
|
||||
# If peer_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_port_proxy]
|
||||
#
|
||||
# An optional, additional listening port number for peers. Incoming
|
||||
# connections on this port will be required to provide a PROXY Protocol
|
||||
# handshake, described in this document (external link):
|
||||
#
|
||||
# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
|
||||
#
|
||||
# The PROXY Protocol is a popular method used by elastic load balancing
|
||||
# service providers such as Amazon, to identify the true IP address and
|
||||
# port number of external incoming connections.
|
||||
#
|
||||
# In addition to enabling this setting, it will also be required to
|
||||
# use your provider-specific control panel or administrative web page
|
||||
# to configure your server instance to receive PROXY Protocol handshakes,
|
||||
# and also to restrict access to your instance to the Elastic Load Balancer.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_private]
|
||||
#
|
||||
# 0 or 1.
|
||||
@@ -136,7 +320,7 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [max_peers]
|
||||
# [peers_max]
|
||||
#
|
||||
# The largest number of desired peer connections (incoming or outgoing).
|
||||
# Cluster and fixed peers do not count towards this total. There are
|
||||
@@ -145,19 +329,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_ssl_cipher_list]
|
||||
#
|
||||
# A colon delimited string with the allowed SSL cipher modes for peer. The
|
||||
# choices for for ciphers are defined by the OpenSSL API function
|
||||
# SSL_CTX_set_cipher_list, documented here (external link):
|
||||
#
|
||||
# http://pic.dhe.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_ssl_ctx_set_cipher_list.html
|
||||
#
|
||||
# The default setting is "ALL:!LOW:!EXP:!MD5:@STRENGTH", which allows
|
||||
# non-authenticated peer connections (they are, however, secure).
|
||||
#
|
||||
#
|
||||
#
|
||||
# [node_seed]
|
||||
#
|
||||
# This is used for clustering. To force a particular node seed or key, the
|
||||
@@ -191,243 +362,49 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
# [overlay] EXPERIMENTAL
|
||||
#
|
||||
# 2. Websocket Networking
|
||||
# This section is EXPERIMENTAL, and should not be
|
||||
# present for production configuration settings.
|
||||
#
|
||||
#------------------------
|
||||
# A set of key/value pair parameters to configure the overlay.
|
||||
#
|
||||
# These settings control security and access attributes of the Websocket
|
||||
# server section of the rippled process, primarily used to service
|
||||
# client requests and backend applications.
|
||||
# auto_connect = 0 | 1
|
||||
#
|
||||
# When set, activates the autoconnect feature. This maintains outgoing
|
||||
# connections using PeerFinder's "Outgoing Connection Strategy."
|
||||
#
|
||||
# http_handshake = 0 | 1
|
||||
#
|
||||
# [websocket_public_ip]
|
||||
# When set, outgoing peer connections will handshaking using a HTTP
|
||||
# request instead of the legacy TMHello protocol buffers message.
|
||||
# Incoming peer connections have their handshakes detected automatically.
|
||||
#
|
||||
# IP address or domain to bind to allow untrusted connections from clients.
|
||||
# In the future, this option will go away and the peer_ip will accept
|
||||
# websocket client connections.
|
||||
# become_superpeer = 'never' | 'always' | 'auto'
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
# Controls the selection of peer roles:
|
||||
#
|
||||
# 'never' Always handshake in the leaf role.
|
||||
# 'always' Always handshake in the superpeer role.
|
||||
# 'auto' Start as a leaf, promote to superpeer after
|
||||
# passing capability check (default).
|
||||
#
|
||||
# In the leaf role, a peer does not advertise its IP and port for
|
||||
# the purpose of receiving incoming connections. The peer also does
|
||||
# not forward transactions and validations received from other peers.
|
||||
#
|
||||
# [websocket_public_port]
|
||||
#
|
||||
# Port to bind to allow untrusted connections from clients. In the future,
|
||||
# this option will go away and the peer_ip will accept websocket client
|
||||
# connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_public_secure]
|
||||
#
|
||||
# 0, 1 or 2.
|
||||
# 0: Provide ws service for websocket_public_ip/websocket_public_port.
|
||||
# 1: Provide both ws and wss service for websocket_public_ip/websocket_public_port. [default]
|
||||
# 2: Provide wss service only for websocket_public_ip/websocket_public_port.
|
||||
#
|
||||
# Browser pages like the Ripple client will not be able to connect to a secure
|
||||
# websocket connection if a self-signed certificate is used. As the Ripple
|
||||
# reference client currently shares secrets with its server, this should be
|
||||
# enabled.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ping_frequency]
|
||||
#
|
||||
# <number>
|
||||
#
|
||||
# The amount of time to wait in seconds, before sending a websocket 'ping'
|
||||
# message. Ping messages are used to determine if the remote end of the
|
||||
# connection is no longer availabile.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow trusted ADMIN connections from backend
|
||||
# applications.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_port]
|
||||
#
|
||||
# Port to bind to allow trusted ADMIN connections from backend applications.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_secure]
|
||||
#
|
||||
# 0, 1, or 2.
|
||||
# 0: Provide ws service only for websocket_ip/websocket_port. [default]
|
||||
# 1: Provide ws and wss service for websocket_ip/websocket_port
|
||||
# 2: Provide wss service for websocket_ip/websocket_port.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_cert]
|
||||
#
|
||||
# Specify the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_chain]
|
||||
#
|
||||
# If you need a certificate chain, specify the path to the certificate chain
|
||||
# here. The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_key]
|
||||
#
|
||||
# Specify the filename holding the SSL key in PEM format.
|
||||
# In the superpeer role, a peer advertises its IP and port for
|
||||
# receiving incoming connections after passing an incoming connection
|
||||
# test. Superpeers forward transactions and protocol messages to all
|
||||
# other peers. Superpeers do not forward validations to other superpeers.
|
||||
# Instead, a validation received by a superpeer from a leaf is forwarded
|
||||
# only to other leaf connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 3. RPC Networking
|
||||
#
|
||||
#------------------
|
||||
#
|
||||
# This group of settings configures security and access attributes of the
|
||||
# RPC server section of the rippled process, used to service both local
|
||||
# an optional remote clients.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_allow_remote]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0: Allow RPC connections only from 127.0.0.1. [default]
|
||||
# 1: Allow RPC connections from any IP.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_allow]
|
||||
#
|
||||
# Specify an list of IP addresses allowed to have admin access. One per line.
|
||||
# If you want to test the output of non-admin commands add this section and
|
||||
# just put an ip address not under your control.
|
||||
# Defaults to 127.0.0.1.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_user]
|
||||
#
|
||||
# As a server, require this as the admin user to be specified. Also, require
|
||||
# rpc_admin_user and rpc_admin_password to be checked for RPC admin functions.
|
||||
# The request must specify these as the admin_user and admin_password in the
|
||||
# request object.
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_password]
|
||||
#
|
||||
# As a server, require this as the admin pasword to be specified. Also,
|
||||
# require rpc_admin_user and rpc_admin_password to be checked for RPC admin
|
||||
# functions. The request must specify these as the admin_user and
|
||||
# admin_password in the request object.
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow insecure RPC connections.
|
||||
# Defaults to not binding, which disallows RPC connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_port]
|
||||
#
|
||||
# If rpc_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_user]
|
||||
#
|
||||
# As a server, require a this user to specified and require rpc_password to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_password]
|
||||
#
|
||||
# As a server, require a this password to specified and require rpc_user to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_secure]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0: Server certificates are not provided for RPC clients using SSL [default]
|
||||
# 1: Client RPC connections wil be provided with SSL certificates.
|
||||
#
|
||||
# Note that if rpc_secure is enabled, it will also be necessasry to configure the
|
||||
# certificate file settings located in rpc_ssl_cert, rpc_ssl_chain, and rpc_ssl_key
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_cert]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the SSL certificate file to use for secure RPC.
|
||||
# The file is in PEM format. The file is not needed if the chain includes it.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_chain]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the file with the certificate chain.
|
||||
# The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_key]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the file with the SSL key.
|
||||
# The file is in PEM format.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 4. SMS Gateway
|
||||
# 3. SMS Gateway
|
||||
#
|
||||
#---------------
|
||||
#
|
||||
@@ -444,7 +421,7 @@
|
||||
#
|
||||
# [sms_url]?from=[sms_from]&to=[sms_to]&api_key=[sms_key]&api_secret=[sms_secret]&text=['text']
|
||||
#
|
||||
# Where [...] are the corresponding valus from the configuration file, and
|
||||
# Where [...] are the corresponding values from the configuration file, and
|
||||
# ['test'] is the value of the JSON field with name 'text'.
|
||||
#
|
||||
# [sms_url]
|
||||
@@ -463,9 +440,9 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 5. Ripple Protocol
|
||||
# 4. Ripple Protocol
|
||||
#
|
||||
#------------------
|
||||
#-------------------
|
||||
#
|
||||
# These settings affect the behavior of the server instance with respect
|
||||
# to Ripple payment protocol level activities such as validating and
|
||||
@@ -504,6 +481,13 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ledger_history_index]
|
||||
#
|
||||
# If set to greater than 0, the index number of the earliest ledger to
|
||||
# acquire.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [fetch_depth]
|
||||
#
|
||||
# The number of past ledgers to serve to other peers that request historical
|
||||
@@ -538,8 +522,8 @@
|
||||
# For domains, rippled will probe for https web servers at the specified
|
||||
# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# For public key entries, a comment may optionally be spcified after adding a
|
||||
# space to the pulic key.
|
||||
# For public key entries, a comment may optionally be specified after adding
|
||||
# a space to the public key.
|
||||
#
|
||||
# Examples:
|
||||
# ripple.com
|
||||
@@ -587,20 +571,27 @@
|
||||
#
|
||||
# [path_search_fast]
|
||||
# [path_search_max]
|
||||
# When seaching for paths, the minimum and maximum search aggressiveness.
|
||||
# When searching for paths, the minimum and maximum search aggressiveness.
|
||||
#
|
||||
# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 10.
|
||||
#
|
||||
# [path_search_old]
|
||||
#
|
||||
# For clients that use the legacy path finding interfaces, the search
|
||||
# agressiveness to use. The default is 7.
|
||||
# agressivness to use. The default is 7.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [fee_default]
|
||||
#
|
||||
# Sets the base cost of a transaction in drops. Used when the server has
|
||||
# no other source of fee information, such as signing transactions offline.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 6. HTTPS Client
|
||||
# 5. HTTPS Client
|
||||
#
|
||||
#----------------
|
||||
#
|
||||
@@ -614,7 +605,9 @@
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0. HTTPS client connections will not verify certificates.
|
||||
# 1. Certificates will be checked for HTTPS client connections .
|
||||
# 1. Certificates will be checked for HTTPS client connections.
|
||||
#
|
||||
# If not specified, this parameter defaults to 1.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -640,7 +633,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 7. Database
|
||||
# 6. Database
|
||||
#
|
||||
#------------
|
||||
#
|
||||
@@ -675,19 +668,28 @@
|
||||
# Examples:
|
||||
# type=HyperLevelDB
|
||||
# path=db/hyperldb
|
||||
# compression=0
|
||||
#
|
||||
# Choices for 'type' (not case-sensitive)
|
||||
# HyperLevelDB Use an improved version of LevelDB (preferred)
|
||||
# LevelDB Use Google's LevelDB database (deprecated)
|
||||
# none Use no backend
|
||||
# RocksDB Use Facebook's RocksDB database
|
||||
# SQLite Use SQLite
|
||||
# RocksDB Use Facebook's RocksDB database (preferred)
|
||||
# NuDB Use Ripple Labs' NuDB (Windows preferred)
|
||||
# HyperLevelDB (Deprecated)
|
||||
# SQLite (Deprecated)
|
||||
# LevelDB (Deprecated)
|
||||
# none (No backend)
|
||||
#
|
||||
# Required keys:
|
||||
# path Location to store the database (all types)
|
||||
#
|
||||
# Optional keys:
|
||||
# (none yet)
|
||||
# compression 0 for none, 1 for Snappy compression
|
||||
# online_delete Minimum value of 256. Enable automatic purging
|
||||
# of older ledger information. Maintain at least this
|
||||
# number of ledger records online. Must be greater
|
||||
# than or equal to ledger_history.
|
||||
# advisory_delete 0 for disabled, 1 for enabled. If set, then
|
||||
# require administrative RPC call "can_delete"
|
||||
# to enable online deletion of ledger records.
|
||||
#
|
||||
# Notes:
|
||||
# The 'node_db' entry configures the primary, persistent storage.
|
||||
@@ -712,7 +714,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 8. Diagnostics
|
||||
# 7. Diagnostics
|
||||
#
|
||||
#---------------
|
||||
#
|
||||
@@ -767,41 +769,135 @@
|
||||
# prefix=my_validator
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Allow other peers to connect to this server.
|
||||
#
|
||||
[peer_ip]
|
||||
0.0.0.0
|
||||
|
||||
[peer_port]
|
||||
51235
|
||||
|
||||
# Allow untrusted clients to connect to this server.
|
||||
# 8. Voting
|
||||
#
|
||||
[websocket_public_ip]
|
||||
0.0.0.0
|
||||
|
||||
[websocket_public_port]
|
||||
5006
|
||||
|
||||
# Provide trusted websocket ADMIN access to the localhost.
|
||||
#----------
|
||||
#
|
||||
[websocket_ip]
|
||||
127.0.0.1
|
||||
|
||||
[websocket_port]
|
||||
6006
|
||||
|
||||
# Provide trusted json-rpc ADMIN access to the localhost.
|
||||
# The vote settings configure settings for the entire Ripple network.
|
||||
# While a single instance of rippled cannot unilaterally enforce network-wide
|
||||
# settings, these choices become part of the instance's vote during the
|
||||
# consensus process for each voting ledger.
|
||||
#
|
||||
[rpc_ip]
|
||||
127.0.0.1
|
||||
# [voting]
|
||||
#
|
||||
# A set of key/value pair parameters used during voting ledgers.
|
||||
#
|
||||
# reference_fee = <drops>
|
||||
#
|
||||
# The cost of the reference transaction fee, specified in drops.
|
||||
# The reference transaction is the simplest form of transaction.
|
||||
# It represents an XRP payment between two parties.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# reference_fee = 10 # 10 drops
|
||||
#
|
||||
# account_reserve = <drops>
|
||||
#
|
||||
# The account reserve requirement specified in drops. The portion of an
|
||||
# account's XRP balance that is at or below the reserve may only be
|
||||
# spent on transaction fees, and not transferred out of the account.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# account_reserve = 20000000 # 20 XRP
|
||||
#
|
||||
# owner_reserve = <drops>
|
||||
#
|
||||
# The owner reserve is the amount of XRP reserved in the account for
|
||||
# each ledger item owned by the account. Ledger items an account may
|
||||
# own include trust lines, open orders, and tickets.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# owner_reserve = 5000000 # 5 XRP
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Example Settings
|
||||
#
|
||||
#--------------------
|
||||
#
|
||||
# Administrators can use these values as a starting poing for configuring
|
||||
# their instance of rippled, but each value should be checked to make sure
|
||||
# it meets the business requirements for the organization.
|
||||
#
|
||||
# Server
|
||||
#
|
||||
# These example configuration settings create these ports:
|
||||
#
|
||||
# "peer"
|
||||
#
|
||||
# Peer protocol open to everyone. This is required to accept
|
||||
# incoming rippled connections. This does not affect automatic
|
||||
# or manual outgoing Peer protocol connections.
|
||||
#
|
||||
# "rpc"
|
||||
#
|
||||
# Administrative RPC commands over HTTPS, when originating from
|
||||
# the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# "wss_admin"
|
||||
#
|
||||
# Admin level API commands over Secure Websockets, when originating
|
||||
# from the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# This port is commented out but can be enabled by removing
|
||||
# the '#' from each corresponding line including the entry under [server]
|
||||
#
|
||||
# "wss_public"
|
||||
#
|
||||
# Guest level API commands over Secure Websockets, open to everyone.
|
||||
#
|
||||
# For HTTPS and Secure Websockets ports, if no certificate and key file
|
||||
# are specified then a self-signed certificate will be generated on startup.
|
||||
# If you have a certificate and key file, uncomment the corresponding lines
|
||||
# and ensure the paths to the files are correct.
|
||||
#
|
||||
# NOTE
|
||||
#
|
||||
# To accept connections on well known ports such as 80 (HTTP) or
|
||||
# 443 (HTTPS), most operating systems will require rippled to
|
||||
# run with administrator privileges, or else rippled will not start.
|
||||
|
||||
[rpc_port]
|
||||
5005
|
||||
[server]
|
||||
port_rpc
|
||||
port_peer
|
||||
port_wss_admin
|
||||
#port_ws_public
|
||||
#ssl_key = /etc/ssl/private/server.key
|
||||
#ssl_cert = /etc/ssl/certs/server.crt
|
||||
|
||||
[rpc_allow_remote]
|
||||
0
|
||||
[port_rpc]
|
||||
port = 5005
|
||||
ip = 127.0.0.1
|
||||
admin = allow
|
||||
protocol = https
|
||||
|
||||
[port_peer]
|
||||
port = 51235
|
||||
ip = 0.0.0.0
|
||||
protocol = peer
|
||||
|
||||
[port_wss_admin]
|
||||
port = 6006
|
||||
ip = 127.0.0.1
|
||||
admin = allow
|
||||
protocol = wss
|
||||
|
||||
#[port_ws_public]
|
||||
#port = 5005
|
||||
#ip = 127.0.0.1
|
||||
#protocol = wss
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
[node_size]
|
||||
medium
|
||||
@@ -809,6 +905,8 @@ medium
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found here: https://ripple.com/wiki/NodeBackEnd
|
||||
# delete old ledgers while maintaining at least 2000. Do not require an
|
||||
# external administrative command to initiate deletion.
|
||||
[node_db]
|
||||
type=RocksDB
|
||||
path=/var/lib/rippled/db/rocksdb
|
||||
@@ -817,6 +915,8 @@ filter_bits=12
|
||||
cache_mb=256
|
||||
file_size_mb=8
|
||||
file_size_mult=2
|
||||
online_delete=2000
|
||||
advisory_delete=0
|
||||
|
||||
[database_path]
|
||||
/var/lib/rippled/db
|
||||
@@ -837,8 +937,9 @@ pool.ntp.org
|
||||
[ips]
|
||||
r.ripple.com 51235
|
||||
|
||||
# These validators are taken from the v0.16 release notes on the wiki:
|
||||
# https://ripple.com/wiki/Latest_rippled_release_notes
|
||||
# The latest validators can be obtained from
|
||||
# https://ripple.com/ripple.txt
|
||||
#
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
@@ -855,22 +956,7 @@ n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
[rpc_startup]
|
||||
{ "command": "log_level", "severity": "warning" }
|
||||
|
||||
# Configure SSL for WebSockets. Not enabled by default because not everybody
|
||||
# has an SSL cert on their server, but if you uncomment the following lines and
|
||||
# set the path to the SSL certificate and private key the WebSockets protocol
|
||||
# will be protected by SSL/TLS.
|
||||
#[websocket_secure]
|
||||
#1
|
||||
|
||||
#[websocket_ssl_cert]
|
||||
#/etc/ssl/certs/server.crt
|
||||
|
||||
#[websocket_ssl_key]
|
||||
#/etc/ssl/private/server.key
|
||||
|
||||
# Defaults to 0 ("no") so that you can use self-signed SSL certificates for
|
||||
# development, or internally.
|
||||
# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
|
||||
# of self-signed certificates for development or internal use, set to 0 ("no").
|
||||
#[ssl_verify]
|
||||
#0
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#
|
||||
|
||||
[validators]
|
||||
n9KPnVLn7ewVzHvn218DcEYsnWLzKerTDwhpofhk4Ym1RUq4TeGw first
|
||||
n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V second
|
||||
n94rSdgTyBNGvYg8pZXGuNt59Y5bGAZGxbxyvjDaqD9ceRAgD85P third
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
BIN
images/build.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
images/contribute.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
images/network.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
images/pathfinding.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
images/ripple.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
images/transact.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
images/vehicle_currency.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
@@ -2,33 +2,28 @@
|
||||
"name": "rippled",
|
||||
"version": "0.0.1",
|
||||
"description": "Rippled Server",
|
||||
|
||||
"private": true,
|
||||
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"ripple-lib": "0.7.25",
|
||||
"ripple-lib": "0.8.2",
|
||||
"async": "~0.2.9",
|
||||
"extend": "~1.2.0",
|
||||
"simple-jsonrpc": "~0.0.2",
|
||||
"deep-equal": "0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assert-diff": "^1.0.1",
|
||||
"coffee-script": "~1.6.3",
|
||||
"mocha": "~1.13.0"
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"test": "mocha test/websocket-test.js test/server-test.js test/*-test.{js,coffee}"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/ripple/rippled.git"
|
||||
},
|
||||
|
||||
"readmeFilename": "README.md"
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2009 Scott Stafford
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
# Author : Scott Stafford
|
||||
# Date : 2009-12-09 20:36:14
|
||||
#
|
||||
# Changes : Vinnie Falco <vinnie.falco@gmail.com>
|
||||
# Date : 2014--4-25
|
||||
|
||||
"""
|
||||
protoc.py: Protoc Builder for SCons
|
||||
|
||||
This Builder invokes protoc to generate C++ and Python from a .proto file.
|
||||
|
||||
NOTE: Java is not currently supported.
|
||||
"""
|
||||
|
||||
__author__ = "Scott Stafford"
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Node.FS
|
||||
import SCons.Util
|
||||
|
||||
from SCons.Script import File, Dir
|
||||
|
||||
import os.path
|
||||
|
||||
protocs = 'protoc'
|
||||
|
||||
ProtocAction = SCons.Action.Action('$PROTOCCOM', '$PROTOCCOMSTR')
|
||||
|
||||
def ProtocEmitter(target, source, env):
|
||||
PROTOCOUTDIR = env['PROTOCOUTDIR']
|
||||
PROTOCPYTHONOUTDIR = env['PROTOCPYTHONOUTDIR']
|
||||
for source_path in [str(x) for x in source]:
|
||||
base = os.path.splitext(os.path.basename(source_path))[0]
|
||||
if PROTOCOUTDIR:
|
||||
target.extend([os.path.join(PROTOCOUTDIR, base + '.pb.cc'),
|
||||
os.path.join(PROTOCOUTDIR, base + '.pb.h')])
|
||||
if PROTOCPYTHONOUTDIR:
|
||||
target.append(os.path.join(PROTOCPYTHONOUTDIR, base + '_pb2.py'))
|
||||
|
||||
try:
|
||||
target.append(env['PROTOCFDSOUT'])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
#print "PROTOC SOURCE:", [str(s) for s in source]
|
||||
#print "PROTOC TARGET:", [str(s) for s in target]
|
||||
|
||||
return target, source
|
||||
|
||||
ProtocBuilder = SCons.Builder.Builder(action = ProtocAction,
|
||||
emitter = ProtocEmitter,
|
||||
srcsuffix = '$PROTOCSRCSUFFIX')
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for protoc to an Environment."""
|
||||
try:
|
||||
bld = env['BUILDERS']['Protoc']
|
||||
except KeyError:
|
||||
bld = ProtocBuilder
|
||||
env['BUILDERS']['Protoc'] = bld
|
||||
|
||||
env['PROTOC'] = env.Detect(protocs) or 'protoc'
|
||||
env['PROTOCFLAGS'] = SCons.Util.CLVar('')
|
||||
env['PROTOCPROTOPATH'] = SCons.Util.CLVar('')
|
||||
env['PROTOCCOM'] = '$PROTOC ${["-I%s"%x for x in PROTOCPROTOPATH]} $PROTOCFLAGS --cpp_out=$PROTOCCPPOUTFLAGS$PROTOCOUTDIR ${PROTOCPYTHONOUTDIR and ("--python_out="+PROTOCPYTHONOUTDIR) or ""} ${PROTOCFDSOUT and ("-o"+PROTOCFDSOUT) or ""} ${SOURCES}'
|
||||
env['PROTOCOUTDIR'] = '${SOURCE.dir}'
|
||||
env['PROTOCPYTHONOUTDIR'] = "python"
|
||||
env['PROTOCSRCSUFFIX'] = '.proto'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(protocs)
|
||||
2
src/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
# boost subtree
|
||||
/boost
|
||||
@@ -57,18 +57,6 @@
|
||||
//#define BEAST_FORCE_DEBUG 1
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_LOG_ASSERTIONS
|
||||
If this flag is enabled, the the bassert and bassertfalse macros will always
|
||||
use Logger::writeToLog() to write a message when an assertion happens.
|
||||
Enabling it will also leave this turned on in release builds. When it's
|
||||
disabled, however, the bassert and bassertfalse macros will not be compiled
|
||||
in a release build.
|
||||
@see bassert, bassertfalse, Logger
|
||||
*/
|
||||
#ifndef BEAST_LOG_ASSERTIONS
|
||||
//#define BEAST_LOG_ASSERTIONS 1
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_CHECK_MEMORY_LEAKS
|
||||
Enables a memory-leak check for certain objects when the app terminates.
|
||||
See the LeakChecked class for more details about enabling leak checking for
|
||||
@@ -78,17 +66,6 @@
|
||||
//#define BEAST_CHECK_MEMORY_LEAKS 0
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
Setting this option makes Socket-derived classes generate compile errors
|
||||
if they forget any of the virtual overrides As some Socket-derived classes
|
||||
intentionally omit member functions that are not applicable, this macro
|
||||
should only be enabled temporarily when writing your own Socket-derived
|
||||
class, to make sure that the function signatures match as expected.
|
||||
*/
|
||||
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
//#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Libraries
|
||||
@@ -166,16 +143,6 @@
|
||||
#define RIPPLE_DUMP_LEAKS_ON_EXIT 1
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_TRACK_MUTEXES
|
||||
Turns on a feature that enables tracking and diagnostics for mutex
|
||||
and recursive mutex objects. This affects the type of lock used
|
||||
by RippleMutex and RippleRecursiveMutex
|
||||
@note This can slow down performance considerably.
|
||||
*/
|
||||
#ifndef RIPPLE_TRACK_MUTEXES
|
||||
#define RIPPLE_TRACK_MUTEXES 0
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// These control whether or not certain functionality gets
|
||||
@@ -200,19 +167,48 @@
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_USE_BOOST_FEATURES
|
||||
This activates boost specific features and improvements. If this is
|
||||
turned on, the include paths for your build environment must be set
|
||||
correctly to find the boost headers.
|
||||
This activates boost specific features and improvements. If this is
|
||||
turned on, the include paths for your build environment must be set
|
||||
correctly to find the boost headers.
|
||||
*/
|
||||
#ifndef BEAST_USE_BOOST_FEATURES
|
||||
//#define BEAST_USE_BOOST_FEATURES 1
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_PROPOSE_FEATURES
|
||||
This determines whether to add any features to the proposed transaction set.
|
||||
This determines whether to add any features to the proposed transaction set.
|
||||
*/
|
||||
#ifndef RIPPLE_PROPOSE_FEATURES
|
||||
#define RIPPLE_PROPOSE_FEATURES 0
|
||||
#ifndef RIPPLE_PROPOSE_AMENDMENTS
|
||||
#define RIPPLE_PROPOSE_AMENDMENTS 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_ENABLE_AUTOBRIDGING
|
||||
This determines whether ripple implements offer autobridging via XRP.
|
||||
*/
|
||||
#ifndef RIPPLE_ENABLE_AUTOBRIDGING
|
||||
#define RIPPLE_ENABLE_AUTOBRIDGING 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_SINGLE_IO_SERVICE_THREAD
|
||||
When set, restricts the number of threads calling io_service::run to one.
|
||||
This is useful when debugging.
|
||||
*/
|
||||
#ifndef RIPPLE_SINGLE_IO_SERVICE_THREAD
|
||||
#define RIPPLE_SINGLE_IO_SERVICE_THREAD 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_HOOK_VALIDATORS
|
||||
Activates code for handling validations and validators (work in progress).
|
||||
*/
|
||||
#ifndef RIPPLE_HOOK_VALIDATORS
|
||||
#define RIPPLE_HOOK_VALIDATORS 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_ENABLE_TICKETS
|
||||
Enables processing of ticket transactions
|
||||
*/
|
||||
#ifndef RIPPLE_ENABLE_TICKETS
|
||||
#define RIPPLE_ENABLE_TICKETS 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# src
|
||||
|
||||
Some of these directories come from entire outside repositories
|
||||
brought in using git-subtree. This means that the source files are
|
||||
inserted directly into the rippled repository. They can be edited
|
||||
and committed just as if they were normal files.
|
||||
Some of these directories come from entire outside repositories brought in
|
||||
using git-subtree. This means that the source files are inserted directly
|
||||
into the rippled repository. They can be edited and committed just as if they
|
||||
were normal files.
|
||||
|
||||
However, if you create a commit that contains files both from a
|
||||
subtree, and from the ripple source tree please use care when designing
|
||||
@@ -99,7 +99,7 @@ ripple-fork
|
||||
## protobuf
|
||||
|
||||
Ripple's fork of protobuf. We've changed some names in order to support the
|
||||
unity-style of build (a single .cpp addded to the project, instead of
|
||||
unity-style of build (a single .cpp added to the project, instead of
|
||||
linking to a separately built static library).
|
||||
|
||||
Repository
|
||||
|
||||
@@ -55,18 +55,6 @@
|
||||
//#define BEAST_FORCE_DEBUG 1
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_LOG_ASSERTIONS
|
||||
If this flag is enabled, the the bassert and bassertfalse macros will always
|
||||
use Logger::writeToLog() to write a message when an assertion happens.
|
||||
Enabling it will also leave this turned on in release builds. When it's
|
||||
disabled, however, the bassert and bassertfalse macros will not be compiled
|
||||
in a release build.
|
||||
@see bassert, bassertfalse, Logger
|
||||
*/
|
||||
#ifndef BEAST_LOG_ASSERTIONS
|
||||
//#define BEAST_LOG_ASSERTIONS 1
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_CHECK_MEMORY_LEAKS
|
||||
Enables a memory-leak check for certain objects when the app terminates.
|
||||
See the LeakChecked class for more details about enabling leak checking for
|
||||
@@ -76,17 +64,6 @@
|
||||
//#define BEAST_CHECK_MEMORY_LEAKS 0
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
Setting this option makes Socket-derived classes generate compile errors
|
||||
if they forget any of the virtual overrides As some Socket-derived classes
|
||||
intentionally omit member functions that are not applicable, this macro
|
||||
should only be enabled temporarily when writing your own Socket-derived
|
||||
class, to make sure that the function signatures match as expected.
|
||||
*/
|
||||
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
//#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Libraries
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<RepoDir>..\..</RepoDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PreprocessorDefinitions>BEAST_INCLUDE_BEASTCONFIG=1;_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<BuildMacro Include="RepoDir">
|
||||
<Value>$(RepoDir)</Value>
|
||||
</BuildMacro>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,228 +0,0 @@
|
||||
Write code in a clear, self-documenting style but use comments where necessary.
|
||||
Use Test Driven Development. It encourages designing interfaces first, before implementation.
|
||||
Don't Repeat Yourself, <20>D.R.Y.<2E>. Put redundant code in a class so it can be re-used and unit tested.
|
||||
Expose as little of a class as possible. Prefer private over protected. Prefer protected over public. The smaller the interface footprint, the easier it is to write unit tests and comprehend the operation of the class. This is the Interface Segregation Principle.
|
||||
Use language constants (enum or static const) with descriptive names instead of hard-coded <20>magic numbers.<2E>
|
||||
Make classes depend on as few external classes or routines as possible. Ideally, no dependencies.
|
||||
Don't limit flexibility of parameters by forcing the caller to use specific types where general types would work.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Coding Standards
|
||||
|
||||
Coding standards used here are extreme strict and consistent. The style
|
||||
evolved gradually over the years, incorporating generally acknowledged
|
||||
best-practice C++ advice, experience, and personal preference.
|
||||
|
||||
## Don't Repeat Yourself!
|
||||
|
||||
The [Don't Repeat Yourself][1] principle summarises the essence of what it
|
||||
means to write good code, in all languages, at all levels.
|
||||
|
||||
## Formatting
|
||||
|
||||
The goal of source code formatting should always be to make things as easy to
|
||||
read as possible. White space is used to guide the eye so that details are not
|
||||
overlooked. Blank lines are used to separate code into "paragraphs."
|
||||
|
||||
* No tab characters please.
|
||||
* Tab stops are set to 4 spaces.
|
||||
* Braces are indented in the [Allman style][2].
|
||||
* Always place a space before and after all binary operators,
|
||||
especially assignments (`operator=`).
|
||||
* The `!` operator should always be followed by a space.
|
||||
* The `~` operator should be preceded by a space, but not followed by one.
|
||||
* The `++` and `--` operators should have no spaces between the operator and
|
||||
the operand.
|
||||
* A space never appears before a comma, and always appears after a comma.
|
||||
* Always place a space before an opening parenthesis. One exception is if
|
||||
the parentheses are empty.
|
||||
* Don't put spaces after a parenthesis. A typical member function call might
|
||||
look like this: `foobar (1, 2, 3);`
|
||||
* In general, leave a blank line before an `if` statement.
|
||||
* In general, leave a blank line after a closing brace `}`.
|
||||
* Do not place code or comments on the same line as any opening or
|
||||
closing brace.
|
||||
* Do not write `if` statements all-on-one-line. The exception to this is when
|
||||
you've got a sequence of similar `if` statements, and are aligning them all
|
||||
vertically to highlight their similarities.
|
||||
* In an `if-else` statement, if you surround one half of the statement with
|
||||
braces, you also need to put braces around the other half, to match.
|
||||
* When writing a pointer type, use this spacing: `SomeObject* myObject`.
|
||||
Technically, a more correct spacing would be `SomeObject *myObject`, but
|
||||
it makes more sense for the asterisk to be grouped with the type name,
|
||||
since being a pointer is part of the type, not the variable name. The only
|
||||
time that this can lead to any problems is when you're declaring multiple
|
||||
pointers of the same type in the same statement - which leads on to the next
|
||||
rule:
|
||||
* When declaring multiple pointers, never do so in a single statement, e.g.
|
||||
`SomeObject* p1, *p2;` - instead, always split them out onto separate lines
|
||||
and write the type name again, to make it quite clear what's going on, and
|
||||
avoid the danger of missing out any vital asterisks.
|
||||
* The previous point also applies to references, so always put the `&` next to
|
||||
the type rather than the variable, e.g. `void foo (Thing const& thing)`. And
|
||||
don't put a space on both sides of the `*` or `&` - always put a space after
|
||||
it, but never before it.
|
||||
* The word `const` should be placed to the right of the thing that it modifies,
|
||||
for consistency. For example `int const` refers to an int which is const.
|
||||
`int const*` is a pointer to an int which is const. `int *const` is a const
|
||||
pointer to an int.
|
||||
* Always place a space in between the template angle brackets and the type
|
||||
name. Template code is already hard enough to read!
|
||||
|
||||
## Naming conventions
|
||||
|
||||
* Member variables and method names are written with camel-case, and never
|
||||
begin with a capital letter.
|
||||
* Class names are also written in camel-case, but always begin with a capital
|
||||
letter.
|
||||
* For global variables... well, you shouldn't have any, so it doesn't matter.
|
||||
* Class data members begin with `m_`, static data members begin with `s_`.
|
||||
Global variables begin with `g_`. This is so the scope of the corresponding
|
||||
declaration can be easily determined.
|
||||
* Avoid underscores in your names, especially leading or trailing underscores.
|
||||
In particular, leading underscores should be avoided, as these are often used
|
||||
in standard library code, so to use them in your own code looks quite jarring.
|
||||
* If you really have to write a macro for some reason, then make it all caps,
|
||||
with underscores to separate the words. And obviously make sure that its name
|
||||
is unlikely to clash with symbols used in other libraries or 3rd party code.
|
||||
|
||||
## Types, const-correctness
|
||||
|
||||
* If a method can (and should!) be const, make it const!
|
||||
* If a method definitely doesn't throw an exception (be careful!), mark it as
|
||||
`noexcept`
|
||||
* When returning a temporary object, e.g. a String, the returned object should
|
||||
be non-const, so that if the class has a C++11 move operator, it can be used.
|
||||
* If a local variable can be const, then make it const!
|
||||
* Remember that pointers can be const as well as primitives; For example, if
|
||||
you have a `char*` whose contents are going to be altered, you may still be
|
||||
able to make the pointer itself const, e.g. `char* const foobar = getFoobar();`.
|
||||
* Do not declare all your local variables at the top of a function or method
|
||||
(i.e. in the old-fashioned C-style). Declare them at the last possible moment,
|
||||
and give them as small a scope as possible.
|
||||
* Object parameters should be passed as `const&` wherever possible. Only
|
||||
pass a parameter as a copy-by-value object if you really need to mutate
|
||||
a local copy inside the method, and if making a local copy inside the method
|
||||
would be difficult.
|
||||
* Use portable `for()` loop variable scoping (i.e. do not have multiple for
|
||||
loops in the same scope that each re-declare the same variable name, as
|
||||
this fails on older compilers)
|
||||
* When you're testing a pointer to see if it's null, never write
|
||||
`if (myPointer)`. Always avoid that implicit cast-to-bool by writing it more
|
||||
fully: `if (myPointer != nullptr)`. And likewise, never ever write
|
||||
`if (! myPointer)`, instead always write `if (myPointer == nullptr)`.
|
||||
It is more readable that way.
|
||||
* Avoid C-style casts except when converting between primitive numeric types.
|
||||
Some people would say "avoid C-style casts altogether", but `static_cast` is
|
||||
a bit unreadable when you just want to cast an `int` to a `float`. But
|
||||
whenever a pointer is involved, or a non-primitive object, always use
|
||||
`static_cast`. And when you're reinterpreting data, always use
|
||||
`reinterpret_cast`.
|
||||
* Until C++ gets a universal 64-bit primitive type (part of the C++11
|
||||
standard), it's best to stick to the `std::int64_t` and `std::uint64_t` typedefs.
|
||||
|
||||
## Object lifetime and ownership
|
||||
|
||||
* Absolutely do NOT use `delete`, `deleteAndZero`, etc. There are very very few
|
||||
situations where you can't use a `ScopedPointer` or some other automatic
|
||||
lifetime management class.
|
||||
* Do not use `new` unless there's no alternative. Whenever you type `new`, always
|
||||
treat it as a failure to find a better solution. If a local variable can be
|
||||
allocated on the stack rather than the heap, then always do so.
|
||||
* Do not ever use `new` or `malloc` to allocate a C++ array. Always use a
|
||||
`HeapBlock` instead.
|
||||
* And just to make it doubly clear: Never use `malloc` or `calloc`.
|
||||
* If a parent object needs to create and own some kind of child object, always
|
||||
use composition as your first choice. If that's not possible (e.g. if the
|
||||
child needs a pointer to the parent for its constructor), then use a
|
||||
`ScopedPointer`.
|
||||
* If possible, pass an object as a reference rather than a pointer. If possible,
|
||||
make it a `const` reference.
|
||||
* Obviously avoid static and global values. Sometimes there's no alternative,
|
||||
but if there is an alternative, then use it, no matter how much effort it
|
||||
involves.
|
||||
* If allocating a local POD structure (e.g. an operating-system structure in
|
||||
native code), and you need to initialise it with zeros, use the `= { 0 };`
|
||||
syntax as your first choice for doing this. If for some reason that's not
|
||||
appropriate, use the `zerostruct()` function, or in case that isn't suitable,
|
||||
use `zeromem()`. Don't use `memset()`.
|
||||
|
||||
## Classes
|
||||
|
||||
* Declare a class's public section first, and put its constructors and
|
||||
destructor first. Any protected items come next, and then private ones.
|
||||
* Use the most restrictive access-specifier possible for each member. Prefer
|
||||
`private` over `protected`, and `protected` over `public`. Don't expose
|
||||
things unnecessarily.
|
||||
* Preferred positioning for any inherited classes is to put them to the right
|
||||
of the class name, vertically aligned, e.g.:
|
||||
class Thing : public Foo,
|
||||
private Bar
|
||||
{
|
||||
}
|
||||
* Put a class's member variables (which should almost always be private, of course),
|
||||
after all the public and protected method declarations.
|
||||
* Any private methods can go towards the end of the class, after the member
|
||||
variables.
|
||||
* If your class does not have copy-by-value semantics, derive the class from
|
||||
`Uncopyable`.
|
||||
* If your class is likely to be leaked, then derive your class from
|
||||
`LeakChecked<>`.
|
||||
* Constructors that take a single parameter should be default be marked
|
||||
`explicit`. Obviously there are cases where you do want implicit conversion,
|
||||
but always think about it carefully before writing a non-explicit constructor.
|
||||
* Do not use `NULL`, `null`, or 0 for a null-pointer. And especially never use
|
||||
'0L', which is particulary burdensome. Use `nullptr` instead - this is the
|
||||
C++2011 standard, so get used to it. There's a fallback definition for `nullptr`
|
||||
in Beast, so it's always possible to use it even if your compiler isn't yet
|
||||
C++2011 compliant.
|
||||
* All the C++ 'guru' books and articles are full of excellent and detailed advice
|
||||
on when it's best to use inheritance vs composition. If you're not already
|
||||
familiar with the received wisdom in these matters, then do some reading!
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
* Constrain the scope of identifiers to the smallest area that needs it. Consider
|
||||
using nested classes or classes inside functions, if doing so will expose less
|
||||
interface and implementation overall.
|
||||
* `goto` statements should not be used at all, even if the alternative is
|
||||
more verbose code. The only exception is when implementing an algorithm in
|
||||
a function as a state machine.
|
||||
* Don't use macros! OK, obviously there are many situations where they're the
|
||||
right tool for the job, but treat them as a last resort. Certainly don't ever
|
||||
use a macro just to hold a constant value or to perform any kind of function
|
||||
that could have been done as a real inline function. And it goes without saying
|
||||
that you should give them names which aren't going to clash with other code.
|
||||
And `#undef` them after you've used them, if possible.
|
||||
* When using the `++` or `--` operators, never use post-increment if
|
||||
pre-increment could be used instead. Although it doesn't matter for
|
||||
primitive types, it's good practice to pre-increment since this can be
|
||||
much more efficient for more complex objects. In particular, if you're
|
||||
writing a for loop, always use pre-increment,
|
||||
e.g. `for (int = 0; i < 10; ++i)`
|
||||
* Never put an "else" statement after a "return"! This is well-explained in the
|
||||
LLVM coding standards...and a couple of other very good pieces of advice from
|
||||
the LLVM standards are in there as well.
|
||||
* When getting a possibly-null pointer and using it only if it's non-null, limit
|
||||
the scope of the pointer as much as possible - e.g. Do NOT do this:
|
||||
|
||||
Foo* f = getFoo ();
|
||||
if (f != nullptr)
|
||||
f->doSomething ();
|
||||
// other code
|
||||
f->doSomething (); // oops! f may be null!
|
||||
|
||||
..instead, prefer to write it like this, which reduces the scope of the
|
||||
pointer, making it impossible to write code that accidentally uses a null
|
||||
pointer:
|
||||
|
||||
if (Foo* f = getFoo ())
|
||||
f->doSomethingElse ();
|
||||
|
||||
// f is out-of-scope here, so impossible to use it if it's null
|
||||
|
||||
(This also results in smaller, cleaner code)
|
||||
|
||||
[1]: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
|
||||
[2]: http://en.wikipedia.org/wiki/Indent_style#Allman_style
|
||||
@@ -102,7 +102,7 @@ INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = YES
|
||||
EXCLUDE = modules/beast_core/beast_core.h \
|
||||
modules/beast_core/beast_core.cpp \
|
||||
modules/beast_core/beast_core.unity.cpp \
|
||||
modules/beast_basics/beast_basics.cpp \
|
||||
modules/beast_basics/native \
|
||||
modules/beast_basics/zip/zlib
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
import itertools
|
||||
import ntpath
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
def add_beast_to_path():
|
||||
@@ -24,7 +27,7 @@ VARIANT_DIRECTORIES = {
|
||||
'modules': ('bin', 'modules'),
|
||||
}
|
||||
|
||||
BOOST_LIBRARIES = 'boost_system',
|
||||
BOOST_LIBRARIES = '' #boost_system'
|
||||
MAIN_PROGRAM_FILE = 'beast/unit_test/tests/main.cpp'
|
||||
DOTFILE = '~/.scons'
|
||||
|
||||
@@ -43,6 +46,94 @@ def main():
|
||||
for name, path in VARIANT_DIRECTORIES.items():
|
||||
env.VariantDir(os.path.join(*path), name, duplicate=0)
|
||||
env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
Tests.run_tests(env, MAIN_PROGRAM_FILE, '.', '.test.cpp')
|
||||
#Tests.run_tests(env, MAIN_PROGRAM_FILE, '.', '.test.cpp')
|
||||
|
||||
#main()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def is_unity(path):
|
||||
b, e = os.path.splitext(path)
|
||||
return os.path.splitext(b)[1] == '.unity' and e in ['.c', '.cpp']
|
||||
|
||||
def files(base):
|
||||
for parent, _, files in os.walk(base):
|
||||
for path in files:
|
||||
path = os.path.join(parent, path)
|
||||
yield os.path.normpath(path)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
'''
|
||||
/MP /GS /W3 /wd"4018" /wd"4244" /wd"4267" /Gy- /Zc:wchar_t
|
||||
/I"D:\lib\OpenSSL-Win64\include" /I"D:\lib\boost_1_55_0"
|
||||
/I"..\..\src\protobuf\src" /I"..\..\src\protobuf\vsprojects"
|
||||
/I"..\..\src\leveldb" /I"..\..\src\leveldb\include" /I"..\..\build\proto"
|
||||
/Zi /Gm- /Od /Fd"..\..\build\obj\VisualStudio2013\Debug.x64\vc120.pdb"
|
||||
/fp:precise /D "_CRTDBG_MAP_ALLOC" /D "WIN32" /D "_DEBUG" /D "_CONSOLE"
|
||||
/D "_VARIADIC_MAX=10" /D "_WIN32_WINNT=0x0600" /D "_SCL_SECURE_NO_WARNINGS"
|
||||
/D "_CRT_SECURE_NO_WARNINGS" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope
|
||||
/RTC1 /GR /Gd /MTd /openmp- /Fa"..\..\build\obj\VisualStudio2013\Debug.x64\"
|
||||
/EHa /nologo /Fo"..\..\build\obj\VisualStudio2013\Debug.x64\"
|
||||
/Fp"..\..\build\obj\VisualStudio2013\Debug.x64\rippled.pch"
|
||||
'''
|
||||
|
||||
# Path to this SConstruct file
|
||||
base_dir = Dir('#').srcnode().get_abspath()
|
||||
|
||||
base_env = Environment(
|
||||
tools = ['default', 'VSProject'],
|
||||
CCCOMSTR = '',
|
||||
CMDLINE_QUIET = 1,
|
||||
CPPPATH = [
|
||||
os.environ['BOOST_ROOT'],
|
||||
os.environ['OPENSSL_ROOT']
|
||||
],
|
||||
CPPDEFINES = [
|
||||
'_WIN32_WINNT=0x6000']
|
||||
)
|
||||
|
||||
#base_env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
|
||||
env = base_env
|
||||
|
||||
bin_dir = os.path.join(base_dir, 'bin')
|
||||
|
||||
srcs = filter(is_unity, list(files('beast')) + list(files('modules')))
|
||||
for variant in ['Debug']: #, 'Release']:
|
||||
for platform in ['Win32']:
|
||||
#env = base_env.Clone()
|
||||
#env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
variant_dir = os.path.join(bin_dir, variant + '.' + platform)
|
||||
env.VariantDir(os.path.join(variant_dir, 'beast'), 'beast', duplicate=0)
|
||||
env.VariantDir(os.path.join(variant_dir, 'modules'), 'modules', duplicate=0)
|
||||
env.Append(CCFLAGS=[
|
||||
'/EHsc',
|
||||
'/bigobj',
|
||||
'/Fd${TARGET}.pdb'
|
||||
])
|
||||
if variant == 'Debug':
|
||||
env.Append(CCFLAGS=[
|
||||
'/MTd',
|
||||
'/Od',
|
||||
'/Zi'
|
||||
])
|
||||
else:
|
||||
env.Append(CCFLAGS=[
|
||||
'/MT',
|
||||
'/Ox'
|
||||
])
|
||||
variant_srcs = [os.path.join(variant_dir, os.path.relpath(f, base_dir)) for f in srcs]
|
||||
|
||||
beast = env.StaticLibrary(
|
||||
target = os.path.join(variant_dir, 'beast.lib'),
|
||||
source = variant_srcs)
|
||||
|
||||
env.VSProject (
|
||||
'out',
|
||||
buildtarget = beast,
|
||||
source = filter(is_unity, list(files('beast')) + list(files('modules'))))
|
||||
|
||||
env.Default ('out.vcxproj')
|
||||
#env.Default (os.path.join(bin_dir,'Debug.Win32', 'beast.lib'))
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
--------------------------------------------------------------------------------
|
||||
BEAST TODO
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
- Change sqdb to use exceptions instead of errors
|
||||
|
||||
- Use SemanticVersion for beast version numbers to replace BEAST_VERSION
|
||||
|
||||
- add support for a __PRETTY_FUNCTION__ equivalent for all environments
|
||||
|
||||
- Import secp256k1 from sipa
|
||||
|
||||
- Set sqlite thread safety model to '2' in beast_sqlite
|
||||
|
||||
- Document and rename all the sqdb files and classes
|
||||
|
||||
- Specialize UnsignedInteger<> for peformance in the storage format
|
||||
|
||||
- Rename HeapBlock routines to not conflict with _CRTDBG_MAP_ALLOC macros
|
||||
|
||||
- Implement beast::Bimap?
|
||||
|
||||
- Use Bimap for storage in the DeadlineTimer::Manager, to support
|
||||
thousands of timers.
|
||||
|
||||
- Think about adding a shouldStop bool to InterruptibleThread, along
|
||||
with a shouldStop () function returning bool, and a stop() method.
|
||||
|
||||
- Tidy up CacheLine, MemoryAlignment
|
||||
|
||||
- Implement a reasonable substitute for boost's thread_local_storage
|
||||
|
||||
- Rename malloc/calloc JUCE members that conflict with the debug CRT from MSVC
|
||||
|
||||
- Reformat every Doxygen comment
|
||||
- Fix Doxygen metatags
|
||||
- update Beast Doxyfile
|
||||
|
||||
- Rename SharedData to SharedState or something?
|
||||
|
||||
- Make sure the template BeastConfig.h is included in the Doxyfile
|
||||
|
||||
- Implement robust key/value database with bulk write
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
#ifndef BEAST_ARITHMETIC_H_INCLUDED
|
||||
#define BEAST_ARITHMETIC_H_INCLUDED
|
||||
|
||||
#include "Config.h"
|
||||
#include <beast/Config.h>
|
||||
|
||||
#include "utility/noexcept.h"
|
||||
#include <beast/utility/noexcept.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
@@ -34,101 +34,6 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
// Some indispensible min/max functions
|
||||
|
||||
/** Returns the larger of two values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b)
|
||||
{ return (a < b) ? b : a; }
|
||||
|
||||
/** Returns the larger of three values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b, const Type c)
|
||||
{ return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); }
|
||||
|
||||
/** Returns the larger of four values. */
|
||||
template <typename Type>
|
||||
inline Type bmax (const Type a, const Type b, const Type c, const Type d)
|
||||
{ return bmax (a, bmax (b, c, d)); }
|
||||
|
||||
/** Returns the smaller of two values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b)
|
||||
{ return (b < a) ? b : a; }
|
||||
|
||||
/** Returns the smaller of three values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b, const Type c)
|
||||
{ return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); }
|
||||
|
||||
/** Returns the smaller of four values. */
|
||||
template <typename Type>
|
||||
inline Type bmin (const Type a, const Type b, const Type c, const Type d)
|
||||
{ return bmin (a, bmin (b, c, d)); }
|
||||
|
||||
/** Scans an array of values, returning the minimum value that it contains. */
|
||||
template <typename Type>
|
||||
const Type findMinimum (const Type* data, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type();
|
||||
|
||||
Type result (*data++);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *data++;
|
||||
if (v < result) result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the maximum value that it contains. */
|
||||
template <typename Type>
|
||||
const Type findMaximum (const Type* values, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type();
|
||||
|
||||
Type result (*values++);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *values++;
|
||||
if (result < v) result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the minimum and maximum values that it contains. */
|
||||
template <typename Type>
|
||||
void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
{
|
||||
lowest = Type();
|
||||
highest = Type();
|
||||
}
|
||||
else
|
||||
{
|
||||
Type mn (*values++);
|
||||
Type mx (mn);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const Type& v = *values++;
|
||||
|
||||
if (mx < v) mx = v;
|
||||
if (v < mn) mn = v;
|
||||
}
|
||||
|
||||
lowest = mn;
|
||||
highest = mx;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Constrains a value to keep it within a given range.
|
||||
|
||||
@@ -151,7 +56,8 @@ inline Type blimit (const Type lowerLimit,
|
||||
const Type upperLimit,
|
||||
const Type valueToConstrain) noexcept
|
||||
{
|
||||
bassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
|
||||
// if these are in the wrong order, results are unpredictable.
|
||||
bassert (lowerLimit <= upperLimit);
|
||||
|
||||
return (valueToConstrain < lowerLimit) ? lowerLimit
|
||||
: ((upperLimit < valueToConstrain) ? upperLimit
|
||||
@@ -177,24 +83,6 @@ inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noe
|
||||
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
|
||||
This is basically a quicker way to write:
|
||||
@code valueToTest >= 0 && valueToTest <= upperLimit
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
|
||||
{
|
||||
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return Type() <= valueToTest && valueToTest <= upperLimit;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) noexcept
|
||||
{
|
||||
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
@@ -214,55 +102,6 @@ int numElementsInArray (Type (&array)[N])
|
||||
return N;
|
||||
}
|
||||
|
||||
/** 64-bit abs function. */
|
||||
inline std::int64_t abs64 (const std::int64_t n) noexcept
|
||||
{
|
||||
return (n >= 0) ? n : -n;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_MSVC
|
||||
#pragma optimize ("t", off)
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently.
|
||||
*/
|
||||
template <typename FloatType>
|
||||
inline int roundToInt (const FloatType value) noexcept
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
|
||||
union { int asInt[2]; double asDouble; } n;
|
||||
n.asDouble = ((double) value) + 6755399441055744.0;
|
||||
|
||||
#if BEAST_BIG_ENDIAN
|
||||
return n.asInt [1];
|
||||
#else
|
||||
return n.asInt [0];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
#endif
|
||||
#pragma optimize ("", on) // resets optimisations to the project defaults
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,428 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.com
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ATOMIC_H_INCLUDED
|
||||
#define BEAST_ATOMIC_H_INCLUDED
|
||||
|
||||
#include "Config.h"
|
||||
#include "StaticAssert.h"
|
||||
|
||||
#include "utility/noexcept.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Simple class to hold a primitive value and perform atomic operations on it.
|
||||
|
||||
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||
There are methods to perform most of the basic atomic operations.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Atomic
|
||||
{
|
||||
public:
|
||||
/** Creates a new value, initialised to zero. */
|
||||
inline Atomic() noexcept
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a new value, with a given initial value. */
|
||||
inline Atomic (const Type initialValue) noexcept
|
||||
: value (initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another value (atomically). */
|
||||
inline Atomic (const Atomic& other) noexcept
|
||||
: value (other.get())
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
inline ~Atomic() noexcept
|
||||
{
|
||||
// This class can only be used for types which are 32 or 64 bits in size.
|
||||
static_bassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||
}
|
||||
|
||||
/** Atomically reads and returns the current value. */
|
||||
Type get() const noexcept;
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
Atomic& operator= (const Atomic& other) noexcept
|
||||
{ exchange (other.get()); return *this; }
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
Atomic& operator= (const Type newValue) noexcept
|
||||
{ exchange (newValue); return *this; }
|
||||
|
||||
/** Atomically sets the current value. */
|
||||
void set (Type newValue) noexcept
|
||||
{ exchange (newValue); }
|
||||
|
||||
/** Atomically sets the current value, returning the value that was replaced. */
|
||||
Type exchange (Type value) noexcept;
|
||||
|
||||
/** Atomically adds a number to this value, returning the new value. */
|
||||
Type operator+= (Type amountToAdd) noexcept;
|
||||
|
||||
/** Atomically subtracts a number from this value, returning the new value. */
|
||||
Type operator-= (Type amountToSubtract) noexcept;
|
||||
|
||||
/** Atomically increments this value, returning the new value. */
|
||||
Type operator++() noexcept;
|
||||
|
||||
/** Atomically decrements this value, returning the new value. */
|
||||
Type operator--() noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||
{
|
||||
if (get() == valueToCompare)
|
||||
{
|
||||
set (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns true if the comparison was true and the value was replaced; false if
|
||||
the comparison failed and the value was left unchanged.
|
||||
@see compareAndSetValue
|
||||
*/
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||
{
|
||||
Type oldValue = get();
|
||||
if (oldValue == valueToCompare)
|
||||
set (newValue);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns the old value before it was changed.
|
||||
@see compareAndSetBool
|
||||
*/
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_64BIT
|
||||
BEAST_ALIGN (8)
|
||||
#else
|
||||
BEAST_ALIGN (4)
|
||||
#endif
|
||||
|
||||
/** The raw value that this class operates on.
|
||||
This is exposed publically in case you need to manipulate it directly
|
||||
for performance reasons.
|
||||
*/
|
||||
volatile Type value;
|
||||
|
||||
private:
|
||||
template <typename Dest, typename Source>
|
||||
static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
|
||||
|
||||
static inline Type castFrom32Bit (std::int32_t value) noexcept { return castTo <Type, std::int32_t> (value); }
|
||||
static inline Type castFrom64Bit (std::int64_t value) noexcept { return castTo <Type, std::int64_t> (value); }
|
||||
static inline std::int32_t castTo32Bit (Type value) noexcept { return castTo <std::int32_t, Type> (value); }
|
||||
static inline std::int64_t castTo64Bit (Type value) noexcept { return castTo <std::int64_t, Type> (value); }
|
||||
|
||||
|
||||
Type operator++ (int); // better to just use pre-increment with atomics..
|
||||
Type operator-- (int);
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename ValueType>
|
||||
inline ValueType negateValue (ValueType n) noexcept
|
||||
{
|
||||
return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
|
||||
: (sizeof (ValueType) == 2 ? (ValueType) -(short) n
|
||||
: (sizeof (ValueType) == 4 ? (ValueType) -(int) n
|
||||
: ((ValueType) -(std::int64_t) n)));
|
||||
}
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename PointerType>
|
||||
inline PointerType* negateValue (PointerType* n) noexcept
|
||||
{
|
||||
return reinterpret_cast <PointerType*> (-reinterpret_cast <std::intptr_t> (n));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
The following code is in the header so that the atomics can be inlined where possible...
|
||||
*/
|
||||
#if BEAST_IOS || (BEAST_MAC && (BEAST_PPC || BEAST_CLANG || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||
#define BEAST_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE
|
||||
#else
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#if BEAST_PPC || BEAST_IOS
|
||||
// None of these atomics are available for PPC or for iOS 3.1 or earlier!!
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return --*a; }
|
||||
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, BEAST_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
||||
{ bassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
#elif BEAST_CLANG && BEAST_LINUX
|
||||
#define BEAST_ATOMICS_GCC 1
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_GCC
|
||||
#define BEAST_ATOMICS_GCC 1 // GCC with intrinsics
|
||||
|
||||
#if BEAST_IOS || BEAST_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#else
|
||||
#define BEAST_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if BEAST_USE_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
#endif
|
||||
#define beast_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||
#define beast_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||
#define beast_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||
#define beast_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||
#define beast_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||
#define beast_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||
#define beast_MemoryBarrier _ReadWriteBarrier
|
||||
#else
|
||||
long beast_InterlockedExchange (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedIncrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedDecrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
||||
__int64 beast_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
||||
inline void beast_MemoryBarrier() noexcept { long x = 0; beast_InterlockedIncrement (&x); }
|
||||
#endif
|
||||
|
||||
#if BEAST_64BIT
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||
#endif
|
||||
#define beast_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||
#define beast_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||
#define beast_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||
#define beast_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||
#else
|
||||
// None of these atomics are available in a 32-bit Windows build!!
|
||||
template <typename Type> static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { bassertfalse; return --*a; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4311) // (truncation warning)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::get() const noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) OSAtomicAdd32Barrier ((int32_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||
: castFrom64Bit ((std::int64_t) OSAtomicAdd64Barrier ((int64_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) __sync_add_and_fetch ((volatile std::int32_t*) &value, 0))
|
||||
: castFrom64Bit ((std::int64_t) __sync_add_and_fetch ((volatile std::int64_t*) &value, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC || BEAST_ATOMICS_GCC
|
||||
Type currentVal = value;
|
||||
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||
return currentVal;
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) (beast_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||
: (Type) (beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
||||
{
|
||||
return operator+= (negateValue (amountToSubtract));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator++() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicIncrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedIncrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, (Type) 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator--() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicDecrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedDecrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, (Type) -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile std::int32_t*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||
: __sync_bool_compare_and_swap ((volatile std::int64_t*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
for (;;) // Annoying workaround for only having a bool CAS operation..
|
||||
{
|
||||
if (compareAndSetBool (newValue, valueToCompare))
|
||||
return valueToCompare;
|
||||
|
||||
const Type result = value;
|
||||
if (result != valueToCompare)
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) __sync_val_compare_and_swap ((volatile std::int32_t*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((std::int64_t) __sync_val_compare_and_swap ((volatile std::int64_t*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void memoryBarrier() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
OSMemoryBarrier();
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
__sync_synchronize();
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
beast_MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,6 @@
|
||||
|
||||
// These classes require boost in order to be used.
|
||||
|
||||
#include "boost/ErrorCode.h"
|
||||
#include <beast/boost/ErrorCode.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
#ifndef BEAST_BYTEORDER_H_INCLUDED
|
||||
#define BEAST_BYTEORDER_H_INCLUDED
|
||||
|
||||
#include "Config.h"
|
||||
#include "Uncopyable.h"
|
||||
#include <beast/Config.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -35,7 +34,7 @@ namespace beast {
|
||||
/** Contains static methods for converting the byte order between different
|
||||
endiannesses.
|
||||
*/
|
||||
class ByteOrder : public Uncopyable
|
||||
class ByteOrder
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
@@ -105,6 +104,8 @@ public:
|
||||
|
||||
private:
|
||||
ByteOrder();
|
||||
ByteOrder(ByteOrder const&) = delete;
|
||||
ByteOrder& operator= (ByteOrder const&) = delete;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
||||