mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 01:41:11 +01:00
Add inventory module and dependencies
This commit is contained in:
parent
492e91c0cb
commit
32a8091484
@ -43,9 +43,12 @@ natpryce-make-it-easy = { strictly = '4.0.1' }
|
||||
netlayer = { strictly = '2b459dc' }
|
||||
openjfx-javafx-plugin = { strictly = '0.0.10' }
|
||||
protobuf = { strictly = '3.19.1' }
|
||||
pushy = { strictly = '0.13.2' }
|
||||
qrgen = { strictly = '1.3' }
|
||||
javacv = { strictly = '1.5.10' }
|
||||
slf4j = { strictly = '1.7.30' }
|
||||
spark = { strictly = '2.5.2' }
|
||||
|
||||
|
||||
[libraries]
|
||||
apache-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "apache-httpclient" }
|
||||
@ -75,6 +78,7 @@ grpc-core = { module = "io.grpc:grpc-core", version.ref = "grpc" }
|
||||
grpc-netty-shaded = { module = "io.grpc:grpc-netty-shaded", version.ref = "grpc" }
|
||||
grpc-protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc" }
|
||||
grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc" }
|
||||
grpc-auth = { module = "io.grpc:grpc-auth", version.ref = "grpc" }
|
||||
|
||||
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
||||
|
||||
@ -108,6 +112,9 @@ netlayer-tor-native = { module = "com.github.bisq-network.netlayer:tor.native",
|
||||
|
||||
openjfx-javafx-plugin = { module = "org.openjfx:javafx-plugin", version.ref = "openjfx-javafx-plugin" }
|
||||
protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" }
|
||||
pushy = { module = "com.turo:pushy", version.ref = "pushy" }
|
||||
qrgen = { module = "net.glxn:qrgen", version.ref = "qrgen" }
|
||||
javacv = { module = "org.bytedeco:javacv-platform", version.ref = "javacv" }
|
||||
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||
spark-core = { module = "com.sparkjava:spark-core", version.ref = "spark" }
|
||||
|
||||
|
@ -38,6 +38,16 @@
|
||||
<sha256 value="ec6a3b1ccb21e66c02e36899735c0c2171c5bd3a4ea269a28be95f9f2e8a822b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.eatthepath" name="fast-uuid" version="0.1">
|
||||
<artifact name="fast-uuid-0.1.jar">
|
||||
<sha256 value="670976cae3f41609128f647388791f43af361f3e7403ef0e3f0529c23fa1bccc"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="fast-uuid-0.1.pom">
|
||||
<sha256 value="8f51f3c717831493529c962e65dde7a4d51762a1818d7bb8777123635b669d9d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.fasterxml" name="oss-parent" version="41">
|
||||
<artifact name="oss-parent-41.pom">
|
||||
<sha256 value="af650fa4dd400bc5769320bcef08ed93813f349cabe8213d469acafbbd945d8a" origin="Generated by Gradle"/>
|
||||
@ -279,6 +289,22 @@
|
||||
<artifact name="proto-google-common-protos-2.0.1.pom">
|
||||
<sha256 value="8b62bfd85d693ebcffd828232af7424f34fd212c5e28e5ed99b0dc5d2bc7d4f5" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.auth" name="google-auth-library-credentials" version="0.22.2">
|
||||
<artifact name="google-auth-library-credentials-0.22.2.jar">
|
||||
<sha256 value="e42c2cbe642744f55bd2a081e6f60f126e691129e7148daec3af79deab4ac65a"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="google-auth-library-credentials-0.22.2.pom">
|
||||
<sha256 value="c6094e9b3875421e8f4433d624b80df29f2aefc224f1238ffbf5e86cc89c1760"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.auth" name="google-auth-library-parent" version="0.22.2">
|
||||
<artifact name="google-auth-library-parent-0.22.2.pom">
|
||||
<sha256 value="6ea6b8eb596209e74d5a82b67e13f717ad6d788abe137f361d5137d457794e87"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.code.findbugs" name="jsr305" version="3.0.2">
|
||||
<artifact name="jsr305-3.0.2.jar">
|
||||
@ -501,6 +527,12 @@
|
||||
<artifact name="listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom">
|
||||
<sha256 value="18d4b1db26153d4e55079ce1f76bb1fe05cdb862ef9954a88cbcc4ff38b8679b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.http-client" name="google-http-client-bom" version="1.38.0">
|
||||
<artifact name="google-http-client-bom-1.38.0.pom">
|
||||
<sha256 value="c443a88cd51ce7714e7df9598267eb7d1c429caa56db4df016c8d3cef98d274d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.inject" name="guice" version="5.0.1">
|
||||
<artifact name="guice-5.0.1.jar">
|
||||
@ -635,6 +667,32 @@
|
||||
<sha256 value="1526287fb2372207be56c8e98b6a1621db9a88774331ba0c603b2710ed365f7d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.sparkjava" name="spark-core" version="2.5.2">
|
||||
<artifact name="spark-core-2.5.2.jar">
|
||||
<sha256 value="76c246771297ebb14196eb2be621a1ab2d5b15d3038cb69f3becff1193e176bc"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="spark-core-2.5.2.pom">
|
||||
<sha256 value="23cc86e685116e709d77f2fce2190b7978ac8a0002bd592c8aec1f03094b00f1"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.turo" name="pushy" version="0.13.2">
|
||||
<artifact name="pushy-0.13.2.jar">
|
||||
<sha256 value="6125ccbad18bdaf92b483e076b990bfd25da24bdb5bcb087308a31890a30911b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="pushy-0.13.2.pom">
|
||||
<sha256 value="b8955ece6942a0e978ae3d208b4508d65bb27231645c1c52699df940daf968d9"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.turo" name="pushy-parent" version="0.13.2">
|
||||
<artifact name="pushy-parent-0.13.2.pom">
|
||||
<sha256 value="2b0e8eeae3ac045f03faae0d7c2b791b65050632acd8463bce9b3b6de4ff9b2f"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="commons-codec" name="commons-codec" version="1.13">
|
||||
<artifact name="commons-codec-1.13.jar">
|
||||
<sha256 value="61f7a3079e92b9fdd605238d0295af5fd11ac411a0a0af48deace1f6c5ffa072" origin="Generated by Gradle"/>
|
||||
@ -720,6 +778,16 @@
|
||||
<sha256 value="e371abe8a43de8416afa1a970466d833d1974f86ed620a5f548ab5aac4610188" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.grpc" name="grpc-auth" version="1.42.1">
|
||||
<artifact name="grpc-auth-1.42.1.jar">
|
||||
<sha256 value="fbfeae9b1b8b913f82a8ed5c20d4536a404464bfd385fd8ecd5a7dac9207ce30"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="grpc-auth-1.42.1.pom">
|
||||
<sha256 value="a9dc9340d89c6ebc1f4534cc911f129bb9413bccdbd95f76122e119e9dfdaab5"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.grpc" name="grpc-context" version="1.42.1">
|
||||
<artifact name="grpc-context-1.42.1.jar">
|
||||
<sha256 value="8810d6dc294b8c025c152a0093a2c62406ed79778f52ebbb28ab51640c1a4504" origin="Generated by Gradle"/>
|
||||
@ -785,6 +853,132 @@
|
||||
<sha256 value="9856d0a3e07df312825e698082b6ec6401cd15814ca74092ae58084f4925e784" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-buffer" version="4.1.25.Final">
|
||||
<artifact name="netty-buffer-4.1.25.Final.jar">
|
||||
<sha256 value="6adf1adb0a89b44c870b4773996679e6736f3b8f40cedb41e8c3e77e75d3619a"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-buffer-4.1.25.Final.pom">
|
||||
<sha256 value="c08ca134d93527a09e5a194cc4e92759fa459bd53f47835bd28d1f8f5504cf54"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-codec" version="4.1.25.Final">
|
||||
<artifact name="netty-codec-4.1.25.Final.jar">
|
||||
<sha256 value="c9c4bf830cb3284028317cb2752f7de54ecddab0142fc7c09cc3ddee0c6c100a"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-codec-4.1.25.Final.pom">
|
||||
<sha256 value="64116b0b2d5e68b74216e2b8abe1c0122513554a2d9f001f0d0508a91b635bcb"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-codec-dns" version="4.1.25.Final">
|
||||
<artifact name="netty-codec-dns-4.1.25.Final.jar">
|
||||
<sha256 value="6c41675e1dbaccfdef9295078917381ea5efd607d4ef92145f632b514de79a44"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-codec-dns-4.1.25.Final.pom">
|
||||
<sha256 value="71d0805a3404ddba9213d482157c92f619045532a6cbb21e172382873f148c53"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-codec-http" version="4.1.25.Final">
|
||||
<artifact name="netty-codec-http-4.1.25.Final.jar">
|
||||
<sha256 value="77fc6fa42dffe37fac5097d6bc5c546de941ed02972806ffd8d80efb3151d32d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-codec-http-4.1.25.Final.pom">
|
||||
<sha256 value="2d01cae5cb0386450e130548e5202dcd97887c11af3ec7ce913e5883cc774164"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-codec-http2" version="4.1.25.Final">
|
||||
<artifact name="netty-codec-http2-4.1.25.Final.jar">
|
||||
<sha256 value="54f4f0012e9404cac014e63b85a72dd4ada89ea208d46969fe5c2b757f55ff40"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-codec-http2-4.1.25.Final.pom">
|
||||
<sha256 value="a869d53ec32fe87d3561dbec68f7c0801187a473659872e1e517ce5e33c3e4b5"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-codec-socks" version="4.1.25.Final">
|
||||
<artifact name="netty-codec-socks-4.1.25.Final.jar">
|
||||
<sha256 value="df75b12f37e00b65357fb41376c9f98bbedd9b7ee60dad0dfef8544ce14f65ea"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-codec-socks-4.1.25.Final.pom">
|
||||
<sha256 value="4a1032b7d1c6b83aa7d75ddaf19721caced5f69d788602f7153b7739b39f1151"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-common" version="4.1.25.Final">
|
||||
<artifact name="netty-common-4.1.25.Final.jar">
|
||||
<sha256 value="50697918592b03624d9a6ea1847d3a831d988d17bd44df370113c83dfda6095b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-common-4.1.25.Final.pom">
|
||||
<sha256 value="20b49d4e77e78623826f931fbcf09e563fbe47062a9d2c9ac4df4dd3684dc57b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-handler" version="4.1.25.Final">
|
||||
<artifact name="netty-handler-4.1.25.Final.jar">
|
||||
<sha256 value="98c45605619a571a75ce82ea49e7c54b2bb2eb5d4ddc3e327ae4559b82b8556a"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-handler-4.1.25.Final.pom">
|
||||
<sha256 value="f605af77b605ce5ba05919b84bb84f8d64218a2e93c9e55502eb52974fb8dc3c"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-handler-proxy" version="4.1.25.Final">
|
||||
<artifact name="netty-handler-proxy-4.1.25.Final.jar">
|
||||
<sha256 value="60952dc844c5d247fffafa0d78b05ca575cd6bf3ca753a132adb097c548da7d8"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-handler-proxy-4.1.25.Final.pom">
|
||||
<sha256 value="74c962cc24d2249d85f757fdc48deb7064e2a3ce2fa3a57cf557354e14007e6d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-parent" version="4.1.25.Final">
|
||||
<artifact name="netty-parent-4.1.25.Final.pom">
|
||||
<sha256 value="fc637d287365b4a093e0bb48fe4689f45f04f924487e4cd84771d3abde562d6c"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-resolver" version="4.1.25.Final">
|
||||
<artifact name="netty-resolver-4.1.25.Final.jar">
|
||||
<sha256 value="85ea31999ad2cdbaa2f251caf2660a8ef0d9f274b0d86771077e7fd69c02b257"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-resolver-4.1.25.Final.pom">
|
||||
<sha256 value="73370505a346ef0de01a88dee28bcd580c9ebfad8a34ebb1f588b44ac036e4fc"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-resolver-dns" version="4.1.25.Final">
|
||||
<artifact name="netty-resolver-dns-4.1.25.Final.jar">
|
||||
<sha256 value="e2bb6ab70f3d3872e55e3127449fa6a2ee8c1a1b9a85b01ac9749fe1f6a0cfd8"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-resolver-dns-4.1.25.Final.pom">
|
||||
<sha256 value="968ecff379b6a854918613a1b4c039921b3718f9b3b265b33f8e4f7c5bba1495"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-transport" version="4.1.25.Final">
|
||||
<artifact name="netty-transport-4.1.25.Final.jar">
|
||||
<sha256 value="278b12a6f2c479124ff44c299c67d50443636ffed6399ae67d71473736cec58d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="netty-transport-4.1.25.Final.pom">
|
||||
<sha256 value="c349608aed8221909b1f84e46a14d7457eba0b2cd5e5c6bcb51ce784875e6b81"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.perfmark" name="perfmark-api" version="0.23.0">
|
||||
<artifact name="perfmark-api-0.23.0.jar">
|
||||
<sha256 value="c705b5c10c18ff3032b9e81742bc2f6b0e5607f6a6dfc0c8ad0cff75d4913042" origin="Generated by Gradle"/>
|
||||
@ -808,6 +1002,16 @@
|
||||
<artifact name="javax.inject-1.pom">
|
||||
<sha256 value="943e12b100627804638fa285805a0ab788a680266531e650921ebfe4621a8bfa" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="javax.servlet" name="javax.servlet-api" version="3.1.0">
|
||||
<artifact name="javax.servlet-api-3.1.0.jar">
|
||||
<sha256 value="af456b2dd41c4e82cf54f3e743bc678973d9fe35bd4d3071fa05c7e5333b8482"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="javax.servlet-api-3.1.0.pom">
|
||||
<sha256 value="b31109e22ea3f2df1ad7955432e718a35def50ae6c19698034afa8a0cf9e9069"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="junit" name="junit" version="4.12">
|
||||
<artifact name="junit-4.12.jar">
|
||||
@ -1831,6 +2035,154 @@
|
||||
<artifact name="plexus-utils-3.0.24.pom">
|
||||
<sha256 value="11067f6a75fded12bcdc8daf7a66ddd942ce289c3daf88a3fe0f8b12858a2ee6" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-http" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-http-9.3.6.v20151106.jar">
|
||||
<sha256 value="f0bb475e064671ccd75fc89edae5f3f718139189e5e09e672cb4fc3784215d1b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-http-9.3.6.v20151106.pom">
|
||||
<sha256 value="60adc7c0614f46d0fc2ec59d637d11df50b02277530d09df5ef188497058e3cd"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-io" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-io-9.3.6.v20151106.jar">
|
||||
<sha256 value="8ece9bf183c6c2d6c5036d7664d450cf9897f0e5aacb8f3dae092db7cf7848ec"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-io-9.3.6.v20151106.pom">
|
||||
<sha256 value="bff43d1881565a84111358449591d854e7c36d7c078338bcf1a484afb7ae53a6"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-parent" version="25">
|
||||
<artifact name="jetty-parent-25.pom">
|
||||
<sha256 value="d6d9cc8ea606d1c2e22d8101d92243ffccfdc4998935a99c459b9d9b1a14ba6c"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-project" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-project-9.3.6.v20151106.pom">
|
||||
<sha256 value="ecdb3554dc53490b385486d8c85d43c762602053814f267e6307888e606fb616"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-security" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-security-9.3.6.v20151106.jar">
|
||||
<sha256 value="d9729341568a245f3c028991c328e5fce35294f026fdfb9e2ab628ff34975fb5"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-security-9.3.6.v20151106.pom">
|
||||
<sha256 value="8e21f15c54b904b7170221e2142db9ce8bfb8d60d4d86b8fce09c98572fc5c0b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-server" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-server-9.3.6.v20151106.jar">
|
||||
<sha256 value="2277b6211e1db363d0cb22317f49906cd906dd47ca93f397cffead618dc052ea"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-server-9.3.6.v20151106.pom">
|
||||
<sha256 value="5381892323929d0367d6c90efc0b808ba871e59ed536425a448ec0e0f8f9c64f"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-servlet" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-servlet-9.3.6.v20151106.jar">
|
||||
<sha256 value="4aabcb8c4b32918cdc66f6b4e48ba08276559f3d3eba6919cb49c221d08bb7f9"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-servlet-9.3.6.v20151106.pom">
|
||||
<sha256 value="ed9b9ebfe9ac1153623288846d645fed319c3b33ee6586feef06b606640336c0"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-util" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-util-9.3.6.v20151106.jar">
|
||||
<sha256 value="3149d7cb665e3b7a37809fb9915a4c4ef190ec3d2d80d6c15207bde075224304"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-util-9.3.6.v20151106.pom">
|
||||
<sha256 value="f1244c89163b51d8e8456668c57e4c1490340a3e3e0c1be8040a19113a0a16e0"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-webapp" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-webapp-9.3.6.v20151106.jar">
|
||||
<sha256 value="2e1805b52831dc88d2c19f1ee660609f337e2ec3007c9931dac65b7867f4aff1"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-webapp-9.3.6.v20151106.pom">
|
||||
<sha256 value="eafd83acd89e883e4e0329fa6fdfb6149ccb61c26d86a8b6e82bc9815bf77842"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty" name="jetty-xml" version="9.3.6.v20151106">
|
||||
<artifact name="jetty-xml-9.3.6.v20151106.jar">
|
||||
<sha256 value="58a7c092323e9bff29fa7cd9ca072f5d7fb8e5806342c941b9780c5cbfcaf112"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="jetty-xml-9.3.6.v20151106.pom">
|
||||
<sha256 value="7010066948db798bea3397eb26e1ef7ff32c3020fad234128699018f1e5e9647"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-api" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-api-9.3.6.v20151106.jar">
|
||||
<sha256 value="541a2c575082b6eec72a2ac59d7397301c41991978768b6b5c9d261ec9a25755"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="websocket-api-9.3.6.v20151106.pom">
|
||||
<sha256 value="0626548a896902b77ababde8822793079556b292987c289024c46bf0cda70aae"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-client" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-client-9.3.6.v20151106.jar">
|
||||
<sha256 value="c4e74f5b2b9ec4b71ecc5c852039f5f43101d0b7332b9c95924591c633427518"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="websocket-client-9.3.6.v20151106.pom">
|
||||
<sha256 value="331955c08e8219cab644221f10de1b1999a27b8fcaca016209873743f238900f"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-common" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-common-9.3.6.v20151106.jar">
|
||||
<sha256 value="df209f43c7d4485263088d1947e9ef20b450218b1c520c14654dcf25b0bd0793"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="websocket-common-9.3.6.v20151106.pom">
|
||||
<sha256 value="a1ef4eb749ef73795a10ea6a9db98802c3d4e68b4089563e803a23ba54e79fee"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-parent" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-parent-9.3.6.v20151106.pom">
|
||||
<sha256 value="60cb05f669bcc0fddbdfa4479f8aa84b6a6479139ef9cec9dcd56686cb09f39b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-server" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-server-9.3.6.v20151106.jar">
|
||||
<sha256 value="cfe658a601eff23ee151c03672ad838388365f79d98556a04be130ac7c11cf4d"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="websocket-server-9.3.6.v20151106.pom">
|
||||
<sha256 value="f21c663407fc22327bf1633c5fd0dd6cda71806734a72c08b9ad6800a41c352b"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.eclipse.jetty.websocket" name="websocket-servlet" version="9.3.6.v20151106">
|
||||
<artifact name="websocket-servlet-9.3.6.v20151106.jar">
|
||||
<sha256 value="fa8d1146605c66b732d5c03066800fee63e4822cde688d189db4a336a442f412"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="websocket-servlet-9.3.6.v20151106.pom">
|
||||
<sha256 value="b2f19e3f5d3c0e225b9d2acd375afab8dca1ad2b8faab54c68789da7e0308abf"
|
||||
origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.fxmisc.easybind" name="easybind" version="1.0.3">
|
||||
<artifact name="easybind-1.0.3.jar">
|
||||
|
57
inventory/build.gradle
Normal file
57
inventory/build.gradle
Normal file
@ -0,0 +1,57 @@
|
||||
plugins {
|
||||
id 'bisq.application'
|
||||
id 'bisq.gradle.app_start_plugin.AppStartPlugin'
|
||||
}
|
||||
mainClassName = 'bisq.inventory.InventoryMonitorMain'
|
||||
|
||||
distTar.enabled = true
|
||||
|
||||
dependencies {
|
||||
implementation project(':proto')
|
||||
implementation project(':common')
|
||||
implementation project(':p2p')
|
||||
implementation project(':core')
|
||||
annotationProcessor libs.lombok
|
||||
compileOnly libs.javax.annotation
|
||||
compileOnly libs.lombok
|
||||
implementation libs.logback.classic
|
||||
implementation libs.logback.core
|
||||
implementation libs.google.gson
|
||||
implementation libs.google.guava
|
||||
implementation libs.protobuf.java
|
||||
implementation libs.apache.commons.lang3
|
||||
implementation libs.jetbrains.annotations
|
||||
implementation libs.slf4j.api
|
||||
implementation(libs.bitcoinj) {
|
||||
exclude(module: 'bcprov-jdk15on')
|
||||
exclude(module: 'guava')
|
||||
exclude(module: 'jsr305')
|
||||
exclude(module: 'okhttp')
|
||||
exclude(module: 'okio')
|
||||
exclude(module: 'protobuf-java')
|
||||
exclude(module: 'slf4j-api')
|
||||
}
|
||||
|
||||
implementation libs.spark.core
|
||||
implementation libs.pushy
|
||||
implementation libs.commons.codec
|
||||
implementation libs.grpc.auth
|
||||
|
||||
implementation(libs.google.guice) {
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
implementation(libs.grpc.protobuf) {
|
||||
exclude(module: 'animal-sniffer-annotations')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
implementation(libs.grpc.stub) {
|
||||
exclude(module: 'animal-sniffer-annotations')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
runtimeOnly(libs.grpc.netty.shaded) {
|
||||
exclude(module: 'animal-sniffer-annotations')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
testAnnotationProcessor libs.lombok
|
||||
testCompileOnly libs.lombok
|
||||
}
|
291
inventory/src/main/java/bisq/inventory/InventoryMonitor.java
Normal file
291
inventory/src/main/java/bisq/inventory/InventoryMonitor.java
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.inventory;
|
||||
|
||||
|
||||
import bisq.core.app.TorSetup;
|
||||
import bisq.core.network.p2p.inventory.GetInventoryRequestManager;
|
||||
import bisq.core.network.p2p.inventory.model.Average;
|
||||
import bisq.core.network.p2p.inventory.model.DeviationSeverity;
|
||||
import bisq.core.network.p2p.inventory.model.InventoryItem;
|
||||
import bisq.core.network.p2p.inventory.model.RequestInfo;
|
||||
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
|
||||
import bisq.core.proto.network.CoreNetworkProtoResolver;
|
||||
import bisq.core.util.JsonUtil;
|
||||
|
||||
import bisq.network.p2p.NetworkNodeProvider;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.network.NetworkNode;
|
||||
import bisq.network.p2p.network.SetupListener;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.config.BaseCurrencyNetwork;
|
||||
import bisq.common.file.JsonFileManager;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import java.time.Clock;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Slf4j
|
||||
public class InventoryMonitor implements SetupListener {
|
||||
private final Map<NodeAddress, JsonFileManager> jsonFileManagerByNodeAddress = new HashMap<>();
|
||||
private final Map<NodeAddress, List<RequestInfo>> requestInfoListByNode = new HashMap<>();
|
||||
private final File appDir;
|
||||
private final boolean useLocalhostForP2P;
|
||||
private final int intervalSec;
|
||||
private NetworkNode networkNode;
|
||||
private GetInventoryRequestManager getInventoryRequestManager;
|
||||
|
||||
private ArrayList<NodeAddress> seedNodes;
|
||||
private InventoryWebServer inventoryWebServer;
|
||||
private int requestCounter = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public InventoryMonitor(File appDir,
|
||||
boolean useLocalhostForP2P,
|
||||
BaseCurrencyNetwork network,
|
||||
int intervalSec,
|
||||
int port,
|
||||
boolean cleanupTorFiles) {
|
||||
this.appDir = appDir;
|
||||
this.useLocalhostForP2P = useLocalhostForP2P;
|
||||
this.intervalSec = intervalSec;
|
||||
|
||||
// We get more connectivity issues. Cleaning tor cache files helps usually for those problems.
|
||||
File torDir = new File(appDir, "tor");
|
||||
if (!torDir.exists()) {
|
||||
torDir.mkdir();
|
||||
}
|
||||
TorSetup torSetup = new TorSetup(torDir);
|
||||
if (cleanupTorFiles) {
|
||||
torSetup.cleanupTorFiles(() -> initialize(network, port, torDir), log::error);
|
||||
} else {
|
||||
initialize(network, port, torDir);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(BaseCurrencyNetwork network, int port, File torDir) {
|
||||
networkNode = getNetworkNode(torDir);
|
||||
getInventoryRequestManager = new GetInventoryRequestManager(networkNode);
|
||||
|
||||
// We maintain our own list as we want to monitor also old v2 nodes which are not part of the normal seed
|
||||
// node list anymore.
|
||||
String networkName = network.name().toLowerCase();
|
||||
String fileName = network.isMainnet() ? "inv_" + networkName : networkName;
|
||||
DefaultSeedNodeRepository.readSeedNodePropertyFile(fileName)
|
||||
.ifPresent(bufferedReader -> {
|
||||
seedNodes = new ArrayList<>(DefaultSeedNodeRepository.getSeedNodeAddressesFromPropertyFile(fileName));
|
||||
addJsonFileManagers(seedNodes);
|
||||
inventoryWebServer = new InventoryWebServer(port, seedNodes, bufferedReader);
|
||||
networkNode.start(this);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void shutDown(Runnable shutDownCompleteHandler) {
|
||||
networkNode.shutDown(shutDownCompleteHandler);
|
||||
jsonFileManagerByNodeAddress.values().forEach(JsonFileManager::shutDown);
|
||||
inventoryWebServer.shutDown();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetupListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onTorNodeReady() {
|
||||
UserThread.runPeriodically(this::requestFromAllSeeds, intervalSec);
|
||||
requestFromAllSeeds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHiddenServicePublished() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges() {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void requestFromAllSeeds() {
|
||||
requestCounter++;
|
||||
seedNodes.forEach(nodeAddress -> {
|
||||
RequestInfo requestInfo = new RequestInfo(System.currentTimeMillis());
|
||||
new Thread(() -> {
|
||||
Thread.currentThread().setName("request @ " + getShortAddress(nodeAddress, useLocalhostForP2P));
|
||||
getInventoryRequestManager.request(nodeAddress,
|
||||
result -> processResponse(nodeAddress, requestInfo, result, null),
|
||||
errorMessage -> processResponse(nodeAddress, requestInfo, null, errorMessage));
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
|
||||
private void processResponse(NodeAddress nodeAddress,
|
||||
RequestInfo requestInfo,
|
||||
@Nullable Map<InventoryItem, String> result,
|
||||
@Nullable String errorMessage) {
|
||||
if (errorMessage != null && !errorMessage.isEmpty()) {
|
||||
log.warn("Error at connection to peer {}: {}", nodeAddress, errorMessage);
|
||||
requestInfo.setErrorMessage(errorMessage);
|
||||
} else {
|
||||
requestInfo.setResponseTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
boolean ignoreDeviationAtStartup;
|
||||
if (result != null) {
|
||||
log.info("nodeAddress={}, result={}", nodeAddress, result.toString());
|
||||
|
||||
// If seed just started up we ignore the deviation as it can be expected that seed is still syncing
|
||||
// DAO state/blocks. P2P data should be ready but as we received it from other seeds it is not that
|
||||
// valuable information either, so we apply the ignore to all data.
|
||||
if (result.containsKey(InventoryItem.jvmStartTime)) {
|
||||
String jvmStartTimeString = result.get(InventoryItem.jvmStartTime);
|
||||
long jvmStartTime = Long.parseLong(jvmStartTimeString);
|
||||
ignoreDeviationAtStartup = jvmStartTime < TimeUnit.MINUTES.toMillis(2);
|
||||
} else {
|
||||
ignoreDeviationAtStartup = false;
|
||||
}
|
||||
} else {
|
||||
ignoreDeviationAtStartup = false;
|
||||
}
|
||||
|
||||
requestInfoListByNode.putIfAbsent(nodeAddress, new ArrayList<>());
|
||||
List<RequestInfo> requestInfoList = requestInfoListByNode.get(nodeAddress);
|
||||
|
||||
|
||||
// We create average of all nodes latest results. It might be that the nodes last result is
|
||||
// from a previous request as the response has not arrived yet.
|
||||
//TODO might be not a good idea to use the last result if its not a recent one. a faulty node would distort
|
||||
// the average calculation.
|
||||
// As we add at the end our own result the average is excluding our own value
|
||||
Collection<List<RequestInfo>> requestInfoListByNodeValues = requestInfoListByNode.values();
|
||||
Set<RequestInfo> requestInfoSet = requestInfoListByNodeValues.stream()
|
||||
.filter(list -> !list.isEmpty())
|
||||
.map(list -> list.get(list.size() - 1))
|
||||
.collect(Collectors.toSet());
|
||||
Map<InventoryItem, Double> averageValues = Average.of(requestInfoSet);
|
||||
|
||||
String daoStateChainHeight = result != null &&
|
||||
result.containsKey(InventoryItem.daoStateChainHeight) ?
|
||||
result.get(InventoryItem.daoStateChainHeight) :
|
||||
null;
|
||||
List.of(InventoryItem.values()).forEach(inventoryItem -> {
|
||||
String value = result != null ? result.get(inventoryItem) : null;
|
||||
Tuple2<Double, Double> tuple = inventoryItem.getDeviationAndAverage(averageValues, value);
|
||||
Double deviation = tuple != null ? tuple.first : null;
|
||||
Double average = tuple != null ? tuple.second : null;
|
||||
DeviationSeverity deviationSeverity = ignoreDeviationAtStartup ? DeviationSeverity.IGNORED :
|
||||
inventoryItem.getDeviationSeverity(deviation,
|
||||
requestInfoListByNodeValues,
|
||||
value,
|
||||
daoStateChainHeight);
|
||||
int endIndex = Math.max(0, requestInfoList.size() - 1);
|
||||
int deviationTolerance = inventoryItem.getDeviationTolerance();
|
||||
int fromIndex = Math.max(0, endIndex - deviationTolerance);
|
||||
List<DeviationSeverity> lastDeviationSeverityEntries = requestInfoList.subList(fromIndex, endIndex).stream()
|
||||
.filter(e -> e.getDataMap().containsKey(inventoryItem))
|
||||
.map(e -> e.getDataMap().get(inventoryItem).getDeviationSeverity())
|
||||
.collect(Collectors.toList());
|
||||
long numWarnings = lastDeviationSeverityEntries.stream()
|
||||
.filter(e -> e == DeviationSeverity.WARN)
|
||||
.count();
|
||||
long numAlerts = lastDeviationSeverityEntries.stream()
|
||||
.filter(e -> e == DeviationSeverity.ALERT)
|
||||
.count();
|
||||
boolean persistentWarning = numWarnings == deviationTolerance;
|
||||
boolean persistentAlert = numAlerts == deviationTolerance;
|
||||
RequestInfo.Data data = new RequestInfo.Data(value, average, deviation, deviationSeverity, persistentWarning, persistentAlert);
|
||||
requestInfo.getDataMap().put(inventoryItem, data);
|
||||
});
|
||||
|
||||
requestInfoList.add(requestInfo);
|
||||
|
||||
inventoryWebServer.onNewRequestInfo(requestInfoListByNode, requestCounter);
|
||||
|
||||
String json = JsonUtil.objectToJson(requestInfo);
|
||||
jsonFileManagerByNodeAddress.get(nodeAddress).writeToDisc(json, String.valueOf(requestInfo.getRequestStartTime()));
|
||||
}
|
||||
|
||||
private void addJsonFileManagers(List<NodeAddress> seedNodes) {
|
||||
File jsonDir = new File(appDir, "json");
|
||||
if (!jsonDir.exists() && !jsonDir.mkdir()) {
|
||||
log.warn("make jsonDir failed");
|
||||
}
|
||||
seedNodes.forEach(nodeAddress -> {
|
||||
JsonFileManager jsonFileManager = new JsonFileManager(new File(jsonDir, getShortAddress(nodeAddress, useLocalhostForP2P)));
|
||||
jsonFileManagerByNodeAddress.put(nodeAddress, jsonFileManager);
|
||||
});
|
||||
}
|
||||
|
||||
private NetworkNode getNetworkNode(File torDir) {
|
||||
CoreNetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone());
|
||||
return new NetworkNodeProvider(networkProtoResolver,
|
||||
() -> null,
|
||||
null,
|
||||
12,
|
||||
useLocalhostForP2P,
|
||||
9999,
|
||||
torDir,
|
||||
null,
|
||||
"",
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
null,
|
||||
false,
|
||||
false)
|
||||
.get();
|
||||
}
|
||||
|
||||
private String getShortAddress(NodeAddress nodeAddress, boolean useLocalhostForP2P) {
|
||||
return useLocalhostForP2P ?
|
||||
nodeAddress.getFullAddress().replace(":", "_") :
|
||||
nodeAddress.getFullAddress().substring(0, 10);
|
||||
}
|
||||
}
|
135
inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java
Normal file
135
inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.inventory;
|
||||
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.AsciiLogo;
|
||||
import bisq.common.app.Log;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.config.BaseCurrencyNetwork;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
|
||||
import sun.misc.Signal;
|
||||
|
||||
@Slf4j
|
||||
public class InventoryMonitorMain {
|
||||
|
||||
private static InventoryMonitor inventoryMonitor;
|
||||
private static boolean stopped;
|
||||
|
||||
// prog args for regtest: 10 1 BTC_REGTEST
|
||||
public static void main(String[] args) {
|
||||
// Default values
|
||||
int intervalSec = 120;
|
||||
boolean useLocalhostForP2P = false;
|
||||
BaseCurrencyNetwork network = BaseCurrencyNetwork.BTC_MAINNET;
|
||||
int port = 8080;
|
||||
|
||||
if (args.length > 0) {
|
||||
intervalSec = Integer.parseInt(args[0]);
|
||||
}
|
||||
if (args.length > 1) {
|
||||
useLocalhostForP2P = args[1].equals("1");
|
||||
}
|
||||
if (args.length > 2) {
|
||||
network = BaseCurrencyNetwork.valueOf(args[2]);
|
||||
}
|
||||
if (args.length > 3) {
|
||||
port = Integer.parseInt(args[3]);
|
||||
}
|
||||
|
||||
// todo
|
||||
boolean cleanupTorFiles = false;
|
||||
|
||||
String appName = "bisq-inventory-monitor-" + network;
|
||||
File appDir = new File(Utilities.getUserDataDir(), appName);
|
||||
if (!appDir.exists() && !appDir.mkdir()) {
|
||||
log.warn("make appDir failed");
|
||||
}
|
||||
inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec, port, cleanupTorFiles);
|
||||
|
||||
setup(network, appDir);
|
||||
|
||||
// We shutdown after 5 days to avoid potential memory leak issue.
|
||||
// The start script will restart the app.
|
||||
UserThread.runAfter(InventoryMonitorMain::shutDown, TimeUnit.DAYS.toSeconds(5));
|
||||
}
|
||||
|
||||
private static void setup(BaseCurrencyNetwork network, File appDir) {
|
||||
String logPath = Paths.get(appDir.getPath(), "bisq").toString();
|
||||
Log.setup(logPath);
|
||||
Log.setLevel(Level.INFO);
|
||||
AsciiLogo.showAsciiLogo();
|
||||
Version.setBaseCryptoNetworkId(network.ordinal());
|
||||
|
||||
Res.setup(); // Used for some formatting in the webserver
|
||||
|
||||
// We do not set any capabilities as we don't want to receive any network data beside our response.
|
||||
// We also do not use capabilities for the request/response messages as we only connect to seeds nodes and
|
||||
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNameFormat(inventoryMonitor.getClass().getSimpleName())
|
||||
.setDaemon(true)
|
||||
.build();
|
||||
UserThread.setExecutor(Executors.newSingleThreadExecutor(threadFactory));
|
||||
|
||||
Signal.handle(new Signal("INT"), signal -> {
|
||||
UserThread.execute(InventoryMonitorMain::shutDown);
|
||||
});
|
||||
|
||||
Signal.handle(new Signal("TERM"), signal -> {
|
||||
UserThread.execute(InventoryMonitorMain::shutDown);
|
||||
});
|
||||
keepRunning();
|
||||
}
|
||||
|
||||
private static void shutDown() {
|
||||
stopped = true;
|
||||
inventoryMonitor.shutDown(() -> {
|
||||
System.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
private static void keepRunning() {
|
||||
while (!stopped) {
|
||||
try {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
552
inventory/src/main/java/bisq/inventory/InventoryWebServer.java
Normal file
552
inventory/src/main/java/bisq/inventory/InventoryWebServer.java
Normal file
@ -0,0 +1,552 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.inventory;
|
||||
|
||||
import bisq.core.network.p2p.inventory.model.DeviationByIntegerDiff;
|
||||
import bisq.core.network.p2p.inventory.model.DeviationByPercentage;
|
||||
import bisq.core.network.p2p.inventory.model.DeviationSeverity;
|
||||
import bisq.core.network.p2p.inventory.model.InventoryItem;
|
||||
import bisq.core.network.p2p.inventory.model.RequestInfo;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
|
||||
import spark.Spark;
|
||||
|
||||
@Slf4j
|
||||
public class InventoryWebServer {
|
||||
private final static String CLOSE_TAG = "</font><br/>";
|
||||
private final static String WARNING_ICON = "⚠ ";
|
||||
private final static String ALERT_ICON = "☠ "; // ⚡ ⚡
|
||||
|
||||
private final List<NodeAddress> seedNodes;
|
||||
private final Map<String, String> operatorByNodeAddress = new HashMap<>();
|
||||
|
||||
private String html;
|
||||
private int requestCounter;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public InventoryWebServer(int port,
|
||||
List<NodeAddress> seedNodes,
|
||||
BufferedReader seedNodeFile) {
|
||||
this.seedNodes = seedNodes;
|
||||
setupOperatorMap(seedNodeFile);
|
||||
|
||||
Spark.port(port);
|
||||
Spark.get("/", (req, res) -> {
|
||||
log.info("Incoming request from: {}", req.userAgent());
|
||||
return html == null ? "Starting up..." : html;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void onNewRequestInfo(Map<NodeAddress, List<RequestInfo>> requestInfoListByNode, int requestCounter) {
|
||||
this.requestCounter = requestCounter;
|
||||
html = generateHtml(requestInfoListByNode);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
Spark.stop();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// HTML
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private String generateHtml(Map<NodeAddress, List<RequestInfo>> map) {
|
||||
StringBuilder html = new StringBuilder();
|
||||
html.append("<html>" +
|
||||
"<head>" +
|
||||
"<style type=\"text/css\">" +
|
||||
" a {" +
|
||||
" text-decoration:none; color: black;" +
|
||||
" }" +
|
||||
" #warn { color: #ff7700; } " +
|
||||
" #alert { color: #ff0000; } " +
|
||||
"table, th, td {border: 1px solid black;}" +
|
||||
"</style></head>" +
|
||||
"<body><h3>")
|
||||
.append("Current time: ").append(new Date().toString()).append("<br/>")
|
||||
.append("Request cycle: ").append(requestCounter).append("<br/>")
|
||||
.append("Version/commit: ").append(Version.VERSION).append(" / ").append("TODO RequestInfo.COMMIT_HASH").append("<br/>")
|
||||
.append("<table style=\"width:100%\">")
|
||||
.append("<tr>")
|
||||
.append("<th align=\"left\">Seed node info</th>")
|
||||
.append("<th align=\"left\">Request info</th>")
|
||||
.append("<th align=\"left\">Data inventory</th>")
|
||||
.append("<th align=\"left\">DAO data</th>")
|
||||
.append("<th align=\"left\">Network info</th>").append("</tr>");
|
||||
|
||||
seedNodes.forEach(seedNode -> {
|
||||
html.append("<tr valign=\"top\">");
|
||||
if (map.containsKey(seedNode) && !map.get(seedNode).isEmpty()) {
|
||||
List<RequestInfo> list = map.get(seedNode);
|
||||
int numRequests = list.size();
|
||||
RequestInfo requestInfo = list.get(numRequests - 1);
|
||||
html.append("<td>").append(getSeedNodeInfo(seedNode, requestInfo)).append("</td>")
|
||||
.append("<td>").append(getRequestInfo(seedNode, requestInfo, numRequests, map)).append("</td>")
|
||||
.append("<td>").append(getDataInfo(seedNode, requestInfo, map)).append("</td>")
|
||||
.append("<td>").append(getDaoInfo(seedNode, requestInfo, map)).append("</td>")
|
||||
.append("<td>").append(getNetworkInfo(seedNode, requestInfo, map)).append("</td>");
|
||||
} else {
|
||||
html.append("<td>").append(getSeedNodeInfo(seedNode, null)).append("</td>")
|
||||
.append("<td>").append("n/a").append("</td>")
|
||||
.append("<td>").append("n/a").append("</td>")
|
||||
.append("<td>").append("n/a").append("</td>")
|
||||
.append("<td>").append("n/a").append("</td>");
|
||||
}
|
||||
html.append("</tr>");
|
||||
});
|
||||
|
||||
html.append("</table></body></html>");
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sub sections
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private String getSeedNodeInfo(NodeAddress nodeAddress,
|
||||
@Nullable RequestInfo requestInfo) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
String operator = operatorByNodeAddress.get(nodeAddress.getFullAddress());
|
||||
sb.append("Operator: ").append(operator).append("<br/>");
|
||||
|
||||
String address = nodeAddress.getFullAddress();
|
||||
|
||||
String filteredSeeds = requestInfo != null ? requestInfo.getValue(InventoryItem.filteredSeeds) : null;
|
||||
if (filteredSeeds != null && filteredSeeds.contains(address)) {
|
||||
sb.append(getColorTagByDeviationSeverity(DeviationSeverity.ALERT)).append("Node address: ")
|
||||
.append(address).append(" (is filtered!)").append(CLOSE_TAG);
|
||||
} else {
|
||||
sb.append("Node address: ").append(address).append("<br/>");
|
||||
}
|
||||
|
||||
if (requestInfo != null) {
|
||||
sb.append("Version: ").append(requestInfo.getDisplayValue(InventoryItem.version)).append("<br/>");
|
||||
sb.append("Commit hash: ").append(requestInfo.getDisplayValue(InventoryItem.commitHash)).append("<br/>");
|
||||
String memory = requestInfo.getValue(InventoryItem.usedMemory);
|
||||
String memoryString = memory != null ? Utilities.readableFileSize(Long.parseLong(memory)) : "n/a";
|
||||
sb.append("Memory used: ")
|
||||
.append(memoryString)
|
||||
.append("<br/>");
|
||||
|
||||
String jvmStartTimeString = requestInfo.getValue(InventoryItem.jvmStartTime);
|
||||
long jvmStartTime = jvmStartTimeString != null ? Long.parseLong(jvmStartTimeString) : 0;
|
||||
sb.append("Node started at: ")
|
||||
.append(new Date(jvmStartTime).toString())
|
||||
.append("<br/>");
|
||||
|
||||
String duration = jvmStartTime > 0 ?
|
||||
FormattingUtils.formatDurationAsWords(System.currentTimeMillis() - jvmStartTime,
|
||||
true, true) :
|
||||
"n/a";
|
||||
sb.append("Run duration: ").append(duration).append("<br/>");
|
||||
|
||||
String filteredSeedNodes = requestInfo.getDisplayValue(InventoryItem.filteredSeeds)
|
||||
.replace(System.getProperty("line.separator"), "<br/>");
|
||||
if (filteredSeedNodes.isEmpty()) {
|
||||
filteredSeedNodes = "-";
|
||||
}
|
||||
sb.append("Filtered seed nodes: ")
|
||||
.append(filteredSeedNodes)
|
||||
.append("<br/>");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getRequestInfo(NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
int numRequests,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
DeviationSeverity deviationSeverity = numRequests == requestCounter ?
|
||||
DeviationSeverity.OK :
|
||||
requestCounter - numRequests > 4 ?
|
||||
DeviationSeverity.ALERT :
|
||||
DeviationSeverity.WARN;
|
||||
sb.append("Number of requests: ").append(getColorTagByDeviationSeverity(deviationSeverity))
|
||||
.append(numRequests).append(CLOSE_TAG);
|
||||
|
||||
DeviationSeverity rrtDeviationSeverity = DeviationSeverity.OK;
|
||||
String rrtString = "n/a";
|
||||
if (requestInfo.getResponseTime() > 0) {
|
||||
long rrt = requestInfo.getResponseTime() - requestInfo.getRequestStartTime();
|
||||
if (rrt > 20_000) {
|
||||
rrtDeviationSeverity = DeviationSeverity.ALERT;
|
||||
} else if (rrt > 10_000) {
|
||||
rrtDeviationSeverity = DeviationSeverity.WARN;
|
||||
}
|
||||
rrtString = MathUtils.roundDouble(rrt / 1000d, 3) + " sec";
|
||||
|
||||
}
|
||||
sb.append("Round trip time: ").append(getColorTagByDeviationSeverity(rrtDeviationSeverity))
|
||||
.append(rrtString).append(CLOSE_TAG);
|
||||
|
||||
Date requestStartTime = new Date(requestInfo.getRequestStartTime());
|
||||
sb.append("Requested at: ").append(requestStartTime).append("<br/>");
|
||||
|
||||
String responseTime = requestInfo.getResponseTime() > 0 ?
|
||||
new Date(requestInfo.getResponseTime()).toString() :
|
||||
"n/a";
|
||||
sb.append("Response received at: ").append(responseTime).append("<br/>");
|
||||
|
||||
sb.append(getErrorMsgLine(seedNode, requestInfo, map));
|
||||
|
||||
sb.append(getLastSuccessfulResponseLine(seedNode, map));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getDataInfo(NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(getLine(InventoryItem.OfferPayload, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.MailboxStoragePayload, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.TradeStatistics3, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.AccountAgeWitness, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.SignedWitness, seedNode, requestInfo, map));
|
||||
|
||||
sb.append(getLine(InventoryItem.Alert, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.Filter, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.Mediator, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.RefundAgent, seedNode, requestInfo, map));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getDaoInfo(NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(getLine("Number of BSQ blocks: ", InventoryItem.numBsqBlocks, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.TempProposalPayload, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.ProposalPayload, seedNode, requestInfo, map));
|
||||
sb.append(getLine(InventoryItem.BlindVotePayload, seedNode, requestInfo, map));
|
||||
sb.append(getLine("DAO state block height: ", InventoryItem.daoStateChainHeight, seedNode, requestInfo, map));
|
||||
|
||||
sb.append(getLine("DAO state hash: ", InventoryItem.daoStateHash, seedNode, requestInfo, map));
|
||||
|
||||
// The hash for proposal changes only at first block of blind vote phase but as we do not want to initialize the
|
||||
// dao domain we cannot check that. But we also don't need that as we can just compare that all hashes at all
|
||||
// blocks from all seeds are the same. Same for blindVoteHash.
|
||||
sb.append(getLine("Proposal state hash: ", InventoryItem.proposalHash, seedNode, requestInfo, map));
|
||||
sb.append(getLine("Blind vote state hash: ", InventoryItem.blindVoteHash, seedNode, requestInfo, map));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getNetworkInfo(NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(getLine("Max. connections: ",
|
||||
InventoryItem.maxConnections, seedNode, requestInfo, map));
|
||||
sb.append(getLine("Number of connections: ",
|
||||
InventoryItem.numConnections, seedNode, requestInfo, map));
|
||||
sb.append(getLine("Peak number of connections: ",
|
||||
InventoryItem.peakNumConnections, seedNode, requestInfo, map));
|
||||
sb.append(getLine("Number of 'All connections lost' events: ",
|
||||
InventoryItem.numAllConnectionsLostEvents, seedNode, requestInfo, map));
|
||||
|
||||
sb.append(getLine("Sent messages/sec: ",
|
||||
InventoryItem.sentMessagesPerSec, seedNode, requestInfo, map, this::getRounded));
|
||||
sb.append(getLine("Received messages/sec: ",
|
||||
InventoryItem.receivedMessagesPerSec, seedNode, requestInfo, map, this::getRounded));
|
||||
sb.append(getLine("Sent kB/sec: ",
|
||||
InventoryItem.sentBytesPerSec, seedNode, requestInfo, map, this::getKbRounded));
|
||||
sb.append(getLine("Received kB/sec: ",
|
||||
InventoryItem.receivedBytesPerSec, seedNode, requestInfo, map, this::getKbRounded));
|
||||
sb.append(getLine("Sent data: ",
|
||||
InventoryItem.sentBytes, seedNode, requestInfo, map,
|
||||
value -> Utilities.readableFileSize(Long.parseLong(value))));
|
||||
sb.append(getLine("Received data: ",
|
||||
InventoryItem.receivedBytes, seedNode, requestInfo, map,
|
||||
value -> Utilities.readableFileSize(Long.parseLong(value))));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private String getLine(InventoryItem inventoryItem,
|
||||
NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
return getLine(getTitle(inventoryItem),
|
||||
inventoryItem,
|
||||
seedNode,
|
||||
requestInfo,
|
||||
map);
|
||||
}
|
||||
|
||||
private String getLine(String title,
|
||||
InventoryItem inventoryItem,
|
||||
NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
return getLine(title,
|
||||
inventoryItem,
|
||||
seedNode,
|
||||
requestInfo,
|
||||
map,
|
||||
null);
|
||||
}
|
||||
|
||||
private String getLine(String title,
|
||||
InventoryItem inventoryItem,
|
||||
NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map,
|
||||
@Nullable Function<String, String> formatter) {
|
||||
String displayValue = requestInfo.getDisplayValue(inventoryItem);
|
||||
String value = requestInfo.getValue(inventoryItem);
|
||||
if (formatter != null && value != null) {
|
||||
displayValue = formatter.apply(value);
|
||||
}
|
||||
|
||||
String deviationAsPercentString = "";
|
||||
DeviationSeverity deviationSeverity = DeviationSeverity.OK;
|
||||
if (requestInfo.getDataMap().containsKey(inventoryItem)) {
|
||||
RequestInfo.Data data = requestInfo.getDataMap().get(inventoryItem);
|
||||
deviationAsPercentString = getDeviationAsPercentString(inventoryItem, data);
|
||||
deviationSeverity = data.getDeviationSeverity();
|
||||
}
|
||||
|
||||
List<RequestInfo> requestInfoList = map.get(seedNode);
|
||||
String historicalWarnings = "";
|
||||
String historicalAlerts = "";
|
||||
List<String> warningsAtRequestNumber = new ArrayList<>();
|
||||
List<String> alertsAtRequestNumber = new ArrayList<>();
|
||||
if (requestInfoList != null) {
|
||||
for (int i = 0; i < requestInfoList.size(); i++) {
|
||||
RequestInfo reqInfo = requestInfoList.get(i);
|
||||
Map<InventoryItem, RequestInfo.Data> deviationInfoMap = reqInfo.getDataMap();
|
||||
if (deviationInfoMap.containsKey(inventoryItem)) {
|
||||
RequestInfo.Data data = deviationInfoMap.get(inventoryItem);
|
||||
String deviationAsPercent = getDeviationAsPercentString(inventoryItem, data);
|
||||
if (data.isPersistentWarning()) {
|
||||
warningsAtRequestNumber.add((i + 1) + deviationAsPercent);
|
||||
} else if (data.isPersistentAlert()) {
|
||||
alertsAtRequestNumber.add((i + 1) + deviationAsPercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!warningsAtRequestNumber.isEmpty()) {
|
||||
historicalWarnings = warningsAtRequestNumber.size() + " repeated warning(s) at request(s) " +
|
||||
Joiner.on(", ").join(warningsAtRequestNumber);
|
||||
}
|
||||
if (!alertsAtRequestNumber.isEmpty()) {
|
||||
historicalAlerts = alertsAtRequestNumber.size() + " repeated alert(s) at request(s): " +
|
||||
Joiner.on(", ").join(alertsAtRequestNumber);
|
||||
}
|
||||
}
|
||||
String historicalWarningsHtml = warningsAtRequestNumber.isEmpty() ? "" :
|
||||
", <b><a id=\"warn\" href=\"#\" title=\"" + historicalWarnings + "\">" + WARNING_ICON +
|
||||
warningsAtRequestNumber.size() + "</a></b>";
|
||||
String historicalAlertsHtml = alertsAtRequestNumber.isEmpty() ? "" :
|
||||
", <b><a id=\"alert\" href=\"#\" title=\"" + historicalAlerts + "\">" + ALERT_ICON +
|
||||
alertsAtRequestNumber.size() + "</a></b>";
|
||||
|
||||
return title +
|
||||
getColorTagByDeviationSeverity(deviationSeverity) +
|
||||
displayValue +
|
||||
deviationAsPercentString +
|
||||
historicalWarningsHtml +
|
||||
historicalAlertsHtml +
|
||||
CLOSE_TAG;
|
||||
}
|
||||
|
||||
private String getDeviationAsPercentString(InventoryItem inventoryItem, RequestInfo.Data data) {
|
||||
Double deviation = data.getDeviation();
|
||||
if (deviation == null || deviation == 1) {
|
||||
return "";
|
||||
}
|
||||
if (inventoryItem.getDeviationType() instanceof DeviationByPercentage) {
|
||||
return getDeviationInRoundedPercent(deviation);
|
||||
} else if (inventoryItem.getDeviationType() instanceof DeviationByIntegerDiff) {
|
||||
// For larger numbers like chain height we need to show all decimals as diff can be very small
|
||||
return getDeviationInExactPercent(deviation);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getDeviationInRoundedPercent(double deviation) {
|
||||
return " (" + MathUtils.roundDouble(100 * deviation, 2) + " %)";
|
||||
}
|
||||
|
||||
private String getDeviationInExactPercent(double deviation) {
|
||||
return " (" + 100 * deviation + " %)";
|
||||
}
|
||||
|
||||
private String getColorTagByDeviationSeverity(@Nullable DeviationSeverity deviationSeverity) {
|
||||
if (deviationSeverity == null) {
|
||||
return "<font color=\"black\">";
|
||||
}
|
||||
|
||||
switch (deviationSeverity) {
|
||||
case WARN:
|
||||
return "<font color=\"#0000cc\">";
|
||||
case ALERT:
|
||||
return "<font color=\"#cc0000\">";
|
||||
case IGNORED:
|
||||
return "<font color=\"#333333\">";
|
||||
case OK:
|
||||
default:
|
||||
return "<font color=\"black\">";
|
||||
}
|
||||
}
|
||||
|
||||
private String getTitle(InventoryItem inventoryItem) {
|
||||
return "Number of " + inventoryItem.getKey() + ": ";
|
||||
}
|
||||
|
||||
private String getRounded(String value) {
|
||||
return String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2));
|
||||
}
|
||||
|
||||
private String getKbRounded(String bytes) {
|
||||
return String.valueOf(MathUtils.roundDouble(Double.parseDouble(bytes) / 1000, 2));
|
||||
}
|
||||
|
||||
private void setupOperatorMap(BufferedReader seedNodeFile) {
|
||||
seedNodeFile.lines().forEach(line -> {
|
||||
if (!line.startsWith("#")) {
|
||||
String[] strings = line.split(" \\(@");
|
||||
String node = strings.length > 0 ? strings[0] : "n/a";
|
||||
String operator = strings.length > 1 ? strings[1].replace(")", "") : "n/a";
|
||||
operatorByNodeAddress.put(node, operator);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We use here a bit diff. model as with other historical data alerts/warnings as we do not store it in the data
|
||||
// object as we do with normal inventoryItems. So the historical error msg are not available in the json file.
|
||||
// If we need it we have to move that handling here to the InventoryMonitor and change the data model to support the
|
||||
// missing data for error messages.
|
||||
private String getErrorMsgLine(NodeAddress seedNode,
|
||||
RequestInfo requestInfo,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
String errorMessage = requestInfo.hasError() ? requestInfo.getErrorMessage() : "-";
|
||||
List<RequestInfo> requestInfoList = map.get(seedNode);
|
||||
List<String> errorsAtRequestNumber = new ArrayList<>();
|
||||
String historicalErrorsHtml = "";
|
||||
if (requestInfoList != null) {
|
||||
for (int i = 0; i < requestInfoList.size(); i++) {
|
||||
RequestInfo requestInfo1 = requestInfoList.get(i);
|
||||
|
||||
// We ignore old errors as at startup timeouts are expected and each node restarts once a day
|
||||
long duration = System.currentTimeMillis() - requestInfo1.getRequestStartTime();
|
||||
if (requestInfo1.getRequestStartTime() > 0 && duration > TimeUnit.HOURS.toMillis(24)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (requestInfo1.hasError()) {
|
||||
errorsAtRequestNumber.add((i + 1) + " (" + requestInfo1.getErrorMessage() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorsAtRequestNumber.isEmpty()) {
|
||||
String errorIcon;
|
||||
String type;
|
||||
String style;
|
||||
if (errorsAtRequestNumber.size() > 4) {
|
||||
errorIcon = ALERT_ICON;
|
||||
type = "alert";
|
||||
style = "alert";
|
||||
} else {
|
||||
errorIcon = WARNING_ICON;
|
||||
type = "warning";
|
||||
style = "warn";
|
||||
}
|
||||
String historicalAlerts = errorsAtRequestNumber.size() + " repeated " + type + "(s) at request(s): " +
|
||||
Joiner.on(", ").join(errorsAtRequestNumber);
|
||||
historicalErrorsHtml = errorsAtRequestNumber.isEmpty() ? "" :
|
||||
", <b><a id=\"" + style + "\" href=\"#\" title=\"" + historicalAlerts + "\">" + errorIcon +
|
||||
errorsAtRequestNumber.size() + "</a></b>";
|
||||
}
|
||||
}
|
||||
DeviationSeverity deviationSeverity = requestInfo.hasError() ?
|
||||
errorsAtRequestNumber.size() > 4 ? DeviationSeverity.ALERT : DeviationSeverity.WARN
|
||||
: DeviationSeverity.OK;
|
||||
|
||||
return "Error message: " +
|
||||
getColorTagByDeviationSeverity(deviationSeverity) +
|
||||
errorMessage +
|
||||
historicalErrorsHtml +
|
||||
CLOSE_TAG;
|
||||
}
|
||||
|
||||
private String getLastSuccessfulResponseLine(NodeAddress seedNode,
|
||||
Map<NodeAddress, List<RequestInfo>> map) {
|
||||
long newestResponseTime = 0;
|
||||
List<RequestInfo> requestInfoList = map.get(seedNode);
|
||||
if (requestInfoList != null) {
|
||||
for (int i = 0; i < requestInfoList.size(); i++) {
|
||||
RequestInfo requestInfo1 = requestInfoList.get(i);
|
||||
newestResponseTime = Math.max(newestResponseTime, requestInfo1.getResponseTime());
|
||||
}
|
||||
}
|
||||
String responseMessage = newestResponseTime > 0 ? new Date(newestResponseTime).toString() : "none";
|
||||
return "Last response received: " +
|
||||
responseMessage +
|
||||
CLOSE_TAG;
|
||||
}
|
||||
}
|
10
inventory/src/main/resources/inv_btc_mainnet.seednodes
Normal file
10
inventory/src/main/resources/inv_btc_mainnet.seednodes
Normal file
@ -0,0 +1,10 @@
|
||||
# nodeaddress.onion:port [(@owner,@backup)]
|
||||
devinv3rhon24gqf5v6ondoqgyrbzyqihzyouzv7ptltsewhfmox2zqd.onion:8000 (@devinbileck)
|
||||
devinsn2teu33efff62bnvwbxmfgbfjlgqsu3ad4b4fudx3a725eqnyd.onion:8000 (@devinbileck)
|
||||
devinsn3xuzxhj6pmammrxpydhwwmwp75qkksedo5dn2tlmu7jggo7id.onion:8000 (@devinbileck)
|
||||
sn3emzy56u3mxzsr4geysc52feoq5qt7ja56km6gygwnszkshunn2sid.onion:8000 (@emzy)
|
||||
sn4emzywye3dhjouv7jig677qepg7fnusjidw74fbwneieruhmi7fuyd.onion:8000 (@emzy)
|
||||
sn5emzyvxuildv34n6jewfp2zeota4aq63fsl5yyilnvksezr3htveqd.onion:8000 (@emzy)
|
||||
y6mvobc6tfp7l3rq2rae7hayvkmy35su33cun2mfdbzd4uw536pqtlyd.onion:8000 (@jester4042)
|
||||
xaebw6lpcckkyb2anyzyfynthebek2abqzyhchenfrdqlfktezgtrtqd.onion:8000 (@jester4042)
|
||||
33ol66i7crfrnypjlpd7kem3imo6zmjkvxdr6ipcdx3e2skbpcrfzuqd.onion:8000 (@jester4042)
|
15
inventory/src/main/resources/logback.xml
Normal file
15
inventory/src/main/resources/logback.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}: %msg %xEx%n)</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="TRACE">
|
||||
<appender-ref ref="CONSOLE_APPENDER"/>
|
||||
</root>
|
||||
|
||||
<!-- <logger name="org.bitcoinj" level="WARN"/>-->
|
||||
<logger name="org.berndpruenster.netlayer.tor.Tor" level="WARN"/>
|
||||
</configuration>
|
@ -19,9 +19,6 @@ package bisq.network.p2p.network;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface BridgeAddressProvider {
|
||||
@Nullable
|
||||
List<String> getBridgeAddresses();
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ include 'core'
|
||||
include 'cli'
|
||||
include 'daemon'
|
||||
include 'desktop'
|
||||
include 'inventory'
|
||||
include 'persistence'
|
||||
include 'seednode'
|
||||
include 'statsnode'
|
||||
|
Loading…
Reference in New Issue
Block a user