Online_fix2

main
Satur@it-depot.ru 2025-03-07 10:58:48 +03:00
parent 0acdb5f1b8
commit 73cb28284d
2 changed files with 258 additions and 12 deletions

10
app.py
View File

@ -119,8 +119,12 @@ async def root():
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
self.max_connections = 100 # Ограничение числа подключений
async def connect(self, websocket: WebSocket):
if len(self.active_connections) >= self.max_connections:
await websocket.close(code=1008, reason="Too many connections")
return
await websocket.accept()
self.active_connections.append(websocket)
@ -128,7 +132,7 @@ class ConnectionManager:
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections:
for connection in self.active_connections[:]: # Копируем список для безопасного удаления
await connection.send_text(message)
manager = ConnectionManager()
@ -359,7 +363,7 @@ async def upload_image(install_id: int = Form(...), file: UploadFile = File(...)
# CORS для API
api_app.add_middleware(
CORSMiddleware,
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
allow_origins=["https://rd.it-depot.ru"], # Обновлено для HTTPS
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
@ -368,7 +372,7 @@ api_app.add_middleware(
# CORS для веб-интерфейса
web_app.add_middleware(
CORSMiddleware,
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
allow_origins=["https://rd.it-depot.ru"], # Обновлено для HTTPS
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@ -8,10 +8,252 @@
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/themes/default/style.min.css">
<style>
/* Существующие стили остаются без изменений */
.status-online { background-color: green; width: 10px; height: 10px; display: inline-block; border-radius: 50%; margin-left: 5px; }
.status-offline { background-color: red; width: 10px; height: 10px; display: inline-block; border-radius: 50%; margin-left: 5px; }
/* Остальные стили остаются без изменений */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
height: 100vh;
background-color: #f4f4f4;
}
body.dark-theme {
background-color: #222;
color: #fff;
}
#tree-container, #installs-container, #notes-panel {
overflow: auto;
}
#tree-container {
width: 250px;
min-width: 200px;
border-right: 1px solid #ccc;
padding: 10px;
background-color: #fff;
}
#tree-container.dark-theme {
border-right-color: #444;
background-color: #333;
}
#installs-container {
flex-grow: 1;
padding: 10px;
background-color: #fff;
}
#installs-container.dark-theme {
background-color: #333;
}
#notes-panel {
width: 300px;
min-width: 200px;
border-left: 1px solid #ccc;
padding: 10px;
background-color: #fff;
}
#notes-panel.dark-theme {
border-left-color: #444;
background-color: #333;
}
#splitter {
width: 5px;
background-color: #ccc;
cursor: col-resize;
position: relative;
z-index: 10;
}
#splitter.dark-theme {
background-color: #444;
}
.header-logo {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.header-logo img {
height: 40px;
margin-right: 10px;
}
.theme-toggle, #add-record-button {
padding: 5px 10px;
cursor: pointer;
}
.theme-toggle.dark-theme, #add-record-button.dark-theme {
background-color: #555;
color: #fff;
border: 1px solid #777;
}
.export-import-container {
margin-bottom: 10px;
}
#search-container {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
#search-container.dark-theme input, #search-container.dark-theme select {
background-color: #444;
color: #fff;
border: 1px solid #666;
}
.header {
display: flex;
justify-content: space-between;
font-weight: bold;
padding: 5px;
background-color: #e0e0e0;
cursor: pointer;
}
.header.dark-theme {
background-color: #444;
}
.header div {
flex: 1;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.sort-arrow {
margin-left: 5px;
}
.install-item {
display: flex;
justify-content: space-between;
padding: 5px;
border-bottom: 1px solid #ddd;
cursor: pointer;
align-items: center;
}
.install-item.dark-theme {
border-bottom-color: #555;
background-color: #444;
}
.install-item:hover {
background-color: #f0f0f0;
}
.install-item.dark-theme:hover {
background-color: #555;
}
.install-item.selected {
background-color: #d0d0d0;
}
.install-item.dark-theme.selected {
background-color: #666;
}
.computer-name, .connection-id, .install-time, .actions {
flex: 1;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
}
.protocol-icon {
vertical-align: middle;
height: 16px;
width: 16px;
margin-right: 5px;
}
.connection-link {
color: #007bff;
text-decoration: none;
flex-grow: 1;
}
.connection-link.dark-theme {
color: #66b0ff;
}
.action-buttons button {
margin: 0 2px;
padding: 2px 5px;
}
.action-buttons.dark-theme button {
background-color: #555;
color: #fff;
border: 1px solid #777;
}
#notes-content {
padding: 10px;
min-height: 200px;
border: 1px solid #ccc;
}
#notes-content.dark-theme {
border-color: #444;
background-color: #444;
}
#modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
#add-modal, #note-modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
padding: 20px;
border-radius: 5px;
z-index: 1001;
width: 400px;
}
#add-modal.dark-theme, #note-modal.dark-theme {
background: #333;
color: #fff;
}
#add-modal input, #add-modal select, #add-modal textarea,
#note-modal textarea {
width: 100%;
margin-bottom: 10px;
padding: 5px;
}
#add-modal.dark-theme input, #add-modal.dark-theme select, #add-modal.dark-theme textarea,
#note-modal.dark-theme textarea {
background-color: #444;
color: #fff;
border: 1px solid #666;
}
.markdown-buttons, .image-upload {
margin-bottom: 10px;
}
.time-hint {
font-size: 0.8em;
color: #666;
}
.time-hint.dark-theme {
color: #bbb;
}
.status-online {
background-color: green;
width: 10px;
height: 10px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
margin-left: 5px;
}
.status-offline {
background-color: red;
width: 10px;
height: 10px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
margin-left: 5px;
}
.highlight {
background-color: #e0e0e0;
}
.highlight.dark-theme {
background-color: #555;
}
</style>
</head>
<body>
@ -157,7 +399,7 @@
const containerRect = document.body.getBoundingClientRect();
let newWidth = e.clientX - containerRect.left;
const minWidth = parseInt(getComputedStyle(treeContainer).minWidth, 10);
const minWidth = 200;
const maxWidth = containerRect.width * 0.5;
if (newWidth < minWidth) newWidth = minWidth;
@ -194,7 +436,6 @@
$(items[currentIndex])[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
});
// Подключение к WebSocket
connectWebSocket();
});
@ -360,7 +601,8 @@
if (ws) {
ws.close();
}
ws = new WebSocket(`ws://${window.location.host}/ws`);
// Используем wss для соответствия HTTPS
ws = new WebSocket(`wss://${window.location.host}/ws`);
ws.onmessage = function(event) {
allInstalls = JSON.parse(event.data);
displayInstalls(allInstalls.filter(i => !selectedFolderId || i.folder_id == selectedFolderId));
@ -438,7 +680,7 @@
return `
<div class="install-item ${isDarkTheme ? 'dark-theme' : ''}" data-id="${item.id}" draggable="true">
<div class="computer-name">${item.computer_name} <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'computer_name', '${item.computer_name}')">✏️</button></div>
<div class="connection-id"><span class="protocol-icon">${protocolIcons[item.protocol]}</span><a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link ${isDarkTheme ? 'dark-theme' : ''}" target="_blank">${item.rust_id}</a> <span class="${statusClass}"></span> <button class="copy-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="copyToClipboard('${item.rust_id}')">📋</button> <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')">✏️</button></div>
<div class="connection-id"><span class="protocol-icon">${protocolIcons[item.protocol]}</span><a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link ${isDarkTheme ? 'dark-theme' : ''}" target="_blank">${item.rust_id}</a><span class="${statusClass}"></span> <button class="copy-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="copyToClipboard('${item.rust_id}')">📋</button> <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')">✏️</button></div>
<div class="install-time">${item.install_time} <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'install_time', '${item.install_time}')">✏️</button></div>
<div class="actions"><span class="action-buttons"><button onclick="deleteInstall(${item.id})">Удалить</button> <button class="note-button">Заметка</button></span></div>
</div>
@ -865,7 +1107,7 @@
function formatItalic() {
const textarea = $('#note-textarea');
const start = textarea[0].selectionStart;
const end = textarea[0].selectionEnd;
end = textarea[0].selectionEnd;
const text = textarea.val();
const selected = text.substring(start, end);
const newText = `*${selected}*`;