Skip to content

Commit

Permalink
Added support for bulk downloading to ObjectBox backend
Browse files Browse the repository at this point in the history
Fixed bugs & reimplemented some removed methods in example app
  • Loading branch information
JaffaKetchup committed Feb 24, 2024
1 parent 2a3f55f commit 645abac
Show file tree
Hide file tree
Showing 19 changed files with 577 additions and 315 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class ConfigureDownloadPopup extends StatelessWidget {
suffixText: 'max. tps',
value: (provider) => provider.rateLimit,
min: 1,
max: 500,
max: 50000,
maxEligibleTilesPreview: 20,
onChanged: (provider, value) =>
provider.rateLimit = value,
Expand Down
2 changes: 1 addition & 1 deletion example/lib/screens/import_store/import_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ImportStorePopup extends StatefulWidget {
class _ImportStorePopupState extends State<ImportStorePopup> {
final Map<String, _ImportStore> importStores = {};

// TODO: Implement
// TODO: Implement
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
import 'package:provider/provider.dart';

import '../../../../configure_download/configure_download.dart';
import '../../region_selection/state/region_selection_provider.dart';

class RecoveryStartButton extends StatelessWidget {
const RecoveryStartButton({
Expand All @@ -26,35 +30,32 @@ class RecoveryStartButton extends StatelessWidget {
onPressed: !result.isFailed
? null
: () async {
//TODO: Implement
/* final DownloaderProvider downloadProvider =
Provider.of<DownloaderProvider>(
context,
listen: false,
)
..region = region.toRegion(
rectangle: (r) => r,
circle: (c) => c,
line: (l) => l,
)
..minZoom = region.minZoom
..maxZoom = region.maxZoom
..setSelectedStore(
FMTC.instance(region.storeName),
)
..regionTiles = tiles.data;
await Navigator.of(context).push(
MaterialPageRoute<String>(
builder: (BuildContext context) =>
DownloadRegionPopup(
region: downloadProvider.region!,
),
fullscreenDialog: true,
),
);
moveToDownloadPage();*/
final regionSelectionProvider =
Provider.of<RegionSelectionProvider>(
context,
listen: false,
)
..region = result.region.toRegion()
..minZoom = result.region.minZoom
..maxZoom = result.region.maxZoom
..setSelectedStore(
FMTCStore(result.region.storeName),
);
// TODO: Check
//..regionTiles = tiles.data;

await Navigator.of(context).push(
MaterialPageRoute<String>(
builder: (context) => ConfigureDownloadPopup(
region: regionSelectionProvider.region!,
minZoom: result.region.minZoom,
maxZoom: result.region.maxZoom,
),
fullscreenDialog: true,
),
);

moveToDownloadPage();
},
)
: const Padding(
Expand Down
19 changes: 19 additions & 0 deletions lib/src/backend/backend_access.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,22 @@ abstract mixin class FMTCBackendAccess {
_internal = newInternal;
}
}

@meta.internal
abstract mixin class FMTCBackendAccessThreadSafe {
static FMTCBackendInternalThreadSafe? _internal;

@meta.internal
@meta.experimental
static FMTCBackendInternalThreadSafe get internal =>
_internal ?? (throw RootUnavailable());

@meta.internal
@meta.protected
static set internal(FMTCBackendInternalThreadSafe? newInternal) {
if (newInternal != null && _internal != null) {
throw RootAlreadyInitialised();
}
_internal = newInternal;
}
}
6 changes: 4 additions & 2 deletions lib/src/backend/export_external.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright © Luka S (JaffaKetchup) under GPL-v3
// A full license can be found at .\LICENSE

export 'impls/objectbox/backend.dart';
export 'interfaces/backend.dart';
export 'impls/objectbox/backend/backend.dart';
export 'interfaces/backend/backend.dart';
export 'interfaces/backend/internal.dart';
export 'interfaces/backend/internal_thread_safe.dart';
export 'utils/errors.dart';
63 changes: 63 additions & 0 deletions lib/src/backend/impls/objectbox/backend/backend.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright © Luka S (JaffaKetchup) under GPL-v3
// A full license can be found at .\LICENSE

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';

import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

import '../../../../../flutter_map_tile_caching.dart';
import '../../../export_internal.dart';
import '../models/generated/objectbox.g.dart';
import '../models/src/recovery.dart';
import '../models/src/store.dart';
import '../models/src/tile.dart';

part 'internal_thread_safe.dart';
part 'internal.dart';
part 'internal_worker.dart';

/// Implementation of [FMTCBackend] that uses ObjectBox as the storage database
final class FMTCObjectBoxBackend implements FMTCBackend {
/// {@macro fmtc.backend.initialise}
///
/// [maxDatabaseSize] is the maximum size the database file can grow
/// to, in KB. Exceeding it throws [DbFullException]. Defaults to 10 GB.
///
/// [macosApplicationGroup] should be set when creating a sandboxed macOS app,
/// specify the application group (of less than 20 chars). See
/// [the ObjectBox docs](https://docs.objectbox.io/getting-started) for
/// details.
@override
Future<void> initialise({
String? rootDirectory,
int maxDatabaseSize = 10000000,
String? macosApplicationGroup,
}) =>
FMTCObjectBoxBackendInternal._instance.initialise(
rootDirectory: rootDirectory,
maxDatabaseSize: maxDatabaseSize,
macosApplicationGroup: macosApplicationGroup,
);

/// {@macro fmtc.backend.uninitialise}
///
/// If [immediate] is `true`, any operations currently underway will be lost,
/// as the worker will be killed as quickly as possible (not necessarily
/// instantly).
/// If `false`, all operations currently underway will be allowed to complete,
/// but any operations started after this method call will be lost. A lost
/// operation may throw [RootUnavailable].
@override
Future<void> uninitialise({
bool deleteRoot = false,
bool immediate = false,
}) =>
FMTCObjectBoxBackendInternal._instance
.uninitialise(deleteRoot: deleteRoot, immediate: immediate);
}
Original file line number Diff line number Diff line change
@@ -1,64 +1,7 @@
// Copyright © Luka S (JaffaKetchup) under GPL-v3
// A full license can be found at .\LICENSE

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';

import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

import '../../../../flutter_map_tile_caching.dart';
import '../../export_internal.dart';
import 'models/generated/objectbox.g.dart';
import 'models/src/recovery.dart';
import 'models/src/store.dart';
import 'models/src/tile.dart';

part 'worker.dart';

/// Implementation of [FMTCBackend] that uses ObjectBox as the storage database
final class FMTCObjectBoxBackend implements FMTCBackend {
/// {@macro fmtc.backend.inititialise}
///
/// [maxDatabaseSize] is the maximum size the database file can grow
/// to, in KB. Exceeding it throws [DbFullException]. Defaults to 10 GB.
///
/// [macosApplicationGroup] should be set when creating a sandboxed macOS app,
/// specify the application group (of less than 20 chars). See
/// [the ObjectBox docs](https://docs.objectbox.io/getting-started) for
/// details.
@override
Future<void> initialise({
String? rootDirectory,
int maxDatabaseSize = 10000000,
String? macosApplicationGroup,
}) =>
FMTCObjectBoxBackendInternal._instance.initialise(
rootDirectory: rootDirectory,
maxDatabaseSize: maxDatabaseSize,
macosApplicationGroup: macosApplicationGroup,
);

/// {@macro fmtc.backend.uninitialise}
///
/// If [immediate] is `true`, any operations currently underway will be lost,
/// as the worker will be killed as quickly as possible (not necessarily
/// instantly).
/// If `false`, all operations currently underway will be allowed to complete,
/// but any operations started after this method call will be lost. A lost
/// operation may throw [RootUnavailable].
@override
Future<void> uninitialise({
bool deleteRoot = false,
bool immediate = false,
}) =>
FMTCObjectBoxBackendInternal._instance
.uninitialise(deleteRoot: deleteRoot, immediate: immediate);
}
part of 'backend.dart';

/// Internal implementation of [FMTCBackend] that uses ObjectBox as the storage
/// database
Expand Down Expand Up @@ -164,13 +107,13 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal {
).create(recursive: true);

// Prepare to recieve `SendPort` from worker
late final ByteData storeReference;
_workerResOneShot[0] = Completer();
unawaited(
_workerResOneShot[0]!.future.then((res) {
_sendPort = res!['sendPort'];
_workerResOneShot.remove(0);
}),
);
final workerInitialRes = _workerResOneShot[0]!.future.then((res) {
storeReference = res!['storeReference'];
_sendPort = res['sendPort'];
_workerResOneShot.remove(0);
});

// Setup worker comms/response handler
final receivePort = ReceivePort();
Expand Down Expand Up @@ -223,7 +166,12 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal {
debugName: '[FMTC] ObjectBox Backend Worker',
);

await workerInitialRes;

FMTCBackendAccess.internal = this;
FMTCBackendAccessThreadSafe.internal = _ObjectBoxBackendThreadSafeImpl._(
storeReference: storeReference,
);
}

Future<void> uninitialise({
Expand Down Expand Up @@ -267,6 +215,7 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal {
//_rotalDebouncer.cancel();

FMTCBackendAccess.internal = null;
FMTCBackendAccessThreadSafe.internal = null;
}

@override
Expand Down Expand Up @@ -352,10 +301,11 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal {
@override
Future<ObjectBoxTile?> readTile({
required String url,
String? storeName,
}) async =>
(await _sendCmdOneShot(
type: _WorkerCmdType.readTile,
args: {'url': url},
args: {'url': url, 'storeName': storeName},
))!['tile'];

@override
Expand All @@ -378,17 +328,6 @@ class _ObjectBoxBackendImpl implements FMTCObjectBoxBackendInternal {
args: {'storeName': storeName, 'url': url, 'bytes': bytes},
);

@override
Future<void> writeTilesDirect({
required String storeName,
required List<String> urls,
required List<Uint8List> bytess,
}) =>
_sendCmdOneShot(
type: _WorkerCmdType.writeTilesDirect,
args: {'storeName': storeName, 'urls': urls, 'bytess': bytess},
);

@override
Future<bool?> deleteTile({
required String storeName,
Expand Down
Loading

0 comments on commit 645abac

Please sign in to comment.