diff --git a/README.md b/README.md index 00cfa5b..96e7586 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Other features: * Login button is clicked automatically (Discord login only). * You could make alerts follow location in background. * Handle links to the map without opening a new tab (requires custom build for custom domains). +* Compressed graphql payload to save bandwidth. For best experiences, ReactMap should be updated to this commit or later: https://github.com/WatWowMap/ReactMap/commit/addb5f3b27c49fe9d7165c8b76f54a5b10912f67 diff --git a/app/src/main/java/be/mygod/reactmap/webkit/BaseReactMapFragment.kt b/app/src/main/java/be/mygod/reactmap/webkit/BaseReactMapFragment.kt index d13fb6b..35f1d1e 100644 --- a/app/src/main/java/be/mygod/reactmap/webkit/BaseReactMapFragment.kt +++ b/app/src/main/java/be/mygod/reactmap/webkit/BaseReactMapFragment.kt @@ -40,6 +40,7 @@ import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import timber.log.Timber +import java.io.ByteArrayOutputStream import java.io.File import java.io.FileDescriptor import java.io.IOException @@ -52,6 +53,8 @@ import java.net.URL import java.nio.charset.Charset import java.util.Locale import java.util.regex.Matcher +import java.util.zip.Deflater +import java.util.zip.DeflaterOutputStream abstract class BaseReactMapFragment : Fragment(), DownloadListener { companion object { @@ -228,6 +231,33 @@ abstract class BaseReactMapFragment : Fragment(), DownloadListener { return handleTranslation(request) } if (vendorJsMatcher.matchEntire(path) != null) return handleVendorJs(request) + if (path == "/graphql" && request.method == "POST") { + val body = request.requestHeaders.remove("_interceptedBody") + if (body != null) return try { + val url = request.url.toString() + val conn = ReactMapHttpEngine.connectWithCookie(url) { conn -> + setupConnection(request, conn) + conn.setRequestProperty("Content-Encoding", "deflate") + conn.doOutput = true + val uncompressed = body.toByteArray() + val out = ByteArrayOutputStream() + DeflaterOutputStream(out, Deflater(Deflater.BEST_COMPRESSION)).use { + it.write(uncompressed) + } + val outArray = out.toByteArray() +// Timber.tag("CompressionStat").i("${outArray.size}/${uncompressed.size} ~ ${outArray.size.toDouble() / uncompressed.size}") + conn.setFixedLengthStreamingMode(outArray.size) + conn.outputStream.use { it.write(outArray) } + } + createResponse(conn) { _ -> conn.findErrorStream } + } catch (e: IOException) { + Timber.d(e) + null + } catch (e: IllegalArgumentException) { + Timber.d(e) + null + } + } } if (ReactMapHttpEngine.isCronet && (path.substringAfterLast('.').lowercase(Locale.ENGLISH) in mediaExtensions || request.requestHeaders.any { (key, value) -> diff --git a/app/src/main/res/raw/setup.js b/app/src/main/res/raw/setup.js index c23fc85..dad1894 100644 --- a/app/src/main/res/raw/setup.js +++ b/app/src/main/res/raw/setup.js @@ -48,3 +48,10 @@ Object.defineProperty(navigator, 'geolocation', { }, }, }); +window._fetch = window.fetch; +window.fetch = function (input, init = {}) { + if (input === '/graphql' && init.method === 'POST' && init.body) { + init.headers['_interceptedBody'] = init.body; + } + return window._fetch(input, init); +};