mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-08-05 16:23:14 +02:00
Feature: Add message length limit with live character counter
Implemented 200-character limit for messages due to LoRa/MeshCore constraints: - Added maxlength=200 to textarea - Added live character counter (0 / 200) - Visual warnings: orange at 75%, red at 90% - Counter updates on input, reply, and send - Backend validation with descriptive error message - Added technotes/limity.md documentation about MeshCore limits Based on MeshCore LoRa payload constraints (~180-200 bytes safe limit). This prevents message fragmentation and improves transmission reliability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,13 @@ def send_message():
|
||||
'error': 'Message text cannot be empty'
|
||||
}), 400
|
||||
|
||||
# MeshCore message length limit (~180-200 bytes for LoRa)
|
||||
if len(text) > 200:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': f'Message too long ({len(text)} chars). Maximum 200 characters allowed due to LoRa constraints.'
|
||||
}), 400
|
||||
|
||||
reply_to = data.get('reply_to')
|
||||
|
||||
# Send message via meshcli
|
||||
|
||||
@@ -45,6 +45,11 @@ function setupEventListeners() {
|
||||
}
|
||||
});
|
||||
|
||||
// Character counter
|
||||
input.addEventListener('input', function() {
|
||||
updateCharCounter();
|
||||
});
|
||||
|
||||
// Manual refresh button
|
||||
document.getElementById('refreshBtn').addEventListener('click', function() {
|
||||
loadMessages();
|
||||
@@ -183,6 +188,7 @@ async function sendMessage() {
|
||||
|
||||
if (data.success) {
|
||||
input.value = '';
|
||||
updateCharCounter();
|
||||
showNotification('Message sent', 'success');
|
||||
|
||||
// Reload messages after short delay
|
||||
@@ -205,6 +211,7 @@ async function sendMessage() {
|
||||
function replyTo(username) {
|
||||
const input = document.getElementById('messageInput');
|
||||
input.value = `@[${username}] `;
|
||||
updateCharCounter();
|
||||
input.focus();
|
||||
}
|
||||
|
||||
@@ -362,6 +369,30 @@ function formatTime(timestamp) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update character counter
|
||||
*/
|
||||
function updateCharCounter() {
|
||||
const input = document.getElementById('messageInput');
|
||||
const counter = document.getElementById('charCounter');
|
||||
const length = input.value.length;
|
||||
const maxLength = 200;
|
||||
|
||||
counter.textContent = `${length} / ${maxLength}`;
|
||||
|
||||
// Visual warning when approaching limit
|
||||
if (length >= maxLength * 0.9) {
|
||||
counter.classList.remove('text-muted', 'text-warning');
|
||||
counter.classList.add('text-danger', 'fw-bold');
|
||||
} else if (length >= maxLength * 0.75) {
|
||||
counter.classList.remove('text-muted', 'text-danger');
|
||||
counter.classList.add('text-warning', 'fw-bold');
|
||||
} else {
|
||||
counter.classList.remove('text-warning', 'text-danger', 'fw-bold');
|
||||
counter.classList.add('text-muted');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML to prevent XSS
|
||||
*/
|
||||
|
||||
@@ -31,13 +31,17 @@
|
||||
class="form-control"
|
||||
placeholder="Type a message..."
|
||||
rows="2"
|
||||
maxlength="200"
|
||||
required
|
||||
></textarea>
|
||||
<button type="submit" class="btn btn-primary px-4" id="sendBtn">
|
||||
<i class="bi bi-send"></i> Send
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted">Press Shift+Enter for new line, Enter to send</small>
|
||||
<div class="d-flex justify-content-between">
|
||||
<small class="text-muted">Press Shift+Enter for new line, Enter to send</small>
|
||||
<small id="charCounter" class="text-muted">0 / 200</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
W **MeshCore** obowiązuje **dość rygorystyczny limit długości pojedynczej wiadomości**, wynikający bezpośrednio z ograniczeń LoRa.
|
||||
|
||||
### 🔹 Limit długości wiadomości
|
||||
|
||||
* **Maksymalnie ~200–240 bajtów payloadu**
|
||||
* W praktyce **bezpiecznie przyjmuj ~180–200 bajtów**, bo część danych zajmują:
|
||||
|
||||
* nagłówki protokołu MeshCore,
|
||||
* adresowanie,
|
||||
* metadane routingu,
|
||||
* CRC / kontrola integralności.
|
||||
|
||||
To oznacza:
|
||||
|
||||
* **kilkadziesiąt znaków tekstu** (zależnie od kodowania),
|
||||
* raczej **krótkie komunikaty**, nie „SMS-y” ani tym bardziej bloki tekstu.
|
||||
|
||||
### 🔹 Co się dzieje przy dłuższej wiadomości?
|
||||
|
||||
* MeshCore **tnie ją na fragmenty (fragmentation)**,
|
||||
* fragmenty są wysyłane osobno i składane u odbiorcy,
|
||||
* **każdy fragment zwiększa czas transmisji i ryzyko utraty**, szczególnie:
|
||||
|
||||
* przy niskim SF,
|
||||
* w zatłoczonej sieci,
|
||||
* na dalekich hopach.
|
||||
|
||||
Dlatego:
|
||||
|
||||
> **zalecenie praktyczne:** traktuj MeshCore jak **pager / radio tekstowe**, a nie komunikator.
|
||||
|
||||
### 🔹 Porównanie (dla intuicji)
|
||||
|
||||
* 1 znak ASCII ≈ 1 bajt
|
||||
* 180 bajtów ≈
|
||||
|
||||
* ~180 znaków ASCII
|
||||
* ~90–120 znaków UTF-8 (polskie znaki, emoji → szybciej zjadają limit)
|
||||
|
||||
### 🔹 Dobre praktyki
|
||||
|
||||
* używaj **krótkich, rzeczowych komunikatów**,
|
||||
* unikaj emoji i znaków narodowych, jeśli zasięg/stabilność jest krytyczna,
|
||||
* jeśli musisz przesłać więcej danych:
|
||||
|
||||
* podziel treść logicznie (kilka wiadomości),
|
||||
* rozważ **out-of-band** (np. MeshCore tylko do „powiadomień”).
|
||||
|
||||
Jeśli chcesz, mogę:
|
||||
|
||||
* rozpisać **dokładną strukturę ramki MeshCore (ile bajtów na co)**,
|
||||
* porównać to z **Meshtastic** (tam limity są trochę inne),
|
||||
* albo pomóc dobrać **SF/BW/CR**, żeby fragmentacja była możliwie bezpieczna.
|
||||
Reference in New Issue
Block a user