Add Base URL field to decoder-ring to make it more flexible

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
pull/13987/head
Michael Telatynski 2020-06-11 01:37:31 +01:00
parent 2419db5195
commit c32d3efd52
1 changed files with 29 additions and 12 deletions

View File

@ -4,8 +4,8 @@ class StartupError extends Error {}
* We need to know the bundle path before we can fetch the sourcemap files. In a production environment, we can guess * We need to know the bundle path before we can fetch the sourcemap files. In a production environment, we can guess
* it using this. * it using this.
*/ */
async function getBundleName() { async function getBundleName(baseUrl) {
const res = await fetch("../index.html"); const res = await fetch(new URL("index.html", baseUrl).toString());
if (!res.ok) { if (!res.ok) {
throw new StartupError(`Couldn't fetch index.html to prefill bundle; ${res.status} ${res.statusText}`); throw new StartupError(`Couldn't fetch index.html to prefill bundle; ${res.status} ${res.statusText}`);
} }
@ -25,7 +25,7 @@ function validateBundle(value) {
* The purpose of this is just to validate that the user entered a real bundle, and provide feedback. * The purpose of this is just to validate that the user entered a real bundle, and provide feedback.
*/ */
const bundleCache = new Map(); const bundleCache = new Map();
function bundleSubject(bundle) { function bundleSubject(baseUrl, bundle) {
if (!bundle.match(/^[0-9a-f]{20}$/)) throw new Error("Bad input"); if (!bundle.match(/^[0-9a-f]{20}$/)) throw new Error("Bad input");
if (bundleCache.has(bundle)) { if (bundleCache.has(bundle)) {
return bundleCache.get(bundle); return bundleCache.get(bundle);
@ -33,7 +33,7 @@ function bundleSubject(bundle) {
const fetcher = new rxjs.BehaviorSubject(Pending.of()); const fetcher = new rxjs.BehaviorSubject(Pending.of());
bundleCache.set(bundle, fetcher); bundleCache.set(bundle, fetcher);
fetch(`../bundles/${bundle}/bundle.js.map`).then((res) => { fetch(new URL(`bundles/${bundle}/bundle.js.map`, baseUrl).toString()).then((res) => {
res.body.cancel(); /* Bail on the download immediately - it could be big! */ res.body.cancel(); /* Bail on the download immediately - it could be big! */
const status = res.ok; const status = res.ok;
if (status) { if (status) {
@ -145,6 +145,7 @@ function ProgressBar({ fetchStatus }) {
* The main component. * The main component.
*/ */
function BundlePicker() { function BundlePicker() {
const [baseUrl, setBaseUrl] = React.useState(new URL("..", window.location).toString());
const [bundle, setBundle] = React.useState(""); const [bundle, setBundle] = React.useState("");
const [file, setFile] = React.useState(""); const [file, setFile] = React.useState("");
const [line, setLine] = React.useState("1"); const [line, setLine] = React.useState("1");
@ -153,19 +154,25 @@ function BundlePicker() {
const [bundleFetchStatus, setBundleFetchStatus] = React.useState(None); const [bundleFetchStatus, setBundleFetchStatus] = React.useState(None);
const [fileFetchStatus, setFileFetchStatus] = React.useState(None); const [fileFetchStatus, setFileFetchStatus] = React.useState(None);
/* At startup, try to fill in the bundle name for the user */ /* On baseUrl change, try to fill in the bundle name for the user */
React.useEffect(() => { React.useEffect(() => {
getBundleName().then((name) => { console.log("DEBUG", baseUrl);
getBundleName(baseUrl).then((name) => {
console.log("DEBUG", name);
if (bundle === "" && validateBundle(name) !== None) { if (bundle === "" && validateBundle(name) !== None) {
setBundle(name); setBundle(name);
} }
}, console.log.bind(console)); }, console.log.bind(console));
}, []); }, [baseUrl]);
/* ------------------------- */ /* ------------------------- */
/* Follow user state changes */ /* Follow user state changes */
/* ------------------------- */ /* ------------------------- */
const onBaseUrlChange = React.useCallback((event) => {
const value = event.target.value;
setBaseUrl(value);
}, []);
const onBundleChange = React.useCallback((event) => { const onBundleChange = React.useCallback((event) => {
const value = event.target.value; const value = event.target.value;
setBundle(value); setBundle(value);
@ -195,14 +202,14 @@ function BundlePicker() {
React.useEffect(() => React.useEffect(() =>
validateBundle(bundle).fold({ validateBundle(bundle).fold({
some: (value) => { some: (value) => {
const subscription = bundleSubject(value) const subscription = bundleSubject(baseUrl, value)
.pipe(rxjs.operators.map(Some.of)) .pipe(rxjs.operators.map(Some.of))
.subscribe(setBundleFetchStatus); .subscribe(setBundleFetchStatus);
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
}, },
none: () => setBundleFetchStatus(None), none: () => setBundleFetchStatus(None),
}), }),
[bundle]); [baseUrl, bundle]);
/* Whenever a valid javascript file is input, see if it corresponds to a sourcemap file and initiate a fetch /* Whenever a valid javascript file is input, see if it corresponds to a sourcemap file and initiate a fetch
* if so. */ * if so. */
@ -211,7 +218,7 @@ function BundlePicker() {
setFileFetchStatus(None); setFileFetchStatus(None);
return; return;
} }
const observable = fetchAsSubject(`../bundles/${bundle}/${file}.map`) const observable = fetchAsSubject(new URL(`bundles/${bundle}/${file}.map`, baseUrl).toString())
.pipe( .pipe(
rxjs.operators.map((fetchStatus) => fetchStatus.flatMap(value => { rxjs.operators.map((fetchStatus) => fetchStatus.flatMap(value => {
try { try {
@ -224,7 +231,7 @@ function BundlePicker() {
); );
const subscription = observable.subscribe(setFileFetchStatus); const subscription = observable.subscribe(setFileFetchStatus);
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
}, [bundle, file]); }, [baseUrl, bundle, file]);
/* /*
* Whenever we have a valid fetched sourcemap, and a valid line, attempt to find the original position from the * Whenever we have a valid fetched sourcemap, and a valid line, attempt to find the original position from the
@ -255,6 +262,16 @@ function BundlePicker() {
/* ------ */ /* ------ */
return e('div', {}, return e('div', {},
e('div', { className: 'inputs' }, e('div', { className: 'inputs' },
e('div', { className: 'baseUrl' },
e('label', { htmlFor: 'baseUrl'}, 'Base URL'),
e('input', {
name: 'baseUrl',
required: true,
pattern: ".+",
onChange: onBaseUrlChange,
value: baseUrl,
}),
),
e('div', { className: 'bundle' }, e('div', { className: 'bundle' },
e('label', { htmlFor: 'bundle'}, 'Bundle'), e('label', { htmlFor: 'bundle'}, 'Bundle'),
e('input', { e('input', {