mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-28 09:24:15 -04:00
general rebase in order to update payment methods and desktop app
Co-authored-by: Alva Swanson <alvasw@protonmail.com> Co-authored-by: andyheko <haoen.ko@gmail.com> Co-authored-by: Bisq GitHub Admin <51445974+bisq-github-admin-3@users.noreply.github.com> Co-authored-by: BtcContributor <79100296+BtcContributor@users.noreply.github.com> Co-authored-by: cd2357 <cd2357@users.noreply.github.com> Co-authored-by: chimp1984 <chimp1984@gmx.com> Co-authored-by: Chris Beams <chris@beams.io> Co-authored-by: Christoph Atteneder <christoph.atteneder@gmail.com> Co-authored-by: Devin Bileck <603793+devinbileck@users.noreply.github.com> Co-authored-by: ghubstan <36207203+ghubstan@users.noreply.github.com> Co-authored-by: Huey <hueydane@gmail.com> Co-authored-by: Jakub Loucký <jakub.loucky@outlook.cz> Co-authored-by: jmacxx <47253594+jmacxx@users.noreply.github.com> Co-authored-by: KanoczTomas <tomas.kanocz@cnl.sk> Co-authored-by: m52go <735155+m52go@users.noreply.github.com> Co-authored-by: Marcus0x <marcus0x@xrhodium.org> Co-authored-by: MarnixCroes <93143998+MarnixCroes@users.noreply.github.com> Co-authored-by: Martin Harrigan <martinharrigan@gmail.com> Co-authored-by: MwithM <50149324+MwithM@users.noreply.github.com> Co-authored-by: sqrrm <sqrrm@users.noreply.github.com> Co-authored-by: Stan <36207203+ghubstan@users.noreply.github.com> Co-authored-by: Stephan Oeste <emzy@emzy.de> Co-authored-by: Steven Barclay <stejbac@gmail.com> Co-authored-by: WAT <shiido.it@gmail.com> Co-authored-by: wiz <j@wiz.biz> Co-authored-by: xyzmaker123 <84982606+xyzmaker123@users.noreply.github.com>
This commit is contained in:
parent
15a1fe8a36
commit
88578bed10
539 changed files with 27629 additions and 8178 deletions
|
@ -122,7 +122,7 @@ public class Config {
|
|||
public static final int UNSPECIFIED_PORT = -1;
|
||||
public static final String DEFAULT_REGTEST_HOST = "none";
|
||||
public static final int DEFAULT_NUM_CONNECTIONS_FOR_BTC = 9; // down from BitcoinJ default of 12
|
||||
static final String DEFAULT_CONFIG_FILE_NAME = "bisq.properties";
|
||||
static final String DEFAULT_CONFIG_FILE_NAME = "haveno.properties";
|
||||
|
||||
// Static fields that provide access to Config properties in locations where injecting
|
||||
// a Config instance is not feasible. See Javadoc for corresponding static accessors.
|
||||
|
@ -599,7 +599,7 @@ public class Config {
|
|||
|
||||
// Option parsing is strict at the command line, but we relax it now for any
|
||||
// subsequent config file processing. This is for compatibility with pre-1.2.6
|
||||
// versions that allowed unrecognized options in the bisq.properties config
|
||||
// versions that allowed unrecognized options in the haveno.properties config
|
||||
// file and because it follows suit with Bitcoin Core's config file behavior.
|
||||
parser.allowsUnrecognizedOptions();
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import bisq.common.file.FileUtil;
|
|||
import bisq.common.handlers.ResultHandler;
|
||||
import bisq.common.proto.persistable.PersistableEnvelope;
|
||||
import bisq.common.proto.persistable.PersistenceProtoResolver;
|
||||
import bisq.common.util.GcUtil;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
@ -325,7 +326,11 @@ public class PersistenceManager<T extends PersistableEnvelope> {
|
|||
new Thread(() -> {
|
||||
T persisted = getPersisted(fileName);
|
||||
if (persisted != null) {
|
||||
UserThread.execute(() -> resultHandler.accept(persisted));
|
||||
UserThread.execute(() -> {
|
||||
resultHandler.accept(persisted);
|
||||
|
||||
GcUtil.maybeReleaseMemory();
|
||||
});
|
||||
} else {
|
||||
UserThread.execute(orElse);
|
||||
}
|
||||
|
@ -434,7 +439,16 @@ public class PersistenceManager<T extends PersistableEnvelope> {
|
|||
}
|
||||
}
|
||||
|
||||
public void forcePersistNow() {
|
||||
// Tor Bridges settings are edited before app init completes, require persistNow to be forced, see writeToDisk()
|
||||
persistNow(null, true);
|
||||
}
|
||||
|
||||
public void persistNow(@Nullable Runnable completeHandler) {
|
||||
persistNow(completeHandler, false);
|
||||
}
|
||||
|
||||
private void persistNow(@Nullable Runnable completeHandler, boolean force) {
|
||||
long ts = System.currentTimeMillis();
|
||||
try {
|
||||
// The serialisation is done on the user thread to avoid threading issue with potential mutations of the
|
||||
|
@ -444,7 +458,7 @@ public class PersistenceManager<T extends PersistableEnvelope> {
|
|||
// For the write to disk task we use a thread. We do not have any issues anymore if the persistable objects
|
||||
// gets mutated while the thread is running as we have serialized it already and do not operate on the
|
||||
// reference to the persistable object.
|
||||
getWriteToDiskExecutor().execute(() -> writeToDisk(serialized, completeHandler));
|
||||
getWriteToDiskExecutor().execute(() -> writeToDisk(serialized, completeHandler, force));
|
||||
|
||||
long duration = System.currentTimeMillis() - ts;
|
||||
if (duration > 100) {
|
||||
|
@ -457,8 +471,8 @@ public class PersistenceManager<T extends PersistableEnvelope> {
|
|||
}
|
||||
}
|
||||
|
||||
public void writeToDisk(protobuf.PersistableEnvelope serialized, @Nullable Runnable completeHandler) {
|
||||
if (!allServicesInitialized.get()) {
|
||||
private void writeToDisk(protobuf.PersistableEnvelope serialized, @Nullable Runnable completeHandler, boolean force) {
|
||||
if (!allServicesInitialized.get() && !force) {
|
||||
log.warn("Application has not completed start up yet so we do not permit writing data to disk.");
|
||||
if (completeHandler != null) {
|
||||
UserThread.execute(completeHandler);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.common.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CompletableFutureUtils {
|
||||
/**
|
||||
* @param list List of futures
|
||||
* @param <T> The generic type of the future
|
||||
* @return Returns a CompletableFuture with a list of the futures we got as parameter once all futures
|
||||
* are completed (incl. exceptionally completed).
|
||||
*/
|
||||
public static <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> list) {
|
||||
CompletableFuture<Void> allFuturesResult = CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()]));
|
||||
return allFuturesResult.thenApply(v ->
|
||||
list.stream().
|
||||
map(CompletableFuture::join).
|
||||
collect(Collectors.<T>toList())
|
||||
);
|
||||
}
|
||||
}
|
85
common/src/main/java/bisq/common/util/GcUtil.java
Normal file
85
common/src/main/java/bisq/common/util/GcUtil.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* This file is part of Haveno.
|
||||
*
|
||||
* Haveno is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.common.util;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class GcUtil {
|
||||
@Setter
|
||||
private static boolean DISABLE_GC_CALLS = false;
|
||||
private static final int TRIGGER_MEM = 1000;
|
||||
private static final int TRIGGER_MAX_MEM = 3000;
|
||||
private static int totalInvocations;
|
||||
private static long totalGCTime;
|
||||
|
||||
public static void autoReleaseMemory() {
|
||||
if (DISABLE_GC_CALLS)
|
||||
return;
|
||||
|
||||
autoReleaseMemory(TRIGGER_MEM);
|
||||
}
|
||||
|
||||
public static void maybeReleaseMemory() {
|
||||
if (DISABLE_GC_CALLS)
|
||||
return;
|
||||
|
||||
maybeReleaseMemory(TRIGGER_MAX_MEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trigger Threshold for free memory in MB when we invoke the garbage collector
|
||||
*/
|
||||
private static void autoReleaseMemory(long trigger) {
|
||||
UserThread.runPeriodically(() -> maybeReleaseMemory(trigger), 120);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trigger Threshold for free memory in MB when we invoke the garbage collector
|
||||
*/
|
||||
private static void maybeReleaseMemory(long trigger) {
|
||||
long ts = System.currentTimeMillis();
|
||||
long preGcMemory = Runtime.getRuntime().totalMemory();
|
||||
if (preGcMemory > trigger * 1024 * 1024) {
|
||||
System.gc();
|
||||
totalInvocations++;
|
||||
long postGcMemory = Runtime.getRuntime().totalMemory();
|
||||
long duration = System.currentTimeMillis() - ts;
|
||||
totalGCTime += duration;
|
||||
log.info("GC reduced memory by {}. Total memory before/after: {}/{}. Free memory: {}. Took {} ms. Total GC invocations: {} / Total GC time {} sec",
|
||||
Utilities.readableFileSize(preGcMemory - postGcMemory),
|
||||
Utilities.readableFileSize(preGcMemory),
|
||||
Utilities.readableFileSize(postGcMemory),
|
||||
Utilities.readableFileSize(Runtime.getRuntime().freeMemory()),
|
||||
duration,
|
||||
totalInvocations,
|
||||
totalGCTime / 1000d);
|
||||
/* if (DevEnv.isDevMode()) {
|
||||
try {
|
||||
// To see from where we got called
|
||||
throw new RuntimeException("Dummy Exception for print stacktrace at maybeReleaseMemory");
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -58,9 +58,9 @@ public class PermutationUtil {
|
|||
|
||||
public static <T, R> List<T> findMatchingPermutation(R targetValue,
|
||||
List<T> list,
|
||||
BiFunction<R, List<T>, Boolean> predicate,
|
||||
BiPredicate<R, List<T>> predicate,
|
||||
int maxIterations) {
|
||||
if (predicate.apply(targetValue, list)) {
|
||||
if (predicate.test(targetValue, list)) {
|
||||
return list;
|
||||
} else {
|
||||
return findMatchingPermutation(targetValue,
|
||||
|
@ -74,7 +74,7 @@ public class PermutationUtil {
|
|||
private static <T, R> List<T> findMatchingPermutation(R targetValue,
|
||||
List<T> list,
|
||||
List<List<T>> lists,
|
||||
BiFunction<R, List<T>, Boolean> predicate,
|
||||
BiPredicate<R, List<T>> predicate,
|
||||
AtomicInteger maxIterations) {
|
||||
for (int level = 0; level < list.size(); level++) {
|
||||
// Test one level at a time
|
||||
|
@ -90,7 +90,7 @@ public class PermutationUtil {
|
|||
@NonNull
|
||||
private static <T, R> List<T> checkLevel(R targetValue,
|
||||
List<T> previousLevel,
|
||||
BiFunction<R, List<T>, Boolean> predicate,
|
||||
BiPredicate<R, List<T>> predicate,
|
||||
int level,
|
||||
int permutationIndex,
|
||||
AtomicInteger maxIterations) {
|
||||
|
@ -106,7 +106,7 @@ public class PermutationUtil {
|
|||
if (level == 0) {
|
||||
maxIterations.decrementAndGet();
|
||||
// Check all permutations on this level
|
||||
if (predicate.apply(targetValue, newList)) {
|
||||
if (predicate.test(targetValue, newList)) {
|
||||
return newList;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -17,18 +17,30 @@
|
|||
|
||||
package bisq.common.util;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Profiler {
|
||||
public static void printSystemLoadPeriodically(long delay, TimeUnit timeUnit) {
|
||||
UserThread.runPeriodically(Profiler::printSystemLoad, delay, timeUnit);
|
||||
}
|
||||
|
||||
public static void printSystemLoad() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long free = runtime.freeMemory() / 1024 / 1024;
|
||||
long total = runtime.totalMemory() / 1024 / 1024;
|
||||
long free = runtime.freeMemory();
|
||||
long total = runtime.totalMemory();
|
||||
long used = total - free;
|
||||
|
||||
log.info("System report: Used memory: {} MB; Free memory: {} MB; Total memory: {} MB; No. of threads: {}",
|
||||
used, free, total, Thread.activeCount());
|
||||
log.info("Total memory: {}; Used memory: {}; Free memory: {}; Max memory: {}; No. of threads: {}",
|
||||
Utilities.readableFileSize(total),
|
||||
Utilities.readableFileSize(used),
|
||||
Utilities.readableFileSize(free),
|
||||
Utilities.readableFileSize(runtime.maxMemory()),
|
||||
Thread.activeCount());
|
||||
}
|
||||
|
||||
public static long getUsedMemoryInMB() {
|
||||
|
|
|
@ -19,12 +19,8 @@ package bisq.common.util;
|
|||
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
@ -52,9 +48,11 @@ import java.nio.file.Paths;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
@ -85,15 +83,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
@Slf4j
|
||||
public class Utilities {
|
||||
public static String objectToJson(Object object) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new AnnotationExclusionStrategy())
|
||||
/*.excludeFieldsWithModifiers(Modifier.TRANSIENT)*/
|
||||
/* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)*/
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
return gson.toJson(object);
|
||||
}
|
||||
|
||||
public static ExecutorService getSingleThreadExecutor(String name) {
|
||||
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
|
@ -337,12 +326,12 @@ public class Utilities {
|
|||
|
||||
public static void openURI(URI uri) throws IOException {
|
||||
if (!DesktopUtil.browse(uri))
|
||||
throw new IOException("Failed to open URI: " + uri.toString());
|
||||
throw new IOException("Failed to open URI: " + uri);
|
||||
}
|
||||
|
||||
public static void openFile(File file) throws IOException {
|
||||
if (!DesktopUtil.open(file))
|
||||
throw new IOException("Failed to open file: " + file.toString());
|
||||
throw new IOException("Failed to open file: " + file);
|
||||
}
|
||||
|
||||
public static String getDownloadOfHomeDir() {
|
||||
|
@ -447,18 +436,6 @@ public class Utilities {
|
|||
return new File(Utilities.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getPath();
|
||||
}
|
||||
|
||||
private static class AnnotationExclusionStrategy implements ExclusionStrategy {
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return f.getAnnotation(JsonExclude.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toTruncatedString(Object message) {
|
||||
return toTruncatedString(message, 200, true);
|
||||
}
|
||||
|
@ -480,6 +457,16 @@ public class Utilities {
|
|||
|
||||
}
|
||||
|
||||
public static List<String> toListOfWrappedStrings(String s, int wrapLength) {
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
int i = 0;
|
||||
while (i + wrapLength < sb.length() && (i = sb.lastIndexOf(" ", i + wrapLength)) != -1) {
|
||||
sb.replace(i, i + 1, "\n");
|
||||
}
|
||||
String[] splitLine = sb.toString().split("\n");
|
||||
return Arrays.asList(splitLine);
|
||||
}
|
||||
|
||||
public static String getRandomPrefix(int minLength, int maxLength) {
|
||||
int length = minLength + new Random().nextInt(maxLength - minLength + 1);
|
||||
String result;
|
||||
|
@ -539,6 +526,34 @@ public class Utilities {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static byte[] copyRightAligned(byte[] src, int newLength) {
|
||||
byte[] dest = new byte[newLength];
|
||||
int srcPos = Math.max(src.length - newLength, 0);
|
||||
int destPos = Math.max(newLength - src.length, 0);
|
||||
System.arraycopy(src, srcPos, dest, destPos, newLength - destPos);
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static byte[] intsToBytesBE(int[] ints) {
|
||||
byte[] bytes = new byte[ints.length * 4];
|
||||
int i = 0;
|
||||
for (int v : ints) {
|
||||
bytes[i++] = (byte) (v >> 24);
|
||||
bytes[i++] = (byte) (v >> 16);
|
||||
bytes[i++] = (byte) (v >> 8);
|
||||
bytes[i++] = (byte) v;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static int[] bytesToIntsBE(byte[] bytes) {
|
||||
int[] ints = new int[bytes.length / 4];
|
||||
for (int i = 0, j = 0; i < bytes.length / 4; i++) {
|
||||
ints[i] = Ints.fromBytes(bytes[j++], bytes[j++], bytes[j++], bytes[j++]);
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
// Helper to filter unique elements by key
|
||||
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
|
||||
Map<Object, Boolean> map = new ConcurrentHashMap<>();
|
||||
|
@ -591,4 +606,8 @@ public class Utilities {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String cleanString(String string) {
|
||||
return string.replaceAll("[\\t\\n\\r]+", " ");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue