mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Merge pull request #765 from hjubb/restore_log_report
Restore log report
This commit is contained in:
commit
d190ac8335
@ -54,15 +54,19 @@ import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
|
||||
import org.thoughtcrime.securesms.database.JobDatabase;
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.database.Storage;
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseModule;
|
||||
import org.thoughtcrime.securesms.groups.OpenGroupManager;
|
||||
import org.thoughtcrime.securesms.home.HomeActivity;
|
||||
import org.thoughtcrime.securesms.groups.OpenGroupManager;
|
||||
import org.thoughtcrime.securesms.home.HomeActivity;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||
import org.thoughtcrime.securesms.jobs.FastJobStorage;
|
||||
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
|
||||
import org.thoughtcrime.securesms.logging.AndroidLogger;
|
||||
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
||||
import org.thoughtcrime.securesms.notifications.BackgroundPollWorker;
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
||||
@ -126,6 +130,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
public Broadcaster broadcaster = null;
|
||||
private Job firebaseInstanceIdJob;
|
||||
private Handler conversationListNotificationHandler;
|
||||
private PersistentLogger persistentLogger;
|
||||
|
||||
@Inject LokiAPIDatabase lokiAPIDatabase;
|
||||
@Inject Storage storage;
|
||||
@ -146,6 +151,10 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
return this.conversationListNotificationHandler;
|
||||
}
|
||||
|
||||
public PersistentLogger getPersistentLogger() {
|
||||
return this.persistentLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
DatabaseModule.init(this);
|
||||
@ -281,7 +290,10 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
}
|
||||
|
||||
private void initializeLogging() {
|
||||
Log.initialize(new AndroidLogger());
|
||||
if (persistentLogger == null) {
|
||||
persistentLogger = new PersistentLogger(this);
|
||||
}
|
||||
Log.initialize(new AndroidLogger(), persistentLogger);
|
||||
}
|
||||
|
||||
private void initializeCrashHandling() {
|
||||
|
@ -123,7 +123,7 @@ class LogFile {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String readEntry() throws IOException {
|
||||
String readEntry() throws IOException {
|
||||
try {
|
||||
Util.readFully(inputStream, ivBuffer);
|
||||
Util.readFully(inputStream, intBuffer);
|
||||
|
@ -0,0 +1,250 @@
|
||||
package org.thoughtcrime.securesms.logging;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.session.libsignal.utilities.ListenableFuture;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
import org.session.libsignal.utilities.NoExternalStorageException;
|
||||
import org.session.libsignal.utilities.SettableFuture;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class PersistentLogger extends Log.Logger {
|
||||
|
||||
private static final String TAG = PersistentLogger.class.getSimpleName();
|
||||
|
||||
private static final String LOG_V = "V";
|
||||
private static final String LOG_D = "D";
|
||||
private static final String LOG_I = "I";
|
||||
private static final String LOG_W = "W";
|
||||
private static final String LOG_E = "E";
|
||||
private static final String LOG_WTF = "A";
|
||||
|
||||
private static final String LOG_DIRECTORY = "log";
|
||||
private static final String FILENAME_PREFIX = "log-";
|
||||
private static final int MAX_LOG_FILES = 5;
|
||||
private static final int MAX_LOG_SIZE = 300 * 1024;
|
||||
private static final int MAX_LOG_EXPORT = 10_000;
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzz");
|
||||
|
||||
private final Context context;
|
||||
private final Executor executor;
|
||||
private final byte[] secret;
|
||||
|
||||
private LogFile.Writer writer;
|
||||
|
||||
public PersistentLogger(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.secret = LogSecretProvider.getOrCreateAttachmentSecret(context);
|
||||
this.executor = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread thread = new Thread(r, "PersistentLogger");
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
return thread;
|
||||
});
|
||||
|
||||
executor.execute(this::initializeWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void v(String tag, String message, Throwable t) {
|
||||
write(LOG_V, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void d(String tag, String message, Throwable t) {
|
||||
write(LOG_D, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void i(String tag, String message, Throwable t) {
|
||||
write(LOG_I, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void w(String tag, String message, Throwable t) {
|
||||
write(LOG_W, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void e(String tag, String message, Throwable t) {
|
||||
write(LOG_E, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wtf(String tag, String message, Throwable t) {
|
||||
write(LOG_WTF, tag, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockUntilAllWritesFinished() {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
executor.execute(latch::countDown);
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
android.util.Log.w(TAG, "Failed to wait for all writes.");
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public ListenableFuture<String> getLogs() {
|
||||
final SettableFuture<String> future = new SettableFuture<>();
|
||||
|
||||
executor.execute(() -> {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
long entriesWritten = 0;
|
||||
|
||||
try {
|
||||
File[] logs = getSortedLogFiles();
|
||||
for (int i = logs.length - 1; i >= 0 && entriesWritten <= MAX_LOG_EXPORT; i--) {
|
||||
try {
|
||||
LogFile.Reader reader = new LogFile.Reader(secret, logs[i]);
|
||||
String entry;
|
||||
while ((entry = reader.readEntry()) != null) {
|
||||
entriesWritten++;
|
||||
builder.append(entry).append('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
android.util.Log.w(TAG, "Failed to read log at index " + i + ". Removing reference.");
|
||||
logs[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
future.set(builder.toString());
|
||||
} catch (NoExternalStorageException e) {
|
||||
future.setException(e);
|
||||
}
|
||||
});
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void initializeWriter() {
|
||||
try {
|
||||
writer = new LogFile.Writer(secret, getOrCreateActiveLogFile());
|
||||
} catch (NoExternalStorageException | IOException e) {
|
||||
android.util.Log.e(TAG, "Failed to initialize writer.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
private void write(String level, String tag, String message, Throwable t) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
if (writer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (writer.getLogSize() >= MAX_LOG_SIZE) {
|
||||
writer.close();
|
||||
writer = new LogFile.Writer(secret, createNewLogFile());
|
||||
trimLogFilesOverMax();
|
||||
}
|
||||
|
||||
for (String entry : buildLogEntries(level, tag, message, t)) {
|
||||
writer.writeEntry(entry);
|
||||
}
|
||||
|
||||
} catch (NoExternalStorageException e) {
|
||||
android.util.Log.w(TAG, "Cannot persist logs.", e);
|
||||
} catch (IOException e) {
|
||||
android.util.Log.w(TAG, "Failed to write line. Deleting all logs and starting over.");
|
||||
deleteAllLogs();
|
||||
initializeWriter();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void trimLogFilesOverMax() throws NoExternalStorageException {
|
||||
File[] logs = getSortedLogFiles();
|
||||
if (logs.length > MAX_LOG_FILES) {
|
||||
for (int i = MAX_LOG_FILES; i < logs.length; i++) {
|
||||
logs[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteAllLogs() {
|
||||
try {
|
||||
File[] logs = getSortedLogFiles();
|
||||
for (File log : logs) {
|
||||
log.delete();
|
||||
}
|
||||
} catch (NoExternalStorageException e) {
|
||||
android.util.Log.w(TAG, "Was unable to delete logs.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getOrCreateActiveLogFile() throws NoExternalStorageException {
|
||||
File[] logs = getSortedLogFiles();
|
||||
if (logs.length > 0) {
|
||||
return logs[0];
|
||||
}
|
||||
|
||||
return createNewLogFile();
|
||||
}
|
||||
|
||||
private File createNewLogFile() throws NoExternalStorageException {
|
||||
return new File(getOrCreateLogDirectory(), FILENAME_PREFIX + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private File[] getSortedLogFiles() throws NoExternalStorageException {
|
||||
File[] logs = getOrCreateLogDirectory().listFiles();
|
||||
if (logs != null) {
|
||||
Arrays.sort(logs, (o1, o2) -> o2.getName().compareTo(o1.getName()));
|
||||
return logs;
|
||||
}
|
||||
return new File[0];
|
||||
}
|
||||
|
||||
private File getOrCreateLogDirectory() throws NoExternalStorageException {
|
||||
File logDir = new File(context.getCacheDir(), LOG_DIRECTORY);
|
||||
if (!logDir.exists() && !logDir.mkdir()) {
|
||||
throw new NoExternalStorageException("Unable to create log directory.");
|
||||
}
|
||||
|
||||
return logDir;
|
||||
}
|
||||
|
||||
private List<String> buildLogEntries(String level, String tag, String message, Throwable t) {
|
||||
List<String> entries = new LinkedList<>();
|
||||
Date date = new Date();
|
||||
|
||||
entries.add(buildEntry(level, tag, message, date));
|
||||
|
||||
if (t != null) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
t.printStackTrace(new PrintStream(outputStream));
|
||||
|
||||
String trace = new String(outputStream.toByteArray());
|
||||
String[] lines = trace.split("\\n");
|
||||
|
||||
for (String line : lines) {
|
||||
entries.add(buildEntry(level, tag, line, date));
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private String buildEntry(String level, String tag, String message, Date date) {
|
||||
return DATE_FORMAT.format(date) + ' ' + level + ' ' + tag + ": " + message;
|
||||
}
|
||||
}
|
@ -85,6 +85,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
helpTranslateButton.setOnClickListener { helpTranslate() }
|
||||
seedButton.setOnClickListener { showSeed() }
|
||||
clearAllDataButton.setOnClickListener { clearAllData() }
|
||||
supportButton.setOnClickListener { shareLogs() }
|
||||
val isLightMode = UiModeUtilities.isDayUiMode(this)
|
||||
oxenLogoImageView.setImageResource(if (isLightMode) R.drawable.oxen_light_mode else R.drawable.oxen_dark_mode)
|
||||
versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||
@ -321,6 +322,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog")
|
||||
}
|
||||
|
||||
private fun shareLogs() {
|
||||
ShareLogsDialog().show(supportFragmentManager,"Share Logs Dialog")
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
private inner class DisplayNameEditActionModeCallback: ActionMode.Callback {
|
||||
|
@ -0,0 +1,65 @@
|
||||
package org.thoughtcrime.securesms.preferences
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.android.synthetic.main.dialog_share_logs.view.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.BuildConfig
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
|
||||
class ShareLogsDialog : BaseDialog() {
|
||||
|
||||
private var shareJob: Job? = null
|
||||
|
||||
override fun setContentView(builder: AlertDialog.Builder) {
|
||||
val contentView =
|
||||
LayoutInflater.from(requireContext()).inflate(R.layout.dialog_share_logs, null)
|
||||
contentView.cancelButton.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
contentView.shareButton.setOnClickListener {
|
||||
// start the export and share
|
||||
shareLogs()
|
||||
}
|
||||
builder.setView(contentView)
|
||||
builder.setCancelable(false)
|
||||
}
|
||||
|
||||
private fun shareLogs() {
|
||||
shareJob?.cancel()
|
||||
shareJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val persistentLogger = ApplicationContext.getInstance(context).persistentLogger
|
||||
try {
|
||||
val logs = persistentLogger.logs.get()
|
||||
val fileName = "${Build.MANUFACTURER}-${Build.DEVICE}-API${Build.VERSION.SDK_INT}-v${BuildConfig.VERSION_NAME}.log"
|
||||
val logUri = BlobProvider().forData(logs.toByteArray())
|
||||
.withFileName(fileName)
|
||||
.withMimeType("text/plain")
|
||||
.createForSingleSessionOnDisk(requireContext(),null)
|
||||
|
||||
val shareIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, logUri)
|
||||
type = "text/plain"
|
||||
}
|
||||
|
||||
dismiss()
|
||||
|
||||
startActivity(Intent.createChooser(shareIntent, getString(R.string.share)))
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(context,"Error saving logs", Toast.LENGTH_LONG).show()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -227,6 +227,18 @@
|
||||
android:gravity="center"
|
||||
android:text="@string/activity_settings_survey_feedback" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/supportButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:text="@string/activity_settings_support" />
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:id="@+id/helpTranslateButton"
|
||||
|
64
app/src/main/res/layout/dialog_share_logs.xml
Normal file
64
app/src/main/res/layout/dialog_share_logs.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@drawable/default_dialog_background_inset"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:elevation="4dp"
|
||||
android:padding="32dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_share_logs_title"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialogDescriptionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_share_logs_explanation"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.Unimportant"
|
||||
android:id="@+id/shareButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="@dimen/medium_spacing"
|
||||
android:text="@string/share" />
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.Small.ThreeBounce"
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
app:SpinKit_Color="@color/accent"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -899,5 +899,8 @@
|
||||
<string name="delete_message_for_everyone">Delete for everyone</string>
|
||||
<string name="delete_message_for_me_and_recipient">Delete for me and %s</string>
|
||||
<string name="activity_settings_survey_feedback">Feedback/Survey</string>
|
||||
<string name="activity_settings_support">Support</string>
|
||||
<string name="dialog_share_logs_title">Share Logs</string>
|
||||
<string name="dialog_share_logs_explanation">Would you like to export your application logs to be able to share for troubleshooting?</string>
|
||||
|
||||
</resources>
|
||||
|
@ -19,7 +19,6 @@ class JobQueue : JobDelegate {
|
||||
private val jobTimestampMap = ConcurrentHashMap<Long, AtomicInteger>()
|
||||
private val rxDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val txDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val attachmentDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
|
||||
private val scope = GlobalScope + SupervisorJob()
|
||||
private val queue = Channel<Job>(UNLIMITED)
|
||||
private val pendingJobIds = mutableSetOf<String>()
|
||||
@ -39,18 +38,15 @@ class JobQueue : JobDelegate {
|
||||
scope.launch {
|
||||
val rxQueue = Channel<Job>(capacity = 4096)
|
||||
val txQueue = Channel<Job>(capacity = 4096)
|
||||
val attachmentQueue = Channel<Job>(capacity = 4096)
|
||||
|
||||
val receiveJob = processWithDispatcher(rxQueue, rxDispatcher)
|
||||
val txJob = processWithDispatcher(txQueue, txDispatcher)
|
||||
val attachmentJob = processWithDispatcher(attachmentQueue, attachmentDispatcher)
|
||||
|
||||
while (isActive) {
|
||||
for (job in queue) {
|
||||
when (job) {
|
||||
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> txQueue.send(job)
|
||||
is AttachmentDownloadJob -> attachmentQueue.send(job)
|
||||
is MessageReceiveJob, is BatchMessageReceiveJob, is TrimThreadJob -> rxQueue.send(job)
|
||||
is MessageReceiveJob, is TrimThreadJob, is BatchMessageReceiveJob, is AttachmentDownloadJob-> rxQueue.send(job)
|
||||
else -> throw IllegalStateException("Unexpected job type.")
|
||||
}
|
||||
}
|
||||
@ -59,7 +55,6 @@ class JobQueue : JobDelegate {
|
||||
// The job has been cancelled
|
||||
receiveJob.cancel()
|
||||
txJob.cancel()
|
||||
attachmentJob.cancel()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsignal.crypto.getRandomElementOrNull
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.successBackground
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
@ -82,7 +81,6 @@ class ClosedGroupPollerV2 {
|
||||
val limit: Long = 12 * 60 * 60 * 1000
|
||||
val a = (Companion.maxPollInterval - minPollInterval).toDouble() / limit.toDouble()
|
||||
val nextPollInterval = a * min(timeSinceLastMessage, limit) + minPollInterval
|
||||
Log.d("Loki", "Next poll interval for closed group with public key: $groupPublicKey is ${nextPollInterval / 1000} s.")
|
||||
executorService?.schedule({
|
||||
poll(groupPublicKey).success {
|
||||
pollRecursively(groupPublicKey)
|
||||
@ -108,7 +106,7 @@ class ClosedGroupPollerV2 {
|
||||
}
|
||||
}
|
||||
promise.fail {
|
||||
Log.d("Loki", "Polling failed for closed group with public key: $groupPublicKey due to error: $it.")
|
||||
Log.d("Loki", "Polling failed for closed group due to error: $it.")
|
||||
}
|
||||
return promise.map { }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user