60 Commits

Author SHA1 Message Date
c4b54357f7 automatically adding recorders, models and rooms and association of those 2019-11-22 14:26:16 +01:00
Tobias Kurze
7700b4381f now rooms, recorders and recorder models get initialized in DB 2019-11-20 16:19:59 +01:00
Tobias Kurze
60ff5bdeaf added code to initialize db with models and recodres 2019-11-20 12:41:05 +01:00
bc1347fe99 changed pw in recorders.jso 2019-11-14 15:40:57 +01:00
9ef9d98132 added logging to smp adapter 2019-11-14 15:19:44 +01:00
bab6403f91 changed thread pool code again 2019-11-14 15:08:06 +01:00
692649e08f changed thread pool code again 2019-11-14 15:05:06 +01:00
6f1e01781a changed thread pool code again 2019-11-14 15:02:20 +01:00
7224038e64 modified threadpool run to use timeout 2019-11-14 14:56:55 +01:00
c96cdfc6e1 fixed bug in smp adapter 2019-11-14 14:39:27 +01:00
c3d8a1e91a fixed bug in smp adapter 2019-11-14 14:29:12 +01:00
b214d161bf slightly modified smp adapter for testing 2019-11-14 14:23:19 +01:00
e19ce060d8 exception decorator and mail send for errors and changes to rec state checker 2019-11-14 14:15:36 +01:00
Tobias Kurze
6081486a35 using git-crypt instead of manual encrypton filters 2019-11-13 13:04:18 +01:00
Tobias Kurze
2da856dd36 using git-crypt instead of manual encrypton filters 2019-11-13 12:59:09 +01:00
Tobias Kurze
872e531ef5 added logging conf and now checking recording status with simple script ; notifications are missing 2019-11-13 08:19:39 +01:00
Tobias Kurze
4563e16137 moved creds to config 2019-11-12 12:43:45 +01:00
Tobias Kurze
8b05bb694f added excel->json recorder source generation script 2019-11-12 12:32:49 +01:00
5d731c9fba moved some models added cron and websocket base class 2019-10-31 16:13:02 +01:00
Tobias Kurze
36c889956f added websocket test flies 2019-10-30 11:54:53 +01:00
Tobias Kurze
a408fd3b4c added ws base code 2019-10-25 15:59:41 +02:00
Tobias Kurze
32c2674210 added code for saving config (might not be complete 2019-10-25 13:49:41 +02:00
d61c395d2c added access control model and more stuff around access mgmt 2019-10-23 16:33:24 +02:00
6b4f7c8118 moved everything to a new module called backend 2019-10-23 15:00:33 +02:00
310d5f4820 using current user in some placesi 2019-08-15 14:32:04 +02:00
9ab0d43f43 profile and other stuff 2019-08-14 16:38:03 +02:00
Tobias Kurze
859a5d880a working on control 2019-08-13 16:30:45 +02:00
Tobias Kurze
f70cbdc463 now scraping rooms from capmus mgmt 2019-08-13 15:29:37 +02:00
48505b76ea fixed (circumvented) bug related to hybrid_property and parameter serialization 2019-08-08 20:31:08 +02:00
c0e56cf40d now scanning model difinietons and updating db entries 2019-08-08 16:38:15 +02:00
Tobias Kurze
123eb65f8e some changes to virtual command 2019-08-05 15:28:39 +02:00
Tobias Kurze
186614bc4a added virtual commands model 2019-08-05 13:41:12 +02:00
Tobias Kurze
51536766bf using reflection to get models 2019-08-02 16:09:39 +02:00
Tobias Kurze
3c6b6ba099 finished smp extron telnet adapter (more or less) 2019-07-04 13:29:44 +02:00
4d01f7025b added more smp >API< functions 2019-07-03 16:09:10 +02:00
Tobias Kurze
3a7d8dbdd4 just added comment for TODO 2019-07-03 13:51:51 +02:00
Tobias Kurze
88f5c3023d added lot of functs for SMP 2019-06-21 16:32:08 +02:00
Tobias Kurze
4485dea583 added recorder command backend 2019-06-21 11:04:12 +02:00
70df74cecf updated recorder model 2019-05-03 18:40:43 +02:00
Tobias Kurze
fad2238b75 added ports to api model 2019-05-03 15:52:52 +02:00
Tobias Kurze
295aadfaeb fixed and extended apis 2019-04-26 15:34:23 +02:00
07d01304be added room and recorder api and added length check (for sqlite) 2019-04-26 09:42:52 +02:00
Tobias Kurze
254637bfa9 some migrations; commit just to be on 'nice' state 2019-04-17 09:07:24 +02:00
3ecc8e0955 some changes to auth and group api 2019-04-15 14:14:42 +02:00
cbc269edf2 removed old dB code and continued on group and user mgmt 2019-04-11 16:18:46 +02:00
Tobias Kurze
2451a56403 added / implemented group API 2019-04-10 15:11:21 +02:00
Tobias Kurze
f0783d97c8 changes to auth and user API 2019-04-05 16:21:24 +02:00
8b7b2f489c added user and group API and models 2019-04-04 16:05:36 +02:00
cfa12717e0 added toJSON func 2019-04-02 16:58:59 +02:00
Tobias Kurze
8cf8632c8c added db migrations and group support, still problems with json serialization 2019-04-02 16:10:46 +02:00
024f063bea better separation between api and frontend login 2019-04-02 10:47:53 +02:00
Tobias Kurze
ed57dc2720 creating users from oidc id token 2019-03-26 16:17:18 +01:00
Tobias Kurze
cad27733f0 oicd now working 2019-03-26 14:58:37 +01:00
Tobias Kurze
bc50e23a22 improved/fixed serve_frontend.py to work from different base paths (change required for wsgi) 2019-03-26 11:57:22 +01:00
Tobias Kurze
ebc34e396d slightly changed user model (sort of fix) 2019-03-22 16:38:42 +01:00
0469b8dbb5 added a lot of auth code 2019-03-21 16:17:25 +01:00
Tobias Kurze
bef3c6dc9b added authentication API 2019-03-19 16:34:05 +01:00
Tobias Kurze
9d9c58d268 added OpenID Connect support 2019-03-19 15:29:26 +01:00
bd9b6c61d3 working db and tests Nr2 2019-03-14 17:14:05 +01:00
1c8cb55b46 working db and tests 2019-03-14 17:13:02 +01:00
76 changed files with 7367 additions and 167 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
PYTHONPATH=${PYTHONPATH}:${PWD}/..

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
backend/models/initial_recorders.json filter=git-crypt diff=git-crypt
#backend/models/initial_recorders.json filter=openssl diff=openssl
backend/config.py filter=git-crypt diff=git-crypt
#backend/config.py filter=openssl diff=openssl
[merge]
renormalize=true

120
.gitignore vendored
View File

@@ -1 +1,121 @@
app.db
# Byte-compiled / optimized / DLL files
.idea
__pycache__/
node_modules/
frontend/node_modules/
backend/uploads/*
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
package-lock.json
logs

22
Pipfile
View File

@@ -11,8 +11,28 @@ flask-sqlalchemy = "*"
flask-login = "*"
pyjwt = "*"
passlib = "*"
sqlalchemy = "*"
sqlalchemy-migrate = "*"
flask-script = "*"
flask-migrate = "*"
coverage = "*"
flask-testing = "*"
flask-pyoidc = "*"
python-jose = "*"
flask-jwt-extended = "*"
ssh2-python = "*"
update = "*"
flask-cors = "*"
html5lib = "*"
beautifulsoup4 = "*"
flask-socketio = "*"
eventlet = "*"
ics = "*"
coloredlogs = "*"
pythonping = "*"
scapy = "*"
[dev-packages]
[requires]
python_version = "3.7"
python_version = "3.8"

652
Pipfile.lock generated
View File

@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "196d1a010314c8f16ccc747ed35b4821e8e3aa63f90ec2893123ea19c95935b1"
"sha256": "76bfb08c216b99c72b4d6f0e7379173e2dcbc59c351b15d0695f60c2ddf46f5c"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
"python_version": "3.8"
},
"sources": [
{
@@ -16,26 +16,113 @@
]
},
"default": {
"alabaster": {
"hashes": [
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
],
"version": "==0.7.12"
},
"alembic": {
"hashes": [
"sha256:49277bb7242192bbb9eac58fed4fe02ec6c3a2a4b4345d2171197459266482b2"
],
"version": "==1.3.1"
},
"aniso8601": {
"hashes": [
"sha256:29ad6be3828ab6ac2a31fd2876fd84477cde11890ffca7e8a9434aad5d4acec8",
"sha256:a5c7595bb65d3919a9944a759d907b57c4d050abaa0e5cf845e84c26cdfd1218"
"sha256:529dcb1f5f26ee0df6c0a1ee84b7b27197c3c50fc3a6321d66c544689237d072",
"sha256:c033f63d028b9a58e3ab0c2c7d0532ab4bfa7452bfc788fbfe3ddabd327b181a"
],
"version": "==5.1.0"
"version": "==8.0.0"
},
"apispec": {
"hashes": [
"sha256:57a7b81fd19fff0663a7e5ffd196eaea79b5364151ed2b65533be36d55e0229c",
"sha256:b45def53903516e67e8584ee41f34bc60c3e4acace6892b69340293ea20f3caa"
"sha256:cf8e1f3b56949710f8cf23797b7f40215e9dae8bac583789a3f2c13dc56349fa",
"sha256:fe5cf5fc89b1c4a73acd5af3a10ede02b31ec116f215ed02271cb905d3172367"
],
"version": "==1.0.0"
"version": "==3.1.0"
},
"arrow": {
"hashes": [
"sha256:4bfacea734ead51495dc47df00421ecfd4ca1f2c0fbe58b9a26eaeddedc31caf",
"sha256:67f8be7c0cf420424bc62d8d7dc40b44e4bb2f7b515f9cc2954fb36e35797656"
],
"version": "==0.14.7"
},
"attrs": {
"hashes": [
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.1.0"
"version": "==19.3.0"
},
"beaker": {
"hashes": [
"sha256:ad5d1c05027ee3be3a482ea39f8cb70339b41e5d6ace0cb861382754076d187e"
],
"version": "==1.11.0"
},
"beautifulsoup4": {
"hashes": [
"sha256:5279c36b4b2ec2cb4298d723791467e3000e5384a43ea0cdf5d45207c7e97169",
"sha256:6135db2ba678168c07950f9a16c4031822c6f4aec75a65e0a97bc5ca09789931",
"sha256:dcdef580e18a76d54002088602eba453eec38ebbcafafeaabd8cab12b6155d57"
],
"index": "pypi",
"version": "==4.8.1"
},
"certifi": {
"hashes": [
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.9.11"
},
"cffi": {
"hashes": [
"sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
"sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
"sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
"sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
"sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
"sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
"sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
"sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
"sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
"sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
"sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
"sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
"sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
"sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
"sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
"sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
"sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
"sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
"sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
"sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
"sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
"sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
"sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
"sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
"sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
"sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
"sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
"sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
"sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
"sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
"sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
"sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
"sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
],
"version": "==1.13.2"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
@@ -44,21 +131,137 @@
],
"version": "==7.0"
},
"flask": {
"coloredlogs": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
"sha256:34fad2e342d5a559c31b6c889e8d14f97cb62c47d9a2ae7b5ed14ea10a79eff8",
"sha256:b869a2dda3fa88154b9dd850e27828d8755bfab5a838a1c97fbc850c6e377c36"
],
"index": "pypi",
"version": "==1.0.2"
"version": "==10.0"
},
"coverage": {
"hashes": [
"sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6",
"sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650",
"sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5",
"sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d",
"sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351",
"sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755",
"sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef",
"sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca",
"sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca",
"sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9",
"sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc",
"sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5",
"sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f",
"sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe",
"sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888",
"sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5",
"sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce",
"sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5",
"sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e",
"sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e",
"sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9",
"sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437",
"sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1",
"sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c",
"sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24",
"sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47",
"sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2",
"sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28",
"sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c",
"sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7",
"sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0",
"sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"
],
"index": "pypi",
"version": "==4.5.4"
},
"cryptography": {
"hashes": [
"sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c",
"sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595",
"sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad",
"sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651",
"sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2",
"sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff",
"sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d",
"sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42",
"sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d",
"sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e",
"sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912",
"sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793",
"sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13",
"sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7",
"sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0",
"sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879",
"sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f",
"sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9",
"sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2",
"sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf",
"sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"
],
"version": "==2.8"
},
"decorator": {
"hashes": [
"sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
"sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
],
"version": "==4.4.1"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
"version": "==1.16.0"
},
"ecdsa": {
"hashes": [
"sha256:64c613005f13efec6541bb0a33290d0d03c27abab5f15fbab20fb0ee162bdd8e",
"sha256:e108a5fe92c67639abae3260e43561af914e7fd0d27bae6d2ec1312ae7934dfe"
],
"version": "==0.14.1"
},
"eventlet": {
"hashes": [
"sha256:658b1cd80937adc1a4860de2841e0528f64e2ca672885c4e00fc0e2217bde6b1",
"sha256:6c9c625af48424c4680d89314dbe45a76cc990cf002489f9469ff214b044ffc1"
],
"index": "pypi",
"version": "==0.25.1"
},
"flask": {
"hashes": [
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
"sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
],
"index": "pypi",
"version": "==1.1.1"
},
"flask-cors": {
"hashes": [
"sha256:72170423eb4612f0847318afff8c247b38bd516b7737adfc10d1c2cdbb382d16",
"sha256:f4d97201660e6bbcff2d89d082b5b6d31abee04b1b3003ee073a6fd25ad1d69a"
],
"index": "pypi",
"version": "==3.0.8"
},
"flask-httpauth": {
"hashes": [
"sha256:c08b69b302f1aa7ecd0db327809132ef6ca9486a36a9174776da146d1a4adc18",
"sha256:f71b7611f385fbdf350e8c430eed17b41c3b2200dc35eae19c1734264b68e31d"
"sha256:0149953720489407e51ec24bc2f86273597b7973d71cd51f9443bd0e2a89bd72",
"sha256:6ef8b761332e780f9ff74d5f9056c2616f52babc1998b01d9f361a1e439e61b9"
],
"index": "pypi",
"version": "==3.2.4"
"version": "==3.3.0"
},
"flask-jwt-extended": {
"hashes": [
"sha256:0aa8ee6fa7eb3be9314e39dd199ac8e19389a95371f9d54e155c7aa635e319dd"
],
"index": "pypi",
"version": "==3.24.1"
},
"flask-login": {
"hashes": [
@@ -69,17 +272,32 @@
},
"flask-marshmallow": {
"hashes": [
"sha256:75c9d80f22af982b1e8ccec109d3b75c14bb5570602ae3705a4ff775badd2816",
"sha256:db7aff4130eb99fd05ab78fd2e2c58843ba0f208899aeb1c14aff9cd98ae8c80"
"sha256:4f507f883838b397638a3a36c7d36ee146b255a49db952f5d9de3f6f4522e8a8",
"sha256:69e99e3a123393894884a032ae2d11e6bdf4519a505819b66cec7eda32057741"
],
"version": "==0.9.0"
"version": "==0.10.1"
},
"flask-migrate": {
"hashes": [
"sha256:6fb038be63d4c60727d5dfa5f581a6189af5b4e2925bc378697b4f0a40cfb4e1",
"sha256:a96ff1875a49a40bd3e8ac04fce73fdb0870b9211e6168608cbafa4eb839d502"
],
"index": "pypi",
"version": "==2.5.2"
},
"flask-pyoidc": {
"hashes": [
"sha256:c5556e82eb45c6314f4dc4c357c9909830e99cd2e4237ba56f34ca9e699aae42"
],
"index": "pypi",
"version": "==3.0.0"
},
"flask-restplus": {
"hashes": [
"sha256:3fad697e1d91dfc13c078abcb86003f438a751c5a4ff41b84c9050199d2eab62",
"sha256:cdc27b5be63f12968a7f762eaa355e68228b0c904b4c96040a314ba7dc6d0e69"
"sha256:a15d251923a8feb09a5d805c2f4d188555910a42c64d58f7dd281b8cac095f1b",
"sha256:a66e442d0bca08f389fc3d07b4d808fc89961285d12fb8013f7cf15516fa9f5c"
],
"version": "==0.12.1"
"version": "==0.13.0"
},
"flask-restplus-patched": {
"hashes": [
@@ -88,13 +306,94 @@
"index": "pypi",
"version": "==0.1.10"
},
"flask-sqlalchemy": {
"flask-script": {
"hashes": [
"sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b",
"sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53"
"sha256:6425963d91054cfcc185807141c7314a9c5ad46325911bd24dcb489bd0161c65"
],
"index": "pypi",
"version": "==2.3.2"
"version": "==2.0.6"
},
"flask-socketio": {
"hashes": [
"sha256:2172dff1e42415ba480cee02c30c2fc833671ff326f1598ee3d69aa02cf768ec",
"sha256:7ff5b2f5edde23e875a8b0abf868584e5706e11741557449bc5147df2cd78268"
],
"index": "pypi",
"version": "==4.2.1"
},
"flask-sqlalchemy": {
"hashes": [
"sha256:0078d8663330dc05a74bc72b3b6ddc441b9a744e2f56fe60af1a5bfc81334327",
"sha256:6974785d913666587949f7c2946f7001e4fa2cb2d19f4e69ead02e4b8f50b33d"
],
"index": "pypi",
"version": "==2.4.1"
},
"flask-testing": {
"hashes": [
"sha256:dc076623d7d850653a018cb64f500948334c8aeb6b10a5a842bf1bcfb98122bc"
],
"index": "pypi",
"version": "==0.7.1"
},
"future": {
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
],
"version": "==0.18.2"
},
"greenlet": {
"hashes": [
"sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0",
"sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28",
"sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8",
"sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304",
"sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0",
"sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214",
"sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043",
"sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6",
"sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625",
"sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc",
"sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638",
"sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163",
"sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4",
"sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490",
"sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248",
"sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939",
"sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87",
"sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720",
"sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656"
],
"version": "==0.4.15"
},
"html5lib": {
"hashes": [
"sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3",
"sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"
],
"index": "pypi",
"version": "==1.0.1"
},
"humanfriendly": {
"hashes": [
"sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d",
"sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85"
],
"version": "==4.18"
},
"ics": {
"hashes": [
"sha256:12cf34aed0dafa1bf99d79ca58e99949d6721511b856386e118015fe5f5d6e3a"
],
"index": "pypi",
"version": "==0.6"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"itsdangerous": {
"hashes": [
@@ -105,17 +404,23 @@
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
"sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f",
"sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"
],
"version": "==2.10"
"version": "==2.10.3"
},
"jsonschema": {
"hashes": [
"sha256:0c0a81564f181de3212efa2d17de1910f8732fa1b71c42266d983cd74304e20d",
"sha256:a5f6559964a3851f59040d3b961de5e68e70971afb88ba519d27e6a039efff1a"
"sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
"sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
],
"version": "==3.0.1"
"version": "==3.2.0"
},
"mako": {
"hashes": [
"sha256:a36919599a9b7dc5d86a7a8988f23a9a3a3d083070023bab23d64f7f1d1e0a4b"
],
"version": "==1.1.0"
},
"markupsafe": {
"hashes": [
@@ -152,10 +457,23 @@
},
"marshmallow": {
"hashes": [
"sha256:6eeaf1301a5f5942bfe8ab2c2eaf03feb793072b56d5fae563638bddd7bb62e6",
"sha256:f72a206432a3369dd72824564d18d915761e07805c05f00d0dcc7885fac1e385"
"sha256:1a358beb89c2b4d5555272065a9533591a3eb02f1b854f3c4002d88d8f2a1ddb",
"sha256:eb97c42c5928b5720812c9268865fe863d4807bc1a8b48ddd7d5c9e1779a6af0"
],
"version": "==2.18.1"
"version": "==3.2.2"
},
"monotonic": {
"hashes": [
"sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0",
"sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"
],
"version": "==1.5"
},
"oic": {
"hashes": [
"sha256:34da42f4f9b4a36a02b28d72a42a3197a91e7efc5356c1c41d7f1a0bdf3ad1d2"
],
"version": "==0.12"
},
"passlib": {
"hashes": [
@@ -165,6 +483,69 @@
"index": "pypi",
"version": "==1.7.1"
},
"pbr": {
"hashes": [
"sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8",
"sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9"
],
"version": "==5.4.3"
},
"pyasn1": {
"hashes": [
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
],
"version": "==0.4.8"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"version": "==2.19"
},
"pycryptodomex": {
"hashes": [
"sha256:0943b65fb41b7403a9def6214061fdd9ab9afd0bbc581e553c72eebe60bded36",
"sha256:0a1dbb5c4d975a4ea568fb7686550aa225d94023191fb0cca8747dc5b5d77857",
"sha256:0f43f1608518347fdcb9c8f443fa5cabedd33f94188b13e4196a3a7ba90d169c",
"sha256:11ce5fec5990e34e3981ed14897ba601c83957b577d77d395f1f8f878a179f98",
"sha256:17a09e38fdc91e4857cf5a7ce82f3c0b229c3977490f2146513e366923fc256b",
"sha256:22d970cee5c096b9123415e183ae03702b2cd4d3ba3f0ced25c4e1aba3967167",
"sha256:2a1793efcbae3a2264c5e0e492a2629eb10d895d6e5f17dbbd00eb8b489c6bda",
"sha256:30a8a148a0fe482cec1aaf942bbd0ade56ec197c14fe058b2a94318c57e1f991",
"sha256:32fbbaf964c5184d3f3e349085b0536dd28184b02e2b014fc900f58bbc126339",
"sha256:347d67faee36d449dc9632da411cc318df52959079062627f1243001b10dc227",
"sha256:45f4b4e5461a041518baabc52340c249b60833aa84cea6377dc8016a2b33c666",
"sha256:4717daec0035034b002d31c42e55431c970e3e38a78211f43990e1b7eaf19e28",
"sha256:51a1ac9e7dda81da444fed8be558a60ec88dfc73b2aa4b0efa310e87acb75838",
"sha256:53e9dcc8f14783f6300b70da325a50ac1b0a3dbaee323bd9dc3f71d409c197a1",
"sha256:5519a2ed776e193688b7ddb61ab709303f6eb7d1237081e298283c72acc44271",
"sha256:583450e8e80a0885c453211ed2bd69ceea634d8c904f23ff8687f677fe810e95",
"sha256:60f862bd2a07133585a4fc2ce2b1a8ec24746b07ac44307d22ef2b767cb03435",
"sha256:612091f1d3c84e723bec7cb855cf77576e646045744794c9a3f75ba80737762f",
"sha256:629a87b87c8203b8789ccefc7f2f2faecd2daaeb56bdd0b4e44cd89565f2db07",
"sha256:6e56ec4c8938fb388b6f250ddd5e21c15e8f25a76e0ad0e2abae9afee09e67b4",
"sha256:8e8092651844a11ec7fa534395f3dfe99256ce4edca06f128efc9d770d6e1dc1",
"sha256:8f5f260629876603e08f3ce95c8ccd9b6b83bf9a921c41409046796267f7adc5",
"sha256:9a6b74f38613f54c56bd759b411a352258f47489bbefd1d57c930a291498b35b",
"sha256:a5a13ebb52c4cd065fb673d8c94f39f30823428a4de19e1f3f828b63a8882d1e",
"sha256:a77ca778a476829876a3a70ae880073379160e4a465d057e3c4e1c79acdf1b8a",
"sha256:a9f7be3d19f79429c2118fd61bc2ec4fa095e93b56fb3a5f3009822402c4380f",
"sha256:dc15a467c4f9e4b43748ba2f97aea66f67812bfd581818284c47cadc81d4caec",
"sha256:e13cdeea23059f7577c230fd580d2c8178e67ebe10e360041abe86c33c316f1c",
"sha256:e45b85c8521bca6bdfaf57e4987743ade53e9f03529dd3adbc9524094c6d55c4",
"sha256:e87f17867b260f57c88487f943eb4d46c90532652bb37046e764842c3b66cbb1",
"sha256:ee40a5b156f6c1192bc3082e9d73d0479904433cdda83110546cd67f5a15a5be",
"sha256:ef63ffde3b267043579af8830fc97fc3b9b8a526a24e3ba23af9989d4e9e689a"
],
"version": "==3.9.4"
},
"pyjwkest": {
"hashes": [
"sha256:5560fd5ba08655f29ff6ad1df1e15dc05abc9d976fcbcec8d2b5167f49b70222"
],
"version": "==1.4.2"
},
"pyjwt": {
"hashes": [
"sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
@@ -173,53 +554,208 @@
"index": "pypi",
"version": "==1.7.1"
},
"pyopenssl": {
"hashes": [
"sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504",
"sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507"
],
"version": "==19.1.0"
},
"pyrsistent": {
"hashes": [
"sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"
"sha256:eb6545dbeb1aa69ab1fb4809bfbf5a8705e44d92ef8fc7c2361682a47c46c778"
],
"version": "==0.14.11"
"version": "==0.15.5"
},
"python-dateutil": {
"hashes": [
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"version": "==2.8.1"
},
"python-editor": {
"hashes": [
"sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d",
"sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b",
"sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"
],
"version": "==1.0.4"
},
"python-engineio": {
"hashes": [
"sha256:4a13fb87c819b855c55a731fdf82559adb8311c04cfdfebd6b9ecd1c2afbb575",
"sha256:9c9a6035b4b5e5a225f426f846afa14cf627f7571d1ae02167cb703fefd134b7"
],
"version": "==3.10.0"
},
"python-jose": {
"hashes": [
"sha256:29701d998fe560e52f17246c3213a882a4a39da7e42c7015bcc1f7823ceaff1c",
"sha256:ed7387f0f9af2ea0ddc441d83a6eb47a5909bd0c8a72ac3250e75afec2cc1371"
],
"index": "pypi",
"version": "==3.0.1"
},
"python-socketio": {
"hashes": [
"sha256:506b2cf7a520b40ea0b3f25e1272eff8de134dce6f471c1f6bc0de8c90fe8c57",
"sha256:d4e2c23241afa0aae2a5bcc107523b2fcc71f5020df89a093f3634eb48955967"
],
"version": "==4.3.1"
},
"pythonping": {
"hashes": [
"sha256:c754c2bd8617943988a0a1b47d7392a57efea51fb7a30c7e938e246e90ea91eb"
],
"index": "pypi",
"version": "==1.0.7"
},
"pytz": {
"hashes": [
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
],
"version": "==2018.9"
"version": "==2019.3"
},
"relativetimebuilder": {
"requests": {
"hashes": [
"sha256:5cc415b539d18a20e09a600cf7ba7199eda7b365d13aaaf9ffbbaa26cfb8062a",
"sha256:8b11e6fa6d6d4a09c61cfa9dadae4ea640bf10818e0991874d33452c0aeff2d7"
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"version": "==0.2.0"
"version": "==2.22.0"
},
"rsa": {
"hashes": [
"sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66",
"sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487"
],
"version": "==4.0"
},
"scapy": {
"hashes": [
"sha256:e2f8d11f6a941c14a789ae8b236b27bd634681f1b29b5e893861e284d234f6b0"
],
"index": "pypi",
"version": "==2.4.3"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
"version": "==1.12.0"
"version": "==1.13.0"
},
"soupsieve": {
"hashes": [
"sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5",
"sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"
],
"version": "==1.9.5"
},
"sqlalchemy": {
"hashes": [
"sha256:11ead7047ff3f394ed0d4b62aded6c5d970a9b718e1dc6add9f5e79442cc5b14"
"sha256:afa5541e9dea8ad0014251bc9d56171ca3d8b130c9627c6cb3681cff30be3f8a"
],
"version": "==1.3.0"
"index": "pypi",
"version": "==1.3.11"
},
"sqlalchemy-migrate": {
"hashes": [
"sha256:0bc02e292a040ade5e35a01d3ea744119e1309cdddb704fdb99bac13236614f8",
"sha256:e5d2348db19a5062132d93e3b4d9e7644af552fffbec4c78cc5358f848d2f6c1"
],
"index": "pypi",
"version": "==0.13.0"
},
"sqlparse": {
"hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
"sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873"
],
"version": "==0.3.0"
},
"ssh2-python": {
"hashes": [
"sha256:054f2cab611ddca34095eb78d1ae1f6e29521678c82f0de17f696072a0b924fe",
"sha256:097d74684172f163d5025aef316987c1c7acf852d9fb75e4735720c8690adf87",
"sha256:0f4555b79e19ca6fdd84a74e85152d375a921d167ed9dc680d05f1f9f5dfc463",
"sha256:0fb3d9eca454b2874748c69e7e836ea5c6544f1b7acd87d8a876f99f618c806c",
"sha256:180c2728796f777a5856b23e5e1656a15a3e8602b4270348f892599ae5426f45",
"sha256:49aaa9d48cf52798d89f466a5e774e9dab8b76dc380b90645fd8d5c6622df177",
"sha256:4b5ba1390ff5e8faa6b2409df750e4650de3934c3b76ad707d7b54b477600226",
"sha256:57a4452dfc5c7f414de14e32f29e21f680fb8d7bdf94306e5f6bc8c2a235fa7a",
"sha256:584f753f0401217a55e70d2ae97a7e5220f4d37993a1bba275c4c5e110d87193",
"sha256:692cf27ddc5583da9b07b0f0348f0577579f8d798a0b8e4bf495b8d7f19fc854",
"sha256:6dc75bacc37de63aa9c86f9982642982c3a8103297fbbb73543a76e3db9abc6a",
"sha256:7a029275e62a1e31333ee7f2f151f661dedfac0345f1108e1a8d0b62e08ddf9b",
"sha256:7a3d761c669392e778c24a0eabcf6f1ba48ad68bb3b82a2d98235f56500bc8b0",
"sha256:8632684aae2f523e603381cf51a1da134fd5937cf0ae9650b1b9e7b4f328c133",
"sha256:8acab66dd73554d2c68abaccf96cdddfc10449ad6c7c273ac4b7a91779d414b2",
"sha256:9410b63c2361b2b65a55b5e8dc8187270de0f81e11864a427ad52b82b926bcc9",
"sha256:abe29ad01ed2ac4465e61c8de42b6850fca9c87d8792686a2de7c7d06c6eb72d",
"sha256:de151500a2a027a29bca3d7196c76008b41bb97db29378f29c4651ba1bcb00e8",
"sha256:debc56711643b82ab60a9c8b8cbf2978b65c0293aa7e53557a3c0d1fc57799cf",
"sha256:f508144d684b3c3c0f264ce67058f05ae3729ae77cc3a8f2051b442e01594849"
],
"index": "pypi",
"version": "==0.18.0.post1"
},
"style": {
"hashes": [
"sha256:6485a4bcb84629341a5fd1587fe3ac4887daa4741f0c8a1d01b9c3c8a263afe7",
"sha256:8eb365fc15039b19b728bd4e6e85fb7daf24e7aeeec6a15a666f97484c564005"
],
"version": "==1.1.0"
},
"tatsu": {
"hashes": [
"sha256:80713413473a009f2081148d0f494884cabaf9d6866b71f2a68a92b6442f343d",
"sha256:c9211eeee9a2d4c90f69879ec0b518b1aa0d9450249cb0dd181f5f5b18be0a92"
],
"version": "==4.4.0"
},
"tempita": {
"hashes": [
"sha256:cacecf0baa674d356641f1d406b8bff1d756d739c46b869a54de515d08e6fc9c"
],
"version": "==0.5.2"
},
"update": {
"hashes": [
"sha256:a25522b4bf60e3e3c1a3ff3ca3a4f5a328ac4b8ff400fdc9614483147e313323"
],
"index": "pypi",
"version": "==0.0.1"
},
"urllib3": {
"hashes": [
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
],
"version": "==1.25.7"
},
"webargs": {
"hashes": [
"sha256:10438164b41b81abe45b299eb182580f7bc6bcdbc864b0cbd62845bb6bab424d",
"sha256:3bed01136ea4a7d1468a54f6c3925d133872a83a2144e83a94f484731576bc58",
"sha256:494044344b5673e3624621d0e9d14d5dc01dd05c0b5b8952febc80a4f80181f6"
"sha256:3beca296598067cec24a0b6f91c0afcc19b6e3c4d84ab026b931669628bb47b4",
"sha256:3f9dc15de183d356c9a0acc159c100ea0506c0c240c1e6f1d8b308c5fed4dbbd",
"sha256:fa4ad3ad9b38bedd26c619264fdc50d7ae014b49186736bca851e5b5228f2a1b"
],
"version": "==5.1.2"
"version": "==5.5.2"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
],
"version": "==0.14.1"
"version": "==0.16.0"
}
},
"develop": {}

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
"""
Backend base module
"""
from flask import Flask
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
from flask_sqlalchemy import SQLAlchemy
jwt_auth = HTTPTokenAuth()
basic_auth = HTTPBasicAuth()
multi_auth = MultiAuth(basic_auth, jwt_auth)
from .serve_frontend import fe_bp
from .api import api_bp
app = Flask(__name__)
app.register_blueprint(api_bp)
app.register_blueprint(fe_bp)
db = SQLAlchemy(app)

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
from backend import app
def main():
app.run(debug=True)
if __name__ == '__main__':
main()

View File

@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
from flask import Blueprint
from flask_restplus import Api
api_authorizations = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'X-API-KEY'
},
'basicAuth': {
'type': 'basic',
'scheme': 'basic'
},
'bearerAuth': {
'type': 'apiKey',
'scheme': 'bearer',
'name': 'Authorization',
'in': 'header'
}
}
api_bp = Blueprint('api', __name__, url_prefix='/api')
api_v1 = Api(api_bp, prefix="/v1", version='0.1', title='Vue Test API',
description='The Vue Test API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
from .example_api import *

183
backend/__init__.py Normal file
View File

@@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
"""
Backend base module
"""
import logging
from io import StringIO
from logging.config import dictConfig
from logging.handlers import MemoryHandler
from typing import Union
import coloredlogs as coloredlogs
import jwt
import requests
from flask import Flask, jsonify
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
from flask_jwt_extended import JWTManager, decode_token
from flask_login import LoginManager
from flask_restplus import abort
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from backend.config import Config
__author__ = "Tobias Kurze"
__copyright__ = "Copyright 2019, Tobias Kurze, KIT"
__credits__ = ["Tobias Kurze"]
__license__ = ""
__version__ = "0.9.0"
__maintainer__ = "Tobias Kurze"
__email__ = "it@t-kurze.de"
# __status__ = "Production"
__status__ = "Development"
from .tools.send_mail import get_smtp_default_handler
dictConfig({
'version': 1,
'formatters': {
'default': {
'format': '[%(asctime)s] {%(threadName)s} %(levelname)s in %(module)s, line %(lineno)d: %(message)s',
}
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
},
'root_file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.ROOT_LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 3,
'formatter': 'default',
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 5,
'formatter': 'default',
},
'errors_file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.ERROR_LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 5,
'level': 'ERROR',
'formatter': 'default',
},
},
'loggers': {
'lrc': {
'level': Config.LOG_LEVEL,
'handlers': ['wsgi', 'file', 'errors_file']
}
},
'root': {
'level': 'ERROR',
'handlers': ['root_file', 'errors_file']
}
})
main_logger = logging.getLogger("lrc")
# following might be dangerous, as buffer might be filled without a mechanism to empty it
smtp_error_handler = get_smtp_default_handler(subject="Warnings, errors and worse...!")
mem_handler = MemoryHandler(capacity=10, flushLevel=logging.ERROR, target=smtp_error_handler)
mem_handler.setLevel(logging.WARNING)
# error_log_stream = StringIO()
# error_log_stream_handler = logging.StreamHandler(stream=error_log_stream)
# error_log_stream_handler.setLevel(logging.ERROR)
# main_logger.addHandler(error_log_stream_handler)
coloredlogs.install(level='DEBUG', logger=main_logger)
class LrcException(Exception):
def __init__(self, message_or_exception: Union[str, Exception], html_code: int = None):
if isinstance(message_or_exception, str):
super().__init__(message_or_exception)
self.type = None
else:
super().__init__(str(message_or_exception))
self.type = type(message_or_exception)
self.html_code = html_code
def __repr__(self):
if self.type is None:
msg = "LRC Exception: \"{}\"".format(', '.join(super().args))
else:
msg = "LRC Exception: (original Exception: {}) \"{}\"".format(self.type, ', '.join(super().args))
if self.html_code is not None:
msg += " (HTML Code: {})".format(self.html_code)
return msg
def __str__(self):
return self.__repr__()
app = Flask(__name__)
app.config.from_object('backend.config.Config')
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
# flask_jwt_extended: to be used usually by API
jwt_extended = JWTManager(app)
# this is another library.... this is (probaby ->verify) used to check JWTs provided by external sources (KIT, etc.)
jwt_auth = HTTPTokenAuth('Bearer')
@jwt_extended.invalid_token_loader
def unauthorized_jwt(token):
main_logger.info("Unauthorized access; invalid token provided: {}".format(token))
abort(401)
@jwt_auth.verify_token
def verify_token(token):
"""This function (and HTTPTokenAuth('Bearer')) has been defined to be used together with MultiAuth. For API calls
solely using JWT authentication, jwt_required of flask_jwt_extended should be used directly."""
app.logger.info(token)
try:
decoded = decode_token(token)
except jwt.exceptions.DecodeError as e:
app.logger.warn("Could not verify token: {}".format(str(e)))
return False
except jwt.exceptions.ExpiredSignatureError as e:
app.logger.warn("Could not verify token: {}".format(str(e)))
return False
app.logger.info(decoded)
return True
basic_auth = HTTPBasicAuth()
multi_auth = MultiAuth(basic_auth, jwt_auth)
from backend.auth import oidc_auth, auth_bp
try:
oidc_auth.init_app(app)
except requests.exceptions.ConnectionError as err:
app.logger.error("Could not connect to OIDC!!", err)
# oidc_multi_auth = MultiAuth(oidc_auth, jwt_auth) <- can't work as OIDCAuthentication not implementing HTTPAuth
from .serve_frontend import fe_bp
from .api import auth_api_bp, api_v1, api_bp
app.register_blueprint(auth_bp)
app.register_blueprint(auth_api_bp)
app.register_blueprint(api_bp)
app.register_blueprint(fe_bp)
CORS(app)
CORS(api_bp)
# Fix flask-restplus by duck typing error handlers
jwt_extended._set_error_handler_callbacks(api_v1)

44
backend/__main__.py Normal file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
import logging
import ssl
from jinja2.exceptions import TemplateNotFound
from backend import app, db
from backend.models import room_model, recorder_model, RecorderCommand
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.model_updater import update_recorder_models_database, create_default_recorders
def main():
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#db.drop_all()
#db.create_all()
room_model.pre_fill_table()
update_recorder_models_database(drop=False)
create_default_recorders()
print(app.config.get("SERVER_NAME", None))
server_name = app.config.get("SERVER_NAME", None)
if server_name is not None and "ubkaps154.ubka.uni-karlsruhe.de" in server_name:
try:
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain('cert.pem', 'key.pem')
app.run(debug=True, ssl_context=context, threaded=True)
except FileNotFoundError:
app.run(debug=True, threaded=True)
try:
db.create_all()
except Exception as e:
logging.critical(e)
app.run(debug=True, host="0.0.0.0")
if __name__ == '__main__':
main()

78
backend/api/__init__.py Normal file
View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
from flask import Blueprint, abort
from flask_restplus import Api, Namespace
api_authorizations = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'X-API-KEY'
},
'basicAuth': {
'type': 'basic',
'scheme': 'basic'
},
'bearerAuth': {
'type': 'apiKey',
'scheme': 'bearer',
'name': 'Authorization',
'in': 'header'
}
}
api_bp = Blueprint('api', __name__, url_prefix='/api')
api_v1 = Api(api_bp, prefix="/v1", version='0.1', title='Vue Test API',
description='The Vue Test API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
api_user = Namespace('user', description="User management namespace", authorizations=api_authorizations)
api_group = Namespace('group', description="Group management namespace", authorizations=api_authorizations)
api_room = Namespace('room', description="Room management namespace", authorizations=api_authorizations)
api_recorder = Namespace('recorder', description="Recorder management namespace", authorizations=api_authorizations)
api_virtual_command = Namespace('virtual_command', description="Virtual command namespace",
authorizations=api_authorizations)
api_cron_job = Namespace('cron_job', description="Cron job namespace",
authorizations=api_authorizations)
api_control = Namespace('control', description="Control namespace",
authorizations=api_authorizations)
api_v1.add_namespace(api_user)
api_v1.add_namespace(api_group)
api_v1.add_namespace(api_room)
api_v1.add_namespace(api_recorder)
api_v1.add_namespace(api_virtual_command)
api_v1.add_namespace(api_cron_job)
api_v1.add_namespace(api_control)
auth_api_bp = Blueprint('auth_api', __name__, url_prefix='/api/auth')
auth_api_v1 = Api(auth_api_bp, prefix="/v1", version='0.1', title='Auth API',
description='Auth API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
auth_api_providers_ns = Namespace('providers')
auth_api_register_ns = Namespace('register')
auth_api_v1.add_namespace(auth_api_providers_ns)
auth_api_v1.add_namespace(auth_api_register_ns)
# user_api_bp = Blueprint('user_api', __name__, url_prefix='/api/user')
# group_api_bp = Blueprint('group_api', __name__, url_prefix='/api/group')
from .example_api import *
from .auth_api import *
from .user_api import *
from .group_api import *
from .room_api import *
from .recorder_api import *
from .control_api import *
from .virtual_command_api import *
# from .group_api import *
@api_bp.route('/<path:path>')
def catch_all_api(path):
"""
Default 404 response for undefined paths in API.
:param path:
:return:
"""
abort(404)

196
backend/api/auth_api.py Normal file
View File

@@ -0,0 +1,196 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
import base64
import json
from pprint import pprint
import flask
from datetime import datetime, timedelta
import jwt
from flask import request, jsonify, current_app, url_for, Response, session, redirect, make_response
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_refresh_token_required, get_jwt_identity, \
get_raw_jwt, jwt_required
from functools import wraps
from random import randint
from flask_login import logout_user, login_user
from typing import Iterable
from flask_restplus import Resource, fields
from werkzeug.routing import BuildError
from backend import db, app, jwt_extended
from backend.api import auth_api_bp, auth_api_providers_ns, auth_api_register_ns
from backend.auth import AUTH_PROVIDERS, oidc_auth
from backend.models.user_model import User, Group, BlacklistToken
@auth_api_bp.route('/providers', methods=('GET',))
def get_auth_providers():
providers = dict()
for p in AUTH_PROVIDERS:
provider = dict(AUTH_PROVIDERS[p])
try:
provider["url"] = url_for(AUTH_PROVIDERS[p]["url"])
except BuildError:
provider["url"] = AUTH_PROVIDERS[p]["url"]
providers[p] = provider
return jsonify(providers)
@auth_api_providers_ns.route('/')
class AuthProviders(Resource):
def get(self):
return get_auth_providers()
@auth_api_bp.route('/register', methods=('POST',))
def register():
data = request.get_json()
user = User(**data)
db.session.add(user)
db.session.commit()
return jsonify(user.to_dict()), 201
@auth_api_register_ns.route('/')
@auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
'nickname': fields.String(required=False, description='The user\'s nickname'),
'first_name': fields.String(required=False, description='The user\'s first name'),
'last_name': fields.String(required=False, description='The user\'s last name'),
'lang': fields.String(required=False, description='The user\'s preferred language'),
'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
'email': fields.String(required=True, description='The user\'s e-mail address'),
'password': fields.String(required=False, description='The group\'s name')
}))
class AuthProviders(Resource):
def get(self):
return register()
@auth_api_bp.route('/login', methods=('GET', 'POST',))
def login():
print("login")
print(request)
data = request.get_json()
if not data:
return jsonify({'message': 'Invalid request data', 'authenticated': False}), 401
print(data)
user = User.authenticate(**data)
if not user:
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
token = {
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
}
return jsonify(token), 200
# Endpoint for revoking the current users access token
@auth_api_bp.route('/logout', methods=['GET', 'DELETE'])
@jwt_required
def logout():
jti = get_raw_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
# Endpoint for revoking the current users refresh token
@auth_api_bp.route('/logout2', methods=['GET', 'DELETE'])
@jwt_refresh_token_required
def logout2():
jti = get_raw_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
def check_and_create_groups(groups: Iterable[str]):
user_groups = []
for g in groups:
group = Group.get_by_name(g)
if group is None:
group = Group(name=g)
db.session.add(group)
user_groups.append(group)
db.session.commit()
return user_groups
def create_or_retrieve_user_from_userinfo(userinfo):
try:
email = userinfo["email"]
except KeyError:
return None
user_groups = check_and_create_groups(groups=userinfo.get("memberOf", []))
user = User.get_by_identifier(email)
if user is not None:
app.logger.info("user found -> update user")
pprint(user.to_dict())
user.first_name = userinfo.get("given_name", "")
user.last_name = userinfo.get("family_name", "")
for g in user_groups:
user.groups.append(g)
db.session.commit()
return user
user = User(email=email, first_name=userinfo.get("given_name", ""),
last_name=userinfo.get("family_name", ""), external_user=True,
groups=user_groups)
app.logger.info("creating new user")
db.session.add(user)
db.session.commit()
return user
@auth_api_bp.route('/oidc', methods=['GET'])
@auth_api_bp.route('/oidc/<redirect_url>', methods=['GET'])
@oidc_auth.oidc_auth()
def oidc(redirect_url=None):
user = create_or_retrieve_user_from_userinfo(flask.session['userinfo'])
if user is None:
return "Could not authenticate: could not find or create user.", 401
if current_app.config.get("AUTH_RETURN_EXTERNAL_JWT", False):
token = jwt.encode(flask.session['id_token'], current_app.config['SECRET_KEY'])
else:
token = json.dumps({
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
})
if redirect_url is None:
redirect_url = request.headers.get("Referer")
if redirect_url is None:
redirect_url = request.args.get('redirect_url')
if redirect_url is None:
redirect_url = "/"
app.logger.info("Token: {}".format(token))
response = make_response(redirect(redirect_url))
response.set_cookie('tokens', base64.b64encode(token.encode('utf-8')))
return response
@auth_api_bp.route('/refresh', methods=['GET'])
@jwt_refresh_token_required
def refresh():
"""Refresh token endpoint. This will generate a new access token from
the refresh token, but will mark that access token as non-fresh,
as we do not actually verify a password in this endpoint."""
jwt_identity = get_jwt_identity()
user = User.get_by_identifier(jwt_identity)
app.logger.info("Refreshing token for " + str(user))
new_token = create_access_token(identity=user, fresh=False)
ret = {'access_token': new_token}
return jsonify(ret), 200

View File

@@ -0,0 +1,42 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
import json
from datetime import datetime
from flask_jwt_extended import jwt_required, get_current_user, get_jwt_claims
from flask_restplus import fields, Resource
from backend import db
from backend.api import api_control, get_jwt_identity
control_command_response_model = api_control.model('Control Command Response', {
'time': fields.DateTime(required=False, description='Creation date of the recorder'),
'state': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'output': fields.String(required=False, description='The recorder\'s description'),
'error': fields.String(required=False, description='The recorder\'s description'),
})
@api_control.route('')
class ControlCommand(Resource):
control_command_parser = api_control.parser()
control_command_parser.add_argument('recorder_id', type=int, default=1, required=True)
control_command_parser.add_argument('command_id', type=int, default=1, required=True)
control_command_parser.add_argument('parameters', default=json.dumps({'p1': 'v1'}), type=dict, required=False,
location='json')
@jwt_required
@api_control.doc('run_command')
@api_control.expect(control_command_parser)
@api_control.marshal_with(control_command_response_model, skip_none=False, code=201)
def post(self):
print(get_current_user())
print(get_jwt_identity())
current_user = {'user': get_current_user(), 'claims': get_jwt_claims()}
args = self.control_command_parser.parse_args()
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}

View File

@@ -1,9 +1,13 @@
import datetime
import ipaddress
import json
import logging
from random import *
from flask import jsonify, Blueprint
from flask import jsonify, Blueprint, request
from flask_restplus import Resource, reqparse
from backend import basic_auth, multi_auth
from backend import basic_auth, multi_auth, db, jwt_auth
from backend.api import api_v1, api_bp
@@ -18,6 +22,18 @@ def random_number():
return jsonify(response)
@api_bp.route('/test_jwt')
@jwt_auth.login_required
def random_number_jwt():
"""
:return: a random number
"""
response = {
'randomNumber': randint(1, 100)
}
return jsonify(response)
class HelloWorld(Resource):
"""
This is a test class.
@@ -59,7 +75,7 @@ class SensorData_Handler(Resource):
print("values...")
print(args['values'])
values = json.loads(args['values'])
wasss_app.logger.info("vals: " + str(values) + " (len: " + str(len(values)) + ")")
app.logger.info("vals: " + str(values) + " (len: " + str(len(values)) + ")")
rough_geo_location = None
try:

87
backend/api/group_api.py Normal file
View File

@@ -0,0 +1,87 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from backend import db
from backend.api import api_group
from backend.models.user_model import Group
group_model = api_group.model('Group', {
'id': fields.String(required=False, description='The group\'s identifier'),
'name': fields.String(required=True, description='The group\'s name'),
'description': fields.String(required=False, description='The group\'s description'),
'users': fields.List(fields.Nested(api_group.model('group_member',
{'id': fields.Integer(), 'nickname': fields.String(),
'first_name': fields.String(), 'last_name': fields.String(),
'email': fields.String(), 'registered_on': fields.DateTime(),
'last_seen': fields.DateTime()})),
required=False, description='Group members.')
})
@api_group.route('/<int:id>')
@api_group.response(404, 'Group not found')
@api_group.param('id', 'The group identifier')
class GroupResource(Resource):
@jwt_required
@api_group.doc('get_group')
@api_group.marshal_with(group_model)
def get(self, id):
"""Fetch a user given its identifier"""
group = Group.get_by_id(id)
if group is not None:
return group
api_group.abort(404)
@jwt_required
@api_group.doc('delete_todo')
@api_group.response(204, 'Todo deleted')
def delete(self, id):
'''Delete a task given its identifier'''
group = Group.get_by_id(id)
if group is not None:
group.delete()
return '', 204
api_group.abort(404)
@jwt_required
@api_group.doc('update_group')
@api_group.expect(group_model)
@api_group.marshal_with(group_model)
def put(self, id):
'''Update a task given its identifier'''
group = Group.get_by_id(id)
if group is not None:
group.name = api_group["name"]
db.session.commit()
return group
api_group.abort(404)
@api_group.route('')
class GroupList(Resource):
@jwt_required
@api_group.doc('groups')
@api_group.marshal_list_with(group_model)
def get(self):
"""
List all groups
:return: groups
"""
return Group.get_all()
@jwt_required
@api_group.doc('create_group')
@api_group.expect(group_model)
@api_group.marshal_with(group_model, code=201)
def post(self):
group = Group(**api_group.payload)
db.session.add(group)
db.session.commit()
return group

102
backend/api/models.py Normal file
View File

@@ -0,0 +1,102 @@
from flask_restplus import fields
from backend.api import api_user, api_recorder, api_v1
generic_id_parser = api_v1.parser()
generic_id_parser.add_argument('id', type=str, required=True, store_missing=False)
user_model = api_user.model('User', {
'id': fields.String(required=True, description='The user\'s identifier'),
'first_name': fields.String(required=True, description='The user\'s first name'),
'last_name': fields.String(required=True, description='The user\'s last name'),
'email': fields.String(required=True, description='The user\'s email address'),
'nickname': fields.String(required=False, description='The user\'s nick name'),
'last_seen': fields.DateTime(required=False, description='Last time user logged in'),
'last_time_modified': fields.DateTime(required=False, description='Last time user was modified'),
'role': fields.String(required=False, description='Role a user might have (in addition to group memberships)'),
'effective_permissions': fields.List(
fields.String(required=True), required=False, description="List of permissions (groups + (optional) role)."
),
'groups': fields.List(
fields.Nested(api_user.model('user_group', {'id': fields.Integer(), 'name': fields.String()})),
required=False, description='Group memberships.'),
'favorite_recorders': fields.List(
fields.Nested(api_user.model('favorite_recorder', {'id': fields.Integer(), 'name': fields.String()})),
required=False, description='Favorite recorders.'),
})
recorder_model = api_recorder.model('Recorder', {
'id': fields.String(required=False, description='The recorder\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False, description='Creation date of the recorder'),
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'model_name': fields.String(min_length=3, required=True,
description='The recorder\'s model name (might slightly '
'differ from actual name of the model)'),
'serial_number': fields.String(required=False, description='The recorder\'s serial number'),
'firmware_version': fields.String(required=False, description='The recorder\'s firmware'),
'description': fields.String(required=False, description='The recorder\'s description'),
'locked': fields.Boolean(required=False, description='Indicates whether the recorder settings can be altered'),
'lock_message': fields.String(required=False, description='Optional: message explaining lock state'),
'offline': fields.Boolean(required=False,
description='Should be set when recorder is disconnected for maintenance, etc.'),
'additional_camera_connected': fields.Boolean(required=False,
description='Indicates whether an additional camera is connected'),
'ip': fields.String(required=False, description='The recorder\'s IP address'),
'mac': fields.String(required=False, description='The recorder\'s IP address'),
'network_name': fields.String(required=False, description='The recorder\'s network name'),
'ssh_port': fields.Integer(required=True, default=22, description='The recorder\'s SSH port number'),
'telnet_port': fields.Integer(required=True, default=23, description='The recorder\'s telnet port number'),
# 'use_telnet_instead_ssh': fields.Boolean(required=False, default=False,
# description='If this is set, telnet will be used instead of ssh. '
# 'This might require specific commands.'),
'recorder_model': fields.Nested(api_recorder.model('recorder_model',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", )}),
required=False,
allow_null=True,
skip_none=False,
description='Model of the recorder.'),
'room': fields.Nested(api_recorder.model('recorder_room',
{'id': fields.Integer(), 'name': fields.String(),
'number': fields.String(), 'alternate_name': fields.String()}),
r0equired=False,
allow_null=True,
skip_none=False,
description='Room in which the recorder is located.'),
'virtual_commands': fields.List(fields.Nested(api_recorder.model('recorder_virtual_commands',
{'id': fields.Integer(),
'name': fields.String()})))
})
recorder_command_model = api_recorder.model('Recorder Command', {
'id': fields.String(required=False, description='The recorder command\'s identifier'),
'name': fields.String(required=True, description='The recorder command\'s name'),
'alternative_name': fields.String(required=False, description='The recorder command\'s alternative name'),
'disabled': fields.Boolean(required=False, description='Indicates if the recorder command is disabled'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False),
'description': fields.String(required=False, description='The recorder command\'s description'),
'parameters': fields.Raw(required=True, description='The recorder parameters'),
'recorder_model': fields.Nested(api_recorder.model('recorder_command_models',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", )})),
})
recorder_model_model = api_recorder.model('Recorder Model', {
'id': fields.String(required=False, description='The recorder model\'s identifier'),
'name': fields.String(attribute="model_name", required=True, description='The recorder model\'s name'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False),
'notes': fields.String(required=False, description='The recorder model\'s notes'),
'requires_username': fields.Boolean(),
'requires_password': fields.Boolean(),
'recorders': fields.List(fields.Nested(api_recorder.model('recorder_model',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", ),
'network_name': fields.String(),
'ip': fields.String()})), required=False,
description='Model of the recorder.'),
'commands': fields.List(fields.Nested(recorder_command_model), attribute="recorder_commands")
})

208
backend/api/recorder_api.py Normal file
View File

@@ -0,0 +1,208 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from datetime import datetime
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource, inputs
from backend import db, app
from backend.api import api_recorder
from backend.api.models import recorder_model, recorder_model_model, recorder_command_model
from backend.models.recorder_model import Recorder, RecorderModel, RecorderCommand
from backend.models.room_model import Room
import backend.recorder_adapters as r_a
# ==
@api_recorder.route('/<int:id>')
@api_recorder.response(404, 'Recorder not found')
@api_recorder.param('id', 'The recorder identifier')
class RecorderResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder')
@api_recorder.marshal_with(recorder_model, skip_none=False)
def get(self, id):
"""Fetch a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
return recorder
api_recorder.abort(404)
@jwt_required
@api_recorder.doc('delete_todo')
@api_recorder.response(204, 'Todo deleted')
def delete(self, id):
"""Delete a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
db.session.delete(recorder)
db.session.commit()
return '', 204
api_recorder.abort(404)
recorder_update_parser = api_recorder.parser()
recorder_update_parser.add_argument('name', type=str, required=False, nullable=False, store_missing=False)
recorder_update_parser.add_argument('network_name', type=inputs.regex(inputs.netloc_regex), required=False, store_missing=False)
recorder_update_parser.add_argument('ip', type=inputs.ipv4, required=False, store_missing=False)
recorder_update_parser.add_argument('ip6', type=inputs.ipv6, required=False, store_missing=False)
recorder_update_parser.add_argument('ssh_port', type=inputs.int_range(0,65535), required=False, default=22, store_missing=False)
recorder_update_parser.add_argument('telnet_port', type=inputs.int_range(0,65535), required=False, default=23, store_missing=False)
recorder_update_parser.add_argument('room_id', type=int, required=False, store_missing=False)
recorder_update_parser.add_argument('offline', type=inputs.boolean, required=False, default=False, store_missing=False)
recorder_update_parser.add_argument('locked', type=inputs.boolean, required=False, default=False, store_missing=False)
recorder_update_parser.add_argument('lock_message', type=str, required=False, nullable=True, default=None,
store_missing=False)
recorder_update_parser.add_argument('model_id', type=int, required=False, store_missing=False)
recorder_update_parser.add_argument('description', type=str, required=False, nullable=True, default=None,
store_missing=False)
recorder_update_parser.add_argument('virtual_command_ids', action='split', nullable=True, default=[],
required=False, store_missing=False)
@jwt_required
@api_recorder.doc('update_recorder')
@api_recorder.expect(recorder_model)
def put(self, id):
"""Update a recorder given its identifier"""
args = self.recorder_update_parser.parse_args(strict=True)
args['last_time_modified'] = datetime.utcnow()
pprint(args)
num_rows_matched = Recorder.query.filter_by(id=id).update(args)
print(num_rows_matched)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('')
class RecorderList(Resource):
@jwt_required
@api_recorder.doc('recorders')
@api_recorder.marshal_list_with(recorder_model, skip_none=False)
def get(self):
"""
List all recorders
:return: recorders
"""
return Recorder.get_all()
@jwt_required
@api_recorder.doc('create_recorder')
@api_recorder.expect(recorder_model)
@api_recorder.marshal_with(recorder_model, skip_none=False, code=201)
def post(self):
if "room_id" in api_recorder.payload:
if api_recorder.payload["room_id"] is None:
api_recorder.payload["room"] = None
else:
room = Room.query.get(api_recorder.payload["room_id"])
if room is not None:
api_recorder.payload["room"] = room
else:
return "specified room (id: {}) does not exist!".format(api_recorder.payload["room_id"]), 404
if "recorder_model_id" in api_recorder.payload:
if api_recorder.payload["recorder_model_id"] is None:
api_recorder.payload["recorder_model"] = None
else:
rec_model = RecorderModel.query.get(api_recorder.payload["recorder_model_id"])
if rec_model is not None:
api_recorder.payload["recorder_model"] = rec_model
else:
return "specified recorder model (id: {}) does not exist!".format(
api_recorder.payload["recorder_model_id"]), 404
recorder = Recorder(**api_recorder.payload)
db.session.add(recorder)
db.session.commit()
return recorder
@api_recorder.route('/model/<int:id>')
@api_recorder.response(404, 'Recorder Model not found')
@api_recorder.param('id', 'The recorder model identifier')
class RecorderModelResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder_model')
@api_recorder.marshal_with(recorder_model_model)
def get(self, id):
"""Fetch a recorder model given its identifier"""
recorder_model = RecorderModel.query.get(id)
if recorder_model is not None:
return recorder_model
api_recorder.abort(404)
recorder_model_parser = api_recorder.parser()
recorder_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_recorder.doc('update_recorder_model')
@api_recorder.expect(recorder_model_parser)
@api_recorder.marshal_with(recorder_model_model)
def put(self, id):
"""Update a recorder_model given its identifier"""
num_rows_matched = RecorderModel.query.filter_by(id=id).update(api_recorder.payload)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('/model')
class RecorderModelList(Resource):
@jwt_required
@api_recorder.doc('recorders')
@api_recorder.marshal_list_with(recorder_model_model)
def get(self):
return RecorderModel.get_all()
@api_recorder.route('/command/<int:id>')
@api_recorder.response(404, 'Recorder Command not found')
@api_recorder.param('id', 'The recorder command identifier')
class RecorderCommandResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder_command')
@api_recorder.marshal_with(recorder_command_model)
def get(self, id):
"""Fetch a recorder command given its identifier"""
recorder_command = RecorderCommand.query.get(id)
if recorder_command is not None:
return recorder_command
api_recorder.abort(404)
recorder_command_model_parser = api_recorder.parser()
recorder_command_model_parser.add_argument('description', type=str, required=False)
recorder_command_model_parser.add_argument('alternative_name', type=str, required=False)
@jwt_required
@api_recorder.doc('update_recorder_command')
@api_recorder.expect(recorder_command_model_parser)
@api_recorder.marshal_with(recorder_command_model)
def put(self, id):
"""Update a recorder command given its identifier"""
num_rows_matched = RecorderCommand.query.filter_by(id=id).update(api_recorder.payload)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('/command')
class RecorderCommandList(Resource):
@jwt_required
@api_recorder.doc('recorder_commands')
@api_recorder.marshal_list_with(recorder_command_model)
def get(self):
"""
List all recorders commands
:return: recorder commands
"""
return RecorderCommand.get_all()

122
backend/api/room_api.py Normal file
View File

@@ -0,0 +1,122 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from sqlalchemy import exc
from backend import db, app
from backend.api import api_room
from backend.models.room_model import Room
from backend.models.recorder_model import Recorder
room_model = api_room.model('Room', {
'id': fields.String(required=False, description='The room\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the room info'),
'name': fields.String(required=True, description='The room\'s name'),
'alternate_name': fields.String(required=False, description='The room\'s alternate name'),
'comment': fields.String(required=False, description='The room\'s comment'),
'number': fields.String(required=True, description='The room\'s number'),
'building_name': fields.String(required=False, description='The building\'s name'),
'building_number': fields.String(required=False, description='The building\'s number'),
'recorder': fields.Nested(api_room.model('room_recorder',
{'id': fields.Integer(), 'name': fields.String(),
'ip': fields.String(), 'network_name': fields.String()}),
allow_null=True,
skip_none=False,
required=False,
description='Room recorder.'),
})
@api_room.route('/<int:id>')
@api_room.response(404, 'Room not found')
@api_room.param('id', 'The room identifier')
class RoomResource(Resource):
@jwt_required
@api_room.doc('get_room')
@api_room.marshal_with(room_model, skip_none=False)
def get(self, id):
"""Fetch a user given its identifier"""
room = Room.query.get(id)
if room is not None:
return room
api_room.abort(404)
@jwt_required
@api_room.doc('delete_todo')
@api_room.response(204, 'Todo deleted')
def delete(self, id):
'''Delete a task given its identifier'''
room = Room.query.get(id)
if room is not None:
db.session.delete(room)
db.session.commit()
return '', 204
api_room.abort(404)
@jwt_required
@api_room.doc('update_room')
@api_room.expect(room_model)
def put(self, id):
app.logger.debug(api_room.payload)
'''Update a task given its identifier'''
if "recorder_id" in api_room.payload:
if api_room.payload["recorder_id"] is None:
api_room.payload["recorder"] = None
else:
recorder = Recorder.query.get(api_room.payload["recorder_id"])
if recorder is not None:
api_room.payload["recorder"] = recorder
else:
return "specified recorder (id: {}) does not exist!".format(api_room.payload["recorder_id"]), 404
room = Room.query.get(id)
if room is not None:
room.recorder = api_room.payload["recorder"]
else:
num_rows_matched = Room.query.filter_by(id=id).update(api_room.payload)
db.session.commit()
return "ok"
api_room.abort(404)
@api_room.route('')
class RoomList(Resource):
@jwt_required
@api_room.doc('rooms')
@api_room.marshal_list_with(room_model, skip_none=False)
def get(self):
"""
List all rooms
:return: rooms
"""
return Room.get_all()
@jwt_required
@api_room.doc('create_room')
@api_room.expect(room_model)
@api_room.marshal_with(room_model, skip_none=False, code=201)
def post(self):
if "recorder_id" in api_room.payload:
if api_room.payload["recorder_id"] is None:
api_room.payload["recorder"] = None
else:
recorder = Recorder.query.get(api_room.payload["recorder_id"])
if recorder is not None:
api_room.payload["recorder"] = recorder
else:
return "specified recorder (id: {}) does not exist!".format(api_room.payload["recorder_id"]), 404
del api_room.payload["recorder_id"]
room = Room(**api_room.payload)
db.session.add(room)
try:
db.session.commit()
return room
except exc.IntegrityError as e:
db.session.rollback()
return str(e.detail), 400

129
backend/api/user_api.py Normal file
View File

@@ -0,0 +1,129 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from datetime import datetime
from pprint import pprint
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user
from flask_restplus import Resource, fields, inputs, abort
from backend import db, app, jwt_auth
from backend.api import api_user
from backend.api.models import user_model, recorder_model, generic_id_parser
from backend.models import Recorder
from backend.models.user_model import User, Group
user_update_parser = api_user.parser()
user_update_parser.add_argument('email', type=inputs.email(), required=False, nullable=False, store_missing=False)
user_update_parser.add_argument('nickname', type=str, required=False, store_missing=False)
user_update_parser.add_argument('first_name', type=str, required=False, store_missing=False)
user_update_parser.add_argument('last_name', type=str, required=False, store_missing=False)
@api_user.route('/profile')
class Profile(Resource):
@jwt_required
@api_user.marshal_with(user_model)
def get(self):
"""Get infos about logged in user."""
current_user_id = get_jwt_identity()
app.logger.info(current_user_id)
return User.get_by_identifier(current_user_id)
@jwt_required
@api_user.expect(user_update_parser)
def put(self):
args = user_update_parser.parse_args()
args['last_time_modified'] = datetime.utcnow()
pprint(args)
print(current_user)
num_rows_matched = User.query.filter_by(id=current_user.id).update(args)
print(num_rows_matched)
if num_rows_matched < 1:
api_user.abort("Nothing has been updated!")
db.session.commit()
return "ok"
@api_user.route('/profile/favorite_recorders')
class UserFavoriteRecorders(Resource):
@jwt_required
@api_user.marshal_list_with(recorder_model)
def get(self):
try:
current_user_id = get_jwt_identity()
return User.get_by_identifier(current_user_id).favorite_recorders
except AttributeError:
abort(404, "User not found!")
@jwt_required
@api_user.expect(generic_id_parser)
@api_user.marshal_list_with(recorder_model)
def put(self):
try:
args = generic_id_parser.parse_args()
current_user_id = get_jwt_identity()
user = User.get_by_identifier(current_user_id)
print(user)
recorder = Recorder.get_by_identifier(args["id"])
print(recorder)
if recorder is None:
abort(404, "(Specified [id: {}]) recorder not found!".format(args["id"]))
user.favorite_recorders.append(recorder)
db.session.commit()
return user.favorite_recorders
except AttributeError:
abort(404, "User not found!")
@api_user.route('')
class UserList(Resource):
"""
This is a test class.
"""
# @jwt_auth.login_required
@jwt_required
@api_user.doc('users')
@api_user.marshal_list_with(user_model)
def get(self):
"""
just a test!
:return: Hello: World
"""
current_user = get_jwt_identity()
app.logger.info(current_user)
return User.get_all()
@jwt_required
@api_user.doc('create_group')
@api_user.expect(user_model)
@api_user.marshal_with(user_model, code=201)
def post(self):
user = User(**api_user.payload)
db.session.add(user)
db.session.commit()
return user
@api_user.route('/<id>')
@api_user.param('id', 'The user identifier')
@api_user.response(404, 'User not found')
class UserResource(Resource):
@jwt_auth.login_required
@api_user.doc('get_user')
@api_user.marshal_with(user_model)
def get(self, id):
"""Fetch a user given its identifier"""
user = User.get_by_id(id)
if user is not None:
return user
api_user.abort(404)
# api_user.add_resource(UserResource, '/')

View File

@@ -0,0 +1,134 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
import inspect
import pkgutil
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from backend import db, app
from backend.api import api_virtual_command
from backend.models.recorder_model import Recorder, RecorderModel, RecorderCommand
from backend.models.room_model import Room
import backend.recorder_adapters as r_a
virtual_command_model = api_virtual_command.model('VirtualCommand', {
'id': fields.String(required=False, description='The recorder\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'description': fields.String(required=False, description='The recorder\'s description'),
'parent_virtual_command': fields.Nested(api_virtual_command.model('VirtualCommandParent',
{
'id': fields.String(required=False,
description='The recorder\'s identifier'),
'name': fields.String(min_length=3,
required=True,
description='The recorder\'s name'),
},
required=False,
allow_null=True,
skip_none=False,
description='Parent virtual command.')),
'room': fields.Nested(api_virtual_command.model('recorder_room',
{'id': fields.Integer(), 'name': fields.String(),
'number': fields.String(), 'alternate_name': fields.String()}),
r0equired=False,
allow_null=True,
skip_none=False,
description='Room in which the recorder is located.')
})
# ==
@api_virtual_command.route('/<int:id>')
@api_virtual_command.response(404, 'Recorder not found')
@api_virtual_command.param('id', 'The recorder identifier')
class VirtualCommandResource(Resource):
@jwt_required
@api_virtual_command.doc('get_recorder')
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False)
def get(self, id):
"""Fetch a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
return recorder
api_virtual_command.abort(404)
@jwt_required
@api_virtual_command.doc('delete_todo')
@api_virtual_command.response(204, 'Todo deleted')
def delete(self, id):
"""Delete a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
db.session.delete(recorder)
db.session.commit()
return '', 204
api_virtual_command.abort(404)
virtual_command_model_parser = api_virtual_command.parser()
virtual_command_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_virtual_command.doc('update_recorder')
@api_virtual_command.expect(virtual_command_model_parser)
def put(self, id):
"""Update a recorder given its identifier"""
num_rows_matched = Recorder.query.filter_by(id=id).update(api_virtual_command.payload)
if num_rows_matched < 1:
api_virtual_command.abort(404)
db.session.commit()
return "ok"
@api_virtual_command.route('')
class RecorderList(Resource):
@jwt_required
@api_virtual_command.doc('recorders')
@api_virtual_command.marshal_list_with(virtual_command_model, skip_none=False)
def get(self):
"""
List all recorders
:return: recorders
"""
return Recorder.get_all()
virtual_command_model_parser = api_virtual_command.parser()
virtual_command_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_virtual_command.doc('create_recorder')
@api_virtual_command.expect(virtual_command_model_parser)
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False, code=201)
def post(self):
if "room_id" in api_virtual_command.payload:
if api_virtual_command.payload["room_id"] is None:
api_virtual_command.payload["room"] = None
else:
room = Room.query.get(api_virtual_command.payload["room_id"])
if room is not None:
api_virtual_command.payload["room"] = room
else:
return "specified room (id: {}) does not exist!".format(api_virtual_command.payload["room_id"]), 404
if "recorder_model_id" in api_virtual_command.payload:
if api_virtual_command.payload["recorder_model_id"] is None:
api_virtual_command.payload["recorder_model"] = None
else:
rec_model = RecorderModel.query.get(api_virtual_command.payload["recorder_model_id"])
if rec_model is not None:
api_virtual_command.payload["recorder_model"] = rec_model
else:
return "specified recorder model (id: {}) does not exist!".format(
api_virtual_command.payload["recorder_model_id"]), 404
recorder = Recorder(**api_virtual_command.payload)
db.session.add(recorder)
db.session.commit()
return recorder

78
backend/auth/__init__.py Normal file
View File

@@ -0,0 +1,78 @@
# Copyright (c) 2019. Tobias Kurze
"""
Base module for auth aspects.
Also this module contains mainly code for login through HTML pages served by the backend.
If frontend pages are build by frontend code (JS, etc.) authentication should consider using api functions.
(For more info, see api.auth_api.py.)
This code uses login_user and logout user (to start and end sessions) ... API code returns JWTs.
"""
from flask import Blueprint, jsonify, url_for
from flask_login import logout_user, LoginManager
from werkzeug.routing import BuildError
from backend import jwt_extended
from backend.models import BlacklistToken, User
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
from backend.auth.oidc_config import OIDC_PROVIDERS
from backend.auth.oidc import oidc_auth
from .basic_auth import *
def auth_decorator(): # custom decorator
pass
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
try:
prov = AUTH_PROVIDERS[DEFAULT_FRONTEND_PROVIDER]
except KeyError:
return "No known default provider specified!"
url = prov["url"]
try:
url = url_for(prov["url"], next=request.endpoint)
except BuildError as e:
pass
#logger.log("Can't create endpoint for '{}' (specified provider: {}).".format(e.endpoint, DEFAULT_PROVIDER))
return redirect(url)
@auth_bp.route('/login_select', methods=['GET'])
def login_select():
return render_template('login_select.html', providers=AUTH_PROVIDERS)
@auth_bp.route('/logout', methods=('GET', ))
def logout():
logout_user()
@jwt_extended.user_claims_loader
def add_claims_to_access_token(user):
if isinstance(user, str):
return {}
return {'role': user.role, 'groups': [g.to_dict() for g in user.groups]}
@jwt_extended.user_identity_loader
def user_identity_loader(user):
return user.email
@jwt_extended.user_loader_callback_loader
def user_loader_callback(identity):
print("### user_loader_callback_loader")
return User.get_by_identifier(identity)
@jwt_extended.token_in_blacklist_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token['jti']
return BlacklistToken.get_by_token(jti) is not None

View File

@@ -0,0 +1,22 @@
# Route for handling the login page logic
from flask import request, redirect, render_template
from flask_login import login_user
from backend.auth import auth_bp
from backend.models.user_model import User
@auth_bp.route('/base_login', methods=['GET', 'POST'])
def base_login():
error = None
if request.method == 'POST':
user = User.authenticate(email=request.form['email'], password=request.form['password'])
if user is None:
error = 'Invalid Credentials. Please try again.'
else:
login_user(user)
return redirect("/")
return render_template('login.html', error=error)

29
backend/auth/config.py Normal file
View File

@@ -0,0 +1,29 @@
from typing import Dict, List
AUTH_PROVIDERS: Dict[str, Dict[str, str]] = {
"KIT OIDC":
{
"type": "oidc",
"url": "auth_api.oidc"
},
"Base Login":
{
"type": "login_form",
"url": "auth.base_login"
},
"KIT OIDC (API)":
{
"type": "api_oidc",
"url": "auth_api.oidc"
},
"User-Password (API)":
{
"type": "api_login_form",
"url": "auth_api.login"
},
}
#DEFAULT_PROVIDER: str = "Base Login"
DEFAULT_PROVIDER: str = "KIT OIDC (API)"
DEFAULT_FRONTEND_PROVIDER: str = "Base Login"

80
backend/auth/oidc.py Normal file
View File

@@ -0,0 +1,80 @@
# Copyright (c) 2019. Tobias Kurze
"""
OIDC login auth module
"""
from datetime import datetime
import flask
from flask import jsonify, redirect, url_for
from flask_login import login_user
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
from flask_pyoidc.user_session import UserSession
from backend import app, db
from backend.models.user_model import User
from . import auth_bp
from .oidc_config import PROVIDER_NAME, OIDC_PROVIDERS
OIDCAuthentication.oidc_auth_orig = OIDCAuthentication.oidc_auth
OIDCAuthentication.oidc_logout_orig = OIDCAuthentication.oidc_logout
def oidc_auth_default_provider(self):
"""monkey patch oidc_auth"""
return self.oidc_auth_orig(PROVIDER_NAME)
def oidc_logout_default_provider(self):
"""monkey patch oidc_logout"""
return self.oidc_logout_orig(PROVIDER_NAME)
OIDCAuthentication.oidc_auth = oidc_auth_default_provider
OIDCAuthentication.oidc_logout = oidc_logout_default_provider
oidc_auth = OIDCAuthentication(OIDC_PROVIDERS)
def create_or_retrieve_user_from_userinfo(userinfo):
"""Updates and returns ar creates a user from userinfo (part of OIDC token)."""
try:
email = userinfo["email"]
except KeyError:
return None
user = User.get_by_identifier(email)
if user is not None:
app.logger.info("user found")
user.last_seen = datetime.utcnow()
# TODO: update user!
db.session.commit()
return user
user = User(email=email, first_name=userinfo.get("given_name", ""),
last_name=userinfo.get("family_name", ""))
app.logger.info("creating new user")
db.session.add(user)
db.session.commit()
return user
@auth_bp.route('/oidc', methods=['GET'])
@oidc_auth.oidc_auth()
def oidc():
user_session = UserSession(flask.session)
app.logger.info(user_session.userinfo)
user = create_or_retrieve_user_from_userinfo(user_session.userinfo)
login_user(user)
return jsonify(id_token=user_session.id_token,
access_token=flask.session['access_token'],
userinfo=user_session.userinfo)
@auth_bp.route('/oidc_logout', methods=['GET'])
def oidc_logout():
oidc_auth.oidc_logout()
return redirect('/')

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2019. Tobias Kurze
from flask_pyoidc.provider_configuration import ClientMetadata, ProviderConfiguration
REG_RESPONSE_CLIENT_ID = "lrc-test-bibliothek-kit-edu"
REG_RESPONSE_CLIENT_SECRET = "d8531b30-0e6b-4280-b611-1e6c8b4911fa"
CLIENT_METADATA = ClientMetadata(REG_RESPONSE_CLIENT_ID, REG_RESPONSE_CLIENT_SECRET)
PROVIDER_URL = "https://oidc.scc.kit.edu/auth/realms/kit"
PROVIDER_NAME = 'kit_oidc'
PROVIDER_CONFIG = ProviderConfiguration(issuer=PROVIDER_URL,
client_metadata=CLIENT_METADATA,
auth_request_params={'scope': ['openid', 'email', 'profile']})
OIDC_PROVIDERS = {PROVIDER_NAME: PROVIDER_CONFIG}

View File

@@ -0,0 +1,23 @@
<html>
<head>
<title>Flask Intro - login page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="E-Mail" name="email" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">
<input class="btn btn-default" type="submit" value="Login">
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title>Flask Intro - login page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<h1>Please select login method</h1>
<br>
<ul>
{% for provider in providers %}
<li><a href="{{url_for(providers[provider].url)}}">{{ provider }} ({{ providers[provider].type }})</a></li>
{% endfor %}
</ul>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>

42
backend/auth/utils.py Normal file
View File

@@ -0,0 +1,42 @@
import flask_jwt_extended
from flask_jwt_extended import jwt_optional, get_jwt_identity
from functools import wraps
from backend import jwt_auth
from backend.models.user_model import User
def requires_permission_level(permission_level):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if flask_jwt_extended.verify_jwt_in_request():
current_user_id = get_jwt_identity()
user = User.get_by_identifier(current_user_id)
if user is not None:
if user.has_permission(permission_level):
#for g in user.groups:
# if g.permissions
#TODO
pass
else:
pass
# return FALSE
#if not session.get('email'):
# return redirect(url_for('users.login'))
#user = User.find_by_email(session['email'])
#elif not user.allowed(access_level):
# return redirect(url_for('users.profile', message="You do not have access to that page. Sorry!"))
return f(*args, **kwargs)
return decorated_function
return decorator
def require_jwt():
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
return jwt_auth.login_required(jwt_optional(f(*args, **kwargs)))
return decorated_function
return decorator

BIN
backend/config.py Normal file

Binary file not shown.

7
backend/cron/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
import logging
cron_log_handler = logging.FileHandler(CRON_LOG_FILE)
cron_logger = logging.getLogger("mal.cron")
cron_logger.addHandler(cron_log_handler)
logging.getLogger("apscheduler.scheduler").addHandler(cron_log_handler)
logging.getLogger("apscheduler.executors.default").addHandler(cron_log_handler)

75
backend/manage.py Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir))
import os
import unittest
import coverage
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from backend import app, db
COV = coverage.coverage(
branch=True,
include='app/*',
omit=[
'app/tests/*',
'app/server/config.py',
'app/server/*/__init__.py'
]
)
COV.start()
migrate = Migrate(app, db)
manager = Manager(app)
# migrations
manager.add_command('db', MigrateCommand)
@manager.command
def test():
"""Runs the unit tests without test coverage."""
tests = unittest.TestLoader().discover('tests', pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
@manager.command
def cov():
"""Runs the unit tests with coverage."""
tests = unittest.TestLoader().discover('app/tests')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
COV.stop()
COV.save()
print('Coverage Summary:')
COV.report()
basedir = os.path.abspath(os.path.dirname(__file__))
covdir = os.path.join(basedir, 'tmp/coverage')
COV.html_report(directory=covdir)
print('HTML version: file://%s/index.html' % covdir)
COV.erase()
return 0
return 1
@manager.command
def create_db():
"""Creates the db tables."""
db.create_all()
@manager.command
def drop_db():
"""Drops the db tables."""
db.drop_all()
if __name__ == '__main__':
manager.run()

View File

@@ -0,0 +1 @@
Generic single-database configuration.

View File

@@ -0,0 +1,45 @@
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

95
backend/migrations/env.py Normal file
View File

@@ -0,0 +1,95 @@
from __future__ import with_statement
import logging
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View File

@@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View File

@@ -0,0 +1,136 @@
"""empty message
Revision ID: b154e49921e0
Revises:
Create Date: 2019-04-11 14:44:25.836132
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b154e49921e0'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('blacklist_tokens',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('token', sa.String(length=500), nullable=False),
sa.Column('blacklisted_on', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('token')
)
op.create_table('example_data_item',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('mac', sa.String(length=32), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=False),
sa.Column('some_string_value', sa.String(), nullable=True),
sa.Column('name', sa.String(length=128), nullable=False),
sa.Column('description', sa.String(length=4096), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_example_data_item_mac'), 'example_data_item', ['mac'], unique=True)
op.create_index(op.f('ix_example_data_item_name'), 'example_data_item', ['name'], unique=False)
op.create_index(op.f('ix_example_data_item_some_string_value'), 'example_data_item', ['some_string_value'], unique=False)
op.create_index(op.f('ix_example_data_item_uuid'), 'example_data_item', ['uuid'], unique=True)
op.create_table('group',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.Unicode(length=63), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('permission',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.Unicode(length=63), nullable=False),
sa.Column('description', sa.Unicode(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('group_permission',
sa.Column('group_id', sa.Integer(), nullable=False),
sa.Column('permission_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['group_id'], ['group.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['permission_id'], ['permission.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('group_id', 'permission_id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('social_id', sa.Unicode(length=63), nullable=True),
sa.Column('nickname', sa.Unicode(length=63), nullable=True),
sa.Column('first_name', sa.Unicode(length=63), nullable=True),
sa.Column('last_name', sa.Unicode(length=63), nullable=True),
sa.Column('email', sa.String(length=120), nullable=False),
sa.Column('lang', sa.Unicode(length=32), nullable=True),
sa.Column('timezone', sa.Unicode(length=63), nullable=True),
sa.Column('example_data_item_id', sa.Integer(), nullable=True),
sa.Column('about_me', sa.Unicode(length=255), nullable=True),
sa.Column('role', sa.Unicode(length=63), nullable=True),
sa.Column('password', sa.String(length=255), nullable=True),
sa.Column('registered_on', sa.DateTime(), nullable=False),
sa.Column('external_user', sa.Boolean(), nullable=True),
sa.Column('last_seen', sa.DateTime(), nullable=True),
sa.Column('jwt_exp_delta_seconds', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['example_data_item_id'], ['example_data_item.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('social_id')
)
op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
op.create_index(op.f('ix_user_first_name'), 'user', ['first_name'], unique=False)
op.create_index(op.f('ix_user_last_name'), 'user', ['last_name'], unique=False)
op.create_index(op.f('ix_user_nickname'), 'user', ['nickname'], unique=True)
op.create_table('acquaintances',
sa.Column('me_id', sa.Integer(), nullable=True),
sa.Column('acquaintance_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['acquaintance_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['me_id'], ['user.id'], )
)
op.create_table('followers',
sa.Column('follower_id', sa.Integer(), nullable=True),
sa.Column('followed_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['followed_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['follower_id'], ['user.id'], )
)
op.create_table('post',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('body', sa.String(length=140), nullable=True),
sa.Column('timestamp', sa.DateTime(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user_group',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('group_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['group_id'], ['group.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('user_id', 'group_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('user_group')
op.drop_table('post')
op.drop_table('followers')
op.drop_table('acquaintances')
op.drop_index(op.f('ix_user_nickname'), table_name='user')
op.drop_index(op.f('ix_user_last_name'), table_name='user')
op.drop_index(op.f('ix_user_first_name'), table_name='user')
op.drop_index(op.f('ix_user_email'), table_name='user')
op.drop_table('user')
op.drop_table('group_permission')
op.drop_table('permission')
op.drop_table('group')
op.drop_index(op.f('ix_example_data_item_uuid'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_some_string_value'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_name'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_mac'), table_name='example_data_item')
op.drop_table('example_data_item')
op.drop_table('blacklist_tokens')
# ### end Alembic commands ###

View File

@@ -0,0 +1,10 @@
"""
Import all models...
"""
from backend.models.example_model import *
from backend.models.user_model import *
from backend.models.post_model import *
from backend.models.recorder_model import *
from backend.models.access_control_model import *
from backend.models.room_model import *
from backend.models.virtual_command_model import *

View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import json
from sqlalchemy import MetaData, CheckConstraint
from sqlalchemy.exc import IntegrityError
from datetime import datetime, timedelta
from backend import db, app, login_manager
from backend.tools.scrape_rooms import scrape_rooms
metadata = MetaData()
class AccessControlEntry(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
name = db.Column(db.Unicode(127), unique=False, nullable=False)
url = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
required_permission_id = db.Column(db.Integer, db.ForeignKey('permission.id'))
required_permission = db.relationship('Permission', back_populates='access_control_entry')
__table_args__ = (
CheckConstraint('length(name) > 2',
name='name_min_length'),
)
def __init__(self, **kwargs):
super(AccessControlEntry, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find ace by name
:param name:
:return:
"""
return AccessControlEntry.query.filter(AccessControlEntry.name == name).first()
@staticmethod
def get_all():
"""
Return all ace
:return:
"""
return AccessControlEntry.query.all()
def __str__(self):
return self.name
def to_dict(self):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
def pre_fill_table():
a_es = {"url": "", }
access_entries = [AccessControlEntry(name=room['name'], number=room['room_number'],
building_name=room['building_name'], building_number=room['building_number']) for room in
a_es]
try:
db.session.bulk_save_objects(access_entries)
db.session.commit()
except IntegrityError as e:
db.session.rollback()

Binary file not shown.

View File

@@ -0,0 +1,240 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import importlib
import ipaddress
import json
import pkgutil
import os
import re
from sqlalchemy import MetaData
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import validates
from backend import db, app, login_manager, LrcException
from sqlalchemy import or_
from datetime import datetime, timedelta
from backend.models.virtual_command_model import virtual_command_recorder_command_table, virtual_command_recorder_table
metadata = MetaData()
class RecorderModel(db.Model):
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=None)
record_adapter_id = db.Column(db.Unicode(63), unique=True, nullable=False)
model_name = db.Column(db.Unicode(63), unique=True, nullable=False)
notes = db.Column(db.Unicode(255), unique=False, nullable=True, default=None)
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
recorders = db.relationship('Recorder', back_populates='recorder_model')
checksum = db.Column(db.String(63), unique=True,
nullable=False) # checksum of the recorder commands! (see: model_updater.py)
last_checksum_change = db.Column(db.DateTime, nullable=True, default=None)
_requires_user = db.Column(db.Integer, default=False, name='requires_user')
_requires_password = db.Column(db.Integer, default=True, name='requires_password')
@staticmethod
def get_all():
return RecorderModel.query.all()
@staticmethod
def get_by_name(name):
return RecorderModel.query.filter(RecorderModel.model_name == name).first()
@staticmethod
def get_by_adapter_id(name):
return RecorderModel.query.filter(RecorderModel.record_adapter_id == name).first()
@staticmethod
def get_where_adapter_id_contains(adapter_id):
return RecorderModel.query.filter(RecorderModel.record_adapter_id.contains(adapter_id)).first()
@staticmethod
def get_by_checksum(md5_sum):
return RecorderModel.query.filter(RecorderModel.checksum == md5_sum).first()
@hybrid_property
def requires_username(self):
return self._requires_user > 0
@requires_username.setter
def requires_username(self, val: bool):
self._requires_user = 1 if val else 0
@hybrid_property
def requires_password(self):
return self._requires_password > 0
@requires_password.setter
def requires_password(self, val: bool):
self._requires_password = 1 if val else 0
def __str__(self):
return self.model_name + " (record adapter: {})".format(self.record_adapter_id)
class Recorder(db.Model):
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
name = db.Column(db.Unicode(63), unique=True, nullable=False)
model_name = db.Column(db.Unicode(63), unique=False, nullable=False)
serial_number = db.Column(db.Unicode(63), unique=True, nullable=True)
locked = db.Column(db.Boolean, default=False) # no modifications allowed
lock_message = db.Column(db.String, nullable=True, default=None)
offline = db.Column(db.Boolean, default=False) # maintenance, etc.
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
_mac = db.Column(db.String(17), unique=True, nullable=True)
_ip = db.Column(db.String(15), unique=True, nullable=True, default=None)
_ip6 = db.Column(db.String(46), unique=True, nullable=True, default=None)
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
username = db.Column(db.String, nullable=True, default=None)
password = db.Column(db.String, nullable=True, default=None)
_configured_options_json_string = db.Column(db.UnicodeText, default='')
_additional_notes_json_string = db.Column(db.UnicodeText, default='')
additional_camera_connected = db.Column(db.Boolean, default=False)
firmware_version = db.Column(db.String, nullable=True, default=None)
room_id = db.Column(db.Integer, db.ForeignKey('room.id'))
room = db.relationship('Room', uselist=False, back_populates='recorder') # one-to-one relation (uselist=False)
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table,
back_populates='recorders')
def __init__(self, **kwargs):
super(Recorder, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
return Recorder.query.filter(Recorder.name == name).first()
@staticmethod
def get_by_identifier(identifier):
return Recorder.query.filter(Recorder.id == identifier).first()
@staticmethod
def get_by_mac(mac: str):
if mac is None or mac == '':
return None
mac = mac.replace('-', ':').lower()
return Recorder.query.filter(Recorder._mac == mac).first()
@staticmethod
def get_all():
return Recorder.query.all()
@validates('name')
def validate_name(self, key, value):
assert len(value) > 2
return value
@hybrid_property
def configured_options(self) -> list:
return json.loads(self._configured_options_json_string)
@configured_options.setter
def configured_options(self, value: list):
self._configured_options_json_string = json.dumps(value)
def add_configured_option(self, value: str):
self._configured_options_json_string = json.dumps(self.configured_options.append(value))
@hybrid_property
def additional_notes(self) -> list:
return json.loads(self._additional_notes_json_string)
@additional_notes.setter
def additional_notes(self, value: list):
self._additional_notes_json_string = json.dumps(value)
def add_additional_notes(self, value: str):
self._additional_notes_json_string = json.dumps(self._additional_notes_json_string.append(value))
@hybrid_property
def mac(self) -> str:
return self._mac.upper()
@mac.setter
def mac(self, value: str):
if value is None or value == '':
return
if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", value.lower()):
self._mac = value.replace('-', ':').lower()
else:
raise LrcException("'{}' is not a valid MAC Address!".format(value))
@hybrid_property
def ip(self) -> str:
return self._ip
@ip.setter
def ip(self, value: str):
try:
ipaddress.IPv4Interface(value)
self._ip = value
except (ipaddress.AddressValueError, ipaddress.NetmaskValueError):
raise LrcException("'{}' is not a valid IPv4 Address!".format(value))
@hybrid_property
def ip6(self) -> str:
return self._ip6
@ip6.setter
def ip6(self, value: str):
try:
ipaddress.IPv6Interface(value)
self._ip6 = value
except (ipaddress.AddressValueError, ipaddress.NetmaskValueError):
raise LrcException("'{}' is not a valid IPv6 Address!".format(value))
# handle bad ip
def __str__(self):
return self.name
def to_dict(self):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
class RecorderCommand(db.Model):
__table_args__ = {'extend_existing': True}
"""Table containing permissions associated with groups."""
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=datetime.utcnow())
name = db.Column(db.Unicode(63), unique=True, nullable=False)
alternative_name = db.Column(db.Unicode(63), unique=True, nullable=True, default=None)
disabled = db.Column(db.Boolean, default=False)
description = db.Column(db.Unicode(511), nullable=True, default=None)
parameters_string = db.Column(db.String(2047), nullable=True)
recorder_model = db.relationship('RecorderModel', back_populates='recorder_commands')
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_command_table,
back_populates='recorder_commands')
@staticmethod
def get_all():
return RecorderCommand.query.all()
@property
def parameters(self):
if self.parameters_string is None:
return None
return json.loads(self.parameters_string)
@parameters.setter
def parameters(self, parameters_dict: dict):
self.parameters_string = json.dumps(parameters_dict)

View File

@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import json
import logging
from sqlalchemy import MetaData, CheckConstraint
from sqlalchemy.exc import IntegrityError
from datetime import datetime, timedelta
from backend import db, app, login_manager
from backend.tools.scrape_rooms import scrape_rooms
logger = logging.getLogger("lrc."+__name__)
metadata = MetaData()
class Room(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
name = db.Column(db.Unicode(127), unique=False, nullable=False)
alternate_name = db.Column(db.Unicode(127), unique=False, nullable=True, default=None)
comment = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
number = db.Column(db.Unicode(63), unique=False, nullable=True)
building_name = db.Column(db.Unicode(63), unique=False, nullable=True)
building_number = db.Column(db.Unicode(63), unique=False, nullable=True)
recorder = db.relationship('Recorder', uselist=False, back_populates='room') # one-to-one relation (uselist=False)
__table_args__ = (
CheckConstraint('length(name) > 2',
name='name_min_length'),
)
def __init__(self, **kwargs):
super(Room, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return Room.query.filter(Room.name == name).first()
@staticmethod
def get_by_building_number(building_number):
"""
Find group by name
:param name:
:return:
"""
return Room.query.filter(Room.building_number == building_number)
@staticmethod
def get_all():
"""
Return all rooms
:return:
"""
return Room.query.all()
def __str__(self):
return self.name
def to_dict(self):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
def pre_fill_table():
rooms = scrape_rooms()
logger.debug("tada")
logger.debug("got {} rooms".format(len(rooms)))
db_rooms = [Room(name=room['name'], number=room['room_number'],
building_name=room['building_name'], building_number=room['building_number']) for room in
rooms]
try:
db.session.bulk_save_objects(db_rooms)
db.session.commit()
logger.debug("rooms commited to DB!")
except IntegrityError as e:
logger.error("Could not add rooms! ({})".format(e))
db.session.rollback()

View File

@@ -2,18 +2,25 @@
"""
Example user model and related models
"""
import json
from backend import db, app
from sqlalchemy.orm import relation
from sqlalchemy import MetaData
from backend import db, app, login_manager
from backend.config import Config
from backend.models.post_model import Post
from backend.models.example_model import ExampleDataItem
import re
import jwt
from flask_login import UserMixin
from sqlalchemy import or_
from sqlalchemy import or_, event
from datetime import datetime, timedelta
from passlib.hash import sha256_crypt
from hashlib import md5
metadata = MetaData()
followers = db.Table('followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
@@ -24,26 +31,70 @@ acquaintances = db.Table('acquaintances',
db.Column('acquaintance_id', db.Integer, db.ForeignKey('user.id'))
)
user_favorite_recorders_table = db.Table('user_favorite_recorders',
db.Column('user_id', db.Integer,
db.ForeignKey('user.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_id', db.Integer,
db.ForeignKey('recorder.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
# This is the association table for the many-to-many relationship between
# groups and members - this is, the memberships.
user_group_table = db.Table('user_group',
db.Column('user_id', db.Integer,
db.ForeignKey('user.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('group_id', db.Integer,
db.ForeignKey('group.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
# This is the association table for the many-to-many relationship between
# groups and permissions.
group_permission_table = db.Table('group_permission',
db.Column('group_id', db.Integer,
db.ForeignKey('group.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('permission_id', db.Integer,
db.ForeignKey('permission.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
class User(UserMixin, db.Model):
"""
Example user model representation.
"""
id = db.Column(db.Integer, primary_key=True)
social_id = db.Column(db.String(64), nullable=True, unique=True)
nickname = db.Column(db.String(64), index=True, unique=True)
first_name = db.Column(db.String(64), index=True, nullable=True)
last_name = db.Column(db.String(64), index=True, nullable=True)
social_id = db.Column(db.Unicode(63), nullable=True, unique=True)
nickname = db.Column(db.Unicode(63), index=True, unique=True)
first_name = db.Column(db.Unicode(63), index=True, nullable=True)
last_name = db.Column(db.Unicode(63), index=True, nullable=True)
email = db.Column(db.String(120), nullable=False, index=True, unique=True)
lang = db.Column(db.String(16), index=False, unique=False)
timezone = db.Column(db.String(32), index=False, unique=False)
lang = db.Column(db.Unicode(32), index=False, unique=False)
timezone = db.Column(db.Unicode(63), index=False, unique=False)
posts = db.relationship('Post', backref='author', lazy='dynamic')
example_data_item = db.relationship('ExampleDataItem', backref='owner', lazy='dynamic')
about_me = db.Column(db.String(140))
role = db.Column(db.String(64))
example_data_item = db.relationship('ExampleDataItem', backref='owner')
example_data_item_id = db.Column(db.ForeignKey(ExampleDataItem.id))
about_me = db.Column(db.Unicode(255))
role = db.Column(db.Unicode(63))
groups = db.relationship('Group', secondary=user_group_table, back_populates='users')
password = db.Column(db.String(255), nullable=True)
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
external_user = db.Column(db.Boolean, default=False)
last_seen = db.Column(db.DateTime, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, default=datetime.utcnow())
jwt_exp_delta_seconds = db.Column(db.Integer, nullable=True)
acquainted = db.relationship('User',
secondary=acquaintances,
@@ -58,7 +109,19 @@ class User(UserMixin, db.Model):
backref=db.backref('followers', lazy='dynamic'),
lazy='dynamic')
favorite_recorders = db.relationship('Recorder', secondary=user_favorite_recorders_table)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
password = kwargs.get("password", None)
external_user = kwargs.get("external_user", None)
if password is not None:
self.password = sha256_crypt.encrypt(password)
if external_user is not None:
self.external_user = external_user
@staticmethod
@login_manager.user_loader
def get_by_identifier(identifier):
"""
Find user by identifier, which might be the nickname or the e-mail address.
@@ -66,7 +129,18 @@ class User(UserMixin, db.Model):
:return:
"""
return User.query.filter(or_(User.nickname == identifier,
User.email == identifier)).first()
User.email == identifier,
User.id == identifier)).first()
@staticmethod
@login_manager.user_loader
def get_by_id(identifier):
"""
Find user by ID.
:param identifier:
:return:
"""
return User.query.filter(User.id == identifier).first()
@staticmethod
def get_all():
@@ -102,6 +176,20 @@ class User(UserMixin, db.Model):
"""
return re.sub('[^a-zA-Z0-9_.]', '', nickname)
@classmethod
def authenticate(cls, **kwargs):
email = kwargs.get('email')
password = kwargs.get('password')
if not email or not password:
return None
user = cls.query.filter_by(email=email).first()
if not user or not user.verify_password(password):
return None
return user
@property
def is_authenticated(self):
"""
@@ -129,6 +217,25 @@ class User(UserMixin, db.Model):
# TODO: implement correctly
return False
@property
def is_read_only(self):
"""
Returns true if user is active.
:return:
"""
# TODO: implement correctly
return True
@property
def effective_permissions(self):
permissions = Config.ROLE_PERMISSION_MAPPINGS.get(self.role, [])
for g in self.groups:
print(g)
for p in g.permissions:
print(p)
permissions.append(p)
return permissions
@staticmethod
def decode_auth_token(auth_token):
"""
@@ -181,6 +288,8 @@ class User(UserMixin, db.Model):
:param password:
:return:
"""
if self.password is None:
return False
return sha256_crypt.verify(password, self.password)
def get_id(self):
@@ -283,8 +392,16 @@ class User(UserMixin, db.Model):
return Post.query.join(followers, (followers.c.followed_id == Post.user_id)).filter(
followers.c.follower_id == self.id).order_by(Post.timestamp.desc())
def to_dict(self):
# return self.__dict__
return dict(id=self.id, email=self.email, groups=[g.to_dict() for g in self.groups])
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
def __repr__(self):
return '<User %r>' % self.nickname
return '<User %r>' % self.email
class BlacklistToken(db.Model):
@@ -304,6 +421,10 @@ class BlacklistToken(db.Model):
def __repr__(self):
return '<id: token: {}'.format(self.token)
@staticmethod
def get_by_token(jwt_id):
return BlacklistToken.query.filter(BlacklistToken.token == jwt_id).first()
@staticmethod
def check_blacklist(auth_token):
"""
@@ -316,3 +437,72 @@ class BlacklistToken(db.Model):
return True
else:
return False
class Group(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
users = db.relationship('User', secondary=user_group_table, back_populates='groups')
permissions = db.relationship('Permission', secondary=group_permission_table, back_populates='groups')
def __init__(self, **kwargs):
super(Group, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return Group.query.filter(Group.name == name).first()
@staticmethod
def get_all():
"""
Return all groups
:return:
"""
return Group.query.all()
def __str__(self):
return self.name
def to_dict(self):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
class Permission(db.Model):
"""Table containing permissions associated with groups."""
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(511))
groups = db.relationship(Group, secondary=group_permission_table,
back_populates='permissions')
access_control_entry = db.relationship('AccessControlEntry', back_populates='required_permission')
@event.listens_for(User.__table__, 'after_create')
def insert_initial_users(*args, **kwargs):
for u in app.config.get("USERS", []):
db.session.add(User(**u))
db.session.commit()
@event.listens_for(Group.__table__, 'after_create')
def insert_initial_groups(*args, **kwargs):
for g in app.config.get("GROUPS", []):
db.session.add(Group(**g))
db.session.commit()
@event.listens_for(Permission.__table__, 'after_create')
def insert_initial_permissions(*args, **kwargs):
for p in app.config.get("PERMISSIONS", []):
db.session.add(Permission(name=p))
db.session.commit()

View File

@@ -0,0 +1,95 @@
import json
from datetime import datetime
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import backref
from backend import db
# This is the association table for the many-to-many relationship between
# virtual commands and recorder commands.
virtual_command_recorder_command_table = db.Table('virtual_command_recorder_command',
db.Column('virtual_command_id', db.Integer,
db.ForeignKey('virtual_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_command_id', db.Integer,
db.ForeignKey('recorder_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
# This is the association table for the many-to-many relationship between
# virtual commands and recorder commands.
virtual_command_recorder_table = db.Table('virtual_command_recorder',
db.Column('virtual_command_id', db.Integer,
db.ForeignKey('virtual_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_id', db.Integer,
db.ForeignKey('recorder.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
class VirtualCommand(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
recorders = db.relationship('Recorder', secondary=virtual_command_recorder_table,
back_populates='virtual_commands')
recorder_commands = db.relationship('RecorderCommand', secondary=virtual_command_recorder_command_table,
back_populates='virtual_commands')
# parent_virtual_command = db.relationship('VirtualCommand', back_populates='child_virtual_commands')
parent_virtual_command_id = db.Column(db.Integer, db.ForeignKey('virtual_command.id'))
child_virtual_commands = db.relationship('VirtualCommand',
backref=backref('parent_virtual_command', remote_side=[id]))
command_order_string = db.Column(db.String)
def __init__(self, **kwargs):
super(VirtualCommand, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return VirtualCommand.query.filter(VirtualCommand.name == name).first()
@staticmethod
def get_all():
"""
Return all groups
:return:
"""
return VirtualCommand.query.all()
@hybrid_property
def command_order(self):
if self.command_order_string is None:
return []
return json.loads(self.command_order_string)
@command_order.setter
def command_order(self, ordered_list_of_commands: list):
self.command_order_string = json.dumps(ordered_list_of_commands)
def __str__(self):
return self.name
def to_dict(self):
return dict(id=self.id, name=self.name, description=self.description)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)

View File

@@ -0,0 +1,178 @@
import importlib
import inspect
import pkgutil
import sys
import telnetlib
from abc import ABC, abstractmethod
defined_recorder_adapters = None
# monkey patching of telnet lib
from pprint import pprint
original_read_until = telnetlib.Telnet.read_until
original_write = telnetlib.Telnet.write
def new_read_until(self, match, timeout=None):
if isinstance(match, str):
return original_read_until(self, match.encode("ascii"), timeout)
else:
return original_read_until(self, match, timeout)
def new_write(self, buffer):
if isinstance(buffer, str):
return original_write(self, buffer.encode("ascii"))
else:
return original_write(self, buffer)
telnetlib.Telnet.read_until = new_read_until
telnetlib.Telnet.write = new_write
def read_line(self, timeout=2):
return self.read_until("\n", timeout)
telnetlib.Telnet.read_line = read_line
def read_until_non_empty_line(self):
line = self.read_line()
if line is None:
return None
while len(line.rstrip()) <= 0:
line = self.read_line()
return line
telnetlib.Telnet.read_until_non_empty_line = read_until_non_empty_line
def assert_string_in_output(self, string, timeout=2):
resp = self.read_until(string, timeout)
if resp is None:
return False, resp,
resp = resp.decode("ascii")
if string in resp:
return True, resp
return False, resp
telnetlib.Telnet.assert_string_in_output = assert_string_in_output
class TelnetAdapter(ABC):
def __init__(self, address, esc_char="W"):
self.address = address
self.tn = None
self.esc_char = esc_char
@abstractmethod
def _login(self):
pass
def _run_cmd(self, cmd, timeout=1, auto_connect=True):
if self.tn is None and not auto_connect:
raise Exception("Not connected!")
elif self.tn is None:
self._login()
self.tn.write(cmd)
out = self.tn.read_until_non_empty_line()
res = out
while out is not None and out != "":
out = self.tn.read_until_non_empty_line()
print(out)
res += out
return res
@staticmethod
def _get_response_str(tn_response):
if isinstance(tn_response, bytes):
return str(tn_response.decode("ascii").rstrip())
else:
return str(tn_response).rstrip()
class RecorderAdapter:
def __init__(self, address: str, user: str, password: str):
self.address = address
self.user = user
self.password = password
@classmethod
@abstractmethod
def get_recorder_params(cls) -> dict:
pass
@abstractmethod
def _get_name(self):
pass
@abstractmethod
def _get_version(self):
pass
@abstractmethod
def is_recording(self) -> bool:
pass
def get_recording_status(self) -> str:
pass
def get_defined_recorder_adapters() -> list:
rec_adapters_module = importlib.import_module(".recorder_adapters", package='backend')
rec_adapter_class = getattr(rec_adapters_module, "RecorderAdapter") # needed, otherwise subclass check may fail
models = []
found_packages = list(pkgutil.iter_modules(rec_adapters_module.__path__))
for f_p in found_packages:
importer = f_p[0]
rec_model_module = importer.find_module(f_p[1]).load_module(f_p[1])
rec_model = {'id': f_p[1], 'name': f_p[1], 'commands': {}, 'path': rec_model_module.__file__}
if hasattr(rec_model_module, 'RECORDER_MODEL_NAME'):
rec_model['name'] = rec_model_module.RECORDER_MODEL_NAME
if hasattr(rec_model_module, 'REQUIRES_USER'):
rec_model['requires_user'] = rec_model_module.REQUIRES_USER
if hasattr(rec_model_module, 'REQUIRES_PW'):
rec_model['requires_password'] = rec_model_module.REQUIRES_PW
for name, obj in inspect.getmembers(rec_model_module, inspect.isclass):
if issubclass(obj, rec_adapter_class) and name != "RecorderAdapter":
rec_model['id'] = rec_model['id'] + "." + obj.__name__
rec_model['class'] = obj
commands = {}
for method_name, method in inspect.getmembers(obj, predicate=inspect.isfunction):
if len(method_name) > 0 and "_" == method_name[0]:
continue
signature = inspect.signature(method)
parameters = {}
for params in signature.parameters:
if params == "self":
continue
param_type = signature.parameters[params].annotation.__name__
param_type = "_unknown_type" if param_type == "_empty" else param_type
parameters[signature.parameters[params].name] = param_type
if len(parameters) <= 0:
parameters = None
commands[method_name] = parameters
rec_model["commands"] = commands
models.append(rec_model)
return models
def get_recorder_adapter_by_id(id: str, **kwargs):
global defined_recorder_adapters
if defined_recorder_adapters is None:
defined_recorder_adapters = get_defined_recorder_adapters()
for rec_adapter in defined_recorder_adapters:
if id in rec_adapter.get('id', '').split("."):
return rec_adapter['class'](**kwargs)
return None
if __name__ == '__main__':
print(get_defined_recorder_adapters())
get_recorder_adapter_by_id('SMP35x', address="172.22.246.207", password="123mzsmp")
exit()

View File

@@ -0,0 +1,164 @@
# Copyright (c) 2019. Tobias Kurze
"""
This is the recorder adapter implementation for Epiphan Recorders. The following Epiphan recorder models are supported:
- LectureRecorder X2
- LectureRecorder
- VGADVI Recorder
- DVI Broadcaster DL
- DVIRecorderDL
"""
import shutil
import time
from datetime import datetime
from pprint import pprint
import requests
from requests.auth import HTTPBasicAuth
from requests.exceptions import ConnectionError
from backend import LrcException
from backend.recorder_adapters import RecorderAdapter
# HOST = "localhost"
from backend.tools.exception_decorator import exception_decorator
RECORDER_MODEL_NAME = "Epiphan Recorder Adapter (for: LectureRecorder X2, LectureRecorder, VGADVI Recorder, " \
"DVI Broadcaster DL and DVIRecorderDL)"
BASE_URL = "http://172.23.8.102" # Audimax SMP 351
USER = "admin"
PW = "lrgrashof+-"
class Epiphan(RecorderAdapter):
def __init__(self, address: str, user: str, password: str, firmware_version: str = "", **kwargs):
if not address.startswith('http'):
address = 'http://' + address
super().__init__(address, user, password)
self.firmware_version = firmware_version
self.session = requests.Session()
self.session.auth = HTTPBasicAuth(self.user, self.password)
@classmethod
def get_recorder_params(cls) -> dict:
return {'_requires_user': True,
'_requires_password': True}
def _get_name(self):
return RECORDER_MODEL_NAME
def _get_version(self):
pass
@exception_decorator(ConnectionError)
def get_recording_status(self) -> dict:
res = self.session.get(self.address + "/admin/ajax/recorder_status.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
@exception_decorator(ConnectionError)
def get_sysinfo(self) -> dict:
res = self.session.get(self.address + "/ajax/sysinfo.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
def is_recording(self) -> bool:
state = self.get_recording_status().get('state', None)
return state == "up"
def get_recording_time(self):
"""
Returns recording time in seconds. Also returns 0 if not recording.
:return:
"""
return self.get_recording_status().get('seconds', None)
def start_recording(self):
res = self.session.get(self.address + "/admin/ajax/start_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(2) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
def stop_recording(self):
res = self.session.get(self.address + "/admin/ajax/stop_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(4) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
def get_ip_address(self):
try:
return self.get_sysinfo().get("system").get("network").get("interfaces")[0].get('ipaddr', None)
except Exception as err:
raise LrcException(str(err))
def get_disk_space(self):
try:
data = self.get_sysinfo().get("system").get("data")
return {'available': data.get("available", None), 'free': data.get("free", None),
'total': data.get("total", None), 'used': data.get("total", 0) - data.get("available", 0)}
except Exception as err:
raise LrcException(str(err))
def get_video_inputs(self) -> list:
ret = []
try:
video = self.get_sysinfo().get("inputs").get("video")
for v in video:
ret.append(
{'id': v.get('id', None), 'name': v.get('name', None), 'resolution': v.get('resolution', None)})
return ret
except Exception as err:
raise LrcException(str(err))
def get_hardware_revision(self):
try:
return self.get_sysinfo().get("system").get("firmware")
except Exception as err:
raise LrcException(str(err))
def get_system_time(self):
try:
time_stamp = self.get_sysinfo().get("time")
return {'unix_time_stamp': time_stamp,
'date_time_utc': datetime.utcfromtimestamp(time_stamp).strftime('%Y-%m-%dT%H:%M:%SZ')}
except Exception as err:
raise LrcException(str(err))
def get_screenshot(self):
ret = self.session.get(self.address + "/admin/grab_frame.cgi?size=256x192&device=DAV93133.vga&_t=1573471990578",
stream=True)
print(ret)
pprint(ret.headers)
with open('out.jpg', 'wb') as out_file:
shutil.copyfileobj(ret.raw, out_file)
del ret
if __name__ == '__main__':
e = Epiphan(BASE_URL, USER, PW)
try:
# print(e.is_recording())
"""
if e.is_recording():
e.stop_recording()
else:
e.start_recording()
print(e.is_recording())
"""
"""
print(e.get_ip_address())
print(e.get_disk_space())
print(e.get_video_inputs())
print(e.get_hardware_revision())
print(e.get_system_time())
"""
e.get_screenshot()
except LrcException as e:
print(e)

View File

@@ -0,0 +1,845 @@
"""
Recorder Adapter for SMP
"""
import logging
from backend import LrcException
from backend.recorder_adapters import telnetlib, TelnetAdapter, RecorderAdapter
from backend.tools.exception_decorator import exception_decorator
logger = logging.getLogger("lrc.recorder_adapters.extron_smp")
RECORDER_MODEL_NAME = "Recorder Adapter for SMP 351 and 352"
VERSION = "0.9.0"
REQUIRES_USER = False
REQUIRES_PW = True
# HOST = "localhost"
# HOST = "129.13.51.102" # Audimax SMP 351
# HOST = "129.13.51.106" # Tulla SMP 351
HOST = "172.22.246.207" # Test SMP MZ
HOST = "129.13.51.109" # Hertz
USER = "admin"
PW = "123mzsmp"
# PW = "audimaxsmp"
PW = "smphertz"
class SMP35x(TelnetAdapter, RecorderAdapter):
def __init__(self, address, password, auto_login=True, **kwargs):
RecorderAdapter.__init__(self, address, "", password)
TelnetAdapter.__init__(self, address)
if auto_login:
self._login()
def _login(self):
logger.debug("Connecting to {} ...".format(self.address))
try:
self.tn = telnetlib.Telnet(self.address)
except TimeoutError as e:
raise LrcException(str(e))
except ConnectionRefusedError as e:
raise LrcException(str(e))
self.tn.read_until("\r\nPassword:")
# password = getpass.getpass()
password = self.password
self.tn.write(password + "\n\r")
out = self.tn.assert_string_in_output("Login Administrator")
print(out)
if not out[0]:
print(out[1])
if "Password:" in out[1]:
# TODO: loop until logged in...
logger.warning("Could not login (as admin) with given password! {}".format(self.address))
print("re-enter pw")
self.tn.write(self.password + "\n\r")
print(self.tn.assert_string_in_output("Login Administrator"))
print("WRONG (admin) password!! Exiting!")
print(self.password)
self.tn = None
logger.error("Could definitely not login (as admin) with given password! {}".format(self.address))
raise Exception("Could not login as administrator with given pw!")
print("OK, we have admin rights!")
def _get_name(self):
return RECORDER_MODEL_NAME
def _get_version(self):
return VERSION
def get_version(self, include_build=False, verbose_info=False):
if verbose_info:
self.tn.write("0Q")
else:
if include_build:
self.tn.write("*Q\n")
else:
self.tn.write("1Q\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_bootstrap_version(self):
self.tn.write("2Q")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_factory_firmware_version(self):
self.tn.write("3Q")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_updated_firmware_version(self):
self.tn.write("4Q")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_part_number(self):
self.tn.write("N")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_model_name(self):
self.tn.write("1I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_model_description(self):
self.tn.write("2I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_system_memory_usage(self):
self.tn.write("3I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_number_of_connected_users(self):
self.tn.write("10I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_system_processer_usage(self):
self.tn.write("11I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_system_processor_idle(self):
self.tn.write("12I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_eth0_link_status(self):
self.tn.write("13I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_file_transfer_config(self):
self.tn.write("38I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_active_alarms(self):
self.tn.write("39I")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_unit_name(self, name: str):
# TODO: check name (must comply with internet host name standards)
self.tn.write(self.esc_char + name + "CN\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_unit_name(self):
self.tn.write(self.esc_char + " CN\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_unit_name(self):
self.tn.write(self.esc_char + "CN\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_telnet_connections(self):
self.tn.write(self.esc_char + "CC\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_verbose_mode(self, mode: int):
"""
Mode:
0=clear/none (default for telnet connections
1=verbose mode (default for USB and RS-232 host control)
2=tagged responses for queries
3=verbose mode and tagged responses for queries
:param mode:
:return:
"""
if mode not in range(4):
raise Exception("Only values from 0 to 3 are allowed!")
self.tn.write(self.esc_char + str(mode) + "CV\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_verbose_mode(self):
self.tn.write(self.esc_char + "CV\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def save_configuration(self, mode: int = 2):
"""
Mode:
0 = IP config
2 = Box specific parameters
:param mode:
:return:
"""
if mode not in [0, 2]:
raise Exception("Only values 0 and 2 are allowed!")
self.tn.write(self.esc_char + "1*{}XF\n".format(mode))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def restore_configuration(self, mode: int = 2):
"""
Mode:
0 = IP config
2 = Box specific parameters
:param mode:
:return:
"""
if mode not in [0, 2]:
raise Exception("Only values 0 and 2 are allowed!")
self.tn.write(self.esc_char + "0*{}XF\n".format(mode))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reboot(self):
self.tn.write(self.esc_char + "1BOOT\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def restart_network(self):
self.tn.write(self.esc_char + "2BOOT\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_flash(self):
"""
Reset flash memory (excludes recording files).
:return:
"""
self.tn.write(self.esc_char + "ZFFF\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def system_reset(self):
"""
Resets device to default and deletes recorded files
:return:
"""
self.tn.write(self.esc_char + "ZXXX\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_settings_and_delete_all_files(self):
"""
Reset to default except IP address, delete all user and recorded files
:return:
"""
self.tn.write(self.esc_char + "ZY\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def absolute_reset(self):
"""
Same as System Reset, plus returns the IP address and subnet mask to defaults.
:return:
"""
self.tn.write(self.esc_char + "ZQQQ\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_front_panel_lock(self, mode: int):
"""
0=Off
1=complete lockout (no front panel control)
2=menu lockout
3=recording controls
:param mode: Execute mode int code
:return:
"""
if mode not in range(4):
raise Exception("Only values from 0 to 3 are allowed!")
self.tn.write(str(mode) + "X\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_front_panel_lock(self):
"""
View executive mode.
0=Off
1=complete lockout (no front panel control)
2=menu lockout
3=recording controls
:return:
"""
self.tn.write("X\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
"""
A lot of stuff related to network settings (ports of services, SNMP, IP, DHCP, etc.)
Only some stuff will be implemented here!
"""
"""
def get_date_time(self):
pass
def get_time_zone(self):
pass
def get_dhcp_mode(self):
pass
def get_network_settings(self):
pass
def get_ip_address(self):
pass
def get_mac_address(self):
pass
def get_subnet_mask(self):
pass
def get_gateway_ip(self):
pass
def get_dns_server_ip(self):
pass
"""
"""
RS-232 / serial port related stuff not implemented.
Password and security related stuff not implemented.
File related stuff not implemented. (-> use sftp)
"""
def set_input(self, input_num: int, channel_num: int):
"""
Switches input # (1 to 5) to output channel (1=A [input 1 and 2], 2=B [input 3, 4 and 5])
:param input_num:
:param channel_num:
:return:
"""
if input_num not in range(1, 6):
raise Exception("input_num must be a value between 1 and 5!")
if channel_num not in range(1, 3):
raise Exception("input_num must be a value between 1 and 2!")
self.tn.write("{}*{}!\n".format(input_num, channel_num))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input(self, channel_num: int):
if channel_num not in range(1, 2):
raise Exception("input_num must be a value between 1 and 2!")
self.tn.write("{}!\n".format(channel_num))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_input_format(self, input_num: int, input_format: int):
"""
Sets the input to the format, where the input_format parameter may be:
1 = YUVp / HDTV (default)
2 = YUVi
3 = Composite
:param input_num:
:param input_format:
:return:
"""
if input_num not in range(1, 6):
raise Exception("input_num must be a value between 1 and 5!")
if input_format not in range(1, 4):
raise Exception("input_num must be a value between 1 and 3!")
self.tn.write("{}*{}\\\n".format(input_num, input_format))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_format(self, input_num: int):
if input_num not in range(1, 6):
raise Exception("input_num must be a value between 1 and 5!")
self.tn.write("{}\\\n".format(input_num))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_input_name(self, input_num: int, input_name: str):
if input_num not in range(1, 6):
raise Exception("input_num must be a value between 1 and 5!")
if len(input_name) > 16:
raise Exception("input_name must be no longer than 16 chars")
try:
input_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("input_name must only contain ascii characters")
self.tn.write("{}{},{}NI\n".format(self.esc_char, input_num, input_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_name(self, input_num: int):
if input_num not in range(1, 6):
raise Exception("input_num must be a value between 1 and 5!")
self.tn.write("{}{}NI\n".format(self.esc_char, input_num))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_selction_per_channel(self):
self.tn.write("32I\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
"""
Input configuration part skipped
"""
def stop_recording(self):
self.tn.write("{}Y0RCDR\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def start_recording(self):
self.tn.write("{}Y1RCDR\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def pause_recording(self):
self.tn.write("{}Y2RCDR\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
@exception_decorator(ConnectionError)
def get_recording_status(self):
"""
Status may be one of:
0=stop
1=record
2=pause
:return: status
"""
self.tn.write("{}YRCDR\n".format(self.esc_char))
return int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()))
def is_recording(self) -> bool:
return self.get_recording_status() == 1
def extent_recording_time(self, extension_time: int):
"""
Extends a scheduled recording by extension_time minutes
:param extension_time: must be an int from 0 to 99
:return:
"""
if extension_time not in range(0, 100):
raise Exception("extension_time must be a value between 0 and 99!")
self.tn.write("{}E{}RCDR\n".format(self.esc_char, extension_time))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def add_chapter_marker(self):
self.tn.write("{}BRCDR\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def swap_channel_positions(self):
self.tn.write("%\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_recording_status_text(self):
self.tn.write("I\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_elapsed_recording_time(self):
self.tn.write("35I\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_remaining_recording_time(self):
self.tn.write("36I\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_recording_destination(self):
self.tn.write("37I\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
"""
Metadata part skipped
"""
def recall_user_preset(self, channel_number: int, preset_number: int):
if channel_number not in range(1, 3):
raise Exception("channel_number must be a value between 1 and 2!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("1*{}*{}.\n".format(channel_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def save_user_preset(self, channel_number: int, preset_number: int):
if channel_number not in range(1, 3):
raise Exception("channel_number must be a value between 1 and 2!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("1*{}*{},\n".format(channel_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_user_preset_name(self, preset_number: int, preset_name: str):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
if len(preset_name) > 16:
raise Exception("preset_name must be no longer than 16 chars")
try:
preset_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("preset_name must only contain ascii characters")
self.tn.write("{}1*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_user_preset_name(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}1*{}PNAM\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_user_presets(self, input_number: int):
if input_number not in range(1, 6):
raise Exception("input_number must be a value between 1 and 5!")
self.tn.write("52*{}#\n".format(input_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
# Input Presets
def recall_input_preset(self, channel_number: int, preset_number: int):
if channel_number not in range(1, 3):
raise Exception("channel_number must be a value between 1 and 2!")
if preset_number not in range(1, 129):
raise Exception("preset_number must be a value between 1 and 128!")
self.tn.write("2*{}*{}.\n".format(channel_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def save_input_preset(self, channel_number: int, preset_number: int):
if channel_number not in range(1, 3):
raise Exception("channel_number must be a value between 1 and 2!")
if preset_number not in range(1, 129):
raise Exception("preset_number must be a value between 1 and 128!")
self.tn.write("1*{}*{},\n".format(channel_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_input_preset_name(self, preset_number: int, preset_name: str):
if preset_number not in range(1, 129):
raise Exception("preset_number must be a value between 1 and 128!")
if len(preset_name) > 16:
raise Exception("preset_name must be no longer than 16 chars")
try:
preset_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("preset_name must only contain ascii characters")
self.tn.write("{}2*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_preset_name(self, preset_number: int):
if preset_number not in range(1, 129):
raise Exception("preset_number must be a value between 1 and 128!")
self.tn.write("{}2*{}PNAM\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def delete_input_preset(self, preset_number: int):
if preset_number not in range(1, 129):
raise Exception("preset_number must be a value between 1 and 128!")
self.tn.write("{}X2*{}PRST\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_presets(self):
self.tn.write("51#\n")
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
# Streaming Presets
def recall_streaming_preset(self, output_number: int, preset_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
3 = Confidence Stream
:param preset_number:
:param output_number:
:return:
"""
if output_number not in range(1, 4):
raise Exception("output_number must be a value between 1 and 3!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("3*{}*{}.\n".format(output_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def save_streaming_preset(self, output_number: int, preset_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
3 = Confidence Stream
:param output_number:
:param preset_number:
:return:
"""
if output_number not in range(1, 4):
raise Exception("output_number must be a value between 1 and 3!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("3*{}*{},\n".format(output_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_streaming_preset_name(self, preset_number: int, preset_name: str):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
if len(preset_name) > 16:
raise Exception("preset_name must be no longer than 16 chars")
try:
preset_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("preset_name must only contain ascii characters")
self.tn.write("{}3*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_streaming_preset_name(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}3*{}PNAM\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_streaming_preset_to_default(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}X3*{}PRST\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
# Encoder Presets
def recall_encoder_preset(self, output_number: int, preset_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
3 = Confidence Stream
:param preset_number:
:param output_number:
:return:
"""
if output_number not in range(1, 4):
raise Exception("output_number must be a value between 1 and 3!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("4*{}*{}.\n".format(output_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def save_encoder_preset(self, output_number: int, preset_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
3 = Confidence Stream
:param preset_number:
:param output_number:
:return:
"""
if output_number not in range(1, 4):
raise Exception("output_number must be a value between 1 and 3!")
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("4*{}*{},\n".format(output_number, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_encoder_preset_name(self, preset_number: int, preset_name: str):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
if len(preset_name) > 16:
raise Exception("preset_name must be no longer than 16 chars")
try:
preset_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("preset_name must only contain ascii characters")
self.tn.write("{}4*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_encoder_preset_name(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}4*{}PNAM\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_encoder_preset_to_default(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}X4*{}PRST\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
# Layout Presets
def save_layout_preset(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("7*{},\n".format(preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def recall_layout_preset(self, preset_number: int, include_input_selections: bool = True):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
if include_input_selections:
self.tn.write("7*{}.\n".format(preset_number))
else:
self.tn.write("8*{}.\n".format(preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_layout_preset_name(self, preset_number: int, preset_name: str):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
if len(preset_name) > 16:
raise Exception("preset_name must be no longer than 16 chars")
try:
preset_name.encode('ascii')
except UnicodeEncodeError:
raise Exception("preset_name must only contain ascii characters")
self.tn.write("{}7*{},{}PNAM\n".format(self.esc_char, preset_number, preset_name))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_layout_preset_name(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}7*{}PNAM\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def reset_layout_preset_to_default(self, preset_number: int):
if preset_number not in range(1, 17):
raise Exception("preset_number must be a value between 1 and 16!")
self.tn.write("{}X7*{}PRST\n".format(self.esc_char, preset_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
"""
Input adjustments skipped
Picture adjustments skipped
"""
def mute_output(self, output_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
:param output_number:
:return:
"""
if output_number not in range(1, 3):
raise Exception("output_number must be a value between 1 and 2!")
self.tn.write("{}*1B\n".format(output_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def unmute_output(self, output_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
:param output_number:
:return:
"""
if output_number not in range(1, 3):
raise Exception("output_number must be a value between 1 and 2!")
self.tn.write("{}*0B\n".format(output_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def is_muted(self, output_number: int):
"""
Output_number:
1 = Channel A
2 = Channel B
:param output_number:
:return:
"""
if output_number not in range(1, 3):
raise Exception("output_number must be a value between 1 and 2!")
self.tn.write("{}B\n".format(output_number))
return int(TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())) > 0
"""
EDID skipped
Encoder settings skipped
some advanced options skipped
"""
@classmethod
def get_recorder_params(cls) -> dict:
return {'_requires_user': False,
'_requires_password': True}
def get_input_hdcp_status(self, input_number: int):
"""
returns:
0 = no sink / source detected
1 = sink / source detected with HDCP
2 = sink / source detected without HDCP
:param input_number: from 1 to 5
:return:
"""
if input_number not in range(1, 6):
raise Exception("input_number must be a value between 1 and 6!")
self.tn.write("{}I{}HDCP\n".format(self.esc_char, input_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_input_authorization_hdcp_on(self, input_number: int):
if input_number not in range(1, 6):
raise Exception("input_number must be a value between 1 and 6!")
self.tn.write("{}E{}*1HDCP\n".format(self.esc_char, input_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def set_input_authorization_hdcp_off(self, input_number: int):
if input_number not in range(1, 6):
raise Exception("input_number must be a value between 1 and 6!")
self.tn.write("{}E{}*0HDCP\n".format(self.esc_char, input_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_input_authorization_hdcp_status(self, input_number: int):
if input_number not in range(1, 6):
raise Exception("input_number must be a value between 1 and 6!")
self.tn.write("{}E{}HDCP\n".format(self.esc_char, input_number))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def enable_hdcp_notification(self):
self.tn.write("{}N1HDCP\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def disable_hdcp_notification(self):
self.tn.write("{}N0HDCP\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_hdcp_notification_status(self):
self.tn.write("{}NHDCP\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
# background image settings
def set_background_image(self, filename: str):
self.tn.write("{}{}RF\n".format(self.esc_char, filename))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def get_background_image_filename(self):
self.tn.write("{}RF\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def mute_background_image(self):
self.tn.write("{}0RF\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def main():
smp = SMP35x(HOST, PW, True)
print(smp)
print(smp.get_recording_status())
print(smp.is_recording())
exit()
smp._login()
print(smp.get_version(verbose_info=False))
print(smp.get_file_transfer_config())
print(smp.save_configuration())
print(smp.restore_configuration())
return
print(smp.get_bootstrap_version())
print(smp.get_part_number())
print(smp.get_model_name())
print(smp.get_model_description())
print(smp.get_system_memory_usage())
print(smp.get_file_transfer_config())
# print(smp.get_unit_name())
# print(smp.set_unit_name("mzsmp"))
# print(smp.get_unit_name())
# print(smp.reset_unit_name())
print(smp.set_front_panel_lock(0))
print(smp.get_front_panel_lock())
print(smp.get_input_name(1))
print(smp.get_input_selction_per_channel())
print(smp.get_recording_status())
print("Preset Name: " + smp.get_user_preset_name(2))
print(smp.get_user_presets(1))
print(smp.get_input_presets())
print(smp.get_layout_preset_name(2))
print(smp.get_encoder_preset_name(1))
print(smp.get_streaming_preset_name(2))
print(smp.recall_encoder_preset(3, 1))
print(smp.is_muted(2))
print(smp.mute_output(2))
print(smp.is_muted(2))
print(smp.unmute_output(2))
print(smp.is_muted(2))
if __name__ == '__main__':
main()

77
backend/serve_frontend.py Normal file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import flask
from flask.json import dump
from jose import jwt, jwk
import os
from flask import render_template, send_from_directory, Blueprint, jsonify, url_for
from flask_pyoidc.user_session import UserSession
from backend import app
from backend.auth import oidc_auth
fe_path = os.path.abspath(os.path.join(app.root_path, os.pardir, os.pardir, "frontend", "dist"))
if not os.path.exists(fe_path) or not os.path.exists(os.path.join(fe_path, "index.html")):
app.logger.critical(
"Frontend path and/or index.html does not exist! Please build frontend before continuing! "
"You might want to go to ../frontend and continue from there.")
print("FATAL: Frontend path wrong or index.html missing -> EXITING!")
exit()
fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, ""))
@fe_bp.route('/js/<path:path>')
def send_js(path):
return send_from_directory(os.path.join(fe_path, "js"), path)
@fe_bp.route('/css/<path:path>')
def send_css(path):
return send_from_directory(os.path.join(fe_path, "css"), path)
@fe_bp.route('/img/<path:path>')
def send_img(path):
return send_from_directory(os.path.join(fe_path, "img"), path)
@fe_bp.route('/test')
@oidc_auth.oidc_auth()
def test_oidc():
user_session = UserSession(flask.session)
access_token = user_session.access_token
token_claim = jwt.get_unverified_claims(access_token)
token_header = jwt.get_unverified_header(access_token)
return jsonify(id_token=flask.session['id_token'], access_token=flask.session['access_token'],
userinfo=flask.session['userinfo'],
token_claim=token_claim,
token_header=token_header)
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
@fe_bp.route("/site-map")
def site_map():
print("# serving site-map!!")
links = []
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if has_no_empty_params(rule):
# if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
# links is now a list of url, endpoint tuples
# dump(links)
return jsonify(links)
@fe_bp.route('/', defaults={'path': ''})
@fe_bp.route('/<path:path>')
def catch_all(path):
return render_template("index.html")

View File

20
backend/tests/base.py Normal file
View File

@@ -0,0 +1,20 @@
from flask_testing import TestCase
from backend import app, db
class BaseTestCase(TestCase):
""" Base Tests """
def create_app(self):
app.config.from_object('backend.config.Config')
return app
def setUp(self):
db.create_all()
db.session.commit()
def tearDown(self):
db.session.remove()
db.drop_all()

View File

@@ -0,0 +1,65 @@
import getpass
import sys
from abc import ABC, abstractmethod
from backend.recorder_adapters import telnetlib
# HOST = "localhost"
# HOST = "129.13.51.102" # Audimax SMP 351
# HOST = "129.13.51.106" # Tulla SMP 351
HOST = "172.22.246.207" # Test SMP MZ
user = "admin"
pw = "123mzsmp"
def print_tn(tn_response):
if isinstance(tn_response, bytes):
print(tn_response.decode("ascii").rstrip())
else:
print(str(tn_response).rstrip())
def run_cmd(tn, cmd, timeout=1):
tn.write(cmd)
out = tn.read_until_non_empty_line()
res = out
while out is not None and out != "":
out = tn.read_until_non_empty_line()
print(out)
res += out
return res
tn = telnetlib.Telnet(HOST)
tn.read_until("\r\nPassword:")
# password = getpass.getpass()
password = pw
tn.write(password + "\n\r")
if not tn.assert_string_in_output("Login Administrator")[0]:
print("WRONG (admin) password!! Exiting!")
exit(1)
print("OK, we have admin rights!")
tn.write("1Q\n")
# print_tn(read_line(tn))
print_tn(tn.read_until_non_empty_line())
print("test")
# print(run_cmd(tn, "I\n"))
# run_cmd(tn, "X1CERT\n")
# tn.write(chr(27)+"X1CERT")
# tn.write("WX1CERT\n")
# tn.write(chr(27)+"1BOOT")
# tn.write("W1BOOT\n")
# print_tn(tn.read_until_non_empty_line())
# tn.write("I\n")
# print_tn(tn.read_some())
# tn.write("exit\n\r".encode("ascii"))
# print_tn(tn.read_eager())

View File

@@ -0,0 +1,49 @@
import os
import unittest
from flask import current_app
from flask_testing import TestCase
from backend import app
basedir = os.path.abspath(os.path.join(os.path.abspath(app.root_path), os.pardir))
class TestDevelopmentConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.DevelopmentConfig')
return app
def test_app_is_development(self):
self.assertFalse(app.config['SECRET_KEY'] is 'you-will-never-guess')
self.assertTrue(app.config['DEBUG'] is True)
self.assertFalse(current_app is None)
self.assertTrue(
app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + os.path.join(basedir, 'app.db_debug')
)
class TestTestingConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.TestingConfig')
return app
def test_app_is_testing(self):
self.assertFalse(app.config['SECRET_KEY'] is 'you-will-never-guess')
self.assertTrue(app.config['DEBUG'])
self.assertTrue(
app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + os.path.join(basedir, 'app.db_test')
)
class TestProductionConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.Config')
return app
def test_app_is_production(self):
self.assertTrue(app.config['DEBUG'] is False)
if __name__ == '__main__':
unittest.main()

287
backend/tests/test_auth.py Normal file
View File

@@ -0,0 +1,287 @@
import unittest
import json
import time
from backend import db
from backend.models.user_model import User, BlacklistToken
from backend.tests.base import BaseTestCase
def register_user(self, email, password):
return self.client.post(
'/auth/register',
data=json.dumps(dict(
email=email,
password=password
)),
content_type='application/json',
)
class TestAuthBlueprint(BaseTestCase):
def test_registration(self):
""" Test for user registration """
with self.client:
response = register_user(self, 'joe@gmail.com', '123456')
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully registered.')
self.assertTrue(data['auth_token'])
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 201)
def test_registered_with_already_registered_user(self):
""" Test registration with already registered email"""
user = User(email='joe@gmail.com', password='test')
db.session.add(user)
db.session.commit()
with self.client:
response = register_user(self, 'joe@gmail.com', '123456')
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(
data['message'] == 'User already exists. Please Log in.')
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 202)
def test_registered_user_login(self):
""" Test for login of registered-user login """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.'
)
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# registered user login
response = self.client.post(
'/auth/login',
data=json.dumps(dict(
nickname='test_nick',
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully logged in.')
self.assertTrue(data['auth_token'])
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 200)
def test_non_registered_user_login(self):
""" Test for login of non-registered user """
with self.client:
response = self.client.post(
'/auth/login',
data=json.dumps(dict(
nickname='test_nick',
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'User does not exist.')
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 404)
def test_user_status(self):
""" Test for user status """
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['data'] is not None)
self.assertTrue(data['data']['email'] == 'joe@gmail.com')
# self.assertTrue(data['data']['admin'] is 'true' or 'false')
self.assertEqual(response.status_code, 200)
def test_valid_logout(self):
""" Test for logout before token expires """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# valid token logout
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully logged out.')
self.assertEqual(response.status_code, 200)
def test_invalid_logout(self):
""" Testing logout after the token expires """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# invalid token logout
time.sleep(6)
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
print(response.data)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(
data['message'] == 'Signature expired. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_valid_blacklisted_token_logout(self):
""" Test for logout after a valid token gets blacklisted """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# blacklist a valid token
blacklist_token = BlacklistToken(
token=json.loads(resp_login.data.decode())['auth_token'])
db.session.add(blacklist_token)
db.session.commit()
# blacklisted valid token logout
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Token blacklisted. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_valid_blacklisted_token_user(self):
""" Test for user status with a blacklisted valid token """
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
# blacklist a valid token
blacklist_token = BlacklistToken(
token=json.loads(resp_register.data.decode())['auth_token'])
db.session.add(blacklist_token)
db.session.commit()
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Token blacklisted. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_user_status_malformed_bearer_token(self):
""" Test for user status with malformed bearer token"""
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Bearer token malformed.')
self.assertEqual(response.status_code, 401)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,36 @@
import unittest
from backend import db
from backend.models.user_model import User
from backend.tests.base import BaseTestCase
class TestUserModel(BaseTestCase):
def test_encode_auth_token(self):
user = User(
nickname='testheini',
email='test@test.com',
password='test'
)
db.session.add(user)
db.session.commit()
auth_token = user.encode_auth_token()
self.assertTrue(isinstance(auth_token, bytes))
def test_decode_auth_token(self):
user = User(
nickname='testheini',
email='test@test.com',
password='test'
)
db.session.add(user)
db.session.commit()
auth_token = user.encode_auth_token()
self.assertTrue(isinstance(auth_token, bytes))
self.assertTrue(User.decode_auth_token(
auth_token.decode("utf-8")) == 1)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,2 @@
# Copyright (c) 2019. Tobias Kurze, KIT

View File

@@ -0,0 +1,13 @@
from backend import LrcException
def exception_decorator(*exceptions):
def decorator(func):
def new_func(*args, **kwargs):
try:
ret = func(*args, **kwargs)
return ret
except exceptions as e:
raise LrcException(e)
return new_func
return decorator

17
backend/tools/helpers.py Normal file
View File

@@ -0,0 +1,17 @@
import hashlib
def calculate_md5_checksum(string_to_md5_sum: str):
return hashlib.md5(string_to_md5_sum.encode('utf-8')).hexdigest()
def file_md5(fname: str) -> str:
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
if __name__ == '__main__':
print(file_md5(__file__))

View File

@@ -0,0 +1,56 @@
import json
from pprint import pprint
import xlrd
MAX_CONSECUTIVE_EMPTY_ROWS_BEFORE_CANCEL = 5
file_location = "/home/tobias/tmp/Hoersaal-Rec-Liste.xlsx"
wb = xlrd.open_workbook(file_location)
sheet = wb.sheet_by_index(0)
headers = None
recorders = []
a_lot_of_empty_rows = False
consecutive_empty_rows = 0
ix = 0
while not a_lot_of_empty_rows:
try:
vals = sheet.row_values(ix)
except IndexError:
break
if len(set(vals)) == 1 and set(vals).pop() == '':
consecutive_empty_rows += 1
if consecutive_empty_rows > MAX_CONSECUTIVE_EMPTY_ROWS_BEFORE_CANCEL:
a_lot_of_empty_rows = True
else:
consecutive_empty_rows = 0
if len(set(vals)) > 5 and headers is None: # get table header
headers = {ix: vals[ix] for ix in range(0, len(vals))}
elif len(set(vals)) > 5: # regular rows
recorders.append({headers[ix]: vals[ix] for ix in range(0, len(vals))})
ix += 1
if ix >= 100:
a_lot_of_empty_rows = True
#pprint(recorders)
print(len(recorders))
nicely_formatted_recorders = []
for r in recorders:
rec = {'name': r['Opencast / CM'],
'building': r['Gebäude'],
'room': r['Hörsaal'],
'username': r['Benutzer'],
'password': r['PW'],
'ip': r['IP'],
'mac': r['MAC'],
'type': 'SMP 351' if 'SMP 351' in r['Rekorder-Typ'] else r['Rekorder-Typ'],
'additional_camera': r['Zus. Kamera'] == 'Ja',
'firmware_version': r['FW Vers.'],
'network_name': r['DNS'],
'description': json.dumps(
{'comment': r['Bemerkung'], 'network_port': r['Dosennummer'], 'rsync_name': r['Rsync-Name']})}
nicely_formatted_recorders.append(rec)
print(json.dumps(nicely_formatted_recorders))

View File

@@ -0,0 +1,192 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
import hashlib
import json
import logging
import os
import re
from datetime import datetime
from json import dumps
from pprint import pprint
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
from backend import db
from backend.models import Room
from backend.models.recorder_model import RecorderModel, RecorderCommand, Recorder
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.helpers import calculate_md5_checksum
logger = logging.getLogger("lrc." + __name__)
KNOWN_RECORDERS = {re.compile(r'(?P<name>SMP)[\s]*(?P<number>[\d]+)[\s]*.?[\s]*(?P<options>[\S]*)'): 'SMP',
re.compile(
r'(?P<name>LectureRecorder X2|LectureRecorder|VGADVI Recorder|DVI Broadcaster DL|DVIRecorderDL)'): 'Epiphan'}
def create_recorder_commands_for_recorder_adapter(command_definitions: dict, recorder_model: RecorderModel):
logger.debug("Received {} command definitions to create "
"for recoder model {}".format(len(command_definitions),
recorder_model.record_adapter_id))
existing_recorder_commands = RecorderCommand.query.filter(
and_(
RecorderCommand.name.in_([recorder_model.record_adapter_id + ":" + k for k in command_definitions.keys()])),
RecorderCommand.recorder_model == recorder_model)
existing_commands = set()
for existing_command in existing_recorder_commands:
existing_commands.add(existing_command.name)
args = command_definitions.get(existing_command.name)
if dumps(existing_command.parameters) != dumps(args):
logger.warning(
"The function definition {} collides with an existing definition of the same name "
"but different parameters!".format(
existing_command.name))
existing_command.last_time_modified = datetime.utcnow()
existing_command.parameters = args
db.session.commit()
for c_d in set(command_definitions.keys()) - existing_commands:
args = command_definitions.get(c_d)
# print(args)
# create new recorder command(s)
r_c = RecorderCommand(name=recorder_model.record_adapter_id + ":" + c_d, parameters=args,
recorder_model=recorder_model)
db.session.add(r_c)
db.session.flush()
db.session.commit()
def update_recorder_models_database(drop: bool = False):
if drop:
for r in RecorderModel.get_all():
db.session.delete(r)
db.session.commit()
r_as = get_defined_recorder_adapters()
for r_a in r_as:
try:
r_m = RecorderModel.get_by_adapter_id(r_a["id"])
model_checksum = calculate_md5_checksum(dumps(r_a["commands"]))
if r_m is None:
r_m = RecorderModel(record_adapter_id=r_a["id"], model_name=r_a["name"], checksum=model_checksum,
**r_a.get('class', {}).get_recorder_params())
db.session.add(r_m)
db.session.flush()
db.session.refresh(r_m)
logger.debug("Creating command definitions for rec mod adapter {}".format(r_m.record_adapter_id))
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
else:
if r_m.model_name != r_a["name"]:
r_m.model_name = r_a["name"]
r_m.last_time_modified = datetime.utcnow()
if model_checksum != r_m.checksum:
r_m.last_time_modified = datetime.utcnow()
r_m.checksum = model_checksum
r_m.last_checksum_change = datetime.utcnow()
logger.debug("Updating command definitions for rec mod adapter {}".format(r_m.record_adapter_id))
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
except IntegrityError as e:
logger.error(e)
db.session.rollback()
db.session.commit()
def get_recorder_room(rec: dict) -> Room():
rooms = Room.get_by_building_number(rec.get('building', None))
if rooms.count() <= 0:
logger.warning("Building {} unknown! Can not find room for recorder {}.".format(rec['building'], rec['name']))
return None
if rooms.count() == 1:
return rooms.first()
room_name = rec.get('room')
room_name = room_name.replace('', ' ')
for room in rooms:
if all([r_n in room.name for r_n in room_name.split()]):
return room
logger.warning("No room found for recorder {}".format(rec['name']))
def create_default_recorders():
f = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'models', 'initial_recorders.json'))
with open(f, 'r') as json_file:
recorders = json.load(json_file)['recorders']
for r in recorders:
type = r.get('type')
firmware_version = r.get('firmware_version', None)
room_rec_name = r.get('name')
username = r.get('username', None)
password = r.get('password', None)
mac = r.get('mac', None)
ip4 = r.get('ip', None)
additional_camera = r.get('additional_camera', False)
description = r.get('description', '')
for k_r in KNOWN_RECORDERS:
if match := k_r.search(type):
name = match.groupdict().get('name')
model_number = match.groupdict().get('number', None)
options = match.groupdict().get('options', None)
if options is not None and options != "":
options = options.split(',')
if model_number is not None:
model_name = name + " " + model_number
model_search_name = name + model_number[:-1] # just get prefix (remove last digit); SMP 35x -> 35
else:
model_name = name
model_search_name = KNOWN_RECORDERS[k_r]
rec_model = RecorderModel.get_where_adapter_id_contains(model_search_name)
rec = Recorder.get_by_mac(mac)
if rec is None:
rec = Recorder.get_by_name(room_rec_name + " Recorder")
if rec is None:
rec = Recorder()
rec.mac = mac
db.session.add(rec)
rec.name = room_rec_name + " Recorder"
rec.model_name = model_name
rec.recorder_model = rec_model
rec.username = username
rec.password = password
rec.firmware_version = firmware_version
rec.ip = ip4
rec.additional_camera_connected = additional_camera
rec.additional_note = description
rec.configured_options = options
rec.room = get_recorder_room(r)
db.session.flush()
db.session.refresh(rec)
db.session.commit()
if __name__ == '__main__':
# for r in Room.get_all():
# print(r)
# exit()
commands = RecorderCommand.get_all()
for c in commands:
print(c)
print(c.recorder_model)
for r_m in RecorderModel.get_all():
print(r_m.recorder_commands)
exit()
recorders = Recorder.get_all()
for r in recorders:
if r.room is None:
print("{}: {}".format(r, r.room))
# db.drop_all()
# db.create_all()
update_recorder_models_database()
create_default_recorders()
db.session.commit()
# print(get_recorder_room({"room": "Grosser Hörsaal Bauingenieure", "building": "10.50"}))
# print(get_recorder_room({"room": "Grosser Hörsaal Bauingenieure", "building": "30.95"}))

View File

@@ -0,0 +1,60 @@
from pprint import pprint
import re
import requests
from bs4 import BeautifulSoup
def scrape_rooms():
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
room_url = "https://campus.kit.edu/live-stud/campus/all/roomgroup.asp?roomgroupcolumn1=H%F6r%2D%2FLehrsaal&tguid=0x1A35C3A1490748388EBEBA3943EFCDD5"
page = requests.get(room_url, headers=headers)
# soup = BeautifulSoup(page.content, 'html5lib')
soup = BeautifulSoup(page.content, 'html.parser')
# pprint(page.content)
# pprint(soup.prettify())
idx = 0
rooms = []
re_string = r"^(\d\d.\d\d)?\s(.*)"
re_exp = re.compile(re_string)
for tr in soup.find_all('tr'):
idx += 1
if idx == 1: # skip first row
continue
a_name = tr.find_all('a')[0].string
a_building = tr.find_all('a')[3].string
match = re_exp.match(a_name)
if match is not None:
building_number, name = re_exp.match(a_name).groups()
else:
name = a_name
building_number = None
match = re_exp.match(a_building)
if match is not None:
building_number, building_name = re_exp.match(a_building).groups()
else:
building_name = a_name
building_number = None
room = {'name': name,
'room_number': tr.find_all('a')[1].string if tr.find_all('a')[0].string != "None" else tr.find_all('a')[
1].string,
'building_name': building_name,
'building_number': building_number}
rooms.append(room)
return rooms
if __name__ == '__main__':
pprint(scrape_rooms())

View File

@@ -0,0 +1,60 @@
import smtplib
import traceback
from email.message import EmailMessage
from logging.handlers import SMTPHandler
from typing import List, Union
from backend import Config
def send_mail(subject: str, msg_body: str, to_mail: List, from_mail: str = Config.FROM_MAIL):
subject = subject.strip().replace("\r", "").split("\n")[0] # remove breaks resp. cut after line break
try:
msg = EmailMessage()
msg.set_content(msg_body)
msg["Subject"] = subject
msg["From"] = from_mail
msg["To"] = to_mail
s = smtplib.SMTP(Config.SMTP_SERVER)
s.send_message(msg)
s.quit()
except Exception as e:
print(
"Could not send E-Mail (Exception: {})".format(str(e)))
def send_error_mail(message_or_exception: Union[str, Exception], subject: str = None,
subject_prefix: str = "[LRC] Error: ",
receiver_mail_addresses=Config.ERROR_E_MAIL_TO):
if isinstance(message_or_exception, Exception):
if subject is None:
subject = subject_prefix + str(type(message_or_exception))
else:
subject = subject_prefix + subject
msg_body = str(type(message_or_exception)) + ": " + str(message_or_exception) + "\n\n" + traceback.format_exc()
else:
if subject is None:
subject = str(message_or_exception)
else:
subject = subject_prefix + subject
msg_body = str(message_or_exception)
send_mail(subject, msg_body, receiver_mail_addresses)
def send_warning_mail():
pass
def get_smtp_default_handler(receiver_mail_addresses=Config.ADMIN_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Log: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)
def get_smtp_error_handler(receiver_mail_addresses=Config.ERROR_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Error: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)

View File

@@ -0,0 +1,200 @@
import json
import os
import logging
import subprocess
import threading
from io import StringIO
from logging.handlers import MemoryHandler
import requests
from requests.auth import HTTPBasicAuth
from multiprocessing.pool import ThreadPool
from multiprocessing.context import TimeoutError
from ics import Calendar
from backend import LrcException
from backend.config import Config
from backend.recorder_adapters import RecorderAdapter
from backend.recorder_adapters.epiphan_base import Epiphan
from backend.recorder_adapters.extron_smp import SMP35x
from backend.tools.send_mail import send_error_mail, get_smtp_error_handler
logger = logging.getLogger("lrc.tools.simple_state_checker")
smtp_error_handler = get_smtp_error_handler(subject="Errors have been detected while checking recorder states!")
#mem_handler = MemoryHandler(capacity=100, flushLevel=logging.FATAL, target=smtp_error_handler)
#mem_handler.setLevel(logging.WARNING)
rec_err_state_log_stream = StringIO()
rec_err_state_log_stream_handler = logging.StreamHandler(stream=rec_err_state_log_stream)
rec_err_state_log_stream_handler.setLevel(logging.WARNING)
logger.addHandler(rec_err_state_log_stream_handler)
#logger.addHandler(mem_handler)
base_url = "https://opencast.bibliothek.kit.edu"
session = requests.session()
session.auth = HTTPBasicAuth(Config.OPENCAST_USER, Config.OPENCAST_PW)
config = {'service_urls': {}}
recorders = None
agent_states_lock = threading.RLock()
agent_states = {}
def get_service_url(service_type: str):
if service_type in config['service_urls']:
return config['service_urls'][service_type]
params = {'serviceType': service_type}
url = base_url + "/services/available.json"
res = session.get(url, params=params)
if res.ok:
service = res.json()["services"]["service"]
config["service_urls"][service_type] = service["host"] + \
service["path"]
return service["host"] + service["path"]
return None
def get_calender(rec_id):
params = {'agentid': rec_id}
url = get_service_url('org.opencastproject.scheduler') + "/calendars"
res = session.get(url, params=params)
if res.ok:
return Calendar(res.text)
def get_capture_agents():
url = get_service_url("org.opencastproject.capture.admin") + "/agents.json"
res = session.get(url)
if res.ok:
return res.json()["agents"]["agent"]
def get_recorder_details():
"""Temporary implementation using initial_recorders.json. Should be replaced by DB layer later!"""
global recorders
if recorders is None:
f = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'models', 'initial_recorders.json'))
with open(f, 'r') as json_file:
recorders = json.load(json_file)['recorders']
return recorders
def get_recorder_by_name(name: str):
for r in get_recorder_details():
if r["name"] == name:
return r
return None
def notify_users_of_problem(msg: str):
pass
def get_recorder_adapter(recorder_info: dict) -> RecorderAdapter:
if "SMP" in recorder_info["type"]:
rec = SMP35x(recorder_info['ip'], recorder_info['password'])
else:
rec = Epiphan(recorder_info['ip'], recorder_info["username"], recorder_info["password"])
return rec
def check_capture_agent_state(a: dict):
logger.debug("Checking Agent {}".format(a['name']))
c = get_calender(a['name'])
is_recording_in_calendar = len(list(c.timeline.now())) >= 1
if is_recording_in_calendar:
logger.info("{} has entry in Calender and should therefore be recording... checking now!".format(a['name']))
if a['state'] == "capturing":
recorder_info = get_recorder_by_name(a['name'])
try:
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
logger.info("OK recorder {} is recording :)".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is recording'
else:
logger.info(rec.get_recording_status())
logger.error("FATAL - recorder {} must be recording but is not!!!!".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder is NOT recording, but should!'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
else:
logger.error("FATAL: {} is not in capturing state...but should be!!".format(a['name']))
else:
recorder_info = get_recorder_by_name(a['name'])
try:
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
logger.error("FATAL - recorder must not be recording!!!!")
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder IS recording, but should NOT!'
else:
logger.info("OK recorder is not recording :)")
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is NOT recording'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
def ping_capture_agent(a: dict):
recorder_ip = get_recorder_by_name(a['name'])['ip']
try:
response = subprocess.check_call(
['ping', '-W', '10', '-c', '2', recorder_ip],
# stderr=subprocess.STDOUT, # get all output
stdout=subprocess.DEVNULL, # suppress output
stderr=subprocess.DEVNULL,
universal_newlines=True # return string not bytes
)
logger.info("Successfully pinged {} ({}). :-)".format(a['name'], recorder_ip))
except subprocess.CalledProcessError:
logger.error("Can not ping {} ({})!!".format(a['name'], recorder_ip))
agents = get_capture_agents()
logger.info("Got {} capture agents that will be checked...".format(len(agents)))
for a in agents:
agent_states[a['name']] = 'PROBLEMATIC - unknown'
# pool = ThreadPool(5)
# pool.map(check_capture_agent_state, agents)
NUM_THREADS = 8
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(ping_capture_agent, (agent,)) for agent in agents]
try:
[res.get(timeout=12) for res in results]
except TimeoutError as e:
logger.error("Timeout while pinging capture agent! {}".format(e))
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(check_capture_agent_state, (agent,)) for agent in agents]
try:
[res.get(timeout=12) for res in results]
except TimeoutError as e:
logger.error("Timeout while getting capture agent state! {}".format(e))
logger.info("DONE checking capture agents / recorders!")
logged_events = rec_err_state_log_stream.getvalue()
if len(logged_events) > 0:
logged_events += "\n\n=============\nAgent States:\n\n{}".format(''.join(
"{:<48}: {}\n".format(a, agent_states[a]) for a in agent_states
))
send_error_mail(logged_events, "Errors have been detected while checking recorder states!")
#mem_handler.close()

View File

@@ -0,0 +1,2 @@
# Copyright (c) 2019. Tobias Kurze

59
backend/websocket/base.py Normal file
View File

@@ -0,0 +1,59 @@
import logging
import threading
from flask_login import current_user
from flask_socketio import SocketIO, emit
from backend import app
logger = logging.getLogger("lrc.websocket")
async_mode = 'threading' # set to traditional python threading model
# async_mode = None
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
class WebSocketBase:
def __init__(self, flask_app_context=None):
if flask_app_context is None:
self.flask_app_context = app
self.socket_thread = None
def start_websocket_in_thread(self, host=None, port=None, debug=None):
self.socket_thread = threading.Thread(
target=self.start_websocket,
args=(host, port, debug))
self.socket_thread.start()
return self.socket_thread
def start_websocket(self, host=None, port=None, debug=None):
if debug is None:
debug = self.flask_app_context.debug
socketio.run(self.flask_app_context, host=host, port=port, debug=debug)
@staticmethod
@socketio.on('connect')
def connect_handler():
logger.debug("new connection...")
print(current_user)
if current_user.is_authenticated:
logger.debug("user is authenticated")
print("allowed!")
emit('my response',
{'message': '{0} has joined'.format(current_user.name)},
broadcast=True)
else:
logger.info("user is not authenticated!")
print("not allowed!!")
return False # not allowed here
@socketio.on_error()
def handle_error(self, error):
logger.error(error)
print(error)
if __name__ == '__main__':
wsb = WebSocketBase()
#wsb.start_websocket_in_thread(debug=True)
wsb.start_websocket(debug=True)

View File

@@ -0,0 +1,127 @@
# Copyright (c) 2019. Tobias Kurze
import logging
import threading
import time
from flask import Flask, request
from flask_socketio import SocketIO, emit
from backend import app
logging.basicConfig()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
async_mode = 'threading'
async_mode = None
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
thread = None
thread_lock = threading.Lock()
clients = []
def background_thread():
"""Example of how to send server generated events to clients."""
count = 0
while True:
socketio.sleep(3)
print("server_event ")
count += 1
socketio.emit('server_event',
{'data': 'Server generated event', 'count': count},
)
def ack():
print('message was received!')
@socketio.on('my_event')
def test_message(message: dict):
print("received msg!")
print(message)
if isinstance(message, str):
emit('my_response', 'tolle Antwort! (got only a string!)', callback=ack)
else:
emit('my_response', {'data': message['data']}, callback=ack)
@socketio.on('my broadcast event', namespace='/')
def test_message(message):
emit('my response', {'data': message['data']}, broadcast=True)
@socketio.on('connect')
def test_connect():
print("connected")
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(background_thread)
emit('connect', "You are connected!")
@socketio.on('disconnect', namespace='/')
def test_disconnect():
print('Client disconnected')
@socketio.on_error()
def handle_error(error):
print(error)
def start_in_thread():
socket_thread = threading.Thread(target=lambda appl, host, port: socketio.run(app=appl, host=host, port=port),
args=(app, "localhost", 5000))
socket_thread.start()
return socket_thread
@app.route("/")
def root():
return """<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('connect', function() {
console.log("connected!");
socket.emit('my_event', {data: 'I am connected!'});
});
socket.on('my_response', function(resp) {
console.log('got response:');
console.log(resp);
});
</script>"""
if __name__ == '__main__':
print("running main")
# socketio.init_app(app, cors_allowed_origins="*")
#while len(clients) <= 0:
# time.sleep(1)
#while True:
# time.sleep(2)
# print("sending message...")
# socketio.send("lala")
# print("send lala")
# print(clients[0])
# socketio.emit("server_event", {'msg': "tolle nachricht"}, room=clients[0])
# with app.test_request_context('/'):
# socketio.emit('server_event', "You!: server_event", namespace="/")
# print("send bla")
#socketio.run(app, host="localhost", port=5000, debug=True)
start_in_thread()
while True:
time.sleep(2)
print("still running! :)")
# socketio.run(app, debug=True)
# ENDE
# t.join()

View File

@@ -0,0 +1,27 @@
# Copyright (c) 2019. Tobias Kurze
import logging
import threading
import time
from flask import Flask
from flask_socketio import SocketIO, emit
from backend import app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
logging.basicConfig()
#socketio = SocketIO(message_queue="redis://")
socketio = SocketIO(app, port=5443, debug=True)
#socketio.run(app, host="localhost", port=5000)
#socketio.init_app(app, host="localhost", port=5000, cors_allowed_origins="*", )
#socketio.init_app(app, host="localhost", port=5000, cors_allowed_origins="*", )
socketio.emit("server_event", {'data': 42, 'msg': 'toll'})
print("sent message!")
socketio.emit({'data': 42, 'msg': 'toll'})
print("sent message 2!")

0
logs/app.log.2019-11-12 Normal file
View File

0
logs/app.log.2019-11-13 Normal file
View File

620
logs/app.log.2019-11-15 Normal file
View File

@@ -0,0 +1,620 @@
[2019-11-14 14:16:53,247] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:16:53,255] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:16:53,255] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:16:53,256] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:16:53,261] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:16:53,261] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:16:53,386] {Thread-4} INFO in extron_smp, line 32: Connecting to 129.13.51.101 ...
[2019-11-14 14:16:54,344] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,355] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:16:54,811] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,827] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:16:55,195] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:55,206] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:16:55,988] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,019] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:16:56,265] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,276] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:16:56,323] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:16:56,365] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:16:56,380] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.109 ...
[2019-11-14 14:16:57,008] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.106 ...
[2019-11-14 14:16:57,095] {Thread-5} INFO in extron_smp, line 32: Connecting to 129.13.51.104 ...
[2019-11-14 14:16:57,272] {Thread-1} INFO in simple_state_checker, line 115: 1
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,321] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:16:57,530] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,541] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:16:57,744] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.108 ...
[2019-11-14 14:16:57,936] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,952] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:16:57,954] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,965] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.107 ...
[2019-11-14 14:16:57,966] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:16:58,634] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,655] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:16:58,902] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.103 ...
[2019-11-14 14:16:58,904] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,904] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:16:59,563] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,579] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:16:59,668] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.105 ...
[2019-11-14 14:16:59,797] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,818] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:17:00,764] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:00,780] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:17:00,983] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.110 ...
[2019-11-14 14:17:01,618] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:01,670] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.102 ...
[2019-11-14 14:17:01,960] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:23:51,783] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:25:33,337] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:00,957] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:14,952] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:28:15,602] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:24,029] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:58,640] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:32:30,592] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:34:08,425] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:36:35,216] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:38:11,521] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:43,884] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:53,493] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:39:53,497] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:39:53,497] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:39:53,497] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:39:53,500] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:39:53,500] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:39:53,619] {Thread-4} INFO in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 14:39:54,913] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:54,942] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:39:55,178] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,220] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:39:55,395] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,416] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:39:56,048] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,092] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:39:56,098] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:39:56,108] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:39:56,127] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:56,248] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,269] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:39:56,761] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 14:39:57,066] {Thread-1} INFO in simple_state_checker, line 113: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:39:57,087] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:39:57,545] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 14:39:57,770] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:57,817] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:39:58,182] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 14:39:58,362] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,378] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:39:58,425] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 14:39:58,599] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,610] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:39:58,950] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,951] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:39:59,487] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,513] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:39:59,604] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 14:39:59,908] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,918] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:40:00,356] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 14:40:00,436] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:00,451] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:40:01,582] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:01,608] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:40:01,789] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 14:40:02,326] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 14:40:02,497] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:02,648] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:57:02,691] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,259] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,261] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:57:51,265] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 14:57:51,266] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:57:52,257] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:57:52,259] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:57:53,279] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,279] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:57:53,873] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,873] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:57:53,892] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:35,956] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 15:02:35,961] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:02:35,961] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:02:35,961] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:02:35,962] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:02:35,966] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:02:36,101] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:36,867] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:36,878] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:02:37,586] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:37,616] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:02:38,200] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,232] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:02:38,487] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,503] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:02:38,698] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,710] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:02:38,856] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:02:38,908] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:02:39,323] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:02:39,609] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:02:39,673] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:02:39,693] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:02:40,001] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,011] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:02:40,115] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:02:40,400] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:02:40,409] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,410] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:02:40,604] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,621] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:02:40,828] {Thread-1} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,828] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:02:41,529] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,549] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:02:41,621] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:02:41,849] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,850] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:02:42,655] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:42,687] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:02:43,620] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:02:44,782] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:44,876] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:02:45,342] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:02:45,550] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:45,716] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:02:46,265] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:05:15,774] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:05:15,776] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:05:15,776] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:05:15,778] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:05:15,778] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:05:15,780] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:05:15,840] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:05:17,298] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,314] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:05:17,677] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,694] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:05:17,842] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,853] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:05:18,841] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:18,887] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:05:19,101] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:19,137] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:05:19,149] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:05:19,210] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:05:19,575] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:05:19,886] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:05:20,281] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:05:20,282] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:05:20,333] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,333] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:05:20,383] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,383] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:05:20,616] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,632] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:05:21,026] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:05:21,456] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:05:21,827] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:21,848] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:05:22,128] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:05:22,566] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,567] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:05:22,813] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,819] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:05:23,169] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:23,205] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:05:23,731] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:05:24,776] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:05:24,963] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:24,963] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:05:25,042] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:25,131] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:05:25,828] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:35,727] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:07:35,729] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:07:35,729] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:07:35,729] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:07:35,730] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:07:35,730] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:07:35,863] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:07:37,438] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,453] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:07:37,481] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,497] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:07:37,744] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:07:37,760] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:07:37,996] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,011] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:07:38,259] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,259] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:07:38,503] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,519] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:07:38,612] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:07:38,612] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:07:38,633] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:07:38,813] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:07:39,478] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,504] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:07:39,592] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:07:39,602] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,625] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:07:39,837] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,871] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:07:39,886] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:07:40,494] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:40,520] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:07:40,903] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:07:41,107] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,108] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:07:41,186] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,186] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:07:41,731] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,747] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:07:41,869] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:07:42,952] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:42,973] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:07:43,268] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:07:44,224] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:44,634] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:07:44,636] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,706] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:20:07,570] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:20:07,572] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:20:07,572] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:20:07,572] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:20:07,575] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:20:07,576] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:20:07,702] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:20:09,335] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,341] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:20:09,527] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,543] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:20:10,343] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:10,375] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:20:11,090] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,106] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:20:11,158] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:20:11,164] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:20:11,194] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,215] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:20:11,464] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:20:11,990] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:20:12,017] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:20:12,028] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:20:12,376] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,387] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:20:12,399] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:20:12,400] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,401] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:20:12,906] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,922] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:20:13,086] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:20:13,264] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,264] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:20:13,943] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:20:13,999] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,999] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:20:14,191] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,192] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:20:14,849] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,938] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:20:16,840] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:20:18,101] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,112] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:20:18,197] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:20:18,231] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,279] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:20:18,965] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:20,327] {Thread-1} WARNING in extron_smp, line 52: Could not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,118] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:41:07,178] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:41:07,180] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:41:07,180] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:41:07,180] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:41:07,180] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:41:07,180] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:41:07,312] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:41:08,619] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,640] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:41:08,822] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,864] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:41:08,864] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,919] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:41:10,309] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:10,319] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:41:10,595] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,610] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:41:10,683] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,706] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:41:10,708] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:41:11,243] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:41:11,253] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:41:11,261] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:41:11,594] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,594] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:41:11,606] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:41:11,624] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,624] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:41:12,061] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,092] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:41:12,311] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,327] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:41:12,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:41:13,130] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:41:13,666] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,677] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:41:13,757] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,777] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:41:14,070] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:14,096] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:41:15,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:15,944] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:41:16,093] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:41:16,804] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:16,805] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:41:16,964] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:41:17,043] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:41:17,168] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:17,905] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,280] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:45:17,132] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:45:17,136] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:45:17,136] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:45:17,136] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:45:17,138] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:45:17,140] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:45:17,246] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:45:18,711] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,763] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:45:18,861] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,872] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:45:18,931] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,941] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:45:19,971] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:45:20,433] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,448] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:45:20,537] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,547] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:45:20,571] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:45:21,177] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,197] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:45:21,408] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:45:21,543] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,564] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:45:22,149] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,165] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:45:22,247] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:45:22,247] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,268] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:45:22,378] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:45:22,958] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,978] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:45:23,300] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:45:23,351] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,351] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:45:23,400] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,400] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:45:24,216] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:45:24,306] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:24,337] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:45:25,245] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:25,266] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:45:25,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:45:26,328] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:26,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:26,923] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:45:27,178] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:27,986] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,239] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-15 09:00:02,960] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:00:02,962] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:00:02,962] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:00:02,963] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:00:02,963] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:00:02,963] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:00:03,163] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:00:04,443] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,454] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:00:04,925] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,941] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:00:05,486] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,507] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:00:05,732] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,753] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:00:05,807] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:00:06,018] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:00:06,443] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:00:06,557] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,583] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:00:06,654] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:00:07,016] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:00:07,028] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:00:07,313] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,333] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:00:07,435] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:00:07,681] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,696] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:00:07,847] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,848] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:00:08,514] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,514] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:00:08,955] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,970] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:00:09,158] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:00:09,479] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:00:10,422] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,443] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:00:10,679] {Thread-1} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:00:10,679] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:00:10,756] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,757] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:00:10,870] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:00:11,648] {Thread-1} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:00:11,726] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:11,959] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,945] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:01:48,428] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:01:48,431] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:01:48,431] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:01:48,431] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:01:48,432] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:01:48,432] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:01:48,538] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:01:49,684] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,690] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,705] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:01:49,716] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:01:50,134] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:01:50,252] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,268] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:01:50,800] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,806] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:01:50,914] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:01:50,915] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,915] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:01:51,069] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,080] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:01:51,673] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,720] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:01:51,726] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:01:51,893] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:01:52,152] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:01:52,231] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,232] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:01:52,598] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,618] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,623] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:01:52,637] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:01:52,956] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,956] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:01:53,679] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:53,721] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:01:54,025] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:01:54,184] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:01:54,998] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,019] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:01:55,087] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,108] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:01:55,254] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:01:55,445] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:01:55,445] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:01:55,943] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:56,200] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:01:56,274] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:03,114] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:03:16,872] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:03:16,875] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:03:16,875] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:03:16,875] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:03:16,875] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:03:16,875] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:03:16,991] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:03:17,901] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:03:17,933] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:03:18,497] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:03:18,639] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:18,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:03:19,037] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,047] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:03:19,189] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,210] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:03:19,310] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,329] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:03:19,329] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:03:19,638] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:03:20,151] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:03:20,331] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,331] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:03:20,462] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,462] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:03:20,494] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,510] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:03:20,633] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:03:21,032] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,053] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:03:21,466] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:03:21,730] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,731] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:03:22,061] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,072] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:03:22,445] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:03:23,370] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:03:24,285] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:24,306] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:03:24,454] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:03:24,681] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:03:24,682] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:03:24,682] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,308] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,616] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,461] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 15:56:02,776] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 15:56:02,783] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 15:56:02,783] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 15:56:02,784] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 15:56:02,787] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 15:56:02,787] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 15:56:02,903] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 15:56:04,320] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,331] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 15:56:04,366] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,377] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 15:56:04,654] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,741] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 15:56:04,779] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 15:56:05,377] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,388] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 15:56:05,479] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 15:56:05,698] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 15:56:06,048] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,105] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 15:56:06,320] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 15:56:06,752] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 15:56:06,834] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,834] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 15:56:06,844] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,845] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 15:56:07,320] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,336] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 15:56:07,555] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 15:56:07,567] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,568] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 15:56:08,323] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,324] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 15:56:08,638] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 15:56:08,687] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 15:56:09,544] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 15:56:09,757] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:09,773] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 15:56:10,425] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:10,441] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 15:56:10,740] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 15:56:11,549] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:11,664] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 15:56:12,063] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:12,450] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,512] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!

View File

@@ -0,0 +1 @@
[2019-11-12 16:17:10,872] {Thread-3} ERROR in simple_state_checker, line 104: FATAL - recorder CS 30.46 Chemie Neuer Hoersaal must be recording!!!!

30
logs/error.log.2019-11-15 Normal file
View File

@@ -0,0 +1,30 @@
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!

68
logs/root.log.2019-11-12 Normal file
View File

@@ -0,0 +1,68 @@
[2019-11-12 16:13:10,529] {MainThread} INFO in simple_state_checker, line 83: Got 19 capture agents that will be checked...
[2019-11-12 16:15:41,995] {MainThread} INFO in simple_state_checker, line 121: Got 19 capture agents that will be checked...
[2019-11-12 16:15:41,998] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-12 16:15:41,998] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-12 16:15:41,998] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-12 16:15:42,000] {Thread-4} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-12 16:15:42,001] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-12 16:15:42,963] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-12 16:15:42,996] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-12 16:15:43,018] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-12 16:15:44,138] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-12 16:15:46,348] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-12 16:15:46,405] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-12 16:15:47,356] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-12 16:15:50,079] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-12 16:15:50,510] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-12 16:15:50,692] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-12 16:15:50,850] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-12 16:15:51,893] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.24 Hörsaal-101
[2019-11-12 16:15:52,190] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-12 16:15:52,980] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent Campus Ost 70.04 SR219
[2019-11-12 16:16:59,911] {MainThread} INFO in simple_state_checker, line 121: Got 19 capture agents that will be checked...
[2019-11-12 16:16:59,914] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-12 16:16:59,914] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-12 16:16:59,914] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-12 16:16:59,915] {Thread-4} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-12 16:16:59,917] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-12 16:17:00,018] {Thread-4} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:01,983] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:01,983] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-12 16:17:02,078] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:02,078] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-12 16:17:02,414] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:02,414] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-12 16:17:04,596] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:04,616] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-12 16:17:04,784] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:04,789] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-12 16:17:05,311] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:05,765] {Thread-1} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:05,780] {Thread-3} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:06,242] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,257] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-12 16:17:06,429] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,430] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-12 16:17:06,631] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,631] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-12 16:17:06,657] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,658] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-12 16:17:08,598] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:08,714] {Thread-1} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:09,251] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,266] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-12 16:17:09,386] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,397] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-12 16:17:09,520] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,536] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.24 Hörsaal-101
[2019-11-12 16:17:09,795] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,795] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-12 16:17:10,460] {Thread-5} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:10,851] {Thread-3} INFO in simple_state_checker, line 103: 1
[2019-11-12 16:17:10,872] {Thread-3} ERROR in simple_state_checker, line 104: FATAL - recorder CS 30.46 Chemie Neuer Hoersaal must be recording!!!!
[2019-11-12 16:17:10,873] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent Campus Ost 70.04 SR219
[2019-11-12 16:17:11,002] {Thread-3} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:11,588] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:11,594] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:11,829] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:12,075] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter

620
logs/root.log.2019-11-15 Normal file
View File

@@ -0,0 +1,620 @@
[2019-11-14 14:16:53,247] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:16:53,255] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:16:53,255] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:16:53,256] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:16:53,261] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:16:53,261] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:16:53,386] {Thread-4} INFO in extron_smp, line 32: Connecting to 129.13.51.101 ...
[2019-11-14 14:16:54,344] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,355] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:16:54,811] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,827] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:16:55,195] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:55,206] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:16:55,988] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,019] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:16:56,265] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,276] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:16:56,323] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:16:56,365] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:16:56,380] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.109 ...
[2019-11-14 14:16:57,008] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.106 ...
[2019-11-14 14:16:57,095] {Thread-5} INFO in extron_smp, line 32: Connecting to 129.13.51.104 ...
[2019-11-14 14:16:57,272] {Thread-1} INFO in simple_state_checker, line 115: 1
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,321] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:16:57,530] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,541] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:16:57,744] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.108 ...
[2019-11-14 14:16:57,936] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,952] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:16:57,954] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,965] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.107 ...
[2019-11-14 14:16:57,966] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:16:58,634] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,655] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:16:58,902] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.103 ...
[2019-11-14 14:16:58,904] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,904] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:16:59,563] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,579] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:16:59,668] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.105 ...
[2019-11-14 14:16:59,797] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,818] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:17:00,764] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:00,780] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:17:00,983] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.110 ...
[2019-11-14 14:17:01,618] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:01,670] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.102 ...
[2019-11-14 14:17:01,960] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:23:51,783] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:25:33,337] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:00,957] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:14,952] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:28:15,602] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:24,029] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:58,640] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:32:30,592] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:34:08,425] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:36:35,216] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:38:11,521] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:43,884] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:53,493] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:39:53,497] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:39:53,497] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:39:53,497] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:39:53,500] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:39:53,500] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:39:53,619] {Thread-4} INFO in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 14:39:54,913] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:54,942] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:39:55,178] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,220] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:39:55,395] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,416] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:39:56,048] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,092] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:39:56,098] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:39:56,108] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:39:56,127] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:56,248] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,269] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:39:56,761] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 14:39:57,066] {Thread-1} INFO in simple_state_checker, line 113: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:39:57,087] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:39:57,545] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 14:39:57,770] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:57,817] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:39:58,182] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 14:39:58,362] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,378] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:39:58,425] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 14:39:58,599] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,610] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:39:58,950] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,951] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:39:59,487] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,513] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:39:59,604] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 14:39:59,908] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,918] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:40:00,356] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 14:40:00,436] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:00,451] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:40:01,582] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:01,608] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:40:01,789] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 14:40:02,326] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 14:40:02,497] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:02,648] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:57:02,691] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,259] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,261] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:57:51,265] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 14:57:51,266] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:57:52,257] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:57:52,259] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:57:53,279] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,279] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:57:53,873] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,873] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:57:53,892] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:35,956] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 15:02:35,961] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:02:35,961] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:02:35,961] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:02:35,962] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:02:35,966] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:02:36,101] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:36,867] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:36,878] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:02:37,586] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:37,616] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:02:38,200] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,232] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:02:38,487] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,503] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:02:38,698] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,710] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:02:38,856] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:02:38,908] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:02:39,323] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:02:39,609] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:02:39,673] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:02:39,693] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:02:40,001] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,011] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:02:40,115] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:02:40,400] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:02:40,409] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,410] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:02:40,604] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,621] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:02:40,828] {Thread-1} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,828] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:02:41,529] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,549] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:02:41,621] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:02:41,849] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,850] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:02:42,655] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:42,687] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:02:43,620] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:02:44,782] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:44,876] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:02:45,342] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:02:45,550] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:45,716] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:02:46,265] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:05:15,774] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:05:15,776] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:05:15,776] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:05:15,778] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:05:15,778] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:05:15,780] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:05:15,840] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:05:17,298] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,314] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:05:17,677] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,694] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:05:17,842] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,853] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:05:18,841] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:18,887] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:05:19,101] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:19,137] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:05:19,149] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:05:19,210] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:05:19,575] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:05:19,886] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:05:20,281] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:05:20,282] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:05:20,333] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,333] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:05:20,383] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,383] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:05:20,616] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,632] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:05:21,026] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:05:21,456] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:05:21,827] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:21,848] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:05:22,128] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:05:22,566] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,567] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:05:22,813] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,819] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:05:23,169] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:23,205] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:05:23,731] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:05:24,776] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:05:24,963] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:24,963] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:05:25,042] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:25,131] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:05:25,828] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:35,727] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:07:35,729] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:07:35,729] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:07:35,729] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:07:35,730] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:07:35,730] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:07:35,863] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:07:37,438] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,453] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:07:37,481] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,497] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:07:37,744] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:07:37,760] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:07:37,996] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,011] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:07:38,259] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,259] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:07:38,503] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,519] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:07:38,612] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:07:38,612] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:07:38,633] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:07:38,813] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:07:39,478] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,504] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:07:39,592] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:07:39,602] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,625] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:07:39,837] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,871] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:07:39,886] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:07:40,494] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:40,520] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:07:40,903] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:07:41,107] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,108] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:07:41,186] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,186] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:07:41,731] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,747] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:07:41,869] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:07:42,952] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:42,973] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:07:43,268] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:07:44,224] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:44,634] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:07:44,636] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,706] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:20:07,570] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:20:07,572] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:20:07,572] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:20:07,572] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:20:07,575] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:20:07,576] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:20:07,702] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:20:09,335] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,341] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:20:09,527] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,543] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:20:10,343] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:10,375] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:20:11,090] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,106] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:20:11,158] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:20:11,164] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:20:11,194] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,215] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:20:11,464] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:20:11,990] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:20:12,017] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:20:12,028] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:20:12,376] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,387] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:20:12,399] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:20:12,400] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,401] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:20:12,906] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,922] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:20:13,086] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:20:13,264] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,264] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:20:13,943] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:20:13,999] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,999] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:20:14,191] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,192] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:20:14,849] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,938] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:20:16,840] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:20:18,101] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,112] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:20:18,197] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:20:18,231] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,279] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:20:18,965] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:20,327] {Thread-1} WARNING in extron_smp, line 52: Could not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,118] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:41:07,178] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:41:07,180] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:41:07,180] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:41:07,180] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:41:07,180] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:41:07,180] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:41:07,312] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:41:08,619] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,640] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:41:08,822] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,864] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:41:08,864] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,919] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:41:10,309] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:10,319] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:41:10,595] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,610] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:41:10,683] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,706] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:41:10,708] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:41:11,243] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:41:11,253] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:41:11,261] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:41:11,594] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,594] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:41:11,606] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:41:11,624] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,624] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:41:12,061] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,092] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:41:12,311] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,327] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:41:12,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:41:13,130] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:41:13,666] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,677] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:41:13,757] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,777] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:41:14,070] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:14,096] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:41:15,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:15,944] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:41:16,093] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:41:16,804] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:16,805] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:41:16,964] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:41:17,043] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:41:17,168] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:17,905] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,280] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:45:17,132] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:45:17,136] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:45:17,136] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:45:17,136] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:45:17,138] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:45:17,140] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:45:17,246] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:45:18,711] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,763] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:45:18,861] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,872] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:45:18,931] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,941] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:45:19,971] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:45:20,433] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,448] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:45:20,537] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,547] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:45:20,571] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:45:21,177] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,197] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:45:21,408] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:45:21,543] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,564] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:45:22,149] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,165] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:45:22,247] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:45:22,247] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,268] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:45:22,378] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:45:22,958] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,978] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:45:23,300] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:45:23,351] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,351] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:45:23,400] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,400] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:45:24,216] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:45:24,306] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:24,337] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:45:25,245] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:25,266] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:45:25,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:45:26,328] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:26,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:26,923] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:45:27,178] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:27,986] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,239] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-15 09:00:02,960] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:00:02,962] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:00:02,962] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:00:02,963] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:00:02,963] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:00:02,963] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:00:03,163] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:00:04,443] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,454] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:00:04,925] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,941] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:00:05,486] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,507] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:00:05,732] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,753] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:00:05,807] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:00:06,018] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:00:06,443] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:00:06,557] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,583] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:00:06,654] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:00:07,016] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:00:07,028] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:00:07,313] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,333] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:00:07,435] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:00:07,681] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,696] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:00:07,847] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,848] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:00:08,514] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,514] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:00:08,955] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,970] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:00:09,158] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:00:09,479] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:00:10,422] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,443] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:00:10,679] {Thread-1} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:00:10,679] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:00:10,756] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,757] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:00:10,870] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:00:11,648] {Thread-1} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:00:11,726] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:11,959] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,945] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:01:48,428] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:01:48,431] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:01:48,431] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:01:48,431] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:01:48,432] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:01:48,432] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:01:48,538] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:01:49,684] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,690] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,705] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:01:49,716] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:01:50,134] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:01:50,252] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,268] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:01:50,800] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,806] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:01:50,914] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:01:50,915] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,915] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:01:51,069] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,080] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:01:51,673] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,720] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:01:51,726] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:01:51,893] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:01:52,152] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:01:52,231] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,232] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:01:52,598] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,618] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,623] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:01:52,637] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:01:52,956] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,956] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:01:53,679] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:53,721] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:01:54,025] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:01:54,184] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:01:54,998] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,019] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:01:55,087] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,108] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:01:55,254] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:01:55,445] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:01:55,445] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:01:55,943] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:56,200] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:01:56,274] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:03,114] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:03:16,872] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:03:16,875] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:03:16,875] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:03:16,875] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:03:16,875] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:03:16,875] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:03:16,991] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:03:17,901] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:03:17,933] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:03:18,497] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:03:18,639] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:18,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:03:19,037] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,047] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:03:19,189] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,210] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:03:19,310] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,329] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:03:19,329] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:03:19,638] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:03:20,151] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:03:20,331] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,331] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:03:20,462] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,462] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:03:20,494] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,510] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:03:20,633] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:03:21,032] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,053] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:03:21,466] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:03:21,730] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,731] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:03:22,061] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,072] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:03:22,445] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:03:23,370] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:03:24,285] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:24,306] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:03:24,454] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:03:24,681] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:03:24,682] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:03:24,682] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,308] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,616] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,461] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 15:56:02,776] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 15:56:02,783] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 15:56:02,783] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 15:56:02,784] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 15:56:02,787] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 15:56:02,787] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 15:56:02,903] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 15:56:04,320] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,331] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 15:56:04,366] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,377] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 15:56:04,654] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,741] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 15:56:04,779] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 15:56:05,377] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,388] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 15:56:05,479] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 15:56:05,698] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 15:56:06,048] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,105] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 15:56:06,320] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 15:56:06,752] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 15:56:06,834] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,834] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 15:56:06,844] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,845] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 15:56:07,320] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,336] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 15:56:07,555] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 15:56:07,567] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,568] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 15:56:08,323] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,324] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 15:56:08,638] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 15:56:08,687] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 15:56:09,544] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 15:56:09,757] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:09,773] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 15:56:10,425] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:10,441] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 15:56:10,740] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 15:56:11,549] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:11,664] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 15:56:12,063] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:12,450] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,512] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from flask import render_template, send_from_directory, Blueprint
fe_path = os.path.join(os.getcwd(), "frontend", "dist")
fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, ""))
@fe_bp.route('/js/<path:path>')
def send_js(path):
return send_from_directory(os.path.join(fe_path, "js"), path)
@fe_bp.route('/css/<path:path>')
def send_css(path):
return send_from_directory(os.path.join(fe_path, "css"), path)
@fe_bp.route('/img/<path:path>')
def send_img(path):
return send_from_directory(os.path.join(fe_path, "img"), path)
@fe_bp.route('/', defaults={'path': ''})
@fe_bp.route('/<path:path>')
def catch_all(path):
return render_template("index.html")