This project uses a set of Android Apps and a server running on the internet to physically transport data from disconnected android phones to the internet. Our first target application is email.
- the core Android apps: BundleClient and BundleTransport
- the core server app: bundleserver
- library modules used by the core apps: bundle-core and serviceadapter-core
- the apps that run on top of the server are under the apps directory. the apps will have a client component and a server component (called the ServiceAdapter).
our first target application is email and we have modified K9 (the opensource android email client) to work with DDD: https://github.com/SJSU-CS-systems-group/DDD-thunderbird-android
the server apps are build with maven, and the android apps are built with gradle. we recommend using intellij and android studio for development. check out this repo directly into the relevant IDE. the IDE will automatically recognize the gradle and maven projects.
for the Android apps, you will first need to run maven install to get the bundle-core library into your local maven repository.
we use kotlin for UI development and Java for everything else. try to keep as much of the logic in Java as possible. this helps with integration testing.
we use intellij to develop the shared logic between clients and server and for the BundleServer and adapters. we use AndroidStudio to develop the Android client apps. tragically, we use two build systems: maven in intellij and gradle for AndroidStudio. you don't have to use intellij and AndroidStudio, but the environment is tailored for those two IDEs.
you must first mvn install before compiling with AndroidStudio.
everything uses bundle-core and that is built with maven.
bundle-core uses our github maven package repo, so you have to set up settings.xml in your .m2 directory! our package repo is public, but even for public repos, you must set up authentication for github. here is an example settings.xml:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>github</id> <!-- Match ID -->
<username>USERNAME</username>
<password>GITHUB_PERSONAL_ACCESS_TOKEN</password>
</server>
</servers>
</settings>
The bundleserver is deployed via a GitHub Actions pipeline (.github/workflows/deploy.yml) triggered on pushes to main (excluding CI-only changes). It can also be triggered manually from any branch via the "Run workflow" button in the Actions UI (workflow_dispatch).
- build — builds all Maven modules on a GitHub-hosted runner (
ubuntu-latest) and uploads bundleserver, k9, and CLI jars as artifacts - deploy-canary — SCPs jars to the canary server and restarts
bundleserverandk9systemd services - test-canary — calls the reusable
client-test.ymlworkflow withenvironment: canary. Uses the nightly CLI jar as the backward-compat jar and the newly built CLI jar for the new-jar exchange. Seeclient-test.ymlfor details. - deploy-production — requires manual approval in the GitHub Actions UI, then SCPs jars to production and restarts services
Three GitHub Environments must be configured in repo Settings → Environments:
- canary — no protection rules
- production-test — no protection rules (used by nightly tests against production server)
- production — "Required reviewers" protection rule enabled
Each environment needs these secrets:
DEPLOY_SSH_HOST— server IP or hostnameDEPLOY_SSH_USER— SSH user for deployment (canary/production only)DEPLOY_SSH_KEY— SSH private key for authentication (canary/production only)SERVER_KEYS_PATH— path to directory containing server public key filesTEST_EMAIL— email address of an existing account used for exchange testsTEST_EMAIL_PASSWORD— password forTEST_EMAILTEST_TARGET_EMAIL— external address with auto-reply configuredDISCORD_WEBHOOK_URL— webhook for failure/warning notifications
SSH access to the canary and production servers must be configured once:
- Generate an SSH key pair on any machine:
ssh-keygen -t ed25519 -f deploy_key -N "" - Add the public key (
deploy_key.pub) to~/.ssh/authorized_keyson both servers - Add the private key (
deploy_key) as theDEPLOY_SSH_KEYsecret in the canary and production environments — the workflow writes it to disk on each run
The production-test environment does not need DEPLOY_SSH_KEY — tests connect to the production server address but only via the bundle protocol (port 7778), not SSH.
The canary server must be set up to mirror the production server:
- Install Java 21
- Set up MySQL and create the
dtn_server_dbdatabase - Generate BundleSecurity server keys (same process as production) and place them at the configured path
- Create systemd service files for
bundleserverandk9(same as production) - Configure
application.ymlwith canary-specific DB credentials, paths, and ports - Ensure the deploy user has
sudoaccess to restart the systemd services
The CLI tool (apps/cli/target/cli-*.jar) is used for canary testing:
# Initialize client storage with server keys and address
java -jar cli.jar bc initializeStorage <dir> --server-keys <keys-dir> --server <host>:<port>
# Add a test ADU
java -jar cli.jar bc addAdu <dir> <appid> <adu-file>
# Perform exchange (upload + download bundles)
java -jar cli.jar bc exchange <dir>If any step exits non-zero, the test-canary job fails and blocks the production approval gate.