86 lines
3.8 KiB
Java
86 lines
3.8 KiB
Java
package com.phenomrom.healerman;
|
|
|
|
import android.content.res.AssetManager;
|
|
import android.webkit.WebResourceRequest;
|
|
import android.webkit.WebResourceResponse;
|
|
import com.getcapacitor.Bridge;
|
|
import org.json.JSONObject;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.InputStream;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.zip.GZIPInputStream;
|
|
|
|
/** Streams shared APK objects at their original logical URLs; no expanded disk copy. */
|
|
final class BundledContentAssets {
|
|
private final Bridge bridge;
|
|
private final AssetManager assets;
|
|
private JSONObject files;
|
|
|
|
BundledContentAssets(Bridge bridge) {
|
|
this.bridge = bridge;
|
|
this.assets = bridge.getContext().getAssets();
|
|
}
|
|
|
|
private synchronized JSONObject files() throws Exception {
|
|
if (files == null) {
|
|
try (InputStream input = assets.open("public/content/bootstrap-manifest.json")) {
|
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
|
byte[] buffer = new byte[16384];
|
|
int count;
|
|
while ((count = input.read(buffer)) != -1) output.write(buffer, 0, count);
|
|
files = new JSONObject(output.toString("UTF-8")).getJSONObject("files");
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
WebResourceResponse intercept(WebResourceRequest request) {
|
|
if (!"GET".equals(request.getMethod()) || !bridge.getHost().equals(request.getUrl().getAuthority())
|
|
|| !bridge.getScheme().equals(request.getUrl().getScheme())) return null;
|
|
String path = request.getUrl().getPath();
|
|
if (path == null || !(path.startsWith("/assets/") || path.startsWith("/basis/") || path.startsWith("/data/"))) return null;
|
|
try {
|
|
JSONObject entry = files().optJSONObject(path);
|
|
if (entry == null) return null;
|
|
JSONObject download = entry.optJSONObject("download");
|
|
String objectUrl = (download == null ? entry : download).getString("url");
|
|
if (!objectUrl.matches("/content/bundled/[a-f0-9]{64}\\.[a-z0-9]+(?:\\.g(?:z|zip))?")) return null;
|
|
InputStream input = assets.open("public" + objectUrl);
|
|
if (download != null) {
|
|
try { input = new GZIPInputStream(input, 128 * 1024); }
|
|
catch (Exception error) { input.close(); throw error; }
|
|
}
|
|
Map<String, String> headers = new HashMap<>();
|
|
headers.put("Content-Length", String.valueOf(entry.getLong("bytes")));
|
|
headers.put("Cache-Control", "public, max-age=3600");
|
|
return new WebResourceResponse(mimeType(path), null, 200, "OK", headers, input);
|
|
} catch (Exception error) {
|
|
return new WebResourceResponse("text/plain", "UTF-8", 500, "Bundled asset unavailable", new HashMap<>(),
|
|
new ByteArrayInputStream("Bundled asset unavailable.".getBytes(StandardCharsets.UTF_8)));
|
|
}
|
|
}
|
|
|
|
private static String mimeType(String path) {
|
|
String extension = path.substring(path.lastIndexOf('.') + 1);
|
|
switch (extension) {
|
|
case "glb": return "model/gltf-binary";
|
|
case "json": return "application/json";
|
|
case "js": return "text/javascript";
|
|
case "wasm": return "application/wasm";
|
|
case "ktx2": return "image/ktx2";
|
|
case "png": return "image/png";
|
|
case "webp": return "image/webp";
|
|
case "avif": return "image/avif";
|
|
case "svg": return "image/svg+xml";
|
|
case "mp3": return "audio/mpeg";
|
|
case "ogg": return "audio/ogg";
|
|
case "wav": return "audio/wav";
|
|
case "webm": return "video/webm";
|
|
default: return "application/octet-stream";
|
|
}
|
|
}
|
|
}
|