lowkey-server / main.py
abhy60098's picture
Create main.py
f67dc09 verified
Raw
History Blame Contribute Delete
4.13 kB
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from typing import Dict
import sqlite3
import json
import os
app = FastAPI()
# Enable CORS so your mobile app/web app can connect without security blocks
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Your mounted storage bucket path
DB_PATH = "/data/lowkey.db"
def init_db():
# Ensures the database file is created directly inside your 1GB persistent bucket
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS queue (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender TEXT,
receiver TEXT,
message TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
# Initialize DB on server startup
@app.on_event("startup")
async def startup_event():
init_db()
class ConnectionManager:
def __init__(self):
self.active_connections: Dict[str, WebSocket] = {}
async def connect(self, user_id: str, websocket: WebSocket):
await websocket.accept()
self.active_connections[user_id] = websocket
await self.flush_offline_messages(user_id)
def disconnect(self, user_id: str):
if user_id in self.active_connections:
del self.active_connections[user_id]
async def send_message(self, receiver_id: str, message: dict):
if receiver_id in self.active_connections:
try:
await self.active_connections[receiver_id].send_text(json.dumps(message))
return True
except Exception:
# If sending fails halfway through, fallback to saving offline
self.queue_message(message['sender'], receiver_id, message['text'])
return False
else:
self.queue_message(message['sender'], receiver_id, message['text'])
return False
def queue_message(self, sender, receiver, text):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT INTO queue (sender, receiver, message) VALUES (?, ?, ?)", (sender, receiver, text))
conn.commit()
conn.close()
async def flush_offline_messages(self, user_id: str):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT id, sender, message FROM queue WHERE receiver = ?", (user_id,))
rows = cursor.fetchall()
if rows:
websocket = self.active_connections[user_id]
for row in rows:
msg_id, sender, text = row
payload = {"sender": sender, "text": text, "status": "offline_delivery"}
try:
await websocket.send_text(json.dumps(payload))
except Exception:
conn.close()
return # Stop if user disconnects mid-delivery
cursor.execute("DELETE FROM queue WHERE receiver = ?", (user_id,))
conn.commit()
conn.close()
manager = ConnectionManager()
@app.get("/")
def read_root():
return {"status": "Lowkey Server is up and running 🔥"}
@app.websocket("/ws/{user_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: str):
await manager.connect(user_id, websocket)
try:
while True:
data = await websocket.receive_text()
payload = json.loads(data)
# Action: App client says "I downloaded and saved this safely"
if payload.get("action") == "seen_and_saved":
continue
target_receiver = payload.get("receiver")
msg_data = {
"sender": user_id,
"text": payload.get("text")
}
await manager.send_message(target_receiver, msg_data)
except WebSocketDisconnect:
manager.disconnect(user_id)