Migrate more to cronet directly (#247)
* Convert GalleryListParser to parse a DirectByteBuffer * Convert FavoritesParser to parse a DirectByteBuffer * Limit buffer size --------- Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
This commit is contained in:
1 parent
70f2bfb760
commit
3bad1d06f4
8 files changed
+81
-57
No files matched your search
@@ -116,9 +116,9 @@ private fun rethrowExactly(code: Int, body: String, e: Throwable): Nothing {
|
||||
throw e
|
||||
}
|
||||
|
||||
val httpContentPool = DirectByteBufferPool(16, 0x20000)
|
||||
val httpContentPool = DirectByteBufferPool(8, 0x80000)
|
||||
|
||||
suspend inline fun <T> fetchCompat(url: String, referer: String? = null, crossinline parser: (ByteBuffer) -> T): T {
|
||||
suspend inline fun <T> fetchCompat(url: String, referer: String? = null, crossinline parser: suspend (ByteBuffer) -> T): T {
|
||||
return if (isCronetSupported) {
|
||||
cronetRequest(url, referer).execute {
|
||||
httpContentPool.useInstance { buffer ->
|
||||
@@ -213,8 +213,7 @@ object EhEngine {
|
||||
return ehRequest(url, referer).executeAndParsingWith(GalleryPageParser::parse)
|
||||
}
|
||||
|
||||
suspend fun getGalleryList(url: String) = ehRequest(url, EhUrl.referer)
|
||||
.executeAndParsingWith(GalleryListParser::parse)
|
||||
suspend fun getGalleryList(url: String) = fetchCompat(url, EhUrl.referer) { GalleryListParser.parse(it) }
|
||||
.apply { fillGalleryList(galleryInfoList, url, true) }
|
||||
.takeUnless { it.galleryInfoList.isEmpty() } ?: GalleryListParser.emptyResult
|
||||
|
||||
@@ -230,8 +229,7 @@ object EhEngine {
|
||||
GalleryDetailParser.parsePreviewList(this) to GalleryDetailParser.parsePreviewPages(this)
|
||||
}
|
||||
|
||||
suspend fun getFavorites(url: String) = ehRequest(url, EhUrl.referer)
|
||||
.executeAndParsingWith(FavoritesParser::parse)
|
||||
suspend fun getFavorites(url: String) = fetchCompat(url, EhUrl.referer, FavoritesParser::parse)
|
||||
.apply { fillGalleryList(galleryInfoList, url) }
|
||||
|
||||
suspend fun signIn(username: String, password: String): String {
|
||||
@@ -356,7 +354,13 @@ object EhEngine {
|
||||
add("ddact", catStr)
|
||||
gidArray.forEach { add("modifygids[]", it.toString()) }
|
||||
}
|
||||
}.executeAndParsingWith(FavoritesParser::parse).apply { fillGalleryList(galleryInfoList, url) }
|
||||
}.executeAndParsingWith {
|
||||
httpContentPool.useInstance {
|
||||
it.put(ByteBuffer.wrap(toByteArray()))
|
||||
it.flip()
|
||||
FavoritesParser.parse(it)
|
||||
}
|
||||
}.apply { fillGalleryList(galleryInfoList, url) }
|
||||
}
|
||||
|
||||
suspend fun getGalleryPageApi(
|
||||
@@ -475,7 +479,13 @@ object EhEngine {
|
||||
if (osc) addFormDataPart("fs_covers", "on")
|
||||
addFormDataPart("f_sfile", "File Search")
|
||||
}
|
||||
}.executeAndParsingWith(GalleryListParser::parse).apply { fillGalleryList(galleryInfoList, EhUrl.imageSearchUrl) }
|
||||
}.executeAndParsingWith {
|
||||
httpContentPool.useInstance {
|
||||
it.put(ByteBuffer.wrap(toByteArray()))
|
||||
it.flip()
|
||||
GalleryListParser.parse(it)
|
||||
}
|
||||
}.apply { fillGalleryList(galleryInfoList, EhUrl.imageSearchUrl) }
|
||||
|
||||
private suspend fun fillGalleryList(list: MutableList<BaseGalleryInfo>, url: String, filter: Boolean = false) {
|
||||
// Filter title and uploader
|
||||
|
||||
@@ -2,16 +2,16 @@ package com.hippo.ehviewer.client.parser
|
||||
|
||||
import com.hippo.ehviewer.client.exception.NotLoggedInException
|
||||
import com.hippo.ehviewer.client.exception.ParseException
|
||||
import java.nio.ByteBuffer
|
||||
import moe.tarsin.coroutines.runSuspendCatching
|
||||
|
||||
object FavoritesParser {
|
||||
suspend fun parse(body: String): Result {
|
||||
if (body.contains("This page requires you to log on.</p>")) {
|
||||
throw NotLoggedInException()
|
||||
}
|
||||
suspend fun parse(body: ByteBuffer): Result {
|
||||
val catArray = arrayOfNulls<String>(10)
|
||||
val countArray = runCatching {
|
||||
parseFav(body, catArray).also { check(it.isNotEmpty()) }
|
||||
val countArray = runSuspendCatching {
|
||||
parseFav(body, favCat = catArray).also { check(it.isNotEmpty()) }
|
||||
}.getOrElse {
|
||||
if (it is RuntimeException && it.message == "Not logged in!") throw NotLoggedInException()
|
||||
throw ParseException("Parse favorites error", it)
|
||||
}
|
||||
val result = GalleryListParser.parse(body)
|
||||
@@ -29,4 +29,4 @@ object FavoritesParser {
|
||||
}
|
||||
}
|
||||
|
||||
private external fun parseFav(body: String, favCat: Array<String?>): IntArray
|
||||
private external fun parseFav(body: ByteBuffer, limit: Int = body.limit(), favCat: Array<String?>): IntArray
|
||||
@@ -8,25 +8,29 @@ import com.hippo.ehviewer.client.data.GalleryInfo.Companion.LOCAL_FAVORITED
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo.Companion.NOT_FAVORITED
|
||||
import com.hippo.ehviewer.client.exception.EhException
|
||||
import com.hippo.ehviewer.client.exception.ParseException
|
||||
import java.nio.ByteBuffer
|
||||
import moe.tarsin.coroutines.runSuspendCatching
|
||||
|
||||
object GalleryListParser {
|
||||
suspend fun parse(body: String) = runCatching {
|
||||
parseGalleryInfoList(body).apply {
|
||||
galleryInfoList.onEach {
|
||||
if (it.favoriteSlot == NOT_FAVORITED && EhDB.containLocalFavorites(it.gid)) {
|
||||
it.favoriteSlot = LOCAL_FAVORITED
|
||||
}
|
||||
it.generateSLang()
|
||||
suspend fun parse(body: ByteBuffer) = runSuspendCatching {
|
||||
parseGalleryInfoList(body)
|
||||
}.onFailure {
|
||||
if (it is RuntimeException) {
|
||||
if (it.message == "No watched tags!") {
|
||||
throw EhException(R.string.gallery_list_empty_hit_subscription)
|
||||
}
|
||||
if (it.message == "No hits found!") {
|
||||
throw EhException(R.string.gallery_list_empty_hit)
|
||||
}
|
||||
}
|
||||
}.getOrElse {
|
||||
if (body.contains("<p>You do not have any watched tags")) {
|
||||
throw EhException(R.string.gallery_list_empty_hit_subscription)
|
||||
}
|
||||
if (body.contains("No hits found</p>")) {
|
||||
throw EhException(R.string.gallery_list_empty_hit)
|
||||
}
|
||||
throw ParseException("Can't parse gallery list", it)
|
||||
}.getOrThrow().apply {
|
||||
galleryInfoList.onEach {
|
||||
if (it.favoriteSlot == NOT_FAVORITED && EhDB.containLocalFavorites(it.gid)) {
|
||||
it.favoriteSlot = LOCAL_FAVORITED
|
||||
}
|
||||
it.generateSLang()
|
||||
}
|
||||
}
|
||||
|
||||
val emptyResult = GalleryListResult(null, null, arrayListOf())
|
||||
@@ -38,4 +42,4 @@ class GalleryListResult @Keep constructor(
|
||||
val galleryInfoList: ArrayList<BaseGalleryInfo>,
|
||||
)
|
||||
|
||||
private external fun parseGalleryInfoList(e: String): GalleryListResult
|
||||
private external fun parseGalleryInfoList(body: ByteBuffer, size: Int = body.limit()): GalleryListResult
|
||||
@@ -13,13 +13,13 @@ extern crate regex_lite;
|
||||
extern crate tl;
|
||||
|
||||
use android_logger::Config;
|
||||
use jnix::jni::objects::{JByteBuffer, JString};
|
||||
use jnix::jni::objects::JByteBuffer;
|
||||
use jnix::jni::sys::{jint, JavaVM, JNI_VERSION_1_6};
|
||||
use jnix::JnixEnv;
|
||||
use log::LevelFilter;
|
||||
use std::ffi::c_void;
|
||||
use std::ptr::slice_from_raw_parts;
|
||||
use std::str::from_utf8;
|
||||
use std::str::from_utf8_unchecked;
|
||||
use tl::{Bytes, Node, NodeHandle, Parser, VDom};
|
||||
|
||||
#[macro_export]
|
||||
@@ -62,28 +62,18 @@ where
|
||||
handle.get(parser)
|
||||
}
|
||||
|
||||
fn parse_jni_string<F, R>(env: &mut JnixEnv, str: &JString, mut f: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(&VDom, &Parser, &JnixEnv) -> Option<R>,
|
||||
{
|
||||
let html = env.get_string(*str).ok()?;
|
||||
let dom = tl::parse(html.to_str().ok()?, tl::ParserOptions::default()).ok()?;
|
||||
let parser = dom.parser();
|
||||
f(&dom, parser, env)
|
||||
}
|
||||
|
||||
fn parse_bytebuffer<F, R>(env: &mut JnixEnv, str: JByteBuffer, limit: jint, mut f: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(&VDom, &Parser, &JnixEnv) -> Option<R>,
|
||||
F: FnMut(&VDom, &Parser, &JnixEnv, &str) -> Option<R>,
|
||||
{
|
||||
let ptr = env.get_direct_buffer_address(str).ok()?;
|
||||
let html = unsafe {
|
||||
let buff = slice_from_raw_parts(ptr, limit as usize);
|
||||
from_utf8(&*buff).ok()?
|
||||
from_utf8_unchecked(&*buff)
|
||||
};
|
||||
let dom = tl::parse(html, tl::ParserOptions::default()).ok()?;
|
||||
let parser = dom.parser();
|
||||
f(&dom, parser, env)
|
||||
f(&dom, parser, env, html)
|
||||
}
|
||||
|
||||
fn get_node_handle_attr<'a>(
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
use apply::Also;
|
||||
use catch_panic::catch_panic;
|
||||
use jni_fn::jni_fn;
|
||||
use jnix::jni::objects::{JClass, JString};
|
||||
use jnix::jni::sys::{jintArray, jobjectArray};
|
||||
use jnix::jni::objects::{JByteBuffer, JClass};
|
||||
use jnix::jni::sys::{jint, jintArray, jobjectArray};
|
||||
use jnix::jni::JNIEnv;
|
||||
use jnix::JnixEnv;
|
||||
use parse_jni_string;
|
||||
use parse_bytebuffer;
|
||||
use quick_xml::escape::unescape;
|
||||
|
||||
#[no_mangle]
|
||||
#[catch_panic(default = "std::ptr::null_mut()")]
|
||||
#[allow(non_snake_case)]
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.FavoritesParserKt")]
|
||||
pub fn parseFav(env: JNIEnv, _class: JClass, input: JString, str: jobjectArray) -> jintArray {
|
||||
pub fn parseFav(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
input: JByteBuffer,
|
||||
limit: jint,
|
||||
str: jobjectArray,
|
||||
) -> jintArray {
|
||||
let mut env = JnixEnv { env };
|
||||
let vec = parse_jni_string(&mut env, &input, |dom, parser, env| {
|
||||
let vec = parse_bytebuffer(&mut env, input, limit, |dom, parser, env, html| {
|
||||
if html.contains("This page requires you to log on.</p>") {
|
||||
panic!("Not logged in!")
|
||||
}
|
||||
let vec: Vec<i32> = dom
|
||||
.get_elements_by_class_name("fp")
|
||||
.enumerate()
|
||||
|
||||
@@ -22,7 +22,7 @@ pub struct Limits {
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.HomeParserKt")]
|
||||
pub fn parseLimit(env: JNIEnv, _class: JClass, input: JByteBuffer, limit: jint) -> jobject {
|
||||
let mut env = JnixEnv { env };
|
||||
parse_bytebuffer(&mut env, input, limit, |dom, parser, _env| {
|
||||
parse_bytebuffer(&mut env, input, limit, |dom, parser, _, _| {
|
||||
let iter = get_vdom_first_element_by_class_name(dom, "homebox")?
|
||||
.as_tag()?
|
||||
.query_selector(parser, "strong")?;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use catch_panic::catch_panic;
|
||||
use jni_fn::jni_fn;
|
||||
use jnix::jni::objects::{JClass, JString};
|
||||
use jnix::jni::sys::jobject;
|
||||
use jnix::jni::objects::{JByteBuffer, JClass};
|
||||
use jnix::jni::sys::{jint, jobject};
|
||||
use jnix::jni::JNIEnv;
|
||||
use jnix::{IntoJava, JnixEnv};
|
||||
use jnix_macros::IntoJava;
|
||||
use parse_jni_string;
|
||||
use parse_bytebuffer;
|
||||
use quick_xml::escape::unescape;
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Index;
|
||||
@@ -197,9 +197,20 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option<BaseGalleryInfo> {
|
||||
#[catch_panic(default = "std::ptr::null_mut()")]
|
||||
#[allow(non_snake_case)]
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.GalleryListParserKt")]
|
||||
pub fn parseGalleryInfoList(env: JNIEnv, _class: JClass, input: JString) -> jobject {
|
||||
pub fn parseGalleryInfoList(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
buffer: JByteBuffer,
|
||||
limit: jint,
|
||||
) -> jobject {
|
||||
let mut env = JnixEnv { env };
|
||||
parse_jni_string(&mut env, &input, |dom, parser, _env| {
|
||||
parse_bytebuffer(&mut env, buffer, limit, |dom, parser, _, str| {
|
||||
if str.contains("<p>You do not have any watched tags") {
|
||||
panic!("No watched tags!")
|
||||
}
|
||||
if str.contains("No hits found</p>") {
|
||||
panic!("No hits found!")
|
||||
}
|
||||
let itg = get_vdom_first_element_by_class_name(dom, "itg")?;
|
||||
let children = itg.children()?;
|
||||
let iter = children.top().iter();
|
||||
|
||||
@@ -27,7 +27,7 @@ pub struct Torrent {
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.TorrentParserKt")]
|
||||
pub fn parseTorrent(env: JNIEnv, _class: JClass, buffer: JByteBuffer, limit: jint) -> jobject {
|
||||
let mut env = JnixEnv { env };
|
||||
parse_bytebuffer(&mut env, buffer, limit, |dom, parser, _env| {
|
||||
parse_bytebuffer(&mut env, buffer, limit, |dom, parser, _, _| {
|
||||
Some(dom.query_selector("table")?.filter_map(|e| {
|
||||
let html = e.get(parser)?.inner_html(parser);
|
||||
if html.contains("Expunged") {
|
||||
|
||||
Reference in new issue
Block a user