generate the poetry config file
parent
a625c95f34
commit
43c4f1c907
|
@ -0,0 +1,292 @@
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2020.12.5"
|
||||||
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chardet"
|
||||||
|
version = "4.0.0"
|
||||||
|
description = "Universal encoding detector for Python 2 and 3"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "7.1.2"
|
||||||
|
description = "Composable command line interface toolkit"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "2.10"
|
||||||
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pillow"
|
||||||
|
version = "8.0.1"
|
||||||
|
description = "Python Imaging Library (Fork)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettytable"
|
||||||
|
version = "2.0.0"
|
||||||
|
description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
wcwidth = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tests = ["pytest", "pytest-cov"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-core"
|
||||||
|
version = "7.0.1"
|
||||||
|
description = "Python<->ObjC Interoperability Module"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-framework-cocoa"
|
||||||
|
version = "7.0.1"
|
||||||
|
description = "Wrappers for the Cocoa frameworks on macOS"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyobjc-core = ">=7.0.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyobjc-framework-quartz"
|
||||||
|
version = "7.0.1"
|
||||||
|
description = "Wrappers for the Quartz frameworks on macOS"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyobjc-core = ">=7.0.1"
|
||||||
|
pyobjc-framework-Cocoa = ">=7.0.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pystray"
|
||||||
|
version = "0.17.2"
|
||||||
|
description = "Provides systray integration"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Pillow = "*"
|
||||||
|
pyobjc-framework-Quartz = {version = ">=3.0", markers = "sys_platform == \"darwin\""}
|
||||||
|
python-xlib = {version = ">=0.17", markers = "sys_platform == \"linux\""}
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-xlib"
|
||||||
|
version = "0.29"
|
||||||
|
description = "Python X Library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = ">=1.10.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.25.1"
|
||||||
|
description = "Python HTTP for Humans."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = ">=2017.4.17"
|
||||||
|
chardet = ">=3.0.2,<5"
|
||||||
|
idna = ">=2.5,<3"
|
||||||
|
urllib3 = ">=1.21.1,<1.27"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.15.0"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tcping"
|
||||||
|
version = "0.1.1rc1"
|
||||||
|
description = "command line for tcp ping"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = "*"
|
||||||
|
prettytable = "*"
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "1.26.2"
|
||||||
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotlipy (>=0.6.0)"]
|
||||||
|
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wcwidth"
|
||||||
|
version = "0.2.5"
|
||||||
|
description = "Measures the displayed width of unicode strings in a terminal"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websocket-client"
|
||||||
|
version = "0.57.0"
|
||||||
|
description = "WebSocket client for Python. hybi13 is supported."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "1.1"
|
||||||
|
python-versions = "^3.9"
|
||||||
|
content-hash = "6394bb0ce3ee58e8649e590ead49d625cfb5051f70af5f70856fc464421521d8"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
certifi = [
|
||||||
|
{file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
|
||||||
|
{file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
|
||||||
|
]
|
||||||
|
chardet = [
|
||||||
|
{file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
|
||||||
|
{file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
|
||||||
|
]
|
||||||
|
click = [
|
||||||
|
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
||||||
|
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
|
||||||
|
]
|
||||||
|
idna = [
|
||||||
|
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
|
||||||
|
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
|
||||||
|
]
|
||||||
|
pillow = [
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3"},
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302"},
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c"},
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11"},
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-win32.whl", hash = "sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e"},
|
||||||
|
{file = "Pillow-8.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-win32.whl", hash = "sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0"},
|
||||||
|
{file = "Pillow-8.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-win32.whl", hash = "sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271"},
|
||||||
|
{file = "Pillow-8.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-win32.whl", hash = "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140"},
|
||||||
|
{file = "Pillow-8.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021"},
|
||||||
|
{file = "Pillow-8.0.1-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6"},
|
||||||
|
{file = "Pillow-8.0.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb"},
|
||||||
|
{file = "Pillow-8.0.1-pp37-pypy37_pp73-win32.whl", hash = "sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8"},
|
||||||
|
{file = "Pillow-8.0.1.tar.gz", hash = "sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e"},
|
||||||
|
]
|
||||||
|
prettytable = [
|
||||||
|
{file = "prettytable-2.0.0-py3-none-any.whl", hash = "sha256:5dc7fcaca227f48deacd86958ae9d7b8c31a186fcb354bbb066763f20adf3eb9"},
|
||||||
|
{file = "prettytable-2.0.0.tar.gz", hash = "sha256:e37acd91976fe6119172771520e58d1742c8479703489321dc1d9c85e7259922"},
|
||||||
|
]
|
||||||
|
pyobjc-core = [
|
||||||
|
{file = "pyobjc-core-7.0.1.tar.gz", hash = "sha256:7213bfd48c49f5b4d479256924e0120d728ed449de8188cba9e204c434ed07f2"},
|
||||||
|
{file = "pyobjc_core-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6f84a5744e44ec709daca1e66b95c3c010e4159bc2cfc442c27c0d28b0456eda"},
|
||||||
|
{file = "pyobjc_core-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2fdba7997d5c9d518256f9d2e9f7780fcc6332b0371207374f38d7e9fad7bc8"},
|
||||||
|
{file = "pyobjc_core-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:758cf96f3848c6e177d6ad94d44fec1b9ea5e32ca066513184d8f1e70d71ff6e"},
|
||||||
|
{file = "pyobjc_core-7.0.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:61c756c9bd5c55e9137cf0549f1d931dd1e1bff30a1cc97e46e55b94d5dc5d97"},
|
||||||
|
]
|
||||||
|
pyobjc-framework-cocoa = [
|
||||||
|
{file = "pyobjc-framework-Cocoa-7.0.1.tar.gz", hash = "sha256:8a545b47b2021884bd8e5644ac32ee6d99a1f8e6a45cab3e6d1b999adf968630"},
|
||||||
|
{file = "pyobjc_framework_Cocoa-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4675accc4720b42f456a35ba7cdd9e1cb44b9b84fcc600beef120ae05d2c5d27"},
|
||||||
|
{file = "pyobjc_framework_Cocoa-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42e106c3d688e66b1032b0819daa842a78eff6f7646b5af4be8774d0c8f5e200"},
|
||||||
|
{file = "pyobjc_framework_Cocoa-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8aa715fa1ff367330fc58eadc1747e222bdf854b9ece6936487c9c4f4e2627d3"},
|
||||||
|
{file = "pyobjc_framework_Cocoa-7.0.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:1d9de6b0612a5e24899522a797425c834405a536db41ba06a19df01b7008eeae"},
|
||||||
|
]
|
||||||
|
pyobjc-framework-quartz = [
|
||||||
|
{file = "pyobjc-framework-Quartz-7.0.1.tar.gz", hash = "sha256:8d76cabfbae38102301f44f1edb3ab4c959f18ed0c828cfff1693a3c559945ef"},
|
||||||
|
{file = "pyobjc_framework_Quartz-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fbf8d816da04f0705707906fb751bd360d652914ace3989ed6e55ff6a7a79c62"},
|
||||||
|
{file = "pyobjc_framework_Quartz-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1854a0b8baea76e6c43812ecf26dd6fc5a11e9cada212b36bf35e23e670750c"},
|
||||||
|
{file = "pyobjc_framework_Quartz-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:019982c0c1a74e68f29c9f961292d4c752a8fdd6d806197a73a41aa6c9fa00a9"},
|
||||||
|
{file = "pyobjc_framework_Quartz-7.0.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:9be4d99d04abd9f9147cc9e83b87324efc0b832320caee310defc71798201816"},
|
||||||
|
]
|
||||||
|
pystray = [
|
||||||
|
{file = "pystray-0.17.2-py2.py3-none-any.whl", hash = "sha256:b8fa8a708744117112f4958cc5b887e2fcaeaa4c0b1e5de62cca74bfb4a1a18b"},
|
||||||
|
{file = "pystray-0.17.2-py3.8.egg", hash = "sha256:101e61be624b759e9faac2ecabb8713d9d22a6b57792b1c50c3197be62fa4a42"},
|
||||||
|
{file = "pystray-0.17.2.tar.gz", hash = "sha256:c8e2256fabfe803feab268e9af143ec3e8de32fc1ed652ba9f1b47bb3777d1e9"},
|
||||||
|
]
|
||||||
|
python-xlib = [
|
||||||
|
{file = "python-xlib-0.29.tar.gz", hash = "sha256:e4bcb756f4aa05be7b82ee21de0ba04d73414018727b42ebd9fbcf409ea75d13"},
|
||||||
|
{file = "python_xlib-0.29-py2.py3-none-any.whl", hash = "sha256:044095d1b1a5eab5a79f8d0b66f811a9ac6acd038dd3bae00cb3dbe90b32a7e3"},
|
||||||
|
]
|
||||||
|
requests = [
|
||||||
|
{file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
|
||||||
|
{file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
||||||
|
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
|
||||||
|
]
|
||||||
|
tcping = [
|
||||||
|
{file = "tcping-0.1.1rc1-py2-none-any.whl", hash = "sha256:48ad03a463cf6d963454d45c199843dc0ad4fb0cd0dde6ab648e35364cbfe34a"},
|
||||||
|
{file = "tcping-0.1.1rc1-py2.7.egg", hash = "sha256:10843d60e2c3abbdf1b4aed0d1133c25d7bc15310d61fd8a0dbd91236d646c29"},
|
||||||
|
{file = "tcping-0.1.1rc1.tar.gz", hash = "sha256:557d5e928601e5a31e55abe20c6b9fff18bdc74a1e1d620d6b28b2f7c7a26606"},
|
||||||
|
]
|
||||||
|
urllib3 = [
|
||||||
|
{file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"},
|
||||||
|
{file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"},
|
||||||
|
]
|
||||||
|
wcwidth = [
|
||||||
|
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
||||||
|
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||||
|
]
|
||||||
|
websocket-client = [
|
||||||
|
{file = "websocket_client-0.57.0-py2.py3-none-any.whl", hash = "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549"},
|
||||||
|
{file = "websocket_client-0.57.0.tar.gz", hash = "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010"},
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "munyal"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Client of Munyal - A selfhosted cloud storage"
|
||||||
|
authors = ["kirbylife <kirbylife@protonmail.com>"]
|
||||||
|
license = "GPL v2.0"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.9"
|
||||||
|
websocket_client = "^0.57.0"
|
||||||
|
tcping = "^0.1.1-rc.1"
|
||||||
|
requests = "^2.25.1"
|
||||||
|
pystray = "^0.17.2"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
363
temp/client.py
363
temp/client.py
|
@ -1,363 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import ftplib
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
from copy import deepcopy
|
|
||||||
from random import randint
|
|
||||||
from shutil import rmtree
|
|
||||||
from threading import Thread
|
|
||||||
from time import sleep
|
|
||||||
from tkinter import Button, Entry, Label, StringVar, Tk
|
|
||||||
|
|
||||||
from requests import post
|
|
||||||
|
|
||||||
import rethinkdb as r
|
|
||||||
from compare_json import compare_json
|
|
||||||
from dir_to_json import get_json
|
|
||||||
from tcping import Ping
|
|
||||||
|
|
||||||
#ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/another"
|
|
||||||
ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/"
|
|
||||||
IP = "localhost"
|
|
||||||
USERNAME = "munyal"
|
|
||||||
PASSWORD = "123"
|
|
||||||
HOSTNAME = socket.gethostname() + str(randint(1, 100000000))
|
|
||||||
SKIP_UPLOAD = []
|
|
||||||
FLAG_DOWNLOAD = False
|
|
||||||
pending_routes = []
|
|
||||||
|
|
||||||
|
|
||||||
def check_network(port):
|
|
||||||
ping = Ping(IP, port, 20)
|
|
||||||
ping.ping(1)
|
|
||||||
print(SKIP_UPLOAD)
|
|
||||||
return ping.result.rows[0].successed == 1
|
|
||||||
|
|
||||||
|
|
||||||
def watch_dir():
|
|
||||||
global pending_routes
|
|
||||||
folder = os.path.join(os.getenv("HOME"), ".munyal")
|
|
||||||
if not os.path.exists(folder):
|
|
||||||
pathlib.Path(folder).mkdir(parents=True)
|
|
||||||
|
|
||||||
actual_file = os.path.join(folder, "actual.json")
|
|
||||||
if not os.path.exists(actual_file):
|
|
||||||
with open(actual_file, "w") as f:
|
|
||||||
f.write(json.dumps([]))
|
|
||||||
pending_file = os.path.join(folder, "pending_routes.json")
|
|
||||||
if not os.path.exists(pending_file):
|
|
||||||
with open(pending_file, "w") as f:
|
|
||||||
f.write(json.dumps([]))
|
|
||||||
|
|
||||||
with open(actual_file, "r") as f:
|
|
||||||
actual = json.loads(f.read())
|
|
||||||
actual = get_json(ORIGINAL)
|
|
||||||
new = deepcopy(actual)
|
|
||||||
with open(pending_file, "r") as f:
|
|
||||||
pending_routes = json.loads(f.read())
|
|
||||||
new = get_json(ORIGINAL)
|
|
||||||
while True:
|
|
||||||
sleep(0.2)
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
jsons = compare_json(deepcopy(actual), deepcopy(new))
|
|
||||||
except:
|
|
||||||
new = get_json(ORIGINAL)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
changes = get_changes(jsons)
|
|
||||||
|
|
||||||
pending_routes = pending_routes + changes
|
|
||||||
with open(pending_file, "w") as f:
|
|
||||||
f.write(json.dumps(pending_routes, indent=4))
|
|
||||||
|
|
||||||
actual = deepcopy(new)
|
|
||||||
with open(actual_file, "w") as f:
|
|
||||||
f.write(json.dumps(actual, indent=4))
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
new = get_json(ORIGINAL)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def need_deleted(items, route):
|
|
||||||
out = []
|
|
||||||
for item in items:
|
|
||||||
if item.get("is_file"):
|
|
||||||
out.append({
|
|
||||||
"action": "delete",
|
|
||||||
"route": os.path.join(route, item.get('name'))
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if item.get('content'):
|
|
||||||
out = out + need_deleted(item.get("content"),
|
|
||||||
os.path.join(route, item.get('name')))
|
|
||||||
else:
|
|
||||||
out.append({
|
|
||||||
"action": "delete_folder",
|
|
||||||
"route": os.path.join(route, item.get('name'))
|
|
||||||
})
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def need_added(items, route):
|
|
||||||
out = []
|
|
||||||
for item in items:
|
|
||||||
if item.get("is_file"):
|
|
||||||
out.append({
|
|
||||||
"action": "add",
|
|
||||||
"route": os.path.join(route, item.get('name'))
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if item.get('content'):
|
|
||||||
out = out + need_added(item.get("content"),
|
|
||||||
os.path.join(route, item.get('name')))
|
|
||||||
else:
|
|
||||||
out.append({
|
|
||||||
"action": "add_folder",
|
|
||||||
"route": os.path.join(route, item.get('name'))
|
|
||||||
})
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def get_changes(jsons, route=''):
|
|
||||||
delete, add = jsons
|
|
||||||
out = need_deleted(delete, route) + need_added(add, route)
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def _is_ftp_dir(ftp_handle, name):
|
|
||||||
original_cwd = ftp_handle.pwd()
|
|
||||||
try:
|
|
||||||
ftp_handle.cwd(name)
|
|
||||||
ftp_handle.cwd(original_cwd)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _make_parent_dir(fpath):
|
|
||||||
#dirname = os.path.dirname(fpath)
|
|
||||||
dirname = os.path.join(ORIGINAL, fpath)
|
|
||||||
while not os.path.exists(dirname):
|
|
||||||
try:
|
|
||||||
os.makedirs(dirname)
|
|
||||||
print("created {0}".format(dirname))
|
|
||||||
except:
|
|
||||||
_make_parent_dir(dirname)
|
|
||||||
|
|
||||||
|
|
||||||
def _download_ftp_file(ftp_handle, name, dest, overwrite):
|
|
||||||
if not os.path.exists(dest) or overwrite is True:
|
|
||||||
try:
|
|
||||||
with open(dest, 'wb') as f:
|
|
||||||
ftp_handle.retrbinary("RETR {0}".format(name), f.write)
|
|
||||||
print("downloaded: {0}".format(dest))
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("FAILED: {0}".format(dest))
|
|
||||||
else:
|
|
||||||
print("already exists: {0}".format(dest))
|
|
||||||
|
|
||||||
|
|
||||||
def _mirror_ftp_dir(ftp_handle, name, overwrite):
|
|
||||||
for item in ftp_handle.nlst(name):
|
|
||||||
SKIP_UPLOAD.append(item)
|
|
||||||
if _is_ftp_dir(ftp_handle, item):
|
|
||||||
_make_parent_dir(item.lstrip("/"))
|
|
||||||
_mirror_ftp_dir(ftp_handle, os.path.join(name, item), overwrite)
|
|
||||||
else:
|
|
||||||
_download_ftp_file(ftp_handle, item, os.path.join(ORIGINAL, item),
|
|
||||||
overwrite)
|
|
||||||
|
|
||||||
|
|
||||||
def download_ftp_tree(overwrite=False):
|
|
||||||
FLAG_DOWNLOAD = True
|
|
||||||
ftp_handle = ftplib.FTP(IP, USERNAME, PASSWORD)
|
|
||||||
path = ""
|
|
||||||
original_directory = os.getcwd()
|
|
||||||
os.chdir(ORIGINAL)
|
|
||||||
_mirror_ftp_dir(ftp_handle, path, overwrite)
|
|
||||||
os.chdir(original_directory)
|
|
||||||
ftp_handle.close()
|
|
||||||
FLAG_DOWNLOAD = False
|
|
||||||
|
|
||||||
|
|
||||||
def upload(*args):
|
|
||||||
global SKIP_UPLOAD
|
|
||||||
global pending_routes
|
|
||||||
print("Modulo de subida listo")
|
|
||||||
while True:
|
|
||||||
sleep(0.1)
|
|
||||||
if check_network('21') and pending_routes:
|
|
||||||
change = pending_routes.pop(0)
|
|
||||||
while FLAG_DOWNLOAD:
|
|
||||||
print("Wait")
|
|
||||||
if change['route'] not in SKIP_UPLOAD:
|
|
||||||
ftp = ftplib.FTP(IP, USERNAME, PASSWORD)
|
|
||||||
route = os.path.join(ORIGINAL, change['route'])
|
|
||||||
success = False
|
|
||||||
while not success:
|
|
||||||
try:
|
|
||||||
if change['action'] == 'add':
|
|
||||||
print("Agregar archivo")
|
|
||||||
with open(route, "rb") as f:
|
|
||||||
ftp.storbinary("STOR /" + change['route'], f)
|
|
||||||
elif change['action'] == 'add_folder':
|
|
||||||
print("Agregar carpeta")
|
|
||||||
ftp.mkd(change['route'])
|
|
||||||
elif change['action'] == 'delete':
|
|
||||||
print("Borrar archivo")
|
|
||||||
ftp.delete(change['route'])
|
|
||||||
elif change['action'] == 'delete_folder':
|
|
||||||
print("Borrar carpeta")
|
|
||||||
ftp.rmd(change['route'])
|
|
||||||
else:
|
|
||||||
print("Unexpected action")
|
|
||||||
except:
|
|
||||||
print("Error uploading\n")
|
|
||||||
r = post("http://" + IP + ':5000/upload',
|
|
||||||
data={
|
|
||||||
'host': HOSTNAME,
|
|
||||||
'action': change['action'],
|
|
||||||
'route': change['route']
|
|
||||||
})
|
|
||||||
r = json.loads(r.text)
|
|
||||||
print(json.dumps(r, indent=4))
|
|
||||||
success = r['status'] == 'ok'
|
|
||||||
ftp.close()
|
|
||||||
else:
|
|
||||||
SKIP_UPLOAD.pop()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def download(*args):
|
|
||||||
global SKIP_UPLOAD
|
|
||||||
while True:
|
|
||||||
sleep(1)
|
|
||||||
if check_network(28015) and check_network(21):
|
|
||||||
try:
|
|
||||||
download_ftp_tree(overwrite=False)
|
|
||||||
|
|
||||||
print("Modulo de descarga listo")
|
|
||||||
print("Carpeta " + ORIGINAL)
|
|
||||||
r.connect(IP, 28015).repl()
|
|
||||||
cursor = r.table("changes").changes().run()
|
|
||||||
for document in cursor:
|
|
||||||
change = document['new_val']
|
|
||||||
#print(change)
|
|
||||||
if change['host'] != HOSTNAME:
|
|
||||||
FLAG_DOWNLOAD = True
|
|
||||||
route = os.path.join(ORIGINAL, change['route'])
|
|
||||||
SKIP_UPLOAD.append(change['route'])
|
|
||||||
try:
|
|
||||||
if change['action'] == 'add':
|
|
||||||
print("Agregar archivo")
|
|
||||||
ftp = ftplib.FTP(IP, USERNAME, PASSWORD)
|
|
||||||
with open(route, "wb") as f:
|
|
||||||
ftp.retrbinary("RETR /" + change['route'],
|
|
||||||
f.write)
|
|
||||||
ftp.close()
|
|
||||||
elif change['action'] == 'add_folder':
|
|
||||||
print("Agregar carpeta")
|
|
||||||
pathlib.Path(route).mkdir(parents=True)
|
|
||||||
elif change['action'] == 'delete':
|
|
||||||
print("Borrar archivo")
|
|
||||||
pathlib.Path(route).unlink()
|
|
||||||
elif change['action'] == 'delete_folder':
|
|
||||||
print("Borrar carpeta")
|
|
||||||
rmtree(route)
|
|
||||||
else:
|
|
||||||
print("Unexpected action")
|
|
||||||
except OSError as e:
|
|
||||||
print("Error en el sistema operativo")
|
|
||||||
except:
|
|
||||||
print("Error en el servidor FTP")
|
|
||||||
FLAG_DOWNLOAD = False
|
|
||||||
except rethinkdb.errors.ReqlDriverError as e:
|
|
||||||
print("Conection refused with rethinkdb")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def run_client(window, password, username, host, folder):
|
|
||||||
global PASSWORD
|
|
||||||
global IP
|
|
||||||
global USERNAME
|
|
||||||
global ORIGINAL
|
|
||||||
|
|
||||||
PASSWORD = password.get()
|
|
||||||
USERNAME = username.get()
|
|
||||||
IP = host.get()
|
|
||||||
ORIGINAL = folder.get()
|
|
||||||
|
|
||||||
if not os.path.exists(ORIGINAL):
|
|
||||||
pathlib.Path(ORIGINAL).mkdir(parents=True)
|
|
||||||
|
|
||||||
download_thread = Thread(target=download, args=[window])
|
|
||||||
download_thread.setDaemon(True)
|
|
||||||
download_thread.start()
|
|
||||||
|
|
||||||
upload_thread = Thread(target=upload, args=[window])
|
|
||||||
upload_thread.setDaemon(True)
|
|
||||||
upload_thread.start()
|
|
||||||
|
|
||||||
watch_dir_thread = Thread(target=watch_dir)
|
|
||||||
watch_dir_thread.setDaemon(True)
|
|
||||||
watch_dir_thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
root = Tk()
|
|
||||||
root.geometry("200x300")
|
|
||||||
root.title("MUNYAL")
|
|
||||||
|
|
||||||
host = StringVar()
|
|
||||||
host.set("localhost")
|
|
||||||
host_field = Entry(root, textvariable=host)
|
|
||||||
|
|
||||||
user = StringVar()
|
|
||||||
user.set("munyal")
|
|
||||||
user_field = Entry(root, textvariable=user)
|
|
||||||
|
|
||||||
passwd = StringVar()
|
|
||||||
passwd.set("123")
|
|
||||||
passwd_field = Entry(root, textvariable=passwd, show="*")
|
|
||||||
|
|
||||||
folder = StringVar()
|
|
||||||
folder.set(os.path.join(os.getenv("HOME"), "Munyal"))
|
|
||||||
folder_field = Entry(root, textvariable=folder)
|
|
||||||
|
|
||||||
connect = Button(
|
|
||||||
root,
|
|
||||||
text="Conectar",
|
|
||||||
command=lambda: run_client(root, passwd, user, host, folder))
|
|
||||||
|
|
||||||
Label(root, text="MUNYAL").pack()
|
|
||||||
Label(root, text="").pack()
|
|
||||||
Label(root, text="Ruta del servidor").pack()
|
|
||||||
host_field.pack()
|
|
||||||
Label(root, text="").pack()
|
|
||||||
Label(root, text="Nombre de usuario").pack()
|
|
||||||
user_field.pack()
|
|
||||||
Label(root, text="").pack()
|
|
||||||
Label(root, text="Contraseña").pack()
|
|
||||||
passwd_field.pack()
|
|
||||||
Label(root, text="").pack()
|
|
||||||
Label(root, text="Carpeta a sincronizar").pack()
|
|
||||||
folder_field.pack()
|
|
||||||
Label(root, text="").pack()
|
|
||||||
connect.pack()
|
|
||||||
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
sys.exit(main(sys.argv))
|
|
|
@ -1,50 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from dir_to_json import get_json
|
|
||||||
|
|
||||||
|
|
||||||
def compare_json(json1, json2):
|
|
||||||
bckup1, bckup2 = json1[:], json2[:]
|
|
||||||
items1 = list(enumerate(json1))
|
|
||||||
items2 = list(enumerate(json2))
|
|
||||||
for i, item1 in items1:
|
|
||||||
for j, item2 in items2:
|
|
||||||
if item1["name"] == item2["name"]:
|
|
||||||
if item1["is_file"] == True == item2["is_file"]:
|
|
||||||
if item1["checksum"] == item2["checksum"]:
|
|
||||||
json1[i] = None
|
|
||||||
json2[j] = None
|
|
||||||
'''
|
|
||||||
else:
|
|
||||||
json1[i]["tag"] = "update"
|
|
||||||
json2[j] = None
|
|
||||||
'''
|
|
||||||
elif item1["is_file"] == False == item2["is_file"]:
|
|
||||||
new_json1, new_json2 = compare_json(item1["content"], item2["content"])
|
|
||||||
if len(new_json1) == 0:
|
|
||||||
json1[i] = None
|
|
||||||
else:
|
|
||||||
json1[i]["content"] = new_json1
|
|
||||||
if len(new_json2) == 0:
|
|
||||||
json2[j] = None
|
|
||||||
else:
|
|
||||||
json2[j]["content"] = new_json2
|
|
||||||
elif item1["is_file"] != item2["is_file"]:##### Caso hipotetico imposible #####
|
|
||||||
json1[i]["tag"] == "delete"
|
|
||||||
json1 = list(filter(None, json1))
|
|
||||||
json2 = list(filter(None, json2))
|
|
||||||
return json1, json2
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
json1 = get_json("/home/kirbylife/Proyectos/munyal_test/original")
|
|
||||||
json2 = get_json("/home/kirbylife/Proyectos/munyal_test/copy")
|
|
||||||
except:
|
|
||||||
print("error outside")
|
|
||||||
json1, json2 = compare_json(json1, json2)
|
|
||||||
#print(len(json1), len(json2))
|
|
||||||
print(json.dumps(json1, indent=4))
|
|
||||||
print("\n============\n")
|
|
||||||
print(json.dumps(json2, indent=4))
|
|
|
@ -1,49 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
from hashlib import md5
|
|
||||||
|
|
||||||
|
|
||||||
def md5sum(filename):
|
|
||||||
try:
|
|
||||||
hash = md5()
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
for chunk in iter(lambda: f.read(128 * hash.block_size), b""):
|
|
||||||
hash.update(chunk)
|
|
||||||
return hash.hexdigest()
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_json(path):
|
|
||||||
out = []
|
|
||||||
items = os.listdir(path)
|
|
||||||
try:
|
|
||||||
for item in items:
|
|
||||||
if item[0] != ".":
|
|
||||||
item_json = {
|
|
||||||
"name": item
|
|
||||||
}
|
|
||||||
route = os.path.join(path, item)
|
|
||||||
if os.path.isdir(route):
|
|
||||||
item_json["is_file"] = False
|
|
||||||
item_json["content"] = get_json(route)
|
|
||||||
elif os.path.isfile(route):
|
|
||||||
item_json["is_file"] = True
|
|
||||||
item_json["size"] = os.path.getsize(route)
|
|
||||||
item_json["last_modified"] = os.path.getmtime(route)
|
|
||||||
item_json["created_at"] = os.path.getctime(route)
|
|
||||||
checksum = md5sum(route)
|
|
||||||
if checksum:
|
|
||||||
item_json["checksum"] = checksum
|
|
||||||
else:
|
|
||||||
item = None
|
|
||||||
out.append(item_json)
|
|
||||||
except:
|
|
||||||
return get_json(path)
|
|
||||||
return out
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
output = get_json("/media/kirbylife/DATOS/Proyectos/PyCharmProjects/Munyal/folder_test")
|
|
||||||
print(json.dumps(output, indent=4))
|
|
|
@ -1,33 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from copy import deepcopy
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from compare_json import compare_json
|
|
||||||
from dir_to_json import get_json
|
|
||||||
|
|
||||||
ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/original"
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
actual = get_json(ORIGINAL)
|
|
||||||
new = deepcopy(actual)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
delete, add = compare_json(deepcopy(actual), deepcopy(new))
|
|
||||||
for item in delete:
|
|
||||||
if item.get("tag"):
|
|
||||||
if item.get("tag") == "update":
|
|
||||||
print("Actualizado el archivo {}".format(item.get("name")))
|
|
||||||
else:
|
|
||||||
print("borrado el archivo {}".format(item.get("name")))
|
|
||||||
|
|
||||||
for item in add:
|
|
||||||
print("Agregado el archivo {}".format(item.get("name")))
|
|
||||||
actual = deepcopy(new)
|
|
||||||
new = get_json(ORIGINAL)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
sys.exit(main(sys.argv))
|
|
|
@ -1,63 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import json
|
|
||||||
from random import randint
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
import rethinkdb as r
|
|
||||||
from flask import Flask, jsonify, request
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
def md5sum(filename):
|
|
||||||
try:
|
|
||||||
hash = md5()
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
for chunk in iter(lambda: f.read(128 * hash.block_size), b""):
|
|
||||||
hash.update(chunk)
|
|
||||||
return hash.hexdigest()
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
|
||||||
def index():
|
|
||||||
return('''
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Munyal API</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Munyal private API</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
''')
|
|
||||||
|
|
||||||
@app.route("/upload", methods=["POST"])
|
|
||||||
def upload():
|
|
||||||
try:
|
|
||||||
r.connect( "localhost", 28015).repl()
|
|
||||||
cursor = r.table("changes")
|
|
||||||
|
|
||||||
host = request.form.get("host")
|
|
||||||
action = request.form.get("action")
|
|
||||||
route = request.form.get("route")
|
|
||||||
obj = {
|
|
||||||
'id' : str(time()).split('.')[0] + str(randint(1, 1000000)),
|
|
||||||
'action': action,
|
|
||||||
'route': route,
|
|
||||||
'host': host
|
|
||||||
}
|
|
||||||
status = 'ok'
|
|
||||||
try:
|
|
||||||
cursor.insert(obj).run()
|
|
||||||
except:
|
|
||||||
status = 'error'
|
|
||||||
except:
|
|
||||||
status = 'error'
|
|
||||||
obj['status'] = status
|
|
||||||
return jsonify(obj)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(debug=True)
|
|
|
@ -1,118 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import ftplib
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
from copy import deepcopy
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from requests import post
|
|
||||||
|
|
||||||
from compare_json import compare_json
|
|
||||||
from dir_to_json import get_json
|
|
||||||
|
|
||||||
|
|
||||||
def need_deleted(items, route):
|
|
||||||
out = []
|
|
||||||
for item in items:
|
|
||||||
if item.get("is_file"):
|
|
||||||
out.append({"action": "delete", "route": os.path.join(route, item.get('name'))})
|
|
||||||
else:
|
|
||||||
if item.get('content'):
|
|
||||||
out = out + need_deleted(item.get("content"), os.path.join(route, item.get('name')))
|
|
||||||
else:
|
|
||||||
out.append({"action": "delete_folder", "route": os.path.join(route, item.get('name'))})
|
|
||||||
return out
|
|
||||||
|
|
||||||
def need_added(items, route):
|
|
||||||
out = []
|
|
||||||
for item in items:
|
|
||||||
if item.get("is_file"):
|
|
||||||
out.append({"action": "add", "route": os.path.join(route, item.get('name'))})
|
|
||||||
else:
|
|
||||||
if item.get('content'):
|
|
||||||
out = out + need_added(item.get("content"), os.path.join(route, item.get('name')))
|
|
||||||
else:
|
|
||||||
out.append({"action": "add_folder", "route": os.path.join(route, item.get('name'))})
|
|
||||||
return out
|
|
||||||
|
|
||||||
def get_changes(jsons, route=''):
|
|
||||||
delete, add = jsons
|
|
||||||
out = need_deleted(delete, route) + need_added(add, route)
|
|
||||||
return out
|
|
||||||
'''
|
|
||||||
out = []
|
|
||||||
|
|
||||||
delete, add = jsons
|
|
||||||
for item in delete:
|
|
||||||
if item.get("is_file"):
|
|
||||||
|
|
||||||
if item.get("tag"):
|
|
||||||
if item.get("tag") == "update":
|
|
||||||
out.append({"action": "update", "file": os.path.join(route, item.get('name'))})
|
|
||||||
elif item.get("tag") == "delete":##### Caso hipotetico imposible #####
|
|
||||||
if item.get("is_file"):
|
|
||||||
out.append({"action": "delete", "file": os.path.join(route, item.get('name'))})
|
|
||||||
else:
|
|
||||||
out.append({"action": "delete_folder", "file": os.path.join(route, item.get('name'))})
|
|
||||||
|
|
||||||
else:
|
|
||||||
out.append({"action": "delete", "file": os.path.join(route, item.get('name'))})
|
|
||||||
|
|
||||||
out.append({"action": "delete", "file": os.path.join(route, item.get('name'))})
|
|
||||||
else:
|
|
||||||
return out
|
|
||||||
'''
|
|
||||||
|
|
||||||
ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/original"
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
ftp = ftplib.FTP('localhost', 'munyal', '123')
|
|
||||||
actual = get_json(ORIGINAL)
|
|
||||||
new = deepcopy(actual)
|
|
||||||
switch = lambda x,o,d=None: o.get(x) if o.get(x) else d if d else lambda *args: None
|
|
||||||
while True:
|
|
||||||
sleep(1)
|
|
||||||
jsons = compare_json(deepcopy(actual), deepcopy(new))
|
|
||||||
changes = get_changes(jsons)
|
|
||||||
for change in changes:
|
|
||||||
route = os.path.join(ORIGINAL, change['route'])
|
|
||||||
success = False
|
|
||||||
while not success:
|
|
||||||
# ~ try:
|
|
||||||
x = change['route']
|
|
||||||
if change['action'] == 'add':
|
|
||||||
print("Agregar archivo")
|
|
||||||
with open(route, "rb") as f:
|
|
||||||
ftp.storbinary("STOR /" + x, f)
|
|
||||||
elif change['action'] == 'add_folder':
|
|
||||||
print("Agregar carpeta")
|
|
||||||
ftp.mkd(x)
|
|
||||||
elif change['action'] == 'delete':
|
|
||||||
print("Borrar archivo")
|
|
||||||
ftp.delete(x)
|
|
||||||
elif change['action'] == 'delete_folder':
|
|
||||||
print("Borrar carpeta")
|
|
||||||
ftp.rmd(x)
|
|
||||||
else:
|
|
||||||
print("Unexpected action")
|
|
||||||
r = post('http://127.0.0.1:5000/upload', data={
|
|
||||||
'host': socket.gethostname(),
|
|
||||||
'action': change['action'],
|
|
||||||
'route': change['route']
|
|
||||||
}
|
|
||||||
)
|
|
||||||
r = json.loads(r.text)
|
|
||||||
print(json.dumps(r, indent=4))
|
|
||||||
success = r['status'] == 'ok'
|
|
||||||
# ~ except:
|
|
||||||
# ~ print("Error uploading, retrying again\n")
|
|
||||||
actual = deepcopy(new)
|
|
||||||
new = get_json(ORIGINAL)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
sys.exit(main(sys.argv))
|
|
Loading…
Reference in New Issue