diff --git a/ndn/pib.db b/ndn/pid/pib.db similarity index 65% rename from ndn/pib.db rename to ndn/pid/pib.db index fb704a6..32d7588 100644 Binary files a/ndn/pib.db and b/ndn/pid/pib.db differ diff --git a/ndn/settings.properties b/ndn/settings.properties index 7d081fa..85e14ab 100644 --- a/ndn/settings.properties +++ b/ndn/settings.properties @@ -1,5 +1,12 @@ #\u4FEE\u6539\u914D\u7F6E\u6587\u4EF6 -#Mon Mar 16 11:20:10 CST 2020 -ServerIPAddress=121.15.171.88 +#Tue Apr 07 15:45:02 CST 2020 +KeyName=/testKey_v3 +loginUserName=466D1203678EFB16BE85C8A02E1486B6 +ndnBlockChainIPAddress=116.77.74.139 +ServerIPAddress=116.77.74.139 +ThreadNumberForFileTransfer=5 +ndnBlockChainPortAddress=9001 DataPackagePrefix=/ndn/edu/pkusz/OA +LoginStatus=true +loginPassWord=A1B9652D9ED940B8FC63453C50CB3337 ServerPortAddress=6363 diff --git a/ndn/tpm/10171a33bb85224dc8cd2620cc9daa14ce5becaf65de863a2568326ebf628d2b.privkey b/ndn/tpm/10171a33bb85224dc8cd2620cc9daa14ce5becaf65de863a2568326ebf628d2b.privkey new file mode 100644 index 0000000..caaac60 --- /dev/null +++ b/ndn/tpm/10171a33bb85224dc8cd2620cc9daa14ce5becaf65de863a2568326ebf628d2b.privkey @@ -0,0 +1,25 @@ +MIIEogIBAAKCAQEA1SfrgYkPWsFCq68QPY/LlaofFZHPsGf3v9xbcSzdOwRlFh1o +c4VOZ6NUqmX4cJtDzsuxcivXyj529VgywrhijreFWlFV8o+94pSGRf3ncQqXXRGM +JdN+Jyk65atPXYZaCb9Qcy0EPcvGy478ysN0vZN9ZLuYMcy4itVpjWCjrKQIhRpI +bPVQ2JO9VYB8ow1emIFMbPlBR2SXeA/Q9hPpl3loqItHzIlcT0QhFzH01QINEy1m +f2cjDaWvHYRobFPTAcv07a956EGXfvodne3BVc6Bcw7tOPJRgQGZPw/iI0vzcITc +XBCJTTnOKbR+5BLmNxdlwVfI1BXTE95nmE/60QIDAQABAoIBABwMlMEG+C5JICzX +bJutQG0BZfXAqkPcao2kwaOy86nAekzesdAByr94jrudj4PB6rpbs44ClvLWJXFD +mepluRJus+2epmC06ZfXU5QCRWJqsmBc3sRbgE5G7qkqUddMxqxhsIR3eAdpuU8w +EbPc5I/NyMJorS5gcihSzQD9powhDA392rFrh5yoZeoRAondJnv/a4TqcWpL86Zr +bArIR1s/Fmx5uNdi2zkXvXKbDEoWGngwGKs3TKVztsIq8z3LaIoTvZshVtRtAi7X +4tyPaVMuVF2nXU2i1Fi3pa2DowblxeA5VgYT8OgcZom3fXQpnoTDChBYL3x0ftE8 +caHkF8ECgYEA/aKcY+XNlbu6sCuya1Qz6O9ot5078Z23UCWhGKAeNYVXjW2Ez7d4 +8rDzvF/XxM5jSM920FbdQWsZl/b9yzh31dBYqgoPbCKxyF/NE6Cm66OfaqIiTLBm +vbr1Q9me1TjFrWvk1yk89nPj7Y9ewFWLO0hKlMb4BGUo9dhF40+7TnsCgYEA1ySw +7gxutLH7pYzdXe1+QhgPVYOR5whFUyAdbg8QPMC5USaZEmjInfvKvMAfzRVF0Kn9 +VEdpWeUHsNxh4c+vJ8ayO7liugI96738iwt1NJwb3fDfemN+sdPw1XsDUfJWZiML +pjmnq6nrhyFHwgKvAl9RXP0oM+jewYPt7FkIwCMCgYBobFiC8Ivxx7aW7YaplaNB +lb/BSOTzFwHv524p21JUqq9fNOXnNxx+nsfamIMXLfnGclPydrDlTBjfbfsTfg4o +Y3z9lOLAnJAhdP/TwuK2RUlO962zcTT7jEuKQcCY/KS2P6OZygqlVRVUKyDRguat +45eBJWHbPWLdxMsRSTROnQKBgEzphAsGDMmyWzk626SJk7qDKXAzwgQq88Wc1IiV +AAQIDfgR6WUoapf3/Olvca76bOQE8Vig0uvdMdurXZ7BhWed4/fv9Xhz9rkBSXhX +10XAjUHRq8LwMMnX7+ARwwUXsoV+/9okAGohK986KZIVLYWWl9q7chTkqkXaKUN2 +LOerAoGAMaeH8w6iQsdBJjmP1Wfk2ZT/Wk47a1RgTqCCahIz5EDGL2/YlTRlIACy +KaWOp9cjHb+sWz4/Mor5unOvTIq3Csa82qGu8sle2PCf8lDfSw+OpaB6jFO6oA56 +OGJ2dzdky9OAAO0ldbO8aX23nqoqqcgCIWedboB/lVYAZlfkSTU= diff --git a/ndn/tpm/36c4c0473f64e76f046871f46a6f923b364b8e17f75ca3b38776a2af27e50da6.privkey b/ndn/tpm/36c4c0473f64e76f046871f46a6f923b364b8e17f75ca3b38776a2af27e50da6.privkey new file mode 100644 index 0000000..3be181a --- /dev/null +++ b/ndn/tpm/36c4c0473f64e76f046871f46a6f923b364b8e17f75ca3b38776a2af27e50da6.privkey @@ -0,0 +1,25 @@ +MIIEowIBAAKCAQEAhZm4MZ8r2h/uBzVLT1DLZCj5J9eF/htay0jhhDU9s4swPsvd +zB1eBBG7IQCyD6BupM0M1jGuRJ64p5Dk17jy/VAuCH5MkCIxXo3C1wAWNKv708gO +CU3LduFg3vjpMP9ceisDfDcCr8ZJ1Mma5JV+7QMsHdTiU41CGUl7bNSn1e0Zq3rY +QGe/HxsSTXGcigl638xGQ9sKdNFrWpQHeHQEoPHylwh4bHKTuN8vGYKQbCpyI3IX +s69Qm3INzgNpCwda1pZLdRKaBDTO91kOZJ9Ln43k2Ic68icaoL8ZDHUD3C6M5b2l +MxSPg2989VV768YNPpiKJskRfY7LlKPy4f5iNQIDAQABAoIBAHDsZ1X59fTefDC3 +iTo3TlMQlthoQSdxM6MTrRo0bjyt70+EvapjQC4sVoEkt1yh/CNr9eeuAmCZz/ZC +cEsuVqRp+x7OsiQ54oTLSd60ghBvNeHh/Is8qDeJdHnC5ke18BKK/N0nGiw8a/dh +mHyRJ8FppwZoBA0fHrmE9MAeVuZnxNfns5VWVha4Z1WopSyGT5Ux+G6vMxFlLgen +b9ANMw9v2kHv5+BNvZ81ro2A8vJhL69ig3mJFefkxHoIWhdwl+CtUC3dR2FRb/9w +fSjXi/D6jkHMeOrZjfBcpDikcZ5oVfmOL4HO6PMWnxx6XgG9fQS2HFcF9C5SqnAj +43KGmEECgYEA+phd35ylwRuzBFH0BJNxk7LnYVWSm2FdpGVc06khnOIvG6i+RXuW +PmqFqGxmm3sKpXzMU0gc9Z8o0hg8nIkFCwr2+ZZIdfP70JsEledvxc/J8/CNL5zJ +Fj0NbkuzSjofZ2FBvmyNorLU+OfNyu5MzdUi9iTrJ1yur90+BBNOdF0CgYEAiHth +KuXMa71oajLDWuGDQ2AXrSWhiVBTH+9p39J6cLUzIfmHRtu5Vwxuxsw91HJw0nsH +izAliqWAZvtFGirfjWlrpe3GWtMdOyy8c0UWXCbI6HKBcJxebe8qlsEyg8e0o3Yj +Z73MwsAifwKprzcKZPSiIhogx/5BxjTxU5u4x7kCgYAq5ANFL5mLKMOGHMTIN7g7 +0GYb2bqjD5IofhTaQVt4b5oigMo4OEPp4O+JeSxCtleHJYoPQwt52sjw1KcjH6yW +TEUjSN6UGbNi6/Vn9tnBoKPvNZ/ko1Ajl0WCOECylqojVpkbD5daXoNnKr2lWw4Y +OL+oI3+AGDPp89MWfXtzHQKBgE/LuyLmml8/rYWxylAfW6yPySf9wXVUFlWsl706 +BUZSWuP5TWNbYgCID1iB34CPrHETZ3S0oK5wVyNes6c5+9xlD4BDBd7iYcvQOxo2 +AX29W2e0UwOxGPCzjbX4nP05TN7pWof0C3yt8z1JJEaCKryd3xGLLzFe8bveBl64 +xA9ZAoGBAImSFu8nFLtQNCTJza4js2t3P4q9Tg5VIbzeEjdtos/dLqGhGOq1wPMt +WPBFh6r29gMuqDeUgZnZo/XioENspBHV99fakO2nkrwcKinAvmIgriXU82pDNp8j +UemLtcHGaAFfinfmGw4Z5H5aApVzDxEAL1TLKyHcJFXhPu5I7RV4 diff --git a/ndn/tpm/48d2f036284dafd1e0955c834256bf0deffb13a12b798128fd6980e9c20175da.privkey b/ndn/tpm/48d2f036284dafd1e0955c834256bf0deffb13a12b798128fd6980e9c20175da.privkey new file mode 100644 index 0000000..aa41d92 --- /dev/null +++ b/ndn/tpm/48d2f036284dafd1e0955c834256bf0deffb13a12b798128fd6980e9c20175da.privkey @@ -0,0 +1,25 @@ +MIIEogIBAAKCAQEAnfq8CLJMv7IYQNOUehxTbi3Wtgv5jxbYo7jtw+HLH85jujkX +BL89G4zpGv0+q7ZKkrxYauSUkvuxyQ7Aeg0xao7TIxQgZPMyY4VPJpLSE+xJaach +xqcTJt2snPy6pw/gz8gVj74G70+j1xK2ZkdsZw/iUzPa+jJlK3rI7+l6LsUUVBHa +jEB136njugNC0s8+nBi06h4u6BhBFYYAx4AuZeBar3EcRnHu8u3L5LCzbS9v87Go +05JmlhtGKzDLgFRTGVc49Kvu4YvVTZ/YnNtQeOjP3Uc3WRAHd0ApDfZMZLvRsbxz +4h/h5/58tSW4Z4m3fOn00nD0pitSBuMjsq8wFwIDAQABAoIBAD21s72x6Ej5SIAK +JfWNGwnu3fA+vT0nr3hExJu/l5jVBh+4LUWtbjFU2bmxMsnga0DmUaNvppnDt67S +FF2YybTWFaOeOQk19njpmgF3WJhvtD2RC6CNou2LqeGo10Bq82Y2wjVkBVF1yoo4 +xQcu3yljCwV1PBR/mwVg8RzGFvQtaO/CHB6x0RxsOk9mFyOn2US8t4vj6oGVAKj3 +7agk3UxGWAiRWPl/x44U7xnXE+6KavbOSguMWzI8LGAwYivNlOg8VhW1NYpuqAZU +LxnwMTC0xHrxQqYtCVRQNl91i+Krkh+0MCH1TkAo+IxJJEmtsGJCB4GrHa+0pcWP +xgr4IAECgYEA6RbOvg6q86H6sVUjWL00ypm9GwBOlDFZNLMWQ8p5NMrpkiHbp43r +IlvSP8IpptImhOhJJs4i84bFt5pkQdqO1FLyLhM3FEaK5LKqlIKNDKfVdW3n0K2d +qoRz38J9UYgtp7ctXttV2oqVUr+F4sylnqGhbRKM+v7zRIWSKJkQ0nsCgYEArYHz +oewqJpQcaNZ4fS/ae+IjUYHbOGs7L5rUocmkXFBeGa8XCl9RqyvxVeg5yqEhn4Mn +3AC7ONWAIXtkMa+IsCgka1cagF57ULcn7oWDRgw3TShvbNXZkWo4+rz0EQT19L75 +zcPa06FWrURT1CMH/xjb899iYbR5wgsFWEXMBBUCgYAdbzfkYE3OPmI+CpZQGnSU +MR3kTwGdTS4KraLeJK9xrz4Xqhbm7dEHobjHPGmuG1Op7Ptv3xAi2J4XNXP7rPHk +diUHFH4cHVxkzPsljebp9jfKgHqJq6MBaYCIfTL+HMhHKaadF+2bj2yT6oOpxFYV +1itgbrtG5vMpcASpA8tQCQKBgE5RUDWQsl4DkOdJl816Ija1Fpgd82P+ExMj4kK9 +D/GTXUZeoBnQeL648RCD6EIshU7JFt7ZfajjxhhW6Bz9TMem9vl0scOr4iHG6sFh +hqXBsdykGdeYl8Jpnhqf29Mq2BKHeZ6Ff2rzcnp3Uxd4UI23HOFxvai4nBUYgGsd +5j8ZAoGAHRYhOF+zDbK3nGQsuZjsDb3LrngdNjiEPA+hYeh3k2BKwirSKoVUQa62 +k0Tb/PRBiPiyQk7uYGwyR9WA8Yr2BA3y+/9m5rNenwJAL/o39DjogV9K/pxSmPH+ +FOz29FNtO0WO5IpNaVroKCn+SHSEahFdhdyR6I9J+chFHnsDQDo= diff --git a/ndn/tpm/92bee710fb68d84d2b370a2ec6af94f8155014ed120a519c84151b920b607cbc.privkey b/ndn/tpm/92bee710fb68d84d2b370a2ec6af94f8155014ed120a519c84151b920b607cbc.privkey new file mode 100644 index 0000000..f9ed169 --- /dev/null +++ b/ndn/tpm/92bee710fb68d84d2b370a2ec6af94f8155014ed120a519c84151b920b607cbc.privkey @@ -0,0 +1,25 @@ +MIIEpQIBAAKCAQEAs9dajy8yS3WCi15hnHumAP6SELbbusHDqx957OwA4V5YSiXJ +ocgT4k+SPg9y+FgM90XNtiYZbqqi0tXtrIXsNN3VZx4UDQAAoR8Xe2RCuINA9o38 +b3roK+3eJnlv0Z6msY7jBawib8ngdyNJMobVPNM2qNT9Z3CE7aNjDvKf/Y4/DeK2 +X9ljvK2+XPjMwZ+otlIcS+q027cGlJO4RkHLukGuJbpltkhcGLL+wVvs7lx/Per0 +Z/6pTum6LPVar2H+qse4XWpVgIVeMEg1uGmdplqqRV0YR1yzhfuQ0tqOYjHvaPwX +e68zOIyDcqkapvsogztm06E0682uzId9vup66QIDAQABAoIBAFgmN4o1TQa1m34q +jdfAt7aHERtGNd+NeBYZgI7Dgw70SnxVl0ZIJo7oB7uJoQXfSsOtIE6m0BJxawvC +thO5NPUYwrAfix5wIN7YuY7OrvF3zFDNea0+5iwaFKhxH4D0raocamRuYha/MdnT +nt44Pq7orEMG2wpnmZBNZJGAFTGXQiuYCr9UVGnlChn3nNORJrYA6yogjSwJVhVo +4S9g0JNI4pq9bgZk7xQ3J51LbJRT7KEnGHNY9E8+3Ya0uQpD9qGHTeueBnEjjh04 +MU7bPfRmfr6E5stQUgt9fK4MmFLGm/DJhI5RGMDIck+8kcWDnP+zzghicscUavmn +XwY9Aq0CgYEA9oAtyUqTCFZGbcHIUu/I4j+vcAoOtIkW5UxNuQJn5jmYuQYJu47o +D9n+AZQVfKrSRgSQw5EqYLx/dkzv1gxmJaM1urfVQG7b/XFtk0CFPhZAFrAT6m5M +RQuqhZ49+F0CYYA4kCeOjDQ3/QUO7ofHOKhKUBBkZn/PQFyJ3EdhLpMCgYEAusWN +69pVMKiT3Rkfo2Lv+uqj+HXCFyiE8ASIulX/VkKnlnFWA9Wiesr3S6PBZBSk58Ky +1lPZdVWTV1DXh2bxSggCVNccxriIQVUCqyWGN3rWhFZvLK7DCcU5cfNGzwnCvisn +JqVENg9fxvBPDI33T1NkcI1QHWTiNiAWTGm5ohMCgYEAocCYyvbJpvXeP1Wi23GH +k5eQyud+oM84m/zHH7lJbpSq9/bTWiU7eHNmr6h5tRXu541FZV+TvGjVB08TLpVy +Tg5cSospP5+/cf8FlVQIWyaEpZ6jYvk/ySsPmaCuL5Tw5AQcmdOrQatedgTkuHeW +rkIYiZNIHs6NtEFFIawhREsCgYEAqk4fhhN1IMRm5/HTvpkluEeispk2HQXOikmo +HzjxdkebJvw7cY2o9Y0DiA5O9qI4aDhJ+FNG883PZ4wIq6e7l0TMU24/CBkV7XTF +1SeHRimVV+C0ySqmH8+d/QDW7Uy6LcuNjJigJSdJr05K1mjRPJ0O9e51QghOmQoT +KyQwp88CgYEAtA/he1Lf81965giwWg6k1Ul2+o4d96eq+aGDesW9awmKQIMVnXPw +9++6uYLNTOazRELEt0+jeuf8T/nqtmjahURhG+rbxj0fvafd0faV07ygIHbpK575 +pEMIV3UUZjKUVPqnhSOc7B71k1163prIjIYvjSe2pCq9KxEAORd9Je4= diff --git a/ndn/tpm/a6ebe12b9cfa5af54fdf095ca4c38a883bc0db1f3d5e5fc4956d2931aa8a4c4d.privkey b/ndn/tpm/a6ebe12b9cfa5af54fdf095ca4c38a883bc0db1f3d5e5fc4956d2931aa8a4c4d.privkey new file mode 100644 index 0000000..15072f3 --- /dev/null +++ b/ndn/tpm/a6ebe12b9cfa5af54fdf095ca4c38a883bc0db1f3d5e5fc4956d2931aa8a4c4d.privkey @@ -0,0 +1,25 @@ +MIIEogIBAAKCAQEA1XSNRuSN3o/wayYGHV4FnBL8iofwlRjUJsJEQuGTi5eIVT7j +qL3IalgGJJ5lAFpaLod83NTXG+4lqFnUfQPB7qd0MQyi9xWt3IdzL83t6V7egLx2 +DpSd8Y5ZgKasD05LA6/kcmAMv04Vvj/ndwvLmHUTr3j8xNMJMFIWdpB19Zuma7Zr +6UwXh+ylS3bvJPDOcDsQgu2f/Boa7cMhALs76AdM7szrnbnHZbv+dtuxOD609Wjy +albxSLqjpqV3w2Af0/Z5PIa8turNREGqxqI7R7vm/VIUrjU6bpzn2E2/lc3l0sPr +XVydRPc1HJi0k+1ivRsWpevpGE5h5Y7rdtckuQIDAQABAoIBAAaHw0647VIyyyMs +DaHWX4uP1SQT1ptpIAxzgw0cw5vQrf4Vp3dhHwGJ4d467lIdcYbc5EgJRu920LYe +0W5lsAgyHU7m2RGAG0qU5kQ/I5kxKtN7cI0vpMlgFoLmFnt9ZLQfLHkHUTyFEgs4 +/0bYGIl4g3qp0+ndnvlYeZF1B/bUlus1VKVjW7tBlXDmst6kcfgi767AAHJjaaaz +Ho9stJR+UT0MIHCz5f+OUrQOfynO1F6K6zVlQBaIgSfmSIhSkzQ10qjhTXka7miF +UEJs580sPg13+EMjSDIWVRe81s9hc9uoeozY+sdnk6AAjhyktU3BijxPdAGZuJyo +1hFEXJECgYEA7ypNV7kMEU8bVNjsFNdpxVoWc6/RgXAYXmJ5kMKC1fXanUxPYGxN +0UWeEhLw3SuL//iAMe9magGeykGsZFr1qcz4eveL0jl5mu8jhv/nZcENemrAHd2P +zBWBe10pvBfT2Wn1dv7Wit3mVz5QpEvdDZNOFTgAYLN5kwf6XGDKdi0CgYEA5Hr2 +cKpP+Bk9f6CeCLwvwFyih2oRn9Z2boRLUVrJcWlxB49rWc1nh+EAZWIarjeZh/8r +sDmCJoX60c9GZSyFFEBRQfprW5Ao3RyXNY6oKenBjCWHJUbv041C2qkdTeblls0e +3etqaa/tHL2zLFiOvlAf/8nj1N4psE0duRR2bD0CgYAMf7h1Ci2wReMWxxNnb26O +qsublierzRDo9dqGjzPJPMUFDXTkhCR4+FtvdF/0Hw98/B6u/WTry1PiHBaHVB2c +lyKxQnijLu/FAhRoPL16GuG6cRPDO84FC2at7Mt+kfw3U4tJgb3ymfAsxQvv2ise +R4GAKGIUq6yB25vg8goCrQKBgCdbSwIjRD0vU9mdODu29t7C1jhPPBP1ZFcrMLIl +2ldP22l6+fnxGOleB6xvFrt11luHx+XGMjYilA76Dl01KwNPBPBBi6atEWztFNrj +5PG7U1ypxjrUmlEtnxt9UA/wOxIb6To+6AimhkiSIL/9zTDZKnnsM/OiBTpaPkl4 +TeHdAoGAO1Tfl5KcEP/zMSg2hDtmrb90z2fVA4ewoFOo5Y64F99GIepS83MYiwRK +tmmqHqG+DUYOs8sLexfKtZyRyguWxFwW69/aTNomZoeCzP9F/nHg+ns8jZsGwSZY +TpER91D1iiTLhl1Wnz7EPGKQVn1a/OdWkxsiFlFpMMxFAQye6A4= diff --git a/ndn/tpm/b858d7bc59d4a7ec29cbf6383f8ed86723ca1893438cea0c09fa7cb856557e4c.privkey b/ndn/tpm/b858d7bc59d4a7ec29cbf6383f8ed86723ca1893438cea0c09fa7cb856557e4c.privkey new file mode 100644 index 0000000..4b79f13 --- /dev/null +++ b/ndn/tpm/b858d7bc59d4a7ec29cbf6383f8ed86723ca1893438cea0c09fa7cb856557e4c.privkey @@ -0,0 +1,25 @@ +MIIEpAIBAAKCAQEAg3GRtC0iPdgugSnyNkp29LDaYNzVjXY46pE+OFSAbFm3X++K +LIinlxqB1cc5nlk82ckzodUzUvGpTbSNib7PKq1625A+k0Ue3WD7aKB+yDoIr66b +ZMqCOx8bpMEOFoHIb/Ua/zDFezZUheX6nVZnTDl3vFf4erx8jZYeC47miJKkjH1l +eiX+U5M9IV4vkU/iIoTyLFOBuqDy95OD7dkFIdOqoSY0MvjuPMT9+bTfBgvVXaYW +kEoLpcdxV6Yq2FhMiCINaYm+dVmg14PYVXLMAsUFzotSZ9jB3JQOcmKZYhyLEke8 +6P90KOrDaT7qwzY+h2vovpIf77EXfNve2ezP9QIDAQABAoIBAE9CyYireq1uUcSj +ZaIlTwwIJPcp00CFXJbd1HYlRnePtgsMp/ZoxR5R5p7hjrYUu6PcNt1McbF/dgcc +bAj23XevupjxpzopAQ6fb5rMxQa6MAi4Mo4Zq2Q5QvMbUwJxaktQsuHVKBA/V8KS +Rohf1NRbBv+00Go6hKTgM+fmWM9bM7t2lpuv2dD8Tt5TwqfWINAjfrHUIVBf2HUG +FOpcaOufmdYiVpTkdrx+lfc8uZBBSM7GYDS6WdtotamWsaL9XhBlVzUFgvd6LKOu +A8iju6YRnDBrBy/MrdShAZGv+AruNXW/psxdUNfSPY9jAzTtS3f2/v6liXCY7xNO +anSnlbUCgYEA4zYDutw2WSAtJDcUtpxIxahwX52vRbnSHToYtvJfkxcFeuJ4jj3M +5WBivV7CSvrKGVlL88O9X7QrmouUhNPoQ4cqHOPWnQecKxAiksfdMNl+bn8PV2bP +W5J35rHFtYfzrO/mHz6Et6De9ASGNAUlvFTZORkqu+EKs4HGzgLC9gcCgYEAlBks +P6iaLDUqnkPaUYC87BKCfztFq0vwBAuFmzJiqti/URaaB1ABOX9ICIii9bLKBBpH +UVk4SxMqxFOkfO4aERBWg08eaT4iEvJOBDF9w/x5ElapEA7uw81rAmpwvQszwSiw +p9e1FocoepSsd34eL/V/EkFFhhqrpxjCxan+KyMCgYEA0Xz22W26alhhZpemcGwO +KLgRzAbuGIKouKvdJ6i2+D5sng17C+LtLLu+rk1VJJ6wgci0X6+kxj2vSlHRgNqE +tuZDrNlhAe2HTqkUx3KhfS27BZP/CB3Rp+OWy0wzNxl/UX7rFPmmkkwv5JrbRdFN +JqSwl5WdshZesH1CWKVxLjcCgYEAkDRqt5mudXlXhD/BpzbZvmzPkJ/gWMlabjXh +5JqNJJpkv8poNNKcPqZHN7gEJYXv20rTQszDWabSL9TaB6O40gC8nKM/k26isxwp +B0BBm8KNCWREvpQrvZCZsAKAwDLWNDEwwl3xwHve2G1H+hpdvoknMFlKHyh9F/mu +PdYm3U0CgYBHKh+FWZ2K/MPY/+69+7BgpdvTYoyV/nO4lTDVoLpMsrk6/PwAwwHT +YyXx36E1xGjFvBN46H3UTXd06mI4a8aX3obRDVvzrHAEd1uWAr4ufYvpib2BFMuu +iIfBlsG7qPSdL5af0w8jKiLW6QxegqYVPrtbCCY4JpbcgEXjtL6z0g== diff --git a/ndn/tpm/f3a1720b4dec2a40f209d1c4f9a00e81cb0a26d075e30ae06392d11c7d49833c.privkey b/ndn/tpm/f3a1720b4dec2a40f209d1c4f9a00e81cb0a26d075e30ae06392d11c7d49833c.privkey new file mode 100644 index 0000000..489a02f --- /dev/null +++ b/ndn/tpm/f3a1720b4dec2a40f209d1c4f9a00e81cb0a26d075e30ae06392d11c7d49833c.privkey @@ -0,0 +1,25 @@ +MIIEowIBAAKCAQEAiA3stSNU6Xkr26SYt/AANIdq1zXCsaErIDM5LIIQ+CG+NK37 +bikKdrxouYhJ00lPTP7GyIwRpbORf4Xy9kNad+Xfs0KhWrebyn8ZWsPFVrDX7aVa +Pb68GY2EuQBwGp2dkZjFGUVQKvK6dhwMl3pvtfucjIjg2qAktNw1SFcAy5kjA6JN +pMqh9MbrV9hF7otMvnfXge2VpIglpS8zmT3fbPjXc+V9PhaY9MIBVnMLA+Q1BvXl +X/127NjgSrMLqW+eBYltZzNt8PD142oL4CMR71nR5sJxXrYHmABQtnRYr+ek0is+ +6EpAdj92hQ7CXAeeoXacEScODV6NQG7dRMtn4wIDAQABAoIBAEOaR6epqqNn5fb5 +Tjj3M+Ll9pyAxgDlCDyztxD6f9wLSCt815XhJqXg8Fhf8+7cWl7zqWo0zv/6va0T +ranXxbgVrJWx4eLloK95f+utovx0WpZmtvQ/Nc+sleom4Y0YDBcwRZ9M5Yyxlxzg +yxDpcWCHaT4bNT7sm9CSKpeLQ4XmEntrOASb3v1G/6bzl5d1M2UXiy85uP2RqSez +uvcugYEGIJTAF2FXH4iISiA0uEvnCu0k4H5CVoe4eu44Ykc86KwHASqwb1Yl/5LF +DOUA4fiy5Grq99gnoOWrPqOfQAZVy16i04+q9qp5BAD9yBsgaLgsgzzhsFm1UAzx +pETc9SECgYEA1Q+ftMsFzLdFa9tzlFzOG4OQu/hFYf2SVweXkpwZk3TMyu9zBTbX +zl9es2ygWYJXwCRl4a6iFOj7j3ucq16Od94MsHl1AtO1XdP2Wx3ppZd5F8a7lyPk +krQaGgealz6y/IqWev5FuzqQuiTOClf+L2OAQkoWgUdpBTxH8aJiIK0CgYEAo3lT +qy9VbHxBh62Mi//C9LXdMzHSZnlf2i1K4VXew8gQHMidxMay6ef/UT4jYRgly5xo +mZoAf5bhmlbgKONVwCsTGi77L+m20QCq4WOfGG770xQtMdAohYvZmfdZhcbxqhmf +IAfXAAR/bAQqYjl9mK7Xyj+GrpUMQLX++YuSbM8CgYBYcYzlWuXEbku2EznuW3v/ +deTt8oiyvbUyxWcJKB2B1ZlxoGaJwpNhCrvgFXaW0YGltDZKsdh8f551mGWXyb+w +SI/R7glBrCp8kZGRj2A/KhrNYOTcP70RnQu8xG1K3W8lYE5JLiY6K3yKmN6i8pYE +i/RhECo5bjBNSRHAX50GXQKBgQCiZr7zOoPf0ZV8R7JvxreUSjQlTuKaAQxzgDl6 +oMc8sr0nCzqJKWjGrT7dJCEbrVSm8YyMxAyotGkN3i61EBu5XFGO2ouabtG60rHw +VfrQ2Dj+2nWHnicTfPrBVZSvLRQaC3gk5wT1tIIt+fltOXYHv/MKro+LUvEoPGXA +3aKqywKBgGjnOX39Un3MB/15i9qV1Mvh6QJgv5ldlRnYtPKpPU7HCGCieLcS9SgG +6O0bZ1bbbIn5boYg21wq1O0HrSFgDi5DW0JdsBysKDqUAyp7346GCez7z98wYHR0 +dInzfUjMgdeQ7JlC5cZi/+ETotKjvZWu1QDaIj2S3UAd9R4MHPP5 diff --git a/ndn/tpm/ff6fc9ef93750b6c82250c41f66ce4fbc1f983db5c1d983357fc7b7979af60bf.privkey b/ndn/tpm/ff6fc9ef93750b6c82250c41f66ce4fbc1f983db5c1d983357fc7b7979af60bf.privkey new file mode 100644 index 0000000..951596c --- /dev/null +++ b/ndn/tpm/ff6fc9ef93750b6c82250c41f66ce4fbc1f983db5c1d983357fc7b7979af60bf.privkey @@ -0,0 +1,25 @@ +MIIEpAIBAAKCAQEAlP1sWRkjTq25xwcrISI1YHR/CjdTacF1MfBZdDNPQ1krFybr +qtzbUeqjUzwHVMhH6TP6x3H6+k9RCAkcuGbafhsKvKdteN9Yi4doadzQE5HUYsQE +fbGSuC2afN4txIqt40QJKhDnqyi9abr3pRn+sGin14AWBUiMi9n/xd9RcOly6AkG +D/Rr3eEmaBKc/GbvKEpurcCuQURsNu0x0LiBm/sGeBKaPXOU3zqfWiDXS9fjenyi +iMLDZZBD45FQxIa2aFWtNbpPFLCjWJCwlIwtC4kKutZR8k0ZN7rXNavpajEXg33H +0hhgQwWNgMPK04lIyAU6MCiUN6cdL59liuQNbQIDAQABAoIBAAUnWwcd+n2vPrzm +v5Qu1b/XZ8mXrlf7LC2lDcMaP0SqIfZ0DzTi3OdRgYLQkcRaBTrI5ITfqXndIoVv +o0GxtR8lmlJ6TCwhNbPl5DO9QqlaowkjlLAwY03hrfVhzh19WpSA9vwwh4MBLsQo +hoZ8hrXdeOjYcmqOXuY7jUBwACYyr5ZSzp8Q+QXuP1QLiyw6TpotrbB6wkx5JS0U +X2CJWxfllMAYr/mDXSXW4uysLqvYCR/VAu/B2s0kue9WjcsGyRuzP42A4gKGKa/E +/RC6RVqR/WSEPMRlt30+A9zNt/1lkTWF5Nr/8CILtAbdhq2uGxS1qs+Smt1uTdBb +BYYsTzUCgYEAxwunZuQduW6mAajuLC03qT6SrJntBnHnr4hJV203n4kaiBvOO54W +pXt2zFXZ7h9C1ziwIGrtQdVUTfDw+pkZCM7EAt82IYwUp4MB/7Dnbe3nW3nRCEd9 +5Q89r0cSLwp8I49jyRjYIb21eZ4NCQRJSryc0L6McqaCbUmm1LJ9Qz8CgYEAv58h +tnKwLfwhXhRNS3UERJ2wGBuuTXGymWyhUTISmPumt0+R8NZRrlJ7zhkLBaDQkA4Q +Zu2GnyZdQ77aBrfXXD1E9gaEO5pukHNZhavSIg48K2nw7eaa0c40iJ2uTbo1nli0 +qK/mywAxd4imjCWpYMLwUHXapFRe7bTeCsgowFMCgYEAlDQkL+M4EqLFbkT3GeON +JzIVCfkOWBcluDgUy8jheqMeIyv48cDzAcIdIWXm/3s9THzD/08+Wx9ZRzNYam7m +Cf3SSoUii/X+Rv+v1E9G8j4KXr0kHDMHFS+08TZM3sPCzMNuPASIoQ7c+bHp6MXN +QJ2RcYf/kTpTsMX/Ny2zQQcCgYEAhvLAwUafwKLRtPnDPaLZMKGExFWqOSwbRWV1 +bkM/SbHgRTSqaNvmhkfcnNaSJpKMjwb4kiQxLJ/OCsm7rgOGjZUwnbsVIQyvVNeH +clYBFK7FvSVM4Z4H5j28TYIOoPrEjBGYmTvX45rtO2tnL0fOszBWIbP+GMC6YdmA +jkNMP7UCgYA2fubLdBrpoS1ITDzqCzpffQNoGeRq0DqnpDMIYuSqYGvWING0UkY0 +w9PHGiVL3p3PisVGOyfv0Zne2bpF6VOOkbGRdd9P82wr85CgsOwt4WQIFRvIEmlu +lx4p38As1CpEDW1wIQ8KOJu6BQoHTI/EuTQDApOEmnaP4I9eQX4Z8A== diff --git a/resources/images/headPhotos/0403vv2.png b/resources/images/headPhotos/0403vv2.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/0403vv2.png differ diff --git a/resources/images/headPhotos/qjm123.png b/resources/images/headPhotos/qjm123.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/qjm123.png differ diff --git a/resources/images/headPhotos/qjm210.png b/resources/images/headPhotos/qjm210.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/qjm210.png differ diff --git a/resources/images/headPhotos/testKey_v1.png b/resources/images/headPhotos/testKey_v1.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/testKey_v1.png differ diff --git a/resources/images/headPhotos/testKey_v2.png b/resources/images/headPhotos/testKey_v2.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/testKey_v2.png differ diff --git a/resources/images/headPhotos/testKey_v3.png b/resources/images/headPhotos/testKey_v3.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/testKey_v3.png differ diff --git a/resources/images/headPhotos/wefree_aac.png b/resources/images/headPhotos/wefree_aac.png new file mode 100644 index 0000000..8b8296b Binary files /dev/null and b/resources/images/headPhotos/wefree_aac.png differ diff --git a/src/main/java/cn/minoa/MainApp.java b/src/main/java/cn/minoa/MainApp.java index 3ddf76d..394ab1c 100644 --- a/src/main/java/cn/minoa/MainApp.java +++ b/src/main/java/cn/minoa/MainApp.java @@ -2,14 +2,16 @@ package cn.minoa; import java.io.*; import java.util.*; +import java.util.concurrent.atomic.AtomicLong; -import cn.minoa.dataRequestInterface.MinoaDataAPI; -import cn.minoa.dataRequestInterface.OrderInfo; -import cn.minoa.dataRequestInterface.ResponseData; +import cn.minoa.dataRequestInterface.*; import cn.minoa.model.*; +import cn.minoa.util.FileUtil; +import cn.minoa.util.LoggerUtil; import cn.minoa.util.StringByteLengthUtil; import cn.minoa.view.NavigationBarController; import cn.minoa.view.home.*; +import cn.minoa.view.login.KeepLoginStatus; import cn.minoa.view.login.LoginOverviewController; import cn.minoa.view.login.RegisterOverviewController; import cn.minoa.view.login.SettingOverviewController; @@ -29,6 +31,7 @@ import javafx.fxml.FXMLLoader; import javafx.geometry.Pos; import javafx.scene.Group; import javafx.scene.Scene; +import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; @@ -36,7 +39,9 @@ import javafx.scene.image.Image; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.scene.text.Text; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.StageStyle; @@ -86,19 +91,25 @@ public class MainApp extends Application { // 判断聊天窗口是否已经被完整加载的锁(保证得到新消息时 在控制器已经被加载出来后才更新气泡) private boolean chatBoxIniFinished; // 标志ChatBox是否初始化完成 - // 服务器数据接口 - public MinoaDataAPI minoaDataAPI; - // 唯一标识数据请求 - private Long dataReqId; + // 服务器数据接口 + public volatile static MinoaDataAPI minoaDataAPI; + // 唯一标识数据请求 + private static AtomicLong dataReqId = new AtomicLong(0); - // 服务器数据接口参数信息 - public String minoaServerIpString; - public Integer minoaServerPortInteger; - public String globalPrefixString; + // 服务器数据接口参数信息 + public String minoaServerIpString; + public Integer minoaServerPortInteger; + public static String NDNBlockChainIPAddress; + public static Integer NDNBlockChainPortAddress; + public String globalPrefixString; + public Integer threadNumberForFileTransfer; //文件传输使用的线程数目 // public String pidDbPathString; + // 密钥导出文件的默认文件名称: username_KeyFileNameString + public static String KeyFileNameString="SecretKeyMIN"; + // 保存登录者信息 - public Loginer loginer; + public static Loginer loginer; // 保存联系人列表数据 public ObservableList contactListData = FXCollections.observableArrayList(); // 保存与所有联系人的消息记录 @@ -110,14 +121,14 @@ public class MainApp extends Application { // 保存通知列表 public ObservableList noticeList = FXCollections.observableArrayList(); - // 文件下载默认保存到windows本地的路径 - public final String fileLocalPath; - // 文件分片包含的最大字节数 - public final Integer sliceSize; - // 文件上传默认上传到服务器的路径[用户根目录] - public final String fileServerBinPath; - // 邮件中的附件文件上传到服务器的路径[/share] - public final String sharedFileServerPath; + // 文件下载默认保存到windows本地的路径 + public final String fileLocalPath; + // 文件分片包含的最大字节数 + public static final Integer sliceSize = 7000; + // 文件上传默认上传到服务器的路径[用户根目录] + public static final String fileServerBinPath = "/"; + // 邮件中的附件文件上传到服务器的路径[/share/] + public final String sharedFileServerPath; // 用户头像的默认保存位置 public final String userHeadPhotoBinPath; @@ -125,17 +136,19 @@ public class MainApp extends Application { // 进度条更新任务[传入子线程] Task copyWorker; // 标记是否是手动取消了上传或下载操作【false表示未取消,true表示取消】 - public boolean isCancelFileTransferFlag; + public static boolean isCancelFileTransferFlag; // 上传文件进度条stage private Stage uploadFileDialogStage; // 下载文件进度条stage private Stage downloadFileDialogStage; + // 决定心跳包是否需要判断登录状态是否失效 + public boolean isNeedKnowLoginStatus=false; + public MainApp() { // 加载配置文件 loadSettingProperties(); // 初始化一些数据 - dataReqId = (long) 0; minoaDataAPI = new MinoaDataAPI(this); messageLogMap = new TreeMap>(); iniNotReadMessageListWhenLogin = new NotReadMessageList(); @@ -144,12 +157,11 @@ public class MainApp extends Application { contactListFinished = false; chatBoxIniFinished = false; fileLocalPath = "E:\\"; - fileServerBinPath = "/"; sharedFileServerPath = "/share/"; System.out.println("客户端根目录:"+getClientPath()); userHeadPhotoBinPath = getClientPath() + "\\resources\\images\\headPhotos\\"; // System.out.println(userHeadPhotoBinPath); - sliceSize = 7000; +// sliceSize = 7000; isCancelFileTransferFlag=false; // 初始化记录当前显示的面板的字符串 @@ -178,49 +190,57 @@ public class MainApp extends Application { System.out.println("en bytelength: "+StringByteLengthUtil.getByteLength("en")); } - // 加载可修改属性的配置文件 - public void loadSettingProperties(){ - InputStream inputStream = null; - try { - //如果 classPath 不存在,则获取的输入流会为 null - inputStream=new BufferedInputStream(new FileInputStream(this.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + // 加载可修改属性的配置文件 + public void loadSettingProperties() { + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(this.getClientPath() + File.separator + "ndn" + File.separator + "settings.properties")); // inputStream = MainApp.class.getClassLoader().getResourceAsStream("/ndn/settings.properties"); - if (inputStream == null) { - System.out.println("没有找到配置文件..."); - } - Properties settingProperties = new Properties(); - settingProperties.load(inputStream); - String serverIPAddress = settingProperties.getProperty("ServerIPAddress"); - String serverPortAddress=settingProperties.getProperty("ServerPortAddress"); - String dataPackagePrefix=settingProperties.getProperty("DataPackagePrefix"); - System.out.println("ServerIPAddress: "+serverIPAddress); - System.out.println("ServerPortAddress: "+serverPortAddress); - System.out.println("DataPackagePrefix: "+dataPackagePrefix); - this.minoaServerIpString=serverIPAddress; - this.minoaServerPortInteger=Integer.parseInt(serverPortAddress); - this.globalPrefixString=dataPackagePrefix; - } catch (IOException e) { - e.printStackTrace(); - }finally{ - //关闭输入流 - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + String serverIPAddress = settingProperties.getProperty("ServerIPAddress"); + String serverPortAddress = settingProperties.getProperty("ServerPortAddress"); + String NDNBlockChainIPAddressString=settingProperties.getProperty("ndnBlockChainIPAddress"); + String NDNBlockChainPortAddressString=settingProperties.getProperty("ndnBlockChainPortAddress"); + String dataPackagePrefix = settingProperties.getProperty("DataPackagePrefix"); + String threadNumberString = settingProperties.getProperty("ThreadNumberForFileTransfer"); + System.out.println("ServerIPAddress: " + serverIPAddress); + System.out.println("ServerPortAddress: " + serverPortAddress); + System.out.println("NDNBlockChainIPAddress: "+NDNBlockChainIPAddressString); + System.out.println("NDNBlockChainPortAddress: "+NDNBlockChainPortAddressString); + System.out.println("DataPackagePrefix: " + dataPackagePrefix); + System.out.println("ThreadNumberString: " + threadNumberString); + this.minoaServerIpString = serverIPAddress; + this.minoaServerPortInteger = Integer.parseInt(serverPortAddress); + this.NDNBlockChainIPAddress=NDNBlockChainIPAddressString; + this.NDNBlockChainPortAddress=Integer.parseInt(NDNBlockChainPortAddressString); + this.globalPrefixString = dataPackagePrefix; + this.threadNumberForFileTransfer = Integer.parseInt(threadNumberString); + } catch (IOException e) { + e.printStackTrace(); + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } - // 获取一个新的数据请求标识 - public Long getNewDataReqId() { - dataReqId++; - return dataReqId; - } + // 获取一个新的数据请求标识 + public static Long getNewDataReqId() { + return dataReqId.incrementAndGet(); + } // 获取项目根目录路径 - public String getClientPath() { + public static String getClientPath() { File directory = new File("");// 参数为空 String path = ""; try { @@ -266,60 +286,132 @@ public class MainApp extends Application { minoaDataAPI.bindNews(); } + // 判断minoaAPI中的face是否启动,如果未开启,说明IP有问题,返回false + public static boolean isFaceLinked(){ + return minoaDataAPI.runFace(); + } + // 下载文件到本地缺省目录下[E盘根目录] - public Integer downloadFileByPathfilename(String pathfileName) { - return loginerController.downloadFile(pathfileName); - } +// public Integer downloadFileByPathfilename(String pathfileName) { +// return loginerController.downloadFile(pathfileName); +// } + + // 登录失效:弹窗提醒,点击确定之后跳转到登录界面 + public void reLogin(){ + // 非FX线程调用FX的UI组件 + Platform.runLater(() -> { + // 首先,修改本地登录状态 + KeepLoginStatus.setLoginStatus(false); + // 然后,弹窗提醒 + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setTitle("登录状态失效"); + alert.setHeaderText("登录状态失效"); + alert.setContentText("您的登录状态失效,请重新登录。"); + alert.showAndWait(); + // 最后,展示登录界面 + showLoginOverview(); + }); + } // 下载文件到指定目录下 - public Integer downloadFileByPathfilename(String pathfileName, String localDir) { - return loginerController.downloadFileToSpecifiedDir(pathfileName, localDir); - } +// public Integer downloadFileByPathfilename(String pathfileName, String localDir) { +// return loginerController.downloadFileToSpecifiedDir(pathfileName, localDir); +// } - // 显示进度条并下载文件到指定目录下 - public void downloadFileByPathfilenameWithProgressBar(String pathfileName, String localDir){ - isCancelFileTransferFlag=false; + // 显示进度条并下载文件到指定目录下 + public void downloadFileByPathfilenameWithProgressBar(String pathfileName, String localDir) { +// currentDownloadedDataSlices.set(0); + isCancelFileTransferFlag = false; // 创建进度条子Stage downloadFileDialogStage = new Stage(); - downloadFileDialogStage.setTitle("minoaClientWindows-文件传输"); + downloadFileDialogStage.setTitle("FileSystem-文件传输"); downloadFileDialogStage.getIcons().add(new Image("file:resources/images/logo_mini.png")); downloadFileDialogStage.initStyle(StageStyle.TRANSPARENT); downloadFileDialogStage.initModality(Modality.WINDOW_MODAL); downloadFileDialogStage.initOwner(primaryStage); Group root = new Group(); - Scene scene = new Scene(root, 330, 120, Color.WHITE); + Scene scene = new Scene(root, 530, 220, Color.WHITE); downloadFileDialogStage.setScene(scene); BorderPane mainPane = new BorderPane(); - mainPane.setPrefHeight(100); - mainPane.setPrefWidth(325); + mainPane.setPrefHeight(200); + mainPane.setPrefWidth(525); root.getChildren().add(mainPane); final Label label = new Label("文件传输进度:"); final ProgressBar progressBar = new ProgressBar(0); + progressBar.setPrefWidth(300); + Long filelen=loginerController.getServerFileLength(pathfileName); + Integer cycle = (int)(filelen / sliceSize); + if (filelen % sliceSize != 0) { + cycle++; + } + final Integer sliceNum=cycle; +// final Text text = new Text("0/" + cycle.toString()); + final Text text = new Text("0%"); + text.setWrappingWidth(50); + + Text nullTextTop=new Text("");//空text,控制位置 + Text nullTextLeft=new Text("");//空text,控制位置 + // 文件名称 + final Label filenamelabel = new Label("文件名称:"); + final Text filenameText = new Text(); + String filename=pathfileName; + if(filename.length()>50){ + filename=filename.substring(0,50)+"..."; + } + filenameText.setText(filename); + final HBox fnhb = new HBox(); + fnhb.setSpacing(10); + fnhb.setAlignment(Pos.CENTER_LEFT); + fnhb.getChildren().addAll(filenamelabel, filenameText); + // 文件大小 + final Label filesizeLabel = new Label("文件大小:"); + final Text filesizeText = new Text(); + String filesize= FileUtil.sizeToShowSize((long)filelen); + filesizeText.setText(filesize); + final HBox fshb = new HBox(); + fshb.setSpacing(10); + fshb.setAlignment(Pos.CENTER_LEFT); + fshb.getChildren().addAll(filesizeLabel, filesizeText); +// fshb.setLayoutX(50); + // 两个合并 + final VBox vb=new VBox(); + vb.setSpacing(25); + vb.setAlignment(Pos.CENTER_LEFT); + vb.getChildren().addAll(nullTextTop,fnhb,fshb); + HBox bigHb=new HBox(); + bigHb.setSpacing(38); + bigHb.setAlignment(Pos.CENTER_LEFT); + bigHb.getChildren().setAll(nullTextLeft,vb); +// vb.setLayoutX(50); + mainPane.setTop(bigHb); final HBox hb = new HBox(); - hb.setSpacing(20); + hb.setSpacing(10); hb.setAlignment(Pos.CENTER); - hb.getChildren().addAll(label, progressBar); + hb.getChildren().addAll(label, progressBar,text); mainPane.setCenter(hb); final Button startButton = new Button("开始传输"); final Button cancelButton = new Button("取消传输"); + final Button sureButton = new Button("确认完成"); + sureButton.setDisable(true); final HBox hb2 = new HBox(); - hb2.setSpacing(20); + hb2.setSpacing(50); hb2.setAlignment(Pos.CENTER); // hb2.getChildren().addAll(startButton); - hb2.getChildren().addAll(startButton, cancelButton); + hb2.getChildren().addAll(startButton, cancelButton,sureButton); mainPane.setBottom(hb2); startButton.setOnAction(new EventHandler() { public void handle(ActionEvent event) { startButton.setDisable(true); progressBar.setProgress(0); - cancelButton.setDisable(true); - cancelButton.setText("确认完成"); - copyWorker = createDownWorker(pathfileName, localDir,cancelButton); + cancelButton.setDisable(false); + sureButton.setDisable(true); + copyWorker = createDownWorkerBasedWindow(pathfileName, localDir,sliceNum, cancelButton,sureButton,text); progressBar.progressProperty().unbind(); progressBar.progressProperty().bind(copyWorker.progressProperty()); copyWorker.messageProperty().addListener(new ChangeListener() { @@ -333,237 +425,315 @@ public class MainApp extends Application { }); cancelButton.setOnAction(new EventHandler() { public void handle(ActionEvent event) { - if(cancelButton.getText().equals("确认完成")){ - }else{ - isCancelFileTransferFlag=true; - } + isCancelFileTransferFlag = true; + downloadFileDialogStage.close(); + } + }); + sureButton.setOnAction(new EventHandler() { + public void handle(ActionEvent event) { downloadFileDialogStage.close(); -// startButton.setDisable(false); -// cancelButton.setDisable(true); -// copyWorker.cancel(true); -// progressBar.progressProperty().unbind(); -// progressBar.setProgress(0); -// System.out.println("传输已终止。"); } }); // 打开文件传输Stage downloadFileDialogStage.showAndWait(); } - // 文件数据下载TASK - public Task createDownWorker(String filename, String localDir,Button button) { + // 文件数据下载TASK:滑动窗口 + public Task createDownWorkerBasedWindow(String filename, String localDir,Integer sliceNum, Button button,Button sureButton,Text text) { return new Task() { @Override protected Object call() throws Exception { - // 下载到本地的文件名称 - String localName = loginerController.getPureFileName(filename); - // 发送数据请求 - Long seqLong = getNewDataReqId(); - OrderInfo orderInfo=new OrderInfo(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(loginerController.getFileInfoJson(filename)); - minoaDataAPI.executeOrder("/fileInfo", orderInfo); - // 获取文件信息 - ResponseData responseData = minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); - JSONObject jsonObject = responseData.praseRequestData(); - System.out.println("fileInfo-JSON: " + jsonObject.toString()); - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (codeInteger == 200) { - String dataString; - try { - dataString = jsonObject.getString("data"); - JSONObject dataJsonObject = new JSONObject(dataString); - Integer sliceNumInteger; - sliceNumInteger = dataJsonObject.getInt("sliceNum"); - // 根据分片信息获取每个分片,并合并成一个完整比特流 - Integer flagSuccessInteger=0; - Integer flagInteger = 0; - for (int i = 0; i < sliceNumInteger; i++) { - flagInteger = loginerController.downLoadFileBySlice(filename, i, localDir, localName); - if(flagInteger==0){ - flagSuccessInteger++; - System.out.println("数据分片"+i+"传输成功. "); -// updateMessage(""); - updateProgress(flagSuccessInteger, sliceNumInteger); - }else{ - flagSuccessInteger++; - System.out.println("数据分片"+i+"传输失败. "); -// updateMessage(""); - updateProgress(flagSuccessInteger, sliceNumInteger); + Long startTime = System.currentTimeMillis(); + // 滑动窗口协议下载文件 +// DownLoadClient downLoadClient = new DownLoadClient(filename,localDir,sliceNum); + DownLoadClientBasedFacePool downLoadClient=new DownLoadClientBasedFacePool(filename, + localDir,sliceNum,threadNumberForFileTransfer); + //启动一个线程监听更新的传输进度值 + Thread listenThread = new Thread(new Runnable() { + @Override + public void run() { + Long sliceNumLong=sliceNum.longValue(); + // TODO Auto-generated method stub + while (true) { + Long progressInteger = downLoadClient.recvCount.get(); + System.out.println("当前已经下载的数据片个数:" + progressInteger); + Double progressPercentDouble=Math.floor((progressInteger*100)/sliceNumLong); + Integer progressPercentInteger=progressPercentDouble.intValue(); + String textString=progressPercentInteger.toString()+"%"; + // 更新进度条 +// String textString=progressInteger.toString()+ "/" + sliceNumLong.toString(); + if (!text.getText().equals(textString)) { + updateProgress(progressInteger, sliceNumLong); + text.setText(textString); + } + //如果当前进度条 + if (progressInteger.equals(sliceNumLong)) { + updateProgress(1,1); + text.setText("100%"); + System.out.println("***************监听进度条的线程结束监听*************"); + break; + } + try { + Thread.sleep(30); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + text.setText("100%"); + updateProgress(1,1); + System.out.println("***************监听进度条的线程结束监听*************"); + break; } } - if(flagSuccessInteger==sliceNumInteger){ - System.out.println("文件数据已成功全部写入本地"); - }else{ - System.out.println("由于未知原因,文件数据全部或部分未成功写入本地"); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } + }); + listenThread.start(); + // 下载文件 + boolean res = downLoadClient.downloadData(); + listenThread.interrupt(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + LoggerUtil.insertFileAction(filename,"下载",(endTime - startTime) + "ms"); + // 每个分片都上传成功 + if (res) { + System.out.println("已成功将文件 " + filename + " 下载到本地" + localDir + "目录下。"); + } else { + System.out.println("由于未知原因,服务器端文件" + filename + "下载失败。"); } //设置确认按钮 - button.setDisable(false); + button.setDisable(true); + sureButton.setDisable(false); return true; } }; } // 上传本地文件到指定的服务器目录下 - public Integer uploadFileToServerPath(File file, String serverpath) { - Integer r=loginerController.sendFileToServer(file, serverpath); - return r; - } +// public Integer uploadFileToServerPath(File file, String serverpath) { +// Integer r=loginerController.sendFileToServer(file, serverpath); +// return r; +// } // 显示进度条并上传文件到指定目录 - public void uploadFileToServerPathWithProgressBar(File file, String serverpath){ - isCancelFileTransferFlag=false; - // 创建进度条子Stage - uploadFileDialogStage = new Stage(); - uploadFileDialogStage.setTitle("minoaClientWindows-文件传输"); - uploadFileDialogStage.getIcons().add(new Image("file:resources/images/logo_mini.png")); - uploadFileDialogStage.initStyle(StageStyle.TRANSPARENT); - uploadFileDialogStage.initModality(Modality.WINDOW_MODAL); - uploadFileDialogStage.initOwner(primaryStage); + public void uploadFileToServerPathWithProgressBar(File file, String serverpath) { +// currentUploadedDataSlices.set(0); + isCancelFileTransferFlag = false; + // 创建进度条子Stage + uploadFileDialogStage = new Stage(); + uploadFileDialogStage.setTitle("FileSystemWindows-文件传输"); + uploadFileDialogStage.getIcons().add(new Image("file:resources/images/logo_mini.png")); + uploadFileDialogStage.initStyle(StageStyle.TRANSPARENT); + uploadFileDialogStage.initModality(Modality.WINDOW_MODAL); + uploadFileDialogStage.initOwner(primaryStage); - Group root = new Group(); - Scene scene = new Scene(root, 330, 120, Color.WHITE); - uploadFileDialogStage.setScene(scene); + Group root = new Group(); + Scene scene = new Scene(root, 530, 220, Color.WHITE); + uploadFileDialogStage.setScene(scene); - BorderPane mainPane = new BorderPane(); - mainPane.setPrefHeight(100); - mainPane.setPrefWidth(325); - root.getChildren().add(mainPane); + BorderPane mainPane = new BorderPane(); + mainPane.setPrefHeight(200); + mainPane.setPrefWidth(525); + root.getChildren().add(mainPane); - final Label label = new Label("文件传输进度:"); - final ProgressBar progressBar = new ProgressBar(0); + Text nullTextTop=new Text("");//空text,控制位置 + Text nullTextLeft=new Text("");//空text,控制位置 + // 文件名称 + final Label filenamelabel = new Label("文件名称:"); + final Text filenameText = new Text(); + String filename=file.getAbsolutePath(); + if(filename.length()>50){ + filename=filename.substring(0,50)+"..."; + } + filenameText.setText(filename); + final HBox fnhb = new HBox(); + fnhb.setSpacing(10); + fnhb.setAlignment(Pos.CENTER_LEFT); + fnhb.getChildren().addAll(filenamelabel, filenameText); + // 文件大小 + final Label filesizeLabel = new Label("文件大小:"); + final Text filesizeText = new Text(); + String filesize= FileUtil.sizeToShowSize(file.length()); + filesizeText.setText(filesize); + final HBox fshb = new HBox(); + fshb.setSpacing(10); + fshb.setAlignment(Pos.CENTER_LEFT); + fshb.getChildren().addAll(filesizeLabel, filesizeText); +// fshb.setLayoutX(50); + // 两个合并 + final VBox vb=new VBox(); + vb.setSpacing(25); + vb.setAlignment(Pos.CENTER_LEFT); + vb.getChildren().addAll(nullTextTop,fnhb,fshb); + HBox bigHb=new HBox(); + bigHb.setSpacing(38); + bigHb.setAlignment(Pos.CENTER_LEFT); + bigHb.getChildren().setAll(nullTextLeft,vb); +// vb.setLayoutX(50); + mainPane.setTop(bigHb); - final HBox hb = new HBox(); - hb.setSpacing(20); - hb.setAlignment(Pos.CENTER); - hb.getChildren().addAll(label, progressBar); - mainPane.setCenter(hb); + final Label label = new Label("文件传输进度:"); + final ProgressBar progressBar = new ProgressBar(0); + progressBar.setPrefWidth(300); +// long filelen = file.length(); +// int cycle = (int) (filelen / sliceSize); +// if (filelen % sliceSize != 0) { +// cycle++; +// } +// final Text text = new Text("0/" + cycle); + final Text text = new Text("0%" ); + text.setWrappingWidth(50); + final HBox hb = new HBox(); + hb.setSpacing(10); + hb.setAlignment(Pos.CENTER); + hb.getChildren().addAll(label, progressBar, text); + mainPane.setCenter(hb); - final Button startButton = new Button("开始传输"); - final Button cancelButton = new Button("取消传输"); - final HBox hb2 = new HBox(); - hb2.setSpacing(20); - hb2.setAlignment(Pos.CENTER); + final Button startButton = new Button("开始传输"); + final Button cancelButton = new Button("取消传输"); + final Button sureButton = new Button("确认完成"); + sureButton.setDisable(true); + final HBox hb2 = new HBox(); + hb2.setSpacing(50); + hb2.setAlignment(Pos.CENTER); // hb2.getChildren().addAll(startButton); - hb2.getChildren().addAll(startButton, cancelButton); - mainPane.setBottom(hb2); - startButton.setOnAction(new EventHandler() { - public void handle(ActionEvent event) { - startButton.setDisable(true); - progressBar.setProgress(0); - cancelButton.setDisable(true); - cancelButton.setText("确认完成"); - copyWorker = createWorker(file, serverpath,cancelButton); - progressBar.progressProperty().unbind(); - progressBar.progressProperty().bind(copyWorker.progressProperty()); - copyWorker.messageProperty().addListener(new ChangeListener() { - public void changed(ObservableValue observable, - String oldValue, String newValue) { - System.out.println(newValue); - } - }); - new Thread(copyWorker).start(); - } - }); - cancelButton.setOnAction(new EventHandler() { - public void handle(ActionEvent event) { - if(cancelButton.getText().equals("确认完成")){ - }else{ - isCancelFileTransferFlag=true; + hb2.getChildren().addAll(startButton, cancelButton,sureButton); + mainPane.setBottom(hb2); + startButton.setOnAction(new EventHandler() { + public void handle(ActionEvent event) { + startButton.setDisable(true); + progressBar.setProgress(0); + cancelButton.setDisable(false); +// copyWorker = createWorker(file, serverpath, cancelButton, text); + copyWorker = createUploadWorkerBasedWindow(file, serverpath, cancelButton, sureButton,text); + progressBar.progressProperty().unbind(); + progressBar.progressProperty().bind(copyWorker.progressProperty()); + copyWorker.messageProperty().addListener(new ChangeListener() { + public void changed(ObservableValue observable, + String oldValue, String newValue) { + System.out.println(newValue); } - uploadFileDialogStage.close(); -// startButton.setDisable(false); -// cancelButton.setDisable(true); -// copyWorker.cancel(true); -// progressBar.progressProperty().unbind(); -// progressBar.setProgress(0); -// System.out.println("传输已终止。"); - } - }); - // 打开文件传输Stage - uploadFileDialogStage.showAndWait(); + }); + new Thread(copyWorker).start(); + } + }); + cancelButton.setOnAction(new EventHandler() { + public void handle(ActionEvent event) { + // 手动取消了传输 + isCancelFileTransferFlag = true; + uploadFileDialogStage.close(); + } + }); + sureButton.setOnAction(new EventHandler() { + public void handle(ActionEvent event) { + // 确认完成了传输 + uploadFileDialogStage.close(); + } + }); + // 打开文件传输Stage + uploadFileDialogStage.showAndWait(); +// }); } - // 文件数据上传TASK - public Task createWorker(File file, String serverpath,Button button) { + // 文件数据上传TASK:滑动窗口 + public Task createUploadWorkerBasedWindow(File file, String serverpath, Button button,Button sureButton, Text text) { return new Task() { @Override protected Object call() throws Exception { //获取要上传文件的文件长度,计算上传次数 long filelen = file.length(); - int cycle = (int) filelen / sliceSize; - int remainder=(int)filelen%sliceSize; - if((cycle>0)&&(remainder==0)) { - cycle--; + int cycle = (int) (filelen / sliceSize); + if (filelen % sliceSize != 0) { + cycle++; } System.out.println("file-len: " + filelen); System.out.println("cycle: " + cycle); - //发送上传命令给上传接口,接口自行取本地数据 - int flagSuccess = 0; //记录收到200回复的次数 - for (int i = 0; i <= cycle; i++) { - OrderInfo orderInfo = new OrderInfo(); - ResponseData responseData = new ResponseData(); - Long seqLong = getNewDataReqId(); - orderInfo.setSeq(seqLong); - //此时传入的文件路径是windows下的绝对路径 - orderInfo.setJsonString(loginerController.getUploadFile(file.getAbsolutePath(), i * sliceSize)); - minoaDataAPI.executeOrder("/uploadFile", orderInfo, serverpath); - responseData = minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -// System.out.println("上传文件的数据回执(200表示成功):"+responseData.getResponseJsonDataString()); - JSONObject jsonObject = responseData.praseRequestData(); - responseData.printSelf(); - // 解析数据 - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Long startTime = System.currentTimeMillis(); + // 滑动窗口协议上传文件 +// UpLoadClient upLoadClient = new UpLoadClient(file, serverpath); + UpLoadClientBasedFacePool upLoadClient=new UpLoadClientBasedFacePool(file, + serverpath,threadNumberForFileTransfer); + //启动一个线程监听更新的传输进度值 + Thread listenThread = new Thread(new Runnable() { + @Override + public void run() { + long filelen = file.length(); + Long sliceNumLong = filelen / sliceSize; + if (filelen % sliceSize != 0) { + sliceNumLong++; + } + // TODO Auto-generated method stub + while (true) { + Long progressInteger = upLoadClient.recvCount.get(); + System.out.println("当前已经上传的数据片个数:" + progressInteger); + Double progressPercentDouble=Math.floor((progressInteger*100)/sliceNumLong); + Integer progressPercentInteger=progressPercentDouble.intValue(); + String textString=progressPercentInteger.toString()+"%"; + // 更新进度条 +// String textString=progressInteger.toString()+ "/" + cycleInteger; + if (!text.getText().equals(textString)) { + updateProgress(progressInteger, sliceNumLong); + text.setText(textString); + } + //如果当前进度条 + if (progressInteger.equals(sliceNumLong)) { + text.setText("100%"); + updateProgress(1,1); + System.out.println("***************监听进度条的线程结束监听*************"); + break; + } + try { + Thread.sleep(30); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + text.setText("100%"); + updateProgress(1,1); + System.out.println("***************监听进度条的线程结束监听*************"); + break; + } + } } - if (codeInteger == 200) { - flagSuccess++; - System.out.println("数据分片"+i+"传输结果[200表示成功]: "+codeInteger); -// updateMessage(""); - updateProgress(i + 1, cycle+1); - }else{ - System.out.println("数据分片"+i+"传输结果[200表示成功]: "+codeInteger); -// updateMessage(""); - updateProgress(i + 1, cycle+1); - } - } - //每个分片都上传成功 - if (flagSuccess == (cycle + 1)) { + }); + // 先发送一个开始上传信号 + String serverFilePath = serverpath + MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath()); +// ECOSUtil.sendUploadFileBeginSignal(serverFilePath); + listenThread.start(); + // 上传文件 + boolean res = upLoadClient.uploadData(); + // 上传完成或取消上传后,取消上传进度监听 + listenThread.interrupt(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + LoggerUtil.insertFileAction(file.getAbsolutePath(),"上传",(endTime - startTime) + "ms"); + // 每个分片都上传成功 + if (res) { System.out.println("已成功将文件" + file.getAbsolutePath() + "上传至服务器" + serverpath + "目录下。"); +// String serverFilePath = serverpath + MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath()); +// ECOSUtil.sendUploadFileEndSignal(serverFilePath); } else { System.out.println("由于未知原因,本地文件" + file.getAbsolutePath() + "上传服务器失败。"); } - //设置确认按钮 - button.setDisable(false); -// System.out.println("文件上传线程:我干完活儿啦"); + // 设置取消按钮状态 + button.setDisable(true); + // 设置确认按钮状态 + sureButton.setDisable(false); return true; } }; } // 上传本地文件到服务器的共享文件夹下 - public Integer uploadFileToServerSharedFolder(File file) { - Integer res=loginerController.sendFileToServer(file, this.sharedFileServerPath); + public boolean uploadFileToServerSharedFolder(File file) { +// Integer res=loginerController.sendFileToServer(file, this.sharedFileServerPath); + Long startTime = System.currentTimeMillis(); + UpLoadClientBasedFacePool upLoadClient = new UpLoadClientBasedFacePool( + file,this.sharedFileServerPath,threadNumberForFileTransfer); + // 下载文件 + boolean res = ((UpLoadClientBasedFacePool) upLoadClient).uploadData(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); return res; } //请求服务器某文件的字节长度 - public Integer getServerFileByteLength(String filename){ + public Long getServerFileByteLength(String filename){ return loginerController.getServerFileLength(filename); } @@ -709,27 +879,49 @@ public class MainApp extends Application { showLoginOverview(); } - // 展示登录界面 - public void showLoginOverview() { - try { - // 加载overview - FXMLLoader loader = new FXMLLoader(); - loader.setLocation(MainApp.class.getClassLoader().getResource("fxml/login/LoginOverview.fxml")); - AnchorPane loginOverview = (AnchorPane) loader.load(); + // 展示登录界面 + public void showLoginOverview() { + try { + // 加载overview + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(MainApp.class.getClassLoader().getResource("fxml/login/LoginOverview.fxml")); + AnchorPane loginOverview = (AnchorPane) loader.load(); - // 设置scene - Scene scene = new Scene(loginOverview); - primaryStage.setScene(scene); + // 设置scene + Scene scene = new Scene(loginOverview); - // 传参给控制器 - loginerController = loader.getController(); - loginerController.setMainApp(this); + // 传参给控制器 + loginerController = loader.getController(); + loginerController.setMainApp(this); - primaryStage.show(); - } catch (IOException e) { - e.printStackTrace(); - } - } + // 判断是否是登录状态,且账号密码是正确的 + boolean m_flag=false; + boolean isLoginning= KeepLoginStatus.getLogineStatus(); + Loginer m_loginer=KeepLoginStatus.getLoginerInfo(); + if((isLoginning==true)&&(m_loginer.getUserName()!=null)&&(m_loginer.getPassWord()!=null)){ + System.out.println("login status: "+isLoginning); + System.out.println("loginer name: "+m_loginer.getUserName()); + System.out.println("loginer password: "+m_loginer.getPassWord()); + String loginString=loginerController.getLoginJsonString( + m_loginer.getUserName(),m_loginer.getPassWord()); + if(loginerController.checkPass(loginString)){ + m_flag=true; + } + } + + if(m_flag){ + // 是登录状态且账号密码正确 + isNeedKnowLoginStatus=true; + iniShow(); + }else{ + // 否则 + primaryStage.setScene(scene); + } + primaryStage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } // 使用弹窗展示设置界面 public void showSettingOverview() { diff --git a/src/main/java/cn/minoa/dataRequestInterface/CongestionWindow.java b/src/main/java/cn/minoa/dataRequestInterface/CongestionWindow.java new file mode 100644 index 0000000..acf8690 --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/CongestionWindow.java @@ -0,0 +1,205 @@ +package cn.minoa.dataRequestInterface; + +/** + * @author mac + * @description + * 拥塞窗口 + * @date 2020-03-24 10:25 + */ +public class CongestionWindow { + + //拥塞窗口大小 + private Double cwnd; + + //表示当前正在发送的数据,发送一条数据需要加一,收到成功恢复需要减一 + private Double inFlight; + + //拥塞窗口阈值 + private Double thresh; + + //下一次窗口减小的界限 + private Integer nSupress = 0; + + //收到数据包的数量,收到一个数据包进行加一操作 + private Long nIndata = 0l; + + //发送兴趣包的数量,发出一个兴趣包进行加一操作 + private Long nOutInterest = 0l; + + //更新nsupress时的一个比率 + private static Double rate = 0.5d; + + public CongestionWindow(){ + this.cwnd = 4d; + this.thresh = 300d; + this.inFlight = 0d; + } + public CongestionWindow(Double cwnd, Double thresh, Double inFlight){ + this.inFlight = inFlight; + this.cwnd = cwnd; + this.thresh = thresh; + } + + /** + * 当前窗口是否为空 + * @return + */ + public boolean empty(){ + boolean res = false; + synchronized (this){ + if (inFlight == 0){ + res = true; + } + } + return res; + } + + /** + * 当前窗口是否已满 + * @return + */ + public boolean full(){ + boolean res = false; + synchronized (this){ + if(cwnd == inFlight){ + res = true; + } + } + return res; + } + + /** + * 获取当前还能发送多少数据 + * 如果不能发送数据,返回值为0 + * @return + */ + public int getAvailableCwnd(){ + int res = 0; + synchronized (this){ + if(inFlight >= cwnd){ + res = 0; + }else{ + res = (int)(cwnd - inFlight); + } + } + return res; + } + + + /** + * 在onData函数中 + * 收到一个数据包,执行加一操作,需要加锁 + */ + public void nIndataIncrease(){ + synchronized (this){ + nIndata++; + } + } + + /** + * 发出一个兴趣包,执行加一操作,不需要加锁 + */ + public void nOutInterestIncrease(){ + nOutInterest++; + } + + /** + * inFlight加一 + */ + public void inFlightIncrease(){ + synchronized (this){ + this.inFlight++; + } + } + + public void inFlightIncrease(int inFlight){ + synchronized (this){ + this.inFlight += inFlight; + } + } + + /** + * inFliehgt减一 + */ + public void inFlightDecrease(){ + synchronized (this){ + this.inFlight--; + } + } + public void inFlightDecrease(int inFlight){ + synchronized (this){ + this.inFlight -= inFlight; + } + } + + /** + * 增加拥塞窗口的值 + * + */ + public void cwndIncrease(){ + + synchronized (this){ + if(this.cwnd < this.thresh){ + //慢开始算法 + this.cwnd += 1; + /*if(this.cwnd > this.thresh){ + this.thresh = this.cwnd; + }*/ + }else{ + //拥塞避免算法 + this.cwnd += (1.0/this.cwnd); + } + } + System.out.println("-----------------------------------------cwnd:" + cwnd + ", thresh:" + thresh); + } + + /** + * 减少拥塞窗口的值 + * 每当检测到拥塞时,就需要执行此函数 + */ + public void cwndDecrease(){ + synchronized (this){ + if(nIndata >= nSupress){ + this.thresh = Math.floor(this.cwnd/2); + this.cwnd = this.thresh; + nSupress = (int)(nOutInterest + rate*(nOutInterest - nIndata)); + } + } + System.out.println("-----------------------------------------cwnd:" + cwnd + ", thresh:" + thresh); + } + + + /** + * 设置拥塞窗口大小 + * @param cwnd + */ + public void setCwnd(Double cwnd){ + synchronized (this){ + this.cwnd = cwnd; + } + } + + /** + * 获得当前拥塞窗口大小 + * @return + */ + public Integer getCwnd(){ + + int res = 0; + synchronized (this){ + res = this.cwnd.intValue(); + } + return res; + + } + + @Override + public String toString() { + return "CongestionWindow {" + + "cwnd=" + cwnd + + ", inFlight=" + inFlight + + ", thresh=" + thresh + + '}'; + } + +} diff --git a/src/main/java/cn/minoa/dataRequestInterface/DataCacheQueue.java b/src/main/java/cn/minoa/dataRequestInterface/DataCacheQueue.java index 6b15a9c..0ec2e74 100644 --- a/src/main/java/cn/minoa/dataRequestInterface/DataCacheQueue.java +++ b/src/main/java/cn/minoa/dataRequestInterface/DataCacheQueue.java @@ -2,28 +2,30 @@ package cn.minoa.dataRequestInterface; //缓存服务器的回执数据 import java.util.Map; -import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; public class DataCacheQueue { //存储数据回执 - public Map responseDataMap; - +// public static volatile Map responseDataMap; + public static volatile ConcurrentHashMap responseDataMap = new ConcurrentHashMap(); + public DataCacheQueue() { // TODO Auto-generated constructor stub - responseDataMap=new TreeMap(); +// responseDataMap=new TreeMap(); + responseDataMap=new ConcurrentHashMap(); } - + //放入一个数据 - public void setResponseData(Long seq,ResponseData rd) { + public static void setResponseData(Long seq,ResponseData rd) { responseDataMap.put(seq, rd); } - + //根据seq获取ResponseData - public ResponseData getResponseDataBySeq(Long seq) { + public static ResponseData getResponseDataBySeq(Long seq) { //等待数据回执 while(!responseDataMap.containsKey(seq)) { try { - Thread.sleep(10); + Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -33,11 +35,20 @@ public class DataCacheQueue { responseDataMap.remove(seq); return rd; } - + //判断是否为空 - public boolean isEmpty() { + public static boolean isEmpty() { return responseDataMap.isEmpty(); } - - + + + public static void showMapData(){ + System.out.println("this is responseDataMap info:"); + for(Map.Entry entry : responseDataMap.entrySet()){ + System.out.println("entry-key:" + entry.getKey() + ", entry-value:"); + entry.getValue().printSelf(); + + } + System.out.println("--------------- end ----------------"); + } } diff --git a/src/main/java/cn/minoa/dataRequestInterface/DataTestMain.java b/src/main/java/cn/minoa/dataRequestInterface/DataTestMain.java deleted file mode 100644 index fae41d2..0000000 --- a/src/main/java/cn/minoa/dataRequestInterface/DataTestMain.java +++ /dev/null @@ -1,133 +0,0 @@ -package cn.minoa.dataRequestInterface; - -import org.json.JSONObject; - -import cn.minoa.MainApp; - -public class DataTestMain { - //文件操作命令 - static private String getFileActionJson(String uuid,String cmd) { - JSONObject jsonObject =new JSONObject(); - String commandString="/fileAction"; - String usernameString="wefree"; - String uuidString=uuid; - String cmdString=cmd; - String filename="/"; - try { - jsonObject.put("command", commandString); - jsonObject.put("username", usernameString); - jsonObject.put("uuid", uuidString); - jsonObject.put("fileCmd", cmdString); - jsonObject.put("filename", filename); - } catch (Exception e) { - // TODO: handle exception - System.out.println("exception: " + e.getMessage()); - } - return jsonObject.toString(); - } - - //发送消息 - static private String getSendRTMsgJson(String uuid,String msgTail) { - JSONObject jsonObject =new JSONObject(); - String commandString="/sendRTMsg"; - String fromString="oa_wefree"; - String toString="wefree"; - String uuidString=uuid; - String msgString="hello,wefree. iam oa_wefree. --"+msgTail; - try { - jsonObject.put("command", commandString); - jsonObject.put("from", fromString); - jsonObject.put("to", toString); - jsonObject.put("uuid", uuidString); - jsonObject.put("msg", msgString); - } catch (Exception e) { - // TODO: handle exception - System.out.println("exception: " + e.getMessage()); - } - return jsonObject.toString(); - } - - //请求通知消息 - static private String getGetInformJson(Integer pageNo,String uuidString) { - JSONObject jsonObject =new JSONObject(); - String commandString="/getInform"; - String usernameString="wefree"; - Integer pageNoInteger=pageNo; - Integer pageSizeInteger=10; - try { - jsonObject.put("command", commandString); - jsonObject.put("username", usernameString); - jsonObject.put("uuid", uuidString); - jsonObject.put("pageNo", pageNoInteger); - jsonObject.put("pageSize", pageSizeInteger); - } catch (Exception e) { - // TODO: handle exception - System.out.println("exception: " + e.getMessage()); - } - return jsonObject.toString(); - } - - public static void main(String args[]){ - MainApp mainApp=new MainApp(); - MinoaDataAPI minoaDataAPI=new MinoaDataAPI(mainApp); - //test register -// minoaDataAPI.executeOrder("/register", orderInfo); - //test login - OrderInfo loginOrderInfo=new OrderInfo(); - loginOrderInfo.setSeq((long) 0); - loginOrderInfo.setLoginJson(); - minoaDataAPI.executeOrder("/login", loginOrderInfo); - ResponseData responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) 0); - responseData.printSelf(); - String uuidString=responseData.getUuidByPraseLoginData(); - //test getUsers -// minoaDataAPI.executeOrder("/getUsers", orderInfo); - //test sendRTMsg -// minoaDataAPI.executeOrder("/sendRTMsg", orderInfo); - //test getRTMsg -// minoaDataAPI.executeOrder("/getRTMsg", orderInfo); - //test getRTMsgLog -// minoaDataAPI.executeOrder("/getRTMsgLog", orderInfo); - - //制造点假数据出来[wefree=>oa_wefree] -// OrderInfo orderInfo=new OrderInfo(); -// String sendJsonString; -// for(int i=1;i<5;i++) { -// orderInfo.setSeq((long) i); -// sendJsonString=getSendRTMsgJson(uuidString,String.valueOf(i)); -// orderInfo.setJsonString(sendJsonString); -// minoaDataAPI.executeOrder("/sendRTMsg", orderInfo); -// responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) i); -// responseData.printSelf(); -// } - - //测试请求通知信息 -// OrderInfo orderInfo=new OrderInfo(); -// orderInfo.setSeq((long)1); -// orderInfo.setJsonString(getGetInformJson(0,uuidString)); -// minoaDataAPI.executeOrder("/getInform", orderInfo); -// responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) 1); -// responseData.printSelf(); - - //测试云文件上传下载 - OrderInfo orderInfo=new OrderInfo(); - - orderInfo.setSeq((long)1); - orderInfo.setJsonString(getFileActionJson(uuidString, "ls")); - minoaDataAPI.executeOrder("/fileAction", orderInfo); - responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) 1); - responseData.printSelf(); - - orderInfo.setSeq((long)2); - orderInfo.setJsonString(getFileActionJson(uuidString, "rm")); - minoaDataAPI.executeOrder("/fileAction", orderInfo); - responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) 2); - responseData.printSelf(); - - orderInfo.setSeq((long)3); - orderInfo.setJsonString(getFileActionJson(uuidString, "mkdir")); - minoaDataAPI.executeOrder("/fileAction", orderInfo); - responseData=minoaDataAPI.dataCacheQueue.getResponseDataBySeq((long) 3); - responseData.printSelf(); - } -} diff --git a/src/main/java/cn/minoa/dataRequestInterface/DownAndUpLoadData.java b/src/main/java/cn/minoa/dataRequestInterface/DownAndUpLoadData.java new file mode 100644 index 0000000..83731ff --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/DownAndUpLoadData.java @@ -0,0 +1,71 @@ +package cn.minoa.dataRequestInterface; +// 多线程上传下载:数据收发接口【3/3】 +import cn.minoa.MainApp; +import org.json.JSONObject; + +/** + * @author mac + * @description + * @date 2020-03-16 11:16 + */ +public class DownAndUpLoadData { + + /** + * 构造下载文件的json信息 + * @param filename + * @param sliceNo + * @return + */ + public static String getDownloadFileJson(String filename, Integer sliceNo) { + JSONObject jsonObject = new JSONObject(); + String commandString; + if(filename.contains("/")){ + commandString = "/downloadFile"; + }else{ + commandString="/downloadShareFile"; + } + String usernameString = MainApp.loginer.getUserName(); + String uuidString = MainApp.loginer.getUuid(); + String filenameString = filename; + Integer sliceNoInteger = sliceNo; + try { + jsonObject.put("command", commandString); + jsonObject.put("username", usernameString); + jsonObject.put("uuid", uuidString); + jsonObject.put("filename", filenameString); + jsonObject.put("sliceNo", sliceNoInteger); + } catch (Exception e) { + // TODO: handle exception + System.out.println("exception: " + e.getMessage()); + } + System.out.println("getDownloadFileJson: "+jsonObject.toString()); + return jsonObject.toString(); + } + + + /** + * 构造上传文件的json字符串 + * @param filename + * @param offset + * @return + */ + public static String getUploadFile(String filename, Long offset) { + JSONObject jsonObject = new JSONObject(); + String commandString = "/uploadFile"; + String usernameString = MainApp.loginer.getUserName(); + String uuidString = MainApp.loginer.getUuid(); + String filenameString = filename; + Long offsetInteger = offset; + try { + jsonObject.put("command", commandString); + jsonObject.put("username", usernameString); + jsonObject.put("uuid", uuidString); + jsonObject.put("filename", filenameString); + jsonObject.put("offset", offsetInteger); + } catch (Exception e) { + // TODO: handle exception + System.out.println("exception: " + e.getMessage()); + } + return jsonObject.toString(); + } +} diff --git a/src/main/java/cn/minoa/dataRequestInterface/DownLoadClientBasedFacePool.java b/src/main/java/cn/minoa/dataRequestInterface/DownLoadClientBasedFacePool.java new file mode 100644 index 0000000..f6f1d8b --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/DownLoadClientBasedFacePool.java @@ -0,0 +1,331 @@ +package cn.minoa.dataRequestInterface; + +import cn.minoa.MainApp; +import net.named_data.jndn.*; +import net.named_data.jndn.security.KeyChain; +import net.named_data.jndn.security.SecurityException; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.util.Blob; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author mac + * @description + * @date 2020-03-22 18:28 + */ +public class DownLoadClientBasedFacePool { + + // 下载前缀 + private String orderPrefix = "/downloadFile"; + + // 要下载的文件的服务器路径 + private String filename; + // 下载到的文件路径 + private String localDir; + // 要下载的文件的总数据片个数 + private Integer sliceNumber; + + // 当前排到应该下载的数据片序号 + private Integer currentSliceNo = 0; + + // FacePool + private FacePool facePool; + + // 下载到本地的文件对象 + private RandomAccessFile randomAccessFile; + + + // 滑动窗口控制类 + private CongestionWindow congestionWindow = new CongestionWindow(); + + // 存放发送失败数据的文件偏移 + private ConcurrentLinkedQueue failedSlice = new ConcurrentLinkedQueue<>(); + + // 收到回复的数量 + public AtomicLong recvCount = new AtomicLong(0); + + //发送的数据是否发送成功,key:第几个数据片,从0开始,value:该数据片超时次数 + private Map timeOutNums = new ConcurrentHashMap<>(); + // 超时重传上限数值,某个兴趣包的重传次数超过此数值,则放弃重传,直接返回false + private Integer timeoutCeil=15; + + public DownLoadClientBasedFacePool(String filename, String localDir, + Integer sliceNumber, Integer facepoolnumber) { + this.filename = filename; + this.localDir = localDir; + System.out.println("localDir: "+this.localDir); + this.sliceNumber = sliceNumber; + this.facePool=new FacePool(facepoolnumber); + this.facePool.start(MinoaDataAPI.minoaServerIpString, MinoaDataAPI.minoaServerPortInteger); + System.out.println("***********FacePool中并发数:"+facepoolnumber+"***********"); + } + + /** + * 判断是否含有超时次数超过阈值的 + * @return + */ + private boolean isTimeOut(){ + for (Map.Entry entry : timeOutNums.entrySet()) { + System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); + if(entry.getValue() > timeoutCeil){ + return true; + } + } + return false; + } + + /** + * 下载数据的主函数 + * + * @return + */ + public boolean downloadData() { + // 先初始化一个本地文件 + try { + String localName= MinoaDataAPI.getPureFileName(filename); + this.randomAccessFile = new RandomAccessFile(localDir + localName, "rw"); + System.out.println("本地文件打开"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + while (true) { + //判断是否已经上传安成 + if (recvCount.longValue()>=this.sliceNumber) { + break; + } + + // 判断是否已经被用户终止上传 + if(MainApp.isCancelFileTransferFlag){ + System.out.println("用户已主动中断下载"); + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + // 每一次发送数据 + int cwnd = 0; + // 获取此次可以发送数据的个数 + while ((cwnd = congestionWindow.getAvailableCwnd()) <= 0) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + for (int i = 0; i < cwnd; i++) { + //TODO 首先发送failedmap中的数据 + if (failedSlice.size() > 0) { + //首先发送failedslice中的数据 + Integer failSliceNo = failedSlice.poll(); + System.out.println("发送数据, name: " + filename + ", failSliceNo:" + failSliceNo+ ", failedSlice Size:" + failedSlice.size()); + recvData(failSliceNo); + } else { + if (this.currentSliceNo < this.sliceNumber) { + System.out.println("发送数据, name: " + filename + ",current SliceNo:" + currentSliceNo + ", failedSlice Size:" + failedSlice.size()); + recvData(currentSliceNo); + currentSliceNo++; + } + } + } + + if(isTimeOut()){ + System.out.println("丢包超过阈值: "+timeoutCeil+" ,文件传输主动中断"); + this.facePool.shutdownNow(); + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + } + + this.facePool.shutdownNow(); + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + return true; + } + + /** + * 下载一个数据片 + * + * @param sliceNo + */ + private void recvData(Integer sliceNo) { + facePool.submit(freeface -> { + // 设置JSON请求命令 + OrderInfo orderInfo = new OrderInfo(); + Long seqLong = MainApp.getNewDataReqId(); + orderInfo.setSeq(seqLong); + String testStr = DownAndUpLoadData.getDownloadFileJson(filename, sliceNo); + System.out.println("*******************DownloadJson:" + testStr + "*******************"); + orderInfo.setJsonString(testStr); + + // 发送兴趣包 + Name name = new Name(MinoaDataAPI.globalPrefixString + orderPrefix + "/" + seqLong); + Interest interest = new Interest(name); + interest.setMustBeFresh(true); + interest.setInterestLifetimeMilliseconds(5000); + try { + ResponseData responseData = new ResponseData(); + responseData.setPrefix(orderPrefix); + // 签名 + try { + // 赋值兴趣包的附带信息,并标志区块链 + interest.setApplicationParameters(new Blob(orderInfo.getJsonString())); + KeyManager.INSTANCE.getKeyChain().sign(interest); +// MinoaDataAPI.keyChain.sign(interest); + } catch (PibImpl.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyChain.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (net.named_data.jndn.security.tpm.TpmBackEnd.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String purefilename = MinoaDataAPI.getPureFileName(filename); + DownLoadData downLoadData = new DownLoadData(this.localDir, purefilename, sliceNo); + // 使用tcp发送数据请求兴趣包 + freeface.expressInterest(interest, downLoadData, downLoadData, downLoadData); + // 滑动窗口:flight++ + congestionWindow.inFlightIncrease(); + // 滑动窗口:outInterest++ + congestionWindow.nOutInterestIncrease(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + + public class DownLoadData implements OnData, OnTimeout, OnNetworkNack { + // 下载到的本地路径 + private String localDir; + //下载到本地后重命名的文件名称 + private String localName; + // 下载到本地路径后的文件名称 + private Integer sliceNo; + // 标记是否拿到网络回复(数据信息/超时信息) + public boolean isFinished = false; + + public DownLoadData(String localDir,String localName, Integer sliceNo) { + this.localDir = localDir; + this.localName = localName; + this.sliceNo = sliceNo; + } + + @Override + public void onData(Interest interest, Data data) { + // 将文件数据片写入本地文件 + try { + synchronized (randomAccessFile) { + System.out.println("开始写入文件数据分片... :" + localDir + localName); +// RandomAccessFile randomAccessFile = new RandomAccessFile(localDir + localName, "rw"); +// int contentSize = data.getContent().size(); +// System.out.println("该数据分片长度为:" + contentSize); +// byte[] content = new byte[contentSize]; +// for (int i = 0; i < contentSize; i++) { +// content[i] = data.getContent().buf().get(i); +// } + // 设置数据分片写入到文件的起点位置 + randomAccessFile.seek(sliceNo * MainApp.sliceSize); + // 写入数据分片 + randomAccessFile.write(data.getContent().getImmutableArray()); +// randomAccessFile.write(content, 0, contentSize); +// randomAccessFile.close(); + System.out.println("写入文件数据分片完毕:" + localDir + localName); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // 滑动窗口:flight-- + congestionWindow.inFlightDecrease(); + // 收到成功数据的数量++ + recvCount.incrementAndGet(); + // 滑动窗口:inData++ + congestionWindow.nIndataIncrease(); + System.out.println("第" + sliceNo + "片下载成功!"); + + // 处理拥塞:拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可 + if (data.getCongestionMark() > 0) { + System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark()); + // 滑动窗口:cwndDecrease() + congestionWindow.cwndDecrease(); + }else{ + // 滑动窗口:cwndIncrease() + congestionWindow.cwndIncrease(); + } + + if(timeOutNums.containsKey(this.sliceNo)){ + timeOutNums.remove(this.sliceNo); + } + + // 处理完成 + isFinished = true; + } + + // 处理兴趣包超时 + @Override + public void onTimeout(Interest interest) { + // 滑动窗口:flight-- + congestionWindow.inFlightDecrease(); + // 加入失败队列 + failedSlice.add(sliceNo); + // 打印超时信息 + System.out.println("########## Time out for interest " + interest.getName()+"###########"); + + if(timeOutNums.containsKey(this.sliceNo)){ + int value = timeOutNums.get(this.sliceNo) + 1; + timeOutNums.put(this.sliceNo,value); + }else{ + timeOutNums.put(this.sliceNo,1); + } + // 处理完成 + isFinished = true; + } + + // 处理收到一个Nack包 + @Override + public void onNetworkNack(Interest interest, NetworkNack networkNack){ + congestionWindow.inFlightDecrease(); + failedSlice.add(sliceNo); + if(timeOutNums.containsKey(this.sliceNo)){ + int value = timeOutNums.get(this.sliceNo) + 1; + timeOutNums.put(this.sliceNo,value); + }else{ + timeOutNums.put(this.sliceNo,1); + } + // 打印超时信息 + System.out.println("########## Nack for interest " + interest.getName() + +", Nack: "+networkNack.toString()); + isFinished=true; + } + } + +} diff --git a/src/main/java/cn/minoa/dataRequestInterface/FacePool.java b/src/main/java/cn/minoa/dataRequestInterface/FacePool.java new file mode 100644 index 0000000..06fb836 --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/FacePool.java @@ -0,0 +1,162 @@ +package cn.minoa.dataRequestInterface; + +import net.named_data.jndn.Face; +import net.named_data.jndn.encoding.EncodingException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Face 池,里面可以创建多个face连接,每个face单独一个线程处理 + */ +public class FacePool { + private int poolSize; + + // 采用阻塞队列来记录任务 + private LinkedBlockingQueue faceLinkedBlockingQueue; + + private ArrayList faces; + + private ExecutorService processEventThreadPool; + private ExecutorService faceDealThreadPool; + + public FacePool(int poolSize) { + this.poolSize = poolSize; + faces = new ArrayList<>(); + processEventThreadPool = Executors.newFixedThreadPool(poolSize); + faceDealThreadPool = Executors.newFixedThreadPool(poolSize); + faceLinkedBlockingQueue = new LinkedBlockingQueue<>(); + } + + public FacePool start(String host, int port) { + for (int i = 0; i < poolSize; i++) { + faces.add(new Face(host, port)); + final int finalI = i; + ProcessEventTask processEventTask = new ProcessEventTask(host, port, faces.get(i), i, task -> { + // 发生错误则自动重新创建face,建立连接,然后将processEvent任务提交到线程池当中 + processEventThreadPool.submit(task); + faces.set(finalI, task.getFace()); + }); + processEventThreadPool.submit(processEventTask); + + // 初始时Face池里所有的Face都是可用的 + faceLinkedBlockingQueue.add(faces.get(i)); + } + return this; + } + + public FacePool submit(AsyncUseFaceCallback asyncUseFaceCallback) { + faceDealThreadPool.submit(() -> { + try { + Face face = faceLinkedBlockingQueue.take(); + asyncUseFaceCallback.onFaceAvailable(face); + faceLinkedBlockingQueue.put(face); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + return this; + } + + public void shutdownNow() { + if (!processEventThreadPool.isShutdown()) { + processEventThreadPool.shutdownNow(); + } + if (!faceDealThreadPool.isShutdown()) { + faceDealThreadPool.shutdown(); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + ///// Callback + /////////////////////////////////////////////////////////////////////////////////////////// + public interface AsyncUseFaceCallback { + void onFaceAvailable(Face face); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + ///// Tasks + /////////////////////////////////////////////////////////////////////////////////////////// + + static class ProcessEventTask implements Runnable { + private Face face; + private int id; + private String host; + private int port; + private StatusCallback statusCallback; + + public ProcessEventTask(String host, int port, Face face, int id, StatusCallback statusCallback) { + this.face = face; + this.id = id; + this.host = host; + this.port = port; + this.statusCallback = statusCallback; + } + + public Face getFace() { + return face; + } + + public void setFace(Face face) { + this.face = face; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public StatusCallback getStatusCallback() { + return statusCallback; + } + + public void setStatusCallback(StatusCallback statusCallback) { + this.statusCallback = statusCallback; + } + + @Override + public void run() { +// System.out.println("faceId: " + id + "(host: " + host + ", port: " + port + ") -> start"); + try { + while (true) { + face.processEvents(); +// System.out.println("faceId: " + id + " -> processEvent"); + Thread.sleep(1); + } + } catch (IOException | EncodingException | InterruptedException e) { + System.out.println(e.getMessage()); + this.face = new Face(this.host, this.port); + if (this.statusCallback != null) { + this.statusCallback.onError(this); + } + } + } + + interface StatusCallback { + void onError(ProcessEventTask task); + } + } +} \ No newline at end of file diff --git a/src/main/java/cn/minoa/dataRequestInterface/KeyManager.java b/src/main/java/cn/minoa/dataRequestInterface/KeyManager.java new file mode 100644 index 0000000..69fd0e1 --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/KeyManager.java @@ -0,0 +1,93 @@ +package cn.minoa.dataRequestInterface; + +import net.named_data.jndn.Name; +import net.named_data.jndn.security.KeyChain; +import net.named_data.jndn.security.pib.Pib; +import net.named_data.jndn.security.pib.PibIdentity; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.security.pib.PibSqlite3; +import net.named_data.jndn.security.tpm.Tpm; +import net.named_data.jndn.security.tpm.TpmBackEnd; +import net.named_data.jndn.security.tpm.TpmBackEndFile; +import net.named_data.jndn.security.v2.CertificateV2; + +public enum KeyManager { + INSTANCE; + private KeyChain keyChain = null; + + KeyManager() { + try { + this.keyChain = getOrBuildKeyChain("/default"); + } catch (KeyChain.Error | PibImpl.Error | Pib.Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error error) { + error.printStackTrace(); + } + } + + public KeyManager initKeyChain(String identityName) throws Pib.Error, Tpm.Error, TpmBackEnd.Error, + CertificateV2.Error, KeyChain.Error, PibImpl.Error { + this.keyChain = getOrBuildKeyChain(identityName); + return this; + } + + public CertificateV2 getCertification(String identityName, String keyName) throws Pib.Error, PibImpl.Error, + CertificateV2.Error, Tpm.Error, KeyChain.Error, TpmBackEnd.Error { + return KeyManager.INSTANCE.initKeyChain(identityName) + .getKeyChain() + .getPib() + .getIdentity(new Name(identityName)) + .getKey(new Name(keyName)) + .getDefaultCertificate(); + } + + private KeyChain getOrBuildKeyChain(String identityName) throws + KeyChain.Error, PibImpl.Error, Pib.Error, Tpm.Error, TpmBackEnd.Error, CertificateV2.Error { + KeyChain keyChain = null; + PibSqlite3 pibSqlite3 = new PibSqlite3("./ndn/pid"); + TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("./ndn/tpm"); + try { + keyChain = new KeyChain(pibSqlite3, tpmBackEndFile); + PibIdentity identity = keyChain.getPib().getIdentity(new Name(identityName)); + keyChain.setDefaultIdentity(identity); + } catch (Pib.Error error) { + error.printStackTrace(); + System.out.println(error.getMessage()); + // 获取本地记录的用户的身份失败,可能是一个新的身份 + PibIdentity identity = keyChain.createIdentityV2(new Name(identityName)); + keyChain.setDefaultIdentity(identity); + pibSqlite3.setDefaultKeyOfIdentity(identity.getName(), identity.getDefaultKey().getName()); + } + return keyChain; + } + + // 判断本地是否有某个标识名对应的证书 + public boolean isInKeyChain(String identityName) throws + KeyChain.Error, PibImpl.Error, Pib.Error, Tpm.Error, TpmBackEnd.Error, CertificateV2.Error { + KeyChain keyChain = null; + PibSqlite3 pibSqlite3 = new PibSqlite3("./ndn/pid"); + TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("./ndn/tpm"); + try { + keyChain = new KeyChain(pibSqlite3, tpmBackEndFile); + PibIdentity identity = keyChain.getPib().getIdentity(new Name(identityName)); + keyChain.setDefaultIdentity(identity); + return true; + } catch (Pib.Error error) { +// error.printStackTrace(); + System.out.println(error.getMessage()); + System.out.println("本地无该标识名称对应的证书:"+identityName); + return false; + } + } + + public CertificateV2 getCertification(String identityName) throws Pib.Error, PibImpl.Error { + return keyChain.getPib().getIdentity(new Name(identityName)).getDefaultKey().getDefaultCertificate(); + } + + public KeyChain getKeyChain() { + return keyChain; + } + + public void setKeyChain(KeyChain keyChain) { + this.keyChain = keyChain; + } + +} \ No newline at end of file diff --git a/src/main/java/cn/minoa/dataRequestInterface/MinoaDataAPI.java b/src/main/java/cn/minoa/dataRequestInterface/MinoaDataAPI.java index d73c05c..ce4aabe 100644 --- a/src/main/java/cn/minoa/dataRequestInterface/MinoaDataAPI.java +++ b/src/main/java/cn/minoa/dataRequestInterface/MinoaDataAPI.java @@ -4,20 +4,24 @@ package cn.minoa.dataRequestInterface; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import cn.minoa.model.SingleNotice; +import cn.minoa.util.KeyStorageUtil; import cn.minoa.util.StringByteLengthUtil; +import net.named_data.jndn.*; +import net.named_data.jndn.security.pib.Pib; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.security.tpm.Tpm; +import net.named_data.jndn.security.tpm.TpmBackEnd; +import net.named_data.jndn.security.v2.CertificateV2; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import cn.minoa.MainApp; import cn.minoa.model.SingleMessage; -import net.named_data.jndn.Data; -import net.named_data.jndn.Face; -import net.named_data.jndn.Interest; -import net.named_data.jndn.Name; -import net.named_data.jndn.OnData; import net.named_data.jndn.encoding.EncodingException; import net.named_data.jndn.security.KeyChain; import net.named_data.jndn.security.SecurityException; @@ -28,73 +32,118 @@ import net.named_data.jndn.security.tpm.TpmBackEndMemory; import net.named_data.jndn.util.Blob; public class MinoaDataAPI { - static private String keyChainNameString = "/wefree"; - private String minoaServerIpString; - private Integer minoaServerPortInteger; - private String globalPrefixString; - private String pidDbPathString; -// private String minoaServerIpString = "121.15.171.89"; -// private Integer minoaServerPortInteger=6363; -// private String globalPrefixString = "/ndn/edu/pkusz/OA"; + public static String keyChainNameString = "/default"; + public static String minoaServerIpString; + public static Integer minoaServerPortInteger; + public static String globalPrefixString; +// public static String pidDbPathString; - KeyChain keyChain; - Face face; - public DataCacheQueue dataCacheQueue; + // 同一兴趣包超时或丢包次数达到上限时的错误信息 + public static String timeoutError = "timeout times reaches the upper limit."; + // 由于连接问题(多次超时/丢包),返回给主线程的错误码 + public static Integer timeoutCodeInteger = 333; + // 同一兴趣包超时或丢包次数达到上限时的错误信息 + public static String nackError = "receive nack."; + // 由于连接问题(多次超时/丢包),返回给主线程的错误码 + public static Integer nackCodeInteger = 334; + +// KeyChain keyChain; + public static Face face; + public volatile DataCacheQueue dataCacheQueue; private MainApp mainApp; + // 标志连接是否正常 + private boolean isConnected; + + //发送的数据是否发送成功,key:第几个数据片,从0开始,value:该数据片超时次数 + private Map timeOutNums = new ConcurrentHashMap<>(); + // 超时重传上限数值,某个兴趣包的重传次数超过此数值,则放弃重传,直接返回false + private Integer timeoutCeil = 10; + public MinoaDataAPI(MainApp mainApp) { // TODO Auto-generated constructor stub minoaServerIpString=mainApp.minoaServerIpString; minoaServerPortInteger=mainApp.minoaServerPortInteger; globalPrefixString=mainApp.globalPrefixString; - this.face = new Face(minoaServerIpString,minoaServerPortInteger); + isConnected=false; this.dataCacheQueue = new DataCacheQueue(); this.mainApp = mainApp; - pidDbPathString=mainApp.getClientPath()+ File.separator+"ndn"; - System.out.println("pidDbPathString: "+pidDbPathString); - runFace(); +// pidDbPathString=mainApp.getClientPath()+ File.separator+"ndn"; +// System.out.println("pidDbPathString: "+pidDbPathString); + runFace(minoaServerIpString, minoaServerPortInteger); + // 首先按照"/default"初始化KeyChain try { - // 密钥“黑盒” - PibSqlite3 pibSqlite3 = new PibSqlite3(pidDbPathString); - TpmBackEndMemory tpmBackEndMemory = new TpmBackEndMemory(); - keyChain = new KeyChain(pibSqlite3, tpmBackEndMemory); - PibIdentity identity = keyChain.getPib().getIdentity(new Name(keyChainNameString)); - keyChain.setDefaultIdentity(identity); - - System.out.println(keyChain.getDefaultCertificateName().toUri()); - } catch (Exception e) { - // TODO: handle exception - System.out.println("exception: " + e.getMessage()); + KeyManager.INSTANCE.initKeyChain(keyChainNameString); + } catch (Pib.Error | PibImpl.Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error | KeyChain.Error error) { + error.printStackTrace(); + } + // 从本地初始化keyName + String keyString= KeyStorageUtil.getKeyName(); + try { + // 如果本地keyName指向的证书确实在keyChain中,就将该证书取出 + if((keyString!=null)&&(KeyManager.INSTANCE.isInKeyChain(keyString))){ + keyChainNameString=keyString; + System.out.println("keyChainNameString: "+keyChainNameString); + // 再次按照本地证书前缀初始化KeyChain + try { + KeyManager.INSTANCE.initKeyChain(keyChainNameString); + } catch (Pib.Error | Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error | KeyChain.Error error) { + error.printStackTrace(); + } + } + } catch (Pib.Error | PibImpl.Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error | KeyChain.Error error) { + error.printStackTrace(); } } + /** + * 判断某个key对应的兴趣包的超时次数是否超过阈值 + * + * @return + */ + private boolean isInterestTimeOut(Long timeoutMapKey) { + if (timeOutNums.get(timeoutMapKey) > timeoutCeil) { + return true; + } + return false; + } + // 开辟线程运行face - private void runFace() { + public boolean runFace(String ipString, Integer portInteger) { + if (isConnected) { + return true; + } + this.face = new Face(ipString, portInteger); + isConnected = true; Thread thread = new Thread(new Runnable() { @Override public void run() { +// System.out.println("face is trying to link..."); // TODO Auto-generated method stub try { while (true) { face.processEvents(); // 线程暂时休眠 - try { - Thread.sleep(5); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + Thread.sleep(1); } - } catch (IOException e) { + } catch (InterruptedException | EncodingException | IOException e) { // TODO Auto-generated catch block - e.printStackTrace(); - } catch (EncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); +// e.printStackTrace(); + System.out.println(e.getMessage()); + isConnected = false; } } }); thread.start(); + return isConnected; + } + + public boolean runFace(String ipString) { + return this.runFace(ipString, minoaServerPortInteger); + } + + public boolean runFace() { + return this.runFace(minoaServerIpString, minoaServerPortInteger); } // 开辟线程监听新消息/新通知/新审批 @@ -303,14 +352,6 @@ public class MinoaDataAPI { singleMessage.setTime(timeLong); singleMessage.setToName(mainApp.loginer.getUserName()); singleMessage.setMsgId(idInteger); - // 加入前端数据内存 -// System.out.println("MinoaDataAPI-addNewMessage-singleMessageString: "+singleMessageString); -// System.out.println("MinoaDataAPI-addNewMessage-fromName: "+fromNameString); -// mainApp.messageLogMap.get(fromNameString).add(singleMessage); -// //加入未读消息的列表中 -// mainApp.notReadMessageList.addNotReadMessage(singleMessage); -// // 产生消息气泡 -// mainApp.newMessageBubble(singleMessage); // 将这条新消息交给mainApp处理 mainApp.handleGetNewMessage(singleMessage); System.out.println("MinoaDataAPI-handleGetNewMessage success: " + singleMessageString); @@ -320,99 +361,6 @@ public class MinoaDataAPI { } } -// //判断是否有新消息产生=>废了,换接口了 -// private boolean judgeNewMessageProdution() { -// //发送数据请求 -// Long seqLong=mainApp.getNewDataReqId(); -// OrderInfo orderInfo=new OrderInfo(); -// orderInfo.setSeq(seqLong); -// orderInfo.setJsonString(getHasNewsJson()); -// mainApp.minoaDataAPI.executeOrder("/hasNews", orderInfo); -// //获取回复消息 -// ResponseData responseData=mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -// JSONObject jsonObject=responseData.praseRequestData(); -//// System.out.println("hasNews-JSON: "+jsonObject.toString()); -// Integer codeInteger = null; -// try { -// codeInteger = jsonObject.getInt("code"); -// } catch (JSONException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// if(codeInteger==200) { -// String dataString; -// try { -// dataString = jsonObject.getString("data"); -// JSONObject dataJSONObject=new JSONObject(dataString); -// Integer msgInteger=dataJSONObject.getInt("msg"); -// if(msgInteger>0) { -// System.out.println(msgInteger); -// return true; -// } -// } catch (JSONException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// } -// return false; -// } -// -// //获取是否有新消息产生的json字符串 -// private String getHasNewsJson() { -// JSONObject jsonObject =new JSONObject(); -// String commandString="/hasNews"; -// String userNameString=mainApp.loginer.getUserName(); -// String uuidString=mainApp.loginer.getUuid(); -// try { -// jsonObject.put("command", commandString); -// jsonObject.put("username", userNameString); -// jsonObject.put("uuid", uuidString); -// } catch (Exception e) { -// // TODO: handle exception -// System.out.println("exception: " + e.getMessage()); -// } -// return jsonObject.toString(); -// } - - // 获取注册请求字符串 -// static private String getRegisterJson() { -// JSONObject jsonObject = new JSONObject(); -// String mPubKey = "Bv0CsQcuCAR3Z2gwCANLRVkICH9+4yjVUHZaCAxjZXJ0LXJlcXVlc3QICf0AAAFv\nEUSBehQJGAECGQQANu6AFf0BJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBANbFutCAZqFjHEa16tYvy4lBgi9/zixKWQzE9I72vaG2Imym+6KR30qkAQOK\nh0uE5RD2YsGhRK99rde+JOqIfk2/sunhp4nctOS5f4DeuOty58ekrO+Co9ZFmNBI\nmyk5i/hakjBEd/vdD7b1VadDRep5mWs3rgCinZOUfVaZ4oKqSws7ZWMvOSlRMOOi\nVzj53P4poY109S6aWmi3xKw/D76vfJapjdOB9Dg7S3rz0Rve1F/ajHCXWLt4XU3k\nUCiBn3Qmt6UD/MyDBaaUCfOvHTN6yVPtN6aOtYJVBAWt/P1ahLYhWkSm6KvrwMt0\nRzy2lw/lPriT99REItc/0wK6XwkCAwEAARZGGwEBHBcHFQgEd2doMAgDS0VZCAh/\nfuMo1VB2Wv0A/Sb9AP4PMjAxOTEyMTdUMDAzMTQw/QD/DzIwMTkxMjI3VDAwMzEz\nORf9AQCM+8WROXfi8WD9DydfLuSUxV0v3KW/Gn422/puDrkwwi1R2ogsAUc2O8pp\npuMLjWrQOTgE6ZTg80uWoDSUjjk44aMjkL2SAfp62vHRbGFx7+dckHAtF+DS6NH7\nX2vojFHOg6fksOE1M7XqLHmEEctZrFVSnQO7nB3DfRg+BqzZC/iy+8YAvTIvqA1c\nNsKYkmNITB80aM1v2H7fKnV4ZJpZnW71G5vbaPUseeklalQ2vEuBgWdd/1PL/0Ml\nI52npzqoeKAEpLp+vBwGN5ryGtWKB12nNimpMfevQAn/9BVIg59lZ7DIlE0sWmgW\nnwDxIXKebdViOejHlKwNAykxRRWw"; -// String commandString = "/register"; -// String userNameString = "oa_wefree"; -// String passWordString = "12345678"; -// String phoneString = "10000000006"; -// Integer levelInteger = 0; -// try { -// jsonObject.put("command", commandString); -// jsonObject.put("username", userNameString); -// jsonObject.put("password", passWordString); -// jsonObject.put("phone", phoneString); -// jsonObject.put("publicKey", mPubKey); -// jsonObject.put("level", levelInteger); -// } catch (Exception e) { -// System.out.println("exception: " + e.getMessage()); -// } -// return jsonObject.toString(); -// } - -// //"获取最近三天未读实时消息" -// static private String getGetRTMsgJson() { -// JSONObject jsonObject =new JSONObject(); -// String commandString="/getRTMsg"; -// String userNameString="oa_wefree"; -// String uuidString="29c8f0a4-52d7-4478-90f0-6136996dbe96"; -// try { -// jsonObject.put("command", commandString); -// jsonObject.put("username", userNameString); -// jsonObject.put("uuid", uuidString); -// } catch (Exception e) { -// // TODO: handle exception -// System.out.println("exception: " + e.getMessage()); -// } -// return jsonObject.toString(); -// } - // 根据命令前缀获取相应的请求字符串【JSON】 static private String getRequestStr(String orderPrefix, OrderInfo orderInfo) { String requestStr; @@ -475,77 +423,6 @@ public class MinoaDataAPI { return requestStr; } - // 执行文件下载的特殊数据请求语句 - // 执行数据请求语句 - public boolean executeOrder(String orderPrefix, OrderInfo orderInfo, String localDir, String localName) { - // 获取json格式的数据请求字符串 - String requestStr = getRequestStr(orderPrefix, orderInfo); -// System.out.println("requestStr: "+requestStr); - // 命令前缀格式不对的情况下返回false - if (requestStr.equals("*wrong command string*")) { - System.out.println(requestStr); - return false; - } - - // 发送数据兴趣包 - Name name = new Name(globalPrefixString + orderPrefix + "/" + orderInfo.getSeq()); - Interest interest = new Interest(name); - interest.setMustBeFresh(true); - try { - // 文件下载 - interest.setApplicationParameters(new Blob(requestStr)); - // 密钥“黑盒” - keyChain.sign(interest); - this.expressTheDownloadInterest(orderPrefix, interest, orderInfo,localDir,localName); - return true; - } catch (Exception e) { - System.out.println("exception: " + e.getMessage()); - return false; - } - } - - // 执行数据请求语句 - public boolean executeOrder(String orderPrefix, OrderInfo orderInfo,String serverpath) { - // 获取json格式的数据请求字符串 - String requestStr = getRequestStr(orderPrefix, orderInfo); -// System.out.println("requestStr: "+requestStr); - // 命令前缀格式不对的情况下返回false - if (requestStr.equals("*wrong command string*")) { - System.out.println(requestStr); - return false; - } - - // 发送数据兴趣包 - Name name = new Name(globalPrefixString + orderPrefix + "/" + orderInfo.getSeq()); - Interest interest = new Interest(name); - interest.setMustBeFresh(true); -// System.out.println("interest name: "+name.toString()); - try { - if (orderPrefix.equals("/downloadFile")) { - // 文件下载 - interest.setApplicationParameters(new Blob(requestStr)); - // 密钥“黑盒” - keyChain.sign(interest); - this.expressTheDownloadInterest(orderPrefix, interest, orderInfo); - } else if (orderPrefix.equals("/uploadFile")) { - // 文件上传[interest和keyChain的参数设置在函数体内] - this.expressTheUploadInterest(orderPrefix, interest, orderInfo,serverpath); - }else { - interest.setApplicationParameters(new Blob(requestStr)); -// System.out.println("setApplicationParameters-blob: "+requestStr); - // 密钥“黑盒” - keyChain.sign(interest); -// System.out.println(interest.toUri()); - this.expressTheInterest(orderPrefix, interest, orderInfo.getSeq()); - } - - return true; - } catch (Exception e) { - System.out.println("exception: " + e.getMessage()); - return false; - } - } - // 执行数据请求语句 public boolean executeOrder(String orderPrefix, OrderInfo orderInfo) { // 获取json格式的数据请求字符串 @@ -561,322 +438,28 @@ public class MinoaDataAPI { Name name = new Name(globalPrefixString + orderPrefix + "/" + orderInfo.getSeq()); Interest interest = new Interest(name); interest.setMustBeFresh(true); -// System.out.println("interest name: "+name.toString()); + interest.setApplicationParameters(new Blob(requestStr)); + interest.setInterestLifetimeMilliseconds(2000); try { - if (orderPrefix.equals("/downloadFile")) { - // 文件下载 - interest.setApplicationParameters(new Blob(requestStr)); - // 密钥“黑盒” - keyChain.sign(interest); - this.expressTheDownloadInterest(orderPrefix, interest, orderInfo); - } else if (orderPrefix.equals("/uploadFile")) { - // 文件上传[interest和keyChain的参数设置在函数体内] - this.expressTheUploadInterest(orderPrefix, interest, orderInfo,"/"); - }else { - interest.setApplicationParameters(new Blob(requestStr)); -// System.out.println("setApplicationParameters-blob: "+requestStr); - // 密钥“黑盒” - keyChain.sign(interest); -// System.out.println(interest.toUri()); - this.expressTheInterest(orderPrefix, interest, orderInfo.getSeq()); - } - +// keyChain.sign(interest); + // 使用KeyManager管理兴趣包签名 + KeyManager.INSTANCE.getKeyChain().sign(interest); + this.expressTheInterest(orderPrefix, interest, orderInfo.getSeq()); return true; } catch (Exception e) { System.out.println("exception: " + e.getMessage()); return false; } } - - //文件上传到指定服务器路径下 - private void expressTheUploadInterest(String orderPrefix, Interest interest, OrderInfo orderInfo,String serverpath) { - // 设置回执前缀 - ResponseData responseData = new ResponseData(); - responseData.setPrefix(orderPrefix); - byte[] requestByte = null; // 请求数据 - // 重写ondata - try { - // 解析并修改文件名【window转server】 - String localFilePath = ""; - String serverFilePath = ""; - Integer offsetInteger = 0; - try { - // 解析 - JSONObject jsonObject = new JSONObject(orderInfo.getJsonString()); - offsetInteger = jsonObject.getInt("offset"); - localFilePath = jsonObject.getString("filename"); - serverFilePath = serverpath + getPureFileNameFromWindows(localFilePath); - // 修改 - jsonObject.remove("filename"); - jsonObject.put("filename", serverFilePath); - orderInfo.setJsonString(jsonObject.toString()); - System.out.println("request head str: " + orderInfo.getJsonString()); - System.out.println("head str length: "+orderInfo.getJsonString().length()); - System.out.println("head str byte length: "+ StringByteLengthUtil.getByteLength(orderInfo.getJsonString())); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 从本地读取数据 - byte[] content = new byte[10000]; // 文件分片内容 - try { - RandomAccessFile randomAccessFile = new RandomAccessFile(localFilePath, "rw"); - // 设置文件的读取起点 - randomAccessFile.seek(offsetInteger); - // 尝试读取数据 - int readLen = randomAccessFile.read(content, 0, 7000); - randomAccessFile.close(); - System.out.println("file slice readLen == " + readLen); -// int jsonLen = orderInfo.getJsonString().length(); - int jsonLen=StringByteLengthUtil.getByteLength(orderInfo.getJsonString()); - requestByte = new byte[jsonLen + 1 + readLen]; - System.arraycopy(orderInfo.getJsonString().getBytes("utf-8"), 0, requestByte, 0, jsonLen); - requestByte[jsonLen] = 0; - System.arraycopy(content, 0, requestByte, jsonLen + 1, readLen); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 赋值兴趣包的附带信息,并标志区块链 - System.out.println("requestByte-len: " + requestByte.length); - System.out.println("requestByte: " + requestByte); - interest.setApplicationParameters(new Blob(requestByte)); - System.out.println("interest.getApplicationParameters().size(): "+interest.getApplicationParameters().size()); - // 密钥“黑盒” - try { - keyChain.sign(interest); - } catch (Error e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyChain.Error e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (net.named_data.jndn.security.tpm.TpmBackEnd.Error e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 使用匿名内部类,发送数据请求兴趣包 - face.expressInterest(interest, new OnData() { - @Override - public void onData(Interest interest, Data data) { - // 返回成功写入或失败写入消息 - responseData.setResponseData(data.getContent().toString()); - dataCacheQueue.setResponseData(orderInfo.getSeq(), responseData); - } - }); - } catch (IOException e) { - e.printStackTrace(); - } - } - - //文件上传=>默认上传到根目录;此函数应废弃不予使用 -// private void expressTheUploadInterest(String orderPrefix, Interest interest, OrderInfo orderInfo) { -// // 设置回执前缀 -// ResponseData responseData = new ResponseData(); -// responseData.setPrefix(orderPrefix); -// byte[] requestByte = null; // 请求数据 -// // 重写ondata -// try { -// // 解析并修改文件名【window转server】 -// String localFilePath = ""; -// String serverFilePath = ""; -// Integer offsetInteger = 0; -// try { -// // 解析 -// JSONObject jsonObject = new JSONObject(orderInfo.getJsonString()); -// offsetInteger = jsonObject.getInt("offset"); -// localFilePath = jsonObject.getString("filename"); -// serverFilePath = mainApp.fileServerBinPath + getPureFileNameFromWindows(localFilePath); -// // 修改 -// jsonObject.remove("filename"); -// jsonObject.put("filename", serverFilePath); -// orderInfo.setJsonString(jsonObject.toString()); -// System.out.println("request head str: " + orderInfo.getJsonString()); -// } catch (JSONException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// // 从本地读取数据 -// byte[] content = new byte[10000]; // 文件分片内容 -// try { -// RandomAccessFile randomAccessFile = new RandomAccessFile(localFilePath, "rw"); -// // 设置文件的读取起点 -// randomAccessFile.seek(offsetInteger); -// // 尝试读取数据 -// int readLen = randomAccessFile.read(content, 0, 7000); -// randomAccessFile.close(); -// System.out.println("file slice readLen == " + readLen); -// int jsonLen = StringByteLengthUtil.getByteLength(orderInfo.getJsonString()); -// requestByte = new byte[jsonLen + 1 + readLen]; -// System.arraycopy(orderInfo.getJsonString().getBytes("utf-8"), 0, requestByte, 0, jsonLen); -// requestByte[jsonLen] = 0; -// System.arraycopy(content, 0, requestByte, jsonLen + 1, readLen); -// } catch (IOException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// // 赋值兴趣包的附带信息,并标志区块链 -// System.out.println("requestByte-len: " + requestByte.length); -// System.out.println("requestByte: " + requestByte); -// interest.setApplicationParameters(new Blob(requestByte)); -// // 密钥“黑盒” -// try { -// keyChain.sign(interest); -// } catch (Error e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } catch (KeyChain.Error e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } catch (net.named_data.jndn.security.tpm.TpmBackEnd.Error e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } catch (SecurityException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// // 使用匿名内部类,发送数据请求兴趣包 -// face.expressInterest(interest, new OnData() { -// @Override -// public void onData(Interest interest, Data data) { -// // 返回成功写入或失败写入消息 -// responseData.setResponseData(data.getContent().toString()); -// dataCacheQueue.setResponseData(orderInfo.getSeq(), responseData); -// } -// }); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } - -// // 合并两个Byte[] -// public byte[] byteMerger(byte[] bt1, byte[] bt2) { -// byte[] bt3 = new byte[bt1.length + bt2.length]; -// System.arraycopy(bt1, 0, bt3, 0, bt1.length); -// System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); -// return bt3; -// } - - //下载文件的数据分片到指定路径,并将文件重命名为指定文件名 - private void expressTheDownloadInterest(String orderPrefix, Interest interest, OrderInfo orderInfo,String localDir,String localName) { - // 设置回执前缀 - ResponseData responseData = new ResponseData(); - responseData.setPrefix(orderPrefix); - try { - // 使用匿名内部类,发送数据请求兴趣包 - face.expressInterest(interest, new OnData() { - @Override - public void onData(Interest interest, Data data) { - // 解析文件名、分片编号 - String filePathString = localDir; - Integer sliceSizeInteger = mainApp.sliceSize; - String filenameString = localName; - Integer sliceNoInteger = null; - try { - JSONObject jsonObject = new JSONObject(orderInfo.getJsonString()); - sliceNoInteger = jsonObject.getInt("sliceNo"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 写入本地文件 - Integer successInfoInteger = 1; - try { - System.out.println("开始写入文件数据分片... :" + filePathString + filenameString); - RandomAccessFile randomAccessFile = new RandomAccessFile(filePathString + filenameString, "rw"); - int contentSize = data.getContent().size(); - System.out.println("该数据分片长度为:" + contentSize); - byte[] content = new byte[contentSize]; - for (int i = 0; i < contentSize; i++) { - content[i] = data.getContent().buf().get(i); - } - // 设置数据分片写入到文件的起点位置 - randomAccessFile.seek(sliceNoInteger * sliceSizeInteger); - // 写入数据分片 - randomAccessFile.write(content, 0, contentSize); - randomAccessFile.close(); - System.out.println("写入文件数据分片完毕:" + filePathString + filenameString); - successInfoInteger = 0; - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 返回成功写入或失败写入消息 - responseData.setResponseData(successInfoInteger.toString()); - dataCacheQueue.setResponseData(orderInfo.getSeq(), responseData); - } - }); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - //下载文件的数据分片到默认路径 - private void expressTheDownloadInterest(String orderPrefix, Interest interest, OrderInfo orderInfo) { - // 设置回执前缀 - ResponseData responseData = new ResponseData(); - responseData.setPrefix(orderPrefix); - try { - // 使用匿名内部类,发送数据请求兴趣包 - face.expressInterest(interest, new OnData() { - @Override - public void onData(Interest interest, Data data) { - // 解析文件名、分片编号 - String filePathString = mainApp.fileLocalPath; - Integer sliceSizeInteger = mainApp.sliceSize; - String filenameString = null; - Integer sliceNoInteger = null; - try { - JSONObject jsonObject = new JSONObject(orderInfo.getJsonString()); - filenameString = getPureFileName(jsonObject.getString("filename")); - sliceNoInteger = jsonObject.getInt("sliceNo"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 写入本地文件 - Integer successInfoInteger = 1; - try { - System.out.println("开始写入文件数据分片... :" + filePathString + filenameString); - RandomAccessFile randomAccessFile = new RandomAccessFile(filePathString + filenameString, "rw"); - int contentSize = data.getContent().size(); - System.out.println("该数据分片长度为:" + contentSize); - byte[] content = new byte[contentSize]; - for (int i = 0; i < contentSize; i++) { - content[i] = data.getContent().buf().get(i); - } - // 设置数据分片写入到文件的起点位置 - randomAccessFile.seek(sliceNoInteger * sliceSizeInteger); - // 写入数据分片 - randomAccessFile.write(content, 0, contentSize); - randomAccessFile.close(); - System.out.println("写入文件数据分片完毕:" + filePathString + filenameString); - successInfoInteger = 0; - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 返回成功写入或失败写入消息 - responseData.setResponseData(successInfoInteger.toString()); - dataCacheQueue.setResponseData(orderInfo.getSeq(), responseData); - } - }); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } private void expressTheInterest(String orderPrefix, Interest interest, Long dataReqId) { ResponseData responseData = new ResponseData(); responseData.setPrefix(orderPrefix); + HandleInterestTimeOutAndNack handleInterestTimeOutAndNack = + new HandleInterestTimeOutAndNack(orderPrefix, interest, dataReqId); try { // 使用匿名内部类,发送数据请求兴趣包 - if(orderPrefix.equals("/getDataSlice")) { + if (orderPrefix.equals("/getDataSlice")) { //接收数据块 face.expressInterest(interest, new OnData() { @Override @@ -886,15 +469,19 @@ public class MinoaDataAPI { byte[] content = new byte[contentSize]; for (int i = 0; i < contentSize; i++) { content[i] = data.getContent().buf().get(i); - System.out.print(i+": "+content[i]+" "); + System.out.print(i + ": " + content[i] + " "); } System.out.println(""); - System.out.println("notice content: "+content); + System.out.println("notice content: " + content); responseData.setFileSlice(content); dataCacheQueue.setResponseData(dataReqId, responseData); + // 重置其超时次数记录 + if (timeOutNums.containsKey(dataReqId)) { + timeOutNums.remove(dataReqId); + } } - }); - }else { + }, handleInterestTimeOutAndNack, handleInterestTimeOutAndNack); + } else { face.expressInterest(interest, new OnData() { @Override public void onData(Interest interest, Data data) { @@ -904,8 +491,12 @@ public class MinoaDataAPI { // System.out.println("ondata data: "+data.getContent().toString()); responseData.setResponseData(data.getContent().toString()); dataCacheQueue.setResponseData(dataReqId, responseData); + // 重置其超时次数记录 + if (timeOutNums.containsKey(dataReqId)) { + timeOutNums.remove(dataReqId); + } } - }); + }, handleInterestTimeOutAndNack, handleInterestTimeOutAndNack); } } catch (IOException e) { // TODO Auto-generated catch block @@ -913,15 +504,8 @@ public class MinoaDataAPI { } } - // 写头像 -// public Integer writeHeadPhotoIntoLocalFile(String filenameString, -// Integer sliceNo,Integer sliceSize,byte[] bytes) { -// String pathString=mainApp.fileLocalPath; -// return writeIntoLocalFile(pathString, filenameString, sliceNo, sliceSize, bytes); -// } - // 根据包含路径的文件名获取纯文件名[linux下] - public String getPureFileName(String pathfilename) { + public static String getPureFileName(String pathfilename) { // 标记最后一个/的下标 int indexLeft = -1; for (int i = 0; i < pathfilename.length(); i++) { @@ -939,7 +523,7 @@ public class MinoaDataAPI { } // 根据包含路径的文件名获取纯文件名[windows本地] - public String getPureFileNameFromWindows(String pathfilename) { + public static String getPureFileNameFromWindows(String pathfilename) { // 标记最后一个/的下标 int indexLeft = -1; for (int i = 0; i < pathfilename.length(); i++) { @@ -955,21 +539,91 @@ public class MinoaDataAPI { return pathfilename.substring(indexLeft + 1, pathfilename.length()); } } -// // 向指定本地文件写入指定数据分片=》被ondata调用 -// public Integer writeIntoLocalFile(String pathString,String filenameString, -// Integer sliceNo,Integer sliceSize,byte[] bytes) { -// try { -// @SuppressWarnings("resource") -// RandomAccessFile randomAccessFile=new RandomAccessFile(pathString+filenameString, "rw"); -// int contentSize= -// randomAccessFile.write(bytes,sliceNo*sliceSize,bytes.length); -// return 0; -// } catch (IOException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// return 1; -// } -// } + + // 解决处理兴趣包超时之后的重传问题[除上传下载外的兴趣包] + public class HandleInterestTimeOutAndNack implements OnTimeout, OnNetworkNack { + // 命令前缀 + private String orderPrefix; + // 兴趣包 + private Interest interest; + // 请求序列号 + private Long dataReqId; + // 标记是否拿到网络回复(数据信息/超时信息):测试使用 + public boolean isFinished = false; + + public HandleInterestTimeOutAndNack(String orderPrefix, Interest interest, Long dataReqId) { + this.orderPrefix = orderPrefix; + this.interest = interest; + this.interest.setInterestLifetimeMilliseconds(2000); + this.dataReqId = dataReqId; + } + + // 处理兴趣包超时 + @Override + public void onTimeout(Interest interest) { + // 打印超时信息 + System.out.println("########## Time out for interest " + interest.getName() + "###########"); + // 记录此次丢包/超时 + if (timeOutNums.containsKey(this.dataReqId)) { + int value = timeOutNums.get(this.dataReqId) + 1; + timeOutNums.put(this.dataReqId, value); + } else { + timeOutNums.put(this.dataReqId, 1); + } + // 根据是否多次超时,决定是否重传该兴趣包:暂时是全部重传 + // 后期可以改作,超时次数超过阈值时候, + // 自拟定一个指定值放入数据回复缓存区,前端控制类收到该值,就 + // 判定网络极其拥塞,进行弹窗提示。 + if (!isInterestTimeOut(this.dataReqId)) { + // 超时次数没有超过阈值:重传该兴趣包 + expressTheInterest(this.orderPrefix, this.interest, this.dataReqId); + } else { + // 超时次数超过阈值 + System.out.println("该兴趣包的超时次数超过阈值:" + timeoutCeil + "!!!"); + // 返回一个timeout信息放入datacache + ResponseData responseData = new ResponseData(); + responseData.setPrefix(this.orderPrefix); + responseData.setResponseData(getWrongAnswerJson(timeoutCodeInteger, timeoutError)); + dataCacheQueue.setResponseData(this.dataReqId, responseData); + } + // 打印重传信息 + System.out.println("########## Resend the interest " + interest.getName() + "###########"); + // 处理完成 + isFinished = true; + } + + // 处理收到一个Nack包 + @Override + public void onNetworkNack(Interest interest, NetworkNack networkNack) { + // 打印超时信息 + System.out.println("########## Nack for interest " + interest.getName() + + ", Nack: " + networkNack.toString()); + // 返回一个nack信息放入datacache + ResponseData responseData = new ResponseData(); + responseData.setPrefix(this.orderPrefix); + responseData.setResponseData(getWrongAnswerJson(nackCodeInteger, nackError)); + dataCacheQueue.setResponseData(this.dataReqId,responseData); + isFinished = true; + } + } + + // 构造一个json,给前端返回一个可以进行JSON解析的错误信息 + // 用以避免界面卡死 + public static String getWrongAnswerJson(Integer wrongAnswerCode, String wrongAnswerString) { + JSONObject jsonObject = new JSONObject(); + Integer code = wrongAnswerCode; + String errMsg = wrongAnswerString; + String data = ""; + try { + jsonObject.put("code", code); + jsonObject.put("errMsg", errMsg); + jsonObject.put("data", data); + } catch (Exception e) { + // TODO: handle exception + System.out.println("exception: " + e.getMessage()); + } + return jsonObject.toString(); + } // 关闭数据连接 public void closeDataConn() { diff --git a/src/main/java/cn/minoa/dataRequestInterface/OrderInfo.java b/src/main/java/cn/minoa/dataRequestInterface/OrderInfo.java index 737ab73..14e4928 100644 --- a/src/main/java/cn/minoa/dataRequestInterface/OrderInfo.java +++ b/src/main/java/cn/minoa/dataRequestInterface/OrderInfo.java @@ -1,5 +1,6 @@ package cn.minoa.dataRequestInterface; +import cn.minoa.MainApp; import org.json.JSONObject; //请求数据时的附加请求信息 @@ -19,6 +20,17 @@ public class OrderInfo { public void setSeq(Long seqLong) { this.seqLong=seqLong; + // 查看是否连接正常,否,重新尝试连接; + // 重新连接失败,默认是ip有问题,返回一个错误包 + if(!MainApp.isFaceLinked()){ + System.out.println("!!!face link error!!!"); + ResponseData responseData=new ResponseData(); + String wrongAnswer=MinoaDataAPI.getWrongAnswerJson(336, + "face link error"); + responseData.setPrefix("/wrongAnswer"); + responseData.setResponseData(wrongAnswer); + MainApp.minoaDataAPI.dataCacheQueue.setResponseData(seqLong,responseData); + } } public Long getSeq() { diff --git a/src/main/java/cn/minoa/dataRequestInterface/UpLoadClientBasedFacePool.java b/src/main/java/cn/minoa/dataRequestInterface/UpLoadClientBasedFacePool.java new file mode 100644 index 0000000..d9f42fa --- /dev/null +++ b/src/main/java/cn/minoa/dataRequestInterface/UpLoadClientBasedFacePool.java @@ -0,0 +1,396 @@ +package cn.minoa.dataRequestInterface; + +import cn.minoa.MainApp; +import cn.minoa.util.StringByteLengthUtil; +import net.named_data.jndn.*; +import net.named_data.jndn.security.KeyChain; +import net.named_data.jndn.security.SecurityException; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.util.Blob; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author mac + * @description + * @date 2020-03-22 18:28 + */ +public class UpLoadClientBasedFacePool { + + private String orderPrefix = "/uploadFile"; + + private String serverPath; + + private File file; + //总数据片大小 + private Long sliceNumbers; + + private Long currentOffset = 0L; + + private CongestionWindow congestionWindow = new CongestionWindow(); + + private FacePool facePool; + + // 要上传的本地文件对象 + private RandomAccessFile randomAccessFile; + + //发送失败,需要重新发送的数据。key:第几个数据片,从0开始计数,value:文件偏移 +// private Map failedSlice = new ConcurrentHashMap<>(); + //存放发送失败数据的文件偏移 + private ConcurrentLinkedQueue failedSlice = new ConcurrentLinkedQueue<>(); + + //发送的数据是否发送成功,key:第几个数据片,从0开始,value:是否发送成功 + private Map sendRes = new ConcurrentHashMap<>(); + + //收到回复的数量 + public AtomicLong recvCount = new AtomicLong(0); + + //发送的数据是否发送成功,key:第几个数据片,从0开始,value:该数据片超时次数 + private Map timeOutNums = new ConcurrentHashMap<>(); + // 超时重传上限数值,某个兴趣包的重传次数超过此数值,则放弃重传,直接返回false + private Integer timeoutCeil=15; + + public UpLoadClientBasedFacePool(File file, String serverPath, Integer facepoolnumber){ + this.file = file; + this.serverPath = serverPath; + this.facePool=new FacePool(facepoolnumber); + this.facePool.start(MinoaDataAPI.minoaServerIpString, MinoaDataAPI.minoaServerPortInteger); + System.out.println("***********FacePool中并发数:"+facepoolnumber+"***********"); + } + + /** + * 判断是否含有超时次数超过阈值的 + * @return + */ + private boolean isTimeOut(){ + for (Map.Entry entry : timeOutNums.entrySet()) { + System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); + if(entry.getValue() > timeoutCeil){ + return true; + } + } + return false; + } + + /** + * 上传数据的主函数 + * @return + */ + public boolean uploadData(){ + // 先初始化一个本地文件 + try { + this.randomAccessFile = new RandomAccessFile(this.file.getAbsolutePath(), "rw"); + System.out.println("本地文件打开"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + if(file.length()% MainApp.sliceSize == 0){ + sliceNumbers = file.length()/ MainApp.sliceSize; + }else{ + sliceNumbers = file.length()/ MainApp.sliceSize + 1; + } + + while(true){ + //判断是否已经上传安成 + if(sliceNumbers <= recvCount.longValue()){ + break; + } + + // 判断是否已经被用户终止上传 + if(MainApp.isCancelFileTransferFlag){ + System.out.println("用户已主动中断上传"); + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + //每一次发送数据 + int cwnd = 0; + //获取此次可以发送数据的个数 + while((cwnd = congestionWindow.getAvailableCwnd()) <= 0){ + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + for(int i=0; i 0){ + //首先发送failedslice中的数据 + Long failOffset = failedSlice.poll(); + System.out.println("发送数据, name: " + file.getName() +",offset:" + currentOffset + ", failedSlice:" + failedSlice.size() ); + sendData(failOffset); + }else{ + if(currentOffset < file.length()){ + System.out.println("发送数据, name: " + file.getName() +",offset:" + currentOffset + ", failedSlice:" + failedSlice.size() ); + sendData(currentOffset); + currentOffset += MainApp.sliceSize; + } + } + congestionWindow.inFlightIncrease(); + congestionWindow.nOutInterestIncrease(); + + } + + if(isTimeOut()){ + System.out.println("丢包超过阈值: "+timeoutCeil+" ,文件传输主动中断"); + this.facePool.shutdownNow(); + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + } + + try { + this.randomAccessFile.close(); + System.out.println("本地文件关闭"); + } catch (IOException e) { + e.printStackTrace(); + } + this.facePool.shutdownNow(); + return true; + } + + /** + * 发送一个数据片 + * @param offset + */ + private void sendData(Long offset){ + facePool.submit(freeface -> { + OrderInfo orderInfo = new OrderInfo(); + Long seqLong = MainApp.getNewDataReqId(); + orderInfo.setSeq(seqLong); + String testStr = DownAndUpLoadData.getUploadFile(file.getAbsolutePath(), offset); + //System.out.println("*******************:" + testStr + "*******************"); + orderInfo.setJsonString(testStr); + + // 获取json格式的数据请求字符串 + //String requestStr = MinoaDataAPI.getRequestStr(orderPrefix, orderInfo); + + // 发送数据兴趣包 + Name name = new Name(MinoaDataAPI.globalPrefixString + orderPrefix + "/" + seqLong); + Interest interest = new Interest(name); + interest.setMustBeFresh(true); + try { + ResponseData responseData = new ResponseData(); + responseData.setPrefix(orderPrefix); + byte[] requestByte = null; // 请求数据 + // 重写ondata + try { + // 解析并修改文件名【window转server】 + String localFilePath = ""; + String serverFilePath = ""; + try { + // 解析 + JSONObject jsonObject = new JSONObject(orderInfo.getJsonString()); + localFilePath = jsonObject.getString("filename"); +// serverFilePath = serverpath + getPureFileNameFromWindows(localFilePath); + serverFilePath = serverPath + MinoaDataAPI.getPureFileNameFromWindows(localFilePath); + // 修改 + jsonObject.remove("filename"); + jsonObject.put("filename", serverFilePath); + orderInfo.setJsonString(jsonObject.toString()); + System.out.println("request head str: " + orderInfo.getJsonString()); + System.out.println("head str length: " + orderInfo.getJsonString().length()); + System.out.println("head str byte length: " + StringByteLengthUtil.getByteLength(orderInfo.getJsonString())); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // 从本地读取数据 + byte[] content = new byte[10000]; // 文件分片内容 + try { + synchronized (randomAccessFile) { +// RandomAccessFile randomAccessFile = new RandomAccessFile(localFilePath, "rw"); + // 设置文件的读取起点 + randomAccessFile.seek(offset); + // 尝试读取数据 + int readLen = randomAccessFile.read(content, 0, 7000); + int jsonLen = StringByteLengthUtil.getByteLength(orderInfo.getJsonString()); + requestByte = new byte[jsonLen + 1 + readLen]; + System.arraycopy(orderInfo.getJsonString().getBytes("utf-8"), 0, requestByte, 0, jsonLen); + requestByte[jsonLen] = 0; + System.arraycopy(content, 0, requestByte, jsonLen + 1, readLen); +// randomAccessFile.close(); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // 赋值兴趣包的附带信息,并标志区块链 + interest.setApplicationParameters(new Blob(requestByte)); + //超时 + interest.setInterestLifetimeMilliseconds(5000); + // 密钥“黑盒” + try { +// MinoaDataAPI.keyChain.sign(interest); + KeyManager.INSTANCE.getKeyChain().sign(interest); + } catch (PibImpl.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyChain.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (net.named_data.jndn.security.tpm.TpmBackEnd.Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + UpLoadData upLoadData = new UpLoadData(orderInfo.getSeq(), responseData, offset / MainApp.sliceSize); + UpLoadTimeout upLoadTimeout = new UpLoadTimeout(upLoadData); + UpLoadOnNetWorkNack upLoadOnNetWorkNack = new UpLoadOnNetWorkNack(upLoadData); + // 使用tcp发送数据请求兴趣包 +// MinoaDataAPI.runFace(); + freeface.expressInterest(interest, upLoadData, upLoadTimeout, upLoadOnNetWorkNack); + + + } catch (IOException e) { + e.printStackTrace(); + } + + } catch (Exception e) { + System.out.println("exception: " + e.getMessage()); + e.printStackTrace(); + } + }); + } + + + public class UpLoadData implements OnData { + + private Long seq; + private ResponseData responseData; + //第几个数据片 + public Long sliceNum; + + public boolean isFinished = false; + + public UpLoadData(Long seq, ResponseData responseData, Long sliceNum){ + this.seq = seq; + this.responseData = responseData; + this.sliceNum = sliceNum; + } + + @Override + public void onData(Interest interest, Data data){ + responseData.setResponseData(data.getContent().toString()); + JSONObject jsonObject = responseData.praseRequestData(); + + congestionWindow.inFlightDecrease(); + // 解析数据,是否成功上传 + Integer codeInteger = null; + try { + codeInteger = jsonObject.getInt("code"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (codeInteger == 200) { + recvCount.incrementAndGet(); + congestionWindow.cwndIncrease(); + System.out.println("第" + sliceNum + "片上传成功!"); + }else{ + failedSlice.add(sliceNum* MainApp.sliceSize); + System.out.println("第" + sliceNum + "片上传失败!"); + } + //拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可 + if(data.getCongestionMark() > 0){ + System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark()); + congestionWindow.cwndDecrease(); + }else{ + //如果没有检测到拥塞,则增加窗口 + congestionWindow.nIndataIncrease(); + } + + if(timeOutNums.containsKey(sliceNum)){ + timeOutNums.remove(sliceNum); + } + + isFinished = true; + + } + public int callbackCount = 0 ; + + } + + public class UpLoadTimeout implements OnTimeout { + + + + private UpLoadData upLoadData; + public int callbackCount = 0 ; + + public UpLoadTimeout(UpLoadData upLoadData) { + this.upLoadData = upLoadData; + } + + @Override + public void onTimeout(Interest interest){ + congestionWindow.inFlightDecrease(); + failedSlice.add(upLoadData.sliceNum* MainApp.sliceSize); + callbackCount ++ ; + System.out.println("Time out for interest " + interest.getName()); + upLoadData.isFinished = false; + + // + if(timeOutNums.containsKey(upLoadData.sliceNum)){ + int value = timeOutNums.get(upLoadData.sliceNum) + 1; + timeOutNums.put(upLoadData.sliceNum,value); + }else{ + timeOutNums.put(upLoadData.sliceNum,1); + } + } + } + + public class UpLoadOnNetWorkNack implements OnNetworkNack { + + private UpLoadData upLoadData; + public int callbackCount = 0 ; + + public UpLoadOnNetWorkNack(UpLoadData upLoadData) { + this.upLoadData = upLoadData; + } + + @Override + public void onNetworkNack(Interest var1, NetworkNack var2){ + congestionWindow.inFlightDecrease(); + failedSlice.add(upLoadData.sliceNum* MainApp.sliceSize); + // + if(timeOutNums.containsKey(upLoadData.sliceNum)){ + int value = timeOutNums.get(upLoadData.sliceNum) + 1; + timeOutNums.put(upLoadData.sliceNum,value); + }else{ + timeOutNums.put(upLoadData.sliceNum,1); + } + callbackCount ++ ; + System.out.println("onNetworkNack " + var1.getName()); + upLoadData.isFinished = true; + } + + } + + +} diff --git a/src/main/java/cn/minoa/dataRequestInterface/creatNDNKey.java b/src/main/java/cn/minoa/dataRequestInterface/creatNDNKey.java deleted file mode 100644 index 496c2aa..0000000 --- a/src/main/java/cn/minoa/dataRequestInterface/creatNDNKey.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.minoa.dataRequestInterface; - -import net.named_data.jndn.*; -import net.named_data.jndn.security.KeyChain; - -import net.named_data.jndn.security.pib.PibIdentity; -import net.named_data.jndn.security.pib.PibSqlite3; -import net.named_data.jndn.security.tpm.TpmBackEndMemory; -//import net.named_data.jndn.util.Blob; -//import org.json.JSONObject; - -//生成密钥 -public class creatNDNKey { - static private String pidDbPathString=""; -// static private String pidDbPathString="E:\\MyCode\\newEclipseWorkspace\\minoa_client_windows_JavaFX11"; - static private String keyChainNameString="/wefree"; - static private String pidIdentityString="wefree"; - - public static void main(String args[]){ - KeyChain keyChain ; - try{ - //密钥“黑盒” - PibSqlite3 pibSqlite3 = new PibSqlite3(pidDbPathString); - TpmBackEndMemory tpmBackEndMemory = new TpmBackEndMemory() ; - keyChain = new KeyChain(pibSqlite3,tpmBackEndMemory ) ; - keyChain.createIdentityV2(new Name(keyChainNameString)) ; - PibIdentity identity = keyChain.getPib().getIdentity(new Name(pidIdentityString)); ; - keyChain.setDefaultIdentity(identity); - //输出测试 - System.out.println(keyChain.getDefaultCertificateName().toUri()); - System.out.println(keyChain.getPib().getPibLocator()); - }catch (Exception e){ - System.out.println("exception: " + e.getMessage()); - } - } -} diff --git a/src/main/java/cn/minoa/dataRequestInterface/registerUser.java b/src/main/java/cn/minoa/dataRequestInterface/registerUser.java deleted file mode 100644 index a995839..0000000 --- a/src/main/java/cn/minoa/dataRequestInterface/registerUser.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.minoa.dataRequestInterface; -// 在注册的界面未完成之前用于注册新用户 - -import org.json.JSONObject; - -public class registerUser { - // 获取注册请求字符串 - @SuppressWarnings("unused") - static private String getRegisterJson() { - JSONObject jsonObject = new JSONObject(); - String mPubKey = "Bv0CsQcuCAR3Z2gwCANLRVkICH9+4yjVUHZaCAxjZXJ0LXJlcXVlc3QICf0AAAFv\nEUSBehQJGAECGQQANu6AFf0BJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBANbFutCAZqFjHEa16tYvy4lBgi9/zixKWQzE9I72vaG2Imym+6KR30qkAQOK\nh0uE5RD2YsGhRK99rde+JOqIfk2/sunhp4nctOS5f4DeuOty58ekrO+Co9ZFmNBI\nmyk5i/hakjBEd/vdD7b1VadDRep5mWs3rgCinZOUfVaZ4oKqSws7ZWMvOSlRMOOi\nVzj53P4poY109S6aWmi3xKw/D76vfJapjdOB9Dg7S3rz0Rve1F/ajHCXWLt4XU3k\nUCiBn3Qmt6UD/MyDBaaUCfOvHTN6yVPtN6aOtYJVBAWt/P1ahLYhWkSm6KvrwMt0\nRzy2lw/lPriT99REItc/0wK6XwkCAwEAARZGGwEBHBcHFQgEd2doMAgDS0VZCAh/\nfuMo1VB2Wv0A/Sb9AP4PMjAxOTEyMTdUMDAzMTQw/QD/DzIwMTkxMjI3VDAwMzEz\nORf9AQCM+8WROXfi8WD9DydfLuSUxV0v3KW/Gn422/puDrkwwi1R2ogsAUc2O8pp\npuMLjWrQOTgE6ZTg80uWoDSUjjk44aMjkL2SAfp62vHRbGFx7+dckHAtF+DS6NH7\nX2vojFHOg6fksOE1M7XqLHmEEctZrFVSnQO7nB3DfRg+BqzZC/iy+8YAvTIvqA1c\nNsKYkmNITB80aM1v2H7fKnV4ZJpZnW71G5vbaPUseeklalQ2vEuBgWdd/1PL/0Ml\nI52npzqoeKAEpLp+vBwGN5ryGtWKB12nNimpMfevQAn/9BVIg59lZ7DIlE0sWmgW\nnwDxIXKebdViOejHlKwNAykxRRWw"; - String commandString = "/register"; - String userNameString = "oa_wefree"; - String passWordString = "12345678"; - String phoneString = "10000000006"; - Integer levelInteger = 0; - try { - jsonObject.put("command", commandString); - jsonObject.put("username", userNameString); - jsonObject.put("password", passWordString); - jsonObject.put("phone", phoneString); - jsonObject.put("publicKey", mPubKey); - jsonObject.put("level", levelInteger); - } catch (Exception e) { - System.out.println("exception: " + e.getMessage()); - } - return jsonObject.toString(); - } -} diff --git a/src/main/java/cn/minoa/model/SingleFile.java b/src/main/java/cn/minoa/model/SingleFile.java new file mode 100644 index 0000000..a70e688 --- /dev/null +++ b/src/main/java/cn/minoa/model/SingleFile.java @@ -0,0 +1,73 @@ +package cn.minoa.model; +// 存储一个file或一个文件夹的属性 + +public class SingleFile { + //文件名 + private String filename; + //文件路径 + private String filepath; + //文件ID + private String fileId; + //文件创建时间 + private Long time; + //文件类型 + private String type; + //文件大小 + private Long size; + + public SingleFile(){ + } + + public SingleFile(String fileId){ + this.fileId=fileId; + } +// public SingleFile(){} + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFilepath() { + return filepath; + } + + public void setFilepath(String filepath) { + this.filepath = filepath; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } +} diff --git a/src/main/java/cn/minoa/util/EncryptionUtil.java b/src/main/java/cn/minoa/util/EncryptionUtil.java new file mode 100644 index 0000000..7da9835 --- /dev/null +++ b/src/main/java/cn/minoa/util/EncryptionUtil.java @@ -0,0 +1,139 @@ +package cn.minoa.util; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +public class EncryptionUtil { + + public static String getMD5String(String str) { + try { + // 生成一个MD5加密计算摘要 + MessageDigest md = MessageDigest.getInstance("MD5"); + // 计算md5函数 + md.update(str.getBytes("utf-8")); + // digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符 + // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值 + //一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方) + String res = new BigInteger(1, md.digest()).toString(16); + System.out.println(str + " MD5加密结果: " + res); + return res; + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + public static String encryptBasedAES(String content) { + byte[] encrypt=encryptBasedAES(content,"123"); + return ParseSystemUtil.parseByte2HexStr(encrypt); + } + +// public static byte[] encryptBasedAES(String content) { +// return encryptBasedAES(content, "123"); +// } + + /** + * AES加密字符串 + * + * @param content 需要被加密的字符串 + * @param password 加密需要的密码 + * @return 密文 + */ + public static byte[] encryptBasedAES(String content, String password) { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者 +// kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出 + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(password.getBytes("utf-8")); + kgen.init(128, secureRandom); + //加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行 + SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥 + byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回 + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥 + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + byte[] byteContent = content.getBytes("utf-8"); + cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器 + byte[] result = cipher.doFinal(byteContent);// 加密 + return result; + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + public static String decryptBasedAES(String hexStr) { + byte[] byte2 = ParseSystemUtil.parseHexStr2Byte(hexStr); + try { + return new String(decryptBasedAES(byte2, "123")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + +// public static byte[] decryptBasedAES(byte[] content) { +// return decryptBasedAES(content, "123"); +// } + + /** + * 解密AES加密过的字符串 + * + * @param content AES加密过过的内容 + * @param password 加密时的密码 + * @return 明文 + */ + public static byte[] decryptBasedAES(byte[] content, String password) throws UnsupportedEncodingException { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者 +// kgen.init(128, new SecureRandom(password.getBytes())); + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(password.getBytes("utf-8")); + kgen.init(128, secureRandom); + SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥 + byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥 + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥 + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器 + byte[] result = cipher.doFinal(content); + return result; // 明文 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + // 测试主函数 +// public static void main(String[] args) throws Exception { +// String content = "哈哈哈"; +// System.out.println("需要加密的内容:" + content); +// String enc=encryptBasedAES(content); +// System.out.println("加密后的16进制密文:" + enc); +// String dec=decryptBasedAES(enc); +// System.out.println("解密后的内容:" + dec); +// } + +} diff --git a/src/main/java/cn/minoa/util/FileUtil.java b/src/main/java/cn/minoa/util/FileUtil.java new file mode 100644 index 0000000..acea801 --- /dev/null +++ b/src/main/java/cn/minoa/util/FileUtil.java @@ -0,0 +1,47 @@ +package cn.minoa.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class FileUtil { + + /** + * 格式化时间 + * @param format 格式化格式,基础格式为yyyy-MM-dd HH:mm:ss + * @param time 精确到ms + * @return + */ + public static String formatTime(String format, long time) + { + SimpleDateFormat df = new SimpleDateFormat(format); + return df.format(new Date(time)); + } + + // 后台返回的Long类型时间戳(精确到s)转日期 + public static String timeToDateString(Long time){ + String timeString = formatTime("yyyy-MM-dd HH:mm:ss", time*1000); + System.out.println(timeString); + return timeString; + } + + // 文件大小根据具体大小,转成B/KB/M/G/T + public static String sizeToShowSize(Long size){ + if(size<1024){ + return size+" B"; + } + Double sizeKB=size/1024.0; + if(sizeKB<1024){ + return String.format("%.3f",sizeKB)+" KB"; + } + Double sizeM=sizeKB/1024.0; + if(sizeM<1024){ + return String.format("%.3f",sizeM)+" M"; + } + Double sizeG=sizeM/1024.0; + if(sizeG<1024){ + return String.format("%.3f",sizeG)+" G"; + } + Double sizeT=sizeG/1024.0; + return String.format("%.3f",sizeT)+" T"; + } +} diff --git a/src/main/java/cn/minoa/util/KeyStorageUtil.java b/src/main/java/cn/minoa/util/KeyStorageUtil.java new file mode 100644 index 0000000..64d5ed8 --- /dev/null +++ b/src/main/java/cn/minoa/util/KeyStorageUtil.java @@ -0,0 +1,76 @@ +package cn.minoa.util; + +import cn.minoa.MainApp; + +import java.io.*; +import java.util.Properties; + +public class KeyStorageUtil { + + // 存数据 + public static void setKeyName(String keyName){ + InputStream inputStream = null; + OutputStream outputStream=null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream=new BufferedInputStream(new FileInputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + settingProperties.setProperty("KeyName", keyName); + outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + settingProperties.store(outputStream,"修改配置文件"); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //关闭输出流 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + // 取数据 + public static String getKeyName() { + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(MainApp.getClientPath() + File.separator + "ndn" + File.separator + "settings.properties")); +// inputStream = MainApp.class.getClassLoader().getResourceAsStream("/ndn/settings.properties"); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + String keyName = settingProperties.getProperty("KeyName"); + return keyName; + } catch (IOException e) { + e.printStackTrace(); + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + +} diff --git a/src/main/java/cn/minoa/util/LocalDateAdapter.java b/src/main/java/cn/minoa/util/LocalDateAdapter.java deleted file mode 100644 index 6876b2b..0000000 --- a/src/main/java/cn/minoa/util/LocalDateAdapter.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.minoa.util; - -//import java.time.LocalDate; -//import javax.xml.bind.annotation.adapters.XmlAdapter; - -//使得JAXB可以转换日期到XML -//public class LocalDateAdapter extends XmlAdapter { -// -// public LocalDate unmarshal(String v) throws Exception{ -// return LocalDate.parse(v); -// } -// -// public String marshal(LocalDate v) throws Exception{ -// return v.toString(); -// } -//} diff --git a/src/main/java/cn/minoa/util/LoggerUtil.java b/src/main/java/cn/minoa/util/LoggerUtil.java new file mode 100644 index 0000000..4be32aa --- /dev/null +++ b/src/main/java/cn/minoa/util/LoggerUtil.java @@ -0,0 +1,32 @@ +package cn.minoa.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; + +public class LoggerUtil { + + // 将文件名、文件操作、传输耗时等信息写入日志. + public static void insertFileAction(String filename, String fileaction, String usedtime) { + try { + File file = new File("./ndn/log.txt"); + FileOutputStream fos = null; + if (!file.exists()) { + file.createNewFile();//如果文件不存在,就创建该文件 + fos = new FileOutputStream(file);//首次写入获取 + } else { + //如果文件已存在,那么就在文件末尾追加写入 + fos = new FileOutputStream(file, true);//这里构造方法多了一个参数true,表示在文件末尾追加写入 + } + + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");//指定以UTF-8格式写入文件 + osw.write("文件名:"+filename+" 文件操作:"+fileaction+" 文件耗时:"+usedtime); + osw.write("\r\n"); + //写入完成关闭流 + osw.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/cn/minoa/util/ParseSystemUtil.java b/src/main/java/cn/minoa/util/ParseSystemUtil.java new file mode 100644 index 0000000..c398c85 --- /dev/null +++ b/src/main/java/cn/minoa/util/ParseSystemUtil.java @@ -0,0 +1,39 @@ +package cn.minoa.util; + +/** + * 进制转换工具类 + */ +public class ParseSystemUtil { + + /**将二进制转换成16进制 + * @param buf + * @return + */ + public static String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /**将16进制转换为二进制 + * @param hexStr + * @return + */ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) + return null; + byte[] result = new byte[hexStr.length()/2]; + for (int i = 0;i< hexStr.length()/2; i++) { + int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); + int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/cn/minoa/util/SecretKeyManageUtil.java b/src/main/java/cn/minoa/util/SecretKeyManageUtil.java new file mode 100644 index 0000000..e64a2ae --- /dev/null +++ b/src/main/java/cn/minoa/util/SecretKeyManageUtil.java @@ -0,0 +1,207 @@ +package cn.minoa.util; + +import cn.minoa.dataRequestInterface.KeyManager; +import cn.minoa.dataRequestInterface.MinoaDataAPI; +import net.named_data.jndn.encoding.EncodingException; +import net.named_data.jndn.security.KeyChain; +import net.named_data.jndn.security.SafeBag; +import net.named_data.jndn.security.pib.Pib; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.security.tpm.TpmBackEnd; +import net.named_data.jndn.security.v2.CertificateV2; +import net.named_data.jndn.util.Blob; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +public class SecretKeyManageUtil { + + // 导出密钥 + public static boolean exportSafeBag(String filepathname) { + try { + // 得到指定identity的证书(包含秘钥信息) + CertificateV2 certificateV2 = KeyManager.INSTANCE + .getCertification(MinoaDataAPI.keyChainNameString); + + // 通过KeyChain导出SafeBag + // exportSafeBag支持设置密码 + SafeBag safeBag = KeyManager.INSTANCE + .getKeyChain().exportSafeBag(certificateV2); + + // 将safeBag进行编码 + Blob blob = safeBag.wireEncode(); + + // 接着就可以将编码后的数据写入到一个文件当中 + writeByteToFile(blob.getImmutableArray(), blob.size(),filepathname); + return true; + }catch (PibImpl.Error | Pib.Error | KeyChain.Error e){ + e.printStackTrace(); + System.out.println(e.getMessage()); + return false; + } + } + + // 导入密钥 + public static String importSafeBag(String filepathname) { + try { + System.out.println("密钥文件:"+filepathname); + // 读取文件,得到字节数组, +// ByteBuffer bb = readByteBuffFromFile(filepathname); + byte[] b=readByteFromFile(filepathname); + + if (b == null) { + return "The read file is empty."; + } + Blob blob=new Blob(b); + // 使用SafeBag的其中一种构造方法 + SafeBag safeBag = new SafeBag(blob); + + String name=safeBag.getCertificate().getName().toString(); + System.out.println("导入文件的证书名称:"+name); + + // 然后用KeyChain导入 + // 如果exportSafeBag时设置了密码,importSafeBag的时候也要传入密码 + KeyManager.INSTANCE + .getKeyChain() + .importSafeBag(safeBag); + return "success"; + } catch (EncodingException | Pib.Error | TpmBackEnd.Error | + KeyChain.Error | PibImpl.Error | CertificateV2.Error | IOException e) { +// e.printStackTrace(); + System.out.println(e.getMessage()); + return e.getMessage(); + } + } + + public static ByteBuffer encodeValue(byte[] value) { + ByteBuffer byteBuffer = ByteBuffer.allocate(value.length); + byteBuffer.clear(); + byteBuffer.get(value, 0, value.length); + return byteBuffer; + } + + // 读取文件到一个byte + public static byte[] readByteFromFile(String filepathname) throws IOException { + File f = new File(filepathname); + if (!f.exists()) { + return null; + } + + FileChannel channel = null; + FileInputStream fs = null; + try { + fs = new FileInputStream(f); + channel = fs.getChannel(); + ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size()); + while ((channel.read(byteBuffer)) > 0) { + // do nothing + // System.out.println("reading"); + } + return byteBuffer.array(); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + fs.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + // 读取文件数据到一个bytebuff + public static ByteBuffer readByteBuffFromFile() throws IOException { + return readByteBuffFromFile("./ndn/SecretKey.txt"); + } + /** + * NIO way + * + * @param + * @return + * @throws IOException + */ + public static ByteBuffer readByteBuffFromFile(String filepathname) throws IOException { + File f = new File(filepathname); + if (!f.exists()) { + return null; + } + + FileChannel channel = null; + FileInputStream fs = null; + try { + fs = new FileInputStream(f); + channel = fs.getChannel(); + ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size()); + while ((channel.read(byteBuffer)) > 0) { + // do nothing + // System.out.println("reading"); + } + return byteBuffer; + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + fs.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + // 写入byte数组到文件 + private static void writeByteToFile(byte[] content, int len) { + writeByteToFile(content,len,"./ndn/SecretKeyMIN"); + } + + // 写入byte数组到文件 + private static void writeByteToFile(byte[] content, int len,String filepathname) { + try { + File file = new File(filepathname); + FileOutputStream fos = null; + if (file.exists()) { + file.delete(); + } + file.createNewFile();//如果文件不存在,就创建该文件 + fos = new FileOutputStream(file);//首次写入获取 + fos.write(content, 0, len); + //写入完成关闭流 + fos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // 写入字符串到文件 + private static void writeStringToFile(String content) { + try { + File file = new File("./ndn/SecretKey.txt"); + FileOutputStream fos = null; + if (file.exists()) { + file.delete(); + } + file.createNewFile();//如果文件不存在,就创建该文件 + fos = new FileOutputStream(file);//首次写入获取 + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");//指定以UTF-8格式写入文件 + osw.write(content); + //写入完成关闭流 + osw.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/minoa/view/home/DealSingleReimbursementController.java b/src/main/java/cn/minoa/view/home/DealSingleReimbursementController.java index 0f009e0..c872ab3 100644 --- a/src/main/java/cn/minoa/view/home/DealSingleReimbursementController.java +++ b/src/main/java/cn/minoa/view/home/DealSingleReimbursementController.java @@ -1,6 +1,7 @@ package cn.minoa.view.home; import cn.minoa.MainApp; +import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool; import cn.minoa.dataRequestInterface.OrderInfo; import cn.minoa.dataRequestInterface.ResponseData; import cn.minoa.model.Email; @@ -118,8 +119,20 @@ public class DealSingleReimbursementController { } System.out.println("开始下载... :"+pathfilename); - int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); - if(flag==0) { +// int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); + Long filelen= mainApp.getServerFileByteLength(pathfilename); + Integer sliceNum = (int)(filelen / mainApp.sliceSize); + if (filelen % mainApp.sliceSize != 0) { + sliceNum++; + } + Long startTime = System.currentTimeMillis(); + DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename, + localDirString,sliceNum,mainApp.threadNumberForFileTransfer); + // 下载文件 + boolean res = downLoadClient.downloadData(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + if(res) { // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("下载成功"); diff --git a/src/main/java/cn/minoa/view/home/SingleReimbursementDetailsController.java b/src/main/java/cn/minoa/view/home/SingleReimbursementDetailsController.java index 87d650e..e722546 100644 --- a/src/main/java/cn/minoa/view/home/SingleReimbursementDetailsController.java +++ b/src/main/java/cn/minoa/view/home/SingleReimbursementDetailsController.java @@ -1,7 +1,9 @@ package cn.minoa.view.home; import cn.minoa.MainApp; +import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool; import cn.minoa.model.Reimbursement; +import cn.minoa.view.login.LoginOverviewController; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.ListView; @@ -106,8 +108,21 @@ public class SingleReimbursementDetailsController { } System.out.println("开始下载... :"+pathfilename); - int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); - if(flag==0) { +// int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); + Long filelen= mainApp.getServerFileByteLength(pathfilename); + Integer sliceNum = (int)(filelen / mainApp.sliceSize); + if (filelen % mainApp.sliceSize != 0) { + sliceNum++; + } + Long startTime = System.currentTimeMillis(); + DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename, + localDirString,sliceNum,mainApp.threadNumberForFileTransfer); + // 下载文件 + boolean res = downLoadClient.downloadData(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + // 每个分片都下载成功 + if(res) { // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("下载成功"); diff --git a/src/main/java/cn/minoa/view/home/WrittenReimbursementController.java b/src/main/java/cn/minoa/view/home/WrittenReimbursementController.java index 3051521..0186c5d 100644 --- a/src/main/java/cn/minoa/view/home/WrittenReimbursementController.java +++ b/src/main/java/cn/minoa/view/home/WrittenReimbursementController.java @@ -313,8 +313,8 @@ public class WrittenReimbursementController { String pathfilename = reimbursementFilesList.get(i); //上传该文件到服务器共享文件夹目录下 File file = new File(pathfilename); - Integer res=mainApp.uploadFileToServerSharedFolder(file); - if(res<0){ + boolean res=mainApp.uploadFileToServerSharedFolder(file); + if(!res){ flag=false; } //将该文件信息[服务器文件路径地址]写入邮件信息中 diff --git a/src/main/java/cn/minoa/view/login/KeepLoginStatus.java b/src/main/java/cn/minoa/view/login/KeepLoginStatus.java new file mode 100644 index 0000000..1bd22b0 --- /dev/null +++ b/src/main/java/cn/minoa/view/login/KeepLoginStatus.java @@ -0,0 +1,154 @@ +package cn.minoa.view.login; + +import cn.minoa.MainApp; +import cn.minoa.model.Loginer; +import cn.minoa.util.EncryptionUtil; + +import java.io.*; +import java.util.Properties; + +// 维持长登录状态 +public class KeepLoginStatus { + + public static void setLoginStatus(boolean flag){ + InputStream inputStream = null; + OutputStream outputStream=null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream=new BufferedInputStream(new FileInputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + if(flag==true){ + settingProperties.setProperty("LoginStatus","true"); + }else{ + settingProperties.setProperty("LoginStatus","false"); + } + outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + settingProperties.store(outputStream,"修改配置文件"); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //关闭输出流 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public static void setLoginInfo(Loginer loginer){ + InputStream inputStream = null; + OutputStream outputStream=null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream=new BufferedInputStream(new FileInputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + settingProperties.setProperty("loginUserName", EncryptionUtil.encryptBasedAES(loginer.getUserName())); + settingProperties.setProperty("loginPassWord", EncryptionUtil.encryptBasedAES(loginer.getPassWord())); + outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties")); + settingProperties.store(outputStream,"修改配置文件"); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //关闭输出流 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public static Loginer getLoginerInfo(){ + Loginer m_loginer=new Loginer(); + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(MainApp.getClientPath() + File.separator + "ndn" + File.separator + "settings.properties")); +// inputStream = MainApp.class.getClassLoader().getResourceAsStream("/ndn/settings.properties"); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + String username = EncryptionUtil.decryptBasedAES(settingProperties.getProperty("loginUserName")); + String password = EncryptionUtil.decryptBasedAES(settingProperties.getProperty("loginPassWord")); +// System.out.println("username: " + username); +// System.out.println("password: " + password); + m_loginer.setUserName(username); + m_loginer.setPassWord(password); + } catch (IOException e) { + e.printStackTrace(); + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return m_loginer; + } + + public static boolean getLogineStatus(){ + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(MainApp.getClientPath() + File.separator + "ndn" + File.separator + "settings.properties")); +// inputStream = MainApp.class.getClassLoader().getResourceAsStream("/ndn/settings.properties"); + if (inputStream == null) { + System.out.println("没有找到配置文件..."); + } + Properties settingProperties = new Properties(); + settingProperties.load(inputStream); + String LoginStatus = settingProperties.getProperty("LoginStatus"); + if(LoginStatus.equals("true")){ + return true; + }else{ + return false; + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/cn/minoa/view/login/LoginOverviewController.java b/src/main/java/cn/minoa/view/login/LoginOverviewController.java index 21e239b..301c3cd 100644 --- a/src/main/java/cn/minoa/view/login/LoginOverviewController.java +++ b/src/main/java/cn/minoa/view/login/LoginOverviewController.java @@ -6,16 +6,26 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import cn.minoa.dataRequestInterface.MinoaDataAPI; +import cn.minoa.dataRequestInterface.*; +import cn.minoa.model.Loginer; +import cn.minoa.util.EncryptionUtil; +import cn.minoa.util.KeyStorageUtil; +import cn.minoa.util.SecretKeyManageUtil; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import net.named_data.jndn.security.KeyChain; +import net.named_data.jndn.security.pib.Pib; +import net.named_data.jndn.security.pib.PibImpl; +import net.named_data.jndn.security.tpm.Tpm; +import net.named_data.jndn.security.tpm.TpmBackEnd; +import net.named_data.jndn.security.v2.CertificateV2; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import cn.minoa.MainApp; -import cn.minoa.dataRequestInterface.OrderInfo; -import cn.minoa.dataRequestInterface.ResponseData; import cn.minoa.model.Person; import cn.minoa.model.SingleMessage; import cn.minoa.model.SingleNotice; @@ -90,22 +100,67 @@ public class LoginOverviewController { private void handleLogin() { // 实例化 // mainApp.minoaDataAPI = new MinoaDataAPI(mainApp); + String userNameString=userNameFiled.getText().trim(); + String passWordString=passwordFiled.getText().trim(); + if(userNameString.equals("")){ + return ; + } + // 登录之前先查看本地是否有该用户拥有的证书 + String keyChainNameString="/"+userNameString; + try { + if(!KeyManager.INSTANCE.isInKeyChain(keyChainNameString)){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("密钥错误"); + alert.setHeaderText("本地没有你的密钥"); + alert.setContentText("请导入密钥/证书。"); + alert.showAndWait(); + return; + } + } catch (Pib.Error | PibImpl.Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error | KeyChain.Error error) { + error.printStackTrace(); + return; + } + // 每次手动登录之前,将keyChain初始化一下 + MinoaDataAPI.keyChainNameString=keyChainNameString; + try { + KeyManager.INSTANCE.initKeyChain(keyChainNameString); + } catch (Pib.Error | PibImpl.Error | Tpm.Error | TpmBackEnd.Error | CertificateV2.Error | KeyChain.Error error) { + error.printStackTrace(); + } // 登录验证 String loginString = getLoginJsonString(); boolean isRight = checkPass(loginString); if (isRight) { + // 持久化保存当前用户名和密码 + keepLoginInfo(true,userNameString,passWordString); + // 持久化保存当前keyName + KeyStorageUtil.setKeyName(keyChainNameString); + // 修改登录状态 + mainApp.isNeedKnowLoginStatus=true; mainApp.iniShow(); } else { // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ Alert alert = new Alert(AlertType.WARNING); - alert.setTitle("Wrong UserName or Password"); - alert.setHeaderText("Please correct UserName or Password."); - alert.setContentText("Please correct UserName or Password."); + alert.setTitle("用户名或密码错误"); + alert.setHeaderText("请核对用户名或密码"); + alert.setContentText("请核对用户名或密码。\n" + + "如果你故意导入了首字段与用户名相同的密钥证书,但" + + "该证书是非法生成的,也将弹出该弹窗!!!"); alert.showAndWait(); } } - private boolean checkPass(String loginJsonString) { + // 将账号密码保存在本地 + private void keepLoginInfo(boolean flag,String username,String passord){ + Loginer m_loginer=new Loginer(); + m_loginer.setUserName(username); + m_loginer.setPassWord(passord); + KeepLoginStatus.setLoginStatus(flag); + KeepLoginStatus.setLoginInfo(m_loginer); + } + + public boolean checkPass(String loginJsonString) { System.out.println("checking your password..."); boolean flag = false; // 发送数据请求 @@ -156,7 +211,7 @@ public class LoginOverviewController { } // 请求服务器某文件的大小:返回-1表示没有该文件或登录失效 - public Integer getServerFileLength(String filename) { + public Long getServerFileLength(String filename) { // 发送数据请求 Long seqLong = mainApp.getNewDataReqId(); orderInfo.setSeq(seqLong); @@ -179,196 +234,70 @@ public class LoginOverviewController { try { dataString = jsonObject.getString("data"); JSONObject dataJsonObject = new JSONObject(dataString); - Integer fileSize= dataJsonObject.getInt("fileSize"); + Long fileSize= dataJsonObject.getLong("fileSize"); return fileSize; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); - return -1; } } - return -1; + return (long)-1; } - // 下载文件[返回0:已经成功接收所有回执数据并写入本地文件] - public Integer downloadFile(String filename) { - // 发送数据请求 - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(getFileInfoJson(filename)); - mainApp.minoaDataAPI.executeOrder("/fileInfo", orderInfo); - // 获取头像信息 - ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); - JSONObject jsonObject = responseData.praseRequestData(); - System.out.println("fileInfo-JSON: " + jsonObject.toString()); - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (codeInteger == 200) { - String dataString; - try { - dataString = jsonObject.getString("data"); - JSONObject dataJsonObject = new JSONObject(dataString); - Integer sliceNumInteger; - sliceNumInteger = dataJsonObject.getInt("sliceNum"); - // 根据分片信息获取每个分片,并合并成一个完整比特流 - Integer flagInteger = 0; - for (int i = 0; i < sliceNumInteger; i++) { - flagInteger += downLoadFileBySlice(filename, i); + // 导入密钥 + @FXML + private void importSafeBag(){ +// SecretKeyManageUtil.testSecretKey(KeyStorageUtil.getKeyName()); +// System.out.println("#####test end#####"); + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("选择密钥文件"); + Stage selectFileStage = new Stage(); + File file = fileChooser.showOpenDialog(selectFileStage); + if (file != null) { + // 文件不为空,且不是文件夹 + if (file.isFile()) { + //判断文件长度是否为0 + System.out.println("file length: " + file.length()); + if (file.length() == 0) { + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("空文件错误"); + alert.setHeaderText("您选择的是一个空文件"); + alert.setContentText("您选择的是一个空文件,请重新选择。"); + alert.showAndWait(); + return; } - System.out.println("下载分片的消息回执[0表示全部数据分片已经被写入本地]: " + flagInteger); - return flagInteger; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return 1; + } else { +// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("文件类型错误"); + alert.setHeaderText("你的文件类型错误"); + alert.setContentText("请确保你选中的是一个文件而非文件夹。"); + alert.showAndWait(); + return ; } + }else{ + return ; + } + // 将所选文件导入密钥 + String res= SecretKeyManageUtil.importSafeBag(file.getAbsolutePath()); + if(res.equals("success")){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("密钥导入成功"); + alert.setHeaderText("密钥导入成功"); + alert.setContentText("你已成功导入密钥"); + alert.showAndWait(); + }else{ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("密钥导入失败"); + alert.setHeaderText("密钥导入失败"); + alert.setContentText("由于如下原因,密钥导入时出现了问题:\n"+res); + alert.showAndWait(); } - return 1; } - /* - * @param filename 要下载的文件的“服务器路径+文件名称”,即写入请求的名称 - * - * @param localDir 要下载文件到的本地地址 - * - * @param localName 要下载的文件重命名之后的本地名称 - * - * @return 0表示已经成功接收所有回执数据并写入本地文件,否则出现error - * - * 目的是下载头像到指定路径,并重命名之。 - */ - private Integer downloadRenamedFileToSpecifiedDir(String filename, String localDir, String localName) { - // 发送数据请求 - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(getFileInfoJson(filename)); - mainApp.minoaDataAPI.executeOrder("/fileInfo", orderInfo); - // 获取头像信息 - ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); - JSONObject jsonObject = responseData.praseRequestData(); - System.out.println("fileInfo-JSON: " + jsonObject.toString()); - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (codeInteger == 200) { - String dataString; - try { - dataString = jsonObject.getString("data"); - JSONObject dataJsonObject = new JSONObject(dataString); - Integer sliceNumInteger; - sliceNumInteger = dataJsonObject.getInt("sliceNum"); - // 根据分片信息获取每个分片,并合并成一个完整比特流 - Integer flagInteger = 0; - for (int i = 0; i < sliceNumInteger; i++) { - flagInteger += downLoadFileBySlice(filename, i, localDir, localName); - } - System.out.println("下载分片的消息回执[0表示全部数据分片已经被写入本地]: " + flagInteger); - return flagInteger; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return 1; - } - } - return 1; - } - - /* - * @param filename 要下载的文件的“服务器路径+文件名称”,即写入请求的名称 - * - * @param localDir 要下载文件到的本地地址 - * - * @return 0表示已经成功接收所有回执数据并写入本地文件,否则出现error - * - * .下载服务器文件到本地指定目录下 - */ - public Integer downloadFileToSpecifiedDir(String filename, String localDir) { - // 下载到本地的文件名称 - String localName = getPureFileName(filename); - // 发送数据请求 - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(getFileInfoJson(filename)); - mainApp.minoaDataAPI.executeOrder("/fileInfo", orderInfo); - // 获取文件信息 - ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); - JSONObject jsonObject = responseData.praseRequestData(); - System.out.println("fileInfo-JSON: " + jsonObject.toString()); - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (codeInteger == 200) { - String dataString; - try { - dataString = jsonObject.getString("data"); - JSONObject dataJsonObject = new JSONObject(dataString); - Integer sliceNumInteger; - sliceNumInteger = dataJsonObject.getInt("sliceNum"); - // 根据分片信息获取每个分片,并合并成一个完整比特流 - Integer flagInteger = 0; - for (int i = 0; i < sliceNumInteger; i++) { - flagInteger += downLoadFileBySlice(filename, i, localDir, localName); - } - System.out.println("下载分片的消息回执[0表示全部数据分片已经被写入本地]: " + flagInteger); - return flagInteger; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return 1; - } - } - return 1; - } - - // 请求文件分片数据=>返回0表示分片数据被成功下载 - public Integer downLoadFileBySlice(String filename, Integer sliceNo, String localDir, String localName) { - Integer flagInteger; - // 发送数据请求 - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(getDownloadFileJson(filename, sliceNo)); - mainApp.minoaDataAPI.executeOrder("/downloadFile", orderInfo, localDir, localName); - // 获取头像信息 - ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -// JSONObject jsonObject=responseData.praseRequestData(); - System.out.println("downloadFileSlice-JSON: " + responseData.getResponseJsonDataString()); - flagInteger = Integer.parseInt(responseData.getResponseJsonDataString()); - return flagInteger; - } - - // 生成本地文件=>没有用到 -// public void creatLocalFile(String filename,byte[] fileBytes) { -// FileOutputStream out; -// try { -// out = new FileOutputStream(new File(filename)); -// try { -// out.write(fileBytes); -// out.flush(); -// System.out.println("download success"); -// out.close(); -// } catch (IOException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// } catch (FileNotFoundException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// } - // 根据包含路径的文件名获取纯文件名[linux下] public String getPureFileName(String pathfilename) { // 标记最后一个/的下标 @@ -387,40 +316,6 @@ public class LoginOverviewController { } } - // 根据包含路径的文件名获取纯文件名 -// public String getPureFileName(String pathfilename) { -// // 文件名称切割 -// while (pathfilename.indexOf('/') > 0) { -// pathfilename = pathfilename.substring(pathfilename.indexOf('/') + 1, pathfilename.length()); -// } -// System.out.println("pure file name: " + pathfilename); -// return pathfilename; -// } - - // 合并两个Byte[] -// public Byte[] byteMerger(Byte[] bt1, Byte[] bt2){ -// Byte[] bt3 = new Byte[bt1.length+bt2.length]; -// System.arraycopy(bt1, 0, bt3, 0, bt1.length); -// System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); -// return bt3; -// } - - // 请求文件分片数据=>返回0表示分片数据被成功下载 - private Integer downLoadFileBySlice(String filename, Integer sliceNo) { - Integer flagInteger; - // 发送数据请求 - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - orderInfo.setJsonString(getDownloadFileJson(filename, sliceNo)); - mainApp.minoaDataAPI.executeOrder("/downloadFile", orderInfo); - // 获取头像信息 - ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -// JSONObject jsonObject=responseData.praseRequestData(); - System.out.println("downloadFileSlice-JSON: " + responseData.getResponseJsonDataString()); - flagInteger = Integer.parseInt(responseData.getResponseJsonDataString()); - return flagInteger; - } - // 获取要下载的文件信息 public String getFileInfoJson(String filename) { JSONObject jsonObject = new JSONObject(); @@ -440,22 +335,18 @@ public class LoginOverviewController { return jsonObject.toString(); } - // 获取要下载的文件信息 - private String getDownloadFileJson(String filename, Integer sliceNo) { + public String getLoginJsonString(String userNameString,String passWordString) { JSONObject jsonObject = new JSONObject(); - String commandString = "/downloadFile"; - String usernameString = mainApp.loginer.getUserName(); - String uuidString = mainApp.loginer.getUuid(); - String filenameString = filename; - Integer sliceNoInteger = sliceNo; + String commandString = "/login"; + // 对密码进行哈希加密 + passWordString= EncryptionUtil.getMD5String(passWordString); + mainApp.loginer.setUserName(userNameString); + mainApp.loginer.setPassWord(passWordString); try { jsonObject.put("command", commandString); - jsonObject.put("username", usernameString); - jsonObject.put("uuid", uuidString); - jsonObject.put("filename", filenameString); - jsonObject.put("sliceNo", sliceNoInteger); + jsonObject.put("username", userNameString); + jsonObject.put("password", passWordString); } catch (Exception e) { - // TODO: handle exception System.out.println("exception: " + e.getMessage()); } return jsonObject.toString(); @@ -467,14 +358,8 @@ public class LoginOverviewController { String commandString = "/login"; String userNameString = userNameFiled.getText().trim(); String passWordString = passwordFiled.getText().trim(); - if (userNameString == null || passWordString == null) { -// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ - Alert alert = new Alert(AlertType.WARNING); - alert.setTitle("UserName or Password is null"); - alert.setHeaderText("Please correct UserName or Password."); - alert.setContentText("Please correct UserName or Password."); - alert.showAndWait(); - } + // 对密码进行哈希加密 + passWordString= EncryptionUtil.getMD5String(passWordString); mainApp.loginer.setUserName(userNameString); mainApp.loginer.setPassWord(passWordString); try { @@ -1076,112 +961,51 @@ public class LoginOverviewController { return jsonObject.toString(); } -// //"获取2019年9月1日之后与该选中人的100条互发消息" -// private String getGetRTMsgLogJson(Person selectedPerson) { -// JSONObject jsonObject =new JSONObject(); -// String commandString="/getRTMsgLog"; -// String userNameString=mainApp.loginer.getUserName(); -// String uuidString=mainApp.loginer.getUuid(); -// String peerString=selectedPerson.getUserName(); -// Long timestampLong = null; -// try { -// timestampLong=get20190901(); -// } catch (ParseException e1) { -// // TODO Auto-generated catch block -// e1.printStackTrace(); -// } -// //期望获取的信息条数 -// Integer limitInteger=100; -// //0表示时间节点之后,1表示之前 -// Integer directInteger=0; -// try { -// jsonObject.put("command", commandString); -// jsonObject.put("username", userNameString); -// jsonObject.put("uuid", uuidString); -// jsonObject.put("peer", peerString); -// jsonObject.put("timestamp", timestampLong); -// jsonObject.put("limit", limitInteger); -// jsonObject.put("direct", directInteger); -// } catch (Exception e) { -// // TODO: handle exception -// System.out.println("exception: " + e.getMessage()); -// } -// return jsonObject.toString(); -// } - - //获取上传文件的json格式 - public String getUploadFile(String filename, Integer offset) { - JSONObject jsonObject = new JSONObject(); - String commandString = "/uploadFile"; - String usernameString = mainApp.loginer.getUserName(); - String uuidString = mainApp.loginer.getUuid(); - String filenameString = filename; - Integer offsetInteger = offset; - try { - jsonObject.put("command", commandString); - jsonObject.put("username", usernameString); - jsonObject.put("uuid", uuidString); - jsonObject.put("filename", filenameString); - jsonObject.put("offset", offsetInteger); - } catch (Exception e) { - // TODO: handle exception - System.out.println("exception: " + e.getMessage()); - } - // 调试输出 - System.out.println("getUploadFile: "+jsonObject.toString()); - return jsonObject.toString(); - } - /* - * .文件上传操作 - * @param serverpath 将该文件上传到的指定服务器路径 - * @param file 要上传的本地文件 - * @return 返回0表示传输成功;返回-1表示传输失败 + * @param filename 要下载的文件的“服务器路径+文件名称”,即写入请求的名称 + * + * @param localDir 要下载文件到的本地地址 + * + * @param localName 要下载的文件重命名之后的本地名称 + * + * @return 0表示已经成功接收所有回执数据并写入本地文件,否则出现error + * + * 目的是下载头像到指定路径,并重命名之。 */ - public Integer sendFileToServer(File file, String serverpath) { - //获取要上传文件的文件长度,计算上传次数 - long filelen = file.length(); - int cycle = (int) filelen / mainApp.sliceSize; - int remainder=(int)filelen%mainApp.sliceSize; - if((cycle>0)&&(remainder==0)) { - cycle--; + private Integer downloadRenamedFileToSpecifiedDir(String filename, String localDir, String localName){ + Long filelen=getServerFileLength(filename); + Integer sliceNum = (int)(filelen / mainApp.sliceSize); + if (filelen % mainApp.sliceSize != 0) { + sliceNum++; } - System.out.println("file-len: " + filelen); - System.out.println("cycle: " + cycle); - //发送上传命令给上传接口,接口自行取本地数据 - int flagSuccess = 0; //记录收到200回复的次数 - for (int i = 0; i <= cycle; i++) { - OrderInfo orderInfo = new OrderInfo(); - ResponseData responseData = new ResponseData(); - Long seqLong = mainApp.getNewDataReqId(); - orderInfo.setSeq(seqLong); - //此时传入的文件路径是windows下的绝对路径 - orderInfo.setJsonString(getUploadFile(file.getAbsolutePath(), i * mainApp.sliceSize)); - - mainApp.minoaDataAPI.executeOrder("/uploadFile", orderInfo, serverpath); - responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -// System.out.println("上传文件的数据回执(200表示成功):"+responseData.getResponseJsonDataString()); - JSONObject jsonObject = responseData.praseRequestData(); - responseData.printSelf(); - // 解析数据 - Integer codeInteger = null; - try { - codeInteger = jsonObject.getInt("code"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (codeInteger == 200) { - flagSuccess++; - } - } - //每个分片都上传成功 - if (flagSuccess == (cycle + 1)) { - System.out.println("已成功将文件" + file.getAbsolutePath() + "上传至服务器" + serverpath + "目录下。"); + Long startTime = System.currentTimeMillis(); + DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(filename, + localDir,sliceNum,mainApp.threadNumberForFileTransfer); + // 下载文件 + boolean res = downLoadClient.downloadData(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + // 每个分片都下载成功 + if (res) { + // 重命名该文件 + String fromPathName=localDir + +MinoaDataAPI.getPureFileName(filename); + String toPathName=localDir+localName; + renameLocalFile(fromPathName,toPathName); return 0; - } else { - System.out.println("由于未知原因,本地文件" + file.getAbsolutePath() + "上传服务器失败。"); + }else{ return -1; } } + + // 重命名本地文件 + private void renameLocalFile(String fromPathName,String toPathName){ + File file=new File(fromPathName); + if (file.exists()) { + File toPathNameFile= new File(toPathName); + file.renameTo(toPathNameFile); + }else{ + System.out.println("要重命名的文件不存在"); + } + } } diff --git a/src/main/java/cn/minoa/view/login/NDNBlockChainConnectClient.java b/src/main/java/cn/minoa/view/login/NDNBlockChainConnectClient.java new file mode 100644 index 0000000..39ca0a0 --- /dev/null +++ b/src/main/java/cn/minoa/view/login/NDNBlockChainConnectClient.java @@ -0,0 +1,294 @@ +package cn.minoa.view.login; +// 与区块链建立TCP连接,发送注册请求 + +import cn.minoa.MainApp; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.*; +import java.net.Socket; + +public class NDNBlockChainConnectClient { + + private String NDNBlockChainIPAddress; + private Integer NDNBlockChainPortAddress; + + public NDNBlockChainConnectClient(){ +// this.NDNBlockChainIPAddress="116.77.74.144"; +// this.NDNBlockChainIPAddress="121.15.171.86"; +// this.NDNBlockChainPortAddress=8010; + this.NDNBlockChainIPAddress= MainApp.NDNBlockChainIPAddress; + System.out.println("区块链IP:"+ MainApp.NDNBlockChainIPAddress); + this.NDNBlockChainPortAddress= MainApp.NDNBlockChainPortAddress; + System.out.println("区块链Port:"+ MainApp.NDNBlockChainPortAddress); + } + + public NDNBlockChainConnectClient(String ipAddress, Integer portAddress){ + this.NDNBlockChainIPAddress= ipAddress; + this.NDNBlockChainPortAddress=portAddress; + } + + // 添加白名单 + public String addWhiteUser(String phone){ + // 获取注册数组 + byte[] registerByte=getBlockChainWhiteBuffer(phone); + System.out.println("whiteuser length: "+registerByte.length); + // 通过TCP连接区块链后台 + Socket blockchainClient; + try { + blockchainClient=new Socket(NDNBlockChainIPAddress,NDNBlockChainPortAddress); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("连接不可达:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); + return e.getMessage(); + } + System.out.println("已成功建立TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress + +"; 远程主机地址:"+blockchainClient.getRemoteSocketAddress()); + try { + OutputStream outToServer = blockchainClient.getOutputStream(); + DataOutputStream out = new DataOutputStream(outToServer); + + out.write(registerByte); + InputStream inFromServer = blockchainClient.getInputStream(); + DataInputStream in = new DataInputStream(inFromServer); + System.out.println("正在等待服务器响应..."); + byte[] res = new byte[4]; + in.read(res); + int resSize = Bytes2Int_LE(res); + System.out.println("返回值长度为:"+ resSize); + res = new byte[resSize]; + in.read(res); + System.out.println("返回值内容为:" + new String(res)); + blockchainClient.close(); + System.out.println("已关闭此次TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); +// System.out.println("服务器响应: " ); + // 解析返回来的数据,如果是200,就返回true + try { + String resString=new String(res); + System.out.println("resString: "+resString); + JSONObject resObject=new JSONObject(resString); + int resCode=resObject.getInt("StatusCode"); + String message=resObject.getString("Message"); + if(resCode==200){ + System.out.println("区块链添加白名单成功:"+phone); + return "true"; + }else{ + return message; + } + } catch (JSONException e) { + e.printStackTrace(); + return e.getMessage(); + } + } catch (IOException e) { + e.printStackTrace(); + System.out.println("添加白名单时数据交换出错:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); + return e.getMessage(); + } +// return true; + } + + // 注册用户 + public String registeNewUser(String username,String phone,String pubkey){ + // 获取注册数组 + byte[] registerByte=getBlockChainRegisterBuffer(username,phone, pubkey); + System.out.println("register length: "+registerByte.length); + // 通过TCP连接区块链后台 + Socket blockchainClient; + try { + blockchainClient=new Socket(NDNBlockChainIPAddress,NDNBlockChainPortAddress); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("连接不可达:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); + return e.getMessage(); + } + System.out.println("已成功建立TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress + +"; 远程主机地址:"+blockchainClient.getRemoteSocketAddress()); + try { + OutputStream outToServer = blockchainClient.getOutputStream(); + DataOutputStream out = new DataOutputStream(outToServer); + + out.write(registerByte); + InputStream inFromServer = blockchainClient.getInputStream(); + DataInputStream in = new DataInputStream(inFromServer); + System.out.println("正在等待服务器响应..."); + byte[] res = new byte[4]; + in.read(res); + int resSize = Bytes2Int_LE(res); + System.out.println("返回值长度为:"+ resSize); + res = new byte[resSize]; + in.read(res); + System.out.println("返回值内容为:" + new String(res)); + System.out.println("服务器响应: " ); + blockchainClient.close(); + System.out.println("已关闭此次TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); +// System.out.println("服务器响应: " ); + // 解析返回来的数据,如果是200,就返回true + try { + String resString=new String(res); + System.out.println("resString: "+resString); + JSONObject resObject=new JSONObject(resString); + int resCode=resObject.getInt("StatusCode"); + String message=resObject.getString("Message"); + if(resCode==200){ + System.out.println("区块链注册用户成功:"+username); + return "true"; + }else{ + return message; + } + } catch (JSONException e) { + e.printStackTrace(); + return e.getMessage(); + } + } catch (IOException e) { + e.printStackTrace(); + System.out.println("注册时数据交换出错:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress); + return e.getMessage(); + } + } + + + private byte[] getBlockChainRegisterBuffer(String username,String phone, String pubkey) { + String registerString=getBlockChainRegisterJsonString(username,phone, pubkey); + System.out.println("json: "+registerString); + int jsonLen = registerString.getBytes().length; + System.out.println("json len: "+jsonLen); + byte[] registerByte=new byte[jsonLen+4]; +// System.arraycopy(intToBytesLittle(jsonLen),0, +// registerByte,0,4); + System.arraycopy(intToBytesLittle(jsonLen),0, + registerByte,0,4); + try { + System.arraycopy(registerString.getBytes("utf-8"), + 0,registerByte,4,jsonLen); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return registerByte; + } + + private byte[] getBlockChainWhiteBuffer(String phone) { + String registerString=getBlockChainWhiteUserJsonString(phone); + System.out.println("json: "+registerString); + int jsonLen = registerString.getBytes().length; + System.out.println("json len: "+jsonLen); + byte[] registerByte=new byte[jsonLen+4]; +// System.arraycopy(intToBytesLittle(jsonLen),0, +// registerByte,0,4); + System.arraycopy(intToBytesLittle(jsonLen),0, + registerByte,0,4); + try { + System.arraycopy(registerString.getBytes("utf-8"), + 0,registerByte,4,jsonLen); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return registerByte; + } + + /** + * 以小端模式将int转成byte[] + * + * @param value + * @return + */ + public static byte[] intToBytesLittle(int value) { + byte[] src = new byte[4]; + src[3] = (byte) ((value >> 24) & 0xFF); + src[2] = (byte) ((value >> 16) & 0xFF); + src[1] = (byte) ((value >> 8) & 0xFF); + src[0] = (byte) (value & 0xFF); + return src; + } + + /** + * 以大端模式将int转成byte[] + * + * @param value + * @return + */ + public static byte[] intToBytesBig(int value) { + byte[] src = new byte[4]; + src[0] = (byte) ((value >> 24) & 0xFF); + src[1] = (byte) ((value >> 16) & 0xFF); + src[2] = (byte) ((value >> 8) & 0xFF); + src[3] = (byte) (value & 0xFF); + return src; + } + + /** + * 转换byte数组为int(小端) + * @return + * @note 数组长度至少为4,按小端方式转换,即传入的bytes是小端的,按这个规律组织成int + */ + public int Bytes2Int_LE(byte[] bytes){ + if(bytes.length < 4) + return -1; + int iRst = (bytes[0] & 0xFF); + iRst |= (bytes[1] & 0xFF) << 8; + iRst |= (bytes[2] & 0xFF) << 16; + iRst |= (bytes[3] & 0xFF)<< 24; + + return iRst; + } + + // 从前端界面获得登录数据并转换成json格式 + private String getBlockChainWhiteUserJsonString(String phone) { + JSONObject jsonObject = new JSONObject(); + String typeString = "whiteUser"; + String commandString = "addWhiteUser"; + String RealNameString = "王锋"; + Integer GenderInteger=0; + String IDCardString=""; + try { + jsonObject.put("Type", typeString); + jsonObject.put("Command", commandString); + jsonObject.put("RealName",RealNameString); + jsonObject.put("Phone",phone); + jsonObject.put("Gender",GenderInteger); + jsonObject.put("IDCard",IDCardString); + } catch (Exception e) { + System.out.println("exception: " + e.getMessage()); + } + return jsonObject.toString(); + } + + // 从前端界面获得登录数据并转换成json格式 + private String getBlockChainRegisterJsonString(String username,String phone, String pubkey) { + JSONObject jsonObject = new JSONObject(); + String typeString = "user-act"; + String commandString = "Registry"; + String pubkeyString = pubkey; + String prefixString="/"+username; + Integer level=0; + String timestamp=""; + String IDCard=""; + String realname=""; + String aboutMe=""; + String face=""; + String print=""; + String iris=""; + String other=""; + String sig=""; + try { + jsonObject.put("Type", typeString); + jsonObject.put("Command", commandString); + jsonObject.put("Pubkey", pubkeyString); + jsonObject.put("Prefix",prefixString); + jsonObject.put("Level",level); + jsonObject.put("Timestamp",timestamp); + jsonObject.put("Username",username); + jsonObject.put("Realname",realname); + jsonObject.put("Phone",phone); + jsonObject.put("IDcard",IDCard); + jsonObject.put("AboutMe",aboutMe); + jsonObject.put("Face",face); + jsonObject.put("Print",print); + jsonObject.put("Iris",iris); + jsonObject.put("Other",other); + jsonObject.put("Sig",sig); + } catch (Exception e) { + System.out.println("exception: " + e.getMessage()); + } + return jsonObject.toString(); + } +} diff --git a/src/main/java/cn/minoa/view/mine/MyCloudFileController.java b/src/main/java/cn/minoa/view/mine/MyCloudFileController.java index d2cd161..c7f5f81 100644 --- a/src/main/java/cn/minoa/view/mine/MyCloudFileController.java +++ b/src/main/java/cn/minoa/view/mine/MyCloudFileController.java @@ -2,6 +2,8 @@ package cn.minoa.view.mine; import java.io.File; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; import java.util.LinkedList; /* * 数据格式说明: @@ -11,7 +13,12 @@ import java.util.LinkedList; * .前端一个listview表项是一个pane,其id是"路径+纯文件名+@文件类型" */ import java.util.List; +import java.util.Map; +import cn.minoa.model.SingleFile; +import cn.minoa.util.FileUtil; +import cn.minoa.util.StringByteLengthUtil; +import cn.minoa.view.login.LoginOverviewController; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -38,6 +45,8 @@ public class MyCloudFileController { private String currentPath; // 当前路径下的文件列表[path+file+@type] private List filePathnameList; + // 当前文件列表对应的文件具体信息,key是filePathnameList中的表项 + private Map detailedFileListMap; @FXML private Text pathText; @@ -53,6 +62,7 @@ public class MyCloudFileController { // TODO Auto-generated constructor stub currentPath = "/"; filePathnameList = new LinkedList(); + detailedFileListMap=new HashMap(); } @FXML @@ -183,7 +193,7 @@ public class MyCloudFileController { }else{ serverPathname=currentPath+"/"+file.getName(); } - Integer fileServerLength=mainApp.getServerFileByteLength(serverPathname); + Long fileServerLength=mainApp.getServerFileByteLength(serverPathname); System.out.println("fileServerLength: "+fileServerLength); if(fileServerLength<0){ //文件未成功创建 @@ -259,7 +269,32 @@ public class MyCloudFileController { } public void makeDir(String foldername) { + //封死空文件夹 + if(foldername.trim().equals("")){ + return ; + } + // 封掉命名为/的文件夹 + if(foldername.trim().equals("/")){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("新建失败"); + alert.setHeaderText("新建文件夹失败"); + alert.setContentText("文件夹名称不许为\"/\"哦~"); + alert.showAndWait(); + return ; + } foldername = currentPath + "/" + foldername; + //封死在用户跟目录下创建share或cache文件夹 + if(foldername.equals("/share")||foldername.equals("/cache")|| + foldername.equals("//share")||foldername.equals("//cache")){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.ERROR); + alert.setTitle("新建失败"); + alert.setHeaderText("新建文件夹失败"); + alert.setContentText("根目录下不允许创建命名为share或cache的文件夹。"); + alert.showAndWait(); + return ; + } // 请求数据 OrderInfo orderInfo = new OrderInfo(); ResponseData responseData = new ResponseData(); @@ -306,6 +341,16 @@ public class MyCloudFileController { // 删除选中项按钮=>只支持删除普通文件 @FXML private void deleteSelectedItem() { + //判断是否选择了文件 + if(fileList.getSelectionModel().getSelectedItem()==null){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("文件未选择"); + alert.setHeaderText("文件未选择"); + alert.setContentText("请先在文件列表中选择一个文件。"); + alert.showAndWait(); + return; + } System.out.println("发送了删除请求到服务器..."); // 获取选中的文件 Pane pane = fileList.getSelectionModel().getSelectedItem(); @@ -356,36 +401,20 @@ public class MyCloudFileController { } - // 下载选中项按钮,下载文件到缺省本地目录[E盘根目录] -// @FXML -// private void downloadSelectedItem() { -// Pane pane=fileList.getSelectionModel().getSelectedItem(); -// String pathfilename=getPathFileName(pane.getId()); -// System.out.println("开始下载... :"+pathfilename); -// int flag=mainApp.downloadFileByPathfilename(pathfilename); -// if(flag==0) { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.INFORMATION); -// alert.setTitle("下载成功"); -// alert.setHeaderText("下载文件成功"); -// alert.setContentText("您请求的文件数据已经被全部下载到本地," -// + "如有发现打开异常或数据内容并非所求,说明出现了服务器数据请求问题。" -// + "您的文件默认保存位置为:"+mainApp.fileLocalPath); -// alert.showAndWait(); -// }else { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.ERROR); -// alert.setTitle("下载失败"); -// alert.setHeaderText("下载文件失败"); -// alert.setContentText("本地文件数据写入失败,请检查是否有权限访问默认存储位置。" -// + "您的文件默认保存位置为:"+mainApp.fileLocalPath); -// alert.showAndWait(); -// } -// } // 下载选中项按钮 @FXML private void downloadSelectedItem() { + // 判断是否选择了文件 + if(fileList.getSelectionModel().getSelectedItem()==null){ + // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ + Alert alert = new Alert(AlertType.WARNING); + alert.setTitle("文件未选择"); + alert.setHeaderText("文件未选择"); + alert.setContentText("请先在文件列表中选择一个文件。"); + alert.showAndWait(); + return; + } // 选择要下载到的文件夹 String localDirString = mainApp.fileLocalPath; DirectoryChooser directoryChooser = new DirectoryChooser(); @@ -420,7 +449,7 @@ public class MyCloudFileController { } // 下载文件之后,通过获取服务器的文件大小,与下载到本地的文件大小对比 // 判断是否传输成功 - Integer fileServerLength=mainApp.getServerFileByteLength(pathfilename); + Long fileServerLength=mainApp.getServerFileByteLength(pathfilename); System.out.println("fileServerLength: "+fileServerLength); String localfilename=localDirString+getPureFileNameFromLinux(pathfilename); File localfile=new File(localfilename); @@ -450,23 +479,6 @@ public class MyCloudFileController { alert.setContentText("文件数据未能全部写入本地。" + "您的文件保存位置为:" +localDirString); alert.showAndWait(); } -// int flag = mainApp.downloadFileByPathfilename(pathfilename,localDirString); -// if (flag == 0) { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.INFORMATION); -// alert.setTitle("下载成功"); -// alert.setHeaderText("下载文件成功"); -// alert.setContentText("您请求的文件数据已经被全部下载到本地," + "如有发现打开异常或数据内容并非所求,说明出现了服务器数据请求问题。" + "您的文件保存位置为:" -// + localDirString); -// alert.showAndWait(); -// } else { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.ERROR); -// alert.setTitle("下载失败"); -// alert.setHeaderText("下载文件失败"); -// alert.setContentText("本地文件数据写入失败,请检查是否有权限访问文件存储位置。" + "您的文件保存位置为:" +localDirString); -// alert.showAndWait(); -// } } // 根据包含路径的文件名获取纯文件名[linux下] @@ -524,9 +536,9 @@ public class MyCloudFileController { return jsonObject.toString(); } - // 列出某目录下的所有文件 + // 列出某目录下的所有文件【非文件夹】 private boolean lsFolder(String foldername) { - System.out.println("foldername: " + foldername); + System.out.println("罗列foldername下文件: " + foldername); // 请求数据 OrderInfo orderInfo = new OrderInfo(); ResponseData responseData = new ResponseData(); @@ -546,12 +558,15 @@ public class MyCloudFileController { // TODO Auto-generated catch block e.printStackTrace(); } - if (codeInteger == 201) { + filePathnameList.clear(); + detailedFileListMap.clear(); + if (codeInteger == 200) { String dataString; try { dataString = jsonObject.getString("data"); if ((dataString.equals("")) || (dataString.equals("null"))) { filePathnameList.clear(); + detailedFileListMap.clear(); return true; } JSONArray dataJsonArray = new JSONArray(dataString); @@ -563,10 +578,23 @@ public class MyCloudFileController { fileCacheJsonObject = new JSONObject(fileCacheString); String filename = fileCacheJsonObject.getString("filename"); String type = fileCacheJsonObject.getString("type"); - if (foldername.charAt(foldername.length() - 1) == '/') { - filePathnameList.add(foldername + filename + "@" + type); - } else { - filePathnameList.add(foldername + '/' + filename + "@" + type); + Long time=fileCacheJsonObject.getLong("time"); + Long size=fileCacheJsonObject.getLong("size"); + if (foldername.charAt(foldername.length() - 1) != '/'){ + foldername=foldername+"/"; + } + if(type.equals("f")){ + // filePathnameList + String fileId=foldername + filename + "@" + type; + filePathnameList.add(fileId); + // map + SingleFile singleFile=new SingleFile(fileId); + singleFile.setFilepath(foldername); + singleFile.setFilename(filename); + singleFile.setType(type); + singleFile.setSize(size); + singleFile.setTime(time); + detailedFileListMap.put(fileId,singleFile); } } return true; @@ -575,10 +603,108 @@ public class MyCloudFileController { e.printStackTrace(); return false; } + }else if(codeInteger==201){ + System.out.println("lsFolder: 201大数据传输接口"); + String dataString; + try { + dataString = jsonObject.getString("data"); + if (dataString.equals("")) { + //数据为空 + } else { + JSONObject dataJsonObject = new JSONObject(dataString); + String dataIdString = dataJsonObject.getString("dataId"); + Integer dataSizeInteger = dataJsonObject.getInt("dataSize"); + Integer sliceNumInteger = dataJsonObject.getInt("sliceNum"); + Integer sliceSizeInteger = dataJsonObject.getInt("sliceSize"); + byte[] noticelistByte = new byte[dataSizeInteger]; + for (Integer sliceNo = 0; sliceNo < sliceNumInteger; sliceNo++) { + // 发送数据请求 + Long seqLongT = mainApp.getNewDataReqId(); + orderInfo.setSeq(seqLongT); + System.out.println("getDataSlice: " + getGetDataSlice(dataIdString, sliceNo)); + orderInfo.setJsonString(getGetDataSlice(dataIdString, sliceNo)); + mainApp.minoaDataAPI.executeOrder("/getDataSlice", orderInfo); + // 获取用户列表信息 + ResponseData responseDataCache = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLongT); + byte[] byteCache = responseDataCache.getFileSlice(); + System.out.println("byteCache size:" + byteCache.length); + System.out.println("byteCache:" + byteCache); + if (sliceNo == (sliceNumInteger - 1)) { + for (int x = (sliceNo * sliceSizeInteger); x < dataSizeInteger; x++) { + noticelistByte[x] = byteCache[x - (sliceNo * sliceSizeInteger)]; + } + } else { + for (int x = (sliceNo * sliceSizeInteger); x < (sliceNo * sliceSizeInteger + 7000); x++) { + noticelistByte[x] = byteCache[x - (sliceNo * sliceSizeInteger)]; + } + } + } + try { + String cacheString = new String(noticelistByte, "UTF-8"); + System.out.println(cacheString); + JSONArray dataJsonArray = new JSONArray(cacheString); + String fileCacheString; + JSONObject fileCacheJsonObject; + // 遍历每个文件信息 + for (int i = 0; i < dataJsonArray.length(); i++) { + fileCacheString = dataJsonArray.getString(i); + fileCacheJsonObject = new JSONObject(fileCacheString); + String filename = fileCacheJsonObject.getString("filename"); + String type = fileCacheJsonObject.getString("type"); + Long time=fileCacheJsonObject.getLong("time"); + Long size=fileCacheJsonObject.getLong("size"); + if (foldername.charAt(foldername.length() - 1) != '/'){ + foldername=foldername+"/"; + } +// if(type.equals("f")){ + // filePathnameList + String fileId=foldername + filename + "@" + type; + filePathnameList.add(fileId); + // map + SingleFile singleFile=new SingleFile(fileId); + singleFile.setFilepath(foldername); + singleFile.setFilename(filename); + singleFile.setType(type); + singleFile.setSize(size); + singleFile.setTime(time); + detailedFileListMap.put(fileId,singleFile); +// } + } + return true; + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } return false; } + public String getGetDataSlice(String dataId, Integer sliceNo) { + JSONObject jsonObject = new JSONObject(); + String commandString = "/getDataSlice"; + String usernameString = mainApp.loginer.getUserName(); + String uuidString = mainApp.loginer.getUuid(); + Integer sliceNoInteger = sliceNo; + String dataIdString = dataId; + try { + jsonObject.put("command", commandString); + jsonObject.put("username", usernameString); + jsonObject.put("uuid", uuidString); + jsonObject.put("dataId", dataIdString); + jsonObject.put("sliceNo", sliceNoInteger); + } catch (Exception e) { + // TODO: handle exception + System.out.println("exception: " + e.getMessage()); + } + return jsonObject.toString(); + } + // 获取上传文件的json格式 private String getUploadFile(String filename, Integer offset) { JSONObject jsonObject = new JSONObject(); @@ -600,65 +726,6 @@ public class MyCloudFileController { return jsonObject.toString(); } -// //上传文件操作=>此函数只支持上传指定文件到用户根目录 -// public void sendFileToServer(File file) { -// // 获取要上传文件的文件长度,计算上传次数 -// long filelen = file.length(); -// int cycle = (int) filelen / mainApp.sliceSize; -// System.out.println("file-len: " + filelen); -// System.out.println("cycle: " + cycle); -// // 发送上传命令给上传接口,接口自行取本地数据 -// int flagSuccess = 0; // 记录收到200回复的次数 -// for (int i = 0; i <= cycle; i++) { -// OrderInfo orderInfo = new OrderInfo(); -// ResponseData responseData = new ResponseData(); -// Long seqLong = mainApp.getNewDataReqId(); -// orderInfo.setSeq(seqLong); -// // 此时传入的文件路径是windows下的绝对路径 -// orderInfo.setJsonString(getUploadFile(file.getAbsolutePath(), i * mainApp.sliceSize)); -// -// mainApp.minoaDataAPI.executeOrder("/uploadFile", orderInfo); -// responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong); -//// System.out.println("上传文件的数据回执(200表示成功):"+responseData.getResponseJsonDataString()); -// JSONObject jsonObject = responseData.praseRequestData(); -// responseData.printSelf(); -// // 解析数据 -// Integer codeInteger = null; -// try { -// codeInteger = jsonObject.getInt("code"); -// } catch (JSONException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// if (codeInteger == 200) { -// flagSuccess++; -// } -// } -// // 每个分片都上传成功 -// if (flagSuccess == (cycle + 1)) { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.INFORMATION); -// alert.setTitle("上传成功"); -// alert.setHeaderText("上传文件成功"); -// alert.setContentText("您的文件已上传。"); -// alert.showAndWait(); -// // 根据当前路径,重新加载整个界面,来刷新listview -// try { -// mainApp.reloadCloudFileOverview(currentPath); -// } catch (IOException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// } else { -//// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ -// Alert alert = new Alert(AlertType.WARNING); -// alert.setTitle("上传失败"); -// alert.setHeaderText("上传文件失败"); -// alert.setContentText("由于未知原因,您的文件上传失败,非常抱歉。"); -// alert.showAndWait(); -// } -// } - // 从paneId中获取文件所在路径 public String getPathFromPaneId(String paneId) { // 标记最后一个/的下标 @@ -731,146 +798,279 @@ public class MyCloudFileController { } return false; } -} -class FileListItem { - // 外部pane - private Pane pane; - private Integer paneWidth; - private Integer paneHeight; - // 头像 - private Button head; - private Integer headLength; - // 文本区域 -// public TextArea text; - private Text text; -// private Integer textWidth; -// private Integer textHeight; + class FileListItem { + // 外部pane + private Pane pane; + private Integer paneWidth; + private Integer paneHeight; + // 头像 + private Button head; + private Integer headLength; + // 文本区域:文件名 + private Text text; + // 文件大小 + private Text filesizeText; + // 文件创建时间 + private Text filetimeText; - // 每个Pane代映射了一个文件[路径+文件名+@文件类型] - String pathfilename; + // 每个Pane代映射了一个文件[路径+文件名+@文件类型] + String pathfilename; - // 组件位置属性 - private Integer headXInteger; - private Integer headYInteger; - private Integer textXInteger; - private Integer textYInteger; + // 组件位置属性 + private Integer headXInteger; + private Integer headYInteger; + private Integer textXInteger; + private Integer textYInteger; + private Integer fileszTextXInteger; + private Integer fileszTextYInteger; + private Integer filetimeTextXInteger; + private Integer filetimeTextYInteger; - // 设置联系人头像 - private void setHeadPortrait(Button button, String filetype) { - button.setStyle( - String.format("-fx-background-image: url('file:resources/images/myFileIcon/%s.png')", filetype)); - } + // 设置联系人头像 + private void setHeadPortrait(Button button, String filetype) { + button.setStyle( + String.format("-fx-background-image: url('file:resources/images/myFileIcon/%s.png')", filetype)); + } - // 构造函数 - public FileListItem(String pathfiletypename) { - // 映射数据 - this.pathfilename = pathfiletypename; - // 大小配置 - paneWidth = 200; - paneHeight = 50; - headLength = 35; -// textWidth = 150; -// textHeight = 25; - // 位置配置 - headXInteger = 10; - headYInteger = 10; - textXInteger = 70; - textYInteger = 28; + // 构造函数 + public FileListItem(String pathfiletypename) { + // 映射数据 + this.pathfilename = pathfiletypename; + // 大小配置 + paneWidth = 200; + paneHeight = 50; + headLength = 35; + // 位置配置 + headXInteger = 10; + headYInteger = 10; + textXInteger = 70; + textYInteger = 28; + fileszTextXInteger=textXInteger+150; + fileszTextYInteger=textYInteger; + filetimeTextXInteger=textXInteger+280; + filetimeTextYInteger=textYInteger; - pane = new Pane(); - head = new Button(); - text = new Text(); + pane = new Pane(); + head = new Button(); + text = new Text(); + filesizeText=new Text(); + filetimeText=new Text(); - // 最外面的pane的大小 - pane.setPrefSize(paneWidth, paneHeight); + // 最外面的pane的大小 + pane.setPrefSize(paneWidth, paneHeight); - // 设置头像和pane的CSS的样式标识 - head.getStyleClass().add("head"); - pane.getStyleClass().add("pane"); + // 设置头像和pane的CSS的样式标识 + head.getStyleClass().add("head"); + pane.getStyleClass().add("pane"); - // 设置消息头像和消息文本属性 - head.setPrefSize(headLength, headLength); -// text.setPrefSize(textWidth, textHeight); -// text.setWrapText(true); -// text.setEditable(false); - } + // 设置消息头像和消息文本属性 + head.setPrefSize(headLength, headLength); + } - public FileListItem(String pathfilename, String filetype) { - // 映射数据 - this.pathfilename = pathfilename + "@" + filetype; - // 大小配置 - paneWidth = 200; - paneHeight = 50; - headLength = 35; -// textWidth = 150; -// textHeight = 25; - // 位置配置 - headXInteger = 10; - headYInteger = 10; - textXInteger = 70; - textYInteger = 28; - - pane = new Pane(); - head = new Button(); - text = new Text(); - - // 最外面的pane的大小 - pane.setPrefSize(paneWidth, paneHeight); - - // 设置头像和pane的CSS的样式标识 - head.getStyleClass().add("head"); - pane.getStyleClass().add("pane"); - - // 设置消息头像和消息文本属性 - head.setPrefSize(headLength, headLength); -// text.setPrefSize(textWidth, textHeight); -// text.setWrapText(true); -// text.setEditable(false); - } - - // 根据person获取pane - public Pane getPaneItem() { - String name = this.pathfilename; - // 头像位置 - head.setLayoutY(headYInteger); - head.setLayoutX(headXInteger); - // text位置 - text.setLayoutX(textXInteger); - text.setLayoutY(textYInteger); - // 头像和气泡文本内容 - text.setText(getPureFilenameFromPaneId(name)); -// text.setText(name); - setHeadPortrait(head, getFileTypeFromPaneId(name)); - pane.getChildren().add(head); - pane.getChildren().add(text); - // 设置pane的id - pane.setId(name); - return pane; - } - - // 根据包含路径的文件名获取纯文件名 - private String getPureFilenameFromPaneId(String paneId) { - // 标记最后一个/的下标 - int indexLeft = -1; - // 标记最后一个@的下标 - int indexRight = -1; - for (int i = 0; i < paneId.length(); i++) { - if (paneId.charAt(i) == '@') { - indexRight = i; - } else if (paneId.charAt(i) == '/') { - indexLeft = i; + // 根据person获取pane + public Pane getPaneItem() { + String name = this.pathfilename; + // 头像位置 + head.setLayoutY(headYInteger); + head.setLayoutX(headXInteger); + // text位置 + text.setLayoutX(textXInteger); + text.setLayoutY(textYInteger); + filesizeText.setLayoutX(fileszTextXInteger); + filesizeText.setLayoutY(fileszTextYInteger); + filetimeText.setLayoutX(filetimeTextXInteger); + filetimeText.setLayoutY(filetimeTextYInteger); + // 头像和气泡文本内容 + String thisfilename=getPureFilenameFromPaneId(name); + if(StringByteLengthUtil.getByteLength(thisfilename)>20){ + thisfilename=thisfilename.substring(0,10)+" ..."; } + text.setText(thisfilename); + setHeadPortrait(head, getFileTypeFromPaneId(name)); + // 文件大小 + Long size=detailedFileListMap.get(name).getSize(); + filesizeText.setText(FileUtil.sizeToShowSize(size)); + // 文件创建时间 + Long time=detailedFileListMap.get(name).getTime(); + filetimeText.setText(FileUtil.timeToDateString(time)); + // 文件大小和文件创建时间 + pane.getChildren().add(head); + pane.getChildren().add(text); + pane.getChildren().add(filesizeText); + pane.getChildren().add(filetimeText); + // 设置pane的id + pane.setId(name); + return pane; } - if ((indexLeft == -1) || (indexRight == -1)) { - System.out.println("prase paneId error: " + paneId); - return ""; - } - return paneId.substring(indexLeft + 1, indexRight); - } - // 从paneId中获取文件类型 - private String getFileTypeFromPaneId(String paneId) { - return paneId.substring(paneId.length() - 1, paneId.length()); + // 根据包含路径的文件名获取纯文件名 + private String getPureFilenameFromPaneId(String paneId) { + // 标记最后一个/的下标 + int indexLeft = -1; + // 标记最后一个@的下标 + int indexRight = -1; + for (int i = 0; i < paneId.length(); i++) { + if (paneId.charAt(i) == '@') { + indexRight = i; + } else if (paneId.charAt(i) == '/') { + indexLeft = i; + } + } + if ((indexLeft == -1) || (indexRight == -1)) { + System.out.println("prase paneId error: " + paneId); + return ""; + } + return paneId.substring(indexLeft + 1, indexRight); + } + + // 从paneId中获取文件类型 + private String getFileTypeFromPaneId(String paneId) { + return paneId.substring(paneId.length() - 1, paneId.length()); + } } } + + + +//class FileListItem { +// // 外部pane +// private Pane pane; +// private Integer paneWidth; +// private Integer paneHeight; +// // 头像 +// private Button head; +// private Integer headLength; +// // 文本区域 +//// public TextArea text; +// private Text text; +//// private Integer textWidth; +//// private Integer textHeight; +// +// // 每个Pane代映射了一个文件[路径+文件名+@文件类型] +// String pathfilename; +// +// // 组件位置属性 +// private Integer headXInteger; +// private Integer headYInteger; +// private Integer textXInteger; +// private Integer textYInteger; +// +// // 设置联系人头像 +// private void setHeadPortrait(Button button, String filetype) { +// button.setStyle( +// String.format("-fx-background-image: url('file:resources/images/myFileIcon/%s.png')", filetype)); +// } +// +// // 构造函数 +// public FileListItem(String pathfiletypename) { +// // 映射数据 +// this.pathfilename = pathfiletypename; +// // 大小配置 +// paneWidth = 200; +// paneHeight = 50; +// headLength = 35; +//// textWidth = 150; +//// textHeight = 25; +// // 位置配置 +// headXInteger = 10; +// headYInteger = 10; +// textXInteger = 70; +// textYInteger = 28; +// +// pane = new Pane(); +// head = new Button(); +// text = new Text(); +// +// // 最外面的pane的大小 +// pane.setPrefSize(paneWidth, paneHeight); +// +// // 设置头像和pane的CSS的样式标识 +// head.getStyleClass().add("head"); +// pane.getStyleClass().add("pane"); +// +// // 设置消息头像和消息文本属性 +// head.setPrefSize(headLength, headLength); +//// text.setPrefSize(textWidth, textHeight); +//// text.setWrapText(true); +//// text.setEditable(false); +// } +// +// public FileListItem(String pathfilename, String filetype) { +// // 映射数据 +// this.pathfilename = pathfilename + "@" + filetype; +// // 大小配置 +// paneWidth = 200; +// paneHeight = 50; +// headLength = 35; +//// textWidth = 150; +//// textHeight = 25; +// // 位置配置 +// headXInteger = 10; +// headYInteger = 10; +// textXInteger = 70; +// textYInteger = 28; +// +// pane = new Pane(); +// head = new Button(); +// text = new Text(); +// +// // 最外面的pane的大小 +// pane.setPrefSize(paneWidth, paneHeight); +// +// // 设置头像和pane的CSS的样式标识 +// head.getStyleClass().add("head"); +// pane.getStyleClass().add("pane"); +// +// // 设置消息头像和消息文本属性 +// head.setPrefSize(headLength, headLength); +//// text.setPrefSize(textWidth, textHeight); +//// text.setWrapText(true); +//// text.setEditable(false); +// } +// +// // 根据person获取pane +// public Pane getPaneItem() { +// String name = this.pathfilename; +// // 头像位置 +// head.setLayoutY(headYInteger); +// head.setLayoutX(headXInteger); +// // text位置 +// text.setLayoutX(textXInteger); +// text.setLayoutY(textYInteger); +// // 头像和气泡文本内容 +// text.setText(getPureFilenameFromPaneId(name)); +//// text.setText(name); +// setHeadPortrait(head, getFileTypeFromPaneId(name)); +// pane.getChildren().add(head); +// pane.getChildren().add(text); +// // 设置pane的id +// pane.setId(name); +// return pane; +// } +// +// // 根据包含路径的文件名获取纯文件名 +// private String getPureFilenameFromPaneId(String paneId) { +// // 标记最后一个/的下标 +// int indexLeft = -1; +// // 标记最后一个@的下标 +// int indexRight = -1; +// for (int i = 0; i < paneId.length(); i++) { +// if (paneId.charAt(i) == '@') { +// indexRight = i; +// } else if (paneId.charAt(i) == '/') { +// indexLeft = i; +// } +// } +// if ((indexLeft == -1) || (indexRight == -1)) { +// System.out.println("prase paneId error: " + paneId); +// return ""; +// } +// return paneId.substring(indexLeft + 1, indexRight); +// } +// +// // 从paneId中获取文件类型 +// private String getFileTypeFromPaneId(String paneId) { +// return paneId.substring(paneId.length() - 1, paneId.length()); +// } +//} diff --git a/src/main/java/cn/minoa/view/mine/SingleEmailDetailsController.java b/src/main/java/cn/minoa/view/mine/SingleEmailDetailsController.java index 02e4c47..3ccab5f 100644 --- a/src/main/java/cn/minoa/view/mine/SingleEmailDetailsController.java +++ b/src/main/java/cn/minoa/view/mine/SingleEmailDetailsController.java @@ -3,6 +3,7 @@ package cn.minoa.view.mine; import java.io.File; import cn.minoa.MainApp; +import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool; import cn.minoa.model.Email; import javafx.fxml.FXML; import javafx.scene.control.Alert; @@ -124,8 +125,20 @@ public class SingleEmailDetailsController { } System.out.println("开始下载... :"+pathfilename); - int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); - if(flag==0) { +// int flag=mainApp.downloadFileByPathfilename(pathfilename,localDirString); + Long filelen= mainApp.getServerFileByteLength(pathfilename); + Integer sliceNum = (int)(filelen / mainApp.sliceSize); + if (filelen % mainApp.sliceSize != 0) { + sliceNum++; + } + Long startTime = System.currentTimeMillis(); + DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename, + localDirString,sliceNum,mainApp.threadNumberForFileTransfer); + // 下载文件 + boolean res = downLoadClient.downloadData(); + Long endTime = System.currentTimeMillis(); + System.out.println("耗时:" + (endTime - startTime) + "ms"); + if(res) { // 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/ Alert alert = new Alert(AlertType.INFORMATION); alert.setTitle("下载成功"); diff --git a/src/main/java/cn/minoa/view/mine/WrittenEmailController.java b/src/main/java/cn/minoa/view/mine/WrittenEmailController.java index 4a5c7ac..4c15dc8 100644 --- a/src/main/java/cn/minoa/view/mine/WrittenEmailController.java +++ b/src/main/java/cn/minoa/view/mine/WrittenEmailController.java @@ -274,8 +274,8 @@ public class WrittenEmailController { String pathfilename=emailFilesList.get(i); //上传该文件到服务器共享文件夹目录下 File file=new File(pathfilename); - Integer res=mainApp.uploadFileToServerSharedFolder(file); - if(res<0){ + boolean res=mainApp.uploadFileToServerSharedFolder(file); + if(!res){ flag=false; } //将该文件信息[服务器文件路径地址]写入邮件信息中