]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/util/Utils.java
Paralellize profile fetching
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / Utils.java
1 package org.asamk.signal.manager.util;
2
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5 import org.whispersystems.libsignal.IdentityKey;
6 import org.whispersystems.libsignal.fingerprint.Fingerprint;
7 import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
8 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
9 import org.whispersystems.signalservice.api.util.StreamDetails;
10
11 import java.io.BufferedInputStream;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.net.URLConnection;
17 import java.nio.file.Files;
18 import java.util.Locale;
19 import java.util.Spliterator;
20 import java.util.Spliterators;
21 import java.util.function.BiFunction;
22 import java.util.function.Consumer;
23 import java.util.stream.Stream;
24 import java.util.stream.StreamSupport;
25
26 public class Utils {
27
28 private final static Logger logger = LoggerFactory.getLogger(Utils.class);
29
30 public static String getFileMimeType(File file, String defaultMimeType) throws IOException {
31 var mime = Files.probeContentType(file.toPath());
32 if (mime == null) {
33 try (InputStream bufferedStream = new BufferedInputStream(new FileInputStream(file))) {
34 mime = URLConnection.guessContentTypeFromStream(bufferedStream);
35 }
36 }
37 if (mime == null) {
38 return defaultMimeType;
39 }
40 return mime;
41 }
42
43 public static StreamDetails createStreamDetailsFromFile(File file) throws IOException {
44 InputStream stream = new FileInputStream(file);
45 final var size = file.length();
46 final var mime = getFileMimeType(file, "application/octet-stream");
47 return new StreamDetails(stream, mime, size);
48 }
49
50 public static Fingerprint computeSafetyNumber(
51 boolean isUuidCapable,
52 SignalServiceAddress ownAddress,
53 IdentityKey ownIdentityKey,
54 SignalServiceAddress theirAddress,
55 IdentityKey theirIdentityKey
56 ) {
57 int version;
58 byte[] ownId;
59 byte[] theirId;
60
61 if (isUuidCapable) {
62 // Version 2: UUID user
63 version = 2;
64 ownId = ownAddress.getAci().toByteArray();
65 theirId = theirAddress.getAci().toByteArray();
66 } else {
67 // Version 1: E164 user
68 version = 1;
69 if (!ownAddress.getNumber().isPresent() || !theirAddress.getNumber().isPresent()) {
70 return null;
71 }
72 ownId = ownAddress.getNumber().get().getBytes();
73 theirId = theirAddress.getNumber().get().getBytes();
74 }
75
76 return new NumericFingerprintGenerator(5200).createFor(version,
77 ownId,
78 ownIdentityKey,
79 theirId,
80 theirIdentityKey);
81 }
82
83 public static Locale getDefaultLocale() {
84 final var locale = Locale.getDefault();
85 if (locale == null) {
86 return null;
87 }
88 try {
89 Locale.LanguageRange.parse(locale.getLanguage() + "-" + locale.getCountry());
90 } catch (IllegalArgumentException e) {
91 logger.debug("Invalid locale, ignoring: {}", locale);
92 return null;
93 }
94
95 return locale;
96 }
97
98 public static <L, R, T> Stream<T> zip(Stream<L> leftStream, Stream<R> rightStream, BiFunction<L, R, T> combiner) {
99 Spliterator<L> lefts = leftStream.spliterator();
100 Spliterator<R> rights = rightStream.spliterator();
101 return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(Long.min(lefts.estimateSize(),
102 rights.estimateSize()), lefts.characteristics() & rights.characteristics()) {
103 @Override
104 public boolean tryAdvance(Consumer<? super T> action) {
105 return lefts.tryAdvance(left -> rights.tryAdvance(right -> action.accept(combiner.apply(left, right))));
106 }
107 }, leftStream.isParallel() || rightStream.isParallel());
108 }
109 }