feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint - usePresenceHeartbeat hook with activity tracking - Auto away after 5 min inactivity - Offline on page close/visibility change - Integrated in MatrixChatRoom component
This commit is contained in:
24
services/space-service/Dockerfile
Normal file
24
services/space-service/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application
|
||||
COPY . .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 7002
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||
CMD python -c "import requests; requests.get('http://localhost:7002/health')"
|
||||
|
||||
# Run application
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7002"]
|
||||
|
||||
|
||||
|
||||
|
||||
258
services/space-service/README.md
Normal file
258
services/space-service/README.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# 🌌 DAARION Space Service
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Статус:** Development (Mock Data)
|
||||
**Порт:** 7002
|
||||
|
||||
---
|
||||
|
||||
## 📋 Опис
|
||||
|
||||
Space Service — це агрегатор даних для Space Dashboard в екосистемі DAARION. Відповідає за космічний шар візуалізації (planets, nodes, events).
|
||||
|
||||
### Функціонал
|
||||
|
||||
- 🪐 **Space Planets** — DAO-планети з метриками
|
||||
- 🖥️ **Space Nodes** — детальні метрики нод
|
||||
- 📡 **Space Events** — події космічного рівня
|
||||
- 🔭 **Anomaly Detection** — виявлення аномалій
|
||||
- 🌠 **Governance Temperature** — активність управління
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Швидкий старт
|
||||
|
||||
### Через Docker Compose
|
||||
|
||||
```bash
|
||||
# З кореня проєкту
|
||||
./scripts/start-city-space-services.sh
|
||||
```
|
||||
|
||||
### Локально (Development)
|
||||
|
||||
```bash
|
||||
cd services/space-service
|
||||
|
||||
# Створити віртуальне середовище
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
# Встановити залежності
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Запустити сервіс
|
||||
python main.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 API Endpoints
|
||||
|
||||
### **GET** `/health`
|
||||
|
||||
Health check endpoint
|
||||
|
||||
---
|
||||
|
||||
### **GET** `/space/planets`
|
||||
|
||||
Повертає DAO-планети у космічному шарі
|
||||
|
||||
**Response:** `List[SpacePlanet]`
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"dao_id": "dao:3",
|
||||
"name": "Aurora Circle",
|
||||
"health": "good",
|
||||
"treasury": 513200,
|
||||
"activity": 0.84,
|
||||
"governance_temperature": 72,
|
||||
"anomaly_score": 0.04,
|
||||
"position": { "x": 120, "y": 40, "z": -300 },
|
||||
"node_count": 12,
|
||||
"satellites": [...]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **GET** `/space/nodes`
|
||||
|
||||
Повертає детальні метрики усіх нод
|
||||
|
||||
**Response:** `List[SpaceNode]`
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"node_id": "node:03",
|
||||
"name": "Quantum Relay",
|
||||
"microdao": "microdao:7",
|
||||
"gpu": {
|
||||
"load": 0.72,
|
||||
"vram_used": 30.1,
|
||||
"vram_total": 40.0,
|
||||
"temperature": 71
|
||||
},
|
||||
"cpu": { "load": 0.44, "temperature": 62 },
|
||||
"memory": { "used": 11.2, "total": 32.0 },
|
||||
"network": {
|
||||
"latency": 12,
|
||||
"bandwidth_in": 540,
|
||||
"bandwidth_out": 430,
|
||||
"packet_loss": 0.01
|
||||
},
|
||||
"agents": 14,
|
||||
"status": "healthy"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **GET** `/space/events`
|
||||
|
||||
Поточні Space/DAO/Node події
|
||||
|
||||
**Query Parameters:**
|
||||
- `seconds` (optional): Time window in seconds (default: 120)
|
||||
|
||||
**Response:** `List[SpaceEvent]`
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "dao.vote.opened",
|
||||
"dao_id": "dao:3",
|
||||
"timestamp": 1735680041,
|
||||
"severity": "info",
|
||||
"meta": {
|
||||
"proposal_id": "P-173",
|
||||
"title": "Budget Allocation 2025"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Схема агрегації даних
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Space Service │
|
||||
│ (Port: 7002) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
|
||||
│ microDAO │ │ Node │ │ Agent │
|
||||
│ Service │ │ Metrics │ │ Registry │
|
||||
└─────────────┘ └─────────────┘ └──────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ NATS │ │ Redis / │
|
||||
│ JetStream │ │ Timescale │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Джерела даних
|
||||
|
||||
| Endpoint | Джерела | NATS Subject |
|
||||
| --------------- | ------------------------------------- | --------------------- |
|
||||
| `/planets` | microDAO service + Node metrics | `dao.state.*` |
|
||||
| `/nodes` | NodeMetrics Agent → NATS | `node.metrics.*` |
|
||||
| `/events` | JetStream Stream | `events.space.*` |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Конфігурація
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Service
|
||||
LOG_LEVEL=INFO
|
||||
ENVIRONMENT=development
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
# NATS
|
||||
NATS_URL=nats://nats:4222
|
||||
|
||||
# CORS
|
||||
CORS_ORIGINS=http://localhost:8899,https://daarion.city
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Тестування
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:7002/health
|
||||
|
||||
# Get planets
|
||||
curl http://localhost:7002/space/planets
|
||||
|
||||
# Get nodes
|
||||
curl http://localhost:7002/space/nodes
|
||||
|
||||
# Get events (last 60 seconds)
|
||||
curl "http://localhost:7002/space/events?seconds=60"
|
||||
|
||||
# Через API Gateway
|
||||
curl http://localhost:8080/space/planets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Документація
|
||||
|
||||
- **OpenAPI Docs:** http://localhost:7002/docs
|
||||
- **ReDoc:** http://localhost:7002/redoc
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Roadmap
|
||||
|
||||
### Phase 1: Mock Data ✅
|
||||
- [x] FastAPI application
|
||||
- [x] Mock planets/nodes/events
|
||||
- [x] OpenAPI documentation
|
||||
- [x] Docker setup
|
||||
|
||||
### Phase 2: Real Data Integration (Current)
|
||||
- [ ] NATS client integration
|
||||
- [ ] Redis client for metrics
|
||||
- [ ] Real-time node metrics
|
||||
- [ ] DAO state integration
|
||||
- [ ] Event stream from JetStream
|
||||
|
||||
### Phase 3: Advanced Features
|
||||
- [ ] Anomaly detection algorithm
|
||||
- [ ] Governance temperature calculation
|
||||
- [ ] Predictive analytics
|
||||
- [ ] WebSocket support
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
Proprietary — DAARION Ecosystem
|
||||
|
||||
|
||||
|
||||
|
||||
239
services/space-service/main.py
Normal file
239
services/space-service/main.py
Normal file
@@ -0,0 +1,239 @@
|
||||
"""
|
||||
DAARION Space Service
|
||||
|
||||
Агрегатор даних для Space Dashboard (planets, nodes, events)
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Query
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List, Optional, Dict, Any
|
||||
import logging
|
||||
|
||||
# Logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(
|
||||
title="DAARION Space Service",
|
||||
version="1.0.0",
|
||||
description="Space data aggregator for DAARION cosmic layer"
|
||||
)
|
||||
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # TODO: обмежити в production
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
# Models
|
||||
# ============================================================================
|
||||
|
||||
class Position3D(BaseModel):
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
|
||||
|
||||
class SpacePlanetSatellite(BaseModel):
|
||||
node_id: str
|
||||
gpu_load: float = Field(ge=0, le=1)
|
||||
latency: float
|
||||
agents: int
|
||||
|
||||
|
||||
class SpacePlanet(BaseModel):
|
||||
dao_id: str
|
||||
name: str
|
||||
health: str = Field(pattern="^(good|warn|critical)$")
|
||||
treasury: float
|
||||
activity: float = Field(ge=0, le=1)
|
||||
governance_temperature: float
|
||||
anomaly_score: float
|
||||
position: Position3D
|
||||
node_count: int
|
||||
satellites: List[SpacePlanetSatellite]
|
||||
|
||||
|
||||
class SpaceNodeGpu(BaseModel):
|
||||
load: float = Field(ge=0, le=1)
|
||||
vram_used: float
|
||||
vram_total: float
|
||||
temperature: float
|
||||
|
||||
|
||||
class SpaceNodeCpu(BaseModel):
|
||||
load: float = Field(ge=0, le=1)
|
||||
temperature: float
|
||||
|
||||
|
||||
class SpaceNodeMemory(BaseModel):
|
||||
used: float
|
||||
total: float
|
||||
|
||||
|
||||
class SpaceNodeNetwork(BaseModel):
|
||||
latency: float
|
||||
bandwidth_in: float
|
||||
bandwidth_out: float
|
||||
packet_loss: float
|
||||
|
||||
|
||||
class SpaceNode(BaseModel):
|
||||
node_id: str
|
||||
name: str
|
||||
microdao: str
|
||||
gpu: SpaceNodeGpu
|
||||
cpu: SpaceNodeCpu
|
||||
memory: SpaceNodeMemory
|
||||
network: SpaceNodeNetwork
|
||||
agents: int
|
||||
status: str = Field(pattern="^(healthy|degraded|offline)$")
|
||||
|
||||
|
||||
class SpaceEvent(BaseModel):
|
||||
type: str
|
||||
dao_id: Optional[str] = None
|
||||
node_id: Optional[str] = None
|
||||
timestamp: int
|
||||
severity: str = Field(pattern="^(info|warn|error|critical)$")
|
||||
meta: Dict[str, Any]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Mock Data
|
||||
# ============================================================================
|
||||
|
||||
MOCK_PLANETS = [
|
||||
SpacePlanet(
|
||||
dao_id="dao:3",
|
||||
name="Aurora Circle",
|
||||
health="good",
|
||||
treasury=513200,
|
||||
activity=0.84,
|
||||
governance_temperature=72,
|
||||
anomaly_score=0.04,
|
||||
position=Position3D(x=120, y=40, z=-300),
|
||||
node_count=12,
|
||||
satellites=[
|
||||
SpacePlanetSatellite(
|
||||
node_id="node:03",
|
||||
gpu_load=0.66,
|
||||
latency=14,
|
||||
agents=22
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
MOCK_NODES = [
|
||||
SpaceNode(
|
||||
node_id="node:03",
|
||||
name="Quantum Relay",
|
||||
microdao="microdao:7",
|
||||
gpu=SpaceNodeGpu(load=0.72, vram_used=30.1, vram_total=40.0, temperature=71),
|
||||
cpu=SpaceNodeCpu(load=0.44, temperature=62),
|
||||
memory=SpaceNodeMemory(used=11.2, total=32.0),
|
||||
network=SpaceNodeNetwork(latency=12, bandwidth_in=540, bandwidth_out=430, packet_loss=0.01),
|
||||
agents=14,
|
||||
status="healthy"
|
||||
)
|
||||
]
|
||||
|
||||
MOCK_EVENTS = [
|
||||
SpaceEvent(
|
||||
type="dao.vote.opened",
|
||||
dao_id="dao:3",
|
||||
timestamp=1735680041,
|
||||
severity="info",
|
||||
meta={"proposal_id": "P-173", "title": "Budget Allocation 2025"}
|
||||
),
|
||||
SpaceEvent(
|
||||
type="node.alert.overload",
|
||||
node_id="node:05",
|
||||
timestamp=1735680024,
|
||||
severity="warn",
|
||||
meta={"gpu_load": 0.92}
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# API Endpoints
|
||||
# ============================================================================
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
"""Health check endpoint"""
|
||||
return {"status": "healthy", "service": "space-service"}
|
||||
|
||||
|
||||
@app.get("/space/planets", response_model=List[SpacePlanet])
|
||||
async def get_planets():
|
||||
"""
|
||||
Повертає DAO-планети у космічному шарі DAARION
|
||||
|
||||
Джерела даних:
|
||||
- DAO state → microDAO service (PostgreSQL)
|
||||
- Node metrics → NATS node.metrics.*
|
||||
- Space events → NATS JetStream events.space.*
|
||||
"""
|
||||
try:
|
||||
logger.info("Fetching space planets")
|
||||
# TODO: замінити на реальну агрегацію з microDAO service
|
||||
return MOCK_PLANETS
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching planets: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to fetch planets")
|
||||
|
||||
|
||||
@app.get("/space/nodes", response_model=List[SpaceNode])
|
||||
async def get_nodes():
|
||||
"""
|
||||
Повертає усі ноди в космічній мережі DAARION
|
||||
|
||||
Джерела даних:
|
||||
- Node metrics → NATS node.metrics.* → Redis/Timescale
|
||||
- Agent counts → Router → Agent Registry
|
||||
"""
|
||||
try:
|
||||
logger.info("Fetching space nodes")
|
||||
# TODO: замінити на реальні метрики з NATS
|
||||
return MOCK_NODES
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching nodes: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to fetch nodes")
|
||||
|
||||
|
||||
@app.get("/space/events", response_model=List[SpaceEvent])
|
||||
async def get_space_events(
|
||||
seconds: int = Query(default=120, description="Time window in seconds")
|
||||
):
|
||||
"""
|
||||
Поточні DAO/Node/Space події
|
||||
|
||||
Джерела даних:
|
||||
- NATS JetStream events.space.*
|
||||
- DAO events → dao.event.*
|
||||
- Node alerts → node.alerts.*
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Fetching space events (last {seconds}s)")
|
||||
# TODO: замінити на реальні події з JetStream
|
||||
return MOCK_EVENTS
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching events: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to fetch events")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=7002)
|
||||
|
||||
|
||||
|
||||
|
||||
10
services/space-service/requirements.txt
Normal file
10
services/space-service/requirements.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
fastapi==0.109.0
|
||||
uvicorn[standard]==0.27.0
|
||||
pydantic==2.5.3
|
||||
python-dotenv==1.0.0
|
||||
redis==5.0.1
|
||||
asyncio-nats-client==0.11.5
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user