Skip to content

Conversation

@blasten
Copy link

@blasten blasten commented Nov 12, 2019

Description

I refactored the the protocol discovery mechanism, so it looks at future observatory URIs instead of old ones. I'm sending this PR to get early feedback. I will then add unit tests.

The main change is that observatoryUri becomes a Stream of Uri.

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require Flutter developers to manually update their apps to accommodate your change?

  • Yes, this is a breaking change (Please read Handling breaking changes). Replace this with a link to the e-mail where you asked for input on this proposed change.
  • No, this is not a breaking change.

@fluttergithubbot fluttergithubbot added the tool Affects the "flutter" command-line tool. See also t: labels. label Nov 12, 2019
@blasten blasten force-pushed the attach_stays branch 2 times, most recently from b7ef16e to 9bdf33e Compare November 12, 2019 03:01
@blasten blasten requested a review from xster November 12, 2019 03:09
Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attach changes generally look good I think - though I would do more verification to ensure that we're cleaning exiting the loop on errors and cleaning up resources in between.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does changing this to a Stream do? I think It takes a list so that for -d all the runner can handle multiple vmservice addresses

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, it looks like as a list this has either 0 or 1 elements, so I don't think it's related to -d all. What I'm not sure about is why it had to be an empty list rather than null when there were no observatory uris.

Copy link
Author

@blasten blasten Nov 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears the intention was to support multiple apps running an observatory on a single device, but it's not implemented. Was this done for Fuchsia?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it looks like this was for the now-deleted fuchsia_reload command. Fuchsia is now handled differently, so I think this can be safely modified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At any rate - I'm not really sure what modifying the resident runner here is accomplishing. Isn't the goal to adjust this behavior for attach only?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per offline discussion, I changed this such that it doesn't reuse the resident runner, which aligns with the expected lifecycle of the resident runner.

Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of making ProtocolDiscovery give a stream of Uris, did you consider having the attach command instead do a loop around _attachToDevice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, it looks like as a list this has either 0 or 1 elements, so I don't think it's related to -d all. What I'm not sure about is why it had to be an empty list rather than null when there were no observatory uris.

@blasten blasten force-pushed the attach_stays branch 3 times, most recently from cfedba2 to 32bea4a Compare November 12, 2019 22:55
@blasten
Copy link
Author

blasten commented Nov 13, 2019

Capturing the offline conversation:

The goal here is to discover the observatory URI of an app:

  1. Already running on the device.
  2. That is restarted. (e.g. killed and then started again)
  3. That starts after running flutter attach. (Currently supported)

cc @zanderso

@blasten blasten requested a review from zanderso November 13, 2019 01:28
@zanderso
Copy link
Member

Overall approach looks good. Need tests of reconnect, and follow-on PRs (or same PR, up to you) to support re-attaching with mdns (and other) discovery.

@blasten blasten force-pushed the attach_stays branch 3 times, most recently from 349f855 to 42f6d74 Compare November 14, 2019 01:15
@blasten
Copy link
Author

blasten commented Nov 14, 2019

This PR is ready for a final review. PTAL

@blasten blasten force-pushed the attach_stays branch 3 times, most recently from 381046c to e9dfe28 Compare November 15, 2019 01:52
@xster
Copy link
Member

xster commented Nov 15, 2019

cc @devoncarew, @DanTup this should make the IDE specific work-around for Android flutter attach redundant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bug. We generally shouldn't be catching Error subclasses unless it is a temporary work around. If you are going to replace uri with uris I would do that in this PR

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow. If something called cancel too early, then this is the equivalent behavior in the current code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what situation does _uriStreamController?.close() triggers the StateError? When you say uris.first after the _uriStreamController?.close()? Can you check _uriStreamController.isClosed or add an onCancel callback to _uriStreamController that records a bit?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The situation is that there's a test returns non-null uri future under protocol_discovery_test.dart that expects uri to return a non-null value. For some reason, this works currently even though the uri future never completes. I checked the documentation for expect and it says:
" If [actual] is a [Future], the test won't complete until the future emits a value." However, it doesn't seem true in this case:

final Completer<void> _completer = Completer<Uri>();
expect(_completer.future, isNotNull);

For this reason, the test is failing when migrated to streams. The stream is closed in the tearDown callback before a value is emitted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catching a StateError is definitely a bug. It implies there's some logic error in our code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, don't use broadcast streams. These do not buffer events, so if the future resolves before the first subscriber is added the event will be lost

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to work fine:

import 'dart:async';

void main() async {
  Stream<String> stream = Stream<String>.fromFuture(Future<String>.value('foo'))
      .asBroadcastStream();

  stream.listen((String value) {
    print(value);
  });
}

prints foo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs for asBroadcastStream() here:

The returned stream will subscribe to this stream when its first subscriber is added, and will stay subscribed until this stream ends, or a callback cancels the subscription.

In general though, I don't know if it would be needed to pass onListen and onCancel callbacks to asBroadcastStream() to pause and resume the underlying stream when the number of subscribers hits zero.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you re-added the updates to resident runner. Were these changes necessary for some reason?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes -- observatoryUris is a stream instead of a list.

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jonahwilliams
Copy link
Contributor

(If LG to @zanderso )

///
/// Port forwarding is only attempted when this is invoked,
/// for each observatory URI in the stream.
Stream<Uri> get uris {
Copy link
Contributor

@gspencergoog gspencergoog Nov 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blasten If you're changing this API's name anyhow, @Hixie has pointed out that there is no such thing as a URI, they're all URLs, so maybe this should be called urls instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Thanks!

)
).asBroadcastStream();
}
// If MDNS discovery fails or we're not on iOS, fallback to ProtocolDiscovery.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not catching this earlier, but this fallback will no longer work since the Stream.fromFuture isn't going to return null. That is the null check below is no longer testing the success of the mdns lookup. Could you please do a small follow-up change that checks the return of MDnsObservatoryDiscovery.instance.getObservatoryUri() for null, and if it is null then uses ProtocolDiscovery.observatory() instead? Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I will follow up on that!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants