mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-04-22 10:02:53 +00:00
fix issue with workmanager
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
68cf1b6b89
commit
5204984f9c
5 changed files with 94 additions and 64 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 0.0.99
|
## 0.1.0
|
||||||
|
|
||||||
- New: Groups can now collect flames as well
|
- New: Groups can now collect flames as well
|
||||||
- New: Background execution to pre-load messages
|
- New: Background execution to pre-load messages
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
|
@ -6,6 +7,7 @@ import 'package:twonly/src/constants/keyvalue.keys.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/api.service.dart';
|
import 'package:twonly/src/services/api.service.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||||
|
import 'package:twonly/src/utils/exclusive_access.dart';
|
||||||
import 'package:twonly/src/utils/keyvalue.dart';
|
import 'package:twonly/src/utils/keyvalue.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
@ -14,12 +16,14 @@ import 'package:workmanager/workmanager.dart';
|
||||||
// ignore: unreachable_from_main
|
// ignore: unreachable_from_main
|
||||||
Future<void> initializeBackgroundTaskManager() async {
|
Future<void> initializeBackgroundTaskManager() async {
|
||||||
await Workmanager().initialize(callbackDispatcher);
|
await Workmanager().initialize(callbackDispatcher);
|
||||||
|
await Workmanager().cancelByUniqueName('fetch_data_from_server');
|
||||||
|
|
||||||
await Workmanager().registerPeriodicTask(
|
await Workmanager().registerPeriodicTask(
|
||||||
'fetch_data_from_server',
|
'fetch_data_from_server',
|
||||||
'eu.twonly.periodic_task',
|
'eu.twonly.periodic_task',
|
||||||
frequency: const Duration(minutes: 20),
|
frequency: const Duration(minutes: 20),
|
||||||
initialDelay: const Duration(minutes: 5),
|
initialDelay: const Duration(minutes: 5),
|
||||||
|
existingWorkPolicy: ExistingPeriodicWorkPolicy.update,
|
||||||
constraints: Constraints(
|
constraints: Constraints(
|
||||||
networkType: NetworkType.connected,
|
networkType: NetworkType.connected,
|
||||||
),
|
),
|
||||||
|
|
@ -64,26 +68,35 @@ Future<bool> initBackgroundExecution() async {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> handlePeriodicTask() async {
|
final Mutex _keyValueMutex = Mutex();
|
||||||
final lastExecution =
|
|
||||||
await KeyValueStore.get(KeyValueKeys.lastPeriodicTaskExecution);
|
|
||||||
if (lastExecution == null || !lastExecution.containsKey('timestamp')) {
|
|
||||||
final lastExecutionTime = lastExecution?['timestamp'] as int?;
|
|
||||||
if (lastExecutionTime != null) {
|
|
||||||
final lastExecution =
|
|
||||||
DateTime.fromMillisecondsSinceEpoch(lastExecutionTime);
|
|
||||||
if (DateTime.now().difference(lastExecution).inMinutes < 2) {
|
|
||||||
Log.info(
|
|
||||||
'eu.twonly.periodic_task not executed as last execution was within the last two minutes.',
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Future<void> handlePeriodicTask() async {
|
||||||
|
final shouldBeExecuted = await exclusiveAccess(
|
||||||
|
lockName: 'periodic_task',
|
||||||
|
mutex: _keyValueMutex,
|
||||||
|
action: () async {
|
||||||
|
final lastExecution = await KeyValueStore.get(
|
||||||
|
KeyValueKeys.lastPeriodicTaskExecution,
|
||||||
|
);
|
||||||
|
if (lastExecution != null && lastExecution.containsKey('timestamp')) {
|
||||||
|
final lastExecutionTime = lastExecution['timestamp'] as int?;
|
||||||
|
if (lastExecutionTime != null) {
|
||||||
|
final lastExecutionDate = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
lastExecutionTime,
|
||||||
|
);
|
||||||
|
if (DateTime.now().difference(lastExecutionDate).inMinutes < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, {
|
await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, {
|
||||||
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
||||||
});
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!shouldBeExecuted) return;
|
||||||
|
|
||||||
Log.info('eu.twonly.periodic_task was called.');
|
Log.info('eu.twonly.periodic_task was called.');
|
||||||
|
|
||||||
|
|
@ -91,12 +104,12 @@ Future<bool> handlePeriodicTask() async {
|
||||||
|
|
||||||
if (!await apiService.connect()) {
|
if (!await apiService.connect()) {
|
||||||
Log.info('Could not connect to the api. Returning early.');
|
Log.info('Could not connect to the api. Returning early.');
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiService.isAuthenticated) {
|
if (!apiService.isAuthenticated) {
|
||||||
Log.info('Api is not authenticated. Returning early.');
|
Log.info('Api is not authenticated. Returning early.');
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!globalGotMessageFromServer) {
|
while (!globalGotMessageFromServer) {
|
||||||
|
|
@ -119,7 +132,7 @@ Future<bool> handlePeriodicTask() async {
|
||||||
stopwatch.stop();
|
stopwatch.stop();
|
||||||
|
|
||||||
Log.info('eu.twonly.periodic_task finished after ${stopwatch.elapsed}.');
|
Log.info('eu.twonly.periodic_task finished after ${stopwatch.elapsed}.');
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleProcessingTask() async {
|
Future<void> handleProcessingTask() async {
|
||||||
|
|
|
||||||
51
lib/src/utils/exclusive_access.dart
Normal file
51
lib/src/utils/exclusive_access.dart
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
|
|
||||||
|
Future<T> exclusiveAccess<T>({
|
||||||
|
required String lockName,
|
||||||
|
required Future<T> Function() action,
|
||||||
|
required Mutex mutex,
|
||||||
|
}) async {
|
||||||
|
final lockFile = File('$globalApplicationSupportDirectory/$lockName.lock');
|
||||||
|
return mutex.protect(() async {
|
||||||
|
var lockAcquired = false;
|
||||||
|
|
||||||
|
while (!lockAcquired) {
|
||||||
|
try {
|
||||||
|
lockFile.createSync(exclusive: true);
|
||||||
|
lockAcquired = true;
|
||||||
|
} on FileSystemException catch (e) {
|
||||||
|
final isExists = e is PathExistsException || e.osError?.errorCode == 17;
|
||||||
|
if (!isExists) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final stat = lockFile.statSync();
|
||||||
|
if (stat.type != FileSystemEntityType.notFound) {
|
||||||
|
final age = DateTime.now().difference(stat.modified).inMilliseconds;
|
||||||
|
if (age > 1000) {
|
||||||
|
lockFile.deleteSync();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
await Future.delayed(const Duration(milliseconds: 50));
|
||||||
|
} catch (_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await action();
|
||||||
|
} finally {
|
||||||
|
if (lockAcquired) {
|
||||||
|
try {
|
||||||
|
if (lockFile.existsSync()) {
|
||||||
|
lockFile.deleteSync();
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/utils/exclusive_access.dart';
|
||||||
|
|
||||||
void initLogger() {
|
void initLogger() {
|
||||||
// Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL;
|
// Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL;
|
||||||
|
|
@ -91,46 +92,11 @@ Future<String> readLast1000Lines() async {
|
||||||
final Mutex _logMutex = Mutex();
|
final Mutex _logMutex = Mutex();
|
||||||
|
|
||||||
Future<T> _protectFileAccess<T>(Future<T> Function() action) async {
|
Future<T> _protectFileAccess<T>(Future<T> Function() action) async {
|
||||||
return _logMutex.protect(() async {
|
return exclusiveAccess(
|
||||||
final lockFile = File('$globalApplicationSupportDirectory/app.log.lock');
|
lockName: 'app.log',
|
||||||
var lockAcquired = false;
|
action: action,
|
||||||
|
mutex: _logMutex,
|
||||||
while (!lockAcquired) {
|
);
|
||||||
try {
|
|
||||||
lockFile.createSync(exclusive: true);
|
|
||||||
lockAcquired = true;
|
|
||||||
} on FileSystemException catch (e) {
|
|
||||||
final isExists = e is PathExistsException || e.osError?.errorCode == 17;
|
|
||||||
if (!isExists) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final stat = lockFile.statSync();
|
|
||||||
if (stat.type != FileSystemEntityType.notFound) {
|
|
||||||
final age = DateTime.now().difference(stat.modified).inMilliseconds;
|
|
||||||
if (age > 1000) {
|
|
||||||
lockFile.deleteSync();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
await Future.delayed(const Duration(milliseconds: 50));
|
|
||||||
} catch (_) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return await action();
|
|
||||||
} finally {
|
|
||||||
if (lockAcquired) {
|
|
||||||
try {
|
|
||||||
if (lockFile.existsSync()) {
|
|
||||||
lockFile.deleteSync();
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _writeLogToFile(LogRecord record) async {
|
Future<void> _writeLogToFile(LogRecord record) async {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.99+99
|
version: 0.1.0+100
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.11.0
|
sdk: ^3.11.0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue