Skip to content

Interfacing with Rust

Rémi Bardon edited this page Jun 10, 2022 · 5 revisions

Interfacing Swift and Rust – what data we will need, screen by screen

This page is a draft, and can be renamed/updated anytime. I just want to start writing down what I have in mind so we can all discuss on something and iterate.

As it would be require a lot of housekeeping to have one page per view/screen, I will group them in features and list them with headings, in alphabetical order.

I also added priorities to requirements, so we can do what to do first.

AuthenticationFeature

Login screen

Initiate Login (Password)

Requirements:

  • Form validation (low priority)
    • A call to ProseCore to check if the JID is correct
      • Debounce keystrokes then String -> Result<JID, JIDParsingError>
  • Log in button (high priority)
    • A call to ProseCore with a JID and a password, sending back either a success or a failure.
      • Shape: (JID, String) async -> Result<LoginRoute, AuthenticationError>
        • LoginRoute: .basic(BasicAuthState) | .mfa(MFAState) | .success(UserCredentials)
        • BasicAuthState: (String, String)
        • MFAState: .digits(String)
          • Make it an enum, so we can support other types in the future
      • Do we need an extra security for passing the password around?
      • What do we need in UserCredentials? We'll see with other screens / XMPP spec (@valeriansaliou what do you think?)
    • This triggers a login call on the backend, possibly asking for a MFA
  • Lost password (low priority)
    • ??? (link?)
  • No account (low priority)
    • Read guide: link

Multi Factor Authentication (MFA)

Initiate Login (MFA)

Requirements:

  • Confirmation code (low priority)
    • A call to ProseCore with a JID (I don't know MFA, you probably have some kind of token for a request? @valeriansaliou) and the confirmation code
      • Shape: (JID, String) async -> Result<LoginRoute, MFAError>
  • Code generation error (low priority)
    • Link?
  • No account yet (low priority)
    • route: LoginRoute = .basic(.init())

Login success

This is not a screen (although it could be), but rather an action handled by the authenticationReducer.

Requirements:

  • Persist the credentials in the Keychain (@nesium or somewhere else?) (high priority)
    • Add some kind of prefix, we might need to store multiple credentials on the same machine
  • Start the main app (high priority)
    • TODO (need access to NSWindow)

MainWindowFeature

On launch

Baseline

This is not a screen (although it could be), but rather an action handled by the authenticationReducer.

Requirements:

  • Request the user's vCard (@valeriansaliou if not already in the credentials?) (high priority)
    • @valeriansaliou Is there a "public" and "private" vCard or is there only one version for everyone?
  • Request the server's vCard (high priority)
    • We will need it for account descriptions
    • Shape: (JIDDomain) async -> Result<VCard, ContactError>
  • Request the user's contacts (to the server, not address book permision to the user) (high priority)
    • @valeriansaliou can XMPP do this? Or is it only possible to have this from the previous conversations a user had?
    • Shape: (JID) async -> Result<[VCard], ContactError> or (JID) async -> Stream<Result<VCard, ContactError>>
      • @valeriansaliou Probably not a JID in input
  • Start streaming incoming messages
    • Shape: (JID) -> AnyPublisher<Message, Never>
      • @valeriansaliou Probably not a JID in input
      • Message: (from: JID, to: JID, content: String, attachments: ???)
        • to is required, as we need to know if the message goes to a group or in the DMs for example
        • How to know if it's in a thread? I don't remember the XEP
    • When receiving a message, the reducer:
      • Adds a new entry in the unread stack
      • Adds a new entry in the "Replies", "Direct messages" or "People & groups" depending on the origin of the message
      • Adds a new entry in the correct conversation
  • Subscribe to push notifications
    • I don't know how this is handled

Chat

Baseline

We're talking about the middle view, the chat with the bar.

Notes:

  • Store the messages in a ring buffer, to avoid storing too many messages in memory
  • Keep the unread count separated from the collection of messages, to allow emptying the collection (for memory cleanup) and to improve performance (no reduce(0, +) on all messages to find the count)
  • After some time, empty the message buffer, to free some memory?
    • Reset the timer every time a new message arrives in this conversation, as the user might probably want to open the conversation after a notification

Requirements:

  • When opening a chat
    • Subscribe to "typing" notifications
      • Shape: (JID) -> AnyPublisher<JID, Never> or (JID) -> AnyPublisher<String, Never>
      • Store in a SortedSet, to avoid duplicates and keep typing order (otherwise it could look bad when updating the list)
  • When closing a chat
    • Unsubscribe from "typing" notifications (we're not currently displaying it in the sidebar)

Chat info pane

Baseline

We're talking about the pane on the right side.

Requirements:

  • When opening the pane
    • Fetch the user/group vCard
    • Subscribe to presence nofitications (XEP-0012/XEP-0256, which one?)
      • This allow displaying "Active 1 min ago" for example
      • On receive
        • If the presence is "away" or "xa"
          • Map the date to a string for the state (i.e. "Active 1 min ago")
          • Depending on the scale (minutes/hours/days), start a recurring task which will update the state's message (i.e. "Active 2 mins ago")
        • If the presence is "online" (not sure about this one)
          • Change the state's message
          • Cancel any timer updating the presence string
  • When closing the pane
    • Unsubscribe from presence nofitications (XEP-0012/XEP-0256, which one?)
    • Stop presence timer