alroyso 1 рік тому
батько
коміт
aade1f7ef7
67 змінених файлів з 7287 додано та 283 видалено
  1. 1 0
      README.md
  2. BIN
      assets/images/login/bgbutton.png
  3. BIN
      assets/images/login/login.png
  4. BIN
      assets/images/logo/logo.ico
  5. BIN
      assets/images/logo/logo.png
  6. BIN
      assets/images/main/connecting.gif
  7. BIN
      assets/images/main/customer.png
  8. BIN
      assets/images/main/disconnected.gif
  9. BIN
      assets/images/main/main.png
  10. BIN
      assets/images/main/promotion.png
  11. BIN
      assets/images/main/refresh.png
  12. BIN
      assets/images/main/renewal.png
  13. BIN
      assets/images/main/stopped.gif
  14. BIN
      assets/images/main/tutorial.png
  15. BIN
      assets/images/main/userstatus.png
  16. BIN
      assets/images/main/userstatusoff.png
  17. BIN
      assets/images/node/nodebg.png
  18. BIN
      assets/images/node/nodetablebg.png
  19. BIN
      assets/tp/clash/Country.mmdb
  20. 16 0
      assets/tp/clash/config.yaml
  21. 1 0
      core/build-arm64-android-template.sh
  22. 1 0
      core/config.yaml
  23. BIN
      core/dist/libclash.dylib
  24. 9 0
      core/enable_tun.sh
  25. 4084 0
      core/fclash-go-bridge/dart_api_dl/dart_api.h
  26. 59 0
      core/fclash-go-bridge/dart_api_dl/dart_api_dl.c
  27. 150 0
      core/fclash-go-bridge/dart_api_dl/dart_api_dl.h
  28. 204 0
      core/fclash-go-bridge/dart_api_dl/dart_native_api.h
  29. 538 0
      core/fclash-go-bridge/dart_api_dl/dart_tools_api.h
  30. 16 0
      core/fclash-go-bridge/dart_api_dl/dart_version.h
  31. 21 0
      core/fclash-go-bridge/dart_api_dl/internal/dart_api_dl_impl.h
  32. 3 0
      core/fclash-go-bridge/go.mod
  33. 41 0
      core/fclash-go-bridge/lib.go
  34. BIN
      core/flutter-clash-binding
  35. 105 0
      core/flutter-clash-binding.h
  36. 94 26
      core/go.mod
  37. 253 49
      core/go.sum
  38. 319 49
      core/lib.go
  39. BIN
      core/libclash.dylib
  40. 26 7
      core/libclash.h
  41. BIN
      images/main/logo.ico
  42. BIN
      images/main/logo.png
  43. 4 2
      ios/Runner.xcodeproj/project.pbxproj
  44. 35 0
      lib/app/bean/clash_config_entity.dart
  45. 138 0
      lib/app/bean/clash_config_generator.dart
  46. 0 0
      lib/app/bean/config_bean.dart
  47. 18 0
      lib/app/bean/proxy_group.dart
  48. 10 0
      lib/app/bean/rule.dart
  49. 2 0
      lib/app/common/SharedPreferencesUtil.dart
  50. 3 3
      lib/app/component/connection_widget.dart
  51. 0 39
      lib/app/global_controller/GlobalConfigFileController.dart
  52. 48 5
      lib/app/modules/home/controllers/home_controller.dart
  53. 7 4
      lib/app/modules/home/views/home_view.dart
  54. 1 1
      lib/app/modules/login/views/login_view.dart
  55. 2 2
      lib/app/modules/node/views/node_view.dart
  56. 543 0
      lib/app/service/clash_service.dart
  57. 328 52
      lib/clash_generated_bindings.dart
  58. 82 20
      lib/main.dart
  59. 12 0
      linux/flutter/generated_plugin_registrant.cc
  60. 3 0
      linux/flutter/generated_plugins.cmake
  61. 8 0
      macos/Flutter/GeneratedPluginRegistrant.swift
  62. 30 0
      macos/Podfile.lock
  63. 14 4
      macos/Runner.xcodeproj/project.pbxproj
  64. 17 1
      macos/Runner/AppDelegate.swift
  65. 25 19
      pubspec.yaml
  66. 12 0
      windows/flutter/generated_plugin_registrant.cc
  67. 4 0
      windows/flutter/generated_plugins.cmake

+ 1 - 0
README.md

@@ -15,6 +15,7 @@ For help getting started with Flutter development, view the
 [online documentation](https://docs.flutter.dev/), which offers tutorials,
 samples, guidance on mobile development, and a full API reference.
 
+dart run ffigen
 
 
 dart run build_runner build --delete-conflicting-outputs

BIN
assets/images/login/bgbutton.png


BIN
assets/images/login/login.png


BIN
assets/images/logo/logo.ico


BIN
assets/images/logo/logo.png


BIN
assets/images/main/connecting.gif


BIN
assets/images/main/customer.png


BIN
assets/images/main/disconnected.gif


BIN
assets/images/main/main.png


BIN
assets/images/main/promotion.png


BIN
assets/images/main/refresh.png


BIN
assets/images/main/renewal.png


BIN
assets/images/main/stopped.gif


BIN
assets/images/main/tutorial.png


BIN
assets/images/main/userstatus.png


BIN
assets/images/main/userstatusoff.png


BIN
assets/images/node/nodebg.png


BIN
assets/images/node/nodetablebg.png


BIN
assets/tp/clash/Country.mmdb


+ 16 - 0
assets/tp/clash/config.yaml

@@ -0,0 +1,16 @@
+external-controller: 127.0.0.1:22345
+
+mixed-port: 22346
+
+rules:
+  # localhost rule
+  - DOMAIN-KEYWORD,announce,DIRECT
+  - DOMAIN-KEYWORD,torrent,DIRECT
+  - DOMAIN-KEYWORD,tracker,DIRECT
+  - DOMAIN-SUFFIX,smtp,DIRECT
+  - DOMAIN-SUFFIX,local,DIRECT
+  - IP-CIDR,192.168.0.0/16,DIRECT
+  - IP-CIDR,10.0.0.0/8,DIRECT
+  - IP-CIDR,172.16.0.0/12,DIRECT
+  - IP-CIDR,127.0.0.0/8,DIRECT
+  - IP-CIDR,100.64.0.0/10,DIRECT

+ 1 - 0
core/build-arm64-android-template.sh

@@ -0,0 +1 @@
+env GOOS=android GOARCH=arm64 CC=/home/kingtous/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang GOARM=7 CGO_ENABLED=1 go build -buildmode=c-shared -o ./libclash.so

+ 1 - 0
core/config.yaml

@@ -0,0 +1 @@
+mixed-port: 7890

BIN
core/dist/libclash.dylib


+ 9 - 0
core/enable_tun.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+echo -e "Add dev..."
+sudo ip tuntap add mode tun dev tun-fclash
+sudo ip addr add 198.18.0.1/15 dev tun-fclash
+sudo ip link set dev tun-fclash up
+# Configure the default route table with different metrics. Let's say the primary interface is eth0 and gateway is 172.17.0.1.
+echo -e "Configuring routes..."
+sudo ip route del default
+sudo ip route add default via 198.18.0.1 dev tun-fclash

+ 4084 - 0
core/fclash-go-bridge/dart_api_dl/dart_api.h

@@ -0,0 +1,4084 @@
+/*
+ * Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_API_H_
+#define RUNTIME_INCLUDE_DART_API_H_
+
+/** \mainpage Dart Embedding API Reference
+ *
+ * This reference describes the Dart Embedding API, which is used to embed the
+ * Dart Virtual Machine within C/C++ applications.
+ *
+ * This reference is generated from the header include/dart_api.h.
+ */
+
+/* __STDC_FORMAT_MACROS has to be defined before including <inttypes.h> to
+ * enable platform independent printf format specifiers. */
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+#define DART_EXTERN_C extern "C"
+#else
+#define DART_EXTERN_C extern
+#endif
+
+#if defined(__CYGWIN__)
+#error Tool chain and platform not supported.
+#elif defined(_WIN32)
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT DART_EXTERN_C __declspec(dllexport)
+#else
+#define DART_EXPORT DART_EXTERN_C
+#endif
+#else
+#if __GNUC__ >= 4
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT                                                            \
+  DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used))
+#else
+#define DART_EXPORT DART_EXTERN_C
+#endif
+#else
+#error Tool chain not supported.
+#endif
+#endif
+
+#if __GNUC__
+#define DART_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#elif _MSC_VER
+#define DART_WARN_UNUSED_RESULT _Check_return_
+#else
+#define DART_WARN_UNUSED_RESULT
+#endif
+
+/*
+ * =======
+ * Handles
+ * =======
+ */
+
+/**
+ * An isolate is the unit of concurrency in Dart. Each isolate has
+ * its own memory and thread of control. No state is shared between
+ * isolates. Instead, isolates communicate by message passing.
+ *
+ * Each thread keeps track of its current isolate, which is the
+ * isolate which is ready to execute on the current thread. The
+ * current isolate may be NULL, in which case no isolate is ready to
+ * execute. Most of the Dart apis require there to be a current
+ * isolate in order to function without error. The current isolate is
+ * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate.
+ */
+typedef struct _Dart_Isolate* Dart_Isolate;
+typedef struct _Dart_IsolateGroup* Dart_IsolateGroup;
+
+/**
+ * An object reference managed by the Dart VM garbage collector.
+ *
+ * Because the garbage collector may move objects, it is unsafe to
+ * refer to objects directly. Instead, we refer to objects through
+ * handles, which are known to the garbage collector and updated
+ * automatically when the object is moved. Handles should be passed
+ * by value (except in cases like out-parameters) and should never be
+ * allocated on the heap.
+ *
+ * Most functions in the Dart Embedding API return a handle. When a
+ * function completes normally, this will be a valid handle to an
+ * object in the Dart VM heap. This handle may represent the result of
+ * the operation or it may be a special valid handle used merely to
+ * indicate successful completion. Note that a valid handle may in
+ * some cases refer to the null object.
+ *
+ * --- Error handles ---
+ *
+ * When a function encounters a problem that prevents it from
+ * completing normally, it returns an error handle (See Dart_IsError).
+ * An error handle has an associated error message that gives more
+ * details about the problem (See Dart_GetError).
+ *
+ * There are four kinds of error handles that can be produced,
+ * depending on what goes wrong:
+ *
+ * - Api error handles are produced when an api function is misused.
+ *   This happens when a Dart embedding api function is called with
+ *   invalid arguments or in an invalid context.
+ *
+ * - Unhandled exception error handles are produced when, during the
+ *   execution of Dart code, an exception is thrown but not caught.
+ *   Prototypically this would occur during a call to Dart_Invoke, but
+ *   it can occur in any function which triggers the execution of Dart
+ *   code (for example, Dart_ToString).
+ *
+ *   An unhandled exception error provides access to an exception and
+ *   stacktrace via the functions Dart_ErrorGetException and
+ *   Dart_ErrorGetStackTrace.
+ *
+ * - Compilation error handles are produced when, during the execution
+ *   of Dart code, a compile-time error occurs.  As above, this can
+ *   occur in any function which triggers the execution of Dart code.
+ *
+ * - Fatal error handles are produced when the system wants to shut
+ *   down the current isolate.
+ *
+ * --- Propagating errors ---
+ *
+ * When an error handle is returned from the top level invocation of
+ * Dart code in a program, the embedder must handle the error as they
+ * see fit.  Often, the embedder will print the error message produced
+ * by Dart_Error and exit the program.
+ *
+ * When an error is returned while in the body of a native function,
+ * it can be propagated up the call stack by calling
+ * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException.
+ * Errors should be propagated unless there is a specific reason not
+ * to.  If an error is not propagated then it is ignored.  For
+ * example, if an unhandled exception error is ignored, that
+ * effectively "catches" the unhandled exception.  Fatal errors must
+ * always be propagated.
+ *
+ * When an error is propagated, any current scopes created by
+ * Dart_EnterScope will be exited.
+ *
+ * Using Dart_SetReturnValue to propagate an exception is somewhat
+ * more convenient than using Dart_PropagateError, and should be
+ * preferred for reasons discussed below.
+ *
+ * Dart_PropagateError and Dart_ThrowException do not return.  Instead
+ * they transfer control non-locally using a setjmp-like mechanism.
+ * This can be inconvenient if you have resources that you need to
+ * clean up before propagating the error.
+ *
+ * When relying on Dart_PropagateError, we often return error handles
+ * rather than propagating them from helper functions.  Consider the
+ * following contrived example:
+ *
+ * 1    Dart_Handle isLongStringHelper(Dart_Handle arg) {
+ * 2      intptr_t* length = 0;
+ * 3      result = Dart_StringLength(arg, &length);
+ * 4      if (Dart_IsError(result)) {
+ * 5        return result;
+ * 6      }
+ * 7      return Dart_NewBoolean(length > 100);
+ * 8    }
+ * 9
+ * 10   void NativeFunction_isLongString(Dart_NativeArguments args) {
+ * 11     Dart_EnterScope();
+ * 12     AllocateMyResource();
+ * 13     Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ * 14     Dart_Handle result = isLongStringHelper(arg);
+ * 15     if (Dart_IsError(result)) {
+ * 16       FreeMyResource();
+ * 17       Dart_PropagateError(result);
+ * 18       abort();  // will not reach here
+ * 19     }
+ * 20     Dart_SetReturnValue(result);
+ * 21     FreeMyResource();
+ * 22     Dart_ExitScope();
+ * 23   }
+ *
+ * In this example, we have a native function which calls a helper
+ * function to do its work.  On line 5, the helper function could call
+ * Dart_PropagateError, but that would not give the native function a
+ * chance to call FreeMyResource(), causing a leak.  Instead, the
+ * helper function returns the error handle to the caller, giving the
+ * caller a chance to clean up before propagating the error handle.
+ *
+ * When an error is propagated by calling Dart_SetReturnValue, the
+ * native function will be allowed to complete normally and then the
+ * exception will be propagated only once the native call
+ * returns. This can be convenient, as it allows the C code to clean
+ * up normally.
+ *
+ * The example can be written more simply using Dart_SetReturnValue to
+ * propagate the error.
+ *
+ * 1    Dart_Handle isLongStringHelper(Dart_Handle arg) {
+ * 2      intptr_t* length = 0;
+ * 3      result = Dart_StringLength(arg, &length);
+ * 4      if (Dart_IsError(result)) {
+ * 5        return result
+ * 6      }
+ * 7      return Dart_NewBoolean(length > 100);
+ * 8    }
+ * 9
+ * 10   void NativeFunction_isLongString(Dart_NativeArguments args) {
+ * 11     Dart_EnterScope();
+ * 12     AllocateMyResource();
+ * 13     Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ * 14     Dart_SetReturnValue(isLongStringHelper(arg));
+ * 15     FreeMyResource();
+ * 16     Dart_ExitScope();
+ * 17   }
+ *
+ * In this example, the call to Dart_SetReturnValue on line 14 will
+ * either return the normal return value or the error (potentially
+ * generated on line 3).  The call to FreeMyResource on line 15 will
+ * execute in either case.
+ *
+ * --- Local and persistent handles ---
+ *
+ * Local handles are allocated within the current scope (see
+ * Dart_EnterScope) and go away when the current scope exits. Unless
+ * otherwise indicated, callers should assume that all functions in
+ * the Dart embedding api return local handles.
+ *
+ * Persistent handles are allocated within the current isolate. They
+ * can be used to store objects across scopes. Persistent handles have
+ * the lifetime of the current isolate unless they are explicitly
+ * deallocated (see Dart_DeletePersistentHandle).
+ * The type Dart_Handle represents a handle (both local and persistent).
+ * The type Dart_PersistentHandle is a Dart_Handle and it is used to
+ * document that a persistent handle is expected as a parameter to a call
+ * or the return value from a call is a persistent handle.
+ *
+ * FinalizableHandles are persistent handles which are auto deleted when
+ * the object is garbage collected. It is never safe to use these handles
+ * unless you know the object is still reachable.
+ *
+ * WeakPersistentHandles are persistent handles which are automatically set
+ * to point Dart_Null when the object is garbage collected. They are not auto
+ * deleted, so it is safe to use them after the object has become unreachable.
+ */
+typedef struct _Dart_Handle* Dart_Handle;
+typedef Dart_Handle Dart_PersistentHandle;
+typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle;
+typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle;
+// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the
+// version when changing this struct.
+
+typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer);
+
+/**
+ * Is this an error handle?
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsError(Dart_Handle handle);
+
+/**
+ * Is this an api error handle?
+ *
+ * Api error handles are produced when an api function is misused.
+ * This happens when a Dart embedding api function is called with
+ * invalid arguments or in an invalid context.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsApiError(Dart_Handle handle);
+
+/**
+ * Is this an unhandled exception error handle?
+ *
+ * Unhandled exception error handles are produced when, during the
+ * execution of Dart code, an exception is thrown but not caught.
+ * This can occur in any function which triggers the execution of Dart
+ * code.
+ *
+ * See Dart_ErrorGetException and Dart_ErrorGetStackTrace.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle);
+
+/**
+ * Is this a compilation error handle?
+ *
+ * Compilation error handles are produced when, during the execution
+ * of Dart code, a compile-time error occurs.  This can occur in any
+ * function which triggers the execution of Dart code.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle);
+
+/**
+ * Is this a fatal error handle?
+ *
+ * Fatal error handles are produced when the system wants to shut down
+ * the current isolate.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
+
+/**
+ * Gets the error message from an error handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A C string containing an error message if the handle is
+ *   error. An empty C string ("") if the handle is valid. This C
+ *   String is scope allocated and is only valid until the next call
+ *   to Dart_ExitScope.
+*/
+DART_EXPORT const char* Dart_GetError(Dart_Handle handle);
+
+/**
+ * Is this an error handle for an unhandled exception?
+ */
+DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle);
+
+/**
+ * Gets the exception Object from an unhandled exception error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle);
+
+/**
+ * Gets the stack trace Object from an unhandled exception error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle);
+
+/**
+ * Produces an api error handle with the provided error message.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param error the error message.
+ */
+DART_EXPORT Dart_Handle Dart_NewApiError(const char* error);
+DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error);
+
+/**
+ * Produces a new unhandled exception error handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param exception An instance of a Dart object to be thrown or
+ *        an ApiError or CompilationError handle.
+ *        When an ApiError or CompilationError handle is passed in
+ *        a string object of the error message is created and it becomes
+ *        the Dart object to be thrown.
+ */
+DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception);
+
+/**
+ * Propagates an error.
+ *
+ * If the provided handle is an unhandled exception error, this
+ * function will cause the unhandled exception to be rethrown.  This
+ * will proceed in the standard way, walking up Dart frames until an
+ * appropriate 'catch' block is found, executing 'finally' blocks,
+ * etc.
+ *
+ * If the error is not an unhandled exception error, we will unwind
+ * the stack to the next C frame.  Intervening Dart frames will be
+ * discarded; specifically, 'finally' blocks will not execute.  This
+ * is the standard way that compilation errors (and the like) are
+ * handled by the Dart runtime.
+ *
+ * In either case, when an error is propagated any current scopes
+ * created by Dart_EnterScope will be exited.
+ *
+ * See the additional discussion under "Propagating Errors" at the
+ * beginning of this file.
+ *
+ * \param handle An error handle (See Dart_IsError)
+ *
+ * On success, this function does not return.  On failure, the
+ * process is terminated.
+ */
+DART_EXPORT void Dart_PropagateError(Dart_Handle handle);
+
+/**
+ * Converts an object to a string.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return The converted string if no error occurs during
+ *   the conversion. If an error does occur, an error handle is
+ *   returned.
+ */
+DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object);
+
+/**
+ * Checks to see if two handles refer to identically equal objects.
+ *
+ * If both handles refer to instances, this is equivalent to using the top-level
+ * function identical() from dart:core. Otherwise, returns whether the two
+ * argument handles refer to the same object.
+ *
+ * \param obj1 An object to be compared.
+ * \param obj2 An object to be compared.
+ *
+ * \return True if the objects are identically equal.  False otherwise.
+ */
+DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2);
+
+/**
+ * Allocates a handle in the current scope from a persistent handle.
+ */
+DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object);
+
+/**
+ * Allocates a handle in the current scope from a weak persistent handle.
+ *
+ * This will be a handle to Dart_Null if the object has been garbage collected.
+ */
+DART_EXPORT Dart_Handle
+Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object);
+
+/**
+ * Allocates a persistent handle for an object.
+ *
+ * This handle has the lifetime of the current isolate unless it is
+ * explicitly deallocated by calling Dart_DeletePersistentHandle.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object);
+
+/**
+ * Assign value of local handle to a persistent handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param obj1 A persistent handle whose value needs to be set.
+ * \param obj2 An object whose value needs to be set to the persistent handle.
+ */
+DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
+                                          Dart_Handle obj2);
+
+/**
+ * Deallocates a persistent handle.
+ *
+ * Requires there to be a current isolate group.
+ */
+DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object);
+
+/**
+ * Allocates a weak persistent handle for an object.
+ *
+ * This handle has the lifetime of the current isolate. The handle can also be
+ * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle.
+ *
+ * If the object becomes unreachable the callback is invoked with the peer as
+ * argument. The callback can be executed on any thread, will have a current
+ * isolate group, but will not have a current isolate. The callback can only
+ * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This
+ * gives the embedder the ability to cleanup data associated with the object.
+ * The handle will point to the Dart_Null object after the finalizer has been
+ * run. It is illegal to call into the VM with any other Dart_* functions from
+ * the callback. If the handle is deleted before the object becomes
+ * unreachable, the callback is never invoked.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param object An object with identity.
+ * \param peer A pointer to a native object or NULL.  This value is
+ *   provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ *   bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ *   after the object is garbage collected, unless the handle has been deleted.
+ *   A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The weak persistent handle or NULL. NULL is returned in case of bad
+ *   parameters.
+ */
+DART_EXPORT Dart_WeakPersistentHandle
+Dart_NewWeakPersistentHandle(Dart_Handle object,
+                             void* peer,
+                             intptr_t external_allocation_size,
+                             Dart_HandleFinalizer callback);
+
+/**
+ * Deletes the given weak persistent [object] handle.
+ *
+ * Requires there to be a current isolate group.
+ */
+DART_EXPORT void Dart_DeleteWeakPersistentHandle(
+    Dart_WeakPersistentHandle object);
+
+/**
+ * Updates the external memory size for the given weak persistent handle.
+ *
+ * May trigger garbage collection.
+ */
+DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object,
+                                         intptr_t external_allocation_size);
+
+/**
+ * Allocates a finalizable handle for an object.
+ *
+ * This handle has the lifetime of the current isolate group unless the object
+ * pointed to by the handle is garbage collected, in this case the VM
+ * automatically deletes the handle after invoking the callback associated
+ * with the handle. The handle can also be explicitly deallocated by
+ * calling Dart_DeleteFinalizableHandle.
+ *
+ * If the object becomes unreachable the callback is invoked with the
+ * the peer as argument. The callback can be executed on any thread, will have
+ * an isolate group, but will not have a current isolate. The callback can only
+ * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle.
+ * This gives the embedder the ability to cleanup data associated with the
+ * object and clear out any cached references to the handle. All references to
+ * this handle after the callback will be invalid. It is illegal to call into
+ * the VM with any other Dart_* functions from the callback. If the handle is
+ * deleted before the object becomes unreachable, the callback is never
+ * invoked.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param object An object with identity.
+ * \param peer A pointer to a native object or NULL.  This value is
+ *   provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ *   bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ *   after the object is garbage collected, unless the handle has been deleted.
+ *   A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The finalizable handle or NULL. NULL is returned in case of bad
+ *   parameters.
+ */
+DART_EXPORT Dart_FinalizableHandle
+Dart_NewFinalizableHandle(Dart_Handle object,
+                          void* peer,
+                          intptr_t external_allocation_size,
+                          Dart_HandleFinalizer callback);
+
+/**
+ * Deletes the given finalizable [object] handle.
+ *
+ * The caller has to provide the actual Dart object the handle was created from
+ * to prove the object (and therefore the finalizable handle) is still alive.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object,
+                                              Dart_Handle strong_ref_to_object);
+
+/**
+ * Updates the external memory size for the given finalizable handle.
+ *
+ * The caller has to provide the actual Dart object the handle was created from
+ * to prove the object (and therefore the finalizable handle) is still alive.
+ *
+ * May trigger garbage collection.
+ */
+DART_EXPORT void Dart_UpdateFinalizableExternalSize(
+    Dart_FinalizableHandle object,
+    Dart_Handle strong_ref_to_object,
+    intptr_t external_allocation_size);
+
+/*
+ * ==========================
+ * Initialization and Globals
+ * ==========================
+ */
+
+/**
+ * Gets the version string for the Dart VM.
+ *
+ * The version of the Dart VM can be accessed without initializing the VM.
+ *
+ * \return The version string for the embedded Dart VM.
+ */
+DART_EXPORT const char* Dart_VersionString(void);
+
+/**
+ * Isolate specific flags are set when creating a new isolate using the
+ * Dart_IsolateFlags structure.
+ *
+ * Current version of flags is encoded in a 32-bit integer with 16 bits used
+ * for each part.
+ */
+
+#define DART_FLAGS_CURRENT_VERSION (0x0000000c)
+
+typedef struct {
+  int32_t version;
+  bool enable_asserts;
+  bool use_field_guards;
+  bool use_osr;
+  bool obfuscate;
+  bool load_vmservice_library;
+  bool copy_parent_code;
+  bool null_safety;
+  bool is_system_isolate;
+  bool snapshot_is_dontneed_safe;
+  bool branch_coverage;
+} Dart_IsolateFlags;
+
+/**
+ * Initialize Dart_IsolateFlags with correct version and default values.
+ */
+DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags);
+
+/**
+ * An isolate creation and initialization callback function.
+ *
+ * This callback, provided by the embedder, is called when the VM
+ * needs to create an isolate. The callback should create an isolate
+ * by calling Dart_CreateIsolateGroup and load any scripts required for
+ * execution.
+ *
+ * This callback may be called on a different thread than the one
+ * running the parent isolate.
+ *
+ * When the function returns NULL, it is the responsibility of this
+ * function to ensure that Dart_ShutdownIsolate has been called if
+ * required (for example, if the isolate was created successfully by
+ * Dart_CreateIsolateGroup() but the root library fails to load
+ * successfully, then the function should call Dart_ShutdownIsolate
+ * before returning).
+ *
+ * When the function returns NULL, the function should set *error to
+ * a malloc-allocated buffer containing a useful error message.  The
+ * caller of this function (the VM) will make sure that the buffer is
+ * freed.
+ *
+ * \param script_uri The uri of the main source file or snapshot to load.
+ *   Either the URI of the parent isolate set in Dart_CreateIsolateGroup for
+ *   Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the
+ *   library tag handler of the parent isolate.
+ *   The callback is responsible for loading the program by a call to
+ *   Dart_LoadScriptFromKernel.
+ * \param main The name of the main entry point this isolate will
+ *   eventually run.  This is provided for advisory purposes only to
+ *   improve debugging messages.  The main function is not invoked by
+ *   this function.
+ * \param package_root Ignored.
+ * \param package_config Uri of the package configuration file (either in format
+ *   of .packages or .dart_tool/package_config.json) for this isolate
+ *   to resolve package imports against. If this parameter is not passed the
+ *   package resolution of the parent isolate should be used.
+ * \param flags Default flags for this isolate being spawned. Either inherited
+ *   from the spawning isolate or passed as parameters when spawning the
+ *   isolate from Dart code.
+ * \param isolate_data The isolate data which was passed to the
+ *   parent isolate when it was created by calling Dart_CreateIsolateGroup().
+ * \param error A structure into which the embedder can place a
+ *   C string containing an error message in the case of failures.
+ *
+ * \return The embedder returns NULL if the creation and
+ *   initialization was not successful and the isolate if successful.
+ */
+typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)(
+    const char* script_uri,
+    const char* main,
+    const char* package_root,
+    const char* package_config,
+    Dart_IsolateFlags* flags,
+    void* isolate_data,
+    char** error);
+
+/**
+ * An isolate initialization callback function.
+ *
+ * This callback, provided by the embedder, is called when the VM has created an
+ * isolate within an existing isolate group (i.e. from the same source as an
+ * existing isolate).
+ *
+ * The callback should setup native resolvers and might want to set a custom
+ * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as
+ * runnable.
+ *
+ * This callback may be called on a different thread than the one
+ * running the parent isolate.
+ *
+ * When the function returns `false`, it is the responsibility of this
+ * function to ensure that `Dart_ShutdownIsolate` has been called.
+ *
+ * When the function returns `false`, the function should set *error to
+ * a malloc-allocated buffer containing a useful error message.  The
+ * caller of this function (the VM) will make sure that the buffer is
+ * freed.
+ *
+ * \param child_isolate_data The callback data to associate with the new
+ *        child isolate.
+ * \param error A structure into which the embedder can place a
+ *   C string containing an error message in the case the initialization fails.
+ *
+ * \return The embedder returns true if the initialization was successful and
+ *         false otherwise (in which case the VM will terminate the isolate).
+ */
+typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data,
+                                               char** error);
+
+/**
+ * An isolate shutdown callback function.
+ *
+ * This callback, provided by the embedder, is called before the vm
+ * shuts down an isolate.  The isolate being shutdown will be the current
+ * isolate. It is safe to run Dart code.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ *   isolate group when it was created.
+ * \param isolate_data The same callback data which was passed to the isolate
+ *   when it was created.
+ */
+typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data,
+                                             void* isolate_data);
+
+/**
+ * An isolate cleanup callback function.
+ *
+ * This callback, provided by the embedder, is called after the vm
+ * shuts down an isolate. There will be no current isolate and it is *not*
+ * safe to run Dart code.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ *   isolate group when it was created.
+ * \param isolate_data The same callback data which was passed to the isolate
+ *   when it was created.
+ */
+typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data,
+                                            void* isolate_data);
+
+/**
+ * An isolate group cleanup callback function.
+ *
+ * This callback, provided by the embedder, is called after the vm
+ * shuts down an isolate group.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ *   isolate group when it was created.
+ *
+ */
+typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data);
+
+/**
+ * A thread start callback function.
+ * This callback, provided by the embedder, is called after a thread in the
+ * vm thread pool starts.
+ * This function could be used to adjust thread priority or attach native
+ * resources to the thread.
+ */
+typedef void (*Dart_ThreadStartCallback)(void);
+
+/**
+ * A thread death callback function.
+ * This callback, provided by the embedder, is called before a thread in the
+ * vm thread pool exits.
+ * This function could be used to dispose of native resources that
+ * are associated and attached to the thread, in order to avoid leaks.
+ */
+typedef void (*Dart_ThreadExitCallback)(void);
+
+/**
+ * Opens a file for reading or writing.
+ *
+ * Callback provided by the embedder for file operations. If the
+ * embedder does not allow file operations this callback can be
+ * NULL.
+ *
+ * \param name The name of the file to open.
+ * \param write A boolean variable which indicates if the file is to
+ *   opened for writing. If there is an existing file it needs to truncated.
+ */
+typedef void* (*Dart_FileOpenCallback)(const char* name, bool write);
+
+/**
+ * Read contents of file.
+ *
+ * Callback provided by the embedder for file operations. If the
+ * embedder does not allow file operations this callback can be
+ * NULL.
+ *
+ * \param data Buffer allocated in the callback into which the contents
+ *   of the file are read into. It is the responsibility of the caller to
+ *   free this buffer.
+ * \param file_length A variable into which the length of the file is returned.
+ *   In the case of an error this value would be -1.
+ * \param stream Handle to the opened file.
+ */
+typedef void (*Dart_FileReadCallback)(uint8_t** data,
+                                      intptr_t* file_length,
+                                      void* stream);
+
+/**
+ * Write data into file.
+ *
+ * Callback provided by the embedder for file operations. If the
+ * embedder does not allow file operations this callback can be
+ * NULL.
+ *
+ * \param data Buffer which needs to be written into the file.
+ * \param length Length of the buffer.
+ * \param stream Handle to the opened file.
+ */
+typedef void (*Dart_FileWriteCallback)(const void* data,
+                                       intptr_t length,
+                                       void* stream);
+
+/**
+ * Closes the opened file.
+ *
+ * Callback provided by the embedder for file operations. If the
+ * embedder does not allow file operations this callback can be
+ * NULL.
+ *
+ * \param stream Handle to the opened file.
+ */
+typedef void (*Dart_FileCloseCallback)(void* stream);
+
+typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length);
+
+/**
+ * Callback provided by the embedder that is used by the vmservice isolate
+ * to request the asset archive. The asset archive must be an uncompressed tar
+ * archive that is stored in a Uint8List.
+ *
+ * If the embedder has no vmservice isolate assets, the callback can be NULL.
+ *
+ * \return The embedder must return a handle to a Uint8List containing an
+ *   uncompressed tar archive or null.
+ */
+typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(void);
+
+/**
+ * The current version of the Dart_InitializeFlags. Should be incremented every
+ * time Dart_InitializeFlags changes in a binary incompatible way.
+ */
+#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000006)
+
+/** Forward declaration */
+struct Dart_CodeObserver;
+
+/**
+ * Callback provided by the embedder that is used by the VM to notify on code
+ * object creation, *before* it is invoked the first time.
+ * This is useful for embedders wanting to e.g. keep track of PCs beyond
+ * the lifetime of the garbage collected code objects.
+ * Note that an address range may be used by more than one code object over the
+ * lifecycle of a process. Clients of this function should record timestamps for
+ * these compilation events and when collecting PCs to disambiguate reused
+ * address ranges.
+ */
+typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer,
+                                       const char* name,
+                                       uintptr_t base,
+                                       uintptr_t size);
+
+typedef struct Dart_CodeObserver {
+  void* data;
+
+  Dart_OnNewCodeCallback on_new_code;
+} Dart_CodeObserver;
+
+typedef struct _Dart_Task* Dart_Task;
+typedef enum {
+  Dart_TaskPriority_Default,
+} Dart_TaskPriority;
+typedef struct {
+  /**
+   * Placeholder.
+   */
+  Dart_TaskPriority priority;
+  /**
+   * Time after which the task should run according to the clock of
+   * Dart_TimelineGetMicros.
+   */
+  int64_t time_point;
+} Dart_TaskData;
+/**
+ * Callback provided by the embedder that is used by the VM to eventually run
+ * various tasks. If no callback is provided, these tasks will run on a
+ * VM-internal thread pool. This callback allows the embedder to make its own
+ * choices around the scheduling of these tasks: when they run, how many threads
+ * are servicing these tasks, the priorities of said threads, etc.
+ * The callback can be invoked as early as during the Dart_Initialize call.
+ *
+ * \param post_task_data
+ *     The data provided to Dart_InitializeParams.post_task_data.
+ * \param task
+ *     A task that should eventually be passed to Dart_RunTask.
+ * \param task_data
+ *     Hints about when the task should run.
+ */
+typedef void (*Dart_PostTaskCallback)(void* post_task_data,
+                                      Dart_Task task,
+                                      Dart_TaskData task_data);
+
+/**
+ * Runs a task given to the Dart_PostTaskCallback. Must not be called
+ * synchronously in response to any callback from the VM. In particular, must
+ * not be called synchronously by the implemention of a Dart native function
+ * or Dart_Post_TaskCallback.
+ *
+ * Requires there to be no current isolate or isolate group.
+ */
+DART_EXPORT void Dart_RunTask(Dart_Task task);
+
+/**
+ * Optional callback provided by the embedder that is used by the VM to
+ * implement registration of kernel blobs for the subsequent Isolate.spawnUri
+ * If no callback is provided, the registration of kernel blobs will throw
+ * an error.
+ * 
+ * \param kernel_buffer A buffer which contains a kernel program. Callback
+ *                      should copy the contents of `kernel_buffer` as
+ *                      it may be freed immediately after registration.
+ * \param kernel_buffer_size The size of `kernel_buffer`.
+ *
+ * \return A C string representing URI which can be later used
+ *         to spawn a new isolate. This C String should be scope allocated
+ *         or owned by the embedder.
+ *         Returns NULL if embedder runs out of memory.
+ */
+typedef const char* (*Dart_RegisterKernelBlobCallback)(
+    const uint8_t* kernel_buffer,
+    intptr_t kernel_buffer_size);
+
+/**
+ * Optional callback provided by the embedder that is used by the VM to
+ * unregister kernel blobs.
+ * If no callback is provided, the unregistration of kernel blobs will throw
+ * an error.
+ * 
+ * \param kernel_blob_uri URI of the kernel blob to unregister.
+ */
+typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri);
+
+/**
+ * Describes how to initialize the VM. Used with Dart_Initialize.
+ */
+typedef struct {
+  /**
+   * Identifies the version of the struct used by the client.
+   * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION.
+   */
+  int32_t version;
+
+  /**
+   * A buffer containing snapshot data, or NULL if no snapshot is provided.
+   *
+   * If provided, the buffer must remain valid until Dart_Cleanup returns.
+   */
+  const uint8_t* vm_snapshot_data;
+
+  /**
+   * A buffer containing a snapshot of precompiled instructions, or NULL if
+   * no snapshot is provided.
+   *
+   * If provided, the buffer must remain valid until Dart_Cleanup returns.
+   */
+  const uint8_t* vm_snapshot_instructions;
+
+  /**
+   * A function to be called during isolate group creation.
+   * See Dart_IsolateGroupCreateCallback.
+   */
+  Dart_IsolateGroupCreateCallback create_group;
+
+  /**
+   * A function to be called during isolate
+   * initialization inside an existing isolate group.
+   * See Dart_InitializeIsolateCallback.
+   */
+  Dart_InitializeIsolateCallback initialize_isolate;
+
+  /**
+   * A function to be called right before an isolate is shutdown.
+   * See Dart_IsolateShutdownCallback.
+   */
+  Dart_IsolateShutdownCallback shutdown_isolate;
+
+  /**
+   * A function to be called after an isolate was shutdown.
+   * See Dart_IsolateCleanupCallback.
+   */
+  Dart_IsolateCleanupCallback cleanup_isolate;
+
+  /**
+   * A function to be called after an isolate group is
+   * shutdown. See Dart_IsolateGroupCleanupCallback.
+   */
+  Dart_IsolateGroupCleanupCallback cleanup_group;
+
+  Dart_ThreadStartCallback thread_start;
+  Dart_ThreadExitCallback thread_exit;
+  Dart_FileOpenCallback file_open;
+  Dart_FileReadCallback file_read;
+  Dart_FileWriteCallback file_write;
+  Dart_FileCloseCallback file_close;
+  Dart_EntropySource entropy_source;
+
+  /**
+   * A function to be called by the service isolate when it requires the
+   * vmservice assets archive. See Dart_GetVMServiceAssetsArchive.
+   */
+  Dart_GetVMServiceAssetsArchive get_service_assets;
+
+  bool start_kernel_isolate;
+
+  /**
+   * An external code observer callback function. The observer can be invoked
+   * as early as during the Dart_Initialize() call.
+   */
+  Dart_CodeObserver* code_observer;
+
+  /**
+   * A task scheduling callback function. See Dart_PostTaskCallback.
+   */
+  Dart_PostTaskCallback post_task;
+
+  void* post_task_data;
+
+  /**
+   * Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback.
+   */
+  Dart_RegisterKernelBlobCallback register_kernel_blob;
+
+  /**
+   * Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback.
+   */
+  Dart_UnregisterKernelBlobCallback unregister_kernel_blob;
+} Dart_InitializeParams;
+
+/**
+ * Initializes the VM.
+ *
+ * \param params A struct containing initialization information. The version
+ *   field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION.
+ *
+ * \return NULL if initialization is successful. Returns an error message
+ *   otherwise. The caller is responsible for freeing the error message.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Initialize(
+    Dart_InitializeParams* params);
+
+/**
+ * Cleanup state in the VM before process termination.
+ *
+ * \return NULL if cleanup is successful. Returns an error message otherwise.
+ *   The caller is responsible for freeing the error message.
+ *
+ * NOTE: This function must not be called on a thread that was created by the VM
+ * itself.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup(void);
+
+/**
+ * Sets command line flags. Should be called before Dart_Initialize.
+ *
+ * \param argc The length of the arguments array.
+ * \param argv An array of arguments.
+ *
+ * \return NULL if successful. Returns an error message otherwise.
+ *  The caller is responsible for freeing the error message.
+ *
+ * NOTE: This call does not store references to the passed in c-strings.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc,
+                                                          const char** argv);
+
+/**
+ * Returns true if the named VM flag is of boolean type, specified, and set to
+ * true.
+ *
+ * \param flag_name The name of the flag without leading punctuation
+ *                  (example: "enable_asserts").
+ */
+DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
+
+/*
+ * ========
+ * Isolates
+ * ========
+ */
+
+/**
+ * Creates a new isolate. The new isolate becomes the current isolate.
+ *
+ * A snapshot can be used to restore the VM quickly to a saved state
+ * and is useful for fast startup. If snapshot data is provided, the
+ * isolate will be started using that snapshot data. Requires a core snapshot or
+ * an app snapshot created by Dart_CreateSnapshot or
+ * Dart_CreatePrecompiledSnapshot* from a VM with the same version.
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param script_uri The main source file or snapshot this isolate will load.
+ *   The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a
+ *   child isolate is created by Isolate.spawn. The embedder should use a URI
+ *   that allows it to load the same program into such a child isolate.
+ * \param name A short name for the isolate to improve debugging messages.
+ *   Typically of the format 'foo.dart:main()'.
+ * \param isolate_snapshot_data Buffer containing the snapshot data of the
+ *   isolate or NULL if no snapshot is provided. If provided, the buffer must
+ *   remain valid until the isolate shuts down.
+ * \param isolate_snapshot_instructions Buffer containing the snapshot
+ *   instructions of the isolate or NULL if no snapshot is provided. If
+ *   provided, the buffer must remain valid until the isolate shuts down.
+ * \param flags Pointer to VM specific flags or NULL for default flags.
+ * \param isolate_group_data Embedder group data. This data can be obtained
+ *   by calling Dart_IsolateGroupData and will be passed to the
+ *   Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
+ *   Dart_IsolateGroupCleanupCallback.
+ * \param isolate_data Embedder data.  This data will be passed to
+ *   the Dart_IsolateGroupCreateCallback when new isolates are spawned from
+ *   this parent isolate.
+ * \param error Returns NULL if creation is successful, an error message
+ *   otherwise. The caller is responsible for calling free() on the error
+ *   message.
+ *
+ * \return The new isolate on success, or NULL if isolate creation failed.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateGroup(const char* script_uri,
+                        const char* name,
+                        const uint8_t* isolate_snapshot_data,
+                        const uint8_t* isolate_snapshot_instructions,
+                        Dart_IsolateFlags* flags,
+                        void* isolate_group_data,
+                        void* isolate_data,
+                        char** error);
+/**
+ * Creates a new isolate inside the isolate group of [group_member].
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param group_member An isolate from the same group into which the newly created
+ *   isolate should be born into. Other threads may not have entered / enter this
+ *   member isolate.
+ * \param name A short name for the isolate for debugging purposes.
+ * \param shutdown_callback A callback to be called when the isolate is being
+ *   shutdown (may be NULL).
+ * \param cleanup_callback A callback to be called when the isolate is being
+ *   cleaned up (may be NULL).
+ * \param isolate_data The embedder-specific data associated with this isolate.
+ * \param error Set to NULL if creation is successful, set to an error
+ *   message otherwise. The caller is responsible for calling free() on the
+ *   error message.
+ *
+ * \return The newly created isolate on success, or NULL if isolate creation
+ *   failed.
+ *
+ * If successful, the newly created isolate will become the current isolate.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateInGroup(Dart_Isolate group_member,
+                          const char* name,
+                          Dart_IsolateShutdownCallback shutdown_callback,
+                          Dart_IsolateCleanupCallback cleanup_callback,
+                          void* child_isolate_data,
+                          char** error);
+
+/* TODO(turnidge): Document behavior when there is already a current
+ * isolate. */
+
+/**
+ * Creates a new isolate from a Dart Kernel file. The new isolate
+ * becomes the current isolate.
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param script_uri The main source file or snapshot this isolate will load.
+ *   The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a
+ * child isolate is created by Isolate.spawn. The embedder should use a URI that
+ *   allows it to load the same program into such a child isolate.
+ * \param name A short name for the isolate to improve debugging messages.
+ *   Typically of the format 'foo.dart:main()'.
+ * \param kernel_buffer A buffer which contains a kernel/DIL program. Must
+ *   remain valid until isolate shutdown.
+ * \param kernel_buffer_size The size of `kernel_buffer`.
+ * \param flags Pointer to VM specific flags or NULL for default flags.
+ * \param isolate_group_data Embedder group data. This data can be obtained
+ *   by calling Dart_IsolateGroupData and will be passed to the
+ *   Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
+ *   Dart_IsolateGroupCleanupCallback.
+ * \param isolate_data Embedder data.  This data will be passed to
+ *   the Dart_IsolateGroupCreateCallback when new isolates are spawned from
+ *   this parent isolate.
+ * \param error Returns NULL if creation is successful, an error message
+ *   otherwise. The caller is responsible for calling free() on the error
+ *   message.
+ *
+ * \return The new isolate on success, or NULL if isolate creation failed.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateGroupFromKernel(const char* script_uri,
+                                  const char* name,
+                                  const uint8_t* kernel_buffer,
+                                  intptr_t kernel_buffer_size,
+                                  Dart_IsolateFlags* flags,
+                                  void* isolate_group_data,
+                                  void* isolate_data,
+                                  char** error);
+/**
+ * Shuts down the current isolate. After this call, the current isolate is NULL.
+ * Any current scopes created by Dart_EnterScope will be exited. Invokes the
+ * shutdown callback and any callbacks of remaining weak persistent handles.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ShutdownIsolate(void);
+/* TODO(turnidge): Document behavior when there is no current isolate. */
+
+/**
+ * Returns the current isolate. Will return NULL if there is no
+ * current isolate.
+ */
+DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void);
+
+/**
+ * Returns the callback data associated with the current isolate. This
+ * data was set when the isolate got created or initialized.
+ */
+DART_EXPORT void* Dart_CurrentIsolateData(void);
+
+/**
+ * Returns the callback data associated with the given isolate. This
+ * data was set when the isolate got created or initialized.
+ */
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate);
+
+/**
+ * Returns the current isolate group. Will return NULL if there is no
+ * current isolate group.
+ */
+DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(void);
+
+/**
+ * Returns the callback data associated with the current isolate group. This
+ * data was passed to the isolate group when it was created.
+ */
+DART_EXPORT void* Dart_CurrentIsolateGroupData(void);
+
+/**
+ * Returns the callback data associated with the specified isolate group. This
+ * data was passed to the isolate when it was created.
+ * The embedder is responsible for ensuring the consistency of this data
+ * with respect to the lifecycle of an isolate group.
+ */
+DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate);
+
+/**
+ * Returns the debugging name for the current isolate.
+ *
+ * This name is unique to each isolate and should only be used to make
+ * debugging messages more comprehensible.
+ */
+DART_EXPORT Dart_Handle Dart_DebugName(void);
+
+/**
+ * Returns the ID for an isolate which is used to query the service protocol.
+ *
+ * It is the responsibility of the caller to free the returned ID.
+ */
+DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate);
+
+/**
+ * Enters an isolate. After calling this function,
+ * the current isolate will be set to the provided isolate.
+ *
+ * Requires there to be no current isolate. Multiple threads may not be in
+ * the same isolate at once.
+ */
+DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate);
+
+/**
+ * Kills the given isolate.
+ *
+ * This function has the same effect as dart:isolate's
+ * Isolate.kill(priority:immediate).
+ * It can interrupt ordinary Dart code but not native code. If the isolate is
+ * in the middle of a long running native function, the isolate will not be
+ * killed until control returns to Dart.
+ *
+ * Does not require a current isolate. It is safe to kill the current isolate if
+ * there is one.
+ */
+DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate);
+
+/**
+ * Notifies the VM that the embedder expects to be idle until |deadline|. The VM
+ * may use this time to perform garbage collection or other tasks to avoid
+ * delays during execution of Dart code in the future.
+ *
+ * |deadline| is measured in microseconds against the system's monotonic time.
+ * This clock can be accessed via Dart_TimelineGetMicros().
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_NotifyIdle(int64_t deadline);
+
+/**
+ * Notifies the VM that the system is running low on memory.
+ *
+ * Does not require a current isolate. Only valid after calling Dart_Initialize.
+ */
+DART_EXPORT void Dart_NotifyLowMemory(void);
+
+/**
+ * Starts the CPU sampling profiler.
+ */
+DART_EXPORT void Dart_StartProfiling(void);
+
+/**
+ * Stops the CPU sampling profiler.
+ *
+ * Note that some profile samples might still be taken after this fucntion
+ * returns due to the asynchronous nature of the implementation on some
+ * platforms.
+ */
+DART_EXPORT void Dart_StopProfiling(void);
+
+/**
+ * Notifies the VM that the current thread should not be profiled until a
+ * matching call to Dart_ThreadEnableProfiling is made.
+ *
+ * NOTE: By default, if a thread has entered an isolate it will be profiled.
+ * This function should be used when an embedder knows a thread is about
+ * to make a blocking call and wants to avoid unnecessary interrupts by
+ * the profiler.
+ */
+DART_EXPORT void Dart_ThreadDisableProfiling(void);
+
+/**
+ * Notifies the VM that the current thread should be profiled.
+ *
+ * NOTE: It is only legal to call this function *after* calling
+ *   Dart_ThreadDisableProfiling.
+ *
+ * NOTE: By default, if a thread has entered an isolate it will be profiled.
+ */
+DART_EXPORT void Dart_ThreadEnableProfiling(void);
+
+/**
+ * Register symbol information for the Dart VM's profiler and crash dumps.
+ *
+ * This consumes the output of //topaz/runtime/dart/profiler_symbols, which
+ * should be treated as opaque.
+ */
+DART_EXPORT void Dart_AddSymbols(const char* dso_name,
+                                 void* buffer,
+                                 intptr_t buffer_size);
+
+/**
+ * Exits an isolate. After this call, Dart_CurrentIsolate will
+ * return NULL.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ExitIsolate(void);
+/* TODO(turnidge): We don't want users of the api to be able to exit a
+ * "pure" dart isolate. Implement and document. */
+
+/**
+ * Creates a full snapshot of the current isolate heap.
+ *
+ * A full snapshot is a compact representation of the dart vm isolate heap
+ * and dart isolate heap states. These snapshots are used to initialize
+ * the vm isolate on startup and fast initialization of an isolate.
+ * A Snapshot of the heap is created before any dart code has executed.
+ *
+ * Requires there to be a current isolate. Not available in the precompiled
+ * runtime (check Dart_IsPrecompiledRuntime).
+ *
+ * \param vm_snapshot_data_buffer Returns a pointer to a buffer containing the
+ *   vm snapshot. This buffer is scope allocated and is only valid
+ *   until the next call to Dart_ExitScope.
+ * \param vm_snapshot_data_size Returns the size of vm_snapshot_data_buffer.
+ * \param isolate_snapshot_data_buffer Returns a pointer to a buffer containing
+ *   the isolate snapshot. This buffer is scope allocated and is only valid
+ *   until the next call to Dart_ExitScope.
+ * \param isolate_snapshot_data_size Returns the size of
+ *   isolate_snapshot_data_buffer.
+ * \param is_core Create a snapshot containing core libraries.
+ *   Such snapshot should be agnostic to null safety mode.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
+                    intptr_t* vm_snapshot_data_size,
+                    uint8_t** isolate_snapshot_data_buffer,
+                    intptr_t* isolate_snapshot_data_size,
+                    bool is_core);
+
+/**
+ * Returns whether the buffer contains a kernel file.
+ *
+ * \param buffer Pointer to a buffer that might contain a kernel binary.
+ * \param buffer_size Size of the buffer.
+ *
+ * \return Whether the buffer contains a kernel binary (full or partial).
+ */
+DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size);
+
+/**
+ * Make isolate runnable.
+ *
+ * When isolates are spawned, this function is used to indicate that
+ * the creation and initialization (including script loading) of the
+ * isolate is complete and the isolate can start.
+ * This function expects there to be no current isolate.
+ *
+ * \param isolate The isolate to be made runnable.
+ *
+ * \return NULL if successful. Returns an error message otherwise. The caller
+ * is responsible for freeing the error message.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable(
+    Dart_Isolate isolate);
+
+/*
+ * ==================
+ * Messages and Ports
+ * ==================
+ */
+
+/**
+ * A port is used to send or receive inter-isolate messages
+ */
+typedef int64_t Dart_Port;
+
+/**
+ * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid
+ * port.
+ */
+#define ILLEGAL_PORT ((Dart_Port)0)
+
+/**
+ * A message notification callback.
+ *
+ * This callback allows the embedder to provide an alternate wakeup
+ * mechanism for the delivery of inter-isolate messages.  It is the
+ * responsibility of the embedder to call Dart_HandleMessage to
+ * process the message.
+ */
+typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate dest_isolate);
+
+/**
+ * Allows embedders to provide an alternative wakeup mechanism for the
+ * delivery of inter-isolate messages. This setting only applies to
+ * the current isolate.
+ *
+ * Most embedders will only call this function once, before isolate
+ * execution begins. If this function is called after isolate
+ * execution begins, the embedder is responsible for threading issues.
+ */
+DART_EXPORT void Dart_SetMessageNotifyCallback(
+    Dart_MessageNotifyCallback message_notify_callback);
+/* TODO(turnidge): Consider moving this to isolate creation so that it
+ * is impossible to mess up. */
+
+/**
+ * Query the current message notify callback for the isolate.
+ *
+ * \return The current message notify callback for the isolate.
+ */
+DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback(void);
+
+/**
+ * The VM's default message handler supports pausing an isolate before it
+ * processes the first message and right after the it processes the isolate's
+ * final message. This can be controlled for all isolates by two VM flags:
+ *
+ *   `--pause-isolates-on-start`
+ *   `--pause-isolates-on-exit`
+ *
+ * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be
+ * used to control this behaviour on a per-isolate basis.
+ *
+ * When an embedder is using a Dart_MessageNotifyCallback the embedder
+ * needs to cooperate with the VM so that the service protocol can report
+ * accurate information about isolates and so that tools such as debuggers
+ * work reliably.
+ *
+ * The following functions can be used to implement pausing on start and exit.
+ */
+
+/**
+ * If the VM flag `--pause-isolates-on-start` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on start was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnStart(void);
+
+/**
+ * Override the VM flag `--pause-isolates-on-start` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on start?
+ *
+ * NOTE: This must be called before Dart_IsolateMakeRunnable.
+ */
+DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause);
+
+/**
+ * Is the current isolate paused on start?
+ *
+ * \return A boolean value indicating if the isolate is paused on start.
+ */
+DART_EXPORT bool Dart_IsPausedOnStart(void);
+
+/**
+ * Called when the embedder has paused the current isolate on start and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on start?
+ */
+DART_EXPORT void Dart_SetPausedOnStart(bool paused);
+
+/**
+ * If the VM flag `--pause-isolates-on-exit` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on exit was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnExit(void);
+
+/**
+ * Override the VM flag `--pause-isolates-on-exit` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on exit?
+ *
+ */
+DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause);
+
+/**
+ * Is the current isolate paused on exit?
+ *
+ * \return A boolean value indicating if the isolate is paused on exit.
+ */
+DART_EXPORT bool Dart_IsPausedOnExit(void);
+
+/**
+ * Called when the embedder has paused the current isolate on exit and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on exit?
+ */
+DART_EXPORT void Dart_SetPausedOnExit(bool paused);
+
+/**
+ * Called when the embedder has caught a top level unhandled exception error
+ * in the current isolate.
+ *
+ * NOTE: It is illegal to call this twice on the same isolate without first
+ * clearing the sticky error to null.
+ *
+ * \param error The unhandled exception error.
+ */
+DART_EXPORT void Dart_SetStickyError(Dart_Handle error);
+
+/**
+ * Does the current isolate have a sticky error?
+ */
+DART_EXPORT bool Dart_HasStickyError(void);
+
+/**
+ * Gets the sticky error for the current isolate.
+ *
+ * \return A handle to the sticky error object or null.
+ */
+DART_EXPORT Dart_Handle Dart_GetStickyError(void);
+
+/**
+ * Handles the next pending message for the current isolate.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage(void);
+
+/**
+ * Drains the microtask queue, then blocks the calling thread until the current
+ * isolate recieves a message, then handles all messages.
+ *
+ * \param timeout_millis When non-zero, the call returns after the indicated
+          number of milliseconds even if no message was received.
+ * \return A valid handle if no error occurs, otherwise an error handle.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_WaitForEvent(int64_t timeout_millis);
+
+/**
+ * Handles any pending messages for the vm service for the current
+ * isolate.
+ *
+ * This function may be used by an embedder at a breakpoint to avoid
+ * pausing the vm service.
+ *
+ * This function can indirectly cause the message notify callback to
+ * be called.
+ *
+ * \return true if the vm service requests the program resume
+ * execution, false otherwise
+ */
+DART_EXPORT bool Dart_HandleServiceMessages(void);
+
+/**
+ * Does the current isolate have pending service messages?
+ *
+ * \return true if the isolate has pending service messages, false otherwise.
+ */
+DART_EXPORT bool Dart_HasServiceMessages(void);
+
+/**
+ * Processes any incoming messages for the current isolate.
+ *
+ * This function may only be used when the embedder has not provided
+ * an alternate message delivery mechanism with
+ * Dart_SetMessageCallbacks. It is provided for convenience.
+ *
+ * This function waits for incoming messages for the current
+ * isolate. As new messages arrive, they are handled using
+ * Dart_HandleMessage. The routine exits when all ports to the
+ * current isolate are closed.
+ *
+ * \return A valid handle if the run loop exited successfully.  If an
+ *   exception or other error occurs while processing messages, an
+ *   error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop(void);
+
+/**
+ * Lets the VM run message processing for the isolate.
+ *
+ * This function expects there to a current isolate and the current isolate
+ * must not have an active api scope. The VM will take care of making the
+ * isolate runnable (if not already), handles its message loop and will take
+ * care of shutting the isolate down once it's done.
+ *
+ * \param errors_are_fatal Whether uncaught errors should be fatal.
+ * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT).
+ * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT).
+ * \param error A non-NULL pointer which will hold an error message if the call
+ *   fails. The error has to be free()ed by the caller.
+ *
+ * \return If successfull the VM takes owernship of the isolate and takes care
+ *   of its message loop. If not successful the caller retains owernship of the
+ *   isolate.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT bool Dart_RunLoopAsync(
+    bool errors_are_fatal,
+    Dart_Port on_error_port,
+    Dart_Port on_exit_port,
+    char** error);
+
+/* TODO(turnidge): Should this be removed from the public api? */
+
+/**
+ * Gets the main port id for the current isolate.
+ */
+DART_EXPORT Dart_Port Dart_GetMainPortId(void);
+
+/**
+ * Does the current isolate have live ReceivePorts?
+ *
+ * A ReceivePort is live when it has not been closed.
+ */
+DART_EXPORT bool Dart_HasLivePorts(void);
+
+/**
+ * Posts a message for some isolate. The message is a serialized
+ * object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param port_id The destination port.
+ * \param object An object from the current isolate.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object);
+
+/**
+ * Returns a new SendPort with the provided port id.
+ *
+ * \param port_id The destination port.
+ *
+ * \return A new SendPort if no errors occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);
+
+/**
+ * Gets the SendPort id for the provided SendPort.
+ * \param port A SendPort object whose id is desired.
+ * \param port_id Returns the id of the SendPort.
+ * \return Success if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
+                                           Dart_Port* port_id);
+
+/*
+ * ======
+ * Scopes
+ * ======
+ */
+
+/**
+ * Enters a new scope.
+ *
+ * All new local handles will be created in this scope. Additionally,
+ * some functions may return "scope allocated" memory which is only
+ * valid within this scope.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_EnterScope(void);
+
+/**
+ * Exits a scope.
+ *
+ * The previous scope (if any) becomes the current scope.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ExitScope(void);
+
+/**
+ * The Dart VM uses "zone allocation" for temporary structures. Zones
+ * support very fast allocation of small chunks of memory. The chunks
+ * cannot be deallocated individually, but instead zones support
+ * deallocating all chunks in one fast operation.
+ *
+ * This function makes it possible for the embedder to allocate
+ * temporary data in the VMs zone allocator.
+ *
+ * Zone allocation is possible:
+ *   1. when inside a scope where local handles can be allocated
+ *   2. when processing a message from a native port in a native port
+ *      handler
+ *
+ * All the memory allocated this way will be reclaimed either on the
+ * next call to Dart_ExitScope or when the native port handler exits.
+ *
+ * \param size Size of the memory to allocate.
+ *
+ * \return A pointer to the allocated memory. NULL if allocation
+ *   failed. Failure might due to is no current VM zone.
+ */
+DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size);
+
+/*
+ * =======
+ * Objects
+ * =======
+ */
+
+/**
+ * Returns the null object.
+ *
+ * \return A handle to the null object.
+ */
+DART_EXPORT Dart_Handle Dart_Null(void);
+
+/**
+ * Is this object null?
+ */
+DART_EXPORT bool Dart_IsNull(Dart_Handle object);
+
+/**
+ * Returns the empty string object.
+ *
+ * \return A handle to the empty string object.
+ */
+DART_EXPORT Dart_Handle Dart_EmptyString(void);
+
+/**
+ * Returns types that are not classes, and which therefore cannot be looked up
+ * as library members by Dart_GetType.
+ *
+ * \return A handle to the dynamic, void or Never type.
+ */
+DART_EXPORT Dart_Handle Dart_TypeDynamic(void);
+DART_EXPORT Dart_Handle Dart_TypeVoid(void);
+DART_EXPORT Dart_Handle Dart_TypeNever(void);
+
+/**
+ * Checks if the two objects are equal.
+ *
+ * The result of the comparison is returned through the 'equal'
+ * parameter. The return value itself is used to indicate success or
+ * failure, not equality.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param obj1 An object to be compared.
+ * \param obj2 An object to be compared.
+ * \param equal Returns the result of the equality comparison.
+ *
+ * \return A valid handle if no error occurs during the comparison.
+ */
+DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1,
+                                          Dart_Handle obj2,
+                                          bool* equal);
+
+/**
+ * Is this object an instance of some type?
+ *
+ * The result of the test is returned through the 'instanceof' parameter.
+ * The return value itself is used to indicate success or failure.
+ *
+ * \param object An object.
+ * \param type A type.
+ * \param instanceof Return true if 'object' is an instance of type 'type'.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
+                                          Dart_Handle type,
+                                          bool* instanceof);
+
+/**
+ * Query object type.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is of the specified type.
+ */
+DART_EXPORT bool Dart_IsInstance(Dart_Handle object);
+DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
+DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
+DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
+DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
+DART_EXPORT bool Dart_IsString(Dart_Handle object);
+DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */
+DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
+DART_EXPORT bool Dart_IsList(Dart_Handle object);
+DART_EXPORT bool Dart_IsMap(Dart_Handle object);
+DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
+DART_EXPORT bool Dart_IsType(Dart_Handle handle);
+DART_EXPORT bool Dart_IsFunction(Dart_Handle handle);
+DART_EXPORT bool Dart_IsVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
+DART_EXPORT bool Dart_IsTypedData(Dart_Handle object);
+DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object);
+DART_EXPORT bool Dart_IsFuture(Dart_Handle object);
+
+/*
+ * =========
+ * Instances
+ * =========
+ */
+
+/*
+ * For the purposes of the embedding api, not all objects returned are
+ * Dart language objects.  Within the api, we use the term 'Instance'
+ * to indicate handles which refer to true Dart language objects.
+ *
+ * TODO(turnidge): Reorganize the "Object" section above, pulling down
+ * any functions that more properly belong here. */
+
+/**
+ * Gets the type of a Dart language object.
+ *
+ * \param instance Some Dart object.
+ *
+ * \return If no error occurs, the type is returned. Otherwise an
+ *   error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
+
+/**
+ * Returns the name for the provided class type.
+ *
+ * \return A valid string handle if no error occurs during the
+ *   operation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type);
+
+/**
+ * Returns the name for the provided function or method.
+ *
+ * \return A valid string handle if no error occurs during the
+ *   operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
+
+/**
+ * Returns a handle to the owner of a function.
+ *
+ * The owner of an instance method or a static method is its defining
+ * class. The owner of a top-level function is its defining
+ * library. The owner of the function of a non-implicit closure is the
+ * function of the method or closure that defines the non-implicit
+ * closure.
+ *
+ * \return A valid handle to the owner of the function, or an error
+ *   handle if the argument is not a valid handle to a function.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
+
+/**
+ * Determines whether a function handle referes to a static function
+ * of method.
+ *
+ * For the purposes of the embedding API, a top-level function is
+ * implicitly declared static.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is declared static.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+                                              bool* is_static);
+
+/**
+ * Is this object a closure resulting from a tear-off (closurized method)?
+ *
+ * Returns true for closures produced when an ordinary method is accessed
+ * through a getter call. Returns false otherwise, in particular for closures
+ * produced from local function declarations.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is a tear-off.
+ */
+DART_EXPORT bool Dart_IsTearOff(Dart_Handle object);
+
+/**
+ * Retrieves the function of a closure.
+ *
+ * \return A handle to the function of the closure, or an error handle if the
+ *   argument is not a closure.
+ */
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
+
+/**
+ * Returns a handle to the library which contains class.
+ *
+ * \return A valid handle to the library with owns class, null if the class
+ *   has no library or an error handle if the argument is not a valid handle
+ *   to a class type.
+ */
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type);
+
+/*
+ * =============================
+ * Numbers, Integers and Doubles
+ * =============================
+ */
+
+/**
+ * Does this Integer fit into a 64-bit signed integer?
+ *
+ * \param integer An integer.
+ * \param fits Returns true if the integer fits into a 64-bit signed integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
+                                                  bool* fits);
+
+/**
+ * Does this Integer fit into a 64-bit unsigned integer?
+ *
+ * \param integer An integer.
+ * \param fits Returns true if the integer fits into a 64-bit unsigned integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer,
+                                                   bool* fits);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The value of the integer.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The unsigned value of the integer.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The value of the integer represented as a C string
+ *   containing a hexadecimal number.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value);
+
+/**
+ * Gets the value of an Integer.
+ *
+ * The integer must fit into a 64-bit signed integer, otherwise an error occurs.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer,
+                                            int64_t* value);
+
+/**
+ * Gets the value of an Integer.
+ *
+ * The integer must fit into a 64-bit unsigned integer, otherwise an
+ * error occurs.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
+                                             uint64_t* value);
+
+/**
+ * Gets the value of an integer as a hexadecimal C string.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer as a hexadecimal C
+ *   string. This C string is scope allocated and is only valid until
+ *   the next call to Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
+                                                 const char** value);
+
+/**
+ * Returns a Double with the provided value.
+ *
+ * \param value A double.
+ *
+ * \return The Double object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewDouble(double value);
+
+/**
+ * Gets the value of a Double
+ *
+ * \param double_obj A Double
+ * \param value Returns the value of the Double.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value);
+
+/**
+ * Returns a closure of static function 'function_name' in the class 'class_name'
+ * in the exported namespace of specified 'library'.
+ *
+ * \param library Library object
+ * \param cls_type Type object representing a Class
+ * \param function_name Name of the static function in the class
+ *
+ * \return A valid Dart instance if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+                                                    Dart_Handle cls_type,
+                                                    Dart_Handle function_name);
+
+/*
+ * ========
+ * Booleans
+ * ========
+ */
+
+/**
+ * Returns the True object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A handle to the True object.
+ */
+DART_EXPORT Dart_Handle Dart_True(void);
+
+/**
+ * Returns the False object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A handle to the False object.
+ */
+DART_EXPORT Dart_Handle Dart_False(void);
+
+/**
+ * Returns a Boolean with the provided value.
+ *
+ * \param value true or false.
+ *
+ * \return The Boolean object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewBoolean(bool value);
+
+/**
+ * Gets the value of a Boolean
+ *
+ * \param boolean_obj A Boolean
+ * \param value Returns the value of the Boolean.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value);
+
+/*
+ * =======
+ * Strings
+ * =======
+ */
+
+/**
+ * Gets the length of a String.
+ *
+ * \param str A String.
+ * \param length Returns the length of the String.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length);
+
+/**
+ * Returns a String built from the provided C string
+ * (There is an implicit assumption that the C string passed in contains
+ *  UTF-8 encoded characters and '\0' is considered as a termination
+ *  character).
+ *
+ * \param str A C String
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str);
+/* TODO(turnidge): Document what happens when we run out of memory
+ * during this call. */
+
+/**
+ * Returns a String built from an array of UTF-8 encoded characters.
+ *
+ * \param utf8_array An array of UTF-8 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array,
+                                               intptr_t length);
+
+/**
+ * Returns a String built from an array of UTF-16 encoded characters.
+ *
+ * \param utf16_array An array of UTF-16 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
+                                                intptr_t length);
+
+/**
+ * Returns a String built from an array of UTF-32 encoded characters.
+ *
+ * \param utf32_array An array of UTF-32 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
+                                                intptr_t length);
+
+/**
+ * Returns a String which references an external array of
+ * Latin-1 (ISO-8859-1) encoded characters.
+ *
+ * \param latin1_array Array of Latin-1 encoded characters. This must not move.
+ * \param length The length of the characters array.
+ * \param peer An external pointer to associate with this string.
+ * \param external_allocation_size The number of externally allocated
+ *   bytes for peer. Used to inform the garbage collector.
+ * \param callback A callback to be called when this string is finalized.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalLatin1String(const uint8_t* latin1_array,
+                             intptr_t length,
+                             void* peer,
+                             intptr_t external_allocation_size,
+                             Dart_HandleFinalizer callback);
+
+/**
+ * Returns a String which references an external array of UTF-16 encoded
+ * characters.
+ *
+ * \param utf16_array An array of UTF-16 encoded characters. This must not move.
+ * \param length The length of the characters array.
+ * \param peer An external pointer to associate with this string.
+ * \param external_allocation_size The number of externally allocated
+ *   bytes for peer. Used to inform the garbage collector.
+ * \param callback A callback to be called when this string is finalized.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalUTF16String(const uint16_t* utf16_array,
+                            intptr_t length,
+                            void* peer,
+                            intptr_t external_allocation_size,
+                            Dart_HandleFinalizer callback);
+
+/**
+ * Gets the C string representation of a String.
+ * (It is a sequence of UTF-8 encoded values with a '\0' termination.)
+ *
+ * \param str A string.
+ * \param cstr Returns the String represented as a C string.
+ *   This C string is scope allocated and is only valid until
+ *   the next call to Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str,
+                                             const char** cstr);
+
+/**
+ * Gets a UTF-8 encoded representation of a String.
+ *
+ * Any unpaired surrogate code points in the string will be converted as
+ * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need
+ * to preserve unpaired surrogates, use the Dart_StringToUTF16 function.
+ *
+ * \param str A string.
+ * \param utf8_array Returns the String represented as UTF-8 code
+ *   units.  This UTF-8 array is scope allocated and is only valid
+ *   until the next call to Dart_ExitScope.
+ * \param length Used to return the length of the array which was
+ *   actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str,
+                                          uint8_t** utf8_array,
+                                          intptr_t* length);
+
+/**
+ * Gets the data corresponding to the string object. This function returns
+ * the data only for Latin-1 (ISO-8859-1) string objects. For all other
+ * string objects it returns an error.
+ *
+ * \param str A string.
+ * \param latin1_array An array allocated by the caller, used to return
+ *   the string data.
+ * \param length Used to pass in the length of the provided array.
+ *   Used to return the length of the array which was actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str,
+                                            uint8_t* latin1_array,
+                                            intptr_t* length);
+
+/**
+ * Gets the UTF-16 encoded representation of a string.
+ *
+ * \param str A string.
+ * \param utf16_array An array allocated by the caller, used to return
+ *   the array of UTF-16 encoded characters.
+ * \param length Used to pass in the length of the provided array.
+ *   Used to return the length of the array which was actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str,
+                                           uint16_t* utf16_array,
+                                           intptr_t* length);
+
+/**
+ * Gets the storage size in bytes of a String.
+ *
+ * \param str A String.
+ * \param size Returns the storage size in bytes of the String.
+ *  This is the size in bytes needed to store the String.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size);
+
+/**
+ * Retrieves some properties associated with a String.
+ * Properties retrieved are:
+ * - character size of the string (one or two byte)
+ * - length of the string
+ * - peer pointer of string if it is an external string.
+ * \param str A String.
+ * \param char_size Returns the character size of the String.
+ * \param str_len Returns the length of the String.
+ * \param peer Returns the peer pointer associated with the String or 0 if
+ *   there is no peer pointer for it.
+ * \return Success if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str,
+                                                 intptr_t* char_size,
+                                                 intptr_t* str_len,
+                                                 void** peer);
+
+/*
+ * =====
+ * Lists
+ * =====
+ */
+
+/**
+ * Returns a List<dynamic> of the desired length.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewList(intptr_t length);
+
+typedef enum {
+  Dart_CoreType_Dynamic,
+  Dart_CoreType_Int,
+  Dart_CoreType_String,
+} Dart_CoreType_Id;
+
+// TODO(bkonyi): convert this to use nullable types once NNBD is enabled.
+/**
+ * Returns a List of the desired length with the desired legacy element type.
+ *
+ * \param element_type_id The type of elements of the list.
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns an error
+ * handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id,
+                                       intptr_t length);
+
+/**
+ * Returns a List of the desired length with the desired element type.
+ *
+ * \param element_type Handle to a nullable type object. E.g., from
+ * Dart_GetType or Dart_GetNullableType.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type,
+                                           intptr_t length);
+
+/**
+ * Returns a List of the desired length with the desired element type, filled
+ * with the provided object.
+ *
+ * \param element_type Handle to a type object. E.g., from Dart_GetType.
+ *
+ * \param fill_object Handle to an object of type 'element_type' that will be
+ * used to populate the list. This parameter can only be Dart_Null() if the
+ * length of the list is 0 or 'element_type' is a nullable type.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type,
+                                                 Dart_Handle fill_object,
+                                                 intptr_t length);
+
+/**
+ * Gets the length of a List.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param list A List.
+ * \param length Returns the length of the List.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length);
+
+/**
+ * Gets the Object at some index of a List.
+ *
+ * If the index is out of bounds, an error occurs.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param list A List.
+ * \param index A valid index into the List.
+ *
+ * \return The Object in the List at the specified index if no error
+ *   occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index);
+
+/**
+* Gets a range of Objects from a List.
+*
+* If any of the requested index values are out of bounds, an error occurs.
+*
+* May generate an unhandled exception error.
+*
+* \param list A List.
+* \param offset The offset of the first item to get.
+* \param length The number of items to get.
+* \param result A pointer to fill with the objects.
+*
+* \return Success if no error occurs during the operation.
+*/
+DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list,
+                                          intptr_t offset,
+                                          intptr_t length,
+                                          Dart_Handle* result);
+
+/**
+ * Sets the Object at some index of a List.
+ *
+ * If the index is out of bounds, an error occurs.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param list A List.
+ * \param index A valid index into the List.
+ * \param value The Object to put in the List.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list,
+                                       intptr_t index,
+                                       Dart_Handle value);
+
+/**
+ * May generate an unhandled exception error.
+ */
+DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
+                                            intptr_t offset,
+                                            uint8_t* native_array,
+                                            intptr_t length);
+
+/**
+ * May generate an unhandled exception error.
+ */
+DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list,
+                                            intptr_t offset,
+                                            const uint8_t* native_array,
+                                            intptr_t length);
+
+/*
+ * ====
+ * Maps
+ * ====
+ */
+
+/**
+ * Gets the Object at some key of a Map.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ * \param key An Object.
+ *
+ * \return The value in the map at the specified key, null if the map does not
+ *   contain the key, or an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key);
+
+/**
+ * Returns whether the Map contains a given key.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ *
+ * \return A handle on a boolean indicating whether map contains the key.
+ *   Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key);
+
+/**
+ * Gets the list of keys of a Map.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ *
+ * \return The list of key Objects if no error occurs. Otherwise returns an
+ *   error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map);
+
+/*
+ * ==========
+ * Typed Data
+ * ==========
+ */
+
+typedef enum {
+  Dart_TypedData_kByteData = 0,
+  Dart_TypedData_kInt8,
+  Dart_TypedData_kUint8,
+  Dart_TypedData_kUint8Clamped,
+  Dart_TypedData_kInt16,
+  Dart_TypedData_kUint16,
+  Dart_TypedData_kInt32,
+  Dart_TypedData_kUint32,
+  Dart_TypedData_kInt64,
+  Dart_TypedData_kUint64,
+  Dart_TypedData_kFloat32,
+  Dart_TypedData_kFloat64,
+  Dart_TypedData_kInt32x4,
+  Dart_TypedData_kFloat32x4,
+  Dart_TypedData_kFloat64x2,
+  Dart_TypedData_kInvalid
+} Dart_TypedData_Type;
+
+/**
+ * Return type if this object is a TypedData object.
+ *
+ * \return kInvalid if the object is not a TypedData object or the appropriate
+ *   Dart_TypedData_Type.
+ */
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object);
+
+/**
+ * Return type if this object is an external TypedData object.
+ *
+ * \return kInvalid if the object is not an external TypedData object or
+ *   the appropriate Dart_TypedData_Type.
+ */
+DART_EXPORT Dart_TypedData_Type
+Dart_GetTypeOfExternalTypedData(Dart_Handle object);
+
+/**
+ * Returns a TypedData object of the desired length and type.
+ *
+ * \param type The type of the TypedData object.
+ * \param length The length of the TypedData object (length in type units).
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
+                                          intptr_t length);
+
+/**
+ * Returns a TypedData object which references an external data array.
+ *
+ * \param type The type of the data array.
+ * \param data A data array. This array must not move.
+ * \param length The length of the data array (length in type units).
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
+                                                  void* data,
+                                                  intptr_t length);
+
+/**
+ * Returns a TypedData object which references an external data array.
+ *
+ * \param type The type of the data array.
+ * \param data A data array. This array must not move.
+ * \param length The length of the data array (length in type units).
+ * \param peer A pointer to a native object or NULL.  This value is
+ *   provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ *   bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ *   after the object is garbage collected, unless the handle has been deleted.
+ *   A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type,
+                                       void* data,
+                                       intptr_t length,
+                                       void* peer,
+                                       intptr_t external_allocation_size,
+                                       Dart_HandleFinalizer callback);
+
+/**
+ * Returns a ByteBuffer object for the typed data.
+ *
+ * \param typed_data The TypedData object.
+ *
+ * \return The ByteBuffer object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data);
+
+/**
+ * Acquires access to the internal data address of a TypedData object.
+ *
+ * \param object The typed data object whose internal data address is to
+ *    be accessed.
+ * \param type The type of the object is returned here.
+ * \param data The internal data address is returned here.
+ * \param len Size of the typed array is returned here.
+ *
+ * Notes:
+ *   When the internal address of the object is acquired any calls to a
+ *   Dart API function that could potentially allocate an object or run
+ *   any Dart code will return an error.
+ *
+ *   Any Dart API functions for accessing the data should not be called
+ *   before the corresponding release. In particular, the object should
+ *   not be acquired again before its release. This leads to undefined
+ *   behavior.
+ *
+ * \return Success if the internal data address is acquired successfully.
+ *   Otherwise, returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
+                                                  Dart_TypedData_Type* type,
+                                                  void** data,
+                                                  intptr_t* len);
+
+/**
+ * Releases access to the internal data address that was acquired earlier using
+ * Dart_TypedDataAcquireData.
+ *
+ * \param object The typed data object whose internal data address is to be
+ *   released.
+ *
+ * \return Success if the internal data address is released successfully.
+ *   Otherwise, returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object);
+
+/**
+ * Returns the TypedData object associated with the ByteBuffer object.
+ *
+ * \param byte_buffer The ByteBuffer object.
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer);
+
+/*
+ * ============================================================
+ * Invoking Constructors, Methods, Closures and Field accessors
+ * ============================================================
+ */
+
+/**
+ * Invokes a constructor, creating a new object.
+ *
+ * This function allows hidden constructors (constructors with leading
+ * underscores) to be called.
+ *
+ * \param type Type of object to be constructed.
+ * \param constructor_name The name of the constructor to invoke.  Use
+ *   Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
+ *   This name should not include the name of the class.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the constructor.
+ *
+ * \return If the constructor is called and completes successfully,
+ *   then the new object. If an error occurs during execution, then an
+ *   error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_New(Dart_Handle type,
+         Dart_Handle constructor_name,
+         int number_of_arguments,
+         Dart_Handle* arguments);
+
+/**
+ * Allocate a new object without invoking a constructor.
+ *
+ * \param type The type of an object to be allocated.
+ *
+ * \return The new object. If an error occurs during execution, then an
+ *   error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Allocate(Dart_Handle type);
+
+/**
+ * Allocate a new object without invoking a constructor, and sets specified
+ *  native fields.
+ *
+ * \param type The type of an object to be allocated.
+ * \param num_native_fields The number of native fields to set.
+ * \param native_fields An array containing the value of native fields.
+ *
+ * \return The new object. If an error occurs during execution, then an
+ *   error handle is returned.
+ */
+DART_EXPORT Dart_Handle
+Dart_AllocateWithNativeFields(Dart_Handle type,
+                              intptr_t num_native_fields,
+                              const intptr_t* native_fields);
+
+/**
+ * Invokes a method or function.
+ *
+ * The 'target' parameter may be an object, type, or library.  If
+ * 'target' is an object, then this function will invoke an instance
+ * method.  If 'target' is a type, then this function will invoke a
+ * static method.  If 'target' is a library, then this function will
+ * invoke a top-level function from that library.
+ * NOTE: This API call cannot be used to invoke methods of a type object.
+ *
+ * This function ignores visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param target An object, type, or library.
+ * \param name The name of the function or method to invoke.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the function.
+ *
+ * \return If the function or method is called and completes
+ *   successfully, then the return value is returned. If an error
+ *   occurs during execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_Invoke(Dart_Handle target,
+            Dart_Handle name,
+            int number_of_arguments,
+            Dart_Handle* arguments);
+/* TODO(turnidge): Document how to invoke operators. */
+
+/**
+ * Invokes a Closure with the given arguments.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return If no error occurs during execution, then the result of
+ *   invoking the closure is returned. If an error occurs during
+ *   execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_InvokeClosure(Dart_Handle closure,
+                   int number_of_arguments,
+                   Dart_Handle* arguments);
+
+/**
+ * Invokes a Generative Constructor on an object that was previously
+ * allocated using Dart_Allocate/Dart_AllocateWithNativeFields.
+ *
+ * The 'object' parameter must be an object.
+ *
+ * This function ignores visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param object An object.
+ * \param name The name of the constructor to invoke.
+ *   Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the function.
+ *
+ * \return If the constructor is called and completes
+ *   successfully, then the object is returned. If an error
+ *   occurs during execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_InvokeConstructor(Dart_Handle object,
+                       Dart_Handle name,
+                       int number_of_arguments,
+                       Dart_Handle* arguments);
+
+/**
+ * Gets the value of a field.
+ *
+ * The 'container' parameter may be an object, type, or library.  If
+ * 'container' is an object, then this function will access an
+ * instance field.  If 'container' is a type, then this function will
+ * access a static field.  If 'container' is a library, then this
+ * function will access a top-level variable.
+ * NOTE: This API call cannot be used to access fields of a type object.
+ *
+ * This function ignores field visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param container An object, type, or library.
+ * \param name A field name.
+ *
+ * \return If no error occurs, then the value of the field is
+ *   returned. Otherwise an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_GetField(Dart_Handle container, Dart_Handle name);
+
+/**
+ * Sets the value of a field.
+ *
+ * The 'container' parameter may actually be an object, type, or
+ * library.  If 'container' is an object, then this function will
+ * access an instance field.  If 'container' is a type, then this
+ * function will access a static field.  If 'container' is a library,
+ * then this function will access a top-level variable.
+ * NOTE: This API call cannot be used to access fields of a type object.
+ *
+ * This function ignores field visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param container An object, type, or library.
+ * \param name A field name.
+ * \param value The new field value.
+ *
+ * \return A valid handle if no error occurs.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value);
+
+/*
+ * ==========
+ * Exceptions
+ * ==========
+ */
+
+/*
+ * TODO(turnidge): Remove these functions from the api and replace all
+ * uses with Dart_NewUnhandledExceptionError. */
+
+/**
+ * Throws an exception.
+ *
+ * This function causes a Dart language exception to be thrown. This
+ * will proceed in the standard way, walking up Dart frames until an
+ * appropriate 'catch' block is found, executing 'finally' blocks,
+ * etc.
+ *
+ * If an error handle is passed into this function, the error is
+ * propagated immediately.  See Dart_PropagateError for a discussion
+ * of error propagation.
+ *
+ * If successful, this function does not return. Note that this means
+ * that the destructors of any stack-allocated C++ objects will not be
+ * called. If there are no Dart frames on the stack, an error occurs.
+ *
+ * \return An error handle if the exception was not thrown.
+ *   Otherwise the function does not return.
+ */
+DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception);
+
+/**
+ * Rethrows an exception.
+ *
+ * Rethrows an exception, unwinding all dart frames on the stack. If
+ * successful, this function does not return. Note that this means
+ * that the destructors of any stack-allocated C++ objects will not be
+ * called. If there are no Dart frames on the stack, an error occurs.
+ *
+ * \return An error handle if the exception was not thrown.
+ *   Otherwise the function does not return.
+ */
+DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception,
+                                              Dart_Handle stacktrace);
+
+/*
+ * ===========================
+ * Native fields and functions
+ * ===========================
+ */
+
+/**
+ * Gets the number of native instance fields in an object.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj,
+                                                         int* count);
+
+/**
+ * Gets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
+                                                    int index,
+                                                    intptr_t* value);
+
+/**
+ * Sets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
+                                                    int index,
+                                                    intptr_t value);
+
+/**
+ * The arguments to a native function.
+ *
+ * This object is passed to a native function to represent its
+ * arguments and return value. It allows access to the arguments to a
+ * native function by index. It also allows the return value of a
+ * native function to be set.
+ */
+typedef struct _Dart_NativeArguments* Dart_NativeArguments;
+
+/**
+ * Extracts current isolate group data from the native arguments structure.
+ */
+DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args);
+
+typedef enum {
+  Dart_NativeArgument_kBool = 0,
+  Dart_NativeArgument_kInt32,
+  Dart_NativeArgument_kUint32,
+  Dart_NativeArgument_kInt64,
+  Dart_NativeArgument_kUint64,
+  Dart_NativeArgument_kDouble,
+  Dart_NativeArgument_kString,
+  Dart_NativeArgument_kInstance,
+  Dart_NativeArgument_kNativeFields,
+} Dart_NativeArgument_Type;
+
+typedef struct _Dart_NativeArgument_Descriptor {
+  uint8_t type;
+  uint8_t index;
+} Dart_NativeArgument_Descriptor;
+
+typedef union _Dart_NativeArgument_Value {
+  bool as_bool;
+  int32_t as_int32;
+  uint32_t as_uint32;
+  int64_t as_int64;
+  uint64_t as_uint64;
+  double as_double;
+  struct {
+    Dart_Handle dart_str;
+    void* peer;
+  } as_string;
+  struct {
+    intptr_t num_fields;
+    intptr_t* values;
+  } as_native_fields;
+  Dart_Handle as_instance;
+} Dart_NativeArgument_Value;
+
+enum {
+  kNativeArgNumberPos = 0,
+  kNativeArgNumberSize = 8,
+  kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize,
+  kNativeArgTypeSize = 8,
+};
+
+#define BITMASK(size) ((1 << size) - 1)
+#define DART_NATIVE_ARG_DESCRIPTOR(type, position)                             \
+  (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) |               \
+   (position & BITMASK(kNativeArgNumberSize)))
+
+/**
+ * Gets the native arguments based on the types passed in and populates
+ * the passed arguments buffer with appropriate native values.
+ *
+ * \param args the Native arguments block passed into the native call.
+ * \param num_arguments length of argument descriptor array and argument
+ *   values array passed in.
+ * \param arg_descriptors an array that describes the arguments that
+ *   need to be retrieved. For each argument to be retrieved the descriptor
+ *   contains the argument number (0, 1 etc.) and the argument type
+ *   described using Dart_NativeArgument_Type, e.g:
+ *   DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates
+ *   that the first argument is to be retrieved and it should be a boolean.
+ * \param arg_values array into which the native arguments need to be
+ *   extracted into, the array is allocated by the caller (it could be
+ *   stack allocated to avoid the malloc/free performance overhead).
+ *
+ * \return Success if all the arguments could be extracted correctly,
+ *   returns an error handle if there were any errors while extracting the
+ *   arguments (mismatched number of arguments, incorrect types, etc.).
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeArguments(Dart_NativeArguments args,
+                        int num_arguments,
+                        const Dart_NativeArgument_Descriptor* arg_descriptors,
+                        Dart_NativeArgument_Value* arg_values);
+
+/**
+ * Gets the native argument at some index.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
+                                               int index);
+/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */
+
+/**
+ * Gets the number of native arguments.
+ */
+DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args);
+
+/**
+ * Gets all the native fields of the native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param num_fields size of the intptr_t array 'field_values' passed in.
+ * \param field_values intptr_t array in which native field values are returned.
+ * \return Success if the native fields where copied in successfully. Otherwise
+ *   returns an error handle. On success the native field values are copied
+ *   into the 'field_values' array, if the argument at 'arg_index' is a
+ *   null object then 0 is copied as the native field values into the
+ *   'field_values' array.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args,
+                               int arg_index,
+                               int num_fields,
+                               intptr_t* field_values);
+
+/**
+ * Gets the native field of the receiver.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args,
+                                               intptr_t* value);
+
+/**
+ * Gets a string native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param peer Returns the peer pointer if the string argument has one.
+ * \return Success if the string argument has a peer, if it does not
+ *   have a peer then the String object is returned. Otherwise returns
+ *   an error handle (argument is not a String object).
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
+                                                     int arg_index,
+                                                     void** peer);
+
+/**
+ * Gets an integer native argument at some index.
+ * \param args Native arguments structure.
+ * \param index Index of the desired argument in the structure above.
+ * \param value Returns the integer value if the argument is an Integer.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
+                                                      int index,
+                                                      int64_t* value);
+
+/**
+ * Gets a boolean native argument at some index.
+ * \param args Native arguments structure.
+ * \param index Index of the desired argument in the structure above.
+ * \param value Returns the boolean value if the argument is a Boolean.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
+                                                      int index,
+                                                      bool* value);
+
+/**
+ * Gets a double native argument at some index.
+ * \param args Native arguments structure.
+ * \param index Index of the desired argument in the structure above.
+ * \param value Returns the double value if the argument is a double.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
+                                                     int index,
+                                                     double* value);
+
+/**
+ * Sets the return value for a native function.
+ *
+ * If retval is an Error handle, then error will be propagated once
+ * the native functions exits. See Dart_PropagateError for a
+ * discussion of how different types of errors are propagated.
+ */
+DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
+                                     Dart_Handle retval);
+
+DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args,
+                                               Dart_WeakPersistentHandle rval);
+
+DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
+                                            bool retval);
+
+DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
+                                            int64_t retval);
+
+DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
+                                           double retval);
+
+/**
+ * A native function.
+ */
+typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments);
+
+/**
+ * Native entry resolution callback.
+ *
+ * For libraries and scripts which have native functions, the embedder
+ * can provide a native entry resolver. This callback is used to map a
+ * name/arity to a Dart_NativeFunction. If no function is found, the
+ * callback should return NULL.
+ *
+ * The parameters to the native resolver function are:
+ * \param name a Dart string which is the name of the native function.
+ * \param num_of_arguments is the number of arguments expected by the
+ *   native function.
+ * \param auto_setup_scope is a boolean flag that can be set by the resolver
+ *   to indicate if this function needs a Dart API scope (see Dart_EnterScope/
+ *   Dart_ExitScope) to be setup automatically by the VM before calling into
+ *   the native function. By default most native functions would require this
+ *   to be true but some light weight native functions which do not call back
+ *   into the VM through the Dart API may not require a Dart scope to be
+ *   setup automatically.
+ *
+ * \return A valid Dart_NativeFunction which resolves to a native entry point
+ *   for the native function.
+ *
+ * See Dart_SetNativeResolver.
+ */
+typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name,
+                                                        int num_of_arguments,
+                                                        bool* auto_setup_scope);
+/* TODO(turnidge): Consider renaming to NativeFunctionResolver or
+ * NativeResolver. */
+
+/**
+ * Native entry symbol lookup callback.
+ *
+ * For libraries and scripts which have native functions, the embedder
+ * can provide a callback for mapping a native entry to a symbol. This callback
+ * maps a native function entry PC to the native function name. If no native
+ * entry symbol can be found, the callback should return NULL.
+ *
+ * The parameters to the native reverse resolver function are:
+ * \param nf A Dart_NativeFunction.
+ *
+ * \return A const UTF-8 string containing the symbol name or NULL.
+ *
+ * See Dart_SetNativeResolver.
+ */
+typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf);
+
+/**
+ * FFI Native C function pointer resolver callback.
+ *
+ * See Dart_SetFfiNativeResolver.
+ */
+typedef void* (*Dart_FfiNativeResolver)(const char* name, uintptr_t args_n);
+
+/*
+ * ===========
+ * Environment
+ * ===========
+ */
+
+/**
+ * An environment lookup callback function.
+ *
+ * \param name The name of the value to lookup in the environment.
+ *
+ * \return A valid handle to a string if the name exists in the
+ * current environment or Dart_Null() if not.
+ */
+typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name);
+
+/**
+ * Sets the environment callback for the current isolate. This
+ * callback is used to lookup environment values by name in the
+ * current environment. This enables the embedder to supply values for
+ * the const constructors bool.fromEnvironment, int.fromEnvironment
+ * and String.fromEnvironment.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback);
+
+/**
+ * Sets the callback used to resolve native functions for a library.
+ *
+ * \param library A library.
+ * \param resolver A native entry resolver.
+ *
+ * \return A valid handle if the native resolver was set successfully.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetNativeResolver(Dart_Handle library,
+                       Dart_NativeEntryResolver resolver,
+                       Dart_NativeEntrySymbol symbol);
+/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */
+
+/**
+ * Returns the callback used to resolve native functions for a library.
+ *
+ * \param library A library.
+ * \param resolver a pointer to a Dart_NativeEntryResolver
+ *
+ * \return A valid handle if the library was found.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver);
+
+/**
+ * Returns the callback used to resolve native function symbols for a library.
+ *
+ * \param library A library.
+ * \param resolver a pointer to a Dart_NativeEntrySymbol.
+ *
+ * \return A valid handle if the library was found.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library,
+                                             Dart_NativeEntrySymbol* resolver);
+
+/**
+ * Sets the callback used to resolve FFI native functions for a library.
+ * The resolved functions are expected to be a C function pointer of the
+ * correct signature (as specified in the `@FfiNative<NFT>()` function
+ * annotation in Dart code).
+ *
+ * NOTE: This is an experimental feature and might change in the future.
+ *
+ * \param library A library.
+ * \param resolver A native function resolver.
+ *
+ * \return A valid handle if the native resolver was set successfully.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetFfiNativeResolver(Dart_Handle library, Dart_FfiNativeResolver resolver);
+
+/*
+ * =====================
+ * Scripts and Libraries
+ * =====================
+ */
+
+typedef enum {
+  Dart_kCanonicalizeUrl = 0,
+  Dart_kImportTag,
+  Dart_kKernelTag,
+} Dart_LibraryTag;
+
+/**
+ * The library tag handler is a multi-purpose callback provided by the
+ * embedder to the Dart VM. The embedder implements the tag handler to
+ * provide the ability to load Dart scripts and imports.
+ *
+ * -- TAGS --
+ *
+ * Dart_kCanonicalizeUrl
+ *
+ * This tag indicates that the embedder should canonicalize 'url' with
+ * respect to 'library'.  For most embedders, the
+ * Dart_DefaultCanonicalizeUrl function is a sufficient implementation
+ * of this tag.  The return value should be a string holding the
+ * canonicalized url.
+ *
+ * Dart_kImportTag
+ *
+ * This tag is used to load a library from IsolateMirror.loadUri. The embedder
+ * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The
+ * return value should be an error or library (the result from
+ * Dart_LoadLibraryFromKernel).
+ *
+ * Dart_kKernelTag
+ *
+ * This tag is used to load the intermediate file (kernel) generated by
+ * the Dart front end. This tag is typically used when a 'hot-reload'
+ * of an application is needed and the VM is 'use dart front end' mode.
+ * The dart front end typically compiles all the scripts, imports and part
+ * files into one intermediate file hence we don't use the source/import or
+ * script tags. The return value should be an error or a TypedData containing
+ * the kernel bytes.
+ *
+ */
+typedef Dart_Handle (*Dart_LibraryTagHandler)(
+    Dart_LibraryTag tag,
+    Dart_Handle library_or_package_map_url,
+    Dart_Handle url);
+
+/**
+ * Sets library tag handler for the current isolate. This handler is
+ * used to handle the various tags encountered while loading libraries
+ * or scripts in the isolate.
+ *
+ * \param handler Handler code to be used for handling the various tags
+ *   encountered while loading libraries or scripts in the isolate.
+ *
+ * \return If no error occurs, the handler is set for the isolate.
+ *   Otherwise an error handle is returned.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler);
+
+/**
+ * Handles deferred loading requests. When this handler is invoked, it should
+ * eventually load the deferred loading unit with the given id and call
+ * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is
+ * recommended that the loading occur asynchronously, but it is permitted to
+ * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the
+ * handler returns.
+ *
+ * If an error is returned, it will be propogated through
+ * `prefix.loadLibrary()`. This is useful for synchronous
+ * implementations, which must propogate any unwind errors from
+ * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler
+ * should return a non-error such as `Dart_Null()`.
+ */
+typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id);
+
+/**
+ * Sets the deferred load handler for the current isolate. This handler is
+ * used to handle loading deferred imports in an AppJIT or AppAOT program.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler);
+
+/**
+ * Notifies the VM that a deferred load completed successfully. This function
+ * will eventually cause the corresponding `prefix.loadLibrary()` futures to
+ * complete.
+ *
+ * Requires the current isolate to be the same current isolate during the
+ * invocation of the Dart_DeferredLoadHandler.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_DeferredLoadComplete(intptr_t loading_unit_id,
+                          const uint8_t* snapshot_data,
+                          const uint8_t* snapshot_instructions);
+
+/**
+ * Notifies the VM that a deferred load failed. This function
+ * will eventually cause the corresponding `prefix.loadLibrary()` futures to
+ * complete with an error.
+ *
+ * If `transient` is true, future invocations of `prefix.loadLibrary()` will
+ * trigger new load requests. If false, futures invocation will complete with
+ * the same error.
+ *
+ * Requires the current isolate to be the same current isolate during the
+ * invocation of the Dart_DeferredLoadHandler.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_DeferredLoadCompleteError(intptr_t loading_unit_id,
+                               const char* error_message,
+                               bool transient);
+
+/**
+ * Canonicalizes a url with respect to some library.
+ *
+ * The url is resolved with respect to the library's url and some url
+ * normalizations are performed.
+ *
+ * This canonicalization function should be sufficient for most
+ * embedders to implement the Dart_kCanonicalizeUrl tag.
+ *
+ * \param base_url The base url relative to which the url is
+ *                being resolved.
+ * \param url The url being resolved and canonicalized.  This
+ *            parameter is a string handle.
+ *
+ * \return If no error occurs, a String object is returned.  Otherwise
+ *   an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url,
+                                                    Dart_Handle url);
+
+/**
+ * Loads the root library for the current isolate.
+ *
+ * Requires there to be no current root library.
+ *
+ * \param kernel_buffer A buffer which contains a kernel binary (see
+ *     pkg/kernel/binary.md). Must remain valid until isolate group shutdown.
+ * \param kernel_size Length of the passed in buffer.
+ *
+ * \return A handle to the root library, or an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size);
+
+/**
+ * Gets the library for the root script for the current isolate.
+ *
+ * If the root script has not yet been set for the current isolate,
+ * this function returns Dart_Null().  This function never returns an
+ * error handle.
+ *
+ * \return Returns the root Library for the current isolate or Dart_Null().
+ */
+DART_EXPORT Dart_Handle Dart_RootLibrary(void);
+
+/**
+ * Sets the root library for the current isolate.
+ *
+ * \return Returns an error handle if `library` is not a library handle.
+ */
+DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library);
+
+/**
+ * Lookup or instantiate a legacy type by name and type arguments from a
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ *   For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ *   For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library,
+                                     Dart_Handle class_name,
+                                     intptr_t number_of_type_arguments,
+                                     Dart_Handle* type_arguments);
+
+/**
+ * Lookup or instantiate a nullable type by name and type arguments from
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ *   For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ *   For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library,
+                                             Dart_Handle class_name,
+                                             intptr_t number_of_type_arguments,
+                                             Dart_Handle* type_arguments);
+
+/**
+ * Lookup or instantiate a non-nullable type by name and type arguments from
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ *   For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ *   For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNonNullableType(Dart_Handle library,
+                        Dart_Handle class_name,
+                        intptr_t number_of_type_arguments,
+                        Dart_Handle* type_arguments);
+
+/**
+ * Creates a nullable version of the provided type.
+ *
+ * \param type The type to be converted to a nullable type.
+ *
+ * \return If no error occurs, a nullable type is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type);
+
+/**
+ * Creates a non-nullable version of the provided type.
+ *
+ * \param type The type to be converted to a non-nullable type.
+ *
+ * \return If no error occurs, a non-nullable type is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type);
+
+/**
+ * A type's nullability.
+ *
+ * \param type A Dart type.
+ * \param result An out parameter containing the result of the check. True if
+ * the type is of the specified nullability, false otherwise.
+ *
+ * \return Returns an error handle if type is not of type Type.
+ */
+DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result);
+DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result);
+DART_EXPORT Dart_Handle Dart_IsLegacyType(Dart_Handle type, bool* result);
+
+/**
+ * Lookup a class or interface by name from a Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The name of the class or interface.
+ *
+ * \return If no error occurs, the class or interface is
+ *   returned. Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library,
+                                      Dart_Handle class_name);
+/* TODO(asiva): The above method needs to be removed once all uses
+ * of it are removed from the embedder code. */
+
+/**
+ * Returns an import path to a Library, such as "file:///test.dart" or
+ * "dart:core".
+ */
+DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library);
+
+/**
+ * Returns a URL from which a Library was loaded.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library);
+
+/**
+ * \return An array of libraries.
+ */
+DART_EXPORT Dart_Handle Dart_GetLoadedLibraries(void);
+
+DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url);
+/* TODO(turnidge): Consider returning Dart_Null() when the library is
+ * not found to distinguish that from a true error case. */
+
+/**
+ * Report an loading error for the library.
+ *
+ * \param library The library that failed to load.
+ * \param error The Dart error instance containing the load error.
+ *
+ * \return If the VM handles the error, the return value is
+ * a null handle. If it doesn't handle the error, the error
+ * object is returned.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library,
+                                                Dart_Handle error);
+
+/**
+ * Called by the embedder to load a partial program. Does not set the root
+ * library.
+ *
+ * \param kernel_buffer A buffer which contains a kernel binary (see
+ *     pkg/kernel/binary.md). Must remain valid until isolate shutdown.
+ * \param kernel_buffer_size Length of the passed in buffer.
+ *
+ * \return A handle to the main library of the compilation unit, or an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer,
+                           intptr_t kernel_buffer_size);
+
+/**
+ * Indicates that all outstanding load requests have been satisfied.
+ * This finalizes all the new classes loaded and optionally completes
+ * deferred library futures.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param complete_futures Specify true if all deferred library
+ *  futures should be completed, false otherwise.
+ *
+ * \return Success if all classes have been finalized and deferred library
+ *   futures are completed. Otherwise, returns an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_FinalizeLoading(bool complete_futures);
+
+/*
+ * =====
+ * Peers
+ * =====
+ */
+
+/**
+ * The peer field is a lazily allocated field intended for storage of
+ * an uncommonly used values.  Most instances types can have a peer
+ * field allocated.  The exceptions are subtypes of Null, num, and
+ * bool.
+ */
+
+/**
+ * Returns the value of peer field of 'object' in 'peer'.
+ *
+ * \param object An object.
+ * \param peer An out parameter that returns the value of the peer
+ *   field.
+ *
+ * \return Returns an error if 'object' is a subtype of Null, num, or
+ *   bool.
+ */
+DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer);
+
+/**
+ * Sets the value of the peer field of 'object' to the value of
+ * 'peer'.
+ *
+ * \param object An object.
+ * \param peer A value to store in the peer field.
+ *
+ * \return Returns an error if 'object' is a subtype of Null, num, or
+ *   bool.
+ */
+DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer);
+
+/*
+ * ======
+ * Kernel
+ * ======
+ */
+
+/**
+ * Experimental support for Dart to Kernel parser isolate.
+ *
+ * TODO(hausner): Document finalized interface.
+ *
+ */
+
+// TODO(33433): Remove kernel service from the embedding API.
+
+typedef enum {
+  Dart_KernelCompilationStatus_Unknown = -1,
+  Dart_KernelCompilationStatus_Ok = 0,
+  Dart_KernelCompilationStatus_Error = 1,
+  Dart_KernelCompilationStatus_Crash = 2,
+  Dart_KernelCompilationStatus_MsgFailed = 3,
+} Dart_KernelCompilationStatus;
+
+typedef struct {
+  Dart_KernelCompilationStatus status;
+  bool null_safety;
+  char* error;
+  uint8_t* kernel;
+  intptr_t kernel_size;
+} Dart_KernelCompilationResult;
+
+typedef enum {
+  Dart_KernelCompilationVerbosityLevel_Error = 0,
+  Dart_KernelCompilationVerbosityLevel_Warning,
+  Dart_KernelCompilationVerbosityLevel_Info,
+  Dart_KernelCompilationVerbosityLevel_All,
+} Dart_KernelCompilationVerbosityLevel;
+
+DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
+DART_EXPORT bool Dart_KernelIsolateIsRunning(void);
+DART_EXPORT Dart_Port Dart_KernelPort(void);
+
+/**
+ * Compiles the given `script_uri` to a kernel file.
+ *
+ * \param platform_kernel A buffer containing the kernel of the platform (e.g.
+ * `vm_platform_strong.dill`). The VM does not take ownership of this memory.
+ *
+ * \param platform_kernel_size The length of the platform_kernel buffer.
+ *
+ * \param snapshot_compile Set to `true` when the compilation is for a snapshot.
+ * This is used by the frontend to determine if compilation related information
+ * should be printed to console (e.g., null safety mode).
+ *
+ * \param verbosity Specifies the logging behavior of the kernel compilation
+ * service.
+ *
+ * \return Returns the result of the compilation.
+ *
+ * On a successful compilation the returned [Dart_KernelCompilationResult] has
+ * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size`
+ * fields are set. The caller takes ownership of the malloc()ed buffer.
+ *
+ * On a failed compilation the `error` might be set describing the reason for
+ * the failed compilation. The caller takes ownership of the malloc()ed
+ * error.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri,
+                     const uint8_t* platform_kernel,
+                     const intptr_t platform_kernel_size,
+                     bool incremental_compile,
+                     bool snapshot_compile,
+                     const char* package_config,
+                     Dart_KernelCompilationVerbosityLevel verbosity);
+
+/**
+ * Compiles the given `script_uri` to a kernel file.
+ *
+ * \param platform_kernel A buffer containing the kernel of the platform (e.g.
+ * `vm_platform_strong.dill`). The VM does not take ownership of this memory.
+ *
+ * \param platform_kernel_size The length of the platform_kernel buffer.
+ *
+ * \param snapshot_compile Set to `true` when the compilation is for a snapshot.
+ * This is used by the frontend to determine if compilation related information
+ * should be printed to console (e.g., null safety mode).
+ *
+ * \param null_safety Provides null-safety mode setting for the compiler.
+ *
+ * \param verbosity Specifies the logging behavior of the kernel compilation
+ * service.
+ *
+ * \return Returns the result of the compilation.
+ *
+ * On a successful compilation the returned [Dart_KernelCompilationResult] has
+ * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size`
+ * fields are set. The caller takes ownership of the malloc()ed buffer.
+ *
+ * On a failed compilation the `error` might be set describing the reason for
+ * the failed compilation. The caller takes ownership of the malloc()ed
+ * error.
+ */
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernelWithGivenNullsafety(
+    const char* script_uri,
+    const uint8_t* platform_kernel,
+    const intptr_t platform_kernel_size,
+    bool snapshot_compile,
+    const char* package_config,
+    const bool null_safety,
+    Dart_KernelCompilationVerbosityLevel verbosity);
+
+typedef struct {
+  const char* uri;
+  const char* source;
+} Dart_SourceFile;
+
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(void);
+
+/**
+ * Sets the kernel buffer which will be used to load Dart SDK sources
+ * dynamically at runtime.
+ *
+ * \param platform_kernel A buffer containing kernel which has sources for the
+ * Dart SDK populated. Note: The VM does not take ownership of this memory.
+ *
+ * \param platform_kernel_size The length of the platform_kernel buffer.
+ */
+DART_EXPORT void Dart_SetDartLibrarySourcesKernel(
+    const uint8_t* platform_kernel,
+    const intptr_t platform_kernel_size);
+
+/**
+ * Detect the null safety opt-in status.
+ *
+ * When running from source, it is based on the opt-in status of `script_uri`.
+ * When running from a kernel buffer, it is based on the mode used when
+ *   generating `kernel_buffer`.
+ * When running from an appJIT or AOT snapshot, it is based on the mode used
+ *   when generating `snapshot_data`.
+ *
+ * \param script_uri Uri of the script that contains the source code
+ *
+ * \param package_config Uri of the package configuration file (either in format
+ *   of .packages or .dart_tool/package_config.json) for the null safety
+ *   detection to resolve package imports against. If this parameter is not
+ *   passed the package resolution of the parent isolate should be used.
+ *
+ * \param original_working_directory current working directory when the VM
+ *   process was launched, this is used to correctly resolve the path specified
+ *   for package_config.
+ *
+ * \param snapshot_data Buffer containing the snapshot data of the
+ *   isolate or NULL if no snapshot is provided. If provided, the buffers must
+ *   remain valid until the isolate shuts down.
+ *
+ * \param snapshot_instructions Buffer containing the snapshot instructions of
+ *   the isolate or NULL if no snapshot is provided. If provided, the buffers
+ *   must remain valid until the isolate shuts down.
+ *
+ * \param kernel_buffer A buffer which contains a kernel/DIL program. Must
+ *   remain valid until isolate shutdown.
+ *
+ * \param kernel_buffer_size The size of `kernel_buffer`.
+ *
+ * \return Returns true if the null safety is opted in by the input being
+ *   run `script_uri`, `snapshot_data` or `kernel_buffer`.
+ *
+ */
+DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri,
+                                       const char* package_config,
+                                       const char* original_working_directory,
+                                       const uint8_t* snapshot_data,
+                                       const uint8_t* snapshot_instructions,
+                                       const uint8_t* kernel_buffer,
+                                       intptr_t kernel_buffer_size);
+
+#define DART_KERNEL_ISOLATE_NAME "kernel-service"
+
+/*
+ * =======
+ * Service
+ * =======
+ */
+
+#define DART_VM_SERVICE_ISOLATE_NAME "vm-service"
+
+/**
+ * Returns true if isolate is the service isolate.
+ *
+ * \param isolate An isolate
+ *
+ * \return Returns true if 'isolate' is the service isolate.
+ */
+DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate);
+
+/**
+ * Writes the CPU profile to the timeline as a series of 'instant' events.
+ *
+ * Note that this is an expensive operation.
+ *
+ * \param main_port The main port of the Isolate whose profile samples to write.
+ * \param error An optional error, must be free()ed by caller.
+ *
+ * \return Returns true if the profile is successfully written and false
+ *         otherwise.
+ */
+DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error);
+
+/*
+ * ==============
+ * Precompilation
+ * ==============
+ */
+
+/**
+ * Compiles all functions reachable from entry points and marks
+ * the isolate to disallow future compilation.
+ *
+ * Entry points should be specified using `@pragma("vm:entry-point")`
+ * annotation.
+ *
+ * \return An error handle if a compilation error or runtime error running const
+ * constructors was encountered.
+ */
+DART_EXPORT Dart_Handle Dart_Precompile(void);
+
+typedef void (*Dart_CreateLoadingUnitCallback)(
+    void* callback_data,
+    intptr_t loading_unit_id,
+    void** write_callback_data,
+    void** write_debug_callback_data);
+typedef void (*Dart_StreamingWriteCallback)(void* callback_data,
+                                            const uint8_t* buffer,
+                                            intptr_t size);
+typedef void (*Dart_StreamingCloseCallback)(void* callback_data);
+
+DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id);
+
+// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name.
+// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual
+// symbol names in the objects are given by the '...AsmSymbol' definitions.
+#if defined(__APPLE__)
+#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId"
+#define kVmSnapshotDataCSymbol "kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions"
+#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss"
+#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss"
+#else
+#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId"
+#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions"
+#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss"
+#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss"
+#endif
+
+#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId"
+#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions"
+#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss"
+#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsAsmSymbol                                  \
+  "_kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss"
+
+/**
+ *  Creates a precompiled snapshot.
+ *   - A root library must have been loaded.
+ *   - Dart_Precompile must have been called.
+ *
+ *  Outputs an assembly file defining the symbols listed in the definitions
+ *  above.
+ *
+ *  The assembly should be compiled as a static or shared library and linked or
+ *  loaded by the embedder. Running this snapshot requires a VM compiled with
+ *  DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and
+ *  kDartVmSnapshotInstructions should be passed to Dart_Initialize. The
+ *  kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be
+ *  passed to Dart_CreateIsolateGroup.
+ *
+ *  The callback will be invoked one or more times to provide the assembly code.
+ *
+ *  If stripped is true, then the assembly code will not include DWARF
+ *  debugging sections.
+ *
+ *  If debug_callback_data is provided, debug_callback_data will be used with
+ *  the callback to provide separate debugging information.
+ *
+ *  \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
+                                    void* callback_data,
+                                    bool stripped,
+                                    void* debug_callback_data);
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsAssemblies(
+    Dart_CreateLoadingUnitCallback next_callback,
+    void* next_callback_data,
+    bool stripped,
+    Dart_StreamingWriteCallback write_callback,
+    Dart_StreamingCloseCallback close_callback);
+
+/**
+ *  Creates a precompiled snapshot.
+ *   - A root library must have been loaded.
+ *   - Dart_Precompile must have been called.
+ *
+ *  Outputs an ELF shared library defining the symbols
+ *   - _kDartVmSnapshotData
+ *   - _kDartVmSnapshotInstructions
+ *   - _kDartIsolateSnapshotData
+ *   - _kDartIsolateSnapshotInstructions
+ *
+ *  The shared library should be dynamically loaded by the embedder.
+ *  Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT.
+ *  The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to
+ *  Dart_Initialize. The kDartIsolateSnapshotData and
+ *  kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate.
+ *
+ *  The callback will be invoked one or more times to provide the binary output.
+ *
+ *  If stripped is true, then the binary output will not include DWARF
+ *  debugging sections.
+ *
+ *  If debug_callback_data is provided, debug_callback_data will be used with
+ *  the callback to provide separate debugging information.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
+                               void* callback_data,
+                               bool stripped,
+                               void* debug_callback_data);
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback,
+                                void* next_callback_data,
+                                bool stripped,
+                                Dart_StreamingWriteCallback write_callback,
+                                Dart_StreamingCloseCallback close_callback);
+
+/**
+ *  Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes
+ *  kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does
+ *  not strip DWARF information from the generated assembly or allow for
+ *  separate debug information.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
+                                   void* callback_data);
+
+/**
+ * Sorts the class-ids in depth first traversal order of the inheritance
+ * tree. This is a costly operation, but it can make method dispatch
+ * more efficient and is done before writing snapshots.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(void);
+
+/**
+ *  Creates a snapshot that caches compiled code and type feedback for faster
+ *  startup and quicker warmup in a subsequent process.
+ *
+ *  Outputs a snapshot in two pieces. The pieces should be passed to
+ *  Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the
+ *  current VM. The instructions piece must be loaded with read and execute
+ *  permissions; the data piece may be loaded as read-only.
+ *
+ *   - Requires the VM to have not been started with --precompilation.
+ *   - Not supported when targeting IA32.
+ *   - The VM writing the snapshot and the VM reading the snapshot must be the
+ *     same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must
+ *     be targeting the same architecture, and must both be in checked mode or
+ *     both in unchecked mode.
+ *
+ *  The buffers are scope allocated and are only valid until the next call to
+ *  Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer,
+                                 intptr_t* isolate_snapshot_data_size,
+                                 uint8_t** isolate_snapshot_instructions_buffer,
+                                 intptr_t* isolate_snapshot_instructions_size);
+
+/**
+ * Like Dart_CreateAppJITSnapshotAsBlobs, but also creates a new VM snapshot.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateCoreJITSnapshotAsBlobs(
+    uint8_t** vm_snapshot_data_buffer,
+    intptr_t* vm_snapshot_data_size,
+    uint8_t** vm_snapshot_instructions_buffer,
+    intptr_t* vm_snapshot_instructions_size,
+    uint8_t** isolate_snapshot_data_buffer,
+    intptr_t* isolate_snapshot_data_size,
+    uint8_t** isolate_snapshot_instructions_buffer,
+    intptr_t* isolate_snapshot_instructions_size);
+
+/**
+ * Get obfuscation map for precompiled code.
+ *
+ * Obfuscation map is encoded as a JSON array of pairs (original name,
+ * obfuscated name).
+ *
+ * \return Returns an error handler if the VM was built in a mode that does not
+ * support obfuscation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length);
+
+/**
+ *  Returns whether the VM only supports running from precompiled snapshots and
+ *  not from any other kind of snapshot or from source (that is, the VM was
+ *  compiled with DART_PRECOMPILED_RUNTIME).
+ */
+DART_EXPORT bool Dart_IsPrecompiledRuntime(void);
+
+/**
+ *  Print a native stack trace. Used for crash handling.
+ *
+ *  If context is NULL, prints the current stack trace. Otherwise, context
+ *  should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler
+ *  running on the current thread.
+ */
+DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
+
+/**
+ *  Indicate that the process is about to abort, and the Dart VM should not
+ *  attempt to cleanup resources.
+ */
+DART_EXPORT void Dart_PrepareToAbort(void);
+
+#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */

+ 59 - 0
core/fclash-go-bridge/dart_api_dl/dart_api_dl.c

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#include "dart_api_dl.h"               /* NOLINT */
+#include "dart_version.h"              /* NOLINT */
+#include "internal/dart_api_dl_impl.h" /* NOLINT */
+
+#include <string.h>
+
+#define DART_API_DL_DEFINITIONS(name, R, A) name##_Type name##_DL = NULL;
+
+DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS)
+
+#undef DART_API_DL_DEFINITIONS
+
+typedef void* DartApiEntry_function;
+
+DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries,
+                                          const char* name) {
+  while (entries->name != NULL) {
+    if (strcmp(entries->name, name) == 0) return entries->function;
+    entries++;
+  }
+  return NULL;
+}
+
+intptr_t Dart_InitializeApiDL(void* data) {
+  DartApi* dart_api_data = (DartApi*)data;
+
+  if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) {
+    // If the DartVM we're running on does not have the same version as this
+    // file was compiled against, refuse to initialize. The symbols are not
+    // compatible.
+    return -1;
+  }
+  // Minor versions are allowed to be different.
+  // If the DartVM has a higher minor version, it will provide more symbols
+  // than we initialize here.
+  // If the DartVM has a lower minor version, it will not provide all symbols.
+  // In that case, we leave the missing symbols un-initialized. Those symbols
+  // should not be used by the Dart and native code. The client is responsible
+  // for checking the minor version number himself based on which symbols it
+  // is using.
+  // (If we would error out on this case, recompiling native code against a
+  // newer SDK would break all uses on older SDKs, which is too strict.)
+
+  const DartApiEntry* dart_api_function_pointers = dart_api_data->functions;
+
+#define DART_API_DL_INIT(name, R, A)                                           \
+  name##_DL =                                                                  \
+      (name##_Type)(FindFunctionPointer(dart_api_function_pointers, #name));
+  DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT)
+#undef DART_API_DL_INIT
+
+  return 0;
+}

+ 150 - 0
core/fclash-go-bridge/dart_api_dl/dart_api_dl.h

@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_API_DL_H_
+#define RUNTIME_INCLUDE_DART_API_DL_H_
+
+#include "dart_api.h"        /* NOLINT */
+#include "dart_native_api.h" /* NOLINT */
+
+/** \mainpage Dynamically Linked Dart API
+ *
+ * This exposes a subset of symbols from dart_api.h and dart_native_api.h
+ * available in every Dart embedder through dynamic linking.
+ *
+ * All symbols are postfixed with _DL to indicate that they are dynamically
+ * linked and to prevent conflicts with the original symbol.
+ *
+ * Link `dart_api_dl.c` file into your library and invoke
+ * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`.
+ */
+
+DART_EXPORT intptr_t Dart_InitializeApiDL(void* data);
+
+// ============================================================================
+// IMPORTANT! Never update these signatures without properly updating
+// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
+//
+// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbol names and types
+// to trigger compile-time errors if the sybols in those files are updated
+// without updating these.
+//
+// Function return and argument types, and typedefs are carbon copied. Structs
+// are typechecked nominally in C/C++, so they are not copied, instead a
+// comment is added to their definition.
+typedef int64_t Dart_Port_DL;
+
+typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
+                                             Dart_CObject* message);
+
+// dart_native_api.h symbols can be called on any thread.
+#define DART_NATIVE_API_DL_SYMBOLS(F)                                          \
+  /***** dart_native_api.h *****/                                              \
+  /* Dart_Port */                                                              \
+  F(Dart_PostCObject, bool, (Dart_Port_DL port_id, Dart_CObject * message))    \
+  F(Dart_PostInteger, bool, (Dart_Port_DL port_id, int64_t message))           \
+  F(Dart_NewNativePort, Dart_Port_DL,                                          \
+    (const char* name, Dart_NativeMessageHandler_DL handler,                   \
+     bool handle_concurrently))                                                \
+  F(Dart_CloseNativePort, bool, (Dart_Port_DL native_port_id))
+
+// dart_api.h symbols can only be called on Dart threads.
+#define DART_API_DL_SYMBOLS(F)                                                 \
+  /***** dart_api.h *****/                                                     \
+  /* Errors */                                                                 \
+  F(Dart_IsError, bool, (Dart_Handle handle))                                  \
+  F(Dart_IsApiError, bool, (Dart_Handle handle))                               \
+  F(Dart_IsUnhandledExceptionError, bool, (Dart_Handle handle))                \
+  F(Dart_IsCompilationError, bool, (Dart_Handle handle))                       \
+  F(Dart_IsFatalError, bool, (Dart_Handle handle))                             \
+  F(Dart_GetError, const char*, (Dart_Handle handle))                          \
+  F(Dart_ErrorHasException, bool, (Dart_Handle handle))                        \
+  F(Dart_ErrorGetException, Dart_Handle, (Dart_Handle handle))                 \
+  F(Dart_ErrorGetStackTrace, Dart_Handle, (Dart_Handle handle))                \
+  F(Dart_NewApiError, Dart_Handle, (const char* error))                        \
+  F(Dart_NewCompilationError, Dart_Handle, (const char* error))                \
+  F(Dart_NewUnhandledExceptionError, Dart_Handle, (Dart_Handle exception))     \
+  F(Dart_PropagateError, void, (Dart_Handle handle))                           \
+  /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */          \
+  F(Dart_HandleFromPersistent, Dart_Handle, (Dart_PersistentHandle object))    \
+  F(Dart_HandleFromWeakPersistent, Dart_Handle,                                \
+    (Dart_WeakPersistentHandle object))                                        \
+  F(Dart_NewPersistentHandle, Dart_PersistentHandle, (Dart_Handle object))     \
+  F(Dart_SetPersistentHandle, void,                                            \
+    (Dart_PersistentHandle obj1, Dart_Handle obj2))                            \
+  F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object))         \
+  F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle,                   \
+    (Dart_Handle object, void* peer, intptr_t external_allocation_size,        \
+     Dart_HandleFinalizer callback))                                           \
+  F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \
+  F(Dart_UpdateExternalSize, void,                                             \
+    (Dart_WeakPersistentHandle object, intptr_t external_allocation_size))     \
+  F(Dart_NewFinalizableHandle, Dart_FinalizableHandle,                         \
+    (Dart_Handle object, void* peer, intptr_t external_allocation_size,        \
+     Dart_HandleFinalizer callback))                                           \
+  F(Dart_DeleteFinalizableHandle, void,                                        \
+    (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object))         \
+  F(Dart_UpdateFinalizableExternalSize, void,                                  \
+    (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object,          \
+     intptr_t external_allocation_size))                                       \
+  /* Dart_Port */                                                              \
+  F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object))               \
+  F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id))                     \
+  F(Dart_SendPortGetId, Dart_Handle,                                           \
+    (Dart_Handle port, Dart_Port_DL * port_id))                                \
+  /* Scopes */                                                                 \
+  F(Dart_EnterScope, void, (void))                                             \
+  F(Dart_ExitScope, void, (void))
+
+#define DART_API_ALL_DL_SYMBOLS(F)                                             \
+  DART_NATIVE_API_DL_SYMBOLS(F)                                                \
+  DART_API_DL_SYMBOLS(F)
+// IMPORTANT! Never update these signatures without properly updating
+// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
+//
+// End of verbatim copy.
+// ============================================================================
+
+// Copy of definition of DART_EXPORT without 'used' attribute.
+//
+// The 'used' attribute cannot be used with DART_API_ALL_DL_SYMBOLS because
+// they are not function declarations, but variable declarations with a
+// function pointer type.
+//
+// The function pointer variables are initialized with the addresses of the
+// functions in the VM. If we were to use function declarations instead, we
+// would need to forward the call to the VM adding indirection.
+#if defined(__CYGWIN__)
+#error Tool chain and platform not supported.
+#elif defined(_WIN32)
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT_DL DART_EXTERN_C __declspec(dllexport)
+#else
+#define DART_EXPORT_DL DART_EXTERN_C
+#endif
+#else
+#if __GNUC__ >= 4
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT_DL DART_EXTERN_C __attribute__((visibility("default")))
+#else
+#define DART_EXPORT_DL DART_EXTERN_C
+#endif
+#else
+#error Tool chain not supported.
+#endif
+#endif
+
+#define DART_API_DL_DECLARATIONS(name, R, A)                                   \
+  typedef R(*name##_Type) A;                                                   \
+  DART_EXPORT_DL name##_Type name##_DL;
+
+DART_API_ALL_DL_SYMBOLS(DART_API_DL_DECLARATIONS)
+
+#undef DART_API_DL_DECLARATIONS
+
+#undef DART_EXPORT_DL
+
+#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */

+ 204 - 0
core/fclash-go-bridge/dart_api_dl/dart_native_api.h

@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_
+#define RUNTIME_INCLUDE_DART_NATIVE_API_H_
+
+#include "dart_api.h" /* NOLINT */
+
+/*
+ * ==========================================
+ * Message sending/receiving from native code
+ * ==========================================
+ */
+
+/**
+ * A Dart_CObject is used for representing Dart objects as native C
+ * data outside the Dart heap. These objects are totally detached from
+ * the Dart heap. Only a subset of the Dart objects have a
+ * representation as a Dart_CObject.
+ *
+ * The string encoding in the 'value.as_string' is UTF-8.
+ *
+ * All the different types from dart:typed_data are exposed as type
+ * kTypedData. The specific type from dart:typed_data is in the type
+ * field of the as_typed_data structure. The length in the
+ * as_typed_data structure is always in bytes.
+ *
+ * The data for kTypedData is copied on message send and ownership remains with
+ * the caller. The ownership of data for kExternalTyped is passed to the VM on
+ * message send and returned when the VM invokes the
+ * Dart_HandleFinalizer callback; a non-NULL callback must be provided.
+ *
+ * Note that Dart_CObject_kNativePointer is intended for internal use by
+ * dart:io implementation and has no connection to dart:ffi Pointer class.
+ * It represents a pointer to a native resource of a known type.
+ * The receiving side will only see this pointer as an integer and will not
+ * see the specified finalizer.
+ * The specified finalizer will only be invoked if the message is not delivered.
+ */
+typedef enum {
+  Dart_CObject_kNull = 0,
+  Dart_CObject_kBool,
+  Dart_CObject_kInt32,
+  Dart_CObject_kInt64,
+  Dart_CObject_kDouble,
+  Dart_CObject_kString,
+  Dart_CObject_kArray,
+  Dart_CObject_kTypedData,
+  Dart_CObject_kExternalTypedData,
+  Dart_CObject_kSendPort,
+  Dart_CObject_kCapability,
+  Dart_CObject_kNativePointer,
+  Dart_CObject_kUnsupported,
+  Dart_CObject_kNumberOfTypes
+} Dart_CObject_Type;
+
+typedef struct _Dart_CObject {
+  Dart_CObject_Type type;
+  union {
+    bool as_bool;
+    int32_t as_int32;
+    int64_t as_int64;
+    double as_double;
+    char* as_string;
+    struct {
+      Dart_Port id;
+      Dart_Port origin_id;
+    } as_send_port;
+    struct {
+      int64_t id;
+    } as_capability;
+    struct {
+      intptr_t length;
+      struct _Dart_CObject** values;
+    } as_array;
+    struct {
+      Dart_TypedData_Type type;
+      intptr_t length; /* in elements, not bytes */
+      uint8_t* values;
+    } as_typed_data;
+    struct {
+      Dart_TypedData_Type type;
+      intptr_t length; /* in elements, not bytes */
+      uint8_t* data;
+      void* peer;
+      Dart_HandleFinalizer callback;
+    } as_external_typed_data;
+    struct {
+      intptr_t ptr;
+      intptr_t size;
+      Dart_HandleFinalizer callback;
+    } as_native_pointer;
+  } value;
+} Dart_CObject;
+// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when
+// changing this struct.
+
+/**
+ * Posts a message on some port. The message will contain the Dart_CObject
+ * object graph rooted in 'message'.
+ *
+ * While the message is being sent the state of the graph of Dart_CObject
+ * structures rooted in 'message' should not be accessed, as the message
+ * generation will make temporary modifications to the data. When the message
+ * has been sent the graph will be fully restored.
+ *
+ * If true is returned, the message was enqueued, and finalizers for external
+ * typed data will eventually run, even if the receiving isolate shuts down
+ * before processing the message. If false is returned, the message was not
+ * enqueued and ownership of external typed data in the message remains with the
+ * caller.
+ *
+ * This function may be called on any thread when the VM is running (that is,
+ * after Dart_Initialize has returned and before Dart_Cleanup has been called).
+ *
+ * \param port_id The destination port.
+ * \param message The message to send.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message);
+
+/**
+ * Posts a message on some port. The message will contain the integer 'message'.
+ *
+ * \param port_id The destination port.
+ * \param message The message to send.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message);
+
+/**
+ * A native message handler.
+ *
+ * This handler is associated with a native port by calling
+ * Dart_NewNativePort.
+ *
+ * The message received is decoded into the message structure. The
+ * lifetime of the message data is controlled by the caller. All the
+ * data references from the message are allocated by the caller and
+ * will be reclaimed when returning to it.
+ */
+typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id,
+                                          Dart_CObject* message);
+
+/**
+ * Creates a new native port.  When messages are received on this
+ * native port, then they will be dispatched to the provided native
+ * message handler.
+ *
+ * \param name The name of this port in debugging messages.
+ * \param handler The C handler to run when messages arrive on the port.
+ * \param handle_concurrently Is it okay to process requests on this
+ *                            native port concurrently?
+ *
+ * \return If successful, returns the port id for the native port.  In
+ *   case of error, returns ILLEGAL_PORT.
+ */
+DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
+                                         Dart_NativeMessageHandler handler,
+                                         bool handle_concurrently);
+/* TODO(turnidge): Currently handle_concurrently is ignored. */
+
+/**
+ * Closes the native port with the given id.
+ *
+ * The port must have been allocated by a call to Dart_NewNativePort.
+ *
+ * \param native_port_id The id of the native port to close.
+ *
+ * \return Returns true if the port was closed successfully.
+ */
+DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
+
+/*
+ * ==================
+ * Verification Tools
+ * ==================
+ */
+
+/**
+ * Forces all loaded classes and functions to be compiled eagerly in
+ * the current isolate..
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(void);
+
+/**
+ * Finalizes all classes.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeAllClasses(void);
+
+/*  This function is intentionally undocumented.
+ *
+ *  It should not be used outside internal tests.
+ */
+DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg);
+
+#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */

+ 538 - 0
core/fclash-go-bridge/dart_api_dl/dart_tools_api.h

@@ -0,0 +1,538 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_INCLUDE_DART_TOOLS_API_H_
+#define RUNTIME_INCLUDE_DART_TOOLS_API_H_
+
+#include "dart_api.h" /* NOLINT */
+
+/** \mainpage Dart Tools Embedding API Reference
+ *
+ * This reference describes the Dart embedding API for tools. Tools include
+ * a debugger, service protocol, and timeline.
+ *
+ * NOTE: The APIs described in this file are unstable and subject to change.
+ *
+ * This reference is generated from the header include/dart_tools_api.h.
+ */
+
+/*
+ * ========
+ * Debugger
+ * ========
+ */
+
+/**
+ * ILLEGAL_ISOLATE_ID is a number guaranteed never to be associated with a
+ * valid isolate.
+ */
+#define ILLEGAL_ISOLATE_ID ILLEGAL_PORT
+
+
+/*
+ * =======
+ * Service
+ * =======
+ */
+
+/**
+ * A service request callback function.
+ *
+ * These callbacks, registered by the embedder, are called when the VM receives
+ * a service request it can't handle and the service request command name
+ * matches one of the embedder registered handlers.
+ *
+ * The return value of the callback indicates whether the response
+ * should be used as a regular result or an error result.
+ * Specifically, if the callback returns true, a regular JSON-RPC
+ * response is built in the following way:
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "result": <json_object>,
+ *   "id": <some sequence id>,
+ * }
+ *
+ * If the callback returns false, a JSON-RPC error is built like this:
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "error": <json_object>,
+ *   "id": <some sequence id>,
+ * }
+ *
+ * \param method The rpc method name.
+ * \param param_keys Service requests can have key-value pair parameters. The
+ *   keys and values are flattened and stored in arrays.
+ * \param param_values The values associated with the keys.
+ * \param num_params The length of the param_keys and param_values arrays.
+ * \param user_data The user_data pointer registered with this handler.
+ * \param result A C string containing a valid JSON object. The returned
+ *   pointer will be freed by the VM by calling free.
+ *
+ * \return True if the result is a regular JSON-RPC response, false if the
+ *   result is a JSON-RPC error.
+ */
+typedef bool (*Dart_ServiceRequestCallback)(const char* method,
+                                            const char** param_keys,
+                                            const char** param_values,
+                                            intptr_t num_params,
+                                            void* user_data,
+                                            const char** json_object);
+
+/**
+ * Register a Dart_ServiceRequestCallback to be called to handle
+ * requests for the named rpc on a specific isolate. The callback will
+ * be invoked with the current isolate set to the request target.
+ *
+ * \param method The name of the method that this callback is responsible for.
+ * \param callback The callback to invoke.
+ * \param user_data The user data passed to the callback.
+ *
+ * NOTE: If multiple callbacks with the same name are registered, only
+ * the last callback registered will be remembered.
+ */
+DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback(
+    const char* method,
+    Dart_ServiceRequestCallback callback,
+    void* user_data);
+
+/**
+ * Register a Dart_ServiceRequestCallback to be called to handle
+ * requests for the named rpc. The callback will be invoked without a
+ * current isolate.
+ *
+ * \param method The name of the command that this callback is responsible for.
+ * \param callback The callback to invoke.
+ * \param user_data The user data passed to the callback.
+ *
+ * NOTE: If multiple callbacks with the same name are registered, only
+ * the last callback registered will be remembered.
+ */
+DART_EXPORT void Dart_RegisterRootServiceRequestCallback(
+    const char* method,
+    Dart_ServiceRequestCallback callback,
+    void* user_data);
+
+/**
+ * Embedder information which can be requested by the VM for internal or
+ * reporting purposes.
+ *
+ * The pointers in this structure are not going to be cached or freed by the VM.
+ */
+
+ #define DART_EMBEDDER_INFORMATION_CURRENT_VERSION (0x00000001)
+
+typedef struct {
+  int32_t version;
+  const char* name;  // [optional] The name of the embedder
+  int64_t current_rss;  // [optional] the current RSS of the embedder
+  int64_t max_rss;  // [optional] the maximum RSS of the embedder
+} Dart_EmbedderInformation;
+
+/**
+ * Callback provided by the embedder that is used by the vm to request
+ * information.
+ *
+ * \return Returns a pointer to a Dart_EmbedderInformation structure.
+ * The embedder keeps the ownership of the structure and any field in it.
+ * The embedder must ensure that the structure will remain valid until the
+ * next invokation of the callback.
+ */
+typedef void (*Dart_EmbedderInformationCallback)(
+    Dart_EmbedderInformation* info);
+
+/**
+ * Register a Dart_ServiceRequestCallback to be called to handle
+ * requests for the named rpc. The callback will be invoked without a
+ * current isolate.
+ *
+ * \param method The name of the command that this callback is responsible for.
+ * \param callback The callback to invoke.
+ * \param user_data The user data passed to the callback.
+ *
+ * NOTE: If multiple callbacks with the same name are registered, only
+ * the last callback registered will be remembered.
+ */
+DART_EXPORT void Dart_SetEmbedderInformationCallback(
+    Dart_EmbedderInformationCallback callback);
+
+/**
+ * Invoke a vm-service method and wait for its result.
+ *
+ * \param request_json The utf8-encoded json-rpc request.
+ * \param request_json_length The length of the json-rpc request.
+ *
+ * \param response_json The returned utf8-encoded json response, must be
+ *   free()ed by caller.
+ * \param response_json_length The length of the returned json response.
+ * \param error An optional error, must be free()ed by caller.
+ *
+ * \return Whether the call was sucessfully performed.
+ *
+ * NOTE: This method does not need a current isolate and must not have the
+ * vm-isolate being the current isolate. It must be called after
+ * Dart_Initialize() and before Dart_Cleanup().
+ */
+DART_EXPORT bool Dart_InvokeVMServiceMethod(uint8_t* request_json,
+                                            intptr_t request_json_length,
+                                            uint8_t** response_json,
+                                            intptr_t* response_json_length,
+                                            char** error);
+
+/*
+ * ========
+ * Event Streams
+ * ========
+ */
+
+/**
+ * A callback invoked when the VM service gets a request to listen to
+ * some stream.
+ *
+ * \return Returns true iff the embedder supports the named stream id.
+ */
+typedef bool (*Dart_ServiceStreamListenCallback)(const char* stream_id);
+
+/**
+ * A callback invoked when the VM service gets a request to cancel
+ * some stream.
+ */
+typedef void (*Dart_ServiceStreamCancelCallback)(const char* stream_id);
+
+/**
+ * Adds VM service stream callbacks.
+ *
+ * \param listen_callback A function pointer to a listen callback function.
+ *   A listen callback function should not be already set when this function
+ *   is called. A NULL value removes the existing listen callback function
+ *   if any.
+ *
+ * \param cancel_callback A function pointer to a cancel callback function.
+ *   A cancel callback function should not be already set when this function
+ *   is called. A NULL value removes the existing cancel callback function
+ *   if any.
+ *
+ * \return Success if the callbacks were added.  Otherwise, returns an
+ *   error handle.
+ */
+DART_EXPORT char* Dart_SetServiceStreamCallbacks(
+    Dart_ServiceStreamListenCallback listen_callback,
+    Dart_ServiceStreamCancelCallback cancel_callback);
+
+/**
+ * Sends a data event to clients of the VM Service.
+ *
+ * A data event is used to pass an array of bytes to subscribed VM
+ * Service clients.  For example, in the standalone embedder, this is
+ * function used to provide WriteEvents on the Stdout and Stderr
+ * streams.
+ *
+ * If the embedder passes in a stream id for which no client is
+ * subscribed, then the event is ignored.
+ *
+ * \param stream_id The id of the stream on which to post the event.
+ *
+ * \param event_kind A string identifying what kind of event this is.
+ *   For example, 'WriteEvent'.
+ *
+ * \param bytes A pointer to an array of bytes.
+ *
+ * \param bytes_length The length of the byte array.
+ *
+ * \return NULL if the arguments are well formed.  Otherwise, returns an
+ *   error string. The caller is responsible for freeing the error message.
+ */
+DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id,
+                                            const char* event_kind,
+                                            const uint8_t* bytes,
+                                            intptr_t bytes_length);
+
+/**
+ * Usage statistics for a space/generation at a particular moment in time.
+ *
+ * \param used Amount of memory used, in bytes.
+ *
+ * \param capacity Memory capacity, in bytes.
+ *
+ * \param external External memory, in bytes.
+ *
+ * \param collections How many times the garbage collector has run in this
+ *   space.
+ *
+ * \param time Cumulative time spent collecting garbage in this space, in
+ *   seconds.
+ *
+ * \param avg_collection_period Average time between garbage collector running
+ *   in this space, in milliseconds.
+ */
+typedef struct {
+  intptr_t used;
+  intptr_t capacity;
+  intptr_t external;
+  intptr_t collections;
+  double time;
+  double avg_collection_period;
+} Dart_GCStats;
+
+/**
+ * A Garbage Collection event with memory usage statistics.
+ *
+ * \param type The event type. Static lifetime.
+ *
+ * \param reason The reason for the GC event. Static lifetime.
+ *
+ * \param new_space Data for New Space.
+ *
+ * \param old_space Data for Old Space.
+ */
+typedef struct {
+  const char* type;
+  const char* reason;
+  const char* isolate_id;
+
+  Dart_GCStats new_space;
+  Dart_GCStats old_space;
+} Dart_GCEvent;
+
+/**
+ * A callback invoked when the VM emits a GC event.
+ *
+ * \param event The GC event data. Pointer only valid for the duration of the
+ *   callback.
+ */
+typedef void (*Dart_GCEventCallback)(Dart_GCEvent* event);
+
+/**
+ * Sets the native GC event callback.
+ *
+ * \param callback A function pointer to an event handler callback function.
+ *   A NULL value removes the existing listen callback function if any.
+ */
+DART_EXPORT void Dart_SetGCEventCallback(Dart_GCEventCallback callback);
+
+/*
+ * ========
+ * Reload support
+ * ========
+ *
+ * These functions are used to implement reloading in the Dart VM.
+ * This is an experimental feature, so embedders should be prepared
+ * for these functions to change.
+ */
+
+/**
+ * A callback which determines whether the file at some url has been
+ * modified since some time.  If the file cannot be found, true should
+ * be returned.
+ */
+typedef bool (*Dart_FileModifiedCallback)(const char* url, int64_t since);
+
+DART_EXPORT char* Dart_SetFileModifiedCallback(
+    Dart_FileModifiedCallback file_modified_callback);
+
+/**
+ * Returns true if isolate is currently reloading.
+ */
+DART_EXPORT bool Dart_IsReloading();
+
+/*
+ * ========
+ * Timeline
+ * ========
+ */
+
+/**
+ * Enable tracking of specified timeline category. This is operational
+ * only when systrace timeline functionality is turned on.
+ *
+ * \param categories A comma seperated list of categories that need to
+ *   be enabled, the categories are
+ *   "all" : All categories
+ *   "API" - Execution of Dart C API functions
+ *   "Compiler" - Execution of Dart JIT compiler
+ *   "CompilerVerbose" - More detailed Execution of Dart JIT compiler
+ *   "Dart" - Execution of Dart code
+ *   "Debugger" - Execution of Dart debugger
+ *   "Embedder" - Execution of Dart embedder code
+ *   "GC" - Execution of Dart Garbage Collector
+ *   "Isolate" - Dart Isolate lifecycle execution
+ *   "VM" - Excution in Dart VM runtime code
+ *   "" - None
+ *
+ *  When "all" is specified all the categories are enabled.
+ *  When a comma seperated list of categories is specified, the categories
+ *   that are specified will be enabled and the rest will be disabled. 
+ *  When "" is specified all the categories are disabled.
+ *  The category names are case sensitive.
+ *  eg:  Dart_EnableTimelineCategory("all");
+ *       Dart_EnableTimelineCategory("GC,API,Isolate");
+ *       Dart_EnableTimelineCategory("GC,Debugger,Dart");
+ *
+ * \return True if the categories were successfully enabled, False otherwise.
+ */
+DART_EXPORT bool Dart_SetEnabledTimelineCategory(const char* categories);
+
+/**
+ * Returns a timestamp in microseconds. This timestamp is suitable for
+ * passing into the timeline system, and uses the same monotonic clock
+ * as dart:developer's Timeline.now.
+ *
+ * \return A timestamp that can be passed to the timeline system.
+ */
+DART_EXPORT int64_t Dart_TimelineGetMicros();
+
+/**
+ * Returns a raw timestamp in from the monotonic clock.
+ *
+ * \return A raw timestamp from the monotonic clock.
+ */
+DART_EXPORT int64_t Dart_TimelineGetTicks();
+
+/**
+ * Returns the frequency of the monotonic clock.
+ *
+ * \return The frequency of the monotonic clock.
+ */
+DART_EXPORT int64_t Dart_TimelineGetTicksFrequency();
+
+typedef enum {
+  Dart_Timeline_Event_Begin,          // Phase = 'B'.
+  Dart_Timeline_Event_End,            // Phase = 'E'.
+  Dart_Timeline_Event_Instant,        // Phase = 'i'.
+  Dart_Timeline_Event_Duration,       // Phase = 'X'.
+  Dart_Timeline_Event_Async_Begin,    // Phase = 'b'.
+  Dart_Timeline_Event_Async_End,      // Phase = 'e'.
+  Dart_Timeline_Event_Async_Instant,  // Phase = 'n'.
+  Dart_Timeline_Event_Counter,        // Phase = 'C'.
+  Dart_Timeline_Event_Flow_Begin,     // Phase = 's'.
+  Dart_Timeline_Event_Flow_Step,      // Phase = 't'.
+  Dart_Timeline_Event_Flow_End,       // Phase = 'f'.
+} Dart_Timeline_Event_Type;
+
+/**
+ * Add a timeline event to the embedder stream.
+ *
+ * \param label The name of the event. Its lifetime must extend at least until
+ *     Dart_Cleanup.
+ * \param timestamp0 The first timestamp of the event.
+ * \param timestamp1_or_async_id The second timestamp of the event or
+ *     the async id.
+ * \param argument_count The number of argument names and values.
+ * \param argument_names An array of names of the arguments. The lifetime of the
+ *     names must extend at least until Dart_Cleanup. The array may be reclaimed
+ *     when this call returns.
+ * \param argument_values An array of values of the arguments. The values and
+ *     the array may be reclaimed when this call returns.
+ */
+DART_EXPORT void Dart_TimelineEvent(const char* label,
+                                    int64_t timestamp0,
+                                    int64_t timestamp1_or_async_id,
+                                    Dart_Timeline_Event_Type type,
+                                    intptr_t argument_count,
+                                    const char** argument_names,
+                                    const char** argument_values);
+
+/**
+ * Associates a name with the current thread. This name will be used to name
+ * threads in the timeline. Can only be called after a call to Dart_Initialize.
+ *
+ * \param name The name of the thread.
+ */
+DART_EXPORT void Dart_SetThreadName(const char* name);
+
+/*
+ * =======
+ * Metrics
+ * =======
+ */
+
+/**
+ * Return metrics gathered for the VM and individual isolates.
+ *
+ * NOTE: Non-heap metrics are not available in PRODUCT builds of Dart.
+ * Calling the non-heap metric functions on a PRODUCT build might return invalid metrics.
+ */
+DART_EXPORT int64_t Dart_VMIsolateCountMetric();  // Counter
+DART_EXPORT int64_t Dart_VMCurrentRSSMetric();    // Byte
+DART_EXPORT int64_t Dart_VMPeakRSSMetric();       // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldCapacityMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldCapacityMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldExternalMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewCapacityMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewCapacityMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewExternalMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapGlobalUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapGlobalUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateRunnableLatencyMetric(Dart_Isolate isolate);  // Microsecond
+DART_EXPORT int64_t
+Dart_IsolateRunnableHeapSizeMetric(Dart_Isolate isolate);  // Byte
+
+/*
+ * ========
+ * UserTags
+ * ========
+ */
+
+/*
+ * Gets the current isolate's currently set UserTag instance.
+ *
+ * \return The currently set UserTag instance.
+ */
+DART_EXPORT Dart_Handle Dart_GetCurrentUserTag();
+
+/*
+ * Gets the current isolate's default UserTag instance.
+ *
+ * \return The default UserTag with label 'Default'
+ */
+DART_EXPORT Dart_Handle Dart_GetDefaultUserTag();
+
+/*
+ * Creates a new UserTag instance.
+ *
+ * \param label The name of the new UserTag.
+ *
+ * \return The newly created UserTag instance or an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label);
+
+/*
+ * Updates the current isolate's UserTag to a new value.
+ *
+ * \param user_tag The UserTag to be set as the current UserTag.
+ *
+ * \return The previously set UserTag instance or an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag);
+
+/*
+ * Returns the label of a given UserTag instance.
+ *
+ * \param user_tag The UserTag from which the label will be retrieved.
+ *
+ * \return The UserTag's label. NULL if the user_tag is invalid. The caller is
+ *   responsible for freeing the returned label.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel(
+    Dart_Handle user_tag);
+
+#endif  // RUNTIME_INCLUDE_DART_TOOLS_API_H_

+ 16 - 0
core/fclash-go-bridge/dart_api_dl/dart_version.h

@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_VERSION_H_
+#define RUNTIME_INCLUDE_DART_VERSION_H_
+
+// On breaking changes the major version is increased.
+// On backwards compatible changes the minor version is increased.
+// The versioning covers the symbols exposed in dart_api_dl.h
+#define DART_API_DL_MAJOR_VERSION 2
+#define DART_API_DL_MINOR_VERSION 0
+
+#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */

+ 21 - 0
core/fclash-go-bridge/dart_api_dl/internal/dart_api_dl_impl.h

@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
+#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
+
+typedef struct {
+  const char* name;
+  void (*function)(void);
+} DartApiEntry;
+
+typedef struct {
+  const int major;
+  const int minor;
+  const DartApiEntry* const functions;
+} DartApi;
+
+#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */

+ 3 - 0
core/fclash-go-bridge/go.mod

@@ -0,0 +1,3 @@
+module github.com/kingtous/fclash-go-bridge
+
+go 1.19

+ 41 - 0
core/fclash-go-bridge/lib.go

@@ -0,0 +1,41 @@
+package fclashgobridge
+
+/*
+#include "stdint.h"
+#include "stdlib.h"
+#include "dart_api_dl/dart_api_dl.h"
+#include "dart_api_dl/dart_api_dl.c"
+#include "dart_api_dl/dart_native_api.h"
+// Go does not allow calling C function pointers directly.
+// we mock a function to call Dart_PostCObject_DL
+bool GoDart_PostCObject(Dart_Port_DL port, Dart_CObject* obj) {
+  return Dart_PostCObject_DL(port, obj);
+}
+*/
+import "C"
+import (
+	"fmt"
+	"unsafe"
+)
+
+func InitDartApi(api unsafe.Pointer) {
+	if C.Dart_InitializeApiDL(api) != 0 {
+		panic("failed to create fclash dart bridge")
+	} else {
+		fmt.Println("Dart Api DL is initialized")
+	}
+}
+
+func SendToPort(port int64, msg string) {
+	var obj C.Dart_CObject
+	obj._type = C.Dart_CObject_kString
+	msg_obj := C.CString(msg) // go string -> char*s
+	// union type, we do a force convertion
+	ptr := unsafe.Pointer(&obj.value[0])
+	*(**C.char)(ptr) = msg_obj
+	defer C.free(unsafe.Pointer(msg_obj))
+	ret := C.GoDart_PostCObject(C.Dart_Port_DL(port), &obj)
+	if !ret {
+		fmt.Println("ERROR: post to port ", port, " failed", msg)
+	}
+}

BIN
core/flutter-clash-binding


+ 105 - 0
core/flutter-clash-binding.h

@@ -0,0 +1,105 @@
+/* Code generated by cmd/cgo; DO NOT EDIT. */
+
+/* package github.com/kingtous/flutter-clash-binding */
+
+
+#line 1 "cgo-builtin-export-prolog"
+
+#include <stddef.h>
+
+#ifndef GO_CGO_EXPORT_PROLOGUE_H
+#define GO_CGO_EXPORT_PROLOGUE_H
+
+#ifndef GO_CGO_GOSTRING_TYPEDEF
+typedef struct { const char *p; ptrdiff_t n; } _GoString_;
+#endif
+
+#endif
+
+/* Start of preamble from import "C" comments.  */
+
+
+#line 3 "lib.go"
+
+#include "stdint.h"
+
+#line 1 "cgo-generated-wrapper"
+
+
+/* End of preamble from import "C" comments.  */
+
+
+/* Start of boilerplate cgo prologue.  */
+#line 1 "cgo-gcc-export-header-prolog"
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
+typedef signed char GoInt8;
+typedef unsigned char GoUint8;
+typedef short GoInt16;
+typedef unsigned short GoUint16;
+typedef int GoInt32;
+typedef unsigned int GoUint32;
+typedef long long GoInt64;
+typedef unsigned long long GoUint64;
+typedef GoInt64 GoInt;
+typedef GoUint64 GoUint;
+typedef size_t GoUintptr;
+typedef float GoFloat32;
+typedef double GoFloat64;
+#ifdef _MSC_VER
+#include <complex.h>
+typedef _Fcomplex GoComplex64;
+typedef _Dcomplex GoComplex128;
+#else
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
+#endif
+
+/*
+  static assertion to make sure the file is being used on architecture
+  at least with matching size of GoInt.
+*/
+typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
+
+#ifndef GO_CGO_GOSTRING_TYPEDEF
+typedef _GoString_ GoString;
+#endif
+typedef void *GoMap;
+typedef void *GoChan;
+typedef struct { void *t; void *v; } GoInterface;
+typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern GoInt clash_init(char* home_dir);
+extern GoInt set_config(char* config_path);
+extern GoInt set_home_dir(char* home);
+extern char* get_config();
+extern GoInt set_ext_controller(GoUint64 port);
+extern void clear_ext_options();
+extern GoInt is_config_valid(char* config_path);
+extern char* get_all_connections();
+extern void close_all_connections();
+extern GoUint8 close_connection(char* id);
+extern GoUint8 parse_options();
+extern char* get_traffic();
+extern void init_native_api_bridge(void* api);
+extern void start_log(long long port);
+extern void stop_log();
+extern long change_proxy(char* selector_name, char* proxy_name);
+extern long change_config_field(char* s);
+extern void async_test_delay(char* proxy_name, char* url, long timeout, long long port);
+extern char* get_proxies();
+extern char* get_configs();
+
+#ifdef __cplusplus
+}
+#endif

+ 94 - 26
core/go.mod

@@ -1,44 +1,112 @@
-module mapleafgo.cn/clash_for_flutter/core
+module github.com/kingtous/flutter-clash-binding
 
-go 1.20
+go 1.21
+
+toolchain go1.21.0
+
+replace github.com/kingtous/fclash-go-bridge => ./fclash-go-bridge
+
+replace github.com/Dreamacro/clash => github.com/MetaCubeX/Clash.Meta v1.16.0
 
 require (
-	github.com/Dreamacro/clash v1.16.0
-	github.com/oschwald/geoip2-golang v1.8.0
+	github.com/Dreamacro/clash v1.18.0
+	github.com/kingtous/fclash-go-bridge v1.0.0
 )
 
+require gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+
 require (
-	github.com/Dreamacro/protobytes v0.0.0-20230524072133-0b6ef2348cfa // indirect
+	github.com/3andne/restls-client-go v0.1.6 // indirect
+	github.com/RyuaNerin/go-krypto v1.0.2 // indirect
+	github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
+	github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
 	github.com/ajg/form v1.5.1 // indirect
-	github.com/go-chi/chi/v5 v5.0.8 // indirect
+	github.com/andybalholm/brotli v1.0.5 // indirect
+	github.com/cilium/ebpf v0.11.0 // indirect
+	github.com/coreos/go-iptables v0.7.0 // indirect
+	github.com/dlclark/regexp2 v1.10.0 // indirect
+	github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
+	github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
+	github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
+	github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect
+	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/gaukas/godicttls v0.0.4 // indirect
+	github.com/go-chi/chi/v5 v5.0.10 // indirect
 	github.com/go-chi/cors v1.2.1 // indirect
-	github.com/go-chi/render v1.0.2 // indirect
+	github.com/go-chi/render v1.0.3 // indirect
+	github.com/go-ole/go-ole v1.3.0 // indirect
+	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
 	github.com/gofrs/uuid/v5 v5.0.0 // indirect
-	github.com/google/go-cmp v0.5.9 // indirect
+	github.com/golang/mock v1.6.0 // indirect
+	github.com/google/btree v1.1.2 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
-	github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb // indirect
+	github.com/hashicorp/yamux v0.1.1 // indirect
+	github.com/insomniacslk/dhcp v0.0.0-20231012130842-9b5d35ae8e55 // indirect
 	github.com/josharian/native v1.1.0 // indirect
+	github.com/jpillora/backoff v1.0.0 // indirect
+	github.com/klauspost/compress v1.16.7 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
+	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+	github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
 	github.com/mdlayher/netlink v1.7.2 // indirect
-	github.com/mdlayher/socket v0.4.1 // indirect
-	github.com/miekg/dns v1.1.54 // indirect
-	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
-	github.com/oschwald/maxminddb-golang v1.10.0 // indirect
-	github.com/pierrec/lz4/v4 v4.1.17 // indirect
+	github.com/mdlayher/socket v0.5.0 // indirect
+	github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
+	github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect
+	github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf // indirect
+	github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 // indirect
+	github.com/metacubex/sing-shadowsocks v0.2.5 // indirect
+	github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect
+	github.com/metacubex/sing-tun v0.1.12 // indirect
+	github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 // indirect
+	github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 // indirect
+	github.com/miekg/dns v1.1.56 // indirect
+	github.com/mroth/weightedrand/v2 v2.1.0 // indirect
+	github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
+	github.com/onsi/ginkgo/v2 v2.9.5 // indirect
+	github.com/openacid/low v0.1.21 // indirect
+	github.com/oschwald/maxminddb-golang v1.12.0 // indirect
+	github.com/pierrec/lz4/v4 v4.1.18 // indirect
+	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+	github.com/puzpuzpuz/xsync/v2 v2.5.0 // indirect
+	github.com/quic-go/qpack v0.4.0 // indirect
+	github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
+	github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
+	github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
+	github.com/sagernet/sing v0.2.11 // indirect
+	github.com/sagernet/sing-mux v0.1.3 // indirect
+	github.com/sagernet/sing-shadowtls v0.1.4 // indirect
+	github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
+	github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect
+	github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
+	github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect
 	github.com/samber/lo v1.38.1 // indirect
-	github.com/sirupsen/logrus v1.9.2 // indirect
+	github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect
+	github.com/shirou/gopsutil/v3 v3.23.8 // indirect
+	github.com/shoenig/go-m1cpu v0.1.6 // indirect
+	github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect
+	github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
+	github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect
+	github.com/sirupsen/logrus v1.9.3 // indirect
+	github.com/tklauser/go-sysconf v0.3.12 // indirect
+	github.com/tklauser/numcpus v0.6.1 // indirect
 	github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
-	github.com/vishvananda/netlink v1.2.1-beta.2.0.20230420174744-55c8b9515a01 // indirect
 	github.com/vishvananda/netns v0.0.4 // indirect
+	github.com/yusufpapurcu/wmi v1.2.3 // indirect
+	github.com/zhangyunhao116/fastrand v0.3.0 // indirect
+	gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect
 	go.etcd.io/bbolt v1.3.7 // indirect
-	go.uber.org/atomic v1.11.0 // indirect
-	golang.org/x/crypto v0.9.0 // indirect
-	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
-	golang.org/x/mod v0.10.0 // indirect
-	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/sync v0.2.0 // indirect
-	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
-	golang.org/x/tools v0.9.1 // indirect
-	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
+	golang.org/x/crypto v0.14.0 // indirect
+	golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
+	golang.org/x/mod v0.13.0 // indirect
+	golang.org/x/net v0.17.0 // indirect
+	golang.org/x/sync v0.4.0 // indirect
+	golang.org/x/sys v0.13.0 // indirect
+	golang.org/x/text v0.13.0 // indirect
+	golang.org/x/time v0.3.0 // indirect
+	golang.org/x/tools v0.14.0 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	lukechampine.com/blake3 v1.2.1 // indirect
 )

+ 253 - 49
core/go.sum

@@ -1,90 +1,294 @@
-github.com/Dreamacro/clash v1.16.0 h1:Ve+8mvtsCv7ySa6f53/GOW6Tho0AFp5RNFsgQZFKcZs=
-github.com/Dreamacro/clash v1.16.0/go.mod h1:ZM3UI2gqqUN7UL7L/F9aTHODTByya6sbC/WivQpaoJk=
-github.com/Dreamacro/protobytes v0.0.0-20230524072133-0b6ef2348cfa h1:1P5rBkdUX+VK0WNJaTAK0LvxVZ6SDPxCU4MLdcVX7R4=
-github.com/Dreamacro/protobytes v0.0.0-20230524072133-0b6ef2348cfa/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k=
+github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
+github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY=
+github.com/MetaCubeX/Clash.Meta v1.16.0 h1:iXyrWiNXW2KTeVavNF6RYT+ZttN1GcA2RZA4yBOJy4g=
+github.com/MetaCubeX/Clash.Meta v1.16.0/go.mod h1:KjXZh8AsC2LLtL9iUvBeHG+GofSfTMj4WLddhuVcKrs=
+github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM=
+github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA=
+github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok=
+github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
+github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
+github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
 github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
 github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
+github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y=
+github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs=
+github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8=
+github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
-github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
+github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
+github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
+github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
+github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po=
+github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg=
+github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c/go.mod h1:ETASDWf/FmEb6Ysrtd1QhjNedUU/ZQxBCRLh60bQ/UI=
+github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY=
+github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4=
+github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA=
+github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok=
+github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
+github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
+github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
+github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
+github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
 github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
-github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
-github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
+github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
+github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
 github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
 github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
+github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I=
+github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q=
-github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
+github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/insomniacslk/dhcp v0.0.0-20231012130842-9b5d35ae8e55 h1:dmjBtYDUZ5eGvu/PaA5T3I56XSFMgOfx1y6ewalrkDs=
+github.com/insomniacslk/dhcp v0.0.0-20231012130842-9b5d35ae8e55/go.mod h1:yuSAiSXw3A4R2pJZhqGa4I7/gBSOZ9aGYP5MBe/Zwoo=
 github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
 github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
+github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
+github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
+github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
 github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
 github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
-github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
-github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
-github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
-github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
-github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
-github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
-github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
+github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
+github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
+github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
+github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
+github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww=
+github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg=
+github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8=
+github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8=
+github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 h1:6g+ohVa8FQLXz/ATmped/4kWuK0HKvhy1hwzQXyF0EI=
+github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4=
+github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc=
+github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo=
+github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE=
+github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k=
+github.com/metacubex/sing-tun v0.1.12 h1:Jgmz0k3ddRiJ8zfS4X7j6B/iSy6GnOdDEU0nhqiZcK4=
+github.com/metacubex/sing-tun v0.1.12/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M=
+github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY=
+github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM=
+github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA=
+github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs=
+github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
+github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
+github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
+github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU=
+github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
+github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
+github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
+github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
+github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
+github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0=
+github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo=
+github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0=
+github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs3U1+I=
+github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do=
+github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
+github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
 github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
-github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
-github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
+github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c=
+github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
+github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
+github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
+github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
+github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
+github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
+github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
+github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
+github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
+github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
+github.com/sagernet/sing v0.2.11 h1:mu0S6d8y/xSVxilOqRd32Fmire5SZz9nT3t9NEHwUMY=
+github.com/sagernet/sing v0.2.11/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg=
+github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA=
+github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0=
+github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
+github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
+github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
+github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
+github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q=
+github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M=
+github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4=
+github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
+github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho=
+github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk=
 github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
 github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
-github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
-github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
+github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
+github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
+github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
+github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8=
+github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM=
+github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk=
+github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU=
+github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo=
+github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
 github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg=
 github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
-github.com/vishvananda/netlink v1.2.1-beta.2.0.20230420174744-55c8b9515a01 h1:F9xjJm4IH8VjcqG4ujciOF+GIM4mjPkHhWLLzOghPtM=
-github.com/vishvananda/netlink v1.2.1-beta.2.0.20230420174744-55c8b9515a01/go.mod h1:cAAsePK2e15YDAMJNyOpGYEWNe4sIghTY7gpz4cX/Ik=
-github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
 github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
 github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
+github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig=
+github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc=
+gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
+gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
 go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
 go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
-go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
-go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
-golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
-golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
-golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
+golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
-golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
+lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

+ 319 - 49
core/lib.go

@@ -1,84 +1,354 @@
 package main
 
+/*
+#include "stdint.h"
+*/
 import "C"
 import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"os"
+	"strconv"
+	"time"
+	"unsafe"
+
+	"github.com/Dreamacro/clash/adapter"
+	"github.com/Dreamacro/clash/adapter/outboundgroup"
+	"github.com/Dreamacro/clash/common/observable"
+	"github.com/Dreamacro/clash/common/utils"
+	"github.com/Dreamacro/clash/component/profile/cachefile"
+	"github.com/Dreamacro/clash/component/resolver"
 	"github.com/Dreamacro/clash/config"
 	"github.com/Dreamacro/clash/constant"
 	"github.com/Dreamacro/clash/hub"
-	"github.com/oschwald/geoip2-golang"
-	"log"
-	"os"
-	"path/filepath"
+	"github.com/Dreamacro/clash/hub/executor"
+	P "github.com/Dreamacro/clash/listener"
+	"github.com/Dreamacro/clash/log"
+	"github.com/Dreamacro/clash/tunnel"
+	"github.com/Dreamacro/clash/tunnel/statistic"
+	fclashgobridge "github.com/kingtous/fclash-go-bridge"
+)
+
+var (
+	options        []hub.Option
+	log_subscriber observable.Subscription[log.Event]
 )
 
-var options []hub.Option
+//export clash_init
+func clash_init(home_dir *C.char) int {
+	home := C.GoString(home_dir)
+	// constant.
+	err := config.Init(home)
+	if err != nil {
+		return -1
+	}
+	return 0
+}
+
+//export set_config
+func set_config(config_path *C.char) int {
+	file := C.GoString(config_path)
+	if _, err := executor.ParseWithPath(file); err != nil {
+		fmt.Println("config validate failed:", err)
+		return -1
+	}
+	constant.SetConfig(file)
+	return 0
+}
+
+//export set_home_dir
+func set_home_dir(home *C.char) int {
+	home_gostr := C.GoString(home)
+	info, err := os.Stat(home_gostr)
+	if err == nil && info.IsDir() {
+		fmt.Println("GO: set home dir to", home_gostr)
+		constant.SetHomeDir(home_gostr)
+		return 0
+	} else {
+		if err != nil {
+			fmt.Println("error:", err)
+		}
+	}
+	return -1
+}
+
+//export get_config
+func get_config() *C.char {
+	return C.CString(constant.Path.Config())
+}
+
+//export set_ext_controller
+func set_ext_controller(port uint64) int {
+	url := "127.0.0.1:" + strconv.FormatUint(port, 10)
+	options = append(options, hub.WithExternalController(url))
+	return 0
+}
+
+//export clear_ext_options
+func clear_ext_options() {
+	options = options[:0]
+}
 
-func init() {
-	constant.Version = "v1.16.0"
+//export is_config_valid
+func is_config_valid(config_path *C.char) int {
+	if _, err := executor.ParseWithPath(C.GoString(config_path)); err != nil {
+		fmt.Println("error reading config:", err)
+		return -1
+	}
+	return 0
 }
 
-//export setHomeDir
-func setHomeDir(homeStr *C.char) bool {
-	homeDir := C.GoString(homeStr)
-	info, err := os.Stat(homeDir)
+//export get_all_connections
+func get_all_connections() *C.char {
+	snapshot := statistic.DefaultManager.Snapshot()
+	data, err := json.Marshal(snapshot)
 	if err != nil {
-		log.Printf("clash_lib [setHomeDir]: %s : %+v\n", homeDir, err)
-		return false
+		fmt.Println("Error:", err)
+		return C.CString("")
 	}
-	if !info.IsDir() {
-		log.Printf("clash_lib [setHomeDir]: Path is not directory %s\n", homeDir)
-		return false
+	return C.CString(string(data))
+}
+
+//export close_all_connections
+func close_all_connections() {
+	statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
+		c.Close()
+		return true
+	})
+}
+
+//export close_connection
+func close_connection(id *C.char) bool {
+	connection_id := C.GoString(id)
+	statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
+		if c.ID() == connection_id {
+			c.Close()
+			return false
+		}
+		return true
+	})
+	return false
+}
+
+//export parse_options
+func parse_options() bool {
+	err := hub.Parse(options...)
+	if err != nil {
+		return true
 	}
-	constant.SetHomeDir(homeDir)
-	return true
+	return false
 }
 
-//export setConfig
-func setConfig(configStr *C.char) bool {
-	configFile := C.GoString(configStr)
-	if configFile == "" {
-		return false
+//export get_traffic
+func get_traffic() *C.char {
+	up, down := statistic.DefaultManager.Now()
+	traffic := map[string]int64{
+		"Up":   up,
+		"Down": down,
 	}
-	if !filepath.IsAbs(configFile) {
-		configFile = filepath.Join(constant.Path.HomeDir(), configFile)
+	data, err := json.Marshal(traffic)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return C.CString("")
 	}
-	constant.SetConfig(configFile)
-	return true
+	return C.CString(string(data))
 }
 
-//export withExternalController
-func withExternalController(externalController *C.char) {
-	options = append(options, hub.WithExternalController(C.GoString(externalController)))
+//export init_native_api_bridge
+func init_native_api_bridge(api unsafe.Pointer) {
+	fclashgobridge.InitDartApi(api)
 }
 
-//export withSecret
-func withSecret(secret *C.char) {
-	options = append(options, hub.WithSecret(C.GoString(secret)))
+//export start_log
+func start_log(port C.longlong) {
+	if log_subscriber != nil {
+		log.UnSubscribe(log_subscriber)
+		log_subscriber = nil
+	}
+	log_subscriber = log.Subscribe()
+	go func() {
+		for elem := range log_subscriber {
+			lg := elem
+			data, err := json.Marshal(lg)
+			if err != nil {
+				fmt.Println("Error:", err)
+			}
+			ret_str := string(data)
+			fclashgobridge.SendToPort(int64(port), ret_str)
+		}
+	}()
+	fmt.Println("[GO] subscribe logger on dart bridge port", int64(port))
 }
 
-//export mmdbVerify
-func mmdbVerify(path *C.char) bool {
-	instance, err := geoip2.Open(C.GoString(path))
-	if err == nil {
-		_ = instance.Close()
+//export stop_log
+func stop_log() {
+	if log_subscriber != nil {
+		log.UnSubscribe(log_subscriber)
+		fmt.Println("Logger stopped")
+		log_subscriber = nil
 	}
-	return err == nil
 }
 
-//export startService
-func startService() bool {
-	if err := config.Init(constant.Path.HomeDir()); err != nil {
-		log.Printf("clash_lib [startService]: Initial error: %+v\n", err)
-		return false
+//export change_proxy
+func change_proxy(selector_name *C.char, proxy_name *C.char) C.long {
+	proxies := tunnel.Proxies()
+	proxy := proxies[C.GoString(selector_name)]
+	if proxy == nil {
+		return C.long(-1)
 	}
-	err := hub.Parse(options...)
+	adapter_proxy := proxy.(*adapter.Proxy)
+	selector, ok := adapter_proxy.ProxyAdapter.(*outboundgroup.Selector)
+	if !ok {
+		// not selector
+		return C.long(-1)
+	}
+	if err := selector.Set(C.GoString(proxy_name)); err != nil {
+		fmt.Println("", err)
+		return C.long(-1)
+	}
+	cachefile.Cache().SetSelected(string(C.GoString(selector_name)), string(C.GoString(proxy_name)))
+	return C.long(0)
+}
+
+type configSchema struct {
+	Port        *int               `json:"port"`
+	SocksPort   *int               `json:"socks-port"`
+	RedirPort   *int               `json:"redir-port"`
+	TProxyPort  *int               `json:"tproxy-port"`
+	MixedPort   *int               `json:"mixed-port"`
+	AllowLan    *bool              `json:"allow-lan"`
+	BindAddress *string            `json:"bind-address"`
+	Mode        *tunnel.TunnelMode `json:"mode"`
+	LogLevel    *log.LogLevel      `json:"log-level"`
+	IPv6        *bool              `json:"ipv6"`
+}
+
+func pointerOrDefault(p *int, def int) int {
+	if p != nil {
+		return *p
+	}
+
+	return def
+}
+
+//export change_config_field
+func change_config_field(s *C.char) C.long {
+	// todo
+	general := &configSchema{}
+	json_str := C.GoString(s)
+	if err := json.Unmarshal([]byte(json_str), general); err != nil {
+		fmt.Println(err)
+		return C.long(-1)
+	}
+	// copy from clash source code
+	if general.AllowLan != nil {
+		P.SetAllowLan(*general.AllowLan)
+	}
+
+	if general.BindAddress != nil {
+		P.SetBindAddress(*general.BindAddress)
+	}
+
+	ports := P.GetPorts()
+	ports.Port = pointerOrDefault(general.Port, ports.Port)
+	ports.MixedPort = pointerOrDefault(general.MixedPort, ports.MixedPort)
+	ports.SocksPort = pointerOrDefault(general.SocksPort, ports.SocksPort)
+	ports.RedirPort = pointerOrDefault(general.RedirPort, ports.RedirPort)
+	ports.TProxyPort = pointerOrDefault(general.TProxyPort, ports.TProxyPort)
+
+	tcpIn := tunnel.TCPIn()
+	udpIn := tunnel.UDPIn()
+	natTable := tunnel.NatTable()
+	// P.ReCreate(*ports, tcpIn, udpIn)
+
+	P.ReCreateHTTP(ports.Port, tcpIn)
+	P.ReCreateMixed(ports.Port, tcpIn, udpIn)
+	P.ReCreateSocks(ports.SocksPort, tcpIn, udpIn)
+	P.ReCreateRedir(ports.RedirPort, tcpIn, udpIn, natTable)
+	P.ReCreateTProxy(ports.TProxyPort, tcpIn, udpIn, natTable)
+
+	if general.Mode != nil {
+		tunnel.SetMode(*general.Mode)
+	}
+
+	if general.LogLevel != nil {
+		log.SetLevel(*general.LogLevel)
+	}
+
+	if general.IPv6 != nil {
+		resolver.DisableIPv6 = !*general.IPv6
+	}
+	return C.long(0)
+}
+
+//export async_test_delay
+func async_test_delay(proxy_name *C.char, url *C.char, timeout C.long, port C.longlong) {
+	go func() {
+		ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(int64(timeout)))
+		defer cancel()
+		proxies := tunnel.Proxies()
+		proxy := proxies[C.GoString(proxy_name)]
+		if proxy == nil {
+			data, err := json.Marshal(map[string]int64{
+				"delay": -1,
+			})
+			if err != nil {
+				return
+			}
+			fclashgobridge.SendToPort(int64(port), string(data))
+			return
+		}
+		rg := make(utils.IntRanges[uint16], 1)
+		rg[0] = utils.NewRange[uint16](200, 400)
+		delay,  err := proxy.URLTest(ctx, C.GoString(url), rg, constant.ExtraHistory)
+		if err != nil || delay == 0 {
+			data, err := json.Marshal(map[string]int64{
+				"delay": -1,
+			})
+			if err != nil {
+				return
+			}
+			fclashgobridge.SendToPort(int64(port), string(data))
+			return
+		}
+		data, err := json.Marshal(map[string]uint16{
+			"delay": delay,
+		})
+		if err != nil {
+			fmt.Println("err: ", err)
+		}
+		fclashgobridge.SendToPort(int64(port), string(data))
+	}()
+}
+
+//export get_proxies
+func get_proxies() *C.char {
+	proxies := tunnel.Proxies()
+	for _, provider := range tunnel.Providers() {
+		for _, proxy := range provider.Proxies() {
+			proxies[proxy.Name()] = proxy
+		}
+	}
+	data, err := json.Marshal(map[string]map[string]constant.Proxy{
+		"proxies": proxies,
+	})
+	if err != nil {
+		return C.CString("")
+	}
+	return C.CString(string(data))
+}
+
+//export get_configs
+func get_configs() *C.char {
+	general := executor.GetGeneral()
+	data, err := json.Marshal(general)
 	if err != nil {
-		log.Printf("clash_lib [startService]: %+v\n", err)
-		return false
+		return C.CString("")
 	}
-	return true
+	return C.CString(string(data))
 }
 
 func main() {
-	log.Println("hello clash")
+	fmt.Println("hello fclash")
 }

BIN
core/libclash.dylib


+ 26 - 7
core/dist/libclash.h → core/libclash.h

@@ -1,6 +1,6 @@
 /* Code generated by cmd/cgo; DO NOT EDIT. */
 
-/* package mapleafgo.cn/clash_for_flutter/core */
+/* package github.com/kingtous/flutter-clash-binding */
 
 
 #line 1 "cgo-builtin-export-prolog"
@@ -19,6 +19,11 @@ typedef struct { const char *p; ptrdiff_t n; } _GoString_;
 /* Start of preamble from import "C" comments.  */
 
 
+#line 3 "lib.go"
+
+#include "stdint.h"
+
+#line 1 "cgo-generated-wrapper"
 
 
 /* End of preamble from import "C" comments.  */
@@ -74,12 +79,26 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
 extern "C" {
 #endif
 
-extern GoUint8 setHomeDir(char* homeStr);
-extern GoUint8 setConfig(char* configStr);
-extern void withExternalController(char* externalController);
-extern void withSecret(char* secret);
-extern GoUint8 mmdbVerify(char* path);
-extern GoUint8 startService();
+extern GoInt clash_init(char* home_dir);
+extern GoInt set_config(char* config_path);
+extern GoInt set_home_dir(char* home);
+extern char* get_config();
+extern GoInt set_ext_controller(GoUint64 port);
+extern void clear_ext_options();
+extern GoInt is_config_valid(char* config_path);
+extern char* get_all_connections();
+extern void close_all_connections();
+extern GoUint8 close_connection(char* id);
+extern GoUint8 parse_options();
+extern char* get_traffic();
+extern void init_native_api_bridge(void* api);
+extern void start_log(long long port);
+extern void stop_log();
+extern long change_proxy(char* selector_name, char* proxy_name);
+extern long change_config_field(char* s);
+extern void async_test_delay(char* proxy_name, char* url, long timeout, long long port);
+extern char* get_proxies();
+extern char* get_configs();
 
 #ifdef __cplusplus
 }

BIN
images/main/logo.ico


BIN
images/main/logo.png


+ 4 - 2
ios/Runner.xcodeproj/project.pbxproj

@@ -161,7 +161,6 @@
 				0E55539F675EF9FF4895197E /* Pods-RunnerTests.release.xcconfig */,
 				5C5514BDB2EE7AF7D247F752 /* Pods-RunnerTests.profile.xcconfig */,
 			);
-			name = Pods;
 			path = Pods;
 			sourceTree = "<group>";
 		};
@@ -323,7 +322,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
 		};
 		56783D2414A4B5DFE3063745 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
@@ -474,6 +473,7 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
+					../core,
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = com.naiyou.wl.naiyouwl;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -652,6 +652,7 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
+					../core,
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = com.naiyou.wl.naiyouwl;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -674,6 +675,7 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
+					../core,
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = com.naiyou.wl.naiyouwl;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 35 - 0
lib/app/bean/clash_config_entity.dart

@@ -0,0 +1,35 @@
+import 'dart:convert';
+
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+import 'package:naiyouwl/app/bean/rule.dart';
+
+import '../data/model/NodeMode.dart';
+import 'clash_config_generator.dart';
+
+@jsonSerializable
+class ClashConfigEntity {
+  int? port;
+  @JsonProperty(name: "socks-port")
+  int? socksPort;
+  @JsonProperty(name: "redir-port")
+  int? redirPort;
+  @JsonProperty(name: "tproxy-port")
+  int? tproxyPort;
+  @JsonProperty(name: "mixed-port")
+  int? mixedPort;
+  List<dynamic>? authentication;
+  @JsonProperty(name: "allow-lan")
+  bool? allowLan;
+  @JsonProperty(name: "bind-address")
+  String? bindAddress;
+  String? mode;
+  @JsonProperty(name: "log-level")
+  String? logLevel;
+  bool? ipv6;
+
+  ClashConfigEntity(this.port,this.socksPort,this.redirPort,this.tproxyPort,this.mixedPort,this.authentication,this.allowLan,this.bindAddress,this.mode,this.logLevel,this.ipv6);
+
+
+
+
+}

+ 138 - 0
lib/app/bean/clash_config_generator.dart

@@ -0,0 +1,138 @@
+// 代理类
+class Proxy {
+  final String name;
+  final String type;
+  final String server;
+  final int port;
+  final String uuid;
+  final int udp;
+  final String? flow;
+  final String? servername;
+  final bool? tls;
+
+  Proxy({
+    required this.name,
+    required this.type,
+    required this.server,
+    required this.port,
+    required this.uuid,
+    required this.udp,
+    this.flow,
+    this.servername,
+    this.tls,
+  });
+
+  String toYamlString() {
+    var lines = [
+      'name: $name',
+      'type: $type',
+      'server: $server',
+      'port: $port',
+      'uuid: $uuid',
+      'udp: $udp',
+    ];
+
+    if (flow != null) lines.add('flow: $flow');
+    if (servername != null) lines.add('servername: $servername');
+    if (tls != null) lines.add('tls: $tls');
+
+    return lines.map((line) => '  - $line').join('\n');
+  }
+}
+
+// 代理组类
+class ProxyGroup {
+  final String name;
+  final String type;
+  final List<String> proxies;
+
+  ProxyGroup({
+    required this.name,
+    required this.type,
+    required this.proxies,
+  });
+
+  String toYamlString() {
+    return '  - name: $name\n  type: $type\n  proxies: [${proxies.join(', ')}]';
+  }
+}
+
+// 主配置类
+class YamlConfig {
+  final int mixedPort;
+  final bool allowLan;
+  final String bindAddress;
+  final String mode;
+  final String logLevel;
+  final String externalController;
+  final List<Proxy> proxies;
+  final List<ProxyGroup> proxyGroups;
+  final List<String> rules;
+
+  YamlConfig({
+    required this.mixedPort,
+    required this.allowLan,
+    required this.bindAddress,
+    required this.mode,
+    required this.logLevel,
+    required this.externalController,
+    required this.proxies,
+    required this.proxyGroups,
+    required this.rules,
+  });
+
+  String toYamlString() {
+    return '''mixed-port: $mixedPort
+allow-lan: $allowLan
+bind-address: '$bindAddress'
+mode: $mode
+log-level: $logLevel
+external-controller: '$externalController'
+proxies:
+${proxies.map((proxy) => proxy.toYamlString()).join('\n')}
+proxy-groups:
+${proxyGroups.map((group) => group.toYamlString()).join('\n')}
+rules:
+- ${rules.join('\n- ')}''';
+  }
+}
+
+// void main() {
+//   // 为示例,这里仅添加了一些代理和代理组。
+//   var exampleProxies = [
+//     Proxy(
+//       name: '香港22-vless',
+//       type: 'vless',
+//       server: 'sz.ip2000.top',
+//       port: 27399,
+//       uuid: '459b4a80-bd61-4ecd-a26b-e9c1809d9e45',
+//       udp: 1,
+//       flow: 'xtls-rprx-vision',
+//       servername: 'www.amazon.com',
+//       tls: true,
+//     ),
+//     // ... 可以根据需要添加更多代理
+//   ];
+//
+//   var exampleProxyGroup = ProxyGroup(
+//     name: 'proxy',
+//     type: 'select',
+//     proxies: ['香港22-vless', '香港原生61D'],
+//   );
+//
+//   var config = YamlConfig(
+//     mixedPort: 7890,
+//     allowLan: true,
+//     bindAddress: '*',
+//     mode: 'rule',
+//     logLevel: 'info',
+//     externalController: '127.0.0.1:9090',
+//     proxies: exampleProxies,
+//     proxyGroups: [exampleProxyGroup],
+//     rules: ['MATCH,用户中心'],
+//   );
+//
+//   // var fileName = 'config_output.yaml';
+//   // File(fileName).writeAsStringSync(config.toYamlString());
+//   // print('YAML config saved to $fileName');
+// }

+ 0 - 0
lib/app/bean/config_bean.dart


+ 18 - 0
lib/app/bean/proxy_group.dart

@@ -0,0 +1,18 @@
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+
+@jsonSerializable
+class ProxyGroup {
+  String? name;
+  String type;
+  List<String> proxies;
+
+  ProxyGroup({required this.name, required this.type, required this.proxies});
+
+  Map<String, dynamic> toYamlMap() {
+    return {
+      "name": name,
+      "type": type,
+      "proxies": proxies,
+    };
+  }
+}

+ 10 - 0
lib/app/bean/rule.dart

@@ -0,0 +1,10 @@
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+
+@jsonSerializable
+class Rule {
+  String rule;
+
+  Rule({required this.rule});
+
+  String toYamlString() => rule;
+}

+ 2 - 0
lib/app/common/SharedPreferencesUtil.dart

@@ -14,6 +14,8 @@ class SharedPreferencesUtil {
   // 获取 SharedPreferences 实例
   Future<SharedPreferences> get _instance async => await SharedPreferences.getInstance();
 
+
+
   // 存储字符串
   Future<void> setString(String key, String value) async {
     final prefs = await _instance;

+ 3 - 3
lib/app/component/connection_widget.dart

@@ -60,13 +60,13 @@ class _ConnectionWidgetState extends State<ConnectionWidget> {
   void _updateImage() {
     switch (_currentStatus) {
       case ConnectionStatus.disconnected:
-        currentImage = 'images/main/disconnected.gif';
+        currentImage = 'assets/images/main/disconnected.gif';
         break;
       case ConnectionStatus.connecting:
-        currentImage = 'images/main/connecting.gif';
+        currentImage = 'assets/images/main/connecting.gif';
         break;
       case ConnectionStatus.stopped:
-        currentImage = 'images/main/stopped.gif';
+        currentImage = 'assets/images/main/stopped.gif';
         break;
     }
   }

+ 0 - 39
lib/app/global_controller/GlobalConfigFileController.dart

@@ -1,39 +0,0 @@
-import 'dart:io';
-
-import 'package:get/get.dart';
-import 'package:naiyouwl/clash_generated_bindings.dart';
-class GlobalConfigFileController extends GetxController{
-  static bool isStartClash = false;
-
-  late Directory configDir;
-  late final Clash clash;
-  late final String clashConfigPath;
-  late final String clashForMePath;
-  late final String profilesPath;
-
-  var systemProxy = false.obs;
-  // var clashConfig = Config.defaultConfig().obs;
-  // var clashForMe = ClashForMeConfig.defaultConfig().obs;
-  //
-  // Future<void> init() async {
-  //    await getApplicationSupportDirectory().then((dir) => configDir = dir);
-  //
-  //   profilesPath = "${configDir.path}${Constants.profilesPath}";
-  //   clashForMePath = "${configDir.path}${Constants.clashForMe}";
-  //   clashConfigPath = "${configDir.path}${Constants.clashConfig}";
-  //
-  //   await _initClash();
-  //   _initConfig();
-  //   _initAction();
-  // }
-  //
-  // _initConfig() async {
-  //   ClashForMeConfig? tempCfm = ClashForMeConfig.formYamlFile(clashForMePath);
-  //   tempCfm = await _profilesInitCheck(tempCfm);
-  //   if (tempCfm != null) {
-  //     clashForMe.value = tempCfm;
-  //   }
-  //
-  //   clashConfig.value = Config.formYamlFile(clashConfigPath);
-  // }
-}

+ 48 - 5
lib/app/modules/home/controllers/home_controller.dart

@@ -1,6 +1,10 @@
 
+import 'dart:io';
+
 import 'package:dart_json_mapper/dart_json_mapper.dart';
 import 'package:get/get.dart';
+import 'package:tray_manager/tray_manager.dart';
+import 'package:window_manager/window_manager.dart';
 import '../../../common/LogHelper.dart';
 import '../../../common/SharedPreferencesUtil.dart';
 import '../../../data/model/LocalUser.dart';
@@ -10,6 +14,7 @@ import '../../../data/model/UserMode.dart';
 import '../../../global_controller/GlobalController.dart';
 import '../../../network/api_service.dart';
 import '../../../routes/app_pages.dart';
+import '../../../service/clash_service.dart';
 
 enum ImageType {
   CUSTOMER,
@@ -18,7 +23,7 @@ enum ImageType {
   RENEWAL,
 }
 
-class HomeController extends GetxController {
+class HomeController extends GetxController with TrayListener,WindowListener {
   //TODO: Implement HomeController
 
   var isLoading = false.obs;
@@ -32,10 +37,10 @@ class HomeController extends GetxController {
 
 
   final Map<ImageType, String> imageMap = {
-    ImageType.CUSTOMER: "images/main/customer.png",
-    ImageType.PROMOTION: "images/main/promotion.png",
-    ImageType.TUTORIAL: "images/main/tutorial.png",
-    ImageType.RENEWAL: "images/main/renewal.png",
+    ImageType.CUSTOMER: "assets/images/main/customer.png",
+    ImageType.PROMOTION: "assets/images/main/promotion.png",
+    ImageType.TUTORIAL: "assets/images/main/tutorial.png",
+    ImageType.RENEWAL: "assets/images/main/renewal.png",
   };
 
   void onImageTap(ImageType type) {
@@ -110,6 +115,8 @@ class HomeController extends GetxController {
     fetchSysConfig();
     fetchLocalUser();
     fetchUserinfo();
+    windowManager.addListener(this);
+    trayManager.addListener(this);
   }
 
   @override
@@ -121,6 +128,42 @@ class HomeController extends GetxController {
   void onClose() {
     super.onClose();
   }
+
+
+  @override
+  void onWindowClose() {
+    super.onWindowClose();
+    windowManager.hide();
+  }
+
+  @override
+  void onTrayIconMouseDown() {
+    // windowManager.focus();
+    windowManager.show();
+  }
+
+  @override
+  void onTrayIconRightMouseDown() {
+    super.onTrayIconRightMouseDown();
+    trayManager.popUpContextMenu();
+  }
+
+  @override
+  void onTrayMenuItemClick(MenuItem menuItem) {
+    switch (menuItem.key) {
+      case 'exit':
+        windowManager.close().then((value) async {
+          await Get.find<ClashService>().closeClashDaemon();
+          exit(0);
+        });
+        break;
+      case 'show':
+        windowManager.focus();
+        windowManager.show();
+    }
+  }
+
+
   bool   GetEnable()  => userMode.value.enable == 1;
   String GetUserName() => localUsers.value.email.toString();
   String GetExpiredAt() => "到期时间:${userMode.value.expiredAt}";

+ 7 - 4
lib/app/modules/home/views/home_view.dart

@@ -5,11 +5,13 @@ import 'package:flutter/material.dart';
 
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/component/sys_app_bar.dart';
+import 'package:tray_manager/tray_manager.dart';
 import 'package:window_manager/window_manager.dart';
 import '../../../component/connection_status.dart';
 import '../../../component/connection_widget.dart';
 
 import '../../../global_controller/GlobalController.dart';
+import '../../../service/clash_service.dart';
 import '../controllers/home_controller.dart';
 
 
@@ -17,12 +19,13 @@ class HomeView extends GetView<HomeController> {
 
   const HomeView({Key? key}) : super(key: key);
 
+
   @override
   Widget build(BuildContext context) {
     return Container(
       decoration: const BoxDecoration(
         image: DecorationImage(
-          image: AssetImage("images/main/main.png"),
+          image: AssetImage("assets/images/main/main.png"),
           fit: BoxFit.fill,
         ),
       ),
@@ -146,8 +149,8 @@ class _UserStatusWidgetState extends State<UserStatusWidget> {
   @override
   Widget build(BuildContext context) {
     String imagePath = widget.isActive
-        ? "images/main/userstatus.png"
-        : "images/main/userstatusoff.png";
+        ? "assets/images/main/userstatus.png"
+        : "assets/images/main/userstatusoff.png";
 
     return Align(
       alignment: Alignment.topCenter,
@@ -175,7 +178,7 @@ class _UserStatusWidgetState extends State<UserStatusWidget> {
                     ),
                     const SizedBox(width: 10,),
                     IconButton(
-                      icon: widget.isLoading ? const CircularProgressIndicator() : Image.asset("images/main/refresh.png"),
+                      icon: widget.isLoading ? const CircularProgressIndicator() : Image.asset("assets/images/main/refresh.png"),
                       onPressed: () {
                         // 刷新操作
                         if(!widget.isLoading){

+ 1 - 1
lib/app/modules/login/views/login_view.dart

@@ -12,7 +12,7 @@ class LoginView extends GetView<LoginController> {
     return Container(
       decoration: const BoxDecoration(
         image: DecorationImage(
-          image: AssetImage("images/login/login.png"),
+          image: AssetImage("assets/images/login/login.png"),
           fit: BoxFit.fill,
         ),
       ),

+ 2 - 2
lib/app/modules/node/views/node_view.dart

@@ -16,7 +16,7 @@ class NodeView extends GetView<NodeController> {
     return Container(
       decoration: const BoxDecoration(
         image: DecorationImage(
-          image: AssetImage("images/node/nodebg.png"),
+          image: AssetImage("assets/images/node/nodebg.png"),
           fit: BoxFit.fill,
         ),
       ),
@@ -43,7 +43,7 @@ class NodeView extends GetView<NodeController> {
             height: 600,
             decoration: const BoxDecoration(
               image: DecorationImage(
-                image: AssetImage("images/node/nodetablebg.png"),
+                image: AssetImage("assets/images/node/nodetablebg.png"),
                 fit: BoxFit.fill,
               ),
             ),

+ 543 - 0
lib/app/service/clash_service.dart

@@ -0,0 +1,543 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:ffi' as ffi;
+import 'dart:io';
+import 'dart:isolate';
+import 'package:naiyouwl/main.dart';
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+import 'package:ffi/ffi.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+import 'package:path/path.dart';
+import 'package:path/path.dart' as p;
+import 'package:get/get.dart';
+import 'package:kommon/request/request.dart';
+import 'package:kommon/tool/sp_util.dart';
+import 'package:naiyouwl/clash_generated_bindings.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:proxy_manager/proxy_manager.dart';
+import 'package:tray_manager/tray_manager.dart';
+import '../bean/clash_config_entity.dart';
+late NativeLibrary clashFFI;
+
+//android 或者ios
+//const mobileChannel = MethodChannel("xxxPlugin");
+
+class ClashService extends GetxService with TrayListener {
+  // 需要一起改端口
+  static const clashBaseUrl = "http://127.0.0.1:$clashExtPort";
+  static const clashExtPort = 22346;
+
+  // 运行时
+  late Directory _clashDirectory;
+  RandomAccessFile? _clashLock;
+
+  // 流量
+  final uploadRate = 0.0.obs;
+  final downRate = 0.0.obs;
+  final yamlConfigs = RxSet<FileSystemEntity>();
+  final currentYaml = 'config.yaml'.obs;
+  final proxyStatus = RxMap<String, int>();
+
+  // action
+  static const ACTION_SET_SYSTEM_PROXY = "assr";
+  static const ACTION_UNSET_SYSTEM_PROXY = "ausr";
+  static const MAX_ENTRIES = 5;
+
+  // default port
+  static var initializedHttpPort = 0;
+  static var initializedSockPort = 0;
+  static var initializedMixedPort = 0;
+
+  // config
+  Rx<ClashConfigEntity?> configEntity = Rx(null);
+
+  // log
+  Stream<dynamic>? logStream;
+  RxMap<String, dynamic> proxies = RxMap();
+  RxBool isSystemProxyObs = RxBool(false);
+
+
+
+  ClashService() {
+    // load lib
+    var fullPath = "";
+    if (Platform.isWindows) {
+      fullPath = "libclash.dll";
+    } else if (Platform.isMacOS) {
+      fullPath = "libclash.dylib";
+    } else {
+      fullPath = "libclash.so";
+    }
+    final lib = ffi.DynamicLibrary.open(fullPath);
+    clashFFI = NativeLibrary(lib);
+    clashFFI.init_native_api_bridge(ffi.NativeApi.initializeApiDLData);
+  }
+
+  Future<ClashService> init() async {
+    _clashDirectory = await getApplicationSupportDirectory();
+
+    final _ = SpUtil.getData('yaml', defValue: currentYaml.value);
+    initializedHttpPort = SpUtil.getData('http-port', defValue: 12346);
+    initializedSockPort = SpUtil.getData('socks-port', defValue: 12347);
+    initializedMixedPort = SpUtil.getData('mixed-port', defValue: 12348);
+    currentYaml.value = _;
+    Request.setBaseUrl(clashBaseUrl);
+    final clashConfigPath = p.join(_clashDirectory.path, "clash");
+    _clashDirectory = Directory(clashConfigPath);
+    if (kDebugMode) {
+      print("fclash work directory: ${_clashDirectory.path}");
+    }
+    final clashConf = p.join(_clashDirectory.path, currentYaml.value);
+    final countryMMdb = p.join(_clashDirectory.path, 'Country.mmdb');
+    if (!await _clashDirectory.exists()) {
+      await _clashDirectory.create(recursive: true);
+    }
+    // copy executable to directory
+    final mmdb = await rootBundle.load('assets/tp/clash/Country.mmdb');
+    // write to clash dir
+    final mmdbF = File(countryMMdb);
+    if (!mmdbF.existsSync()) {
+      await mmdbF.writeAsBytes(mmdb.buffer.asInt8List());
+    }
+    final config = await rootBundle.load('assets/tp/clash/config.yaml');
+    // write to clash dir
+    final configF = File(clashConf);
+    if (!configF.existsSync()) {
+      await configF.writeAsBytes(config.buffer.asInt8List());
+    }
+    // create or detect lock file
+    await _acquireLock(_clashDirectory);
+    // ffi
+    clashFFI.set_home_dir(_clashDirectory.path.toNativeUtf8().cast());
+    clashFFI.clash_init(_clashDirectory.path.toNativeUtf8().cast());
+    clashFFI.set_config(clashConf.toNativeUtf8().cast());
+    clashFFI.set_ext_controller(clashExtPort);
+    if (clashFFI.parse_options() == 0) {
+      Get.printInfo(info: "parse ok");
+    }
+    Future.delayed(Duration.zero, () {
+     initDaemon();
+    });
+    // tray show issue
+    if (isDesktop) {
+      trayManager.addListener(this);
+    }
+    // wait getx initialize
+    // Future.delayed(const Duration(seconds: 3), () {
+    //   if (!Platform.isWindows) {
+    //     Get.find<NotificationService>()
+    //         .showNotification("Fclash", "Is running".tr);
+    //   }
+    // });
+    return this;
+  }
+
+  void getConfigs() {
+    yamlConfigs.clear();
+    final entities = _clashDirectory.listSync();
+    for (final entity in entities) {
+      if (entity.path.toLowerCase().endsWith('.yaml') &&
+          !yamlConfigs.contains(entity)) {
+        yamlConfigs.add(entity);
+        Get.printInfo(info: 'detected: ${entity.path}');
+      }
+    }
+  }
+
+  Map<String, dynamic> getConnections() {
+    final connsPtr = clashFFI.get_all_connections().cast<Utf8>();
+    String connections = connsPtr.toDartString();
+    // malloc.free(connsPtr);
+    return json.decode(connections);
+  }
+
+  void closeAllConnections() {
+    clashFFI.close_all_connections();
+  }
+
+  bool closeConnection(String connectionId) {
+    final id = connectionId.toNativeUtf8().cast<ffi.Char>();
+    return clashFFI.close_connection(id) == 1;
+  }
+
+  void getCurrentClashConfig() {
+    final configPtr = clashFFI.get_configs().cast<Utf8>();
+    final jsondata = json.decode(configPtr.toDartString());
+    final data =  JsonMapper.deserialize<ClashConfigEntity>(jsondata);
+    configEntity.value = data;
+    // malloc.free(configPtr);
+  }
+
+  Future<void> reload() async {
+    // get configs
+    getConfigs();
+    getCurrentClashConfig();
+    // proxies
+    getProxies();
+    updateTray();
+  }
+  void initDaemon() async {
+    printInfo(info: 'init clash service');
+    // wait for online
+    // while (!await isRunning()) {
+    //   printInfo(info: 'waiting online status');
+    //   await Future.delayed(const Duration(milliseconds: 500));
+    // }
+    // get traffic
+    Timer.periodic(const Duration(seconds: 1), (t) {
+      final trafficPtr = clashFFI.get_traffic().cast<Utf8>();
+      final traffic = trafficPtr.toDartString();
+      if (kDebugMode) {
+        debugPrint(traffic);
+      }
+      try {
+        final trafficJson = jsonDecode(traffic);
+        uploadRate.value = trafficJson['Up'].toDouble() / 1024; // KB
+        downRate.value = trafficJson['Down'].toDouble() / 1024; // KB
+        // fix: 只有KDE不会导致Tray自动消失
+        // final desktop = Platform.environment['XDG_CURRENT_DESKTOP'];
+        // updateTray();
+      } catch (e) {
+        Get.printError(info: '$e');
+      }
+      // malloc.free(trafficPtr);
+    });
+    // system proxy
+    // listen port
+    await reload();
+    checkPort();
+    if (isSystemProxy()) {
+      setSystemProxy();
+    }
+  }
+
+  @override
+  void onClose() {
+    closeClashDaemon();
+    super.onClose();
+  }
+
+  Future<void> closeClashDaemon() async {
+    Get.printInfo(info: 'fclash: closing daemon');
+    // double check
+    // stopClashSubP();
+    if (isSystemProxy()) {
+      // just clear system proxy
+      await clearSystemProxy(permanent: false);
+    }
+    await _clashLock?.unlock();
+  }
+  Future<void> setSystemProxy() async {
+    if (isDesktop) {
+      if (configEntity.value != null) {
+        final entity = configEntity.value!;
+        if (entity.port != 0) {
+          await Future.wait([
+            proxyManager.setAsSystemProxy(
+                ProxyTypes.http, '127.0.0.1', entity.port!),
+            proxyManager.setAsSystemProxy(
+                ProxyTypes.https, '127.0.0.1', entity.port!)
+          ]);
+          debugPrint("set http");
+        }
+        if (entity.socksPort != 0 && !Platform.isWindows) {
+          debugPrint("set socks");
+          await proxyManager.setAsSystemProxy(
+              ProxyTypes.socks, '127.0.0.1', entity.socksPort!);
+        }
+        await setIsSystemProxy(true);
+      }
+    } else {
+      if (configEntity.value != null) {
+        final entity = configEntity.value!;
+        if (entity.port != 0) {
+          // await mobileChannel
+          //     .invokeMethod("SetHttpPort", {"port": entity.port});
+        }
+       // mobileChannel.invokeMethod("StartProxy");
+        await setIsSystemProxy(true);
+      }
+
+      // await Clipboard.setData(
+      //     ClipboardData(text: "${configEntity.value?.port}"));
+      // final dialog = BrnDialog(
+      //   titleText: "请手动设置代理",
+      //   messageText:
+      //       "端口号已复制。请进入已连接WiFi的详情设置,将代理设置为手动,主机名填写127.0.0.1,端口填写${configEntity.value?.port},然后返回点击已完成即可",
+      //   actionsText: ["取消", "已完成", "去设置填写"],
+      //   indexedActionCallback: (index) async {
+      //     if (index == 0) {
+      //       if (Get.isOverlaysOpen) {
+      //         Get.back();
+      //       }
+      //     } else if (index == 1) {
+      //       final proxy = await SystemProxy.getProxySettings();
+      //       if (proxy != null) {
+      //         if (proxy["host"] == "127.0.0.1" &&
+      //             int.parse(proxy["port"].toString()) ==
+      //                 configEntity.value?.port) {
+      //           Future.delayed(Duration.zero, () {
+      //             if (Get.overlayContext != null) {
+      //               BrnToast.show("设置成功", Get.overlayContext!);
+      //               setIsSystemProxy(true);
+      //             }
+      //           });
+      //           if (Get.isOverlaysOpen) {
+      //             Get.back();
+      //           }
+      //         }
+      //       } else {
+      //         Future.delayed(Duration.zero, () {
+      //           if (Get.overlayContext != null) {
+      //             BrnToast.show("好像未完成设置哦", Get.overlayContext!);
+      //           }
+      //         });
+      //       }
+      //     } else {
+      //       Future.delayed(Duration.zero, () {
+      //         BrnToast.show("端口号已复制", Get.context!);
+      //       });
+      //       await OpenSettings.openWIFISetting();
+      //     }
+      //   },
+      // );
+      // Get.dialog(dialog);
+    }
+  }
+
+  Future<void> clearSystemProxy({bool permanent = true}) async {
+    if (isDesktop) {
+      await proxyManager.cleanSystemProxy();
+      if (permanent) {
+        await setIsSystemProxy(false);
+      }
+    } else {
+      //mobileChannel.invokeMethod("StopProxy");
+      await setIsSystemProxy(false);
+      // final dialog = BrnDialog(
+      //   titleText: "请手动设置代理",
+      //   messageText: "请进入已连接WiFi的详情设置,将代理设置为无",
+      //   actionsText: ["取消", "已完成", "去设置清除"],
+      //   indexedActionCallback: (index) async {
+      //     if (index == 0) {
+      //       if (Get.isOverlaysOpen) {
+      //         Get.back();
+      //       }
+      //     } else if (index == 1) {
+      //       final proxy = await SystemProxy.getProxySettings();
+      //       if (proxy != null) {
+      //         Future.delayed(Duration.zero, () {
+      //           if (Get.overlayContext != null) {
+      //             BrnToast.show("好像没有清除成功哦,当前代理${proxy}", Get.overlayContext!);
+      //           }
+      //         });
+      //       } else {
+      //         Future.delayed(Duration.zero, () {
+      //           if (Get.overlayContext != null) {
+      //             BrnToast.show("清除成功", Get.overlayContext!);
+      //           }
+      //           setIsSystemProxy(false);
+      //           if (Get.isOverlaysOpen) {
+      //             Get.back();
+      //           }
+      //         });
+      //       }
+      //     } else {
+      //       OpenSettings.openWIFISetting().then((_) async {
+      //         final proxy = await SystemProxy.getProxySettings();
+      //         debugPrint("$proxy");
+      //       });
+      //     }
+      //   },
+      // );
+      // Get.dialog(dialog);
+    }
+  }
+  void getProxies() {
+    final proxiesPtr = clashFFI.get_proxies().cast<Utf8>();
+    proxies.value = json.decode(proxiesPtr.toDartString());
+    // malloc.free(proxiesPtr);
+  }
+
+  bool isSystemProxy() {
+    return SpUtil.getData('system_proxy', defValue: false);
+  }
+
+  Future<bool> setIsSystemProxy(bool proxy) {
+    isSystemProxyObs.value = proxy;
+    return SpUtil.setData('system_proxy', proxy);
+  }
+
+
+
+  void checkPort() {
+    if (configEntity.value != null) {
+      if (configEntity.value!.port == 0) {
+        changeConfigField('port', initializedHttpPort);
+      }
+      if (configEntity.value!.mixedPort == 0) {
+        changeConfigField('mixed-port', initializedMixedPort);
+      }
+      if (configEntity.value!.socksPort == 0) {
+        changeConfigField('socks-port', initializedSockPort);
+      }
+      updateTray();
+    }
+  }
+  //切换配置
+  bool changeConfigField(String field, dynamic value) {
+    try {
+      int ret = clashFFI.change_config_field(
+          json.encode(<String, dynamic>{field: value}).toNativeUtf8().cast());
+      return ret == 0;
+    } finally {
+      getCurrentClashConfig();
+      if (field.endsWith("port") && isSystemProxy()) {
+        setSystemProxy();
+      }
+    }
+  }
+
+  Future<void> _acquireLock(Directory clashDirectory) async {
+    final path = p.join(clashDirectory.path, "fclash.lock");
+    final lockFile = File(path);
+    if (!lockFile.existsSync()) {
+      lockFile.createSync(recursive: true);
+    }
+    try {
+      _clashLock = await lockFile.open(mode: FileMode.write);
+      await _clashLock?.lock();
+    } catch (e) {
+      // if (!Platform.isWindows) {
+      //   await Get.find<NotificationService>()
+      //       .showNotification("Fclash", "Already running, Now exit.".tr);
+      // }
+      exit(0);
+    }
+  }
+  ReceivePort? _logReceivePort;
+
+  void startLogging() {
+    _logReceivePort?.close();
+    _logReceivePort = ReceivePort();
+    logStream = _logReceivePort!.asBroadcastStream();
+    if (kDebugMode) {
+      logStream?.listen((event) {
+        debugPrint("LOG: ${event}");
+      });
+    }
+    final nativePort = _logReceivePort!.sendPort.nativePort;
+    debugPrint("port: $nativePort");
+    clashFFI.start_log(nativePort);
+  }
+  void stopLog() {
+    logStream = null;
+    clashFFI.stop_log();
+  }
+  void updateTray() {
+    if (!isDesktop) {
+      return;
+    }
+    final stringList = List<MenuItem>.empty(growable: true);
+    // yaml
+    stringList
+        .add(MenuItem(label: "profile: ${currentYaml.value}", disabled: true));
+    if (proxies['proxies'] != null) {
+      Map<String, dynamic> m = proxies['proxies'];
+      m.removeWhere((key, value) => value['type'] != "Selector");
+      var cnt = 0;
+      for (final k in m.keys) {
+        if (cnt >= ClashService.MAX_ENTRIES) {
+          stringList.add(MenuItem(label: "...", disabled: true));
+          break;
+        }
+        stringList.add(
+            MenuItem(label: "${m[k]['name']}: ${m[k]['now']}", disabled: true));
+        cnt += 1;
+      }
+    }
+    // port
+    if (configEntity.value != null) {
+      stringList.add(
+          MenuItem(label: 'http: ${configEntity.value?.port}', disabled: true));
+      stringList.add(MenuItem(
+          label: 'socks: ${configEntity.value?.socksPort}', disabled: true));
+    }
+    // system proxy
+    stringList.add(MenuItem.separator());
+    if (!isSystemProxy()) {
+      stringList
+          .add(MenuItem(label: "Not system proxy yet.".tr, disabled: true));
+      stringList.add(MenuItem(
+          label: "Set as system proxy".tr,
+          toolTip: "click to set fclash as system proxy".tr,
+          key: ACTION_SET_SYSTEM_PROXY));
+    } else {
+      stringList.add(MenuItem(label: "System proxy now.".tr, disabled: true));
+      stringList.add(MenuItem(
+          label: "Unset system proxy".tr,
+          toolTip: "click to reset system proxy",
+          key: ACTION_UNSET_SYSTEM_PROXY));
+      stringList.add(MenuItem.separator());
+    }
+
+    initAppTray(details: stringList, isUpdate: true);
+  }
+
+  Future<bool> _changeConfig(FileSystemEntity config) async {
+    // check if it has `rule-set`, and try to convert it
+    final content = await convertConfig(await File(config.path).readAsString())
+        .catchError((e) {
+      printError(info: e);
+    });
+    if (content.isNotEmpty) {
+      await File(config.path).writeAsString(content);
+    }
+    // judge valid
+    if (clashFFI.is_config_valid(config.path.toNativeUtf8().cast()) == 0) {
+      final resp = await Request.dioClient.put('/configs',
+          queryParameters: {"force": false}, data: {"path": config.path});
+      Get.printInfo(info: 'config changed ret: ${resp.statusCode}');
+      currentYaml.value = basename(config.path);
+      SpUtil.setData('yaml', currentYaml.value);
+      return resp.statusCode == 204;
+    } else {
+      Future.delayed(Duration.zero, () {
+        Get.defaultDialog(
+            middleText: 'not a valid config file'.tr,
+            onConfirm: () {
+              Get.back();
+            });
+      });
+      config.delete();
+      return false;
+    }
+  }
+
+  //切换配置文件
+  Future<bool> changeYaml(FileSystemEntity config) async {
+    try {
+      if (await config.exists()) {
+        return await _changeConfig(config);
+      } else {
+        return false;
+      }
+    } finally {
+      reload();
+    }
+  }
+
+  bool changeProxy(String selectName, String proxyName) {
+    final ret = clashFFI.change_proxy(
+        selectName.toNativeUtf8().cast(), proxyName.toNativeUtf8().cast());
+    if (ret == 0) {
+      reload();
+    }
+    return ret == 0;
+  }
+}
+
+Future<String> convertConfig(String content) async {
+  return "";
+}

+ 328 - 52
lib/clash_generated_bindings.dart

@@ -4,97 +4,266 @@
 // ignore_for_file: type=lint
 import 'dart:ffi' as ffi;
 
-class Clash {
+class NativeLibrary {
   /// Holds the symbol lookup function.
   final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
       _lookup;
 
   /// The symbols are looked up in [dynamicLibrary].
-  Clash(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
+  NativeLibrary(ffi.DynamicLibrary dynamicLibrary)
+      : _lookup = dynamicLibrary.lookup;
 
   /// The symbols are looked up with [lookup].
-  Clash.fromLookup(
+  NativeLibrary.fromLookup(
       ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
           lookup)
       : _lookup = lookup;
 
-  int setHomeDir(
-    ffi.Pointer<ffi.Char> homeStr,
+  int clash_init(
+    ffi.Pointer<ffi.Char> home_dir,
   ) {
-    return _setHomeDir(
-      homeStr,
+    return _clash_init(
+      home_dir,
     );
   }
 
-  late final _setHomeDirPtr =
-      _lookup<ffi.NativeFunction<GoUint8 Function(ffi.Pointer<ffi.Char>)>>(
-          'setHomeDir');
-  late final _setHomeDir =
-      _setHomeDirPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+  late final _clash_initPtr =
+      _lookup<ffi.NativeFunction<GoInt Function(ffi.Pointer<ffi.Char>)>>(
+          'clash_init');
+  late final _clash_init =
+      _clash_initPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
 
-  int setConfig(
-    ffi.Pointer<ffi.Char> configStr,
+  int set_config(
+    ffi.Pointer<ffi.Char> config_path,
   ) {
-    return _setConfig(
-      configStr,
+    return _set_config(
+      config_path,
     );
   }
 
-  late final _setConfigPtr =
-      _lookup<ffi.NativeFunction<GoUint8 Function(ffi.Pointer<ffi.Char>)>>(
-          'setConfig');
-  late final _setConfig =
-      _setConfigPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+  late final _set_configPtr =
+      _lookup<ffi.NativeFunction<GoInt Function(ffi.Pointer<ffi.Char>)>>(
+          'set_config');
+  late final _set_config =
+      _set_configPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
 
-  void withExternalController(
-    ffi.Pointer<ffi.Char> externalController,
+  int set_home_dir(
+    ffi.Pointer<ffi.Char> home,
   ) {
-    return _withExternalController(
-      externalController,
+    return _set_home_dir(
+      home,
     );
   }
 
-  late final _withExternalControllerPtr =
-      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>(
-          'withExternalController');
-  late final _withExternalController = _withExternalControllerPtr
-      .asFunction<void Function(ffi.Pointer<ffi.Char>)>();
+  late final _set_home_dirPtr =
+      _lookup<ffi.NativeFunction<GoInt Function(ffi.Pointer<ffi.Char>)>>(
+          'set_home_dir');
+  late final _set_home_dir =
+      _set_home_dirPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+
+  ffi.Pointer<ffi.Char> get_config() {
+    return _get_config();
+  }
 
-  void withSecret(
-    ffi.Pointer<ffi.Char> secret,
+  late final _get_configPtr =
+      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
+          'get_config');
+  late final _get_config =
+      _get_configPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
+
+  int set_ext_controller(
+    int port,
   ) {
-    return _withSecret(
-      secret,
+    return _set_ext_controller(
+      port,
     );
   }
 
-  late final _withSecretPtr =
-      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>(
-          'withSecret');
-  late final _withSecret =
-      _withSecretPtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>();
+  late final _set_ext_controllerPtr =
+      _lookup<ffi.NativeFunction<GoInt Function(GoUint64)>>(
+          'set_ext_controller');
+  late final _set_ext_controller =
+      _set_ext_controllerPtr.asFunction<int Function(int)>();
+
+  void clear_ext_options() {
+    return _clear_ext_options();
+  }
+
+  late final _clear_ext_optionsPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function()>>('clear_ext_options');
+  late final _clear_ext_options =
+      _clear_ext_optionsPtr.asFunction<void Function()>();
 
-  int mmdbVerify(
-    ffi.Pointer<ffi.Char> path,
+  int is_config_valid(
+    ffi.Pointer<ffi.Char> config_path,
   ) {
-    return _mmdbVerify(
-      path,
+    return _is_config_valid(
+      config_path,
     );
   }
 
-  late final _mmdbVerifyPtr =
+  late final _is_config_validPtr =
+      _lookup<ffi.NativeFunction<GoInt Function(ffi.Pointer<ffi.Char>)>>(
+          'is_config_valid');
+  late final _is_config_valid =
+      _is_config_validPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+
+  ffi.Pointer<ffi.Char> get_all_connections() {
+    return _get_all_connections();
+  }
+
+  late final _get_all_connectionsPtr =
+      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
+          'get_all_connections');
+  late final _get_all_connections =
+      _get_all_connectionsPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
+
+  void close_all_connections() {
+    return _close_all_connections();
+  }
+
+  late final _close_all_connectionsPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function()>>('close_all_connections');
+  late final _close_all_connections =
+      _close_all_connectionsPtr.asFunction<void Function()>();
+
+  int close_connection(
+    ffi.Pointer<ffi.Char> id,
+  ) {
+    return _close_connection(
+      id,
+    );
+  }
+
+  late final _close_connectionPtr =
       _lookup<ffi.NativeFunction<GoUint8 Function(ffi.Pointer<ffi.Char>)>>(
-          'mmdbVerify');
-  late final _mmdbVerify =
-      _mmdbVerifyPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+          'close_connection');
+  late final _close_connection =
+      _close_connectionPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+
+  int parse_options() {
+    return _parse_options();
+  }
+
+  late final _parse_optionsPtr =
+      _lookup<ffi.NativeFunction<GoUint8 Function()>>('parse_options');
+  late final _parse_options = _parse_optionsPtr.asFunction<int Function()>();
+
+  ffi.Pointer<ffi.Char> get_traffic() {
+    return _get_traffic();
+  }
+
+  late final _get_trafficPtr =
+      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
+          'get_traffic');
+  late final _get_traffic =
+      _get_trafficPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
+
+  void init_native_api_bridge(
+    ffi.Pointer<ffi.Void> api,
+  ) {
+    return _init_native_api_bridge(
+      api,
+    );
+  }
+
+  late final _init_native_api_bridgePtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
+          'init_native_api_bridge');
+  late final _init_native_api_bridge = _init_native_api_bridgePtr
+      .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
+
+  void start_log(
+    int port,
+  ) {
+    return _start_log(
+      port,
+    );
+  }
+
+  late final _start_logPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.LongLong)>>('start_log');
+  late final _start_log = _start_logPtr.asFunction<void Function(int)>();
+
+  void stop_log() {
+    return _stop_log();
+  }
+
+  late final _stop_logPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function()>>('stop_log');
+  late final _stop_log = _stop_logPtr.asFunction<void Function()>();
+
+  int change_proxy(
+    ffi.Pointer<ffi.Char> selector_name,
+    ffi.Pointer<ffi.Char> proxy_name,
+  ) {
+    return _change_proxy(
+      selector_name,
+      proxy_name,
+    );
+  }
+
+  late final _change_proxyPtr = _lookup<
+      ffi.NativeFunction<
+          ffi.Long Function(
+              ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>)>>('change_proxy');
+  late final _change_proxy = _change_proxyPtr
+      .asFunction<int Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>)>();
+
+  int change_config_field(
+    ffi.Pointer<ffi.Char> s,
+  ) {
+    return _change_config_field(
+      s,
+    );
+  }
+
+  late final _change_config_fieldPtr =
+      _lookup<ffi.NativeFunction<ffi.Long Function(ffi.Pointer<ffi.Char>)>>(
+          'change_config_field');
+  late final _change_config_field =
+      _change_config_fieldPtr.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
+
+  void async_test_delay(
+    ffi.Pointer<ffi.Char> proxy_name,
+    ffi.Pointer<ffi.Char> url,
+    int timeout,
+    int port,
+  ) {
+    return _async_test_delay(
+      proxy_name,
+      url,
+      timeout,
+      port,
+    );
+  }
+
+  late final _async_test_delayPtr = _lookup<
+      ffi.NativeFunction<
+          ffi.Void Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>,
+              ffi.Long, ffi.LongLong)>>('async_test_delay');
+  late final _async_test_delay = _async_test_delayPtr.asFunction<
+      void Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, int, int)>();
+
+  ffi.Pointer<ffi.Char> get_proxies() {
+    return _get_proxies();
+  }
 
-  int startService() {
-    return _startService();
+  late final _get_proxiesPtr =
+      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
+          'get_proxies');
+  late final _get_proxies =
+      _get_proxiesPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
+
+  ffi.Pointer<ffi.Char> get_configs() {
+    return _get_configs();
   }
 
-  late final _startServicePtr =
-      _lookup<ffi.NativeFunction<GoUint8 Function()>>('startService');
-  late final _startService = _startServicePtr.asFunction<int Function()>();
+  late final _get_configsPtr =
+      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
+          'get_configs');
+  late final _get_configs =
+      _get_configsPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
 }
 
 final class __mbstate_t extends ffi.Union {
@@ -217,6 +386,7 @@ final class GoSlice extends ffi.Struct {
 
 typedef GoInt = GoInt64;
 typedef GoInt64 = ffi.LongLong;
+typedef GoUint64 = ffi.UnsignedLongLong;
 typedef GoUint8 = ffi.UnsignedChar;
 
 const int __DARWIN_ONLY_64_BIT_INO_T = 1;
@@ -288,3 +458,109 @@ const int _FORTIFY_SOURCE = 2;
 const int NULL = 0;
 
 const int USER_ADDR_NULL = 0;
+
+const int __WORDSIZE = 64;
+
+const int INT8_MAX = 127;
+
+const int INT16_MAX = 32767;
+
+const int INT32_MAX = 2147483647;
+
+const int INT64_MAX = 9223372036854775807;
+
+const int INT8_MIN = -128;
+
+const int INT16_MIN = -32768;
+
+const int INT32_MIN = -2147483648;
+
+const int INT64_MIN = -9223372036854775808;
+
+const int UINT8_MAX = 255;
+
+const int UINT16_MAX = 65535;
+
+const int UINT32_MAX = 4294967295;
+
+const int UINT64_MAX = -1;
+
+const int INT_LEAST8_MIN = -128;
+
+const int INT_LEAST16_MIN = -32768;
+
+const int INT_LEAST32_MIN = -2147483648;
+
+const int INT_LEAST64_MIN = -9223372036854775808;
+
+const int INT_LEAST8_MAX = 127;
+
+const int INT_LEAST16_MAX = 32767;
+
+const int INT_LEAST32_MAX = 2147483647;
+
+const int INT_LEAST64_MAX = 9223372036854775807;
+
+const int UINT_LEAST8_MAX = 255;
+
+const int UINT_LEAST16_MAX = 65535;
+
+const int UINT_LEAST32_MAX = 4294967295;
+
+const int UINT_LEAST64_MAX = -1;
+
+const int INT_FAST8_MIN = -128;
+
+const int INT_FAST16_MIN = -32768;
+
+const int INT_FAST32_MIN = -2147483648;
+
+const int INT_FAST64_MIN = -9223372036854775808;
+
+const int INT_FAST8_MAX = 127;
+
+const int INT_FAST16_MAX = 32767;
+
+const int INT_FAST32_MAX = 2147483647;
+
+const int INT_FAST64_MAX = 9223372036854775807;
+
+const int UINT_FAST8_MAX = 255;
+
+const int UINT_FAST16_MAX = 65535;
+
+const int UINT_FAST32_MAX = 4294967295;
+
+const int UINT_FAST64_MAX = -1;
+
+const int INTPTR_MAX = 9223372036854775807;
+
+const int INTPTR_MIN = -9223372036854775808;
+
+const int UINTPTR_MAX = -1;
+
+const int INTMAX_MAX = 9223372036854775807;
+
+const int UINTMAX_MAX = -1;
+
+const int INTMAX_MIN = -9223372036854775808;
+
+const int PTRDIFF_MIN = -9223372036854775808;
+
+const int PTRDIFF_MAX = 9223372036854775807;
+
+const int SIZE_MAX = -1;
+
+const int RSIZE_MAX = 9223372036854775807;
+
+const int WCHAR_MAX = 2147483647;
+
+const int WCHAR_MIN = -2147483648;
+
+const int WINT_MIN = -2147483648;
+
+const int WINT_MAX = 2147483647;
+
+const int SIG_ATOMIC_MIN = -2147483648;
+
+const int SIG_ATOMIC_MAX = 2147483647;

+ 82 - 20
lib/main.dart

@@ -6,13 +6,28 @@ import 'package:dart_json_mapper/dart_json_mapper.dart';
 import 'package:flutter/material.dart';
 
 import 'package:get/get.dart';
+import 'package:kommon/tool/sp_util.dart';
+import 'package:proxy_manager/proxy_manager.dart';
+import 'package:tray_manager/tray_manager.dart';
 import 'package:window_manager/window_manager.dart';
 
 import 'app/routes/app_pages.dart';
+import 'app/service/clash_service.dart';
 import 'main.mapper.g.dart' show initializeJsonMapper;
+
+final proxyManager = ProxyManager();
+final isDesktop = GetPlatform.isDesktop;
+
 void main() async {
-  const width = 375.0;
-  const height = 736.0;
+  WidgetsFlutterBinding.ensureInitialized();
+  if (isDesktop) {
+    await Future.wait([
+      Future.microtask(() async {
+        await windowManager.ensureInitialized();
+        await windowManager.setPreventClose(true);
+      })
+    ]);
+  }
   initializeJsonMapper();
   JsonMapper().useAdapter(JsonMapperAdapter(valueDecorators: {
     typeOf<Map<String, String>>(): (value) {
@@ -20,24 +35,6 @@ void main() async {
     },
   }));
 
-  if(Platform.isWindows || Platform.isMacOS){
-    WidgetsFlutterBinding.ensureInitialized();
-    await windowManager.ensureInitialized();
-    WindowOptions windowOptions = const WindowOptions(
-      minimumSize: Size(width, height),
-      maximumSize: Size(width, height - kToolbarHeight),
-      size: Size(width, height),
-      center: true,
-      backgroundColor: Colors.transparent,
-      skipTaskbar: false,
-      titleBarStyle: TitleBarStyle.hidden,
-    );
-
-    await windowManager.waitUntilReadyToShow(windowOptions, () async {
-      await windowManager.show();
-      await windowManager.focus();
-    });
-  }
   const Set<PointerDeviceKind> kTouchLikeDeviceTypes = <PointerDeviceKind>{
     PointerDeviceKind.touch,
     PointerDeviceKind.mouse,
@@ -45,6 +42,9 @@ void main() async {
     PointerDeviceKind.invertedStylus,
     PointerDeviceKind.unknown
   };
+
+  await initAppService();
+
   runApp(
     GetMaterialApp(
       scrollBehavior: const MaterialScrollBehavior().copyWith(
@@ -54,6 +54,68 @@ void main() async {
       title: "Application",
       initialRoute: AppPages.INITIAL,
       getPages: AppPages.routes,
+
     ),
   );
+
+  if (isDesktop) {
+    initWindow();
+  }
+
 }
+
+Future<void> initWindow() async {
+  const width = 375.0;
+  const height = 736.0;
+
+  WindowOptions opts = const WindowOptions(
+    minimumSize: Size(width, height),
+    maximumSize: Size(width, height - kToolbarHeight),
+    size: Size(width, height),
+    center: true,
+    backgroundColor: Colors.transparent,
+    skipTaskbar: true,
+    titleBarStyle: TitleBarStyle.hidden,
+  );
+  windowManager.waitUntilReadyToShow(opts, () {
+    // hide window when start
+    // if (Get.find<ClashService>().isHideWindowWhenStart() && kReleaseMode) {
+    //   windowManager.hide();
+    // }
+    //windowManager.show();
+    // windowManager.focus();
+  });
+}
+
+
+Future<void> initAppService() async {
+  await SpUtil.getInstance();
+  await Get.putAsync(() => ClashService().init());
+  if (isDesktop) {
+    // await Get.putAsync(() => AutostartService().init());
+  }
+  //Get.put(ThemeController());
+}
+
+Future<void> initAppTray(
+    {List<MenuItem>? details, bool isUpdate = false}) async {
+  await trayManager.setIcon(Platform.isWindows
+      ? 'assets/images/logo/logo.ico'
+      : 'assets/images/logo/logo.png');
+
+  List<MenuItem> items = [
+    MenuItem(
+      key: 'show',
+      label: 'Show Fclash'.tr,
+    ),
+    MenuItem.separator(),
+    MenuItem(
+      key: 'exit',
+      label: 'Exit Fclash'.tr,
+    ),
+  ];
+  if (details != null) {
+    items.insertAll(0, details);
+  }
+  await trayManager.setContextMenu(Menu(items: items));
+}

+ 12 - 0
linux/flutter/generated_plugin_registrant.cc

@@ -6,18 +6,30 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <file_selector_linux/file_selector_plugin.h>
 #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
+#include <proxy_manager/proxy_manager_plugin.h>
 #include <screen_retriever/screen_retriever_plugin.h>
+#include <tray_manager/tray_manager_plugin.h>
 #include <url_launcher_linux/url_launcher_plugin.h>
 #include <window_manager/window_manager_plugin.h>
 
 void fl_register_plugins(FlPluginRegistry* registry) {
+  g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
+  file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
   g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
   flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
+  g_autoptr(FlPluginRegistrar) proxy_manager_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "ProxyManagerPlugin");
+  proxy_manager_plugin_register_with_registrar(proxy_manager_registrar);
   g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
   screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
+  g_autoptr(FlPluginRegistrar) tray_manager_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin");
+  tray_manager_plugin_register_with_registrar(tray_manager_registrar);
   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

+ 3 - 0
linux/flutter/generated_plugins.cmake

@@ -3,8 +3,11 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  file_selector_linux
   flutter_secure_storage_linux
+  proxy_manager
   screen_retriever
+  tray_manager
   url_launcher_linux
   window_manager
 )

+ 8 - 0
macos/Flutter/GeneratedPluginRegistrant.swift

@@ -6,19 +6,27 @@ import FlutterMacOS
 import Foundation
 
 import connectivity_plus_macos
+import file_selector_macos
 import flutter_secure_storage_macos
 import path_provider_foundation
+import proxy_manager
 import screen_retriever
 import shared_preferences_foundation
+import sqflite
+import tray_manager
 import url_launcher_macos
 import window_manager
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
+  FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
   FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin"))
   PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+  ProxyManagerPlugin.register(with: registry.registrar(forPlugin: "ProxyManagerPlugin"))
   ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
+  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
+  TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
   WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
 }

+ 30 - 0
macos/Podfile.lock

@@ -2,18 +2,30 @@ PODS:
   - connectivity_plus_macos (0.0.1):
     - FlutterMacOS
     - ReachabilitySwift
+  - file_selector_macos (0.0.1):
+    - FlutterMacOS
   - flutter_secure_storage_macos (3.3.1):
     - FlutterMacOS
   - FlutterMacOS (1.0.0)
+  - FMDB (2.7.5):
+    - FMDB/standard (= 2.7.5)
+  - FMDB/standard (2.7.5)
   - path_provider_foundation (0.0.1):
     - Flutter
     - FlutterMacOS
+  - proxy_manager (0.0.1):
+    - FlutterMacOS
   - ReachabilitySwift (5.0.0)
   - screen_retriever (0.0.1):
     - FlutterMacOS
   - shared_preferences_foundation (0.0.1):
     - Flutter
     - FlutterMacOS
+  - sqflite (0.0.2):
+    - FlutterMacOS
+    - FMDB (>= 2.7.5)
+  - tray_manager (0.0.1):
+    - FlutterMacOS
   - url_launcher_macos (0.0.1):
     - FlutterMacOS
   - window_manager (0.2.0):
@@ -21,31 +33,44 @@ PODS:
 
 DEPENDENCIES:
   - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`)
+  - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
   - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
   - FlutterMacOS (from `Flutter/ephemeral`)
   - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
+  - proxy_manager (from `Flutter/ephemeral/.symlinks/plugins/proxy_manager/macos`)
   - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
   - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
+  - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
+  - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`)
   - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
   - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
 
 SPEC REPOS:
   trunk:
+    - FMDB
     - ReachabilitySwift
 
 EXTERNAL SOURCES:
   connectivity_plus_macos:
     :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos
+  file_selector_macos:
+    :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
   flutter_secure_storage_macos:
     :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
   FlutterMacOS:
     :path: Flutter/ephemeral
   path_provider_foundation:
     :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
+  proxy_manager:
+    :path: Flutter/ephemeral/.symlinks/plugins/proxy_manager/macos
   screen_retriever:
     :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
   shared_preferences_foundation:
     :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
+  sqflite:
+    :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
+  tray_manager:
+    :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos
   url_launcher_macos:
     :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
   window_manager:
@@ -53,12 +78,17 @@ EXTERNAL SOURCES:
 
 SPEC CHECKSUMS:
   connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308
+  file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
   flutter_secure_storage_macos: 6ceee8fbc7f484553ad17f79361b556259df89aa
   FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
+  FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
   path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
+  proxy_manager: 542f2521a9ade938bfdd8a2ff566d95515fa7f2c
   ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
   screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
   shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
+  sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
+  tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
   url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
   window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
 

+ 14 - 4
macos/Runner.xcodeproj/project.pbxproj

@@ -27,7 +27,8 @@
 		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
 		33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
 		33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
-		3B5D091F2AD913BB0057E569 /* libclash.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 3B5D091E2AD913BB0057E569 /* libclash.dylib */; };
+		3B5A16BB2ADD14A2002F295B /* libclash.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 3B5A16BA2ADD14A2002F295B /* libclash.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+		3B5A16BC2ADD1937002F295B /* libclash.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B5A16B82ADD1496002F295B /* libclash.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
 		8444AE800248F37BB8ABF637 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F397D2CB6412D720D523E30C /* Pods_Runner.framework */; };
 		CC6EB3AF67BFAAA84BB25D80 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AC0DF046605705B6C85E2E2 /* Pods_RunnerTests.framework */; };
 /* End PBXBuildFile section */
@@ -56,6 +57,7 @@
 			dstPath = "";
 			dstSubfolderSpec = 10;
 			files = (
+				3B5A16BB2ADD14A2002F295B /* libclash.dylib in Bundle Framework */,
 			);
 			name = "Bundle Framework";
 			runOnlyForDeploymentPostprocessing = 0;
@@ -82,7 +84,8 @@
 		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
 		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
 		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
-		3B5D091E2AD913BB0057E569 /* libclash.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libclash.dylib; path = Frameworks/libclash.dylib; sourceTree = "<group>"; };
+		3B5A16B82ADD1496002F295B /* libclash.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libclash.dylib; path = ../core/libclash.dylib; sourceTree = "<group>"; };
+		3B5A16BA2ADD14A2002F295B /* libclash.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libclash.dylib; path = ../core/libclash.dylib; sourceTree = "<group>"; };
 		75F24307BAD49042829F2A60 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
@@ -105,6 +108,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				3B5A16BC2ADD1937002F295B /* libclash.dylib in Frameworks */,
 				8444AE800248F37BB8ABF637 /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -134,7 +138,7 @@
 		33CC10E42044A3C60003C045 = {
 			isa = PBXGroup;
 			children = (
-				3B5D091E2AD913BB0057E569 /* libclash.dylib */,
+				3B5A16BA2ADD14A2002F295B /* libclash.dylib */,
 				33FAB671232836740065AC1E /* Runner */,
 				33CEB47122A05771004F2AC0 /* Flutter */,
 				331C80D6294CF71000263BE5 /* RunnerTests */,
@@ -204,6 +208,7 @@
 		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				3B5A16B82ADD1496002F295B /* libclash.dylib */,
 				F397D2CB6412D720D523E30C /* Pods_Runner.framework */,
 				0AC0DF046605705B6C85E2E2 /* Pods_RunnerTests.framework */,
 			);
@@ -318,7 +323,6 @@
 			files = (
 				33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
 				33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
-				3B5D091F2AD913BB0057E569 /* libclash.dylib in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -578,10 +582,12 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/../Frameworks",
+					../core,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Frameworks",
+					../core,
 				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
@@ -709,10 +715,12 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/../Frameworks",
+					../core,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Frameworks",
+					../core,
 				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -734,10 +742,12 @@
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/../Frameworks",
+					../core,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Frameworks",
+					../core,
 				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;

+ 17 - 1
macos/Runner/AppDelegate.swift

@@ -4,6 +4,22 @@ import FlutterMacOS
 @NSApplicationMain
 class AppDelegate: FlutterAppDelegate {
   override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
-    return true
+    return false
   }
+
+    override func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool)
+      -> Bool
+    {
+      if !flag {
+        for window in NSApp.windows {
+          if !window.isVisible {
+            window.setIsVisible(true)
+          }
+          window.makeKeyAndOrderFront(self)
+          NSApp.activate(ignoringOtherApps: true)
+        }
+      }
+      return true
+    }
+
 }

+ 25 - 19
pubspec.yaml

@@ -6,6 +6,8 @@ environment:
   sdk: '>=3.1.1 <4.0.0'
 
 dependencies:
+  tray_manager: ^0.2.0
+  proxy_manager: ^0.0.3
   shared_preferences: ^2.0.10
   cupertino_icons: ^1.0.2
   window_manager: ^0.3.6
@@ -23,7 +25,7 @@ dependencies:
   dart_json_mapper: ^2.2.7
   url_launcher: ^6.1.11
   path_provider: ^2.0.11
-
+  kommon: ^0.4.1
 
 dev_dependencies: 
   flutter_lints: ^2.0.0
@@ -31,29 +33,33 @@ dev_dependencies:
     sdk: flutter
   ffigen: any
   build_runner: ^2.4.4
-flutter: 
-  assets: 
-    - images/login/login.png
-    - images/main/main.png
-    - images/main/refresh.png
-    - images/main/userstatus.png
-    - images/main/userstatusoff.png
-    - images/main/customer.png
-    - images/main/promotion.png
-    - images/main/tutorial.png
-    - images/main/renewal.png
-    - images/main/disconnected.gif
-    - images/main/connecting.gif
-    - images/main/stopped.gif
-    - images/node/nodebg.png
-    - images/node/nodetablebg.png
+flutter:
+  assets:
+    - assets/tp/clash/
+    - assets/images/login/
+    - assets/images/main/
+    - assets/images/node/
+    - assets/images/logo/
+#    - images/login/login.png
+#    - images/main/main.png
+#    - images/main/refresh.png
+#    - images/main/userstatus.png
+#    - images/main/userstatusoff.png
+#    - images/main/customer.png
+#    - images/main/promotion.png
+#    - images/main/tutorial.png
+#    - images/main/renewal.png
+#    - images/main/disconnected.gif
+#    - images/main/connecting.gif
+#    - images/main/stopped.gif
+#    - images/node/nodebg.png
+#    - images/node/nodetablebg.png
   uses-material-design: true
 
 ffigen:
-  name: "Clash"
   output: 'lib/clash_generated_bindings.dart'
   headers:
     entry-points:
-      - 'core/dist/libclash.h'
+      - 'core/libclash.h'
 #  llvm-path:
 #    - 'C:/Users/Casbin/Scoop/apps/llvm/current'

+ 12 - 0
windows/flutter/generated_plugin_registrant.cc

@@ -7,18 +7,30 @@
 #include "generated_plugin_registrant.h"
 
 #include <connectivity_plus_windows/connectivity_plus_windows_plugin.h>
+#include <file_selector_windows/file_selector_windows.h>
 #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
+#include <permission_handler_windows/permission_handler_windows_plugin.h>
+#include <proxy_manager/proxy_manager_plugin.h>
 #include <screen_retriever/screen_retriever_plugin.h>
+#include <tray_manager/tray_manager_plugin.h>
 #include <url_launcher_windows/url_launcher_windows.h>
 #include <window_manager/window_manager_plugin.h>
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
   ConnectivityPlusWindowsPluginRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
+  FileSelectorWindowsRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("FileSelectorWindows"));
   FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
+  PermissionHandlerWindowsPluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
+  ProxyManagerPluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("ProxyManagerPlugin"));
   ScreenRetrieverPluginRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
+  TrayManagerPluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("TrayManagerPlugin"));
   UrlLauncherWindowsRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("UrlLauncherWindows"));
   WindowManagerPluginRegisterWithRegistrar(

+ 4 - 0
windows/flutter/generated_plugins.cmake

@@ -4,8 +4,12 @@
 
 list(APPEND FLUTTER_PLUGIN_LIST
   connectivity_plus_windows
+  file_selector_windows
   flutter_secure_storage_windows
+  permission_handler_windows
+  proxy_manager
   screen_retriever
+  tray_manager
   url_launcher_windows
   window_manager
 )