image switch address

This commit is contained in:
niuhuan 2021-11-30 10:23:49 +08:00
parent caef949f32
commit c95771e637
13 changed files with 213 additions and 63 deletions

View File

@ -24,7 +24,8 @@ import (
func InitClient() {
client.Timeout = time.Second * 60
switchAddress, _ = properties.LoadSwitchAddress()
switchAddress, _ = properties.LoadIntProperty("switchAddress", 1)
imageSwitchAddress, _ = properties.LoadIntProperty("imageSwitchAddress", 1)
proxy, _ := properties.LoadProxy()
changeProxyUrl(proxy)
}
@ -36,15 +37,18 @@ var dialer = &net.Dialer{
}
// SwitchAddress
// addr = "172.67.7.24:443"
// addr = "104.20.180.50:443"
// addr = "172.67.208.169:443"
var switchAddress = ""
var switchAddressPattern, _ = regexp.Compile("^.+picacomic\\.com:\\d+$")
var switchAddresses = map[int]string{
1: "172.67.7.24:443",
2: "104.20.180.50:443",
3: "172.67.208.169:443",
}
var switchAddress = 1
var switchAddressPattern, _ = regexp.Compile("^.+pica" + "comic\\.com:\\d+$")
func switchAddressContext(ctx context.Context, network, addr string) (net.Conn, error) {
if switchAddressPattern.MatchString(addr) && switchAddress != "" {
addr = switchAddress
if sAddr, ok := switchAddresses[switchAddress]; ok {
addr = sAddr
}
return dialer.DialContext(ctx, network, addr)
}

View File

@ -2,6 +2,7 @@ package controller
import (
"bytes"
"context"
"errors"
_ "golang.org/x/image/webp"
"image"
@ -9,20 +10,46 @@ import (
_ "image/jpeg"
_ "image/png"
"io/ioutil"
"net"
"net/http"
"pikapika/main/database/comic_center"
"sync"
"time"
)
var mutexCounter = -1
var busMutex *sync.Mutex
var subMutexes []*sync.Mutex
var imageHttpClient *http.Client
// imageSwitchAddress
// 图片的分流直接使用 switchAddressPattern 可以正常使用
// 通过ping发现图片的分流地址与ip一致
// 这里为了域名与官方一致改为域名分流
var imageSwitchAddresses = map[int]string{
1: "https://storage.wika" + "wika.xyz",
2: "https://s2.pica" + "comic.com",
3: "https://s3.pica" + "comic.com",
}
var imageSwitchAddress int
func init() {
busMutex = &sync.Mutex{}
for i := 0; i < 5; i++ {
subMutexes = append(subMutexes, &sync.Mutex{})
}
imageHttpClient = &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: time.Second * 10,
ExpectContinueTimeout: time.Second * 10,
ResponseHeaderTimeout: time.Second * 10,
IdleConnTimeout: time.Second * 10,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, network, addr)
},
},
}
}
// takeMutex 下载图片获取一个锁, 这样只能同时下载5张图片
@ -52,6 +79,13 @@ func decodeFromFile(path string) ([]byte, image.Image, string, error) {
// 下载图片并decode
func decodeFromUrl(fileServer string, path string) ([]byte, image.Image, string, error) {
useClient := imageHttpClient
if imageSwitchAddress == -1 {
useClient = &client.Client
}
if server, ok := imageSwitchAddresses[imageSwitchAddress]; ok {
fileServer = server
}
m := takeMutex()
m.Lock()
defer m.Unlock()
@ -59,7 +93,7 @@ func decodeFromUrl(fileServer string, path string) ([]byte, image.Image, string,
if err != nil {
return nil, nil, "", err
}
response, err := client.Do(request)
response, err := useClient.Do(request)
if err != nil {
return nil, nil, "", err
}

View File

@ -100,16 +100,37 @@ func loadDownloadThreadCount() int {
}
func setSwitchAddress(nSwitchAddress string) error {
err := properties.SaveSwitchAddress(nSwitchAddress)
num, err := strconv.Atoi(nSwitchAddress)
if err != nil {
return err
}
switchAddress = nSwitchAddress
err = properties.SaveIntProperty("switchAddress", num)
if err != nil {
return err
}
switchAddress = num
return nil
}
func getSwitchAddress() (string, error) {
return switchAddress, nil
return strconv.Itoa(switchAddress), nil
}
func setImageSwitchAddress(nSwitchAddress string) error {
num, err := strconv.Atoi(nSwitchAddress)
if err != nil {
return err
}
err = properties.SaveIntProperty("imageSwitchAddress", num)
if err != nil {
return err
}
switchAddress = num
return nil
}
func getImageSwitchAddress() (string, error) {
return strconv.Itoa(imageSwitchAddress), nil
}
func setProxy(value string) error {
@ -534,6 +555,10 @@ func FlatInvoke(method string, params string) (string, error) {
return "", setSwitchAddress(params)
case "getSwitchAddress":
return getSwitchAddress()
case "setImageSwitchAddress":
return "", setImageSwitchAddress(params)
case "getImageSwitchAddress":
return getImageSwitchAddress()
case "setProxy":
return "", setProxy(params)
case "getProxy":

View File

@ -2,6 +2,7 @@ package properties
import (
"errors"
"fmt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/clause"
@ -65,18 +66,22 @@ func LoadBoolProperty(name string, defaultValue bool) (bool, error) {
return strconv.ParseBool(stringValue)
}
func LoadIntProperty(name string, defaultValue int) (int, error) {
str, err := LoadProperty(name, fmt.Sprintf("%d", defaultValue))
if err != nil {
return 0, err
}
return strconv.Atoi(str)
}
func SaveIntProperty(name string, value int) error {
return SaveProperty(name, strconv.Itoa(value))
}
func SaveBoolProperty(name string, value bool) error {
return SaveProperty(name, strconv.FormatBool(value))
}
func SaveSwitchAddress(value string) error {
return SaveProperty("switch_address", value)
}
func LoadSwitchAddress() (string, error) {
return LoadProperty("switch_address", "")
}
func SaveProxy(value string) error {
return SaveProperty("proxy", value)
}

View File

@ -50,6 +50,16 @@ class Method {
return await _flatInvoke("setSwitchAddress", switchAddress);
}
///
Future<String> getImageSwitchAddress() async {
return await _flatInvoke("getImageSwitchAddress", "");
}
///
Future<dynamic> setImageSwitchAddress(String switchAddress) async {
return await _flatInvoke("setImageSwitchAddress", switchAddress);
}
///
Future<String> getProxy() async {
return await _flatInvoke("getProxy", "");

View File

@ -9,10 +9,10 @@ import 'package:flutter/material.dart';
import '../Method.dart';
var _addresses = {
"不分流": "",
"分流1": "172.67.7.24:443",
"分流2": "104.20.180.50:443",
"分流3": "72.67.208.169:443",
"0": "不分流",
"1": "分流1 (推荐)",
"2": "分流2",
"3": "分流3",
};
late String _currentAddress;
@ -21,16 +21,11 @@ Future<void> initAddress() async {
_currentAddress = await method.getSwitchAddress();
}
String currentAddressName() {
for (var value in _addresses.entries) {
if (value.value == _currentAddress) {
return value.key;
}
}
return "";
String _currentAddressName() {
return _addresses[_currentAddress] ?? "";
}
Future<void> chooseAddress(BuildContext context) async {
Future<void> _chooseAddress(BuildContext context) async {
String? choose = await showDialog<String>(
context: context,
builder: (BuildContext context) {
@ -39,9 +34,9 @@ Future<void> chooseAddress(BuildContext context) async {
children: <Widget>[
..._addresses.entries.map(
(e) => SimpleDialogOption(
child: Text(e.key),
child: Text(e.value),
onPressed: () {
Navigator.of(context).pop(e.value);
Navigator.of(context).pop(e.key);
},
),
),
@ -54,3 +49,18 @@ Future<void> chooseAddress(BuildContext context) async {
_currentAddress = choose;
}
}
Widget switchAddressSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("分流"),
subtitle: Text(_currentAddressName()),
onTap: () async {
await _chooseAddress(context);
setState(() {});
},
);
},
);
}

View File

@ -0,0 +1,62 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../Method.dart';
var _imageAddresses = {
"-1": "跟随api分流",
"0": "不分流",
"1": "分流1 (推荐)",
"2": "分流2",
"3": "分流3",
};
late String _currentImageAddress;
Future<void> initImageAddress() async {
_currentImageAddress = await method.getImageSwitchAddress();
}
String _currentImageAddressName() {
return _imageAddresses[_currentImageAddress] ?? "";
}
Future<void> _chooseImageAddress(BuildContext context) async {
String? choose = await showDialog<String>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
title: Text('选择图片分流'),
children: <Widget>[
..._imageAddresses.entries.map(
(e) => SimpleDialogOption(
child: Text(e.value),
onPressed: () {
Navigator.of(context).pop(e.key);
},
),
),
],
);
},
);
if (choose != null) {
await method.setImageSwitchAddress(choose);
_currentImageAddress = choose;
}
}
Widget imageSwitchAddressSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("图片"),
subtitle: Text(_currentImageAddressName()),
onTap: () async {
await _chooseImageAddress(context);
setState(() {});
},
);
},
);
}

View File

@ -28,3 +28,18 @@ Future<dynamic> inputProxy(BuildContext context) async {
_currentProxy = input;
}
}
Widget proxySetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("代理服务器"),
subtitle: Text(currentProxyName()),
onTap: () async {
await inputProxy(context);
setState(() {});
},
);
},
);
}

View File

@ -6,17 +6,17 @@ import 'package:pikapika/basic/Navigatior.dart';
import 'basic/config/Themes.dart';
void main() {
runApp(PikapiApp());
runApp(PikapikaApp());
}
class PikapiApp extends StatefulWidget {
const PikapiApp({Key? key}) : super(key: key);
class PikapikaApp extends StatefulWidget {
const PikapikaApp({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _PikapiAppState();
State<StatefulWidget> createState() => _PikapikaAppState();
}
class _PikapiAppState extends State<PikapiApp> {
class _PikapikaAppState extends State<PikapikaApp> {
@override
void initState() {
themeEvent.subscribe(_onChangeTheme);

View File

@ -11,6 +11,7 @@ import 'package:pikapika/basic/config/DownloadAndExportPath.dart';
import 'package:pikapika/basic/config/DownloadThreadCount.dart';
import 'package:pikapika/basic/config/FullScreenAction.dart';
import 'package:pikapika/basic/config/FullScreenUI.dart';
import 'package:pikapika/basic/config/ImageAddress.dart';
import 'package:pikapika/basic/config/KeyboardController.dart';
import 'package:pikapika/basic/config/NoAnimation.dart';
import 'package:pikapika/basic/config/PagerAction.dart';
@ -49,6 +50,7 @@ class _InitScreenState extends State<InitScreen> {
await initPlatform(); // ,
await initAutoClean();
await initAddress();
await initImageAddress();
await initProxy();
await initQuality();
await initFont();

View File

@ -220,7 +220,7 @@ class _RemoteImageState extends State<RemoteImage> {
@override
void initState() {
_mock = widget.fileServer == "" || widget.fileServer.contains(".xyz/");
_mock = widget.fileServer == "";
if (!_mock) {
_future = method
.remoteImageData(widget.fileServer, widget.path)

View File

@ -1,35 +1,18 @@
import 'package:flutter/material.dart';
import 'package:pikapika/basic/config/Address.dart';
import 'package:pikapika/basic/config/ImageAddress.dart';
import 'package:pikapika/basic/config/Proxy.dart';
//
class NetworkSetting extends StatefulWidget {
@override
State<StatefulWidget> createState() => _NetworkSettingState();
}
class _NetworkSettingState extends State<NetworkSetting> {
class NetworkSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
ListTile(
title: Text("分流"),
subtitle: Text(currentAddressName()),
onTap: () async {
await chooseAddress(context);
setState(() {});
},
),
ListTile(
title: Text("代理服务器"),
subtitle: Text(currentProxyName()),
onTap: () async {
await inputProxy(context);
setState(() {});
},
),
switchAddressSetting(),
imageSwitchAddressSetting(),
proxySetting(),
],
),
);

View File

@ -13,7 +13,7 @@ import 'package:pikapika/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(PikapiApp());
await tester.pumpWidget(PikapikaApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);