Skip to content

Repository files navigation

Bump Service

License: MIT Rust

A fast, lightweight, and ephemeral proximity-based data exchange service that enables secure data transfer between devices through a simple "bump" gesture. Built with Rust for high performance and reliability.

Bump Service Logo

What is Bump?

Bump is a modern solution to a common problem: how do you quickly share data between devices that are physically next to each other? While technologies like AirDrop, NFC, or QR codes exist, they often require specific hardware, complex setup, or are platform-dependent.

Bump makes sharing as intuitive as physically bumping two devices together:

  1. Two users with devices next to each other want to share data
  2. They both make a "bump" gesture with their devices
  3. Our service matches these gestures based on time and location
  4. Data is instantly exchanged between the devices

Why Bump?

  • 🚀 Platform Independent: Works on any device with a web browser
  • 🎯 No Special Hardware: Uses standard sensors (GPS, accelerometer) available in most devices
  • 🔒 Privacy-First: Ephemeral by design - no data storage, no tracking
  • Lightning Fast: Sub-second data exchange
  • 🌐 Universal: Share any type of data - text, URLs, JSON, or encoded binary

How Does It Work?

The Bump Protocol

Device A                 Server                  Device B
   |                       |                       |
   |------ /bump -------->|                       |
   |                      |<------ /bump ---------|
   |                      |                       |
   |                      |---(match algorithm)---|
   |                      |                       |
   |<---- payload B ------|                       |
   |                      |------ payload A ----->|
   |                      |                       |
  1. When a device initiates a bump, it sends a request to our /bump endpoint with:

    • Current location
    • Timestamp
    • Optional payload
    • Optional custom matching key
  2. Our service uses a sophisticated matching algorithm to pair devices based on:

    • Temporal proximity (within milliseconds)
    • Spatial proximity (within meters)
    • Custom keys (if provided)
  3. When a match is found, payloads are exchanged instantly between the devices

Ephemeral, Fast, and Efficient

Our service is designed with performance and privacy in mind:

  • Zero Persistence: No databases, no storage, everything happens in memory
  • Auto-Cleanup: Unmatched requests automatically expire after their TTL
  • Race-Condition Protected: Thread-safe queue management
  • Resource Efficient:
    • Configurable queue sizes
    • Automatic request cleanup
    • Minimal memory footprint
    • Sub-millisecond matching algorithm

Try It Out!

Live Demo

Visit our live demo at bump.nyn.me to try Bump in action! Make suer you have two devices to test it with :-)

Client Implementation

Check out our open-source client implementation at github.com/codevalley/bump-me

🚀 Quick Start

# Clone the repository
git clone https://github.com/codevalley/bump.git
cd bump-service

# Build and run
cargo run

# The service will start on localhost:8080

API Documentation

POST /bump/bump

The unified endpoint for all bump operations. Note the doubled /bump: every route is nested under the web::scope("/bump") prefix in src/main.rs, and this particular handler is itself registered as #[post("/bump")] in src/api.rs — so the full path is /bump/bump, not /bump.

curl -X POST http://localhost:8080/bump/bump \
  -H "Content-Type: application/json" \
  -d '{
    "matching_data": {
      "location": {"lat": 37.7749, "long": -122.4194},
      "timestamp": 1646078423000,
      "custom_key": "optional-key"
    },
    "payload": "https://example.com/shared-document",
    "ttl": 500
  }'

Response (Success):

{
  "status": "matched",
  "sender_id": "request-id-456",
  "receiver_id": "request-id-123",
  "timestamp": 1646078425000,
  "payload": "payload from matching request",
  "message": "Match successful"
}

Other endpoints: POST /bump/send, POST /bump/receive, GET /bump/health, GET /bump/timestamp, and GET /bump/weather?lat=&long= — a server-side proxy to OpenWeather that returns {city, temperature, weather_icon, weather_description} and never exposes the API key to clients (503 if BUMP_OPENWEATHER_KEY is unset).

For detailed API documentation, see our API Guide.

Configuration

Configure the service through environment variables (see sample.env for a ready-to-copy reference). Every BUMP_* variable has its own per-field default in src/config.rs, so a partial environment (only some vars set) does not revert the rest to some other fallback:

Variable Description Default
BUMP_MAX_QUEUE_SIZE Maximum pending requests 1000
BUMP_MAX_DISTANCE_METERS Maximum matching distance (meters) 250.0
BUMP_MAX_TIME_DIFF_MS Maximum time difference (ms) 1500
BUMP_DEFAULT_TTL_MS Default request TTL (ms) 500
BUMP_TEMPORAL_WEIGHT Weight given to temporal proximity in match scoring 0.7
BUMP_SPATIAL_WEIGHT Weight given to spatial proximity in match scoring 0.3
BUMP_CLEANUP_INTERVAL_MS Interval at which expired requests are swept from the queue (ms) 1000
BUMP_OPENWEATHER_KEY Server-side OpenWeather API key used by the /bump/weather proxy. No default — leave unset to disable the feature (the endpoint then returns 503). (none)
RUST_LOG Log level info

Docker image note: the shipped Dockerfile bakes in stricter matching overrides than the defaults above — BUMP_MAX_TIME_DIFF_MS=5000 and BUMP_MAX_DISTANCE_METERS=100 — to make matching reliable out of the box given server-assigned timestamps and real-world GPS accuracy. Every other BUMP_* variable is left unset in the image and falls back to its src/config.rs default. All of these, including the two baked-in overrides, remain tunable per-deployment via Railway dashboard vars.

Project Structure

bump-service/
├── src/
│   ├── main.rs           # Application entry point, route wiring under /bump
│   ├── api.rs            # HTTP endpoint handlers
│   ├── models.rs         # Data structures
│   ├── service.rs        # Core matching service
│   ├── config.rs         # Configuration
│   └── queue/             # Thread-safe unified request queue
│       ├── mod.rs         # Module wiring + default score/threshold constants
│       ├── types.rs       # Shared types: QueuedRequest, RequestType, RequestQueue trait
│       ├── q_core.rs      # UnifiedQueue struct, clone semantics, constructors
│       ├── q_impl.rs      # RequestQueue trait impl (add/remove/subscribe/cleanup)
│       ├── q_matching.rs  # Candidate scan + atomic match commit under lock
│       └── matching.rs    # Pure match-scoring function (time/distance/key)
├── docs/                 # Documentation
└── tests/
    └── integration/       # Integration tests (single Cargo test binary)

Development

# Start with hot reload
cargo watch -x run

# Run tests
cargo test

# Format and lint
cargo fmt
cargo clippy

Deploying to Railway

The service auto-deploys to Railway from GitHub main using the repo's Dockerfile (multi-stage build, non-root runtime user, binds $PORT). To deploy:

  1. Push to main — Railway picks up the commit and rebuilds the image.
  2. Configure environment variables (matching overrides, BUMP_OPENWEATHER_KEY, RUST_LOG, etc.) via the Railway dashboard; they take precedence over the Dockerfile's baked-in defaults.
  3. Railway health-checks the deployment against GET /bump/health.

Warning: if main doesn't compile, the Railway build fails and production goes down — the live URL will start returning Railway's own "Application not found" 404 instead of the service. There is no automatic rollback to the last good image, so keep main green. See DEPLOYMENT.md for details.

📜 License

This project is licensed under the MIT License - see the LICENSE file for details.

🤝 Contributing

We welcome contributions! See our Contributing Guidelines for details.

📞 Contact

About

Proximity sharing without connecting

Resources

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages