Skip to content

Commit

Permalink
Fix parallel download use a larger window_size and frame_size
Browse files Browse the repository at this point in the history
  • Loading branch information
normalllll committed Oct 23, 2024
1 parent bda51a7 commit 13f7f10
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 37 deletions.
10 changes: 10 additions & 0 deletions lib/global.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ void setYandeClient(YandeClient client) {
_yandeClient = client;
}


YandeClient get yandeClientForLargeFile => _yandeClientForLargeFile!;

YandeClient? _yandeClientForLargeFile;

void setYandeClientForLargeFile(YandeClient client) {
_yandeClientForLargeFile = client;
}


bool get isDesktop => Platform.isWindows || Platform.isLinux || Platform.isMacOS;

bool get isMobile => Platform.isAndroid || Platform.isIOS;
2 changes: 1 addition & 1 deletion lib/pages/downloads/logic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class DownloadTask extends _$DownloadTask {
} else {
EasyLoading.showToast(i18n.downloads.messages.downloadStartWithId(state.post.id));
}
yandeClient
yandeClientForLargeFile
.downloadToMemory(
url: state.post.fileUrl ?? state.post.jpegUrl,
autoMultiplePart: true,
Expand Down
18 changes: 11 additions & 7 deletions lib/pages/index/index_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ class IndexPage extends StatefulWidget {

class _IndexPageState extends State<IndexPage> {
Map<(IconData, String), WidgetBuilder> get _pages => {
(Icons.list_alt_outlined, i18n.postList.short): (context) => PostListPage(key: ValueKey(widget.language)),
(Icons.search_outlined, i18n.postSearch.title): (context) => PostSearchPage(key: ValueKey(widget.language)),
(Icons.cloud_download_outlined, i18n.downloads.title): (context) => DownloadsPage(key: ValueKey(widget.language)),
(Icons.info_outlined, i18n.about.title): (context) => AboutPage(key: ValueKey(widget.language)),
(Icons.settings, i18n.settings.title): (context) => SettingsPage(key: ValueKey(widget.language)),
(Icons.list_alt_outlined, i18n.postList.short): (context) => PostListPage(key: ValueKey(widget.language)),
(Icons.search_outlined, i18n.postSearch.title): (context) => PostSearchPage(key: ValueKey(widget.language)),
(Icons.cloud_download_outlined, i18n.downloads.title): (context) => DownloadsPage(key: ValueKey(widget.language)),
(Icons.info_outlined, i18n.about.title): (context) => AboutPage(key: ValueKey(widget.language)),
(Icons.settings, i18n.settings.title): (context) => SettingsPage(key: ValueKey(widget.language)),
};

final controller = PageController();
Expand All @@ -40,16 +40,20 @@ class _IndexPageState extends State<IndexPage> {
void initState() {
Future.delayed(Duration.zero, () async {
YandeClient instance;
YandeClient instanceForLargeFile;
try {
final List<String>? dns = await DnsService.fetchDns();

final ips = dns != null ? StringArray3(dns) : null;
instance = await YandeClient.newInstance(ips: ips);
instance = await YandeClient.newInstance(ips: ips, forLargeFile: false);
instanceForLargeFile = await YandeClient.newInstance(ips: ips, forLargeFile: true);
} catch (e) {
instance = await YandeClient.newInstance(ips: null);
instance = await YandeClient.newInstance(ips: null, forLargeFile: false);
instanceForLargeFile = await YandeClient.newInstance(ips: null, forLargeFile: true);
}

setYandeClient(instance);
setYandeClientForLargeFile(instanceForLargeFile);

setState(() {
_initialized = true;
Expand Down
6 changes: 4 additions & 2 deletions lib/src/rust/api/yande_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ abstract class YandeClient implements RustOpaqueInterface {
Future<Similar> getSimilar({required PlatformInt64 postId});

// HINT: Make it `#[frb(sync)]` to let it become the default constructor of Dart class.
static Future<YandeClient> newInstance({StringArray3? ips}) =>
RustLib.instance.api.crateApiYandeClientYandeClientNew(ips: ips);
static Future<YandeClient> newInstance(
{StringArray3? ips, required bool forLargeFile}) =>
RustLib.instance.api.crateApiYandeClientYandeClientNew(
ips: ips, forLargeFile: forLargeFile);
}

class StringArray3 extends NonGrowableListView<String> {
Expand Down
11 changes: 7 additions & 4 deletions lib/src/rust/frb_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ abstract class RustLibApi extends BaseApi {
Future<Similar> crateApiYandeClientYandeClientGetSimilar(
{required YandeClient that, required PlatformInt64 postId});

Future<YandeClient> crateApiYandeClientYandeClientNew({StringArray3? ips});
Future<YandeClient> crateApiYandeClientYandeClientNew(
{StringArray3? ips, required bool forLargeFile});

RustArcIncrementStrongCountFnType
get rust_arc_increment_strong_count_YandeClient;
Expand Down Expand Up @@ -234,11 +235,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);

@override
Future<YandeClient> crateApiYandeClientYandeClientNew({StringArray3? ips}) {
Future<YandeClient> crateApiYandeClientYandeClientNew(
{StringArray3? ips, required bool forLargeFile}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_opt_String_array_3(ips, serializer);
sse_encode_bool(forLargeFile, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
funcId: 5, port: port_);
},
Expand All @@ -248,15 +251,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
decodeErrorData: null,
),
constMeta: kCrateApiYandeClientYandeClientNewConstMeta,
argValues: [ips],
argValues: [ips, forLargeFile],
apiImpl: this,
));
}

TaskConstMeta get kCrateApiYandeClientYandeClientNewConstMeta =>
const TaskConstMeta(
debugName: "YandeClient_new",
argNames: ["ips"],
argNames: ["ips", "forLargeFile"],
);

Future<void> Function(int, dynamic, dynamic)
Expand Down
4 changes: 2 additions & 2 deletions rust/src/api/yande_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ pub struct YandeClient {
}

impl YandeClient {
pub fn new(ips: Option<[String; 3]>) -> Self {
pub fn new(ips: Option<[String; 3]>, for_large_file: bool) -> Self {
Self {
http: HttpClient::new(ips),
http: HttpClient::new(ips, for_large_file),
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions rust/src/frb_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,13 @@ fn wire__crate__api__yande_client__YandeClient_new_impl(
let mut deserializer =
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_ips = <Option<[String; 3]>>::sse_decode(&mut deserializer);
let api_for_large_file = <bool>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, ()>((move || {
let output_ok =
Result::<_, ()>::Ok(crate::api::yande_client::YandeClient::new(api_ips))?;
let output_ok = Result::<_, ()>::Ok(
crate::api::yande_client::YandeClient::new(api_ips, api_for_large_file),
)?;
Ok(output_ok)
})())
}
Expand Down
47 changes: 28 additions & 19 deletions rust/src/yande/http_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;
use std::time::Duration;
use flutter_rust_bridge::DartFnFuture;

use futures_util::future::join_all;
use futures_util::stream::StreamExt;
use reqwest::Url;
use tokio::sync::Mutex;
Expand All @@ -14,22 +14,34 @@ pub struct HttpClient {


impl HttpClient {
pub fn new(ips: Option<[String; 3]>) -> Self {
pub fn new(ips: Option<[String; 3]>, for_large_file: bool) -> Self {
let mut client_builder = reqwest::ClientBuilder::new().
http2_prior_knowledge().
https_only(true).
http2_adaptive_window(true).
http2_keep_alive_interval(Duration::from_secs(30)).
http2_keep_alive_timeout(Duration::from_secs(60)).
http2_keep_alive_while_idle(true);

if for_large_file {
client_builder = client_builder.
http2_keep_alive_interval(Duration::from_secs(30)).
http2_keep_alive_timeout(Duration::from_secs(120)).
http2_initial_connection_window_size(1024 * 1024).
http2_initial_stream_window_size(1024 * 1024).
http2_max_frame_size(128 * 1024).
http2_keep_alive_while_idle(true)
}

if let Some(ips) = ips {
let socket0 = format!("{}:443", ips[0]).parse();
let socket1 = format!("{}:443", ips[1]).parse();
let socket2 = format!("{}:443", ips[2]).parse();

if let (Ok(socket0), Ok(socket1), Ok(socket2)) = (socket0, socket1, socket2) {
return Self {
client: reqwest::ClientBuilder::new().
client: client_builder.
tls_sni(false).
http2_prior_knowledge().
https_only(true).
http2_adaptive_window(true).
http2_keep_alive_interval(Duration::from_secs(30)).
http2_keep_alive_timeout(Duration::from_secs(60)).
http2_keep_alive_while_idle(true).
resolve("yande.re", socket0).
resolve("files.yande.re", socket1).
resolve("assets.yande.re", socket2).
Expand All @@ -39,14 +51,7 @@ impl HttpClient {
}
}
Self {
client: reqwest::ClientBuilder::new().
http2_prior_knowledge().
https_only(true).
http2_adaptive_window(true).
http2_keep_alive_interval(Duration::from_secs(30)).
http2_keep_alive_timeout(Duration::from_secs(60)).
http2_keep_alive_while_idle(true).
build().unwrap(),
client: client_builder.build().unwrap(),
}
}

Expand Down Expand Up @@ -150,10 +155,14 @@ impl HttpClient {
}

// Wait for all parts to be downloaded
for task in tasks {
let part = task.await??;
let results = join_all(tasks).await;

// Combine all results
for result in results {
let part = result??;
bytes.extend_from_slice(&part);
}

return Ok(bytes);
}
}
Expand Down

0 comments on commit 13f7f10

Please sign in to comment.