-
Notifications
You must be signed in to change notification settings - Fork 31
MainPage
The MainPage contains both the conversation list and the selected conversation. It requires that the database contains valid signal authentication credentials, and handles the receiving and sending of messages. This document describes the MainPage, MainPageViewModel, ThreadView and ThreadViewModel.
The pipe is our primary communication channel with the libsignal-service-dotnet library. It is used to send and receive messages.
The ActionInProgress lock primarily guards the order and integrity of UI operations. It shall be held whenever the UI task was invoked update the UI in a transactional way. Since we can await
the lock operation, the UI task may pile up several waiting calls. Note: We might replace the AsyncLock with a SemaphoreSlim, if required.
The OutgoingQueue is the input queue of the OutgoingMessages task. The UI task deposits SignalMessages, the OutgoingMessages task sends them, and invokes the UI task if the MessageBox needs to be updated.
The SelectedThread is the conversation which was opened. It can be changed by selecting a new conversation, or by hitting the back button in the narrow state.
The OutgoingCache is a cache for outgoing messages which have not been confirmed as sent or delivered. It is used by the IncomingMessages and OutgoingMessages tasks, since these need to acquire a reference to a MessageBox to update it. Note: We have to assess whether the locking assumptions hold true for the OutgoingCache. If not, we need more locking in our UI invocations.
The UI task naturally executes every UI event handler in case of events. It is also invoked by the IncomingMessagesTask and OutgoingMessagesTask: The former in case of a received, decrypted and parsed envelope, the latter in case of a successful or unsuccessful send operation. It holds the ActionInProgress lock when changing the UI in a way that could bother other invocations.
When the user sends a message, the UI task composes a new SignalMessage and acquires the ActionInProgress lock. Then it displays the message, saves it, adds it to the OutgoingCache, appends it to the OutgoingQueue
and releases the lock. Note: Locking is neccessary here: We must ensure that no incoming message is saved and displayed, because any save operation could win the race.
When the UI goes into the narrow state and SelectedThread is not null, it transitions into the narrow style, displays the conversation and enables the back button.
When the UI goes into the wide state, it transitions into the wide style and disables the back button.
When the back button is pressed, it acquires the lock, deselects and disposes the conversation, "switches" to narrow state again. Note: The lock might not be neccessary and be removed soon. It also could pose problems since multiple back button handler calls can stack up if the lock is contended.
When a new conversation is selected, it acquires the lock, disposes the previous conversation, loads the new one, clears the OutgoingCache, and releases the lock. Note: The lock might not be neccessary and be removed soon. All update invocations don't await anything, and thus cannot be bothered by a conversation change. We should definitely implement something that prevents multiple conversation selection handlers from piling up.
The IncomingMessages task reads SignalServiceEnvelope from the pipe. In case of an incoming receipt, we transactionally increase the receipt count, and invoke UIUpdateMessageBox
to update the corresponding MessageBox if neccessary. Note: We do not hold the ActionInProgress lock, because UIUpdateMessageBox
does not await
anything and thus cannot be bothered by other UI task invocations.
In case of an incoming message, we prepare the SignalMessage and invoke UIHandleIncomingMessage
, which grabs the ActionInProgress lock, saves the message to the database, displays it if neccessary, adds it to the OutgoingCache if neccessary, and releases the lock. Note: Locking is neccessary here: We must ensure that no outgoing message is saved and displayed, because any save operation could win the race.
The OutgoingMessages task reads composed SignalMessages from its queue. If a send operation is successful, it transactionally updates the message's status in the database and invokes UIUpdateMessageBox
. Note: We do not hold the ActionInProgress lock, because UIUpdateMessageBox
does not await
anything and thus cannot be bothered by other UI task invocations.
TODO
TODO