diff --git a/.gitignore b/.gitignore
index 15ca555d..2190bca8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,5 @@ dist/
.idea/**/markdown-navigator.xml
.idea/**/markdown-exported-files.xml
.idea/**/misc.xml
+.idea/**/discord.xml
.idea/**/*.iml
\ No newline at end of file
diff --git a/.idea/royalnet.iml b/.idea/royalnet.iml
index c64f4618..cb36690b 100644
--- a/.idea/royalnet.iml
+++ b/.idea/royalnet.iml
@@ -9,10 +9,10 @@
+
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/royalnet__config_ini_.xml b/.idea/runConfigurations/royalnet__config_toml_.xml
similarity index 85%
rename from .idea/runConfigurations/royalnet__config_ini_.xml
rename to .idea/runConfigurations/royalnet__config_toml_.xml
index 25897d9a..463279f5 100644
--- a/.idea/runConfigurations/royalnet__config_ini_.xml
+++ b/.idea/runConfigurations/royalnet__config_toml_.xml
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
-
+
diff --git a/README.md b/README.md
index 815a3978..c26d66e0 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ A multipurpose bot framework and webserver
- [Telegram](https://core.telegram.org/bots)
- [Discord](https://discordapp.com/developers/docs/)
+- [Matrix]() (no E2E support yet)
## Installing
diff --git a/poetry.lock b/poetry.lock
index af89c799..6da9a645 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -194,7 +194,27 @@ description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
name = "h11"
optional = true
python-versions = "*"
-version = "0.8.1"
+version = "0.9.0"
+
+[[package]]
+category = "main"
+description = "HTTP/2 State-Machine based protocol implementation"
+name = "h2"
+optional = true
+python-versions = "*"
+version = "3.1.1"
+
+[package.dependencies]
+hpack = ">=2.3,<4"
+hyperframe = ">=5.2.0,<6"
+
+[[package]]
+category = "main"
+description = "Pure-Python HPACK header compression"
+name = "hpack"
+optional = true
+python-versions = "*"
+version = "3.0.0"
[[package]]
category = "main"
@@ -216,6 +236,14 @@ version = "4.18"
[package.dependencies]
pyreadline = "*"
+[[package]]
+category = "main"
+description = "HTTP/2 framing layer for Python"
+name = "hyperframe"
+optional = true
+python-versions = "*"
+version = "5.2.0"
+
[[package]]
category = "main"
description = "Internationalized Domain Names in Applications (IDNA)"
@@ -246,6 +274,43 @@ MarkupSafe = ">=0.23"
[package.extras]
i18n = ["Babel (>=0.8)"]
+[[package]]
+category = "main"
+description = "An implementation of JSON Schema validation for Python"
+name = "jsonschema"
+optional = true
+python-versions = "*"
+version = "3.2.0"
+
+[package.dependencies]
+attrs = ">=17.4.0"
+pyrsistent = ">=0.14.0"
+setuptools = "*"
+six = ">=1.11.0"
+
+[package.extras]
+format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
+format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"]
+
+[[package]]
+category = "main"
+description = "A logging replacement for Python"
+name = "logbook"
+optional = true
+python-versions = "*"
+version = "1.5.3"
+
+[package.extras]
+all = ["redis", "brotli", "pytest (>4.0)", "execnet (>=1.0.9)", "cython", "pyzmq", "pytest-cov (>=2.6)", "sqlalchemy", "jinja2"]
+compression = ["brotli"]
+dev = ["pytest-cov (>=2.6)", "pytest (>4.0)", "cython"]
+execnet = ["execnet (>=1.0.9)"]
+jinja = ["jinja2"]
+redis = ["redis"]
+sqlalchemy = ["sqlalchemy"]
+test = ["pytest-cov (>=2.6)", "pytest (>4.0)"]
+zmq = ["pyzmq"]
+
[[package]]
category = "dev"
description = "Safely add untrusted strings to HTML/XML markup."
@@ -254,6 +319,31 @@ optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.1.1"
+[[package]]
+category = "main"
+description = "A Python Matrix client library, designed according to sans I/O principles."
+name = "matrix-nio"
+optional = true
+python-versions = "*"
+version = "0.6"
+
+[package.dependencies]
+attrs = "*"
+future = "*"
+h11 = "*"
+h2 = "*"
+jsonschema = "*"
+logbook = "*"
+pycryptodome = "*"
+unpaddedbase64 = "*"
+
+[package.dependencies.aiohttp]
+python = ">=3.6"
+version = "*"
+
+[package.extras]
+e2e = ["python-olm (>=3.1.0)", "peewee (>=3.9.5)", "cachetools", "atomicwrites"]
+
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
@@ -268,7 +358,7 @@ description = "multidict implementation"
name = "multidict"
optional = true
python-versions = ">=3.5"
-version = "4.6.1"
+version = "4.7.2"
[[package]]
category = "dev"
@@ -325,6 +415,14 @@ optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.19"
+[[package]]
+category = "main"
+description = "Cryptographic library for Python"
+name = "pycryptodome"
+optional = true
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+version = "3.9.4"
+
[[package]]
category = "dev"
description = "Pygments is a syntax highlighting package written in Python."
@@ -366,13 +464,24 @@ optional = true
python-versions = "*"
version = "2.1"
+[[package]]
+category = "main"
+description = "Persistent/Functional/Immutable data structures"
+name = "pyrsistent"
+optional = true
+python-versions = "*"
+version = "0.15.6"
+
+[package.dependencies]
+six = "*"
+
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
-version = "5.3.1"
+version = "5.3.2"
[package.dependencies]
atomicwrites = ">=1.0"
@@ -441,7 +550,7 @@ description = "Alternative regular expression module, to replace re."
name = "regex"
optional = false
python-versions = "*"
-version = "2019.12.9"
+version = "2019.12.20"
[[package]]
category = "dev"
@@ -509,7 +618,7 @@ description = "Python documentation generator"
name = "sphinx"
optional = false
python-versions = ">=3.5"
-version = "2.2.2"
+version = "2.3.1"
[package.dependencies]
Jinja2 = ">=2.3"
@@ -532,7 +641,7 @@ sphinxcontrib-serializinghtml = "*"
[package.extras]
docs = ["sphinxcontrib-websupport"]
-test = ["pytest", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.750)", "docutils-stubs"]
+test = ["pytest", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"]
[[package]]
category = "dev"
@@ -617,7 +726,7 @@ description = "Database Abstraction Library"
name = "sqlalchemy"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.3.11"
+version = "1.3.12"
[package.extras]
mssql = ["pyodbc"]
@@ -685,6 +794,14 @@ version = "2.0.0"
[package.dependencies]
pytz = "*"
+[[package]]
+category = "main"
+description = "Unpadded Base64"
+name = "unpaddedbase64"
+optional = true
+python-versions = "*"
+version = "1.1.0"
+
[[package]]
category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more."
@@ -704,11 +821,11 @@ description = "The lightning-fast ASGI server."
name = "uvicorn"
optional = true
python-versions = "*"
-version = "0.10.8"
+version = "0.10.9"
[package.dependencies]
click = ">=7.0.0,<8.0.0"
-h11 = ">=0.8.0,<0.9.0"
+h11 = ">=0.9.0,<0.10.0"
httptools = "0.0.13"
uvloop = ">=0.14.0"
websockets = ">=8.0.0,<9.0.0"
@@ -766,11 +883,12 @@ coloredlogs = ["coloredlogs"]
constellation = ["starlette", "uvicorn", "python-multipart"]
discord = ["temp_discordpy_without_websockets_requirement", "pynacl"]
herald = ["websockets"]
+matrix = ["matrix-nio"]
sentry = ["sentry_sdk"]
telegram = ["python_telegram_bot"]
[metadata]
-content-hash = "8942e2b1e550c8a28c4bf6c17d0d71b5cb221eeb21228d460eaf72ef8b5810c8"
+content-hash = "b9830879d783d148ddf7af68fac91adcfe2e957d387ed5ca70a9d8cc2dc09ce5"
python-versions = "^3.8"
[metadata.files]
@@ -913,8 +1031,16 @@ future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
h11 = [
- {file = "h11-0.8.1-py2.py3-none-any.whl", hash = "sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7"},
- {file = "h11-0.8.1.tar.gz", hash = "sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208"},
+ {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"},
+ {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"},
+]
+h2 = [
+ {file = "h2-3.1.1-py2.py3-none-any.whl", hash = "sha256:ac377fcf586314ef3177bfd90c12c7826ab0840edeb03f0f24f511858326049e"},
+ {file = "h2-3.1.1.tar.gz", hash = "sha256:b8a32bd282594424c0ac55845377eea13fa54fe4a8db012f3a198ed923dc3ab4"},
+]
+hpack = [
+ {file = "hpack-3.0.0-py2.py3-none-any.whl", hash = "sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89"},
+ {file = "hpack-3.0.0.tar.gz", hash = "sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2"},
]
httptools = [
{file = "httptools-0.0.13.tar.gz", hash = "sha256:e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc"},
@@ -923,6 +1049,10 @@ humanfriendly = [
{file = "humanfriendly-4.18-py2.py3-none-any.whl", hash = "sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d"},
{file = "humanfriendly-4.18.tar.gz", hash = "sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85"},
]
+hyperframe = [
+ {file = "hyperframe-5.2.0-py2.py3-none-any.whl", hash = "sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40"},
+ {file = "hyperframe-5.2.0.tar.gz", hash = "sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f"},
+]
idna = [
{file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"},
{file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"},
@@ -935,6 +1065,21 @@ jinja2 = [
{file = "Jinja2-2.10.3-py2.py3-none-any.whl", hash = "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f"},
{file = "Jinja2-2.10.3.tar.gz", hash = "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"},
]
+jsonschema = [
+ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
+ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
+]
+logbook = [
+ {file = "Logbook-1.5.3-cp27-cp27m-win32.whl", hash = "sha256:56ee54c11df3377314cedcd6507638f015b4b88c0238c2e01b5eb44fd3a6ad1b"},
+ {file = "Logbook-1.5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2dc85f1510533fddb481e97677bb7bca913560862734c0b3b289bfed04f78c92"},
+ {file = "Logbook-1.5.3-cp35-cp35m-win32.whl", hash = "sha256:94e2e11ff3c2304b0d09a36c6208e5ae756eb948b210e5cbd63cd8d27f911542"},
+ {file = "Logbook-1.5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:97fee1bd9605f76335b169430ed65e15e457a844b2121bd1d90a08cf7e30aba0"},
+ {file = "Logbook-1.5.3-cp36-cp36m-win32.whl", hash = "sha256:7c533eb728b3d220b1b5414ba4635292d149d79f74f6973b4aa744c850ca944a"},
+ {file = "Logbook-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:e18f7422214b1cf0240c56f884fd9c9b4ff9d0da2eabca9abccba56df7222f66"},
+ {file = "Logbook-1.5.3-cp37-cp37m-win32.whl", hash = "sha256:8f76a2e7b1f72595f753228732f81ce342caf03babc3fed6bbdcf366f2f20f18"},
+ {file = "Logbook-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0cf2cdbfb65a03b5987d19109dacad13417809dcf697f66e1a7084fb21744ea9"},
+ {file = "Logbook-1.5.3.tar.gz", hash = "sha256:66f454ada0f56eae43066f604a222b09893f98c1adc18df169710761b8f32fe8"},
+]
markupsafe = [
{file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
@@ -965,28 +1110,31 @@ markupsafe = [
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
+matrix-nio = [
+ {file = "matrix-nio-0.6.tar.gz", hash = "sha256:25a4ac9d5e1435035f5c5b6e9a6b453ac66ade25cb455ba6bbe9cc3ae1e0ef50"},
+]
more-itertools = [
{file = "more-itertools-8.0.2.tar.gz", hash = "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d"},
{file = "more_itertools-8.0.2-py3-none-any.whl", hash = "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564"},
]
multidict = [
- {file = "multidict-4.6.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:318aadf1cfb6741c555c7dd83d94f746dc95989f4f106b25b8a83dfb547f2756"},
- {file = "multidict-4.6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9c890978e2b37dd0dc1bd952da9a5d9f245d4807bee33e3517e4119c48d66f8c"},
- {file = "multidict-4.6.1-cp35-cp35m-win32.whl", hash = "sha256:efaf1b18ea6c1f577b1371c0159edbe4749558bfe983e13aa24d0a0c01e1ad7b"},
- {file = "multidict-4.6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:07f9a6bf75ad675d53956b2c6a2d4ef2fa63132f33ecc99e9c24cf93beb0d10b"},
- {file = "multidict-4.6.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:42cdd649741a14b0602bf15985cad0dd4696a380081a3319cd1ead46fd0f0fab"},
- {file = "multidict-4.6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:205a011e636d885af6dd0029e41e3514a46e05bb2a43251a619a6e8348b96fc0"},
- {file = "multidict-4.6.1-cp36-cp36m-win32.whl", hash = "sha256:cfec9d001a83dc73580143f3c77e898cf7ad78b27bb5e64dbe9652668fcafec7"},
- {file = "multidict-4.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8d919034420378132d074bf89df148d0193e9780c9fe7c0e495e895b8af4d8a2"},
- {file = "multidict-4.6.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:a37433ce8cdb35fc9e6e47e1606fa1bfd6d70440879038dca7d8dd023197eaa9"},
- {file = "multidict-4.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1b605272c558e4c659dbaf0fb32a53bfede44121bcf77b356e6e906867b958b7"},
- {file = "multidict-4.6.1-cp37-cp37m-win32.whl", hash = "sha256:891b7e142885e17a894d9d22b0349b92bb2da4769b4e675665d0331c08719be5"},
- {file = "multidict-4.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:250632316295f2311e1ed43e6b26a63b0216b866b45c11441886ac1543ca96e1"},
- {file = "multidict-4.6.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:2bc9c2579312c68a3552ee816311c8da76412e6f6a9cf33b15152e385a572d2a"},
- {file = "multidict-4.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0ffe4d4d28cbe9801952bfb52a8095dd9ffecebd93f84bdf973c76300de783c5"},
- {file = "multidict-4.6.1-cp38-cp38-win32.whl", hash = "sha256:87e26d8b89127c25659e962c61a4c655ec7445d19150daea0759516884ecb8b4"},
- {file = "multidict-4.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:c626029841ada34c030b94a00c573a0c7575fe66489cde148785b6535397d675"},
- {file = "multidict-4.6.1.tar.gz", hash = "sha256:5159c4975931a1a78bf6602bbebaa366747fce0a56cb2111f44789d2c45e379f"},
+ {file = "multidict-4.7.2-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:8f30ead697c2e37147d82ba8019952b5ea99bd3d1052f1f1ebff951eaa953209"},
+ {file = "multidict-4.7.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:824716bba5a4efd74ddd36a3830efb9e49860149514ef7c41aac0144757ebb5d"},
+ {file = "multidict-4.7.2-cp35-cp35m-win32.whl", hash = "sha256:63d9a3d93a514549760cb68c82864966bddb6ab53a3326931c8db9ad29414603"},
+ {file = "multidict-4.7.2-cp35-cp35m-win_amd64.whl", hash = "sha256:a03efe8b7591c77d9ad4b9d81dcfb9c96e538ae25eb114385f35f4d7ffa3bac2"},
+ {file = "multidict-4.7.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:7dd6f6a51b64d0a6473bc30c53e1d73fcb461c437f43662b7d6d701bd90db253"},
+ {file = "multidict-4.7.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:77264002c184538df5dcb4fc1de5df6803587fa30bbe12203a7a3436b8aafc0f"},
+ {file = "multidict-4.7.2-cp36-cp36m-win32.whl", hash = "sha256:b86e8e33a0a24240b293e7fad233a7e886bae6e51ca6923d39f4e313dd1d5578"},
+ {file = "multidict-4.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:daf6d89e47418e38af98e1f2beb3fe0c8aa34806f681d04df314c0f131dcf01d"},
+ {file = "multidict-4.7.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:7f4e591ec80619e74c50b7800f9db9b0e01d2099094767050dfe2e78e1c41839"},
+ {file = "multidict-4.7.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:335344a3c3b19845c73a7826f359c51c4a12a1ccd2392b5f572a63b452bfc771"},
+ {file = "multidict-4.7.2-cp37-cp37m-win32.whl", hash = "sha256:615a282acd530a1bc1b01f069a8c5874cb7c2780c287a2895ad5ab7407540e9d"},
+ {file = "multidict-4.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:20081b14c923d2c5122c13e060d0ee334e078e1802c36006b20c8d7a59ee6a52"},
+ {file = "multidict-4.7.2-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:49e80c53659c7ac50ec1c4b5fa50f045b67fffeb5b735dccb6205e4ff122e8b6"},
+ {file = "multidict-4.7.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ff53a434890a16356bc45c0b90557efd89d0e5a820dbab37015d7ee630c6707a"},
+ {file = "multidict-4.7.2-cp38-cp38-win32.whl", hash = "sha256:c1c64c93b8754a5cebd495d136f47a5ca93cbfceba532e306a768c27a0c1292b"},
+ {file = "multidict-4.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:e03b7addca96b9eb24d6eabbdc3041e8f71fd47b316e0f3c0fa993fc7b99002c"},
+ {file = "multidict-4.7.2.tar.gz", hash = "sha256:d4dafdcfbf0ac80fc5f00603f0ce43e487c654ae34a656e4749f175d9832b1b5"},
]
packaging = [
{file = "packaging-19.2-py2.py3-none-any.whl", hash = "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"},
@@ -1052,6 +1200,40 @@ py = [
pycparser = [
{file = "pycparser-2.19.tar.gz", hash = "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"},
]
+pycryptodome = [
+ {file = "pycryptodome-3.9.4-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:6c2720696b10ae356040e888bde1239b8957fe18885ccf5e7b4e8dec882f0856"},
+ {file = "pycryptodome-3.9.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:5c485ed6e9718ebcaa81138fa70ace9c563d202b56a8cee119b4085b023931f5"},
+ {file = "pycryptodome-3.9.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:56fdd0e425f1b8fd3a00b6d96351f86226674974814c50534864d0124d48871f"},
+ {file = "pycryptodome-3.9.4-cp27-cp27m-win32.whl", hash = "sha256:2de33ed0a95855735d5a0fc0c39603314df9e78ee8bbf0baa9692fb46b3b8bbb"},
+ {file = "pycryptodome-3.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:eec0689509389f19875f66ae8dedd59f982240cdab31b9f78a8dc266011df93a"},
+ {file = "pycryptodome-3.9.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:68fab8455efcbfe87c5d75015476f9b606227ffe244d57bfd66269451706e899"},
+ {file = "pycryptodome-3.9.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4b9533d4166ca07abdd49ce9d516666b1df944997fe135d4b21ac376aa624aff"},
+ {file = "pycryptodome-3.9.4-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:d3fe3f33ad52bf0c19ee6344b695ba44ffbfa16f3c29ca61116b48d97bd970fb"},
+ {file = "pycryptodome-3.9.4-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:319e568baf86620b419d53063b18c216abf924875966efdfe06891b987196a45"},
+ {file = "pycryptodome-3.9.4-cp34-cp34m-win32.whl", hash = "sha256:042ae873baadd0c33b4d699a5c5b976ade3233a979d972f98ca82314632d868c"},
+ {file = "pycryptodome-3.9.4-cp34-cp34m-win_amd64.whl", hash = "sha256:a30f501bbb32e01a49ef9e09ca1260e5ab49bf33a257080ec553e08997acc487"},
+ {file = "pycryptodome-3.9.4-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:b55c60c321ac91945c60a40ac9896ac7a3d432bb3e8c14006dfd82ad5871c331"},
+ {file = "pycryptodome-3.9.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:9d9945ac8375d5d8e60bd2a2e1df5882eaa315522eedf3ca868b1546dfa34eba"},
+ {file = "pycryptodome-3.9.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:4372ec7518727172e1605c0843cdc5375d4771e447b8148c787b860260aae151"},
+ {file = "pycryptodome-3.9.4-cp35-cp35m-win32.whl", hash = "sha256:0502876279772b1384b660ccc91563d04490d562799d8e2e06b411e2d81128a9"},
+ {file = "pycryptodome-3.9.4-cp35-cp35m-win_amd64.whl", hash = "sha256:72166c2ac520a5dbd2d90208b9c279161ec0861662a621892bd52fb6ca13ab91"},
+ {file = "pycryptodome-3.9.4-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b4af098f2a50f8d048ab12cabb59456585c0acf43d90ee79782d2d6d0ed59dba"},
+ {file = "pycryptodome-3.9.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8a799bea3c6617736e914a2e77c409f52893d382f619f088f8a80e2e21f573c1"},
+ {file = "pycryptodome-3.9.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7c52308ac5b834331b2f107a490b2c27de024a229b61df4cdc5c131d563dfe98"},
+ {file = "pycryptodome-3.9.4-cp36-cp36m-win32.whl", hash = "sha256:63c103a22cbe9752f6ea9f1a0de129995bad91c4d03a66c67cffcf6ee0c9f1e1"},
+ {file = "pycryptodome-3.9.4-cp36-cp36m-win_amd64.whl", hash = "sha256:54456cf85130e01674d21fb1ab89ffccacb138a8ade88d72fa2b0ac898d2798b"},
+ {file = "pycryptodome-3.9.4-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:aec4d42deb836b8fb3ba32f2ba1ef0d33dd3dc9d430b1479ee7a914490d15b5e"},
+ {file = "pycryptodome-3.9.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:896e9b6fd0762aa07b203c993fbbee7a1f1a4674c6886afd7bfa86f3d1be98a8"},
+ {file = "pycryptodome-3.9.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:57b1b707363490c495ad0eeb38bd1b0e1697c497af25fad78d3a1ebf0477fd5b"},
+ {file = "pycryptodome-3.9.4-cp37-cp37m-win32.whl", hash = "sha256:87d8d85b4792ca5e730fb7a519fbc3ed976c59dcf79c5204589c59afd56b9926"},
+ {file = "pycryptodome-3.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:e3a79a30d15d9c7c284a7734036ee8abdb5ca3a6f5774d293cdc9e1358c1dc10"},
+ {file = "pycryptodome-3.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:48821950ffb9c836858d8fa09d7840b6df52eadd387a3c5acece55cb387743f9"},
+ {file = "pycryptodome-3.9.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cbfd97f9e060f0d30245cd29fa267a9a84de9da97559366fca0a3f7655acc63f"},
+ {file = "pycryptodome-3.9.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9ef966c727de942de3e41aa8462c4b7b4bca70f19af5a3f99e31376589c11aac"},
+ {file = "pycryptodome-3.9.4-cp38-cp38-win32.whl", hash = "sha256:a8ca2450394d3699c9f15ef25e8de9a24b401933716a1e39d37fa01f5fe3c58b"},
+ {file = "pycryptodome-3.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:c53348358408d94869059e16fba5ff3bef8c52c25b18421472aba272b9bb450f"},
+ {file = "pycryptodome-3.9.4.tar.gz", hash = "sha256:a168e73879619b467072509a223282a02c8047d932a48b74fbd498f27224aa04"},
+]
pygments = [
{file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"},
{file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"},
@@ -1088,9 +1270,12 @@ pyreadline = [
{file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"},
{file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},
]
+pyrsistent = [
+ {file = "pyrsistent-0.15.6.tar.gz", hash = "sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b"},
+]
pytest = [
- {file = "pytest-5.3.1-py3-none-any.whl", hash = "sha256:63344a2e3bce2e4d522fd62b4fdebb647c019f1f9e4ca075debbd13219db4418"},
- {file = "pytest-5.3.1.tar.gz", hash = "sha256:f67403f33b2b1d25a6756184077394167fe5e2f9d8bdaab30707d19ccec35427"},
+ {file = "pytest-5.3.2-py3-none-any.whl", hash = "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4"},
+ {file = "pytest-5.3.2.tar.gz", hash = "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa"},
]
python-dateutil = [
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
@@ -1108,17 +1293,27 @@ pytz = [
{file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"},
]
regex = [
- {file = "regex-2019.12.9-cp27-none-win32.whl", hash = "sha256:40b7d1291a56897927e08bb973f8c186c2feb14c7f708bfe7aaee09483e85a20"},
- {file = "regex-2019.12.9-cp27-none-win_amd64.whl", hash = "sha256:c203c9ee755e9656d0af8fab82754d5a664ebaf707b3f883c7eff6a3dd5151cf"},
- {file = "regex-2019.12.9-cp35-none-win32.whl", hash = "sha256:719978a9145d59fc78509ea1d1bb74243f93583ef2a34dcc5623cf8118ae9726"},
- {file = "regex-2019.12.9-cp35-none-win_amd64.whl", hash = "sha256:75cf3796f89f75f83207a5c6a6e14eaf57e0369ef0ffff8e22bf36bbcfa0f1de"},
- {file = "regex-2019.12.9-cp36-none-win32.whl", hash = "sha256:3dbd8333fd2ebd50977ac8747385a73aa1f546eb6b16fcd83d274470fe11f243"},
- {file = "regex-2019.12.9-cp36-none-win_amd64.whl", hash = "sha256:ad9e3c7260809c0d1ded100269f78ea0217c0704f1eaaf40a382008461848b45"},
- {file = "regex-2019.12.9-cp37-none-win32.whl", hash = "sha256:91235c98283d2bddf1a588f0fbc2da8afa37959294bbd18b76297bdf316ba4d6"},
- {file = "regex-2019.12.9-cp37-none-win_amd64.whl", hash = "sha256:aaffd68c4c1ed891366d5c390081f4bf6337595e76a157baf453603d8e53fbcb"},
- {file = "regex-2019.12.9-cp38-none-win32.whl", hash = "sha256:e865bc508e316a3a09d36c8621596e6599a203bc54f1cd41020a127ccdac468a"},
- {file = "regex-2019.12.9-cp38-none-win_amd64.whl", hash = "sha256:77396cf80be8b2a35db863cca4c1a902d88ceeb183adab328b81184e71a5eafe"},
- {file = "regex-2019.12.9.tar.gz", hash = "sha256:77a3799152951d6d14ae5720ca162c97c64f85d4755da585418eac216b736cad"},
+ {file = "regex-2019.12.20-cp27-cp27m-win32.whl", hash = "sha256:7bbbdbada3078dc360d4692a9b28479f569db7fc7f304b668787afc9feb38ec8"},
+ {file = "regex-2019.12.20-cp27-cp27m-win_amd64.whl", hash = "sha256:a83049eb717ae828ced9cf607845929efcb086a001fc8af93ff15c50012a5716"},
+ {file = "regex-2019.12.20-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:27d1bd20d334f50b7ef078eba0f0756a640fd25f5f1708d3b5bed18a5d6bced9"},
+ {file = "regex-2019.12.20-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1768cf42a78a11dae63152685e7a1d90af7a8d71d2d4f6d2387edea53a9e0588"},
+ {file = "regex-2019.12.20-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:4850c78b53acf664a6578bba0e9ebeaf2807bb476c14ec7e0f936f2015133cae"},
+ {file = "regex-2019.12.20-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:78b3712ec529b2a71731fbb10b907b54d9c53a17ca589b42a578bc1e9a2c82ea"},
+ {file = "regex-2019.12.20-cp36-cp36m-win32.whl", hash = "sha256:8d9ef7f6c403e35e73b7fc3cde9f6decdc43b1cb2ff8d058c53b9084bfcb553e"},
+ {file = "regex-2019.12.20-cp36-cp36m-win_amd64.whl", hash = "sha256:faad39fdbe2c2ccda9846cd21581063086330efafa47d87afea4073a08128656"},
+ {file = "regex-2019.12.20-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:adc35d38952e688535980ae2109cad3a109520033642e759f987cf47fe278aa1"},
+ {file = "regex-2019.12.20-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ef0b828a7e22e58e06a1cceddba7b4665c6af8afeb22a0d8083001330572c147"},
+ {file = "regex-2019.12.20-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:0e6cf1e747f383f52a0964452658c04300a9a01e8a89c55ea22813931b580aa8"},
+ {file = "regex-2019.12.20-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:032fdcc03406e1a6485ec09b826eac78732943840c4b29e503b789716f051d8d"},
+ {file = "regex-2019.12.20-cp37-cp37m-win32.whl", hash = "sha256:77ae8d926f38700432807ba293d768ba9e7652df0cbe76df2843b12f80f68885"},
+ {file = "regex-2019.12.20-cp37-cp37m-win_amd64.whl", hash = "sha256:c29a77ad4463f71a506515d9ec3a899ed026b4b015bf43245c919ff36275444b"},
+ {file = "regex-2019.12.20-cp38-cp38-manylinux1_i686.whl", hash = "sha256:57eacd38a5ec40ed7b19a968a9d01c0d977bda55664210be713e750dd7b33540"},
+ {file = "regex-2019.12.20-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:724eb24b92fc5fdc1501a1b4df44a68b9c1dda171c8ef8736799e903fb100f63"},
+ {file = "regex-2019.12.20-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d508875793efdf6bab3d47850df8f40d4040ae9928d9d80864c1768d6aeaf8e3"},
+ {file = "regex-2019.12.20-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cfd31b3300fefa5eecb2fe596c6dee1b91b3a05ece9d5cfd2631afebf6c6fadd"},
+ {file = "regex-2019.12.20-cp38-cp38-win32.whl", hash = "sha256:29b20f66f2e044aafba86ecf10a84e611b4667643c42baa004247f5dfef4f90b"},
+ {file = "regex-2019.12.20-cp38-cp38-win_amd64.whl", hash = "sha256:d3ee0b035816e0520fac928de31b6572106f0d75597f6fa3206969a02baba06f"},
+ {file = "regex-2019.12.20.tar.gz", hash = "sha256:106e25a841921d8259dcef2a42786caae35bc750fb996f830065b3dfaa67b77e"},
]
requests = [
{file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"},
@@ -1137,8 +1332,8 @@ snowballstemmer = [
{file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"},
]
sphinx = [
- {file = "Sphinx-2.2.2-py3-none-any.whl", hash = "sha256:3b16e48e791a322d584489ab28d8800652123d1fbfdd173e2965a31d40bf22d7"},
- {file = "Sphinx-2.2.2.tar.gz", hash = "sha256:559c1a8ed1365a982f77650720b41114414139a635692a23c2990824d0a84cf2"},
+ {file = "Sphinx-2.3.1-py3-none-any.whl", hash = "sha256:298537cb3234578b2d954ff18c5608468229e116a9757af3b831c2b2b4819159"},
+ {file = "Sphinx-2.3.1.tar.gz", hash = "sha256:e6e766b74f85f37a5f3e0773a1e1be8db3fcb799deb58ca6d18b70b0b44542a5"},
]
sphinx-rtd-theme = [
{file = "sphinx_rtd_theme-0.4.3-py2.py3-none-any.whl", hash = "sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4"},
@@ -1169,7 +1364,7 @@ sphinxcontrib-serializinghtml = [
{file = "sphinxcontrib_serializinghtml-1.1.3-py2.py3-none-any.whl", hash = "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"},
]
sqlalchemy = [
- {file = "SQLAlchemy-1.3.11.tar.gz", hash = "sha256:afa5541e9dea8ad0014251bc9d56171ca3d8b130c9627c6cb3681cff30be3f8a"},
+ {file = "SQLAlchemy-1.3.12.tar.gz", hash = "sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec"},
]
starlette = [
{file = "starlette-0.12.13.tar.gz", hash = "sha256:9597bc28e3c4659107c1c4a45ec32dc45e947d78fe56230222be673b2c36454a"},
@@ -1196,12 +1391,17 @@ tzlocal = [
{file = "tzlocal-2.0.0-py2.py3-none-any.whl", hash = "sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048"},
{file = "tzlocal-2.0.0.tar.gz", hash = "sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"},
]
+unpaddedbase64 = [
+ {file = "unpaddedbase64-1.1.0-py2-none-any.whl", hash = "sha256:8917367e4e915b7dce1a72a99db8798c9f3d0d9a74cdd9aafac6d7c65ca495c5"},
+ {file = "unpaddedbase64-1.1.0-py2.py3-none-any.whl", hash = "sha256:81cb4eaaa28cc6a282dd3f2c3855eaa1fbaafa736b5ee64df69889e20540a339"},
+]
urllib3 = [
{file = "urllib3-1.25.7-py2.py3-none-any.whl", hash = "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293"},
{file = "urllib3-1.25.7.tar.gz", hash = "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"},
]
uvicorn = [
- {file = "uvicorn-0.10.8.tar.gz", hash = "sha256:f4c34642618449f55e2bab8c6b22ff7615b520d2e7e23275be2ca894254327a3"},
+ {file = "uvicorn-0.10.9-py3-none-any.whl", hash = "sha256:dc7119b28e15c4c737315c5a570081b0a5a7d8d5c1e8a70a7be70043d88b23a7"},
+ {file = "uvicorn-0.10.9.tar.gz", hash = "sha256:c010df69d16e27f1a18481316325b4fd23f562c1fac050915fc03a397d0f6b64"},
]
uvloop = [
{file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"},
diff --git a/pyproject.toml b/pyproject.toml
index 9f6d3f90..d9a42327 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,8 +1,11 @@
-# Remember to run `poetry update` after you edit this file!
+# Remember to run `poetry update` editing this file!
+
+# Install everything with
+# poetry install -E telegram -E discord -E alchemy_easy -E alchemy_hard -E bard -E constellation -E sentry -E herald -E coloredlogs
[tool.poetry]
name = "royalnet"
- version = "5.1.6"
+ version = "5.2.1"
description = "A multipurpose bot and web framework"
authors = ["Stefano Pigozzi "]
license = "AGPL-3.0+"
@@ -29,6 +32,9 @@
temp_discordpy_without_websockets_requirement = {version="0.1", optional=true} # discord.py 1.2.4 is missing Go Live related methods
pynacl = {version="^1.3.0", optional=true} # This requires libffi-dev and python3.*-dev to be installed on Linux systems
+ # matrix
+ matrix-nio = {version="^0.6", optional=true}
+
# bard
ffmpeg_python = {version="~0.2.0", optional=true}
youtube_dl = {version="*", optional=true}
@@ -63,6 +69,7 @@
[tool.poetry.extras]
telegram = ["python_telegram_bot"]
discord = ["temp_discordpy_without_websockets_requirement", "pynacl"]
+ matrix = ["matrix-nio"]
alchemy_easy = ["sqlalchemy", "psycopg2_binary"]
alchemy_hard = ["sqlalchemy", "psycopg2"]
bard = ["ffmpeg_python", "youtube_dl"]
diff --git a/royalnet/__main__.py b/royalnet/__main__.py
index d848f258..11024b86 100644
--- a/royalnet/__main__.py
+++ b/royalnet/__main__.py
@@ -58,7 +58,7 @@ def run(config_filename: str):
# Serfs
telegram_process = None
- if config["Serfs"]["Telegram"]["enabled"]:
+ if "Telegram" in config["Serfs"] and config["Serfs"]["Telegram"]["enabled"]:
telegram_process = multiprocessing.Process(name="Serf.Telegram",
target=rs.telegram.TelegramSerf.run_process,
daemon=True,
@@ -76,7 +76,7 @@ def run(config_filename: str):
log.info("Serf.Telegram: Disabled")
discord_process = None
- if config["Serfs"]["Discord"]["enabled"]:
+ if "Discord" in config["Serfs"] and config["Serfs"]["Discord"]["enabled"]:
discord_process = multiprocessing.Process(name="Serf.Discord",
target=rs.discord.DiscordSerf.run_process,
daemon=True,
@@ -93,6 +93,24 @@ def run(config_filename: str):
else:
log.info("Serf.Discord: Disabled")
+ matrix_process = None
+ if "Matrix" in config["Serfs"] and config["Serfs"]["Matrix"]["enabled"]:
+ matrix_process = multiprocessing.Process(name="Serf.Matrix",
+ target=rs.matrix.MatrixSerf.run_process,
+ daemon=True,
+ kwargs={
+ "alchemy_cfg": config["Alchemy"],
+ "herald_cfg": herald_cfg,
+ "packs_cfg": config["Packs"],
+ "sentry_cfg": config["Sentry"],
+ "logging_cfg": config["Logging"],
+ "serf_cfg": config["Serfs"]["Matrix"],
+ })
+ matrix_process.start()
+ log.info("Serf.Discord: Started")
+ else:
+ log.info("Serf.Discord: Disabled")
+
# Constellation
constellation_process = None
if config["Constellation"]["enabled"]:
diff --git a/royalnet/backpack/tables/__init__.py b/royalnet/backpack/tables/__init__.py
index ca4f3429..b33c646f 100644
--- a/royalnet/backpack/tables/__init__.py
+++ b/royalnet/backpack/tables/__init__.py
@@ -2,12 +2,14 @@
from .users import User
from .telegram import Telegram
from .discord import Discord
+from .matrix import Matrix
# Enter the tables of your Pack here!
available_tables = {
User,
Telegram,
- Discord
+ Discord,
+ Matrix,
}
# Don't change this, it should automatically generate __all__
diff --git a/royalnet/backpack/tables/matrix.py b/royalnet/backpack/tables/matrix.py
new file mode 100644
index 00000000..b1c11d61
--- /dev/null
+++ b/royalnet/backpack/tables/matrix.py
@@ -0,0 +1,44 @@
+from sqlalchemy import *
+from sqlalchemy.orm import relationship
+from sqlalchemy.ext.declarative import declared_attr
+# noinspection PyUnresolvedReferences
+from .users import User
+import re
+
+
+class Matrix:
+ __tablename__ = "matrix"
+
+ @declared_attr
+ def user_id(self):
+ return Column(Integer, ForeignKey("users.uid"))
+
+ @declared_attr
+ def user(self):
+ return relationship("User", backref="matrix")
+
+ @declared_attr
+ def matrix_id(self):
+ return Column(String, nullable=False, primary_key=True)
+
+ @property
+ def username(self):
+ # TODO: check this regex
+ match = re.match("^@(.+):.+$", self.matrix_id)
+ result = match.group(1)
+ assert result is not None
+ return result
+
+ @property
+ def homeserver(self):
+ # TODO: check this regex
+ match = re.match("^@.+:(.+)$", self.matrix_id)
+ result = match.group(1)
+ assert result is not None
+ return result
+
+ def __repr__(self):
+ return f""
+
+ def __str__(self):
+ return f"[c]matrix:{self.matrix_id}[/c]"
diff --git a/royalnet/serf/__init__.py b/royalnet/serf/__init__.py
index 57cc18c3..dffff404 100644
--- a/royalnet/serf/__init__.py
+++ b/royalnet/serf/__init__.py
@@ -1,10 +1,11 @@
from .serf import Serf
from .errors import SerfError
-from . import telegram, discord
+from . import telegram, discord, matrix
__all__ = [
"Serf",
"SerfError",
"telegram",
"discord",
+ "matrix",
]
diff --git a/royalnet/serf/matrix/__init__.py b/royalnet/serf/matrix/__init__.py
new file mode 100644
index 00000000..09d99dcd
--- /dev/null
+++ b/royalnet/serf/matrix/__init__.py
@@ -0,0 +1,5 @@
+from .matrixserf import MatrixSerf
+
+__all__ = [
+ "MatrixSerf",
+]
\ No newline at end of file
diff --git a/royalnet/serf/matrix/matrixserf.py b/royalnet/serf/matrix/matrixserf.py
new file mode 100644
index 00000000..adf3f8a0
--- /dev/null
+++ b/royalnet/serf/matrix/matrixserf.py
@@ -0,0 +1,139 @@
+from typing import *
+import logging
+import datetime
+import asyncio as aio
+import royalnet.backpack as rb
+import royalnet.commands as rc
+import royalnet.utils as ru
+from ..serf import Serf
+
+
+try:
+ import nio
+except ImportError:
+ nio = None
+
+
+log = logging.getLogger(__name__)
+
+
+class MatrixSerf(Serf):
+ """A serf that connects to `Matrix `_ as an user."""
+ interface_name = "matrix"
+
+ _identity_table = rb.tables.Matrix
+ _identity_column = "matrix_id"
+
+ def __init__(self,
+ loop: aio.AbstractEventLoop,
+ alchemy_cfg: Dict[str, Any],
+ herald_cfg: Dict[str, Any],
+ sentry_cfg: Dict[str, Any],
+ packs_cfg: Dict[str, Any],
+ serf_cfg: Dict[str, Any],
+ **_):
+ if nio is None:
+ raise ImportError("'matrix' extra is not installed")
+
+ super().__init__(loop=loop,
+ alchemy_cfg=alchemy_cfg,
+ herald_cfg=herald_cfg,
+ sentry_cfg=sentry_cfg,
+ packs_cfg=packs_cfg,
+ serf_cfg=serf_cfg)
+
+ self.client: Optional[nio.AsyncClient] = None
+
+ self.homeserver: str = serf_cfg["homeserver"]
+ self.matrix_id: str = serf_cfg["matrix_id"]
+ self.password: str = serf_cfg["password"]
+
+ self._started_timestamp: Optional[int] = None
+
+ def interface_factory(self) -> Type[rc.CommandInterface]:
+ # noinspection PyPep8Naming
+ GenericInterface = super().interface_factory()
+
+ # noinspection PyMethodParameters,PyAbstractClass
+ class DiscordInterface(GenericInterface):
+ name = self.interface_name
+ prefix = "!"
+
+ return DiscordInterface
+
+ def data_factory(self) -> Type[rc.CommandData]:
+ # noinspection PyMethodParameters,PyAbstractClass
+ class DiscordData(rc.CommandData):
+ def __init__(data,
+ interface: rc.CommandInterface,
+ session,
+ loop: aio.AbstractEventLoop,
+ room: nio.MatrixRoom,
+ event: nio.Event):
+ super().__init__(interface=interface, session=session, loop=loop)
+ data.room: nio.MatrixRoom = room
+ data.event: nio.Event = event
+
+ async def reply(data, text: str):
+ await self.client.room_send(room_id=data.room.room_id, message_type="m.room.message", content={
+ "msgtype": "m.text",
+ "body": text
+ })
+
+ async def get_author(data, error_if_none=False):
+ user: str = data.event.sender
+ query = data.session.query(self.master_table)
+ for link in self.identity_chain:
+ query = query.join(link.mapper.class_)
+ query = query.filter(self.identity_column == user)
+ result = await ru.asyncify(query.one_or_none)
+ if result is None and error_if_none:
+ raise rc.CommandError("You must be registered to use this command.")
+ return result
+
+ # Delete invoking does not really make sense on Matrix
+
+ return DiscordData
+
+ async def handle_message(self, room: "nio.MatrixRoom", event: "nio.RoomMessageText"):
+ # Skip events happened before the startup of the Serf
+ if event.server_timestamp < self._started_timestamp:
+ return
+ # Find the text in the event
+ text = event.body
+ # Skip non-command events
+ if not text.startswith("!"):
+ return
+ # Find and clean parameters
+ command_text, *parameters = text.split(" ")
+ # Don't use a case-sensitive command name
+ command_name = command_text.lower()
+ # Find the command
+ try:
+ command = self.commands[command_name]
+ except KeyError:
+ # Skip the message
+ return
+ # Send typing
+ await self.client.room_typing(room_id=room.room_id, typing_state=True)
+ # Open an alchemy session, if available
+ if self.alchemy is not None:
+ session = await ru.asyncify(self.alchemy.Session)
+ else:
+ session = None
+ # Prepare data
+ data = self.Data(interface=command.interface, session=session, loop=self.loop, room=room, event=event)
+ # Call the command
+ await self.call(command, data, parameters)
+ # Close the alchemy session
+ if session is not None:
+ await ru.asyncify(session.close)
+
+ async def run(self):
+ self.client = nio.AsyncClient(self.homeserver, self.matrix_id)
+ await self.client.login(self.password)
+ self._started_timestamp = int(datetime.datetime.now().timestamp() * 1000)
+ # matrix-nio type annotations are wrong for asyncclients
+ # noinspection PyTypeChecker
+ self.client.add_event_callback(self.handle_message, (nio.RoomMessageText,))
+ await self.client.sync_forever()
diff --git a/royalnet/version.py b/royalnet/version.py
index a4a20039..c45e457a 100644
--- a/royalnet/version.py
+++ b/royalnet/version.py
@@ -1 +1 @@
-semantic = "5.1.6"
+semantic = "5.2.1"
diff --git a/sample_config.toml b/sample_config.toml
index 4376fe89..fbe24ae5 100644
--- a/sample_config.toml
+++ b/sample_config.toml
@@ -81,6 +81,18 @@ enabled = true
# Obtain one at https://discordapp.com/developers/applications/ > Bot > Token
token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+[Serfs.Matrix]
+# Use the Matrix Serf (matrix-nio) included in Royalnet
+# Requires the `matrix` extra to be installed
+enabled = true
+# The homeserver to login at
+homeserver = "https://example.org"
+# The full matrix id to login as
+matrix_id = "@username:example.org"
+# The password of the matrix account to login as
+password = "xxxxxxx"
+
+
[Logging]
# The output format for the Royalnet logs
# See https://docs.python.org/3/library/logging.html#logrecord-attributes for {}-formatting