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

Desktop cleanups #1143

Merged
merged 26 commits into from
Aug 22, 2024
Merged

Desktop cleanups #1143

merged 26 commits into from
Aug 22, 2024

Conversation

atavism
Copy link
Contributor

@atavism atavism commented Aug 8, 2024

For https://github.com/getlantern/engineering/issues/1504

  • Use singleton class for Lantern FFI bindings
  • Remove use of global variables in desktop library
  • Updates to settings package: remove use of eventual
  • Add missing default values for certain settings
  • Improve error checking
  • Simplify startup method
  • Updates to ffi value notifier class

@atavism atavism marked this pull request as draft August 8, 2024 04:33
@atavism
Copy link
Contributor Author

atavism commented Aug 8, 2024

@jigar-f I discovered there were a few different issues that were causing the desktop app to crash on macOS: certain settings not being initialized, missing error handling, etc). The most prominent issue is when you navigate to a new screen: after calling context.pushRoute(), the FFI function calls are suddenly undefined or return a null result (that we weren't checking for). You can reproduce this in the existing code by switching to the account tab and navigating to the "invite friends" screen.

I think I've gotten it to a point where the app doesn't crash at all for me, but it would be great if you could take this for a spin to see how it works for you

@atavism atavism force-pushed the atavism/desktop-cleanups branch 2 times, most recently from f7640ce to 49fb3c5 Compare August 9, 2024 04:13
@jigar-f
Copy link
Contributor

jigar-f commented Aug 9, 2024

@atavism thanks for making those changes, I will do testing today with this branch.

@jigar-f
Copy link
Contributor

jigar-f commented Aug 9, 2024

@atavism I am trying to run this branch I am getting this error at most places, I think this coz we are using class method inside compute.

flutter: [2024-08-09 19:06:52.091571 | Catcher 2 | INFO] Invalid argument(s): Illegal argument in isolate message: (object is a DynamicLibrary)
 <- lanternFFI in Instance of 'LanternFFI' (from package:lantern/ffi.dart)
 <- Closure: (List<dynamic>) => FutureOr<String> from Function 'paymentRedirect':. (from package:lantern/ffi.dart)
 <- field callback in compute.<anonymous closure> (from package:flutter/src/foundation/_isolates_io.dart)
 <- resultPort in Instance of '_RemoteRunner<String>' (from dart:isolate)

flutter: [2024-08-09 19:06:52.091614 | Catcher 2 | INFO] 
flutter: [2024-08-09 19:06:52.091652 | Catcher 2 | INFO] ------- STACK TRACE -------
flutter: [2024-08-09 19:06:52.091731 | Catcher 2 | INFO] #0      Isolate._spawnFunction (dart:isolate-patch/isolate_patch.dart:398:25)
flutter: [2024-08-09 19:06:52.091764 | Catcher 2 | INFO] #1      Isolate.spawn (dart:isolate-patch/isolate_patch.dart:378:7)
flutter: [2024-08-09 19:06:52.091792 | Catcher 2 | INFO] #2      Isolate.run (dart:isolate:285:15)
flutter: [2024-08-09 19:06:52.091819 | Catcher 2 | INFO] #3      compute (package:flutter/src/foundation/_isolates_io.dart:18:18)
flutter: [2024-08-09 19:06:52.091847 | Catcher 2 | INFO] #4      compute (package:flutter/src/foundation/isolates.dart:76:19)
flutter: [2024-08-09 19:06:52.091875 | Catcher 2 | INFO] #5      SessionModel.paymentRedirectForDesktop (package:lantern/common/session_model.dart:900:18)
flutter: [2024-08-09 19:06:52.091904 | Catcher 2 | INFO] #6      _PlanCardState._processLegacyCheckOut (package:lantern/plans/plan_details.dart:226:48)

@atavism
Copy link
Contributor Author

atavism commented Aug 9, 2024

@jigar-f Thanks! I think that is happening because of the following:

flutter: [2024-08-09 07:12:47.512493 | Catcher 2 | INFO] ---------- ERROR ----------
flutter: [2024-08-09 07:12:47.512546 | Catcher 2 | INFO] type 'Null' is not a subtype of type 'Map<String, dynamic>'
flutter: [2024-08-09 07:12:47.512592 | Catcher 2 | INFO]
flutter: [2024-08-09 07:12:47.512784 | Catcher 2 | INFO] ------- STACK TRACE -------
flutter: [2024-08-09 07:12:47.512901 | Catcher 2 | INFO] #0      SessionModel.paymentMethodFromJson (package:lantern/common/session_model.dart:667:32)
flutter: [2024-08-09 07:12:47.512943 | Catcher 2 | INFO] #1      SessionModel.paymentMethodsv4 (package:lantern/common/session_model.dart:714:12)
flutter: [2024-08-09 07:12:47.512981 | Catcher 2 | INFO] <asynchronous suspension>
flutter: [2024-08-09 07:12:47.513015 | Catcher 2 | INFO] #2      _PlanCardState._processLegacyCheckOut (package:lantern/plans/plan_details.dart:219:30)
flutter: [2024-08-09 07:12:47.513038 | Catcher 2 | INFO] <asynchronous suspension>

Making some changes to fix this

@atavism
Copy link
Contributor Author

atavism commented Aug 9, 2024

@jigar-f So another reason the app has been crashing is totally unrelated to lantern-client 🤦 The old desktop app crashed for me using the latest flashlight.. Pretty sure we've been seeing the same error:

op=dualfetcher origin_port=80 parallel=true proxy_type=fronted root_op=chainedandfronted]
Aug 09 16:48:29.966 - 2m44s DEBUG flashlight.proxied: proxied.go:466 Got good first response [http_method=GET http_proto=HTTP/1.1 http_status_code=200 op=dualfetcher origin_port=80 parallel=true proxy_type=fronted root_op=chainedandfronted]
Aug 09 16:48:29.966 - 2m44s DEBUG flashlight.common: headers.go:123 Request is not a CORS request
Aug 09 16:48:29.966 - 2m44s DEBUG flashlight.proxied: proxied.go:476 Ignoring error on second response [http_method=GET http_proto=HTTP/1.1 http_status_code=200 op=dualfetcher origin_port=80 parallel=true proxy_type=fronted root_op=chainedandfronted]
Aug 09 16:48:29.966 - 2m44s DEBUG flashlight.proxied: proxied.go:357 Chained request to http://api.getiantem.org/plans-v3?countrycode=us&locale= failed [http_method=GET http_proto=HTTP/1.1 http_status_code=200 op=dualfetcher origin_port=80 parallel=true proxy_type=fronted root_op=chainedandfronted]
==================
WARNING: DATA RACE
Read at 0x00c000376110 by goroutine 583:
  time.(*Time).MarshalJSON()
      <autogenerated>:1 +0x38
  encoding/json.addrMarshalerEncoder()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:459 +0x1ec
  encoding/json.condAddrEncoder.encode()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:891 +0x78
  encoding/json.condAddrEncoder.encode-fm()
      <autogenerated>:1 +0x78
  encoding/json.structEncoder.encode()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:704 +0x1d4
  encoding/json.structEncoder.encode-fm()
      <autogenerated>:1 +0x98
  encoding/json.ptrEncoder.encode()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:876 +0x2e8
  encoding/json.ptrEncoder.encode-fm()
      <autogenerated>:1 +0x6c
  encoding/json.arrayEncoder.encode()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:847 +0xe8
  encoding/json.arrayEncoder.encode-fm()
      <autogenerated>:1 +0x6c
  encoding/json.sliceEncoder.encode()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:820 +0x3a8
  encoding/json.sliceEncoder.encode-fm()
      <autogenerated>:1 +0x6c
  encoding/json.(*encodeState).reflectValue()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:321 +0x74
  encoding/json.(*encodeState).marshal()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:297 +0xb4
  encoding/json.Marshal()
      /opt/homebrew/Cellar/go/1.22.5/libexec/src/encoding/json/encode.go:163 +0xbc
  github.com/getlantern/fronted.(*direct).updateCache()
      /Users/paul/go/pkg/mod/github.com/getlantern/fronted@v0.0.0-20240730140724-9369ca3c94f0/cache.go:82 +0x1b0
  github.com/getlantern/fronted.(*direct).maintainCache()
      /Users/paul/go/pkg/mod/github.com/getlantern/fronted@v0.0.0-20240730140724-9369ca3c94f0/cache.go:69 +0x40
  github.com/getlantern/fronted.(*direct).initCaching.gowrap1()
      /Users/paul/go/pkg/mod/github.com/getlantern/fronted@v0.0.0-20240730140724-9369ca3c94f0/cache.go:11 +0x4c

@jigar-f
Copy link
Contributor

jigar-f commented Aug 12, 2024

Ahh, Yeah, that might be right.

@jigar-f
Copy link
Contributor

jigar-f commented Aug 12, 2024

I am still getting issues, with plans, report issues, and others. Also, I added a few more changes.

@atavism atavism force-pushed the atavism/desktop-cleanups branch from 1ebb46e to b20b808 Compare August 14, 2024 00:41
lib/app.dart Outdated
@@ -122,9 +122,7 @@ class _LanternAppState extends State<LanternApp>
ChangeNotifierProvider(create: (context) => VPNChangeNotifier()),
ChangeNotifierProvider(create: (context) => InternetStatusProvider())
],
child: ChangeNotifierProvider(
Copy link
Contributor Author

@atavism atavism Aug 14, 2024

Choose a reason for hiding this comment

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

@jigar-f I think this may be another reason why the app has been crashing.. it looks like we are creating multiple ChangeNotifierProviders in the App class for the bottom bar notifier? There's an instance already passed to MultiProvider.

Copy link
Contributor

Choose a reason for hiding this comment

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

I might have forgotten to remove that, but I don't think that should crash app.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok cool, I assume we only need to use a single ChangeNotifierProvider though

@jigar-f
Copy link
Contributor

jigar-f commented Aug 14, 2024

@atavism I ended up changing the LanternFFi class, To fix the issue and isolate the issue, When we used to compute we had to use the static method.

@atavism atavism marked this pull request as ready for review August 14, 2024 15:17
@atavism
Copy link
Contributor Author

atavism commented Aug 14, 2024

@atavism I ended up changing the LanternFFi class, To fix the issue and isolate the issue, When we used to compute we had to use the static method.

Sweet, thanks for making those changes! Working well for me.

@atavism
Copy link
Contributor Author

atavism commented Aug 16, 2024

@jigar-f Another potential issue I found is in initCallbacks in the VPN notifier:

  (bool, bool, bool) startUpInitCallBacks() {
    return LanternFFI.startUpInitCallBacks();
  }

  void initCallbacks() {
    if (timer != null) {
      return;
    }
    timer = Timer.periodic(const Duration(seconds: 1), (_) {
      final result = startUpInitCallBacks();
      if (!result.$1 || !result.$2) {
        flashlightState = 'fetching_configuration'.i18n;
      }
      if (result.$1 && result.$2 && !result.$3) {
        flashlightState = 'establish_connection_to_server'.i18n;
      }
      notifyListeners();
      if (result.$1 && result.$2 && result.$3) {
        // everything is initialized
        isFlashlightInitialized = true;
        isFlashlightInitializedFailed = false;
        print("flashlight initialized");
        notifyListeners();
        timer?.cancel();
      } else if (timer!.tick >= 6) {
        // Timer has reached 6 seconds
        // Stop the timer and set isFlashlightInitialized to true
        print("flashlight fail initialized");
        isFlashlightInitialized = true;
        isFlashlightInitializedFailed = true;
        notifyListeners();
      }
    });
  }

It looks like there's occasions where we invoke the Timer.periodic callback, which calls LanternFFI.startUpInitCallBacks() , and the app crashes trying to call any FFI function on the _lanternFFI instance. I confirmed this by printing a message out right before we call _lanternFFI.hasProxyFected():

flutter: startup status proxy false config true success true
flutter: flashlight fail initialized
flutter: startUpInitCallBacks
signal 16 received but handler not on signal stack
mp.gsignal stack [0x14000084000 0x1400008c000], mp.g0 stack [0x16b1f8000 0x16b3fb000], sp=0x14002aa3848
fatal error: non-Go code set up signal handler without SA_ONSTACK flag

runtime stack:
runtime.throw({0x14ced5252?, 0x0?})
	runtime/panic.go:1023 +0x40 fp=0x14002aa37a0 sp=0x14002aa3770 pc=0x14c03e820
runtime.sigNotOnStack(0x10, 0x14002aa3848, 0x14000080008)
	runtime/signal_unix.go:1065 +0x118 fp=0x14002aa37d0 sp=0x14002aa37a0 pc=0x14c059288
runtime.adjustSignalStack(0x10, 0x14000080008, 0x14002aa3878)
	runtime/signal_unix.go:592 +0x25c fp=0x14002aa3840 sp=0x14002aa37d0 pc=0x14c0580ec
runtime.sigtrampgo(0x10, 0x14002aa39e0, 0x14002aa3a48)
	runtime/signal_unix.go:480 +0x8c fp=0x14002aa38c0 sp=0x14002aa3840 pc=0x14c057c2c
runtime.sigtrampgo(0x10, 0x14002aa39e0, 0x14002aa3a48)
	<autogenerated>:1 +0x1c fp=0x14002aa38f0 sp=0x14002aa38c0 pc=0x14c07df6c
runtime.sigtramp()
	runtime/sys_darwin_arm64.s:227 +0x4c fp=0x14002aa39b0 sp=0x14002aa38f0 pc=0x14c07ca3c

I think the callback function that we provide to Timer.periodic runs asynchronously, and that's causing issues since we expect to call the FFI functions on the main thread and would need to use isolates to manage them otherwise.

I disabled the initCallbacks call for now

@jigar-f
Copy link
Contributor

jigar-f commented Aug 16, 2024

The @atavism issue you are facing, Is nothing to do with, startUpInitCallBacks, and the reason we are running this on the main thread depends on the state in which we are showing a message to the user.

This issue is same issue, I am facing due to some signal handler.

@atavism
Copy link
Contributor Author

atavism commented Aug 16, 2024

The @atavism issue you are facing, Is nothing to do with, startUpInitCallBacks

I meant initCallbacks in the VPN notifier. I thought it may be related because I'm able to get the app to crash repeatedly with the following test code:

class TestWidget extends StatelessWidget {

  const TestWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final vpnNotifier = context.watch<VPNChangeNotifier>();
    final res = vpnNotifier.isFlashlightInitialized;
    return SizedBox();
  }
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await LanternFFI.startDesktopService();
  await Localization.ensureInitialized();
  runApp(MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => VPNChangeNotifier())
      ],
      child: TestWidget()));
}

That's with app.Run() disabled so this is without even starting Lantern

@atavism atavism closed this Aug 16, 2024
@atavism atavism reopened this Aug 16, 2024
@atavism atavism mentioned this pull request Aug 19, 2024
@jigar-f
Copy link
Contributor

jigar-f commented Aug 20, 2024

Thats a great find, I will take a look at this sprint.

@atavism
Copy link
Contributor Author

atavism commented Aug 22, 2024

I am going to pull in these changes and if we need to fix additional issues, we can do that on the websocket PR

@atavism atavism merged commit 37e8dce into main Aug 22, 2024
1 check passed
@atavism atavism deleted the atavism/desktop-cleanups branch August 22, 2024 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants