magma-connect
v1.0.3
Published
A smart magmastream plugin to connect nodes based on their region.
Maintainers
Readme
magma-connect
Smart MagmaStream plugin that picks the best Lavalink node per guild using region and geolocation. It acts like a lightweight load balancer: if you don’t specify a node, it chooses the closest one to the guild’s Discord voice region (or your bot host as fallback).
Features
- Per-guild node selection based on distance (Haversine great‑circle)
- Learns guild regions from Discord VOICE_SERVER_UPDATE events
- Optional static overrides for node and guild locations
- Background refresh of node geolocation
- Safe defaults and graceful fallbacks when data is missing
Requirements
- Node.js >= 16
- magmastream ^2.9.0 (peer dependency)
- One or more Lavalink nodes configured in your Manager
Install
npm install magma-connect
# or
yarn add magma-connect
# or directly from GitHub (main branch)
yarn add muralianand12345/magma-connect#mainQuick start
import { Manager } from 'magmastream';
import { MagmaConnect } from 'magma-connect';
const manager = new Manager({
nodes: [
{ host: 'lavalink-us.myhost.com', identifier: 'us', password: 'youshallnotpass' },
{ host: 'lavalink-eu.myhost.com', identifier: 'eu', password: 'youshallnotpass' },
],
enabledPlugins: [
new MagmaConnect({ debug: true, refreshIntervalMs: 60_000 }),
],
});
await manager.init({ clientId: 'YOUR_CLIENT_ID', clusterId: 0 });
// If you omit nodeIdentifier, the plugin auto-picks the nearest node
const player = manager.create({
guildId: '123',
textChannelId: '456',
voiceChannelId: '789',
});
// You can still force a node explicitly:
// manager.create({ ..., nodeIdentifier: 'eu' })Options
export interface MagmaConnectOptions {
/** Optional explicit node locations keyed by node identifier (or host if no identifier). */
nodeLocations?: Record<string, { lat: number; lon: number } | { region: string }>;
/** Optional provider to supply a guild's approximate location or region code. */
getGuildLocation?: (guildId: string) => Promise<{ lat: number; lon: number } | { region: string } | undefined>;
/** Interval (ms) to periodically refresh node geolocation. Disable by leaving undefined/0. */
refreshIntervalMs?: number;
/** Enables debug logging prefixed with [MAGMACONNECT]. */
debug?: boolean;
}Example: static node locations
new MagmaConnect({
nodeLocations: {
us: { region: 'us-east' },
eu: { lat: 50.11, lon: 8.68 }, // Frankfurt
},
});Example: custom guild resolver
new MagmaConnect({
getGuildLocation: async (guildId) => {
// e.g., fetch from your DB
const cfg = await db.guilds.find(guildId);
return cfg?.region ? { region: cfg.region } : undefined;
},
});How it chooses a node
- Capture guild voice region from VOICE_SERVER_UPDATE and map to lat/lon.
- Resolve node geolocation via:
- Static
nodeLocationsoverrides, or - Public IP geo APIs (ipwho.is, ip-api.com) using their free endpoints.
- Static
- Compute great‑circle distance from guild location to each node and pick the closest.
- Fallbacks: bot host location -> first configured node.
Notes:
- Existing players aren’t modified; selection happens when
manager.createis called withoutnodeIdentifier. - You can override guild and node locations at any time for full control.
Privacy and networking
When no overrides are provided, the plugin may query public geolocation APIs:
- https://ipwho.is
- http://ip-api.com
Only hostnames/IPs of your Lavalink nodes (and your server’s public IP for fallback) are sent. Consider providing nodeLocations if you prefer zero external lookups or are behind NAT.
Troubleshooting
- Always picking the same node: ensure
VOICE_SERVER_UPDATEevents reach the Manager and that your nodes have distinct identifiers/hosts. - Corporate/VPC networks: public geo may be inaccurate. Provide
nodeLocations. - Frequent API timeouts: set
refreshIntervalMshigher and/or use static locations.
Development
# Lint and build
yarn lint
yarn buildType definitions are included. The library can be used from TypeScript or JavaScript (CJS or ESM).
License
Apache-2.0
