Initial commit
This commit is contained in:
1
plugins/flutter_distributor
Submodule
1
plugins/flutter_distributor
Submodule
Submodule plugins/flutter_distributor added at e31c994e67
30
plugins/proxy/.gitignore
vendored
Normal file
30
plugins/proxy/.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
33
plugins/proxy/.metadata
Normal file
33
plugins/proxy/.metadata
Normal file
@@ -0,0 +1,33 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "e1e47221e86272429674bec4f1bd36acc4fc7b77"
|
||||
channel: "stable"
|
||||
|
||||
project_type: plugin
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
base_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
- platform: android
|
||||
create_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
base_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
- platform: windows
|
||||
create_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
base_revision: e1e47221e86272429674bec4f1bd36acc4fc7b77
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
3
plugins/proxy/CHANGELOG.md
Normal file
3
plugins/proxy/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
||||
1
plugins/proxy/LICENSE
Normal file
1
plugins/proxy/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
15
plugins/proxy/README.md
Normal file
15
plugins/proxy/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# proxy
|
||||
|
||||
A new Flutter plugin project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter
|
||||
[plug-in package](https://flutter.dev/developing-packages/),
|
||||
a specialized package that includes platform-specific implementation code for
|
||||
Android and/or iOS.
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
|
||||
4
plugins/proxy/analysis_options.yaml
Normal file
4
plugins/proxy/analysis_options.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
208
plugins/proxy/lib/proxy.dart
Normal file
208
plugins/proxy/lib/proxy.dart
Normal file
@@ -0,0 +1,208 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'proxy_platform_interface.dart';
|
||||
import "package:path/path.dart";
|
||||
|
||||
enum ProxyTypes { http, https, socks }
|
||||
|
||||
class Proxy extends ProxyPlatform {
|
||||
static String url = "127.0.0.1";
|
||||
|
||||
@override
|
||||
Future<bool?> startProxy(int port, String? args) async {
|
||||
bool? isStart = false;
|
||||
switch (Platform.operatingSystem) {
|
||||
case "macos":
|
||||
isStart = await _startProxyWithMacos(port);
|
||||
break;
|
||||
case "linux":
|
||||
isStart = await _startProxyWithLinux(port);
|
||||
break;
|
||||
case "windows":
|
||||
isStart = await ProxyPlatform.instance.startProxy(port, args);
|
||||
break;
|
||||
}
|
||||
if (isStart == true) {
|
||||
startTime = DateTime.now();
|
||||
}
|
||||
return isStart;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool?> stopProxy() async {
|
||||
bool? isStop = false;
|
||||
switch (Platform.operatingSystem) {
|
||||
case "macos":
|
||||
isStop = await _stopProxyWithMacos();
|
||||
break;
|
||||
case "linux":
|
||||
isStop = await _stopProxyWithLinux();
|
||||
break;
|
||||
case "windows":
|
||||
isStop = await ProxyPlatform.instance.stopProxy();
|
||||
break;
|
||||
}
|
||||
if (isStop == true) {
|
||||
startTime = null;
|
||||
}
|
||||
return isStop;
|
||||
}
|
||||
|
||||
@override
|
||||
get startTime => ProxyPlatform.instance.startTime;
|
||||
|
||||
@override
|
||||
set startTime(DateTime? dateTime) {
|
||||
ProxyPlatform.instance.startTime = dateTime;
|
||||
}
|
||||
|
||||
Future<bool> _startProxyWithLinux(int port) async {
|
||||
try {
|
||||
final homeDir = Platform.environment['HOME']!;
|
||||
final configDir = join(homeDir, ".config");
|
||||
final cmdList = List<List<String>>.empty(growable: true);
|
||||
final desktop = Platform.environment['XDG_CURRENT_DESKTOP'];
|
||||
final isKDE = desktop == "KDE";
|
||||
for (final type in ProxyTypes.values) {
|
||||
cmdList.add(
|
||||
["gsettings", "set", "org.gnome.system.proxy", "mode", "manual"],
|
||||
);
|
||||
cmdList.add(
|
||||
[
|
||||
"gsettings",
|
||||
"set",
|
||||
"org.gnome.system.proxy.${type.name}",
|
||||
"host",
|
||||
url
|
||||
],
|
||||
);
|
||||
cmdList.add(
|
||||
[
|
||||
"gsettings",
|
||||
"set",
|
||||
"org.gnome.system.proxy.${type.name}",
|
||||
"port",
|
||||
"$port"
|
||||
],
|
||||
);
|
||||
if (isKDE) {
|
||||
cmdList.add(
|
||||
[
|
||||
"kwriteconfig5",
|
||||
"--file",
|
||||
"$configDir/kioslaverc",
|
||||
"--group",
|
||||
"Proxy Settings",
|
||||
"--key",
|
||||
"ProxyType",
|
||||
"1"
|
||||
],
|
||||
);
|
||||
cmdList.add(
|
||||
[
|
||||
"kwriteconfig5",
|
||||
"--file",
|
||||
"$configDir/kioslaverc",
|
||||
"--group",
|
||||
"Proxy Settings",
|
||||
"--key",
|
||||
"${type.name}Proxy",
|
||||
"${type.name}://$url:$port"
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
for (final cmd in cmdList) {
|
||||
await Process.run(cmd[0], cmd.sublist(1), runInShell: true);
|
||||
}
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _stopProxyWithLinux() async {
|
||||
try {
|
||||
final homeDir = Platform.environment['HOME']!;
|
||||
final configDir = join(homeDir, ".config/");
|
||||
final cmdList = List<List<String>>.empty(growable: true);
|
||||
final desktop = Platform.environment['XDG_CURRENT_DESKTOP'];
|
||||
final isKDE = desktop == "KDE";
|
||||
cmdList
|
||||
.add(["gsettings", "set", "org.gnome.system.proxy", "mode", "none"]);
|
||||
if (isKDE) {
|
||||
cmdList.add([
|
||||
"kwriteconfig5",
|
||||
"--file",
|
||||
"$configDir/kioslaverc",
|
||||
"--group",
|
||||
"Proxy Settings",
|
||||
"--key",
|
||||
"ProxyType",
|
||||
"0"
|
||||
]);
|
||||
}
|
||||
for (final cmd in cmdList) {
|
||||
await Process.run(cmd[0], cmd.sublist(1));
|
||||
}
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _startProxyWithMacos(int port) async {
|
||||
try {
|
||||
final devices = await _getNetworkDeviceListWithMacos();
|
||||
for (final dev in devices) {
|
||||
await Future.wait([
|
||||
Process.run(
|
||||
"/usr/sbin/networksetup", ["-setwebproxystate", dev, "on"]),
|
||||
Process.run(
|
||||
"/usr/sbin/networksetup", ["-setwebproxy", dev, url, "$port"]),
|
||||
Process.run(
|
||||
"/usr/sbin/networksetup", ["-setsecurewebproxystate", dev, "on"]),
|
||||
Process.run("/usr/sbin/networksetup",
|
||||
["-setsecurewebproxy", dev, url, "$port"]),
|
||||
Process.run("/usr/sbin/networksetup",
|
||||
["-setsocksfirewallproxystate", dev, "on"]),
|
||||
Process.run("/usr/sbin/networksetup",
|
||||
["-setsocksfirewallproxy", dev, url, "$port"]),
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _stopProxyWithMacos() async {
|
||||
try {
|
||||
final devices = await _getNetworkDeviceListWithMacos();
|
||||
for (final dev in devices) {
|
||||
await Future.wait([
|
||||
Process.run(
|
||||
"/usr/sbin/networksetup", ["-setautoproxystate", dev, "off"]),
|
||||
Process.run(
|
||||
"/usr/sbin/networksetup", ["-setwebproxystate", dev, "off"]),
|
||||
Process.run("/usr/sbin/networksetup",
|
||||
["-setsecurewebproxystate", dev, "off"]),
|
||||
Process.run("/usr/sbin/networksetup",
|
||||
["-setsocksfirewallproxystate", dev, "off"]),
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<String>> _getNetworkDeviceListWithMacos() async {
|
||||
final res = await Process.run(
|
||||
"/usr/sbin/networksetup", ["-listallnetworkservices"]);
|
||||
final lines = res.stdout.toString().split("\n");
|
||||
lines.removeWhere((element) => element.contains("*"));
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
27
plugins/proxy/lib/proxy_method_channel.dart
Normal file
27
plugins/proxy/lib/proxy_method_channel.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'proxy_platform_interface.dart';
|
||||
|
||||
/// An implementation of [ProxyPlatform] that uses method channels.
|
||||
class MethodChannelProxy extends ProxyPlatform {
|
||||
/// The method channel used to interact with the native platform.
|
||||
@visibleForTesting
|
||||
final methodChannel = const MethodChannel('proxy');
|
||||
|
||||
MethodChannelProxy();
|
||||
|
||||
@override
|
||||
Future<bool?> startProxy(int port, String? args) async {
|
||||
return await methodChannel.invokeMethod<bool>("StartProxy", {'port': port});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool?> stopProxy() async {
|
||||
final isStop = await methodChannel.invokeMethod<bool>("StopProxy");
|
||||
if (isStop == true) {
|
||||
startTime = null;
|
||||
}
|
||||
return isStop;
|
||||
}
|
||||
}
|
||||
32
plugins/proxy/lib/proxy_platform_interface.dart
Normal file
32
plugins/proxy/lib/proxy_platform_interface.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'proxy_method_channel.dart';
|
||||
|
||||
abstract class ProxyPlatform extends PlatformInterface {
|
||||
/// Constructs a ProxyPlatform.
|
||||
ProxyPlatform() : super(token: _token);
|
||||
|
||||
static final Object _token = Object();
|
||||
|
||||
static ProxyPlatform _instance = MethodChannelProxy();
|
||||
|
||||
/// The default instance of [ProxyPlatform] to use.
|
||||
///
|
||||
/// Defaults to [MethodChannelProxy].
|
||||
static ProxyPlatform get instance => _instance;
|
||||
|
||||
static set instance(ProxyPlatform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
DateTime? startTime;
|
||||
|
||||
Future<bool?> startProxy(int port, String? args) {
|
||||
throw UnimplementedError('startProxy() has not been implemented.');
|
||||
}
|
||||
|
||||
Future<bool?> stopProxy() {
|
||||
throw UnimplementedError('stopProxy() has not been implemented.');
|
||||
}
|
||||
}
|
||||
70
plugins/proxy/pubspec.yaml
Normal file
70
plugins/proxy/pubspec.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
name: proxy
|
||||
description: A new Flutter plugin project.
|
||||
version: 0.0.1
|
||||
homepage:
|
||||
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
flutter: '>=3.3.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.0.2
|
||||
path: ^1.8.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
# This section identifies this Flutter project as a plugin project.
|
||||
# The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
|
||||
# which should be registered in the plugin registry. This is required for
|
||||
# using method channels.
|
||||
# The Android 'package' specifies package in which the registered class is.
|
||||
# This is required for using method channels on Android.
|
||||
# The 'ffiPlugin' specifies that native code should be built and bundled.
|
||||
# This is required for using `dart:ffi`.
|
||||
# All these are used by the tooling to maintain consistency when
|
||||
# adding or updating assets for this project.
|
||||
plugin:
|
||||
platforms:
|
||||
windows:
|
||||
pluginClass: ProxyPluginCApi
|
||||
|
||||
# To add assets to your plugin package, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
#
|
||||
# For details regarding assets in packages, see
|
||||
# https://flutter.dev/assets-and-images/#from-packages
|
||||
#
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||
|
||||
# To add custom fonts to your plugin package, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
# "family" key with the font family name, and a "fonts" key with a
|
||||
# list giving the asset and other descriptors for the font. For
|
||||
# example:
|
||||
# fonts:
|
||||
# - family: Schyler
|
||||
# fonts:
|
||||
# - asset: fonts/Schyler-Regular.ttf
|
||||
# - asset: fonts/Schyler-Italic.ttf
|
||||
# style: italic
|
||||
# - family: Trajan Pro
|
||||
# fonts:
|
||||
# - asset: fonts/TrajanPro.ttf
|
||||
# - asset: fonts/TrajanPro_Bold.ttf
|
||||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts in packages, see
|
||||
# https://flutter.dev/custom-fonts/#from-packages
|
||||
17
plugins/proxy/windows/.gitignore
vendored
Normal file
17
plugins/proxy/windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter/
|
||||
|
||||
# Visual Studio user-specific files.
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Visual Studio build-related files.
|
||||
x64/
|
||||
x86/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
53
plugins/proxy/windows/.vscode/settings.json
vendored
Normal file
53
plugins/proxy/windows/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.ftl": "vue-html",
|
||||
"*.vue": "vue",
|
||||
"*.scss": "sass",
|
||||
"*.md": "markdown",
|
||||
".gitignore": "ignore",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"exception": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"ios": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"iterator": "cpp",
|
||||
"limits": "cpp",
|
||||
"memory": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"utility": "cpp",
|
||||
"variant": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstddef": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xutility": "cpp"
|
||||
}
|
||||
}
|
||||
100
plugins/proxy/windows/CMakeLists.txt
Normal file
100
plugins/proxy/windows/CMakeLists.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
# The Flutter tooling requires that developers have a version of Visual Studio
|
||||
# installed that includes CMake 3.14 or later. You should not increase this
|
||||
# version, as doing so will cause the plugin to fail to compile for some
|
||||
# customers of the plugin.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
# Project-level configuration.
|
||||
set(PROJECT_NAME "proxy")
|
||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
cmake_policy(VERSION 3.14...3.25)
|
||||
|
||||
# This value is used when generating builds using this plugin, so it must
|
||||
# not be changed
|
||||
set(PLUGIN_NAME "proxy_plugin")
|
||||
|
||||
# Any new source files that you add to the plugin should be added here.
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
"proxy_plugin.cpp"
|
||||
"proxy_plugin.h"
|
||||
)
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
# on PLUGIN_NAME above).
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
"include/proxy/proxy_plugin_c_api.h"
|
||||
"proxy_plugin_c_api.cpp"
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
|
||||
# Apply a standard set of build settings that are configured in the
|
||||
# application-level CMakeLists.txt. This can be removed for plugins that want
|
||||
# full control over build settings.
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
|
||||
# Symbols are hidden by default to reduce the chance of accidental conflicts
|
||||
# between plugins. This should not be removed; any symbols that should be
|
||||
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
|
||||
# Source include directories and library dependencies. Add any plugin-specific
|
||||
# dependencies here.
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||
# This list could contain prebuilt libraries, or libraries created by an
|
||||
# external build triggered from this build file.
|
||||
set(proxy_bundled_libraries
|
||||
""
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
# === Tests ===
|
||||
# These unit tests can be run from a terminal after building the example, or
|
||||
# from Visual Studio after opening the generated solution file.
|
||||
|
||||
# Only enable test builds when building the example (which sets this variable)
|
||||
# so that plugin clients aren't building the tests.
|
||||
if (${include_${PROJECT_NAME}_tests})
|
||||
set(TEST_RUNNER "${PROJECT_NAME}_test")
|
||||
enable_testing()
|
||||
|
||||
# Add the Google Test dependency.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
||||
)
|
||||
# Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
# Disable install commands for gtest so it doesn't end up in the bundle.
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
# The plugin's C API is not very useful for unit testing, so build the sources
|
||||
# directly into the test binary rather than using the DLL.
|
||||
add_executable(${TEST_RUNNER}
|
||||
test/proxy_plugin_test.cpp
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
apply_standard_settings(${TEST_RUNNER})
|
||||
target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin)
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock)
|
||||
# flutter_wrapper_plugin has link dependencies on the Flutter DLL.
|
||||
add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${FLUTTER_LIBRARY}" $<TARGET_FILE_DIR:${TEST_RUNNER}>
|
||||
)
|
||||
|
||||
# Enable automatic test discovery.
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(${TEST_RUNNER})
|
||||
endif()
|
||||
23
plugins/proxy/windows/include/proxy/proxy_plugin_c_api.h
Normal file
23
plugins/proxy/windows/include/proxy/proxy_plugin_c_api.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef FLUTTER_PLUGIN_PROXY_PLUGIN_C_API_H_
|
||||
#define FLUTTER_PLUGIN_PROXY_PLUGIN_C_API_H_
|
||||
|
||||
#include <flutter_plugin_registrar.h>
|
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void ProxyPluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // FLUTTER_PLUGIN_PROXY_PLUGIN_C_API_H_
|
||||
171
plugins/proxy/windows/proxy_plugin.cpp
Normal file
171
plugins/proxy/windows/proxy_plugin.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "proxy_plugin.h"
|
||||
|
||||
// This must be included before many other Windows headers.
|
||||
#include <windows.h>
|
||||
|
||||
#include <WinInet.h>
|
||||
#include <Ras.h>
|
||||
#include <RasError.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#pragma comment(lib, "wininet")
|
||||
#pragma comment(lib, "Rasapi32")
|
||||
|
||||
// For getPlatformVersion; remove unless needed for your plugin implementation.
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
void startProxy(const int port)
|
||||
{
|
||||
INTERNET_PER_CONN_OPTION_LIST list;
|
||||
DWORD dwBufSize = sizeof(list);
|
||||
list.dwSize = sizeof(list);
|
||||
list.pszConnection = nullptr;
|
||||
auto url = "127.0.0.1:" + std::to_string(port);
|
||||
auto wUrl = std::wstring(url.begin(), url.end());
|
||||
auto fullAddr = new WCHAR[url.length() + 1];
|
||||
wcscpy_s(fullAddr, url.length() + 1, wUrl.c_str());
|
||||
list.dwOptionCount = 2;
|
||||
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
|
||||
|
||||
if (!list.pOptions)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
||||
list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT | PROXY_TYPE_PROXY;
|
||||
|
||||
list.pOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
|
||||
list.pOptions[1].Value.pszValue = fullAddr;
|
||||
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
||||
|
||||
RASENTRYNAME entry;
|
||||
entry.dwSize = sizeof(entry);
|
||||
std::vector<RASENTRYNAME> entries;
|
||||
DWORD size = sizeof(entry), count;
|
||||
LPRASENTRYNAME entryAddr = &entry;
|
||||
auto ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
if (ret == ERROR_BUFFER_TOO_SMALL)
|
||||
{
|
||||
entries.resize(count);
|
||||
entries[0].dwSize = sizeof(RASENTRYNAME);
|
||||
entryAddr = entries.data();
|
||||
ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
}
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
list.pszConnection = entryAddr[i].szEntryName;
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
||||
}
|
||||
delete[] list.pOptions;
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
||||
}
|
||||
|
||||
void stopProxy()
|
||||
{
|
||||
INTERNET_PER_CONN_OPTION_LIST list;
|
||||
DWORD dwBufSize = sizeof(list);
|
||||
|
||||
list.dwSize = sizeof(list);
|
||||
list.pszConnection = nullptr;
|
||||
list.dwOptionCount = 1;
|
||||
list.pOptions = new INTERNET_PER_CONN_OPTION[1];
|
||||
if (nullptr == list.pOptions)
|
||||
{
|
||||
return;
|
||||
}
|
||||
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
||||
list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT;
|
||||
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
||||
|
||||
RASENTRYNAME entry;
|
||||
entry.dwSize = sizeof(entry);
|
||||
std::vector<RASENTRYNAME> entries;
|
||||
DWORD size = sizeof(entry), count;
|
||||
LPRASENTRYNAME entryAddr = &entry;
|
||||
auto ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
if (ret == ERROR_BUFFER_TOO_SMALL)
|
||||
{
|
||||
entries.resize(count);
|
||||
entries[0].dwSize = sizeof(RASENTRYNAME);
|
||||
entryAddr = entries.data();
|
||||
ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
}
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
list.pszConnection = entryAddr[i].szEntryName;
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
|
||||
}
|
||||
delete[] list.pOptions;
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
||||
}
|
||||
|
||||
namespace proxy
|
||||
{
|
||||
|
||||
// static
|
||||
void ProxyPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarWindows *registrar)
|
||||
{
|
||||
auto channel =
|
||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||
registrar->messenger(), "proxy",
|
||||
&flutter::StandardMethodCodec::GetInstance());
|
||||
|
||||
auto plugin = std::make_unique<ProxyPlugin>();
|
||||
|
||||
channel->SetMethodCallHandler(
|
||||
[plugin_pointer = plugin.get()](const auto &call, auto result)
|
||||
{
|
||||
plugin_pointer->HandleMethodCall(call, std::move(result));
|
||||
});
|
||||
|
||||
registrar->AddPlugin(std::move(plugin));
|
||||
}
|
||||
|
||||
ProxyPlugin::ProxyPlugin() {}
|
||||
|
||||
ProxyPlugin::~ProxyPlugin() {}
|
||||
|
||||
void ProxyPlugin::HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
|
||||
{
|
||||
if (method_call.method_name().compare("StopProxy") == 0)
|
||||
{
|
||||
stopProxy();
|
||||
result->Success(true);
|
||||
}
|
||||
else if (method_call.method_name().compare("StartProxy") == 0)
|
||||
{
|
||||
auto *arguments = std::get_if<flutter::EncodableMap>(method_call.arguments());
|
||||
auto port = std::get<int>(arguments->at(flutter::EncodableValue("port")));
|
||||
startProxy(port);
|
||||
result->Success(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
result->NotImplemented();
|
||||
}
|
||||
}
|
||||
} // namespace proxy
|
||||
31
plugins/proxy/windows/proxy_plugin.h
Normal file
31
plugins/proxy/windows/proxy_plugin.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef FLUTTER_PLUGIN_PROXY_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_PROXY_PLUGIN_H_
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace proxy {
|
||||
|
||||
class ProxyPlugin : public flutter::Plugin {
|
||||
public:
|
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
||||
|
||||
ProxyPlugin();
|
||||
|
||||
virtual ~ProxyPlugin();
|
||||
|
||||
// Disallow copy and assign.
|
||||
ProxyPlugin(const ProxyPlugin&) = delete;
|
||||
ProxyPlugin& operator=(const ProxyPlugin&) = delete;
|
||||
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
};
|
||||
|
||||
} // namespace proxy
|
||||
|
||||
#endif // FLUTTER_PLUGIN_PROXY_PLUGIN_H_
|
||||
12
plugins/proxy/windows/proxy_plugin_c_api.cpp
Normal file
12
plugins/proxy/windows/proxy_plugin_c_api.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "include/proxy/proxy_plugin_c_api.h"
|
||||
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include "proxy_plugin.h"
|
||||
|
||||
void ProxyPluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar) {
|
||||
proxy::ProxyPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarManager::GetInstance()
|
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||
}
|
||||
43
plugins/proxy/windows/test/proxy_plugin_test.cpp
Normal file
43
plugins/proxy/windows/test/proxy_plugin_test.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <flutter/method_call.h>
|
||||
#include <flutter/method_result_functions.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "proxy_plugin.h"
|
||||
|
||||
namespace proxy {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
using flutter::EncodableMap;
|
||||
using flutter::EncodableValue;
|
||||
using flutter::MethodCall;
|
||||
using flutter::MethodResultFunctions;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ProxyPlugin, GetPlatformVersion) {
|
||||
ProxyPlugin plugin;
|
||||
// Save the reply value from the success callback.
|
||||
std::string result_string;
|
||||
plugin.HandleMethodCall(
|
||||
MethodCall("getPlatformVersion", std::make_unique<EncodableValue>()),
|
||||
std::make_unique<MethodResultFunctions<>>(
|
||||
[&result_string](const EncodableValue* result) {
|
||||
result_string = std::get<std::string>(*result);
|
||||
},
|
||||
nullptr, nullptr));
|
||||
|
||||
// Since the exact string varies by host, just ensure that it's a string
|
||||
// with the expected format.
|
||||
EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace proxy
|
||||
Reference in New Issue
Block a user