Skip to content

Commit 88e36a0

Browse files
committed
feat: remove JSON filesystem storage
1 parent 5056a58 commit 88e36a0

11 files changed

Lines changed: 106 additions & 732 deletions

POSTGRES.md

Lines changed: 42 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,43 @@
1-
# PostgreSQL Integration for MeshInfo
1+
# PostgreSQL Storage
22

3-
This document describes the PostgreSQL dual-write implementation for MeshInfo.
4-
5-
## Overview
6-
7-
MeshInfo now supports PostgreSQL as an alternative storage backend alongside JSON files. The implementation follows a **dual-write pattern** where:
8-
9-
1. All writes go to **both** JSON files and PostgreSQL (when enabled)
10-
2. Reads can come from **either** JSON or PostgreSQL (configurable)
11-
3. JSON files remain authoritative during the transition period
12-
4. PostgreSQL failures never block JSON operations
3+
MeshInfo uses PostgreSQL as its storage backend. This document covers configuration, schema, and operational guidance.
134

145
## Configuration
156

167
Add the following to your `config.toml`:
178

189
```toml
1910
[storage]
20-
read_from = "json"
21-
write_to = ["json", "postgres"]
11+
read_from = "postgres"
12+
write_to = ["postgres"]
2213

2314
[storage.postgres]
24-
enabled = false
15+
enabled = true
2516
host = "postgres"
2617
port = 5432
2718
database = "meshinfo"
2819
username = "postgres"
29-
password = "password"
30-
min_pool_size = 5
31-
max_pool_size = 20
20+
password = "your_password"
21+
min_pool_size = 1
22+
max_pool_size = 5
3223
```
3324

3425
### Configuration Options
3526

36-
- **`read_from`**: `"json"` or `"postgres"` - Controls where data is loaded from on startup
37-
- **`write_to`**: Array of `["json", "postgres"]` - Controls which backends receive writes
38-
- **`postgres.enabled`**: `true` or `false` - Master switch for PostgreSQL functionality
39-
- **`postgres.host`**: Database server hostname
27+
- **`read_from`**: Must be `"postgres"`
28+
- **`write_to`**: Must be `["postgres"]`
29+
- **`postgres.enabled`**: Must be `true`
30+
- **`postgres.host`**: Database server hostname (use `"localhost"` if not using Docker)
4031
- **`postgres.port`**: Database server port (default: 5432)
4132
- **`postgres.database`**: Database name
4233
- **`postgres.username`**: Database user
4334
- **`postgres.password`**: Database password
44-
- **`postgres.min_pool_size`**: Minimum connection pool size (default: 5)
45-
- **`postgres.max_pool_size`**: Maximum connection pool size (default: 20)
35+
- **`postgres.min_pool_size`**: Minimum connection pool size (default: 1)
36+
- **`postgres.max_pool_size`**: Maximum connection pool size (default: 5)
4637

4738
## Database Schema
4839

49-
The PostgreSQL schema stores data in a relational structure while maintaining compatibility with the JSON format. Key tables include:
40+
The schema is automatically created on first run. Key tables:
5041

5142
- **`nodes`**: Core node information (ID, name, hardware, status)
5243
- **`node_positions`**: Historical position data
@@ -57,147 +48,48 @@ The PostgreSQL schema stores data in a relational structure while maintaining co
5748
- **`chat_messages`**: All chat messages
5849
- **`traceroutes`**: Complete traceroute history (JSONB payloads)
5950

60-
The schema is automatically created on first run when PostgreSQL is enabled.
61-
62-
## Migration
63-
64-
To migrate existing JSON data to PostgreSQL:
65-
66-
### Step 1: Enable PostgreSQL
67-
68-
Update `config.toml`:
69-
```toml
70-
[storage.postgres]
71-
enabled = true
72-
```
73-
74-
### Step 2: Start PostgreSQL
75-
76-
If using Docker Compose, PostgreSQL should already be running. Otherwise, start it:
77-
78-
```bash
79-
docker-compose up -d postgres
80-
```
81-
82-
### Step 3: Run Migration Script
83-
84-
```bash
85-
python scripts/migrate_json_to_postgres.py
86-
```
87-
88-
The script will:
89-
- Connect to PostgreSQL
90-
- Create the database schema if needed
91-
- Import all nodes, chat messages, telemetry, and traceroutes from JSON files
92-
- Preserve all historical data
93-
- Report progress and any errors
94-
95-
### Step 4: Enable Dual-Write
96-
97-
Update `config.toml` to write to both backends:
98-
```toml
99-
[storage]
100-
read_from = "json"
101-
write_to = ["json", "postgres"]
102-
103-
[storage.postgres]
104-
enabled = true
105-
```
106-
107-
### Step 5: Verify Data Consistency
108-
109-
- Monitor logs for any PostgreSQL write errors
110-
- Spot-check the API to ensure data is identical
111-
- Compare record counts between JSON and PostgreSQL
112-
113-
### Step 6: Switch to PostgreSQL Reads
114-
115-
Once confident in data consistency, switch to direct PostgreSQL queries:
116-
```toml
117-
[storage]
118-
read_from = "postgres"
119-
write_to = ["json", "postgres"]
120-
```
121-
122-
**Important**: When `read_from: "postgres"`, the API queries PostgreSQL directly without loading data into memory. This provides:
123-
- Lower memory footprint
124-
- Always up-to-date data from the database
125-
- Better scalability for large datasets
126-
12751
## Architecture
12852

12953
### Write Flow
13054

13155
1. MQTT message received
13256
2. Data stored in memory (MemoryDataStore) for internal use
13357
3. **Real-time write to PostgreSQL** (non-blocking, errors logged)
134-
4. Periodic write to JSON files (every 300 seconds by default)
13558

136-
### Read Flow (JSON mode)
59+
### Read Flow
13760

13861
1. Application starts
139-
2. Data loaded from JSON files into memory
140-
3. API serves from in-memory data structures
141-
4. Fast response times with full dataset in RAM
142-
143-
### Read Flow (PostgreSQL mode)
144-
145-
1. Application starts
146-
2. PostgreSQL connection established (no data loaded into memory)
147-
3. **API queries PostgreSQL directly** for each request
62+
2. PostgreSQL connection established
63+
3. API queries PostgreSQL directly for each request
14864
4. Lower memory footprint, always current data
149-
5. Efficient queries with proper indexing
15065

15166
### Error Handling
15267

15368
- PostgreSQL write failures are logged but **never block** application execution
154-
- If PostgreSQL reads fail, the system automatically falls back to JSON
15569
- Connection pool handles transient network issues
15670
- Failed writes are logged for manual investigation
15771

158-
## Data Retention
159-
160-
- **JSON files**: Limited history (configurable via file-based rotation)
161-
- **PostgreSQL**: Unlimited history (all records preserved indefinitely)
162-
16372
## Performance Considerations
16473

16574
### Real-time Writes
16675

167-
All writes to PostgreSQL happen in real-time as data arrives from MQTT. This ensures:
168-
- Minimal data loss in case of application crash
169-
- Up-to-date data in PostgreSQL at all times
170-
- No batch write delays
76+
All writes happen in real-time as data arrives from MQTT, ensuring minimal data loss on crash.
17177

17278
### Connection Pooling
17379

174-
The implementation uses asyncpg connection pooling (5-20 connections by default) to handle concurrent writes efficiently.
80+
asyncpg connection pooling handles concurrent writes efficiently. Tune `min_pool_size` and `max_pool_size` based on your load.
17581

17682
### Indexing
17783

178-
Key indexes are created on:
179-
- Node IDs
180-
- Timestamps
181-
- Foreign key relationships
182-
183-
This ensures fast queries even with large datasets.
184-
185-
## Backwards Compatibility
186-
187-
The implementation fully supports:
188-
189-
1. **Running without PostgreSQL**: Simply don't enable it in config
190-
2. **Downgrading to JSON-only**: Set `postgres.enabled: false` and restart
191-
3. **JSON as authoritative source**: Keep `read_from: "json"` during transition
84+
Key indexes are maintained on node IDs, timestamps, and foreign key relationships for fast queries even with large datasets.
19285

19386
## Monitoring
19487

19588
PostgreSQL operations are logged at INFO and ERROR levels:
19689

19790
```
198-
INFO: PostgreSQL connection pool established
199-
INFO: Loaded 1234 nodes from PostgreSQL
200-
ERROR: Failed to write node abc123 to PostgreSQL: connection timeout
91+
INFO: PostgreSQL mode: Data will be queried directly from database
92+
ERROR: Failed to write node abc123 to Postgres: connection timeout
20193
```
20294

20395
Monitor these logs to ensure healthy operation.
@@ -206,54 +98,39 @@ Monitor these logs to ensure healthy operation.
20698

20799
### Connection Failures
208100

209-
If PostgreSQL connection fails:
210-
1. Check that PostgreSQL container is running
211-
2. Verify connection settings in config.toml
212-
3. Check network connectivity
213-
4. Review PostgreSQL logs
101+
If PostgreSQL connection fails on startup, MeshInfo will log the error and exit. Check:
214102

215-
The application will continue running with JSON-only mode.
103+
1. PostgreSQL container/service is running
104+
2. Connection settings in `config.toml` are correct (`host`, `port`, `username`, `password`)
105+
3. Network connectivity between MeshInfo and the database
216106

217107
### Data Inconsistencies
218108

219-
To verify data consistency:
220-
221-
1. **Count records**:
222-
```sql
223-
SELECT COUNT(*) FROM nodes;
224-
SELECT COUNT(*) FROM chat_messages;
225-
SELECT COUNT(*) FROM telemetry;
226-
SELECT COUNT(*) FROM traceroutes;
227-
```
228-
229-
2. **Compare with JSON** via API endpoints
109+
To verify record counts:
230110

231-
3. **Check for write errors** in application logs
111+
```sql
112+
SELECT COUNT(*) FROM nodes;
113+
SELECT COUNT(*) FROM chat_messages;
114+
SELECT COUNT(*) FROM telemetry;
115+
SELECT COUNT(*) FROM traceroutes;
116+
```
232117

233-
### Migration Issues
118+
### Migrating from JSON Storage
234119

235-
If migration fails:
236-
1. Check PostgreSQL logs for errors
237-
2. Verify JSON files are valid and readable
238-
3. Ensure sufficient disk space
239-
4. Try migrating data types individually (modify script)
120+
If you are upgrading from an older version that used JSON file storage, a one-time migration script is available:
240121

241-
## Future Enhancements
122+
```bash
123+
docker exec -it meshinfo-meshinfo-1 python3 scripts/migrate_json_to_postgres.py
124+
```
242125

243-
Potential future improvements:
244-
- Write-ahead log for failed PostgreSQL writes
245-
- Automatic retry logic with exponential backoff
246-
- Data validation and integrity checks
247-
- Performance metrics and monitoring
248-
- Support for read replicas
249-
- Automatic failover between backends
126+
This reads your existing JSON data files and imports them into PostgreSQL. Run it once before switching to PostgreSQL-only mode.
250127

251128
## Security
252129

253130
- Use strong passwords for PostgreSQL
254-
- Consider using SSL/TLS for database connections in production
131+
- Consider SSL/TLS for database connections in production
255132
- Restrict database access via network policies
256-
- Regular backups of PostgreSQL data
133+
- Set up regular PostgreSQL backups (e.g., `pg_dump`)
257134
- Keep PostgreSQL updated with security patches
258135

259136
## Support

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Realtime web UI to run against a Meshtastic regional or private mesh network.
66

77
## Overview
88

9-
MeshInfo is written in Python and connects to an MQTT server that is receiving Meshtastic messages for the purpose of visualizing and inspecting traffic. It (currently) uses a filesystem to persist content, such as node info and telemetry. There are plans to optionally support Postgres and SQLite3 as optional persistance storage methods.
9+
MeshInfo is written in Python and connects to an MQTT server that is receiving Meshtastic messages for the purpose of visualizing and inspecting traffic. It uses PostgreSQL to persist content such as node info and telemetry.
1010

1111
To make deployment to run an instance for your mesh easy, Docker support is included. We recommend using Docker Compose with a personalized version of the `docker-compose.yml` file to most easily deploy it, but any seasoned Docker user can also use the Docker image alone.
1212

@@ -72,7 +72,7 @@ cd meshinfo
7272

7373
##### Edit Configuration
7474

75-
1. Copy and then edit the `config.toml.sample` to `config.toml` (or `config.json.sample` to `config.json` for legacy JSON format).
75+
1. Copy and then edit the `config.toml.sample` to `config.toml`.
7676
2. Copy `Caddyfile.sample` to `Caddyfile` then edit the `Caddyfile` and be sure it is setup for your hostname (FQDN if requiring Let's Encrypt cert to be generated) and your email address for the TLS line.
7777

7878
- Caddy will request a cert of the FQDN, be sure to specify any subdomain. For example: `https://meshinfo.domain.com`.

0 commit comments

Comments
 (0)