Skip to content

andyshinn/coretact

Repository files navigation

Coretact - Meshcore Contact Management System

A Discord bot and API for managing meshcore contact advertisements.

Vibe Coded

This is a vibe-coding project. Here be dragons!

Features

  • Discord Bot: Manage your meshcore contact advertisements via slash commands
  • Web API: RESTful API for programmatic access to contact data
  • File-based Storage: Simple JSON storage using the datafiles library
  • Contact Filtering: Search and filter contacts by type, name, and public key
  • CORS Support: Access the API from any origin

Setup

Quick Start with Podman (Recommended)

For production deployments, use Podman containers:

# Build the container
podman build -t localhost/coretact:latest -f Containerfile .

# Deploy with Podman Play
podman play kube podman-play.yaml

See DEPLOYMENT.md for detailed deployment instructions.

Development Setup

Prerequisites

Installation

  1. Clone the repository:
git clone <repository-url>
cd coretact
  1. Install dependencies with uv:
uv sync
  1. Configure environment variables:
cp .env.default .env
# Edit .env and add your Discord bot token and owner ID
  1. Run the bot or API server:
# Run the Discord bot
uv run python -m coretact bot

# Run the Web API server
uv run python -m coretact api

# Run the Web API server on a custom host/port
uv run python -m coretact api --host 127.0.0.1 --port 8080

Discord Commands

All commands use the /coretact prefix:

/coretact add <meshcore_url>

Add or update your meshcore contact advertisement.

Example:

/coretact add meshcore://110055365953947d253d213d7ab36df0be29ffb7a758049f657a6b32e1d00d66087d...

/coretact list [user]

List contact advertisements. Without arguments, lists your own adverts. Optionally specify a user to list their adverts.

/coretact remove <public_key>

Remove one of your advertisements by providing the first 8+ characters of the public key.

Example:

/coretact remove 55365953

/coretact search [type] [key_prefix] [name] [user]

Search for contact advertisements in the current server with optional filters:

  • type: Filter by device type (companion, repeater, or room)
  • key_prefix: Filter by public key prefix
  • name: Filter by name (partial match)
  • user: Filter by specific user

/coretact download [type] [key_prefix] [name] [user]

Download contacts as a JSON file with optional filters (same as search command).

/coretact info

Show statistics for the current server including total contacts, breakdown by type, and unique users.

Web API

The Web API provides programmatic access to contact data. All endpoints return JSON responses.

Base URL

http://localhost:8080

Endpoints

Health Check

GET /health

Returns the API health status and version.

Response:

{
  "status": "ok",
  "version": "1.0.0"
}

Get Mesh Contacts

GET /api/v1/mesh/{server_id}/contacts

Get all contacts for a mesh (Discord server).

Query Parameters:

  • type (optional): Filter by device type (1=companion, 2=repeater, 3=room)
  • key_prefix (optional): Filter by public key prefix
  • name (optional): Filter by name (partial match)
  • user_id (optional): Filter by Discord user ID

Example Request:

curl "http://localhost:8080/api/v1/mesh/123456789/contacts?type=1&name=Core"

Response:

{
  "contacts": [
    {
      "type": 1,
      "name": "egrme.sh Core",
      "custom_name": null,
      "public_key": "55365953947d253d213d7ab36df0be29ffb7a758049f657a6b32e1d00d66087d",
      "flags": 0,
      "latitude": "0.0",
      "longitude": "0.0",
      "last_advert": 1760299414,
      "last_modified": 1760299413,
      "out_path": ""
    }
  ]
}

Get Contact by Public Key

GET /api/v1/contact/{public_key}

Get a single contact by public key (searches across all meshes).

Example Request:

curl "http://localhost:8080/api/v1/contact/55365953947d253d213d7ab36df0be29ffb7a758049f657a6b32e1d00d66087d"

Response:

{
  "type": 1,
  "name": "egrme.sh Core",
  "custom_name": null,
  "public_key": "55365953947d253d213d7ab36df0be29ffb7a758049f657a6b32e1d00d66087d",
  "flags": 0,
  "latitude": "0.0",
  "longitude": "0.0",
  "last_advert": 1760299414,
  "last_modified": 1760299413,
  "out_path": "",
  "advert_string": "meshcore://110055365953...",
  "discord_server_id": "123456789",
  "discord_user_id": "987654321"
}

Bulk Contacts

POST /api/v1/mesh/{server_id}/contacts/bulk

Get specific contacts by public keys.

Request Body:

{
  "public_keys": ["55365953...", "83c3e551..."],
  "include_metadata": true
}

Response: Same format as "Get Mesh Contacts" endpoint.

Get User Contacts

GET /api/v1/mesh/{server_id}/user/{user_id}/contacts

Get all contacts for a specific Discord user.

Example Request:

curl "http://localhost:8080/api/v1/mesh/123456789/user/987654321/contacts"

Response: Same format as "Get Mesh Contacts" endpoint.

List All Meshes

GET /api/v1/mesh

List all meshes (Discord servers) with their basic information and contact counts.

Example Request:

curl "http://localhost:8080/api/v1/mesh"

Response:

{
  "meshes": [
    {
      "server_id": "123456789",
      "name": "My Discord Server",
      "description": "A server for meshcore enthusiasts",
      "icon_url": "https://cdn.discordapp.com/icons/123456789/abcdef.png",
      "contact_count": 42,
      "created_at": 1760299414,
      "updated_at": 1760299414
    },
    {
      "server_id": "987654321",
      "name": "Another Server",
      "description": "",
      "icon_url": "",
      "contact_count": 15,
      "created_at": 1760299500,
      "updated_at": 1760299500
    }
  ]
}

Get Mesh Info

GET /api/v1/mesh/{server_id}

Get information about a mesh (Discord server) including name, description, icon, and contact count.

Example Request:

curl "http://localhost:8080/api/v1/mesh/123456789"

Response:

{
  "server_id": "123456789",
  "name": "My Discord Server",
  "description": "A server for meshcore enthusiasts",
  "icon_url": "https://cdn.discordapp.com/icons/123456789/abcdef.png",
  "contact_count": 42,
  "created_at": 1760299414,
  "updated_at": 1760299414
}

Get Mesh Stats

GET /api/v1/mesh/{server_id}/stats

Get statistics for a mesh.

Example Request:

curl "http://localhost:8080/api/v1/mesh/123456789/stats"

Response:

{
  "server_id": "123456789",
  "total_adverts": 42,
  "by_type": {
    "companion": 25,
    "repeater": 10,
    "room": 7
  },
  "unique_users": 15,
  "last_updated": 1760299414
}

CORS

The API supports CORS and allows requests from any origin. All endpoints include the following CORS headers:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Methods: GET, POST, OPTIONS
  • Access-Control-Allow-Headers: Content-Type

Error Responses

All error responses follow this format:

{
  "error": "Error message",
  "status": 400
}

Common status codes:

  • 400: Bad Request (invalid parameters)
  • 404: Not Found (resource doesn't exist)
  • 500: Internal Server Error

Development

Running Tests

pytest

Project Structure

coretact/
├── coretact/
│   ├── __main__.py         # CLI entry point
│   ├── bot.py              # Discord bot initialization
│   ├── models.py           # Data models (Advert, Contact)
│   ├── storage.py          # Storage layer
│   ├── log.py              # Logging configuration
│   ├── meshcore/
│   │   └── parser.py       # Meshcore URL parser
│   ├── cogs/
│   │   └── coretact/       # Discord command handlers
│   │       └── __init__.py
│   └── api/
│       ├── __init__.py
│       ├── server.py       # API server setup
│       ├── routes.py       # API route handlers
│       └── middleware.py   # CORS and error handling
├── tests/
│   ├── conftest.py         # Pytest configuration
│   ├── test_storage.py     # Storage tests
│   ├── test_advert_parser.py  # Parser tests
│   └── test_api.py         # API tests
└── storage/                # Contact data (git-ignored)

Environment Variables

Discord Bot

Variable Required Description
DISCORD_BOT_TOKEN Yes Your Discord bot token
DISCORD_BOT_OWNER_ID No Your Discord user ID (for owner commands)
AUTO_SYNC_COMMANDS No Auto-sync commands on startup (default: true)

Web API

Variable Required Description
WEB_API_HOST No API host to bind to (default: 0.0.0.0)
WEB_API_PORT No API port to bind to (default: 8080)

Storage

Variable Required Description
STORAGE_PATH No Storage directory path (default: ./storage)

Logging

Variable Required Description
LOG_LEVEL No Logging level (default: INFO)

License

[Add license information]

Contributing

[Add contributing guidelines]

About

MeshCore contact sharing Discord bot

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors