Initial Commit
This commit is contained in:
commit
1d95646a96
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.vscode/
|
||||||
|
meme.py
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||||
|
|
||||||
|
COPY prestart.sh /app/prestart.sh
|
||||||
|
COPY cards.json /app/
|
||||||
|
|
||||||
|
COPY ./Pipf* ./
|
||||||
|
RUN pip install pipenv && pipenv install --deploy --system
|
||||||
|
|
||||||
|
|
||||||
|
COPY ./app /app/app
|
21
Pipfile
Normal file
21
Pipfile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
pylint = "*"
|
||||||
|
autopep8 = "*"
|
||||||
|
rope = "*"
|
||||||
|
websocket-client = "*"
|
||||||
|
requests = "*"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
fastapi = "*"
|
||||||
|
uvicorn = "*"
|
||||||
|
aioredis= "*"
|
||||||
|
redis = "*"
|
||||||
|
hashids = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.7"
|
318
Pipfile.lock
generated
Normal file
318
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "1e9d6c7d62986e9fe9f46a0afbec4bb992b75150632e56d2decfd5a97298ede3"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.7"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"aioredis": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84d62be729beb87118cf126c20b0e3f52d7a42bb7373dc5bcdd874f26f1f251a",
|
||||||
|
"sha256:aee16aa5cb3f636cf8fa0e2b62d2f6abc90366e19b5c30e94a5471d834a55975"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.2.0"
|
||||||
|
},
|
||||||
|
"async-timeout": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||||
|
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||||
|
],
|
||||||
|
"version": "==3.0.1"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||||
|
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||||
|
],
|
||||||
|
"version": "==7.0"
|
||||||
|
},
|
||||||
|
"fastapi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:53259a2b572e49ac2634fc643912c6a818623242705ebe2a060db4f51807a83e",
|
||||||
|
"sha256:7117cb8464b3525cd5c5b09ed44628425ca62ce65925f5076b52faf2e7078b5e"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.31.0"
|
||||||
|
},
|
||||||
|
"h11": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208",
|
||||||
|
"sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7"
|
||||||
|
],
|
||||||
|
"version": "==0.8.1"
|
||||||
|
},
|
||||||
|
"hashids": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6539b892a426e75747a9c0ad69409e9566f9c21b79310fc3424b5b6726f28da6"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.2.0"
|
||||||
|
},
|
||||||
|
"hiredis": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0124911115f2cb7deb4f8e221e109a53d3d718174b238a2c5e2162175a3929a5",
|
||||||
|
"sha256:0656658d0448c2c82c4890ae933c2c2e51196101d3d06fc19cc92e062410c2fd",
|
||||||
|
"sha256:09d284619f7142ddd7a4ffa94c12a0445e834737f4ce8739a737f2b1ca0f6142",
|
||||||
|
"sha256:12299b7026e5dc22ed0ff603375c1bf583cf59adbb0e4d062df434e9140d72dd",
|
||||||
|
"sha256:12fc6210f8dc3e9c8ce4b95e8f5db404b838dbdeb25bca41e33497de6d89334f",
|
||||||
|
"sha256:197febe5e63c77f4ad19b36e15ed33152064dc606c8b7413c7a0ca3fd04672cc",
|
||||||
|
"sha256:20e48289fbffb59a5ac7cc677fc02c2726c1da22488e5f7636b9feb9afde199f",
|
||||||
|
"sha256:26bed296b92b88db02afe214aa1fefad7f9e8ba88a5a7c0e355b55c4b168d212",
|
||||||
|
"sha256:321b19d2a21fd576111032fe7694d317de2c11b265ef775f2e3f22734a6b94c8",
|
||||||
|
"sha256:32d5f2c461250f5fc7ccef647682651b1d9f69443f16c213d7fa5e183222b233",
|
||||||
|
"sha256:36bfcc86715d109a5ef6edefd52b893de97d555cb5cb0e9cab83eb9665942ccc",
|
||||||
|
"sha256:438ddfd1484e98110959dc4648c0ba22c3307c9c0ae7e2a856755067f9ce9cef",
|
||||||
|
"sha256:66f17c1633b2fb967bf4165f7b3d369a1bdfe3537d3646cf9a7c208506c96c49",
|
||||||
|
"sha256:94ab0fa3ac93ab36a5400c474439881d182b43fd38a2766d984470c57931ae88",
|
||||||
|
"sha256:955f12da861f2608c181049f623bbb52851769e10639c4919cc586395b89813f",
|
||||||
|
"sha256:b1fd831f96ce0f715e9356574f5184b840b59eb8901fc5f9124fedbe84ad2a59",
|
||||||
|
"sha256:b3813c641494fca2eda66c32a2117816472a5a39b12f59f7887c6d17bdb8c77e",
|
||||||
|
"sha256:bbc3ee8663024c82a1226a0d56ad882f42a2fd8c2999bf52d27bdd25f1320f4b",
|
||||||
|
"sha256:bd12c2774b574f5b209196e25b03b5d62c7919bf69046bc7b955ebe84e0ec1fe",
|
||||||
|
"sha256:c54d2b3d7a2206df35f3c1140ac20ca6faf7819ff92ea5be8bf4d1cbdb433216",
|
||||||
|
"sha256:c7b0bcaf2353a2ad387dd8b5e1b5f55991adc3a7713ac3345a4ef0de58276690",
|
||||||
|
"sha256:c9319a1503efb3b5a4ec13b2f8fae2c23610a645e999cb8954d330f0610b0f6d",
|
||||||
|
"sha256:cbe5c0273224babe2ec77058643312d07aa5e8fed08901b3f7bccaa744c5728e",
|
||||||
|
"sha256:cc884ea50185009d794b31314a144110efc76b71beb0a5827a8bff970ae6d248",
|
||||||
|
"sha256:d1e2e751327781ad81df5a5a29d7c7b19ee0ebfbeddf037fd8df19ec1c06e18b",
|
||||||
|
"sha256:d2ef58cece6cae4b354411df498350d836f10b814c8a890df0d8079aff30c518",
|
||||||
|
"sha256:e97c953f08729900a5e740f1760305434d62db9f281ac351108d6c4b5bf51795",
|
||||||
|
"sha256:fcdf2e10f56113e1cb4326dbca7bf7edbfdbd246cd6d7ec088688e5439129e2c"
|
||||||
|
],
|
||||||
|
"version": "==1.0.0"
|
||||||
|
},
|
||||||
|
"pydantic": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:098ffe36047a35f78dbc0d8f7c2d40da053e35158b6f4326c50d669c56e48ea7",
|
||||||
|
"sha256:549c5d05138b7e0f33bd24d4313783c90342d0595d824e02ceb562a992c78239",
|
||||||
|
"sha256:6901572483a00d53aaba9121c6261017334511c44864b00b36714b32cc7af712",
|
||||||
|
"sha256:70a5cbab8b52ac3e5f9660a8ad028581095e48abc4a0fc67d1b2bf69e8a51d03",
|
||||||
|
"sha256:9d34421072a7df679638e5896a4a15f48ffbbfb8a57eb5fac6c45806269d0dc0",
|
||||||
|
"sha256:e4968f16f448d7c3026b0197bd29e78b5f39a7d27dbe22d5b3f07fb8602a2dc1"
|
||||||
|
],
|
||||||
|
"version": "==0.29"
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6946b5dca72e86103edc8033019cc3814c031232d339d5f4533b02ea85685175",
|
||||||
|
"sha256:8ca418d2ddca1b1a850afa1680a7d2fd1f3322739271de4b704e0d4668449273"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.2.1"
|
||||||
|
},
|
||||||
|
"starlette": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d313433ef5cc38e0a276b59688ca2b11b8f031c78808c1afdf9d55cb86f34590"
|
||||||
|
],
|
||||||
|
"version": "==0.12.0"
|
||||||
|
},
|
||||||
|
"uvicorn": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a7f41b8a132810431f0e1d2a40fe123e5c9deac1baf1ea11dd381728647c2591"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.8.3"
|
||||||
|
},
|
||||||
|
"websockets": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:04b42a1b57096ffa5627d6a78ea1ff7fad3bc2c0331ffc17bc32a4024da7fea0",
|
||||||
|
"sha256:08e3c3e0535befa4f0c4443824496c03ecc25062debbcf895874f8a0b4c97c9f",
|
||||||
|
"sha256:10d89d4326045bf5e15e83e9867c85d686b612822e4d8f149cf4840aab5f46e0",
|
||||||
|
"sha256:232fac8a1978fc1dead4b1c2fa27c7756750fb393eb4ac52f6bc87ba7242b2fa",
|
||||||
|
"sha256:4bf4c8097440eff22bc78ec76fe2a865a6e658b6977a504679aaf08f02c121da",
|
||||||
|
"sha256:51642ea3a00772d1e48fb0c492f0d3ae3b6474f34d20eca005a83f8c9c06c561",
|
||||||
|
"sha256:55d86102282a636e195dad68aaaf85b81d0bef449d7e2ef2ff79ac450bb25d53",
|
||||||
|
"sha256:564d2675682bd497b59907d2205031acbf7d3fadf8c763b689b9ede20300b215",
|
||||||
|
"sha256:5d13bf5197a92149dc0badcc2b699267ff65a867029f465accfca8abab95f412",
|
||||||
|
"sha256:5eda665f6789edb9b57b57a159b9c55482cbe5b046d7db458948370554b16439",
|
||||||
|
"sha256:5edb2524d4032be4564c65dc4f9d01e79fe8fad5f966e5b552f4e5164fef0885",
|
||||||
|
"sha256:79691794288bc51e2a3b8de2bc0272ca8355d0b8503077ea57c0716e840ebaef",
|
||||||
|
"sha256:7fcc8681e9981b9b511cdee7c580d5b005f3bb86b65bde2188e04a29f1d63317",
|
||||||
|
"sha256:8e447e05ec88b1b408a4c9cde85aa6f4b04f06aa874b9f0b8e8319faf51b1fee",
|
||||||
|
"sha256:90ea6b3e7787620bb295a4ae050d2811c807d65b1486749414f78cfd6fb61489",
|
||||||
|
"sha256:9e13239952694b8b831088431d15f771beace10edfcf9ef230cefea14f18508f",
|
||||||
|
"sha256:d40f081187f7b54d7a99d8a5c782eaa4edc335a057aa54c85059272ed826dc09",
|
||||||
|
"sha256:e1df1a58ed2468c7b7ce9a2f9752a32ad08eac2bcd56318625c3647c2cd2da6f",
|
||||||
|
"sha256:e98d0cec437097f09c7834a11c69d79fe6241729b23f656cfc227e93294fc242",
|
||||||
|
"sha256:f8d59627702d2ff27cb495ca1abdea8bd8d581de425c56e93bff6517134e0a9b",
|
||||||
|
"sha256:fc30cdf2e949a2225b012a7911d1d031df3d23e99b7eda7dfc982dc4a860dae9"
|
||||||
|
],
|
||||||
|
"version": "==7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"astroid": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4",
|
||||||
|
"sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"
|
||||||
|
],
|
||||||
|
"version": "==2.2.5"
|
||||||
|
},
|
||||||
|
"autopep8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.4.4"
|
||||||
|
},
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
|
||||||
|
"sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
|
||||||
|
],
|
||||||
|
"version": "==2019.6.16"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"colorama": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d",
|
||||||
|
"sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"
|
||||||
|
],
|
||||||
|
"markers": "sys_platform == 'win32'",
|
||||||
|
"version": "==0.4.1"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||||
|
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||||
|
],
|
||||||
|
"version": "==2.8"
|
||||||
|
},
|
||||||
|
"isort": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
|
||||||
|
"sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
|
||||||
|
],
|
||||||
|
"version": "==4.3.21"
|
||||||
|
},
|
||||||
|
"lazy-object-proxy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661",
|
||||||
|
"sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f",
|
||||||
|
"sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13",
|
||||||
|
"sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821",
|
||||||
|
"sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71",
|
||||||
|
"sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e",
|
||||||
|
"sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea",
|
||||||
|
"sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229",
|
||||||
|
"sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4",
|
||||||
|
"sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e",
|
||||||
|
"sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20",
|
||||||
|
"sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16",
|
||||||
|
"sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b",
|
||||||
|
"sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7",
|
||||||
|
"sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c",
|
||||||
|
"sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a",
|
||||||
|
"sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e",
|
||||||
|
"sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1"
|
||||||
|
],
|
||||||
|
"version": "==1.4.1"
|
||||||
|
},
|
||||||
|
"mccabe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||||
|
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||||
|
],
|
||||||
|
"version": "==0.6.1"
|
||||||
|
},
|
||||||
|
"pycodestyle": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||||
|
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||||
|
],
|
||||||
|
"version": "==2.5.0"
|
||||||
|
},
|
||||||
|
"pylint": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09",
|
||||||
|
"sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.3.1"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
|
||||||
|
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.22.0"
|
||||||
|
},
|
||||||
|
"rope": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6b728fdc3e98a83446c27a91fc5d56808a004f8beab7a31ab1d7224cecc7d969",
|
||||||
|
"sha256:c5c5a6a87f7b1a2095fb311135e2a3d1f194f5ecb96900fdd0a9100881f48aaf",
|
||||||
|
"sha256:f0dcf719b63200d492b85535ebe5ea9b29e0d0b8aebeb87fe03fc1a65924fdaf"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.14.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||||
|
],
|
||||||
|
"version": "==1.12.0"
|
||||||
|
},
|
||||||
|
"typed-ast": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e",
|
||||||
|
"sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e",
|
||||||
|
"sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0",
|
||||||
|
"sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c",
|
||||||
|
"sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631",
|
||||||
|
"sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4",
|
||||||
|
"sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34",
|
||||||
|
"sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b",
|
||||||
|
"sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a",
|
||||||
|
"sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233",
|
||||||
|
"sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1",
|
||||||
|
"sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36",
|
||||||
|
"sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d",
|
||||||
|
"sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a",
|
||||||
|
"sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"
|
||||||
|
],
|
||||||
|
"markers": "implementation_name == 'cpython'",
|
||||||
|
"version": "==1.4.0"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
|
||||||
|
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
|
||||||
|
],
|
||||||
|
"version": "==1.25.3"
|
||||||
|
},
|
||||||
|
"websocket-client": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1151d5fb3a62dc129164292e1227655e4bbc5dd5340a5165dfae61128ec50aa9",
|
||||||
|
"sha256:1fd5520878b68b84b5748bb30e592b10d0a91529d5383f74f4964e72b297fd3a"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.56.0"
|
||||||
|
},
|
||||||
|
"wrapt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
|
||||||
|
],
|
||||||
|
"version": "==1.11.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
app/__init__.py
Normal file
1
app/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from .main import app
|
180
app/main.py
Normal file
180
app/main.py
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
import redis
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import random
|
||||||
|
import hashids
|
||||||
|
import asyncio
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from starlette.responses import HTMLResponse
|
||||||
|
from starlette.exceptions import HTTPException
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import List, Dict
|
||||||
|
# pylint: disable=unused-wildcard-import
|
||||||
|
from .models import *
|
||||||
|
from starlette.websockets import WebSocket
|
||||||
|
|
||||||
|
hashes = hashids.Hashids("a very good salt yes this is nice ok",
|
||||||
|
4, "ABCDEFGHJKLMNPQRSTUVXYZ23456789")
|
||||||
|
|
||||||
|
app = FastAPI(title="Cards against idiots")
|
||||||
|
r = redis.Redis(host='redis', port=6379, password='yeet')
|
||||||
|
# loop = asyncio.get_event_loop()
|
||||||
|
# r = aioredis.create_redis("redis://redis", loop=loop)
|
||||||
|
cards = {}
|
||||||
|
|
||||||
|
with open("cards.json", encoding="UTF-8") as file:
|
||||||
|
cards = json.load(file)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/cards/random", response_model=Card)
|
||||||
|
async def get_random_card():
|
||||||
|
return random.choice(cards["black"])
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/packs", response_model=Dict[str, Pack])
|
||||||
|
async def get_all_packs():
|
||||||
|
return cards["metadata"]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/packs/{id}")
|
||||||
|
async def get_pack(id: str):
|
||||||
|
return cards["metadata"][id]
|
||||||
|
|
||||||
|
|
||||||
|
@app.websocket("/ws/room/{code}/{kind}")
|
||||||
|
async def ws_room(ws: WebSocket, code: str, kind: str):
|
||||||
|
await ws.accept()
|
||||||
|
if kind == "sub":
|
||||||
|
ps = r.pubsub()
|
||||||
|
ps.subscribe(code)
|
||||||
|
while True:
|
||||||
|
# 1: Message from pub/sub
|
||||||
|
msg = ps.get_message()
|
||||||
|
if msg:
|
||||||
|
await ws.send_text(str(msg["data"]))
|
||||||
|
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
elif kind == "pub": # 2: Message from WS
|
||||||
|
while True:
|
||||||
|
msg = Message(**(await ws.receive_json()))
|
||||||
|
get_r = r.hget("rooms", code)
|
||||||
|
# Room should already be created even if we are the first person to join
|
||||||
|
if not get_r:
|
||||||
|
await ws.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
room = Room(**json.loads(get_r))
|
||||||
|
|
||||||
|
if msg.msgtype is MessageType.JOIN:
|
||||||
|
# ps.subscribe(code)
|
||||||
|
name: str = str(msg.data)
|
||||||
|
|
||||||
|
if room.started:
|
||||||
|
await ws.send_text("you fucked up dawg")
|
||||||
|
await ws.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
p = Player(name=name, uuid=uuid.uuid4())
|
||||||
|
|
||||||
|
if not room.admin_uuid:
|
||||||
|
room.admin_uuid = p.uuid
|
||||||
|
|
||||||
|
room.players.append(p)
|
||||||
|
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
|
||||||
|
r.publish(code, PubRoom(**room.dict()).json())
|
||||||
|
|
||||||
|
await ws.send_text(str(p.uuid))
|
||||||
|
elif msg.msgtype is MessageType.START:
|
||||||
|
pid: str = str(msg.data)
|
||||||
|
|
||||||
|
if pid == str(room.admin_uuid):
|
||||||
|
room.started = True
|
||||||
|
|
||||||
|
if not next_round(code):
|
||||||
|
await ws.close()
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
|
||||||
|
elif msg.msgtype is MessageType.ANSWER:
|
||||||
|
answer = AnswerReceived(**json.loads(msg.data))
|
||||||
|
|
||||||
|
mapper = {p.uuid: i for i, p in enumerate(room.players)}
|
||||||
|
|
||||||
|
mapped = AnswerSending(**answer, index=mapper[answer.uuid])
|
||||||
|
room.answers.append(mapped)
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
|
||||||
|
if len(room.answers) == (len(room.players) - 1):
|
||||||
|
r.publish(code, Message(
|
||||||
|
msgtype=MessageType.ANSWER, data=room.answers).json())
|
||||||
|
|
||||||
|
elif msg.msgtype is MessageType.PICK:
|
||||||
|
answer = AnswerSendingButItHasAUUIDBecauseItIsImportantToCheckIfItWasSentByTheCzar(
|
||||||
|
**json.loads(msg.data))
|
||||||
|
if answer.uuid != room.czar:
|
||||||
|
continue
|
||||||
|
r.publish(code, Message(
|
||||||
|
msgtype=MessageType.PICK, data=answer).json())
|
||||||
|
room.players[answer.index].points += 1
|
||||||
|
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
r.publish(code, PubRoom(**room.dict()).json())
|
||||||
|
|
||||||
|
next_round(code)
|
||||||
|
else:
|
||||||
|
raise HTTPException(400, "That's an illegal (message type)!")
|
||||||
|
|
||||||
|
else:
|
||||||
|
await ws.close()
|
||||||
|
|
||||||
|
|
||||||
|
def next_round(code: str):
|
||||||
|
get_r = r.hget("rooms", code)
|
||||||
|
|
||||||
|
# Room should exist if we want to start it
|
||||||
|
if not get_r:
|
||||||
|
return False
|
||||||
|
|
||||||
|
room = Room(**json.loads(get_r))
|
||||||
|
room.answers = []
|
||||||
|
cardid = random.randrange(0, len(cards["black"]))
|
||||||
|
while cardid in room.played_cards:
|
||||||
|
cardid = random.randrange(0, len(cards["black"]))
|
||||||
|
room.played_cards.append(cardid)
|
||||||
|
room.czar = (room.czar + 1) % len(room.players)
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
|
||||||
|
r.publish(code, Message(
|
||||||
|
msgtype=MessageType.START,
|
||||||
|
data=RoundStart(czar=room.czar, card=cards["black"][cardid])).json())
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def memes():
|
||||||
|
return cards
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/room", response_model=Room)
|
||||||
|
async def create_room():
|
||||||
|
n = r.incr("RoomCounter")
|
||||||
|
room = Room(number=n, code=hashes.encode(n))
|
||||||
|
r.hset("rooms", room.code, room.json())
|
||||||
|
|
||||||
|
return room
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/room/{code}", response_model=PubRoom)
|
||||||
|
async def get_room_by_id(code: str):
|
||||||
|
try:
|
||||||
|
return Room(**json.loads(r.hget("rooms", code)))
|
||||||
|
except:
|
||||||
|
raise HTTPException(404, "Room not found!")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/rooms", response_model=Dict[str, PubRoom])
|
||||||
|
async def dump_redis():
|
||||||
|
return {k: Room(**json.loads(v)) for k, v in r.hgetall("rooms").items()}
|
82
app/models.py
Normal file
82
app/models.py
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
from pydantic import BaseModel, UUID4
|
||||||
|
from typing import List, Any
|
||||||
|
from enum import Enum, auto
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Card(BaseModel):
|
||||||
|
text: str
|
||||||
|
pick: int
|
||||||
|
deck: str
|
||||||
|
icon: str
|
||||||
|
|
||||||
|
|
||||||
|
class Pack(BaseModel):
|
||||||
|
icon: str
|
||||||
|
official: bool
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class RoundStart(BaseModel):
|
||||||
|
czar: int
|
||||||
|
card: Card
|
||||||
|
|
||||||
|
class PubPlayer(BaseModel):
|
||||||
|
name: str
|
||||||
|
points: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class Player(PubPlayer):
|
||||||
|
uuid: UUID4
|
||||||
|
|
||||||
|
# def __init__(self, name):
|
||||||
|
# self.name = name
|
||||||
|
# self.uuid = uuid.uuid4()
|
||||||
|
|
||||||
|
|
||||||
|
class PubRoom(BaseModel):
|
||||||
|
code: str
|
||||||
|
czar: int = 0
|
||||||
|
players: List[PubPlayer] = [] # List of player's uuids
|
||||||
|
started: bool = False
|
||||||
|
played_cards: List[int] = []
|
||||||
|
|
||||||
|
class Answer(BaseModel):
|
||||||
|
text: str
|
||||||
|
|
||||||
|
class AnswerReceived(Answer):
|
||||||
|
uuid: str
|
||||||
|
|
||||||
|
class AnswerSending(Answer):
|
||||||
|
index: int
|
||||||
|
|
||||||
|
class AnswerSendingButItHasAUUIDBecauseItIsImportantToCheckIfItWasSentByTheCzar(AnswerSending):
|
||||||
|
uuid: str
|
||||||
|
|
||||||
|
class Room(PubRoom):
|
||||||
|
players: List[Player] = [] # List of player's uuids
|
||||||
|
number: int
|
||||||
|
admin_uuid: UUID4 = None
|
||||||
|
answers:List[AnswerSending] = []
|
||||||
|
# def __init__(self, number):
|
||||||
|
# super().__init__()
|
||||||
|
# self.number = number
|
||||||
|
# self.code = hashes.encode(number)
|
||||||
|
|
||||||
|
|
||||||
|
class AutoName(Enum):
|
||||||
|
# pylint: disable=no-self-argument
|
||||||
|
def _generate_next_value_(name, start, count, last_values):
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
class MessageType(AutoName):
|
||||||
|
JOIN = auto()
|
||||||
|
START = auto()
|
||||||
|
ANSWER = auto()
|
||||||
|
PICK = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Message(BaseModel):
|
||||||
|
msgtype: MessageType
|
||||||
|
data: Any
|
18134
cards.json
Normal file
18134
cards.json
Normal file
File diff suppressed because it is too large
Load diff
19
docker-compose.yml
Normal file
19
docker-compose.yml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
networks:
|
||||||
|
- overlay
|
||||||
|
image: redis:alpine
|
||||||
|
command: redis-server --requirepass yeet
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build: ./
|
||||||
|
image: cards-backend:dev
|
||||||
|
networks:
|
||||||
|
- overlay
|
||||||
|
ports:
|
||||||
|
- "8000:80"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
overlay:
|
2
prestart.sh
Normal file
2
prestart.sh
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#! /bin/bash
|
||||||
|
echo nice
|
Loading…
Reference in a new issue