add api endpoint to fetch call info

This commit is contained in:
liamcottle
2024-05-21 02:42:03 +12:00
parent c7a1549299
commit 85a6093668
3 changed files with 113 additions and 21 deletions

View File

@@ -21,7 +21,7 @@
<body class="bg-gray-100">
<div id="app" class="flex h-full">
<div class="mx-auto my-auto w-full max-w-lg p-4">
<div class="mx-auto my-auto w-full max-w-xl p-4">
<!-- in active call -->
<div v-if="isWebsocketConnected" class="w-full">
@@ -38,7 +38,25 @@
<div class="mb-2">
<div class="mb-1 text-sm font-medium text-gray-900">Call Hash</div>
<div class="text-xs text-gray-600">{{ callHash }}</div>
<div class="text-xs text-gray-600">{{ audioCall?.hash || "Unknown" }}</div>
</div>
<div class="mb-2">
<div class="mb-1 text-sm font-medium text-gray-900">Remote Identity Hash</div>
<div class="text-xs text-gray-600">{{ audioCall?.remote_identity_hash || "Unknown" }}</div>
</div>
<div class="mb-2">
<div class="mb-1 text-sm font-medium text-gray-900">Remote Destination Hash</div>
<div class="text-xs text-gray-600">{{ audioCall?.remote_destination_hash || "Unknown" }}</div>
</div>
<div class="mb-2">
<div class="mb-1 text-sm font-medium text-gray-900">Path</div>
<div class="text-xs text-gray-600">
<span v-if="audioCall?.path">{{ audioCall.path.hops }} {{ audioCall.path.hops === 1 ? 'hop' : 'hops' }} away via {{ audioCall.path.next_hop_interface }}</span>
<span v-else>Unknown</span>
</div>
</div>
<div class="mb-2">
@@ -118,11 +136,12 @@
</div>
<div class="my-auto">Active Calls</div>
</div>
<div>
<div class="divide-y">
<div v-for="audioCall in activeAudioCalls" class="flex p-2">
<div>
<div>Call Hash: {{ audioCall.hash }}</div>
<div v-if="!audioCall.is_outbound">Initiator Identity: {{ audioCall.initiator_identity_hash || "Unknown" }}</div>
<div>Identity: {{ audioCall.remote_identity_hash || "Unknown" }}</div>
<div>Destination: {{ audioCall.remote_destination_hash || "Unknown" }}</div>
<div>
<span v-if="audioCall.is_outbound">Direction: Outbound</span>
<span v-else>Direction: Inbound</span>
@@ -159,11 +178,12 @@
</div>
<div class="my-auto">Call History</div>
</div>
<div>
<div class="divide-y">
<div v-for="audioCall in inactiveAudioCalls" class="flex p-2">
<div>
<div>Call Hash: {{ audioCall.hash }}</div>
<div v-if="!audioCall.is_outbound">Initiator Identity: {{ audioCall.initiator_identity_hash || "Unknown" }}</div>
<div>Identity: {{ audioCall.remote_identity_hash || "Unknown" }}</div>
<div>Destination: {{ audioCall.remote_destination_hash || "Unknown" }}</div>
<div>
<span v-if="audioCall.is_outbound">Direction: Outbound</span>
<span v-else>Direction: Inbound</span>
@@ -201,6 +221,7 @@
data() {
return {
audioCall: null,
audioCalls: [],
myAudioCallAddressHash: null,
@@ -313,6 +334,8 @@
// we are now connected
this.isWebsocketConnected = true;
await this.updateCall(callHash);
// send mic audio over call
await this.startRecordingMicrophone((encoded) => {
@@ -543,6 +566,24 @@
// do nothing on error
}
},
async updateCall(callHash) {
// clear previous call
this.audioCall = null;
try {
// get path to destination
const response = await window.axios.get(`/api/v1/calls/${callHash}`);
// update ui
this.audioCall = response.data.audio_call;
} catch(e) {
console.log(e);
}
},
},
computed: {
activeAudioCalls: function() {

View File

@@ -56,8 +56,8 @@ class AudioCall:
# send codec2 audio received from call receiver to call initiator over reticulum link
RNS.Packet(self.link, data).send()
# gets the identity of the caller, or returns None if they did not identify
def initiator_identity(self):
# gets the identity of the other person, or returns None if they did not identify
def get_remote_identity(self):
return self.link.get_remote_identity()
# determine if this call is still active

77
web.py
View File

@@ -254,24 +254,33 @@ class ReticulumWebChat:
# get audio calls
audio_calls = []
for audio_call in self.audio_call_manager.audio_calls:
# get initiator identity hash
initiator_identity_hash = None
initiator_identity = audio_call.initiator_identity()
if initiator_identity is not None:
initiator_identity_hash = initiator_identity.hash.hex()
audio_calls.append({
"hash": audio_call.link.hash.hex(),
"initiator_identity_hash": initiator_identity_hash,
"is_active": audio_call.is_active(),
"is_outbound": audio_call.is_outbound,
})
audio_calls.append(self.convert_audio_call_to_dict(audio_call))
return web.json_response({
"audio_calls": audio_calls,
})
# get calls
@routes.get("/api/v1/calls/{audio_call_link_hash}")
async def index(request):
# get path params
audio_call_link_hash = request.match_info.get("audio_call_link_hash", "")
# convert hash to bytes
audio_call_link_hash = bytes.fromhex(audio_call_link_hash)
# find audio call
audio_call = self.audio_call_manager.find_audio_call_by_link_hash(audio_call_link_hash)
if audio_call is None:
return web.json_response({
"message": "audio call not found",
}, status=404)
return web.json_response({
"audio_call": self.convert_audio_call_to_dict(audio_call),
})
# initiate a call to the provided destination
@routes.get("/api/v1/calls/initiate/{destination_hash}")
async def index(request):
@@ -782,6 +791,48 @@ class ReticulumWebChat:
"audio_call_address_hash": self.audio_call_manager.audio_call_receiver.destination.hexhash,
}
# convert audio call to dict
def convert_audio_call_to_dict(self, audio_call: AudioCall):
# get remote identity hash
remote_identity_hash = None
remote_identity = audio_call.get_remote_identity()
if remote_identity is not None:
remote_identity_hash = remote_identity.hash.hex()
# get remote destination hash
# we need to know the remote identity to determine their destination hash
remote_destination_hash = None
if remote_identity is not None:
remote_destination_hash = RNS.Destination.hash(remote_identity, "call", "audio")
# determine path to remote destination
path = None
if remote_destination_hash is not None:
# determine next hop and hop count
hops = RNS.Transport.hops_to(remote_destination_hash)
next_hop_bytes = self.reticulum.get_next_hop(remote_destination_hash)
# ensure next hop provided
if next_hop_bytes is not None:
next_hop = next_hop_bytes.hex()
next_hop_interface = self.reticulum.get_next_hop_if_name(remote_destination_hash)
path = {
"hops": hops,
"next_hop": next_hop,
"next_hop_interface": next_hop_interface,
}
return {
"hash": audio_call.link.hash.hex(),
"remote_destination_hash": remote_destination_hash.hex(),
"remote_identity_hash": remote_identity_hash,
"is_active": audio_call.is_active(),
"is_outbound": audio_call.is_outbound,
"path": path,
}
# convert app data to string, or return none unable to do so
def convert_app_data_to_string(self, app_data):