Compare commits
No commits in common. "3a113c9bafc1782aba44149e43d2460f9ce12c29" and "c2ef36c5a7a31ea39f51c91c7ba76430f0aaa048" have entirely different histories.
3a113c9baf
...
c2ef36c5a7
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
||||
__pycache__
|
||||
dist/
|
||||
.venv
|
||||
|
@ -333,8 +333,6 @@ cdr_finalize=UPDATE users SET inuse=(CASE WHEN inuse>0 THEN inuse-1 ELSE 0 END)
|
||||
Just choose one of your RFPs as your OMM.
|
||||
Find out the MAC address and fill it in the according fields in the kea config before.
|
||||
|
||||
To be able to have secure sip connections between the OMM and yate, generate a 16-characters long hexadecimal sip-secret.
|
||||
|
||||
Create a privileged user account and add the credentials to `fieldpoc_config.json`:
|
||||
|
||||
```
|
||||
@ -343,7 +341,6 @@ Create a privileged user account and add the credentials to `fieldpoc_config.jso
|
||||
"host": "10.222.222.11",
|
||||
"username": "omm",
|
||||
"password": "<password>"
|
||||
"sipsecret": "<secret>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -42,7 +42,7 @@ class Config:
|
||||
return self.dect.check()
|
||||
|
||||
|
||||
class ExtensionConfig(ConfigBase):
|
||||
class ExtensionConfig:
|
||||
def __init__(self, c):
|
||||
self.num = c[0]
|
||||
self._c = c[1]
|
||||
|
@ -41,16 +41,12 @@ class Controller:
|
||||
|
||||
if data == "help":
|
||||
self.request.sendall("""Availiable commands:
|
||||
help Show this info
|
||||
handlers Show currently running handlers
|
||||
sync Start syncing
|
||||
queues Show queue stats
|
||||
reload Reload extension config file
|
||||
claim <ext> <token> claim dect extension
|
||||
exit Disconnect
|
||||
help Show this info
|
||||
handlers Show currently running handlers
|
||||
sync Start syncing
|
||||
queues Show queue stats
|
||||
exit Disconnect
|
||||
""".encode("utf-8"))
|
||||
elif data == "":
|
||||
continue
|
||||
elif data == "quit" or data == "exit":
|
||||
self.request.sendall("disconnecting\n".encode("utf-8"))
|
||||
return
|
||||
@ -60,14 +56,6 @@ exit Disconnect
|
||||
self.fp.queue_all({"type": "sync"})
|
||||
elif data == "queues":
|
||||
self.request.sendall(("\n".join(["{} {}".format(name, queue.qsize()) for name, queue in self.fp.queues.items()]) + "\n").encode("utf-8"))
|
||||
elif data == "reload":
|
||||
self.fp.reload_config()
|
||||
elif data.startswith("claim"):
|
||||
data = data.split(" ")
|
||||
if len(data) == 3:
|
||||
self.fp.queue_all({"type": "claim", "extension": data[1], "token": data[2]})
|
||||
else:
|
||||
self.request.sendall("error: You have to specify calling extension and token\n".encode("utf-8"))
|
||||
else:
|
||||
self.request.sendall("Unknown command, type 'help'\n".encode("utf-8"))
|
||||
|
||||
|
127
fieldpoc/dect.py
127
fieldpoc/dect.py
@ -3,7 +3,6 @@
|
||||
import logging
|
||||
import mitel_ommclient2
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
logger = logging.getLogger("fieldpoc.dect")
|
||||
|
||||
@ -19,46 +18,23 @@ class Dect:
|
||||
ommsync=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def temp_num_prefix(self):
|
||||
return next(self.fp.extensions.extensions_by_type("temp")).num
|
||||
|
||||
def load_temp_extensions(self):
|
||||
current_temp_extension = 0
|
||||
used_temp_extensions = self.c.find_users(lambda u: u.num.startswith(self.temp_num_prefix))
|
||||
for u in used_temp_extensions:
|
||||
temp_num = u.num
|
||||
self.fp.temp_extensions[temp_num] = {
|
||||
"name": f"Temp {temp_num[4:]}",
|
||||
"type": "dect",
|
||||
"trunk": False,
|
||||
"dialout_allowed": False,
|
||||
}
|
||||
|
||||
|
||||
def get_temp_number(self):
|
||||
temp_num_prefix = next(self.fp.extensions.extensions_by_type("temp")).num
|
||||
current_temp_extension = 0
|
||||
used_temp_extensions = [num[len(self.temp_num_prefix):] for num, ext in self.fp.temp_extensions.items()]
|
||||
used_temp_extensions = [u.num[len(temp_num_prefix):] for u in self.c.find_users(lambda u: u.num.startswith(temp_num_prefix))]
|
||||
|
||||
while "{:0>4}".format(current_temp_extension) in used_temp_extensions:
|
||||
current_temp_extension += 1
|
||||
|
||||
return "{}{:0>4}".format(self.temp_num_prefix, current_temp_extension)
|
||||
return "{}{:0>4}".format(temp_num_prefix, current_temp_extension)
|
||||
|
||||
def get_sip_password_for_number(self, num):
|
||||
return hashlib.sha256(bytes.fromhex((self.fp.config.dect.sipsecret + str(num))[-16:])).hexdigest()[:16]
|
||||
return num
|
||||
|
||||
def create_and_bind_user(self, d, num):
|
||||
u = self.c.create_user(num)
|
||||
self.c.attach_user_device(u.uid, d.ppn)
|
||||
self.c.set_user_relation_fixed(u.uid)
|
||||
self.c.set_user_sipauth(u.uid, num, self.get_sip_password_for_number(num))
|
||||
return u
|
||||
|
||||
def run(self):
|
||||
logger.info("initialising connection to OMM")
|
||||
self._init_client()
|
||||
self.load_temp_extensions()
|
||||
|
||||
while True:
|
||||
msg = self.fp.queues["dect"].get()
|
||||
@ -67,90 +43,13 @@ class Dect:
|
||||
if msg.get("type") == "stop":
|
||||
break
|
||||
elif msg.get("type") == "sync":
|
||||
logger.info("syncing")
|
||||
unbound_devices = self.c.find_devices(lambda d: d.relType == mitel_ommclient2.types.PPRelTypeType("Unbound"))
|
||||
|
||||
extensions = self.fp.extensions.extensions_by_type("dect")
|
||||
extensions_by_num = {e.num: e for e in extensions}
|
||||
extensions_by_ipei = {e._c['dect_ipei']: e for _, e in extensions_by_num.items() if e._c.get('dect_ipei')}
|
||||
created_tmp_ext = False
|
||||
|
||||
users_by_ext = {}
|
||||
users_by_uid = {}
|
||||
for user in self.c.get_users():
|
||||
e = extensions_by_num.get(user.num)
|
||||
if not e:
|
||||
# user in omm, but not as dect in nerd
|
||||
if user.num.startswith(next(self.fp.extensions.extensions_by_type("temp")).num):
|
||||
users_by_ext[user.num] = user
|
||||
users_by_uid[user.uid] = user
|
||||
else:
|
||||
pass
|
||||
# TODO: delete in omm
|
||||
continue
|
||||
elif e._c['name'] != user.name:
|
||||
self.c.set_user_name(user.uid, e._c['name'])
|
||||
if e._c.get('dect_ipei') and user.relType != mitel_ommclient2.types.PPRelTypeType("Unbound"):
|
||||
d = self.c.get_device(user.ppn)
|
||||
if d.ipei != e._c['dect_ipei']:
|
||||
logger.debug(f"Detaching {user} {d}")
|
||||
self.c.detach_user_device(user.uid, user.ppn)
|
||||
|
||||
self.c.set_user_sipauth(user.uid, e.num, self.get_sip_password_for_number(e.num))
|
||||
users_by_ext[user.num] = user
|
||||
users_by_uid[user.uid] = user
|
||||
|
||||
for d in self.c.get_devices():
|
||||
e = extensions_by_ipei.get(d.ipei)
|
||||
if e:
|
||||
# device is in nerd
|
||||
u = users_by_ext.get(e.num)
|
||||
if u and d.relType == mitel_ommclient2.types.PPRelTypeType("Unbound"):
|
||||
logger.debug(f'Binding user for {d}')
|
||||
self.c.attach_user_device(u.uid, d.ppn)
|
||||
self.c.set_user_relation_fixed(u.uid)
|
||||
elif d.relType != mitel_ommclient2.types.PPRelTypeType("Unbound"):
|
||||
ui = users_by_uid.get(d.uid)
|
||||
if ui.num != e.num:
|
||||
logger.debug(f'User for {d} has wrong number')
|
||||
if self.fp.temp_extensions.get(ui.num):
|
||||
self.fp.temp_extensions.pop(ui.num)
|
||||
self.c.set_user_num(d.uid, e.num)
|
||||
self.c.set_user_sipauth(d.uid, e.num, self.get_sip_password_for_number(e.num))
|
||||
self.c.set_user_name(user.uid, e._c['name'])
|
||||
else:
|
||||
logger.debug(f'Creating and binding user for {d}')
|
||||
user = self.create_and_bind_user(d, e.num)
|
||||
self.c.set_user_name(user.uid, e._c['name'])
|
||||
|
||||
elif d.relType == mitel_ommclient2.types.PPRelTypeType("Unbound"):
|
||||
temp_num = self.get_temp_number()
|
||||
logger.debug(f'Creating and binding tmp-user for {d}: {temp_num}')
|
||||
user = self.create_and_bind_user(d, temp_num)
|
||||
self.c.set_user_name(user.uid, f"Temp {temp_num[4:]}")
|
||||
self.fp.temp_extensions[temp_num] = {
|
||||
"name": f"Temp {temp_num[4:]}",
|
||||
"type": "dect",
|
||||
"trunk": False,
|
||||
"dialout_allowed": False,
|
||||
}
|
||||
created_tmp_ext = True
|
||||
|
||||
if created_tmp_ext:
|
||||
self.fp.queues['routing'].put({"type": "sync"})
|
||||
|
||||
elif msg.get("type") == "claim":
|
||||
e = None
|
||||
for ext in self.fp.extensions.extensions_by_type("dect"):
|
||||
if ext._c.get('dect_claim_token') and ext._c['dect_claim_token'] == msg.get("token")[4:]:
|
||||
e = ext
|
||||
break
|
||||
|
||||
if e:
|
||||
user = next(self.c.find_users(lambda u: u.num == msg.get("extension")))
|
||||
if self.fp.temp_extensions.get(user.num):
|
||||
self.fp.temp_extensions.pop(user.num)
|
||||
self.c.set_user_num(user.uid, e.num)
|
||||
self.c.set_user_sipauth(user.uid, e.num, self.get_sip_password_for_number(e.num))
|
||||
self.c.set_user_name(user.uid, e._c['name'])
|
||||
|
||||
self.c.connection.close()
|
||||
for d in unbound_devices:
|
||||
print(d)
|
||||
temp_num = self.get_temp_number()
|
||||
u = self.c.create_user(temp_num)
|
||||
print(u)
|
||||
self.c.attach_user_device(u.uid, d.ppn)
|
||||
self.c.set_user_relation_fixed(u.uid)
|
||||
self.c.set_user_sipauth(u.uid, temp_num, self.get_sip_password_for_number(temp_num))
|
||||
|
@ -17,7 +17,6 @@ logger = logging.getLogger("fieldpoc.fieldpoc")
|
||||
class FieldPOC:
|
||||
config = None
|
||||
extensions = None
|
||||
temp_extensions = {}
|
||||
|
||||
def __init__(self, config_file_path, extensions_file_path):
|
||||
logger.info("loading configuration")
|
||||
@ -76,10 +75,6 @@ class FieldPOC:
|
||||
|
||||
logger.info("started components")
|
||||
|
||||
def reload_config(self):
|
||||
self._load_extensions()
|
||||
self.queue_all({"type": "sync"})
|
||||
|
||||
def _load_config(self):
|
||||
self.config = config.Config(json.loads(self.config_file_path.read_text()))
|
||||
|
||||
|
@ -27,12 +27,11 @@ class YwsdYateModel(YateModel):
|
||||
@classmethod
|
||||
def create(cls, diffsync, ids, attrs):
|
||||
with diffsync.engine.connect() as conn:
|
||||
result = conn.execute(
|
||||
conn.execute(
|
||||
Yate.table.insert().values(
|
||||
guru3_identifier=ids["guru3_identifier"], **attrs
|
||||
)
|
||||
)
|
||||
attrs["yate_id"] = result.inserted_primary_key[0]
|
||||
return super().create(diffsync, ids=ids, attrs=attrs)
|
||||
|
||||
def update(self, attrs):
|
||||
@ -85,7 +84,7 @@ class YwsdExtensionModel(ExtensionModel):
|
||||
@classmethod
|
||||
def create(cls, diffsync, ids, attrs):
|
||||
with diffsync.engine.connect() as conn:
|
||||
result = conn.execute(
|
||||
conn.execute(
|
||||
Extension.table.insert().values(
|
||||
extension=ids["extension"],
|
||||
type=attrs["extension_type"],
|
||||
@ -99,7 +98,6 @@ class YwsdExtensionModel(ExtensionModel):
|
||||
),
|
||||
)
|
||||
)
|
||||
attrs["extension_id"] = result.inserted_primary_key[0]
|
||||
return super().create(diffsync, ids=ids, attrs=attrs)
|
||||
|
||||
def update(self, attrs):
|
||||
@ -212,7 +210,7 @@ class YwsdForkRankModel(ForkRankModel):
|
||||
@classmethod
|
||||
def create(cls, diffsync, ids, attrs):
|
||||
with diffsync.engine.connect() as conn:
|
||||
result = conn.execute(
|
||||
conn.execute(
|
||||
ForkRank.table.insert().values(
|
||||
extension_id=diffsync.get(
|
||||
"extension", ids["extension"]
|
||||
@ -221,7 +219,6 @@ class YwsdForkRankModel(ForkRankModel):
|
||||
**attrs,
|
||||
)
|
||||
)
|
||||
attrs["forkrank_id"] = result.inserted_primary_key[0]
|
||||
return super().create(diffsync, ids=ids, attrs=attrs)
|
||||
|
||||
def update(self, attrs):
|
||||
@ -278,7 +275,7 @@ class YwsdForkRankMemberModel(ForkRankMemberModel):
|
||||
conn.execute(
|
||||
ForkRank.member_table.update()
|
||||
.where(
|
||||
sqlalchemy.and_(
|
||||
_and(
|
||||
ForkRank.member_table.c.forkrank_id
|
||||
== self.diffsync.get("forkrank", self.forkrank).forkrank_id,
|
||||
ForkRank.member_table.c.extension_id
|
||||
@ -293,7 +290,7 @@ class YwsdForkRankMemberModel(ForkRankMemberModel):
|
||||
with self.diffsync.engine.connect() as conn:
|
||||
conn.execute(
|
||||
ForkRank.member_table.delete().where(
|
||||
sqlalchemy.and_(
|
||||
_and(
|
||||
ForkRank.member_table.c.forkrank_id
|
||||
== self.diffsync.get("forkrank", self.forkrank).forkrank_id,
|
||||
ForkRank.member_table.c.extension_id
|
||||
@ -313,15 +310,11 @@ class BackendNerd(diffsync.DiffSync):
|
||||
|
||||
top_level = ["yate", "extension", "user", "forkrank", "forkrankmember"]
|
||||
|
||||
def __init__(self, fp, *args, **kwargs):
|
||||
self.fp = fp
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def load(self, data):
|
||||
#yate_dect = self.yate(
|
||||
# guru3_identifier="dect", hostname="dect", voip_listener="local"
|
||||
#)
|
||||
#self.add(yate_dect)
|
||||
yate_dect = self.yate(
|
||||
guru3_identifier="dect", hostname="dect", voip_listener="local"
|
||||
)
|
||||
self.add(yate_dect)
|
||||
yate_sip = self.yate(
|
||||
guru3_identifier="sip", hostname="sip", voip_listener="local"
|
||||
)
|
||||
@ -346,8 +339,6 @@ class BackendNerd(diffsync.DiffSync):
|
||||
active=True,
|
||||
)
|
||||
self.add(frm)
|
||||
elif value["type"] in ["temp"]:
|
||||
continue
|
||||
|
||||
extension = self.extension(
|
||||
extension=key,
|
||||
@ -370,7 +361,7 @@ class BackendNerd(diffsync.DiffSync):
|
||||
user = self.user(
|
||||
username=key,
|
||||
displayname=value["name"],
|
||||
password=value.get("sip_password", self.fp._dect.get_sip_password_for_number(key)),
|
||||
password=value.get("sip_password", key),
|
||||
user_type=user_type[value["type"]],
|
||||
trunk=value["trunk"],
|
||||
static_target=value.get("static_target", ""),
|
||||
@ -482,8 +473,8 @@ class Routing:
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
msg = self.fp.queues["routing"].get()
|
||||
self.fp.queues["routing"].task_done()
|
||||
msg = self.fp.queues["dect"].get()
|
||||
self.fp.queues["dect"].task_done()
|
||||
|
||||
if msg.get("type") == "stop":
|
||||
break
|
||||
@ -491,10 +482,8 @@ class Routing:
|
||||
|
||||
logger.info("syncing")
|
||||
|
||||
state_fieldpoc = BackendNerd(self.fp)
|
||||
extensions = self.fp.extensions._c.copy()
|
||||
extensions['extensions'].update(self.fp.temp_extensions)
|
||||
state_fieldpoc.load(extensions)
|
||||
state_fieldpoc = BackendNerd()
|
||||
state_fieldpoc.load(self.fp.extensions._c)
|
||||
state_yate = BackendYwsd()
|
||||
state_yate.load("postgresql+psycopg2://{}:{}@{}/{}".format(
|
||||
self.fp.config.database.username,
|
||||
|
@ -7,7 +7,6 @@
|
||||
"host": "10.222.222.11",
|
||||
"username": "omm",
|
||||
"password": "xxx"
|
||||
"sipsecret": "51df84aace052b0e75b8c1da5a6da9e2"
|
||||
},
|
||||
"yate": {
|
||||
"host": "127.0.0.1",
|
||||
|
@ -95,14 +95,14 @@
|
||||
"name": "Temporary Numbers",
|
||||
"trunk": false,
|
||||
"dialout_allowed": true,
|
||||
"type": "temp"
|
||||
"type": "static"
|
||||
},
|
||||
"9997": {
|
||||
"9999": {
|
||||
"name": "DECT Claim Extensions",
|
||||
"type": "static",
|
||||
"dialout_allowed": false,
|
||||
"trunk": true,
|
||||
"static_target": "external/nodata//run/current-system/sw/bin/dect_claim"
|
||||
"static_target": "external/nodata//opt/nerdsync/claim.py"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user