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:
MarekWo
2025-12-21 14:44:41 +01:00
parent a8393d5815
commit 8d9c2b241c
4 changed files with 96 additions and 1 deletions
+7
View File
@@ -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
+31
View File
@@ -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
*/
+5 -1
View File
@@ -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>
+53
View File
@@ -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 ~200240 bajtów payloadu**
* W praktyce **bezpiecznie przyjmuj ~180200 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
* ~90120 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.