]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/messageCache/MessageCache.java
76e402ad2ab2e3ab493e535b7581777a35927636
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / messageCache / MessageCache.java
1 package org.asamk.signal.manager.storage.messageCache;
2
3 import org.asamk.signal.manager.storage.recipients.RecipientId;
4 import org.asamk.signal.manager.util.IOUtils;
5 import org.asamk.signal.manager.util.MessageCacheUtils;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
9
10 import java.io.File;
11 import java.io.IOException;
12 import java.nio.file.Files;
13 import java.util.Arrays;
14 import java.util.Collections;
15 import java.util.Date;
16 import java.util.Objects;
17 import java.util.stream.Collectors;
18 import java.util.stream.Stream;
19
20 public class MessageCache {
21
22 private final static Logger logger = LoggerFactory.getLogger(MessageCache.class);
23
24 private final File messageCachePath;
25
26 public MessageCache(final File messageCachePath) {
27 this.messageCachePath = messageCachePath;
28 }
29
30 public Iterable<CachedMessage> getCachedMessages() {
31 if (!messageCachePath.exists()) {
32 return Collections.emptyList();
33 }
34
35 return Arrays.stream(Objects.requireNonNull(messageCachePath.listFiles())).flatMap(dir -> {
36 if (dir.isFile()) {
37 return Stream.of(dir);
38 }
39
40 final var files = Objects.requireNonNull(dir.listFiles());
41 if (files.length == 0) {
42 try {
43 Files.delete(dir.toPath());
44 } catch (IOException e) {
45 logger.warn("Failed to delete cache dir “{}”, ignoring: {}", dir, e.getMessage());
46 }
47 return Stream.empty();
48 }
49 return Arrays.stream(files).filter(File::isFile);
50 }).map(CachedMessage::new).collect(Collectors.toList());
51 }
52
53 public CachedMessage cacheMessage(SignalServiceEnvelope envelope, RecipientId recipientId) {
54 final var now = new Date().getTime();
55
56 try {
57 var cacheFile = getMessageCacheFile(recipientId, now, envelope.getTimestamp());
58 MessageCacheUtils.storeEnvelope(envelope, cacheFile);
59 return new CachedMessage(cacheFile);
60 } catch (IOException e) {
61 logger.warn("Failed to store encrypted message in disk cache, ignoring: {}", e.getMessage());
62 return null;
63 }
64 }
65
66 public CachedMessage replaceSender(CachedMessage cachedMessage, RecipientId sender) throws IOException {
67 final var cacheFile = getMessageCacheFile(sender, cachedMessage.getFile().getName());
68 if (cacheFile.equals(cachedMessage.getFile())) {
69 return cachedMessage;
70 }
71 Files.move(cachedMessage.getFile().toPath(), cacheFile.toPath());
72 return new CachedMessage(cacheFile);
73 }
74
75 private File getMessageCachePath(RecipientId recipientId) {
76 if (recipientId == null) {
77 return messageCachePath;
78 }
79
80 var sender = String.valueOf(recipientId.getId());
81 return new File(messageCachePath, sender.replace("/", "_"));
82 }
83
84 private File getMessageCacheFile(RecipientId recipientId, String filename) throws IOException {
85 var cachePath = getMessageCachePath(recipientId);
86 IOUtils.createPrivateDirectories(cachePath);
87 return new File(cachePath, filename);
88 }
89
90 private File getMessageCacheFile(RecipientId recipientId, long now, long timestamp) throws IOException {
91 var cachePath = getMessageCachePath(recipientId);
92 IOUtils.createPrivateDirectories(cachePath);
93 return new File(cachePath, now + "_" + timestamp);
94 }
95
96 public void mergeRecipients(final RecipientId recipientId, final RecipientId toBeMergedRecipientId) {
97 final var toBeMergedMessageCachePath = getMessageCachePath(toBeMergedRecipientId);
98 if (!toBeMergedMessageCachePath.exists()) {
99 return;
100 }
101
102 for (var file : Objects.requireNonNull(toBeMergedMessageCachePath.listFiles())) {
103 if (!file.isFile()) {
104 continue;
105 }
106
107 try {
108 final var cacheFile = getMessageCacheFile(recipientId, file.getName());
109 Files.move(file.toPath(), cacheFile.toPath());
110 } catch (IOException e) {
111 logger.warn("Failed to move cache file “{}”, ignoring: {}", file, e.getMessage());
112 }
113 }
114 }
115 }