Skip to content

Commit 0e7014f

Browse files
committed
Chksums set support.
1 parent 458b322 commit 0e7014f

File tree

2 files changed

+119
-77
lines changed

2 files changed

+119
-77
lines changed

src/android/BackgroundMode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ private void setChannels(JSONObject channels) {
195195
editor.putString("gMyChannel" + channelName, channelData.optString("channel"));
196196
editor.putString("gMyChannelDec" + channelName, channelData.optString("channel_dec"));
197197
editor.putString("gAddrPortInput" + channelName, channelData.optString("server"));
198-
editor.putString("gMsgChksum" + channelName, channelData.optString("msg_chksum"));
198+
editor.putString("gMsgChksums" + channelName, channelData.optString("msg_chksums"));
199+
//Log.d(TAG, "Channel data chksums: " + channelData.optString("msg_chksums"));
199200
}
200201

201202
// Save active channels list

src/android/MlesMonitor.java

Lines changed: 117 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import java.util.List;
1818
import java.util.Map;
1919
import java.util.concurrent.TimeUnit;
20+
import java.util.HashSet;
21+
import java.util.Set;
2022

2123
import okhttp3.OkHttpClient;
2224
import okhttp3.Request;
@@ -303,9 +305,6 @@ private void onNetworkLost() {
303305
connections.clear();
304306
}
305307

306-
/**
307-
* Parse channels from JSON string passed via Intent
308-
*/
309308
private List<ChannelConfig> parseChannelsJson(String channelsJson) {
310309
List<ChannelConfig> channels = new ArrayList<>();
311310

@@ -327,7 +326,7 @@ private List<ChannelConfig> parseChannelsJson(String channelsJson) {
327326
String channel = data.optString("channel", null);
328327
String channel_dec = data.optString("channel_dec", null);
329328
String serverPort = data.optString("server", "mles.io:443");
330-
String msgChksum = data.optString("msg_chksum", "0");
329+
String msgChksums = data.optString("msg_chksums", "[]"); // Changed from msg_chksum to msg_chksums
331330

332331
if (userName == null || channel == null || userName.isEmpty() || channel.isEmpty()) {
333332
//Log.w(TAG, "Skipping channel, missing data: " + channelName);
@@ -351,8 +350,8 @@ private List<ChannelConfig> parseChannelsJson(String channelsJson) {
351350
}
352351
}
353352

354-
//Log.d(TAG, "Parsed channel: " + channel + " channel_dec: " + channel_dec + " user: " + userName + " @ " + server + ":" + port + " chksum: " + msgChksum);
355-
channels.add(new ChannelConfig(userName, channel, channel_dec, server, port, msgChksum));
353+
//Log.d(TAG, "Parsed channel: " + channel + " channel_dec: " + channel_dec + " user: " + userName + " @ " + server + ":" + port + " chksums: " + msgChksums);
354+
channels.add(new ChannelConfig(userName, channel, channel_dec, server, port, msgChksums));
356355
}
357356
} catch (Exception e) {
358357
Log.e(TAG, "Error parsing channels JSON", e);
@@ -370,27 +369,77 @@ private static class ChannelConfig {
370369
String channelDecrypted;
371370
String server;
372371
int port;
373-
String msgChksum;
372+
String msgChksumsJson; // Store checksums as JSON string
373+
private Set<String> checksumsCache;
374+
private String latestChecksum;
374375

375-
ChannelConfig(String userName, String channelName, String channelDecrypted, String server, int port, String msgChksum) {
376+
ChannelConfig(String userName, String channelName, String channelDecrypted, String server, int port, String msgChksumsJson) {
376377
this.userName = userName;
377378
this.channelName = channelName;
378379
this.channelDecrypted = channelDecrypted;
379380
this.server = server;
380381
this.port = port;
381-
this.msgChksum = msgChksum;
382+
this.msgChksumsJson = msgChksumsJson != null ? msgChksumsJson : "[]";
383+
this.checksumsCache = new HashSet<>();
384+
385+
//Log.d(TAG, "ChannelConfig, msgChksumsJson: " + msgChksumsJson);
386+
387+
initChecksumsFromJson();
388+
}
389+
390+
private void initChecksumsFromJson() {
391+
try {
392+
if (!msgChksumsJson.isEmpty() && !msgChksumsJson.equals("[]")) {
393+
org.json.JSONArray array = new org.json.JSONArray(msgChksumsJson);
394+
395+
//Log.d(TAG, "Loaded " + array.length() + " checksums from JSON");
396+
for (int i = 0; i < array.length(); i++) {
397+
String chk = array.getString(i);
398+
checksumsCache.add(chk);
399+
latestChecksum = chk; // last item wins
400+
}
401+
}
402+
else {
403+
// Handle empty or invalid JSON string
404+
Log.w(TAG, "Empty or invalid checksums JSON");
405+
}
406+
} catch (Exception e) {
407+
Log.e(TAG, "Error parsing checksums JSON", e);
408+
}
382409
}
383410

384411
String getWsUrl() {
385412
return "wss://" + server + ":" + port;
386413
}
387414

388-
void setChksum(String msgChksum) {
389-
this.msgChksum = msgChksum;
415+
Set<String> getChksums() {
416+
return checksumsCache;
417+
}
418+
419+
/**
420+
* Get the latest (most recent) checksum
421+
*/
422+
String getLatestChksum() {
423+
return latestChecksum;
390424
}
391425

392-
String getChksum() {
393-
return this.msgChksum;
426+
/**
427+
* Check if a checksum exists in the array
428+
*/
429+
boolean hasChksum(String checksum) {
430+
if (checksum == null) {
431+
return false;
432+
}
433+
return getChksums().contains(checksum);
434+
}
435+
436+
/**
437+
* Add a new checksum to the in-memory array (no persistence)
438+
*/
439+
void addChksum(String checksum) {
440+
if (checksum != null) {
441+
getChksums().add(checksum);
442+
}
394443
}
395444
}
396445

@@ -401,8 +450,7 @@ private List<ChannelConfig> loadChannels() {
401450
List<ChannelConfig> channels = new ArrayList<>();
402451

403452
try {
404-
@SuppressWarnings("deprecation")
405-
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_MULTI_PROCESS);
453+
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
406454
String activeChannelsJson = prefs.getString("gActiveChannelsJSON", null);
407455

408456
if (activeChannelsJson == null || activeChannelsJson.isEmpty()) {
@@ -431,9 +479,6 @@ private List<ChannelConfig> loadChannels() {
431479
return channels;
432480
}
433481

434-
/**
435-
* Save channels to cache for process restart recovery
436-
*/
437482
private void saveChannelsToCache(List<ChannelConfig> channels) {
438483
if (channels == null || channels.isEmpty()) {
439484
//Log.d(TAG, "No channels to save to cache");
@@ -453,7 +498,7 @@ private void saveChannelsToCache(List<ChannelConfig> channels) {
453498
channelJson.put("channelDecrypted", config.channelDecrypted);
454499
channelJson.put("server", config.server);
455500
channelJson.put("port", config.port);
456-
channelJson.put("msgChksum", config.msgChksum);
501+
channelJson.put("msgChksumsJson", config.msgChksumsJson); // Changed from msgChksum
457502

458503
cacheJson.put(config.channelName, channelJson);
459504
}
@@ -468,9 +513,6 @@ private void saveChannelsToCache(List<ChannelConfig> channels) {
468513
}
469514
}
470515

471-
/**
472-
* Load channels from cache (for process restart)
473-
*/
474516
private List<ChannelConfig> loadChannelsFromCache() {
475517
List<ChannelConfig> channels = new ArrayList<>();
476518

@@ -497,10 +539,10 @@ private List<ChannelConfig> loadChannelsFromCache() {
497539
String channelDec = channelJson.optString("channelDecrypted", null);
498540
String server = channelJson.optString("server", "mles.io");
499541
int port = channelJson.optInt("port", 443);
500-
String msgChksum = channelJson.optString("msgChksum", "0");
542+
String msgChksumsJson = channelJson.optString("msgChksumsJson", "[]"); // Changed from msgChksum
501543

502544
if (userName != null && channel != null) {
503-
channels.add(new ChannelConfig(userName, channel, channelDec, server, port, msgChksum));
545+
channels.add(new ChannelConfig(userName, channel, channelDec, server, port, msgChksumsJson));
504546
//Log.d(TAG, "Restored channel from cache: " + channel);
505547
}
506548
}
@@ -530,41 +572,43 @@ private void clearChannelsCache() {
530572
/**
531573
* Load configuration for a specific channel
532574
*/
533-
private ChannelConfig loadChannelConfig(SharedPreferences prefs, String channelName) {
534-
try {
535-
String userName = prefs.getString("gMyName" + channelName, null);
536-
String channel = prefs.getString("gMyChannel" + channelName, null);
537-
String channelDec = prefs.getString("gMyChannelDec" + channelName, null);
538-
String addrPort = prefs.getString("gAddrPortInput" + channelName, "mles.io:443");
539-
String msgChksum = prefs.getString("gMsgChksum" + channelName, "0");
540-
541-
//Log.d(TAG, "Channel " + channelName + ", Channel decrypted " + channelDec + ": name=" + userName + ", channel=" + channel + ", server=" + addrPort + ", chksum=" + msgChksum);
542-
543-
// Parse server:port
544-
String server = "mles.io";
545-
int port = 443;
546-
547-
if (addrPort != null && !addrPort.isEmpty()) {
548-
String[] parts = addrPort.split(":");
549-
if (parts.length >= 1 && !parts[0].isEmpty()) {
550-
server = parts[0];
551-
}
552-
if (parts.length >= 2) {
553-
try {
554-
port = Integer.parseInt(parts[1]);
555-
} catch (NumberFormatException e) {
556-
port = 443;
557-
}
558-
}
559-
}
560-
561-
return new ChannelConfig(userName, channel, channelDec, server, port, msgChksum);
562-
563-
} catch (Exception e) {
564-
//Log.e(TAG, "Error loading channel config: " + channelName, e);
565-
return null;
566-
}
567-
}
575+
/**
576+
* Load configuration for a specific channel
577+
*/
578+
private ChannelConfig loadChannelConfig(SharedPreferences prefs, String channelName) {
579+
try {
580+
String userName = prefs.getString("gMyName" + channelName, null);
581+
String channel = prefs.getString("gMyChannel" + channelName, null);
582+
String channelDec = prefs.getString("gMyChannelDec" + channelName, null);
583+
String addrPort = prefs.getString("gAddrPortInput" + channelName, "mles.io:443");
584+
String msgChksums = prefs.getString("gMsgChksums" + channelName, "[]"); // Load array, default to empty array
585+
586+
//Log.d(TAG, "Channel " + channelName + ", Channel decrypted " + channelDec + ": name=" + userName + ", channel=" + channel + ", server=" + addrPort + ", chksums=" + msgChksums);
587+
588+
// Parse server:port
589+
String server = "mles.io";
590+
int port = 443;
591+
if (addrPort != null && !addrPort.isEmpty()) {
592+
String[] parts = addrPort.split(":");
593+
if (parts.length >= 1 && !parts[0].isEmpty()) {
594+
server = parts[0];
595+
}
596+
if (parts.length >= 2) {
597+
try {
598+
port = Integer.parseInt(parts[1]);
599+
} catch (NumberFormatException e) {
600+
port = 443;
601+
}
602+
}
603+
}
604+
605+
return new ChannelConfig(userName, channel, channelDec, server, port, msgChksums);
606+
607+
} catch (Exception e) {
608+
//Log.e(TAG, "Error loading channel config: " + channelName, e);
609+
return null;
610+
}
611+
}
568612

569613
/**
570614
* Connect to a channel via WebSocket
@@ -729,33 +773,31 @@ private void handleMessage(String message, ChannelConfig config) {
729773
}
730774

731775
/**
732-
* Handle incoming message - sync first, then notify on new
776+
* Handle incoming message - sync by matching latest checksum, check against all for duplicates
733777
*/
734778
private void handleMessage(ByteString message, ChannelConfig config) {
735779
byte[] messageBytes = message.toByteArray();
736780

737781
// Compute SipHash with zero key
738782
long hash = SipHash.hash(SIPHASH_KEY, messageBytes);
739783
String hashHex = SipHash.toHexString(hash);
740-
741-
String lastChksum = config.getChksum();
742-
//Log.d(TAG, "Last chksum for channel "+ config.channelName + ": " + lastChksum + ", got " + hashHex + " message: " + message);
743784
Boolean synced = channelSynced.get(config.channelName);
744785
long now = System.currentTimeMillis();
745786

746-
// Not synced yet - waiting for initial checksum match
787+
// Not synced yet - waiting for latest checksum match
747788
if (synced == null || !synced) {
748-
if (lastChksum == null || lastChksum.isEmpty() || lastChksum.equals("0")) {
789+
String latestChksum = config.getLatestChksum();
790+
if (latestChksum == null || latestChksum.isEmpty()) {
749791
// No previous checksum - sync immediately
750-
//Log.d(TAG, "No previous checksum for " + config.channelName + ", synced");
792+
Log.d(TAG, "No previous checksum for " + config.channelName + ", synced");
751793
channelSynced.put(config.channelName, true);
752-
config.setChksum(hashHex);
794+
config.addChksum(hashHex);
753795
if (resyncListener != null) {
754796
resyncListener.onResync(config.channelName);
755797
}
756-
} else if (lastChksum.equals(hashHex)) {
757-
// Found the last known message - now synced
758-
//Log.d(TAG, "Synced to last message on " + config.channelName);
798+
} else if (latestChksum.equals(hashHex)) {
799+
// Found the latest message - now synced
800+
// Log.d(TAG, "Synced to last message on " + config.channelName);
759801
channelSynced.put(config.channelName, true);
760802
syncStartTime.remove(config.channelName);
761803
if (resyncListener != null) {
@@ -770,9 +812,9 @@ private void handleMessage(ByteString message, ChannelConfig config) {
770812
//Log.d(TAG, "Catching up on " + config.channelName + ", waiting for sync");
771813
} else if (now - startTime > SYNC_TIMEOUT_MS) {
772814
// Timeout - sync to latest
773-
//Log.d(TAG, "Sync timeout on " + config.channelName + ", syncing to latest");
815+
// Log.d(TAG, "Sync timeout on " + config.channelName + ", syncing to latest");
774816
channelSynced.put(config.channelName, true);
775-
config.setChksum(hashHex);
817+
config.addChksum(hashHex);
776818
syncStartTime.remove(config.channelName);
777819
if (resyncListener != null) {
778820
resyncListener.onResync(config.channelName);
@@ -785,14 +827,13 @@ private void handleMessage(ByteString message, ChannelConfig config) {
785827
return;
786828
}
787829

788-
// Already synced - check for new messages
789-
if (lastChksum != null && lastChksum.equals(hashHex)) {
790-
// Same message, ignore
830+
if (config.hasChksum(hashHex)) {
831+
// Already seen (original or resend), ignore
791832
return;
792833
}
793834

794835
// New message!
795-
config.setChksum(hashHex);
836+
config.addChksum(hashHex);
796837
//Log.d(TAG, "New message on " + config.channelName + ", checksum: " + hashHex);
797838

798839
if (listener != null) {

0 commit comments

Comments
 (0)