mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Fix
This commit is contained in:
@@ -576,6 +576,7 @@ buck-out/
|
|||||||
|
|
||||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||||
|
|
||||||
|
backend/services/main/.fromchat_instance_id
|
||||||
backend/data
|
backend/data
|
||||||
backend/files
|
backend/files
|
||||||
.vite
|
.vite
|
||||||
|
|||||||
@@ -19,4 +19,4 @@ slowapi>=0.1.9
|
|||||||
firebase_admin>=7.1.0
|
firebase_admin>=7.1.0
|
||||||
PyNaCl>=1.5.0
|
PyNaCl>=1.5.0
|
||||||
numpy
|
numpy
|
||||||
livekit-api>=0.8.0
|
livekit-api>=1.0.0,<2
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status, Request
|
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status, Request
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy import inspect, text
|
from sqlalchemy import inspect, text
|
||||||
@@ -20,6 +22,38 @@ from ..security.profanity import contains_profanity
|
|||||||
from ..security.rate_limit import rate_limit_per_ip
|
from ..security.rate_limit import rate_limit_per_ip
|
||||||
from ..key_lifecycle import destroy_message_keys_for_user
|
from ..key_lifecycle import destroy_message_keys_for_user
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_SERVER_INSTANCE_ID: str | None = None
|
||||||
|
_INSTANCE_ID_FILE = Path(__file__).resolve().parent.parent / ".fromchat_instance_id"
|
||||||
|
|
||||||
|
|
||||||
|
def get_server_instance_id() -> str:
|
||||||
|
"""Stable server fingerprint; UUID generated once and persisted next to the main service package."""
|
||||||
|
global _SERVER_INSTANCE_ID
|
||||||
|
if _SERVER_INSTANCE_ID is not None:
|
||||||
|
return _SERVER_INSTANCE_ID
|
||||||
|
path = _INSTANCE_ID_FILE
|
||||||
|
try:
|
||||||
|
if path.is_file():
|
||||||
|
text = path.read_text(encoding="utf-8").strip()
|
||||||
|
if text:
|
||||||
|
_SERVER_INSTANCE_ID = text
|
||||||
|
return _SERVER_INSTANCE_ID
|
||||||
|
except OSError as exc:
|
||||||
|
_logger.warning("Could not read instance id from %s: %s", path, exc)
|
||||||
|
iid = str(uuid.uuid4())
|
||||||
|
try:
|
||||||
|
path.write_text(iid + "\n", encoding="utf-8")
|
||||||
|
except OSError as exc:
|
||||||
|
_logger.warning(
|
||||||
|
"Could not persist instance id to %s (%s); using in-process id only.",
|
||||||
|
path,
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
_SERVER_INSTANCE_ID = iid
|
||||||
|
return iid
|
||||||
|
|
||||||
|
|
||||||
_FAILED_ATTEMPT_WINDOW_SECONDS = 300
|
_FAILED_ATTEMPT_WINDOW_SECONDS = 300
|
||||||
_FAILED_ATTEMPT_THRESHOLD = 5
|
_FAILED_ATTEMPT_THRESHOLD = 5
|
||||||
@@ -71,6 +105,12 @@ def convert_user(user: User) -> dict:
|
|||||||
"deleted": (user.deleted or user.suspended) or False # Treat suspended as deleted
|
"deleted": (user.deleted or user.suspended) or False # Treat suspended as deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@router.get("/instance_id")
|
||||||
|
def get_instance_id_public():
|
||||||
|
"""Public deploy fingerprint (used when the client changes server host/port)."""
|
||||||
|
return {"instance_id": get_server_instance_id()}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/check_auth")
|
@router.get("/check_auth")
|
||||||
def check_auth(current_user: User = Depends(get_current_user)):
|
def check_auth(current_user: User = Depends(get_current_user)):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,38 +1,57 @@
|
|||||||
import express from 'express';
|
import http from "http";
|
||||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
import type { IncomingMessage } from "http";
|
||||||
import { resolve } from 'path';
|
import type { Duplex } from "stream";
|
||||||
|
import express from "express";
|
||||||
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||||
|
import { resolve } from "path";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = process.env.PORT || 3000;
|
/** Same default as Vite dev server: HTTPS reverse-proxy entry (API + WebSocket on /api). */
|
||||||
const lan = process.env.LAN_IP;
|
const port = Number(process.env.PORT) || 8301;
|
||||||
const backendHost =
|
const backendHost = process.env.BACKEND_HOST || "http://127.0.0.1:8300";
|
||||||
process.env.BACKEND_HOST || (lan ? `http://${lan}:8300` : "http://localhost:8300");
|
const fileStorageHost = process.env.FILE_STORAGE_HOST || "http://localhost:8302";
|
||||||
const fileStorageHost =
|
|
||||||
process.env.FILE_STORAGE_HOST || (lan ? `http://${lan}:8302` : "http://localhost:8302");
|
|
||||||
const filePath = process.env.STATIC_FILE_PATH || ".";
|
const filePath = process.env.STATIC_FILE_PATH || ".";
|
||||||
|
|
||||||
// API proxy middleware
|
// API + WebSocket (e.g. /api/chat/ws) — must attach upgrade on the HTTP server, not app.listen().
|
||||||
app.use('/api', createProxyMiddleware({
|
const apiProxy = createProxyMiddleware({
|
||||||
target: backendHost,
|
target: backendHost,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: { '^/api': '' },
|
pathRewrite: { "^/api": "" },
|
||||||
ws: true
|
ws: true,
|
||||||
}));
|
});
|
||||||
|
|
||||||
// File serving proxy middleware
|
app.use("/api", apiProxy);
|
||||||
app.use('/uploads/files', createProxyMiddleware({
|
|
||||||
|
app.use(
|
||||||
|
"/uploads/files",
|
||||||
|
createProxyMiddleware({
|
||||||
target: fileStorageHost,
|
target: fileStorageHost,
|
||||||
changeOrigin: true
|
changeOrigin: true,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Serve static files
|
|
||||||
app.use(express.static(resolve(filePath)));
|
app.use(express.static(resolve(filePath)));
|
||||||
|
|
||||||
// SPA routing - catch all handler for client-side routing
|
|
||||||
app.use((_req, res) => {
|
app.use((_req, res) => {
|
||||||
res.sendFile(resolve(filePath, 'index.html'));
|
res.sendFile(resolve(filePath, "index.html"));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
const server = http.createServer(app);
|
||||||
console.log(`Server launched on http://localhost:${port}`);
|
|
||||||
|
type ProxyWithUpgrade = ReturnType<typeof createProxyMiddleware> & {
|
||||||
|
upgrade?: (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
server.on("upgrade", (req, socket, head) => {
|
||||||
|
const path = req.url?.split("?")[0] ?? "";
|
||||||
|
const upgrade = (apiProxy as ProxyWithUpgrade).upgrade;
|
||||||
|
if (path.startsWith("/api") && upgrade) {
|
||||||
|
upgrade.call(apiProxy, req, socket, head);
|
||||||
|
} else {
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(`Server listening on http://localhost:${port} (API+WS → ${backendHost})`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ export default defineConfig({
|
|||||||
"@fromchat/protocol": path.resolve(__dirname, "./packages/fromchat-protocol/src/index.ts")
|
"@fromchat/protocol": path.resolve(__dirname, "./packages/fromchat-protocol/src/index.ts")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Dev entry on 8301: browser uses same-origin `/api` (HTTP + WebSocket, e.g. `/api/chat/ws`).
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 8301,
|
port: 8301,
|
||||||
@@ -86,7 +87,8 @@ export default defineConfig({
|
|||||||
target: _backendProxy,
|
target: _backendProxy,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, ""),
|
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||||
ws: true
|
ws: true,
|
||||||
|
proxyTimeout: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
allowedHosts: [
|
allowedHosts: [
|
||||||
|
|||||||
Reference in New Issue
Block a user