Skip to content

MainPage

Trolldemorted edited this page Jul 25, 2017 · 2 revisions

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.

Code Documentation

Important Structures

SignalServiceMessagePipe Pipe

The pipe is our primary communication channel with the libsignal-service-dotnet library. It is used to send and receive messages.

AsyncLock ActionInProgress

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.

BlockingCollection<SignalMessage> OutgoingQueue

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.

SignalThread SelectedThread

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.

Dictionary<ulong, MessageBox> OutgoingCache

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.

Tasks

UI

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.

IncomingMessages

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.

OutgoingMessages

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.

Initialization

TODO

Shutdown

TODO