MVP~
This commit is contained in:
parent
fe7bd5a373
commit
bcc78eb022
4 changed files with 384 additions and 11 deletions
1
Pipfile
1
Pipfile
|
@ -10,6 +10,7 @@ gunicorn = "*"
|
|||
flask-redis = "*"
|
||||
|
||||
[dev-packages]
|
||||
python-language-server = {extras = ["all"], version = "*"}
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
|
321
Pipfile.lock
generated
321
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "44417add08bc4e06a9422d66c18bd8e4e854fd19a0cda4f635b552cc29c0a7c8"
|
||||
"sha256": "efe46f7b1fd34a7a36b922ae5ebe7148c229aacc045eb0f00791555109f327ca"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -420,5 +420,322 @@
|
|||
"version": "==5.4.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
"develop": {
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877",
|
||||
"sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.2'",
|
||||
"version": "==2.9.3"
|
||||
},
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:9e136c472c475f4ee4978b51a88a494bfcd4e3ed17950a44a988d9e434837bea",
|
||||
"sha256:cae4bc0fb616408191af41d062d7ec7ef8679c7f27b068875ca3a9e2878d5443"
|
||||
],
|
||||
"version": "==1.5.5"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839",
|
||||
"sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"
|
||||
],
|
||||
"version": "==3.8.4"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7",
|
||||
"sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"
|
||||
],
|
||||
"markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
|
||||
"version": "==5.10.1"
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20",
|
||||
"sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.17.2"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
"sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7",
|
||||
"sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a",
|
||||
"sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c",
|
||||
"sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc",
|
||||
"sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f",
|
||||
"sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09",
|
||||
"sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442",
|
||||
"sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e",
|
||||
"sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029",
|
||||
"sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61",
|
||||
"sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb",
|
||||
"sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0",
|
||||
"sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35",
|
||||
"sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42",
|
||||
"sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1",
|
||||
"sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad",
|
||||
"sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443",
|
||||
"sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd",
|
||||
"sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9",
|
||||
"sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148",
|
||||
"sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38",
|
||||
"sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55",
|
||||
"sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36",
|
||||
"sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a",
|
||||
"sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b",
|
||||
"sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44",
|
||||
"sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6",
|
||||
"sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69",
|
||||
"sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4",
|
||||
"sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84",
|
||||
"sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de",
|
||||
"sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28",
|
||||
"sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c",
|
||||
"sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1",
|
||||
"sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8",
|
||||
"sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b",
|
||||
"sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.7.1"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"parso": {
|
||||
"hashes": [
|
||||
"sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea",
|
||||
"sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
"sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca",
|
||||
"sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.4.1"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
|
||||
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
|
||||
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
|
||||
],
|
||||
"version": "==2.6.0"
|
||||
},
|
||||
"pydocstyle": {
|
||||
"hashes": [
|
||||
"sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc",
|
||||
"sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"
|
||||
],
|
||||
"version": "==6.1.1"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
|
||||
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9",
|
||||
"sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"
|
||||
],
|
||||
"version": "==2.12.2"
|
||||
},
|
||||
"python-jsonrpc-server": {
|
||||
"hashes": [
|
||||
"sha256:62c543e541f101ec5b57dc654efc212d2c2e3ea47ff6f54b2e7dcb36ecf20595",
|
||||
"sha256:e5a908ff182e620aac07db5f57887eeb0afe33993008f57dc1b85b594cea250c"
|
||||
],
|
||||
"version": "==0.4.0"
|
||||
},
|
||||
"python-language-server": {
|
||||
"extras": [
|
||||
"all"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:9984c84a67ee2c5102c8e703215f407fcfa5e62b0ae86c9572d0ada8c4b417b0",
|
||||
"sha256:a0ad0aca03f4a20c1c40f4f230c6773eac82c9b7cdb026cb09ba10237f4815d5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.36.2"
|
||||
},
|
||||
"rope": {
|
||||
"hashes": [
|
||||
"sha256:2847220bf72ead09b5abe72b1edc9cacff90ab93663ece06913fc97324167870",
|
||||
"sha256:b00fbc064a26fc62d7220578a27fd639b2fad57213663cc396c137e92d73f10f"
|
||||
],
|
||||
"version": "==0.22.0"
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:2404879cda71495fc4d5cbc445ed52fdaddf352b36e40be8dcc63147cb4edabe",
|
||||
"sha256:68eb94073fc486091447fcb0501efd6560a0e5a1839ba249e5ff3c4c93f05f90"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==60.5.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1",
|
||||
"sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"toml": {
|
||||
"hashes": [
|
||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e",
|
||||
"sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"
|
||||
],
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"ujson": {
|
||||
"hashes": [
|
||||
"sha256:00d6ea9702c2eaeaf1a826934eaba1b4c609c873379bf54e36ba7b7e128edf94",
|
||||
"sha256:05aa6c7297a22081f65497b6f586de6b7060ea47c3ecda80896f47200e9dbf04",
|
||||
"sha256:06bed66ae62d517f67a61cf53c056800b35ef364270723168a1db62702e2d30c",
|
||||
"sha256:08265db5ccff8b521ff68aee13a417d68cca784d7e711d961b92fda6ccffcc4f",
|
||||
"sha256:083c1078e4de3a39019e590c43865b17e07a763fee25b012e650bb4f42c89703",
|
||||
"sha256:0cae4a9c141856f7ad1a79c17ff1aaebf7fd8faa2f2c2614c37d6f82ed261d96",
|
||||
"sha256:110633a8dda6c8ca78090292231e15381f8b2423e998399d4bc5f135149c722b",
|
||||
"sha256:173b90a2c2836ee42f708df88ecfe3efbc4d868df73c9fcea8cb8f6f3ab93892",
|
||||
"sha256:202ae52f4a53f03c42ead6d046b1a146517e93bd757f517bdeef0a26228e0260",
|
||||
"sha256:31671ad99f0395eb881d698f2871dc64ff00fbd4380c5d9bfd8bff3d4c8f8d88",
|
||||
"sha256:368f855779fded560724a6448838304621f498113a116d66bc5ed5ad5ad3ca92",
|
||||
"sha256:4155a7c29bf330329519027c815e15e381c1fff22f50d26f135584d482bbd95d",
|
||||
"sha256:452990c2b18445a7379a45873527d2ec47789b9289c13a17a3c1cc76b9641126",
|
||||
"sha256:4ba63b789d83ca92237dbc72041a268d91559f981c01763a107105878bae442e",
|
||||
"sha256:4dd97e45a0f450ba2c43cda18147e54b8e41e886c22e3506c62f7d61e9e53b0d",
|
||||
"sha256:51142c9d40439f299594e399bef8892a16586ded54c88d3af926865ca221a177",
|
||||
"sha256:5304ad25d100d50b5bc8513ef110335df678f66c7ccf3d4728c0c3aa69e08e0c",
|
||||
"sha256:585271d6ad545a2ccfc237582f70c160e627735c89d0ca2bde24afa321bc0750",
|
||||
"sha256:5c8a884d60dd2eed2fc95a9474d57ead82adf254f54caffb3d9e8ed185c49aba",
|
||||
"sha256:644552d1e89983c08d0c24358fbcb5829ae5b5deee9d876e16d20085cfa7dc81",
|
||||
"sha256:681fed63c948f757466eeb3aea98873e2ab8b2b18e9020c96a97479a513e2018",
|
||||
"sha256:68e38122115a8097fbe1cfe52979a797eaff91c10c1bf4b27774e5f30e7f723a",
|
||||
"sha256:6c45ad95e82155372d9908774db46e0ef7880af28a734d0b14eaa4f505e64982",
|
||||
"sha256:6f73946c047a38640b1f5a2a459237b7bdc417ab028a76c796e4eea984b359b9",
|
||||
"sha256:6fc4376266ae67f6d8f9e69386ab950eb84ba345c6fdbeb1884fa5b773c8c76b",
|
||||
"sha256:74e41a0222e6e8136e38f103d6cc228e4e20f1c35cc80224a42804fd67fb35c8",
|
||||
"sha256:7a4bed7bd7b288cf73ba47bda27fdd1d78ef6906831489e7f296aef9e786eccb",
|
||||
"sha256:7ba8be1717b1867a85b2413a8585bad0e4507a22d6af2c244e1c74151f6d5cc0",
|
||||
"sha256:7bbb87f040e618bebe8c6257b3e4e8ae2f708dcbff3270c84718b3360a152799",
|
||||
"sha256:838d35eb9006d36f9241e95958d9f4819bcf1ea2ec155daf92d5751c31bcc62b",
|
||||
"sha256:8dca10174a3bd482d969a2d12d0aec2fdd63fb974e255ec0147e36a516a2d68a",
|
||||
"sha256:9937e819196b894ffd00801b24f1042dabda142f355313c3f20410993219bc4f",
|
||||
"sha256:994eaf4369e6bc24258f59fe8c6345037abcf24557571814e27879851c4353aa",
|
||||
"sha256:a48efcb5d3695b295c26835ed81048da8cd40e76c4fde2940c807aa452b560c9",
|
||||
"sha256:a53c4fe8e1c067e6c98b4526e982ed9486f08578ad8eb5f0e94f8cadf0c1d911",
|
||||
"sha256:a88944d2f99db71a3ca0c63d81f37e55b660edde0b07216fb65a3e46403ef004",
|
||||
"sha256:afe91153c2046fa8210b92def513124e0ea5b87ad8fa4c14fef8197204b980f1",
|
||||
"sha256:b09843123425337d2efee5c8ff6519e4dfc7b044db66c8bd560517fc1070a157",
|
||||
"sha256:b1ef400fc73ab0cb61b74a662ad4207917223aba6f933a9fea9b0fbe75de2361",
|
||||
"sha256:b2c7e4afde0d36926b091fa9613b18b65e911fcaa60024e8721f2dcfedc25329",
|
||||
"sha256:b631af423e6d5d35f9f37fbcc4fbdb6085abc1c441cf864c64b7fbb5b150faf7",
|
||||
"sha256:caeadbf95ce277f1f8f4f71913bc20c01f49fc9228f238920f9ff6f7645d2a5f",
|
||||
"sha256:ce441ab7ad1db592e2db95b6c2a1eb882123532897340afac1342c28819e9833",
|
||||
"sha256:ce620a6563b21aa3fbb1658bc1bfddb484a6dad542de1efb5121eb7bb4f2b93a",
|
||||
"sha256:d0b26d9d6eb9a0979d37f28c715e717a409c9e03163e5cd8fa73aab806351ab5",
|
||||
"sha256:d423956f8dfd98a075c9338b886414b6e3c2817dbf67935797466c998af39936",
|
||||
"sha256:e2b1c372583eb4363b42e21222d3a18116a41973781d502d61e1b0daf4b8352f",
|
||||
"sha256:fa616d0d3c594785c6e9b7f42686bb1c86f9e64aa0f30a72c86d8eb315f54194",
|
||||
"sha256:fdac161127ef8e0889180a4c07475457c55fe0bbd644436d8f4c7ef07565d653",
|
||||
"sha256:fe4e8f71e2fd42dce245bace7e2aa97dabef13926750a351eadca89a1e0f1abd"
|
||||
],
|
||||
"markers": "python_version >= '3.1'",
|
||||
"version": "==5.1.0"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179",
|
||||
"sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096",
|
||||
"sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374",
|
||||
"sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df",
|
||||
"sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185",
|
||||
"sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785",
|
||||
"sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7",
|
||||
"sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909",
|
||||
"sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918",
|
||||
"sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33",
|
||||
"sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068",
|
||||
"sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829",
|
||||
"sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af",
|
||||
"sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79",
|
||||
"sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce",
|
||||
"sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc",
|
||||
"sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36",
|
||||
"sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade",
|
||||
"sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca",
|
||||
"sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32",
|
||||
"sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125",
|
||||
"sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e",
|
||||
"sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709",
|
||||
"sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f",
|
||||
"sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b",
|
||||
"sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb",
|
||||
"sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb",
|
||||
"sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489",
|
||||
"sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640",
|
||||
"sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb",
|
||||
"sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851",
|
||||
"sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d",
|
||||
"sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44",
|
||||
"sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13",
|
||||
"sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2",
|
||||
"sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb",
|
||||
"sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b",
|
||||
"sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9",
|
||||
"sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755",
|
||||
"sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c",
|
||||
"sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a",
|
||||
"sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf",
|
||||
"sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3",
|
||||
"sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229",
|
||||
"sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e",
|
||||
"sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de",
|
||||
"sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554",
|
||||
"sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10",
|
||||
"sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80",
|
||||
"sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056",
|
||||
"sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==1.13.3"
|
||||
},
|
||||
"yapf": {
|
||||
"hashes": [
|
||||
"sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32",
|
||||
"sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b"
|
||||
],
|
||||
"version": "==0.32.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
70
app.py
70
app.py
|
@ -1,8 +1,20 @@
|
|||
from flask import Flask
|
||||
import toml
|
||||
import json
|
||||
|
||||
from flask import Flask, request, abort, Response
|
||||
from flask_sockets import Sockets
|
||||
from flask_redis import FlaskRedis
|
||||
from geventwebsocket.exceptions import WebSocketError
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_file("config.toml", load=toml.load)
|
||||
|
||||
sockets = Sockets(app)
|
||||
redis_client = FlaskRedis(app)
|
||||
|
||||
EVENT_BUFFER = app.config['EVENT_BUFFER']
|
||||
DISSCONECT_ALLOWANCE_TIME = app.config['DISSCONECT_ALLOWANCE_TIME']
|
||||
EVENT_KEY = 'event'.encode('utf-8')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
|
@ -10,18 +22,58 @@ def index():
|
|||
return 'TODO: index page'
|
||||
|
||||
|
||||
@app.route('/webhook/<client_id>')
|
||||
@app.route('/webhook/<client_id>', methods=['POST'])
|
||||
def handle_webhook(client_id):
|
||||
# TODO: verify message against client's secret, push event data to redux, un-register if client is dead
|
||||
if request.headers.get('Twitch-Eventsub-Message-Type') == 'webhook_callback_verification':
|
||||
clients = redis_client.get(f'{client_id}_active')
|
||||
if clients > 0:
|
||||
return request.get_json()['challenge'], 200, {'content-type': 'text/plain'}
|
||||
else:
|
||||
return Response(status=504)
|
||||
elif request.headers.get('Twitch-Eventsub-Message-Type') == 'revocation':
|
||||
# TODO: Notify websocket
|
||||
return Response(status=204)
|
||||
elif request.headers.get('Twitch-Eventsub-Message-Type') == 'notification':
|
||||
if redis_client.exists(f'{client_id}_active'):
|
||||
data = {**request.get_json(),
|
||||
'headers': {k:v for k, v in request.headers.items() if k.startswith('Twitch-Eventsub')}}
|
||||
stream_item = dict(event=json.dumps(data))
|
||||
redis_client.xadd(client_id, stream_item, maxlen=EVENT_BUFFER)
|
||||
return Response(status=204)
|
||||
else:
|
||||
return Response(status=504)
|
||||
|
||||
return abort(400)
|
||||
|
||||
|
||||
@sockets.route('/ws/<client_id>')
|
||||
def client_websocket(ws, client_id):
|
||||
ws.send(client_id)
|
||||
secret = ws.receive()
|
||||
while not ws.closed:
|
||||
# TODO: listen for events via redis
|
||||
msg = ws.receive()
|
||||
ws.send(msg)
|
||||
clients = redis_client.incr(f'{client_id}_active')
|
||||
try:
|
||||
if clients == 1:
|
||||
payload = dict(status=1, msg=f"Now accepting subscriptions for /webhook/{client_id}")
|
||||
redis_client.persist(f'{client_id}_active')
|
||||
else:
|
||||
payload = dict(status=1, msg=f"Welcome! You are listener #{clients}")
|
||||
ws.send(json.dumps(payload))
|
||||
|
||||
# MAGIC: $ is a special id that causes xread to only return for items added after it started blocking
|
||||
last_id = request.args.get('since', '$')
|
||||
while not ws.closed:
|
||||
stream_items = redis_client.xread({ client_id: last_id }, block=0)[0][1]
|
||||
for item_id, stream_data in stream_items:
|
||||
event = stream_data[EVENT_KEY].decode()
|
||||
payload = dict(id=item_id.decode(), data=event)
|
||||
try:
|
||||
ws.send(json.dumps(payload))
|
||||
except WebSocketError:
|
||||
break
|
||||
else: break
|
||||
last_id = item_id
|
||||
finally:
|
||||
clients = redis_client.decr(f'{client_id}_active')
|
||||
if clients == 0:
|
||||
redis_client.expire(f'{client_id}_active', DISSCONECT_ALLOWANCE_TIME)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
3
config.toml
Normal file
3
config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
REDIS_URL = "redis://localhost:6379/1"
|
||||
EVENT_BUFFER = 100
|
||||
DISSCONECT_ALLOWANCE_TIME = 120
|
Loading…
Add table
Reference in a new issue