mautrix/imessage BlueBubbles Connector

a launchd guide

Jason LaGuidice @shadowdrake:beeper.com Last updated 3/7/2024 Added experimental automatic script for this guide


This guide will create a single-user Launch Agent to run the bluebubbles connector of mautrix/imessage using the Beeper Bridge Manager. The end result will be the bridge manager is started on user login to the Mac and will be automatically restarted in case of crash. Log files will be automatically generated and kept in the same folder as the working files. The launchd service will be called bbctl-bluebubbles.

Prerequisites

  • This guide builds off of the Mautrix/iMessage BlueBubbles Connector with Beeper by ampersandru & matchstick
    • Setting up any of the optional features listed in that guide is not required to automate bridge startup using this method
  • It is assumed you have moved the latest copy of the bridge manager to /usr/local/bin/ and named it bbctl
    • You will need to change file paths if you chose a different folder when running the previous guide
    • You may also add an entry to the system's $PATH to the bridge manager executable if you desire
  • You must have successfully run the bridge at least once and acknowledged any prompts
    • Note that first time sending a message may result in MacOS prompts for BlueBubbles for access
    • Prompts will still appear when the system is running via launchd, but they still have to be acknowledged for full operation

This guide will use nano as the text editor but any other feasible text editor can be used in its place

  1. Open Terminal
  2. Run nano ~/Library/LaunchAgents/bbctl-bluebubbles.plist
  3. Paste or type the following basic .plist file (change your bluebubbles URL and password as required)
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
        <dict>
            <key>KeepAlive</key>
            <dict>
                <key>Crashed</key>
                <true/>
            </dict>
            <key>Label</key>
            <string>bbctl-bluebubbles</string>
            <key>ProgramArguments</key>
            <array>
                <string>sh</string>
                <string>-c</string>
                <string>bbctl run --param 'bluebubbles_url=http://localhost:1234' --param 'bluebubbles_password=YourBlueBubblesPassword' --param 'imessage_platform=bluebubbles' sh-imessage</string>
            </array>
            <key>RunAtLoad</key>
            <true/>
            <key>StandardErrorPath</key>
            <string>/Users/Shared/errors.log</string>
            <key>StandardOutPath</key>
            <string>/Users/Shared/out.log</string>
            <key>WorkingDirectory</key>
            <string>/Users/Shared</string>
            <key>EnvironmentVariables</key>
                <dict>
                    <key>PATH</key>
                    <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
                </dict>
        </dict>
    </plist>
    
  4. Press ctrl+x then y then enter to save the file
  5. Run launchctl load -w ~/Library/LaunchAgents/bbctl-bluebubbles.plist

The service should start silently. You can open the out.log and error.log files to view the output from the program


Stopping the service
`launchctl unload -w ~/Library/LaunchAgents/bbctl-bluebubbles.plist``


Updating the service

  1. Stop the service with launchctl unload -w ~/Library/LaunchAgents/bbctl-bluebubbles.plist
  2. Restart the service with launchctl load -w ~/Library/LaunchAgents/bbctl-bluebubbles.plist

Other notes

  • This will not run as a LaunchDaemon - the iMessage database and service calls are not available unless the user is logged in
    • It does not work even if you set a specific user for the LaunchDaemon to run as
  • This can be converted into a global LaunchAgent (runs for all users)
    • Remove the StandardErrorPath and StandardOutPath keys and their associated strings
    • Place the .plist file in /Library/LaunchAgents and load it with an adjusted path
  • It is possible to run a bash script instead of launching bbctl directly - in this script you can have multiple items such as git fetch and git pull before bbctl is run to automatically update mautrix-imessage on service start
    • (This is why the WorkingDirectory is set as such)

Experimental automatic script

Experimental

The script below is untested and may not work. Please reach out if you try it and it can be revised and fixed

Below is a bash script that will do the following for you. The only prerequisites to this is to have logged into the bridge manager at least once and have BlueBubbles installed and working. All files will be stored in /Users/Shared

  • a bash script that pulls the latest copy of the beeper bridge manager, and starts the bridge
  • launchd .plist file which references the bash script mentioned in the line above
  • Starts the service

As usual, this begins with nano to make it less jarring to have to set execute permission on the script you create. A GUI text editor is also totally acceptable

  1. Open Terminal
  2. cd /Users/Shared
  3. nano ./setup-launchd.sh
  4. Paste the following into nano:
    #!/bin/bash
    entry_loop () {
        printf "Enter BlueBubbles URL & port (http://localhost:1234)\n"
        read -p "(Press enter to accept default): " "bb_url"
    
        if [ -z "$bb_url" ]; then
            # Use default URL
            bb_url="http://localhost:1234"
        fi
    
        read -p "Enter BlueBubbles password: " "bb_pass"
    
        if [ -z "$bb_pass" ]; then
            # User didn't enter password - start over
            printf "\nPassword entry is mandatory, restarting\n\n"
            entry_loop
        fi
    
        printf "Enter location to store scripts (/Users/Shared)\n"
        read -p "(Press enter to accept default): " "script_location"
    
        if [ -z "$script_location" ]; then
            # Use default script location
            script_location="/Users/Shared"
        fi
    
        printf "Enter log file location (/Users/Shared)\n"
        read -p "(Press enter to accept default): " "logfile_location"
    
        if [ -z "$logfile_location" ]; then
            # Use default log file location
            logfile_location="/Users/Shared"
        fi
    
        printf "\n"
        printf "Are your entries correct? Please note this script does not confirm your entries are valid\n"
        read -n 1 -p "(y to continue, any key to retry): "
        printf "\n"
    
        if [ $REPLY = "y" ]; then
            return 0
        fi
    
        entry_loop
    }
    
    entry_loop
    
    printf "Generating launch script\n"
    cat > update-launch.sh << EOF
    #!/bin/sh
    echo "Detecting operating system... "
    [[ `uname -s` == "Linux" ]] && os_type="linux" || os_type="macos"
    echo \$os_type
    echo "Detecting architecture... "
    [[ `uname -p` == "arm" ]] && architecture="arm64" || architecture="amd64"
    echo \$architecture
    
    echo "Backing up existing bridge manager"
    mv /Users/Shared/bbctl-nightly /Users/Shared/bbctl-nightly.bak
    
    echo "Downloaing latest Beeper Bridge Manager nightly artifact"
    curl -L http://nightly.link/beeper/bridge-manager/workflows/go.yaml/main/bbctl-\$os_type-\$architecture.zip --output bbctl-nightly.zip
    unzip bbctl-nightly.zip
    rm ./bbctl-nightly.zip
    mv ./bbctl-\$os_type-\$architecture ./bbctl-nightly
    
    echo "Granting bridge manager execute permission"
    chmod +x ./bbctl-nightly
    
    echo "Starting bridge"
    
    /Users/Shared/bbctl-nightly run --param 'bluebubbles_url=$bb_url' --param 'bluebubbles_password=$bb_pass' --param 'imessage_platform=bluebubbles' sh-imessage
    EOF
    
    printf "Moving launch script\n"
    mv update-launch.sh ${script_location}/update-launch.sh
    
    printf "Generating launchd plist\n"
    cat > com.beeper.bridgemanager.imessage.plist << EOF
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
      <dict>
        <key>KeepAlive</key>
        <dict>
          <key>Crashed</key>
          <true/>
        </dict>
        <key>Label</key>
        <string>com.beeper.bridgemanager.imessage</string>
        <key>ProgramArguments</key>
        <array>
          <string>sh</string>
          <string>-c</string>
          <string>$script_location/update-launch.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>$logfile_location/errors.log</string>
        <key>StandardOutPath</key>
        <string>$logfile_location/out.log</string>
      </dict>
    </plist>
    EOF
    
    printf "Moving launchd plist file to local user LaunchAgent folder\n"
    mv com.beeper.bridgemanager.imessage.plist ~/Library/LaunchAgents/com.beeper.bridgemanager.imessage.plist
    
    printf "Starting Launch Agent\n"
    launchctl load -w ~/Library/LaunchAgents/com.beeper.bridgemanager.imessage.plist
    
    printf "Bridge should be starting now. Review ${logfile_location}/out.log and ${logfile_location}/errors.log if necessary"
    
  5. ctrl+x then y then enter to save and exit nano
  6. chmod +x ./setup-launchd.sh
  7. ./setup-launchd.sh

The script should ask you for information about your BlueBubbles server, compile the files for you, then start the service

Edit
Pub: 31 Jan 2024 22:27 UTC
Edit: 07 Mar 2024 17:01 UTC
Views: 2772