Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
*.log
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
@@ -0,0 +1,40 @@
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
dbus \
|
||||
avahi \
|
||||
avahi-tools
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1000 appuser && \
|
||||
adduser -D -u 1000 -G appuser appuser && \
|
||||
chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8080 5353 1900
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
@@ -0,0 +1,38 @@
|
||||
# Archipelago Router
|
||||
|
||||
Mesh routing and local network management for Archipelago.
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
# From the apps directory
|
||||
./build.sh router
|
||||
|
||||
# Or manually
|
||||
cd router
|
||||
docker build -t archipelago/router:latest .
|
||||
# or
|
||||
podman build -t archipelago/router:latest .
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
cd router
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Ports
|
||||
|
||||
- **8084**: Web UI (dev: 18084)
|
||||
- **5353**: mDNS/Bonjour (dev: 15353)
|
||||
- **1900**: SSDP (dev: 11900)
|
||||
|
||||
## Running Locally
|
||||
|
||||
```bash
|
||||
docker run -p 8084:8080 -p 5353:5353/udp -p 1900:1900/udp \
|
||||
-v /tmp/archipelago-dev/router:/app/data \
|
||||
archipelago/router:latest
|
||||
```
|
||||
@@ -0,0 +1,75 @@
|
||||
app:
|
||||
id: router
|
||||
name: Mesh Router
|
||||
version: 1.0.0
|
||||
description: Mesh routing and local network management. Provides device discovery, routing, and network topology visualization.
|
||||
|
||||
container:
|
||||
image: archipelago/router:1.0.0
|
||||
image_signature: cosign://...
|
||||
pull_policy: if-not-present
|
||||
|
||||
dependencies:
|
||||
- storage: 500Mi
|
||||
|
||||
resources:
|
||||
cpu_limit: 2
|
||||
memory_limit: 512Mi
|
||||
disk_limit: 500Mi
|
||||
|
||||
security:
|
||||
capabilities: [NET_ADMIN, NET_RAW] # Required for network management
|
||||
readonly_root: true
|
||||
no_new_privileges: true
|
||||
user: 1000
|
||||
seccomp_profile: default
|
||||
network_policy: host # Requires host network for routing
|
||||
apparmor_profile: router
|
||||
|
||||
ports:
|
||||
- host: 8084
|
||||
container: 8080
|
||||
protocol: tcp # Web UI
|
||||
bind: 127.0.0.1
|
||||
auth: gated
|
||||
- host: 5353
|
||||
container: 5353
|
||||
protocol: udp # mDNS/Bonjour
|
||||
auth: none
|
||||
auth_rationale: >-
|
||||
mDNS is UDP multicast service discovery; gating it would break .local name resolution for every device on the LAN.
|
||||
- host: 1900
|
||||
container: 1900
|
||||
protocol: udp # SSDP
|
||||
auth: none
|
||||
auth_rationale: >-
|
||||
SSDP/UPnP discovery is UDP multicast — there is no HTTP request to gate and no client that could hold a session.
|
||||
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /var/lib/archipelago/router
|
||||
target: /app/data
|
||||
options: [rw]
|
||||
- type: bind
|
||||
source: /var/run/dbus
|
||||
target: /var/run/dbus
|
||||
options: [ro]
|
||||
|
||||
environment:
|
||||
- NETWORK_INTERFACE=eth0
|
||||
- MESH_ENABLED=true
|
||||
- DEVICE_DISCOVERY=true
|
||||
|
||||
health_check:
|
||||
type: http
|
||||
endpoint: http://localhost:8084
|
||||
path: /health
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
networking:
|
||||
mesh_enabled: true
|
||||
local_network_access: true
|
||||
device_discovery: true
|
||||
routing_protocols: [olsr, babel]
|
||||
Generated
+1486
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "archipelago-router",
|
||||
"version": "1.0.0",
|
||||
"description": "Mesh routing and local network management for Archipelago",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "ts-node src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"bonjour": "^3.5.0",
|
||||
"network-interfaces": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.10.0",
|
||||
"typescript": "^5.3.3",
|
||||
"ts-node": "^10.9.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import express from 'express';
|
||||
import bonjour from 'bonjour';
|
||||
|
||||
const app = express();
|
||||
const port = 8080;
|
||||
|
||||
// Initialize Bonjour for mDNS
|
||||
const bonjourInstance = bonjour();
|
||||
|
||||
// Publish Archipelago Router service
|
||||
bonjourInstance.publish({
|
||||
name: 'Archipelago Router',
|
||||
type: 'http',
|
||||
port: port,
|
||||
txt: {
|
||||
version: '1.0.0',
|
||||
mesh: 'enabled',
|
||||
discovery: 'enabled'
|
||||
}
|
||||
});
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
|
||||
// Health check endpoint
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({ status: 'ok', service: 'archipelago-router' });
|
||||
});
|
||||
|
||||
// Network topology endpoint
|
||||
app.get('/api/topology', (req, res) => {
|
||||
res.json({
|
||||
nodes: [],
|
||||
links: [],
|
||||
timestamp: Date.now()
|
||||
});
|
||||
});
|
||||
|
||||
// Device discovery endpoint
|
||||
app.get('/api/devices', (req, res) => {
|
||||
res.json({
|
||||
devices: [],
|
||||
count: 0
|
||||
});
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(port, '0.0.0.0', () => {
|
||||
console.log(`Archipelago Router listening on port ${port}`);
|
||||
console.log('mDNS service published');
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('Shutting down...');
|
||||
bonjourInstance.unpublishAll(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2020"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user