mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
Add pve http proxy
This commit is contained in:
@@ -10,20 +10,24 @@ import 'package:toolbox/core/extension/context/locale.dart';
|
|||||||
import 'package:toolbox/data/model/app/error.dart';
|
import 'package:toolbox/data/model/app/error.dart';
|
||||||
import 'package:toolbox/data/model/server/pve.dart';
|
import 'package:toolbox/data/model/server/pve.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
|
||||||
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
||||||
|
|
||||||
final class PveProvider extends ChangeNotifier {
|
final class PveProvider extends ChangeNotifier {
|
||||||
final ServerPrivateInfo spi;
|
final ServerPrivateInfo spi;
|
||||||
late final String addr;
|
late String addr;
|
||||||
//late final SSHClient _client;
|
late final SSHClient _client;
|
||||||
|
late final ServerSocket _serverSocket;
|
||||||
|
final List<SSHForwardChannel> _forwards = [];
|
||||||
|
int _localPort = 0;
|
||||||
|
|
||||||
PveProvider({required this.spi}) {
|
PveProvider({required this.spi}) {
|
||||||
// final client = _spi.server?.client;
|
final client = spi.server?.client;
|
||||||
// if (client == null) {
|
if (client == null) {
|
||||||
// throw Exception('Server client is null');
|
throw Exception('Server client is null');
|
||||||
// }
|
}
|
||||||
// _client = client;
|
_client = client;
|
||||||
final addr = spi.custom?.pveAddr;
|
final addr = spi.custom?.pveAddr;
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
err.value = 'PVE address is null';
|
err.value = 'PVE address is null';
|
||||||
@@ -36,11 +40,12 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
final err = ValueNotifier<String?>(null);
|
final err = ValueNotifier<String?>(null);
|
||||||
final connected = Completer<void>();
|
final connected = Completer<void>();
|
||||||
|
|
||||||
late final _ignoreCert = spi.custom?.pveIgnoreCert ?? false;
|
late bool _ignoreCert = spi.custom?.pveIgnoreCert ?? false;
|
||||||
late final session = Dio()
|
late final session = Dio()
|
||||||
..httpClientAdapter = IOHttpClientAdapter(
|
..httpClientAdapter = IOHttpClientAdapter(
|
||||||
createHttpClient: () {
|
createHttpClient: () {
|
||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
|
client.connectionFactory = cf;
|
||||||
if (_ignoreCert) {
|
if (_ignoreCert) {
|
||||||
client.badCertificateCallback = (_, __, ___) => true;
|
client.badCertificateCallback = (_, __, ___) => true;
|
||||||
}
|
}
|
||||||
@@ -50,16 +55,14 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final data = ValueNotifier<PveRes?>(null);
|
final data = ValueNotifier<PveRes?>(null);
|
||||||
|
|
||||||
bool get onlyOneNode => data.value?.nodes.length == 1;
|
bool get onlyOneNode => data.value?.nodes.length == 1;
|
||||||
String? release;
|
String? release;
|
||||||
bool isBusy = false;
|
bool isBusy = false;
|
||||||
|
|
||||||
// int _localPort = 0;
|
|
||||||
// String get addr => 'http://127.0.0.1:$_localPort';
|
|
||||||
|
|
||||||
Future<void> _init() async {
|
Future<void> _init() async {
|
||||||
try {
|
try {
|
||||||
//await _forward();
|
await _forward();
|
||||||
await _login();
|
await _login();
|
||||||
await _release;
|
await _release;
|
||||||
} on PveErr {
|
} on PveErr {
|
||||||
@@ -72,33 +75,53 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _forward() async {
|
Future<void> _forward() async {
|
||||||
// var retries = 0;
|
final url = Uri.parse(addr);
|
||||||
// while (retries < 3) {
|
if (_localPort == 0) {
|
||||||
// try {
|
_serverSocket = await ServerSocket.bind('localhost', 0);
|
||||||
// _localPort = Random().nextInt(1000) + 37000;
|
_localPort = _serverSocket.port;
|
||||||
// print('Forwarding local port $_localPort');
|
_serverSocket.listen((socket) async {
|
||||||
// final serverSocket = await ServerSocket.bind('localhost', _localPort);
|
final forward = await _client.forwardLocal(url.host, url.port);
|
||||||
// final forward = await _client.forwardLocal('127.0.0.1', 8006);
|
_forwards.add(forward);
|
||||||
// serverSocket.listen((socket) {
|
forward.stream.cast<List<int>>().pipe(socket);
|
||||||
// forward.stream.cast<List<int>>().pipe(socket);
|
socket.cast<List<int>>().pipe(forward.sink);
|
||||||
// socket.pipe(forward.sink);
|
});
|
||||||
// });
|
final newUrl = Uri.parse(addr)
|
||||||
// return;
|
.replace(host: 'localhost', port: _localPort)
|
||||||
// } on SocketException {
|
.toString();
|
||||||
// retries++;
|
print('Forwarding $newUrl to $addr');
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// throw Exception('Failed to bind local port');
|
|
||||||
// }
|
Future<ConnectionTask<Socket>> cf(
|
||||||
|
Uri url, String? proxyHost, int? proxyPort) async {
|
||||||
|
/* final serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, 0);
|
||||||
|
final _localPort = serverSocket.port;
|
||||||
|
serverSocket.listen((socket) async {
|
||||||
|
final forward = await _client.forwardLocal(url.host, url.port);
|
||||||
|
forwards.add(forward);
|
||||||
|
forward.stream.cast<List<int>>().pipe(socket);
|
||||||
|
socket.cast<List<int>>().pipe(forward.sink);
|
||||||
|
});*/
|
||||||
|
|
||||||
|
if (url.isScheme("https")) {
|
||||||
|
return SecureSocket.startConnect('localhost', _localPort,
|
||||||
|
onBadCertificate: (_) => true);
|
||||||
|
} else {
|
||||||
|
return Socket.startConnect('localhost', _localPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _login() async {
|
Future<void> _login() async {
|
||||||
final resp = await session.post('$addr/api2/extjs/access/ticket', data: {
|
final resp = await session.post('$addr/api2/extjs/access/ticket',
|
||||||
'username': spi.user,
|
data: {
|
||||||
'password': spi.pwd,
|
'username': spi.user,
|
||||||
'realm': 'pam',
|
'password': spi.pwd,
|
||||||
'new-format': '1'
|
'realm': 'pam',
|
||||||
});
|
'new-format': '1'
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
headers: {HttpHeaders.contentTypeHeader: Headers.jsonContentType}));
|
||||||
try {
|
try {
|
||||||
final ticket = resp.data['data']['ticket'];
|
final ticket = resp.data['data']['ticket'];
|
||||||
session.options.headers['CSRFPreventionToken'] =
|
session.options.headers['CSRFPreventionToken'] =
|
||||||
@@ -167,4 +190,13 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
bool _isCtrlSuc(Response resp) {
|
bool _isCtrlSuc(Response resp) {
|
||||||
return resp.statusCode == 200;
|
return resp.statusCode == 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
super.dispose();
|
||||||
|
await _serverSocket.close();
|
||||||
|
for (final forward in _forwards) {
|
||||||
|
forward.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
|
_pve.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Reference in New Issue
Block a user