feat(voicemail): implement new voicemail notification callback and enhance call history retrieval with search and pagination support
This commit is contained in:
@@ -372,6 +372,7 @@ class ReticulumMeshChat:
|
||||
self.voicemail_manager.get_name_for_identity_hash = (
|
||||
self.get_name_for_identity_hash
|
||||
)
|
||||
self.voicemail_manager.on_new_voicemail_callback = self.on_new_voicemail_received
|
||||
|
||||
# init Ringtone Manager
|
||||
self.ringtone_manager = RingtoneManager(
|
||||
@@ -1335,8 +1336,39 @@ class ReticulumMeshChat:
|
||||
value = value.lower()
|
||||
return value in {"1", "true", "yes", "on"}
|
||||
|
||||
def on_new_voicemail_received(self, remote_hash, remote_name, duration):
|
||||
AsyncUtils.run_async(
|
||||
self.websocket_broadcast(
|
||||
json.dumps(
|
||||
{
|
||||
"type": "new_voicemail",
|
||||
"remote_identity_hash": remote_hash,
|
||||
"remote_identity_name": remote_name,
|
||||
"duration": duration,
|
||||
"timestamp": time.time(),
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# handle receiving a new audio call
|
||||
def on_incoming_telephone_call(self, caller_identity: RNS.Identity):
|
||||
caller_hash = caller_identity.hash.hex()
|
||||
|
||||
# Check if caller is blocked
|
||||
if self.is_destination_blocked(caller_hash):
|
||||
print(f"Rejecting incoming call from blocked source: {caller_hash}")
|
||||
if self.telephone_manager.telephone:
|
||||
self.telephone_manager.telephone.hangup()
|
||||
return
|
||||
|
||||
# Check for Do Not Disturb
|
||||
if self.config.do_not_disturb_enabled.get():
|
||||
print(f"Rejecting incoming call due to Do Not Disturb: {caller_hash}")
|
||||
if self.telephone_manager.telephone:
|
||||
self.telephone_manager.telephone.hangup()
|
||||
return
|
||||
|
||||
# Trigger voicemail handling
|
||||
self.voicemail_manager.handle_incoming_call(caller_identity)
|
||||
|
||||
@@ -1403,6 +1435,21 @@ class ReticulumMeshChat:
|
||||
timestamp=time.time(),
|
||||
)
|
||||
|
||||
# Trigger missed call notification if it was an incoming call that ended while ringing
|
||||
if is_incoming and status_code == 4:
|
||||
AsyncUtils.run_async(
|
||||
self.websocket_broadcast(
|
||||
json.dumps(
|
||||
{
|
||||
"type": "telephone_missed_call",
|
||||
"remote_identity_hash": remote_identity_hash,
|
||||
"remote_identity_name": remote_identity_name,
|
||||
"timestamp": time.time(),
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
AsyncUtils.run_async(
|
||||
self.websocket_broadcast(
|
||||
json.dumps(
|
||||
@@ -3139,7 +3186,13 @@ class ReticulumMeshChat:
|
||||
@routes.get("/api/v1/telephone/history")
|
||||
async def telephone_history(request):
|
||||
limit = int(request.query.get("limit", 10))
|
||||
history = self.database.telephone.get_call_history(limit=limit)
|
||||
offset = int(request.query.get("offset", 0))
|
||||
search = request.query.get("search", None)
|
||||
history = self.database.telephone.get_call_history(
|
||||
search=search,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
|
||||
call_history = []
|
||||
for row in history:
|
||||
|
||||
@@ -135,6 +135,9 @@ class ConfigManager:
|
||||
self.custom_ringtone_enabled = self.BoolConfig(self, "custom_ringtone_enabled", False)
|
||||
self.ringtone_filename = self.StringConfig(self, "ringtone_filename", None)
|
||||
|
||||
# telephony config
|
||||
self.do_not_disturb_enabled = self.BoolConfig(self, "do_not_disturb_enabled", False)
|
||||
|
||||
# map config
|
||||
self.map_offline_enabled = self.BoolConfig(self, "map_offline_enabled", False)
|
||||
self.map_offline_path = self.StringConfig(self, "map_offline_path", None)
|
||||
|
||||
@@ -2,7 +2,7 @@ from .provider import DatabaseProvider
|
||||
|
||||
|
||||
class DatabaseSchema:
|
||||
LATEST_VERSION = 18
|
||||
LATEST_VERSION = 19
|
||||
|
||||
def __init__(self, provider: DatabaseProvider):
|
||||
self.provider = provider
|
||||
@@ -551,6 +551,11 @@ class DatabaseSchema:
|
||||
"CREATE INDEX IF NOT EXISTS idx_contacts_remote_identity_hash ON contacts(remote_identity_hash)",
|
||||
)
|
||||
|
||||
if current_version < 19:
|
||||
self.provider.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_call_history_remote_name ON call_history(remote_identity_name)",
|
||||
)
|
||||
|
||||
# Update version in config
|
||||
self.provider.execute(
|
||||
"""
|
||||
|
||||
@@ -40,10 +40,19 @@ class TelephoneDAO:
|
||||
),
|
||||
)
|
||||
|
||||
def get_call_history(self, limit=10):
|
||||
def get_call_history(self, search=None, limit=10, offset=0):
|
||||
if search:
|
||||
return self.provider.fetchall(
|
||||
"""
|
||||
SELECT * FROM call_history
|
||||
WHERE remote_identity_name LIKE ? OR remote_identity_hash LIKE ?
|
||||
ORDER BY timestamp DESC LIMIT ? OFFSET ?
|
||||
""",
|
||||
(f"%{search}%", f"%{search}%", limit, offset),
|
||||
)
|
||||
return self.provider.fetchall(
|
||||
"SELECT * FROM call_history ORDER BY timestamp DESC LIMIT ?",
|
||||
(limit,),
|
||||
"SELECT * FROM call_history ORDER BY timestamp DESC LIMIT ? OFFSET ?",
|
||||
(limit, offset),
|
||||
)
|
||||
|
||||
def clear_call_history(self):
|
||||
|
||||
@@ -34,6 +34,8 @@ class VoicemailManager:
|
||||
self.recording_remote_identity = None
|
||||
self.recording_filename = None
|
||||
|
||||
self.on_new_voicemail_callback = None
|
||||
|
||||
# Paths to executables
|
||||
self.espeak_path = self._find_espeak()
|
||||
self.ffmpeg_path = self._find_ffmpeg()
|
||||
@@ -377,6 +379,13 @@ class VoicemailManager:
|
||||
f"Saved voicemail from {RNS.prettyhexrep(self.recording_remote_identity.hash)} ({duration}s)",
|
||||
RNS.LOG_DEBUG,
|
||||
)
|
||||
|
||||
if self.on_new_voicemail_callback:
|
||||
self.on_new_voicemail_callback(
|
||||
self.recording_remote_identity.hash.hex(),
|
||||
remote_name,
|
||||
duration,
|
||||
)
|
||||
else:
|
||||
# Delete short/empty recording
|
||||
filepath = os.path.join(self.recordings_dir, self.recording_filename)
|
||||
|
||||
Reference in New Issue
Block a user