Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keeps the SyncEngine alive when the Wiredash widget updates #211

Merged
merged 1 commit into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 27 additions & 31 deletions lib/src/core/services/services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,39 @@ class WiredashServices extends ChangeNotifier {

final Locator _locator = Locator();

WiredashModel get wiredashModel => _locator.get();
WiredashModel get wiredashModel => _locator.watch();

FeedbackModel get feedbackModel => _locator.get();
FeedbackModel get feedbackModel => _locator.watch();

NpsModel get npsModel => _locator.get();
NpsModel get npsModel => _locator.watch();

BackdropController get backdropController => _locator.get();
BackdropController get backdropController => _locator.watch();

DeviceInfoGenerator get deviceInfoGenerator => _locator.get();
DeviceInfoGenerator get deviceInfoGenerator => _locator.watch();

PicassoController get picassoController => _locator.get();
PicassoController get picassoController => _locator.watch();

ScreenCaptureController get screenCaptureController => _locator.get();
ScreenCaptureController get screenCaptureController => _locator.watch();

BuildInfoManager get buildInfoManager => _locator.get();
BuildInfoManager get buildInfoManager => _locator.watch();

FeedbackSubmitter get feedbackSubmitter => _locator.get();
FeedbackSubmitter get feedbackSubmitter => _locator.watch();

DeviceIdGenerator get deviceIdGenerator => _locator.get();
DeviceIdGenerator get deviceIdGenerator => _locator.watch();

Wiredash get wiredashWidget => _locator.get();
Wiredash get wiredashWidget => _locator.watch();

WiredashOptionsData get wiredashOptions => _locator.get();
WiredashOptionsData get wiredashOptions => _locator.watch();

WiredashApi get api => _locator.get();
WiredashApi get api => _locator.watch();

SyncEngine get syncEngine => _locator.get();
SyncEngine get syncEngine => _locator.watch();

DiscardFeedbackUseCase get discardFeedback => _locator.get();
DiscardFeedbackUseCase get discardFeedback => _locator.watch();

DiscardNpsUseCase get discardNps => _locator.get();
DiscardNpsUseCase get discardNps => _locator.watch();

ProjectCredentialValidator get projectCredentialValidator => _locator.get();
ProjectCredentialValidator get projectCredentialValidator => _locator.watch();

void updateWidget(Wiredash wiredashWidget) {
inject<Wiredash>((_) => wiredashWidget);
Expand All @@ -83,15 +83,11 @@ class WiredashServices extends ChangeNotifier {
}

InstanceFactory<T> inject<T>(
T Function(WiredashServices) create, {
T Function(WiredashServices, T oldInstance)? update,
T Function(Locator) create, {
Function(T)? dispose,
}) {
final factory = _locator.injectProvider(
(locator) => create(this),
update: update == null
? null
: (_, T oldInstance) => update(this, oldInstance),
(locator) => create(_locator),
dispose: dispose,
);
notifyListeners();
Expand Down Expand Up @@ -124,7 +120,7 @@ void _setupServices(WiredashServices sl) {
);
sl.inject<DeviceInfoGenerator>((_) => DeviceInfoGenerator(window));
sl.inject<WiredashOptionsData>(
(locator) => locator.wiredashWidget.options ?? const WiredashOptionsData(),
(_) => sl.wiredashWidget.options ?? const WiredashOptionsData(),
);
sl.inject<ScreenCaptureController>(
(locator) => ScreenCaptureController(),
Expand All @@ -150,17 +146,17 @@ void _setupServices(WiredashServices sl) {
(locator) {
return WiredashApi(
httpClient: Client(),
projectId: locator.wiredashWidget.projectId,
secret: locator.wiredashWidget.secret,
deviceIdProvider: locator.deviceIdGenerator.deviceId,
projectId: sl.wiredashWidget.projectId,
secret: sl.wiredashWidget.secret,
deviceIdProvider: sl.deviceIdGenerator.deviceId,
);
},
);

sl.inject<FeedbackSubmitter>(
(locator) {
if (kIsWeb) {
return DirectFeedbackSubmitter(locator.api);
return DirectFeedbackSubmitter(sl.api);
}

const fileSystem = LocalFileSystem();
Expand All @@ -172,7 +168,7 @@ void _setupServices(WiredashServices sl) {
uuidV4Generator: const UuidV4Generator(),
);
final retryingFeedbackSubmitter =
RetryingFeedbackSubmitter(fileSystem, storage, locator.api);
RetryingFeedbackSubmitter(fileSystem, storage, sl.api);
return retryingFeedbackSubmitter;
},
);
Expand All @@ -184,14 +180,14 @@ void _setupServices(WiredashServices sl) {
engine.addJob(
'ping',
PingJob(
api: locator.api,
apiProvider: locator.get,
sharedPreferencesProvider: SharedPreferences.getInstance,
),
);
engine.addJob(
'feedback',
UploadPendingFeedbackJob(
feedbackSubmitter: locator.feedbackSubmitter,
feedbackSubmitterProvider: locator.get,
),
);

Expand Down
87 changes: 59 additions & 28 deletions lib/src/core/services/streampod.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,38 @@ class Locator {
throw Exception('Locator is disposed');
}
final provider = _registry[T];
return provider!.instance as T;
return provider!.get as T;
}

/// Retrieve a instance of type [T]
T watch<T>() {
if (_disposed) {
throw Exception('Locator is disposed');
}
final provider = _registry[T];
return provider!.watch as T;
}

/// Listen to change of type [T]
void listen<T>(void Function(T) callback) {
final factory = _registry[T]!;

factory.listeners.add(() {
final currentFactory = _registry[T]!;
callback(currentFactory.get as T);
});
callback(factory.get as T);
}

InstanceFactory<T> injectProvider<T>(
T Function(Locator) create, {
T Function(Locator, T oldInstance)? update,
void Function(T)? dispose,
}) {
if (_disposed) {
throw Exception('Locator is disposed');
}
late InstanceFactory<T> provider;
provider = InstanceFactory(this, create, update, () {
provider = InstanceFactory(this, create, () {
final instance = provider._instance;
if (instance != null && dispose != null) {
dispose(instance);
Expand All @@ -41,12 +60,20 @@ class Locator {
final existing = _registry[T];
_registry[T] = provider;
if (existing != null) {
final consumers = existing.consumers.toList();
final listeners = existing.listeners.toList();
existing.listeners = [];
existing.consumers = [];
existing.dependencies = [];
existing.listeners = [];
existing.dispose?.call();
for (final consumer in consumers) {
// rebuilding automatically registers dependencies and listeners again
consumer.rebuild();
}

provider.listeners.addAll(listeners);
for (final listener in listeners) {
listener.rebuild();
listener.call();
}
}
return provider;
Expand All @@ -59,64 +86,68 @@ class InstanceFactory<T> {
InstanceFactory(
this.locator,
this.create,
this.update,
this.dispose,
);

final T Function(Locator) create;
final T Function(Locator, T oldInstance)? update;
final Locator locator;

final int id = _id++;
T? _instance;
T? _oldInstance;

List<InstanceFactory> listeners = [];
/// Those factories that use the instance and rebuild when it changes
List<InstanceFactory> consumers = [];

/// Receive notifications about instance changes
List<void Function()> listeners = [];

/// When those change, instance gets recreated
List<InstanceFactory> dependencies = [];

final Function()? dispose;

late final DependencyTracker _tracker = DependencyTracker(this);

T get instance {
/// Rebuilds the calling [InstanceFactory] when [_instance] changes.
T get watch {
if (_instance == null) {
_tracker.create();
late final T i;
if (_oldInstance != null && update != null) {
// ignore: null_check_on_nullable_type_parameter
i = update!.call(locator, _oldInstance!);
} else {
i = create(locator);
}
i = create(locator);
_tracker.created();
// print("$T\n"
// "\t-depends on: ${dependencies.map((e) => e.runtimeType)}\n"
// "\t-Listeners: ${listeners.map((e) => e.runtimeType)}\n");
_instance = i;
} else {
_tracker.create();
_tracker.created();
}
return _instance!;
return _instance as T;
}

/// Reads the current [_instance], doesn't subscribe the calling [InstanceFactory] to changes.
T get get {
if (_instance == null) {
final T i = create(locator);
_instance = i;
}
return _instance as T;
}

/// Discards the current [_instance] and rebuilds it with updated dependencies.
///
/// Tracks dependencies to other providers during rebuild
void rebuild() {
dispose?.call();
final listeners = this.listeners.toList();
final consumers = this.consumers.toList();
dependencies = [];
this.listeners = [];
_oldInstance = _instance;
this.consumers = [];
_instance = null;

// invalidate existing dependency instances
for (final provider in listeners) {
for (final provider in consumers) {
_tracker.create();
provider.rebuild();
_tracker.created();
}

// create instance
// instance;
}

@override
Expand Down Expand Up @@ -144,7 +175,7 @@ class DependencyTracker {
if (_prevActive != null) {
final listener = locator._registry.values
.firstWhere((element) => element.id == _prevActive);
provider.listeners.add(listener);
provider.consumers.add(listener);
listener.dependencies.add(provider);
}
}
Expand Down
6 changes: 3 additions & 3 deletions lib/src/core/sync/ping_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import 'package:wiredash/src/core/network/wiredash_api.dart';
import 'package:wiredash/src/core/sync/sync_engine.dart';

class PingJob extends Job {
final WiredashApi api;
final WiredashApi Function() apiProvider;
final Future<SharedPreferences> Function() sharedPreferencesProvider;

PingJob({
required this.api,
required this.apiProvider,
required this.sharedPreferencesProvider,
});

Expand Down Expand Up @@ -45,7 +45,7 @@ class PingJob extends Job {
}

try {
await api.ping();
await apiProvider().ping();
await _saveLastSuccessfulPing(now);
syncDebugPrint('ping');
} on KillSwitchException catch (_) {
Expand Down
8 changes: 4 additions & 4 deletions lib/src/core/sync/sync_feedback_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import 'package:wiredash/src/core/sync/sync_engine.dart';
import 'package:wiredash/src/feedback/_feedback.dart';

class UploadPendingFeedbackJob extends Job {
final FeedbackSubmitter feedbackSubmitter;
final FeedbackSubmitter Function() feedbackSubmitterProvider;

UploadPendingFeedbackJob({
required this.feedbackSubmitter,
required this.feedbackSubmitterProvider,
});

@override
Expand All @@ -16,11 +16,11 @@ class UploadPendingFeedbackJob extends Job {

@override
Future<void> execute() async {
if (feedbackSubmitter is! RetryingFeedbackSubmitter) {
final submitter = feedbackSubmitterProvider();
if (submitter is! RetryingFeedbackSubmitter) {
return;
}

final submitter = feedbackSubmitter as RetryingFeedbackSubmitter;
await submitter.submitPendingFeedbackItems();

if (kDebugMode) {
Expand Down
Loading