allow selecting delivery method before sending messages

This commit is contained in:
liamcottle 2024-11-04 18:37:41 +13:00
commit 018075eb12
3 changed files with 117 additions and 13 deletions

View file

@ -1254,6 +1254,11 @@ class ReticulumMeshChat:
# get request body as json
data = await request.json()
# get delivery method
delivery_method = None
if "delivery_method" in data:
delivery_method = data["delivery_method"]
# get data from json
destination_hash = data["lxmf_message"]["destination_hash"]
content = data["lxmf_message"]["content"]
@ -1295,7 +1300,8 @@ class ReticulumMeshChat:
content=content,
image_field=image_field,
audio_field=audio_field,
file_attachments_field=file_attachments_field
file_attachments_field=file_attachments_field,
delivery_method=delivery_method
)
return web.json_response({
@ -2143,7 +2149,8 @@ class ReticulumMeshChat:
async def send_message(self, destination_hash: str, content: str,
image_field: LxmfImageField = None,
audio_field: LxmfAudioField = None,
file_attachments_field: LxmfFileAttachmentsField = None) -> LXMF.LXMessage:
file_attachments_field: LxmfFileAttachmentsField = None,
delivery_method: str = None) -> LXMF.LXMessage:
# convert destination hash to bytes
destination_hash = bytes.fromhex(destination_hash)
@ -2171,14 +2178,27 @@ class ReticulumMeshChat:
# create destination for recipients lxmf delivery address
lxmf_destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "lxmf", "delivery")
# send messages over a direct link by default
desired_delivery_method = LXMF.LXMessage.DIRECT
if not self.message_router.delivery_link_available(destination_hash) and RNS.Identity.current_ratchet_id(destination_hash) != None:
# since there's no link established to the destination, it's faster to send opportunistically
# this is because it takes several packets to establish a link, and then we still have to send the message over it
# oppotunistic mode will send the message in a single packet (if the message is small enough, otherwise it falls back to a direct link)
# we will only do this if an encryption ratchet is available, so single packet delivery is more secure
# determine how the user wants to send the message
desired_delivery_method = None
if delivery_method == "direct":
desired_delivery_method = LXMF.LXMessage.DIRECT
elif delivery_method == "opportunistic":
desired_delivery_method = LXMF.LXMessage.OPPORTUNISTIC
elif delivery_method == "propagated":
desired_delivery_method = LXMF.LXMessage.PROPAGATED
# determine how to send the message if the user didn't provide a method
if desired_delivery_method is None:
# send messages over a direct link by default
desired_delivery_method = LXMF.LXMessage.DIRECT
if not self.message_router.delivery_link_available(destination_hash) and RNS.Identity.current_ratchet_id(destination_hash) != None:
# since there's no link established to the destination, it's faster to send opportunistically
# this is because it takes several packets to establish a link, and then we still have to send the message over it
# oppotunistic mode will send the message in a single packet (if the message is small enough, otherwise it falls back to a direct link)
# we will only do this if an encryption ratchet is available, so single packet delivery is more secure
desired_delivery_method = LXMF.LXMessage.OPPORTUNISTIC
# create lxmf message
lxmf_message = LXMF.LXMessage(lxmf_destination, self.local_lxmf_destination, content, desired_method=desired_delivery_method)

View file

@ -332,10 +332,14 @@
</div>
<!-- send message -->
<button @click="sendMessage" :disabled="!canSendMessage" type="button" class="ml-auto my-auto inline-flex items-center gap-x-1 rounded-md px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" :class="[ canSendMessage ? 'bg-blue-500 hover:bg-blue-400 focus-visible:outline-blue-500' : 'bg-gray-400 focus-visible:outline-gray-500 cursor-not-allowed']">
<span v-if="isSendingMessage">Sending...</span>
<span v-else>Send</span>
</button>
<div class="ml-auto my-auto">
<SendMessageButton
@send="sendMessage"
@delivery-method-changed="this.newMessageDeliveryMethod = $event"
:is-sending-message="isSendingMessage"
:can-send-message="canSendMessage"
:delivery-method="newMessageDeliveryMethod"/>
</div>
</div>
@ -371,10 +375,12 @@ import NotificationUtils from "../../js/NotificationUtils";
import WebSocketConnection from "../../js/WebSocketConnection";
import AddAudioButton from "./AddAudioButton.vue";
import moment from "moment";
import SendMessageButton from "./SendMessageButton.vue";
export default {
name: 'ConversationViewer',
components: {
SendMessageButton,
AddAudioButton,
},
props: {
@ -394,6 +400,7 @@ export default {
isLoadingPrevious: false,
hasMorePrevious: true,
newMessageDeliveryMethod: null,
newMessageText: "",
newMessageImage: null,
newMessageImageUrl: null,
@ -1022,6 +1029,7 @@ export default {
// send message to reticulum
const response = await window.axios.post(`/api/v1/lxmf-messages/send`, {
"delivery_method": this.newMessageDeliveryMethod,
"lxmf_message": {
"destination_hash": this.selectedPeer.destination_hash,
"content": this.newMessageText,

View file

@ -0,0 +1,76 @@
<template>
<div class="inline-flex rounded-md shadow-sm">
<!-- send button -->
<button @click="send" :disabled="!canSendMessage" type="button" class="my-auto inline-flex items-center rounded-l-md px-2.5 py-1.5 text-sm font-semibold text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" :class="[ canSendMessage ? 'bg-blue-500 hover:bg-blue-400 focus-visible:outline-blue-500' : 'bg-gray-400 focus-visible:outline-gray-500 cursor-not-allowed']">
<span v-if="isSendingMessage">Sending...</span>
<span v-else>
<span>Send</span>
<span v-if="deliveryMethod === 'direct'"> (Direct Link)</span>
<span v-if="deliveryMethod === 'opportunistic'"> (Opportunistic)</span>
<span v-if="deliveryMethod === 'propagated'"> (Propagated)</span>
</span>
</button>
<div class="relative">
<!-- dropdown button -->
<button @click="showMenu" :disabled="!canSendMessage" type="button" class="my-auto border-l relative inline-flex items-center rounded-r-md bg-gray-500 focus-visible:outline-gray-400 px-2 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" :class="[ canSendMessage ? 'bg-blue-500 hover:bg-blue-400 focus-visible:outline-blue-500' : 'bg-gray-400 focus-visible:outline-gray-500 cursor-not-allowed']">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
</svg>
</button>
<!-- dropdown menu -->
<Transition
enter-active-class="transition ease-out duration-100"
enter-from-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95">
<div v-if="isShowingMenu" v-click-outside="hideMenu" class="absolute bottom-0 -ml-11 right-0 ml-0 z-10 mb-10 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<div class="py-1">
<button @click="setDeliveryMethod(null)" type="button" class="w-full block text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 whitespace-nowrap border-b">Send Automatically</button>
<button @click="setDeliveryMethod('direct')" type="button" class="w-full block text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 whitespace-nowrap">Send over Direct Link</button>
<button @click="setDeliveryMethod('opportunistic')" type="button" class="w-full block text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 whitespace-nowrap">Send Opportunistically</button>
<button @click="setDeliveryMethod('propagated')" type="button" class="w-full block text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 whitespace-nowrap">Send to Propagation Node</button>
</div>
</div>
</Transition>
</div>
</div>
</template>
<script>
export default {
name: 'SendMessageButton',
props: {
deliveryMethod: String,
canSendMessage: Boolean,
isSendingMessage: Boolean,
},
data() {
return {
isShowingMenu: false,
};
},
methods: {
showMenu() {
this.isShowingMenu = true;
},
hideMenu() {
this.isShowingMenu = false;
},
setDeliveryMethod(deliveryMethod) {
this.$emit("delivery-method-changed", deliveryMethod);
this.hideMenu();
},
send() {
this.$emit("send");
},
},
}
</script>