Signal for Windows: Multiple Views and Background Task Blues
Signal is an encrypted messaging app. It's like Facebook Messenger or WhatsApp but by default your messages are secret between you and the person you're talking to. Yes, Facebook can read your messages, but probably doesn't. Signal (the app) uses the Signal protocol to provide encrypted communication. The Signal protocol has been built into WhatsApp, Facebook Messenger, Google Allo, and will soon be built into Skype as well. All of the encrypted messaging modes for those apps are optional, meaning your conversations are not encrypted by default. Some also worry about the fact that those apps are closed source, meaning you have to trust that the company really can't read your encrypted messages. Open Whisper Systems (the people that make Signal) trust them so there's really no reason not to just use encrypted messaging in your favorite messaging app.
So what's the point of Signal for Windows? I wanted Signal on my phone (a Windows phone) so I decided to work on porting the app over. Please note that I am not a crypto expert, a security expert, or even a regular expert but I wanted to try and move things over still. The app is broken up into various parts, the curve25519 implementation, the Signal protocol, the part that talks to the Signal servers (the service), and the app itself (the UI). A lot of work had been done to move the first three parts over to C# but they were out of date and the app was still very alpha, and didn't work. So in the end of 2016 I updated the first three libraries to be in sync with the main Signal repos. It was mainly a line by line port from Java to C#. Over the course of 2017 the app has slowly been built by me and a few other people. Right now you can only send and receive messages but the app does work fairly well.
So this month and partially in November I started working on getting notifications working. Right now you have to open the app every once in a while to check if you got new messages. Since our app is unofficial we don't have push notification support from Signal so there are only a few ways to get notifications working.
1. Ask Signal for Windows Push Notification Services (WNS) support.
2. Setup our own server and then use that to deliver push notifications.
3. Have the app periodically check for new messages using a background task.
Setting up option 2 would have been more difficult (and costly) so I decided to implement a background task that would start up every 15 minutes, check for new messages, and send you a notification if you got new messages.
This is easier said than done however because the UI code was pretty interwoven with the code that talks to Signal. This meant I would need to rewrite portions of the app to get the background task working. So in November I did but getting code to work is never that simple.
We also wanted to support multiple views (or windows). This would allow you to talk to multiple people at once without switching between conversations. This also required the same code change to get notifications working. So the person working on the multi view support also did a refactor. Our refactors were largely the same but they handled how the UI was notified of messages differently. I tried to use events, this worked fairly well but there are a couple of issues with events.
If you aren't familiar with events they are C#'s built in form of the observer pattern. The problem with the observer pattern is that the observer cannot send feedback to the source. We need the UI to notify the handle (the thing that talks to Signal) if the message that was just received for a conversation is active on the UI. So if you are not looking at a specific conversation and you get a message for it you could get a notification for that message. The other problem with events is that they don't run in parallel, they run one at a time, which would cause a UI freeze if there were many app windows open. You can get events to run in parallel but getting that to work would have been more trouble than it was worth so we moved forward with the other approach, which is to have each part that needs Signal message updates implement an interface. When a message comes in the handle makes a call to each window with the message. The handle can then asynchronously wait for any responses from each window and then act accordingly, like sending a notification. You can see that PR here.
Getting multiple views working is a pain on it's own. There are a few resources regarding multiple views but they all come to the same conclusion, it's a pain in the ass to get right. Every view in the app has it's own UI thread. Only the UI thread can update things on the UI. Also if you have two views, view 1 and view 2, view 1's UI thread can only update things on view 1's UI and view 2's UI thread can only update things on view 2's UI. With the Signal app, there is also another thread (a background thread) that is listening for messages from Signal. When it gets a new message it has to send that message to each UI thread. If you try to update the UI from a background thread your app will crash. The last two posts I linked above go into more detail about how to get multiple views working. I also made a small test app to learn how all this multi window shit works..
Now back to getting notifications working. Background tasks on Windows kind of seem unpredictable. Here are the official docs on getting a background task up and running. Tasks running on a timer can only run every 15 minutes. Which makes it kind of a pain for seeing if your background task works, so the suggestion is to make your background task start if you change the time zone. However this currently only works sometimes for me. Right now my test app successfully launches its background task every 15 minutes. It however does not launch when I change the time zone. The background task I set up for Signal does not launch on a timer but works fine when changing the time zone.
Test app | Signal app | |
Timed trigger | Works | Doesn't work |
Time zone trigger | Doesn't work | Works |
They use the same code.
I have no idea why they both hate me.
Please also note that the test app background task worked with a time zone trigger earlier in January so the fact that it does not work now is mystifying. I have however discovered that background tasks launch at regular 15 minute intervals (00, 15, 30, and 45). I also discovered that the time zone trigger does not work on phones so I can only rely on waiting for a 15 minute mark.
In conclusion, still using Windows phone is kind of insane (just use an iPhone amirite), working on this app is kind of insane (see the previous point, also I could just use Messenger (not supported on Windows phone, see previous point again)), and trying to get background tasks working is kind of insane. If you would like to learn more about Signal, the protocol and how it works, or the work that I'm doing please see the following links.
Signal (website)
Signal technical information
Official Signal GitHub org
Signal for Windows GitHub org
If for some reason you don't want to use the official Signal Desktop app (I mean why would you it's an Electron app 🙃) and you want to try out our unofficial desktop app (I mean why wouldn't you it's NATIVE) you can get access to the app by sending an email to signal.windows@gmail.com. We only take feedback on GitHub at the moment so you'll need to send us your GitHub account name before we send you a link to the app. You can also build the app yourself since it's open source.
Maybe my next technical post will have more code snippets in it.