Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve viewer handling errors #984

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions packages/viewer/src/latex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ async function replaceLatexInTextNode(properties: Properties, node: Node) {
// Get LaTeX text.
const latex = textContent.substring(nextLatexPosition.start + "$$".length, nextLatexPosition.end);
// Convert LaTeX to mathml.
const response = await latexToMathml(latex, properties.editorServicesRoot, properties.editorServicesExtension);
let responseText;
try {
const response = await latexToMathml(latex, properties.editorServicesRoot, properties.editorServicesExtension);
responseText = response.text;
} catch (e) {
responseText = "Error converting LaTeX to MathML";
console.error(responseText + " " + e);
}
// Insert mathml node.
const fragment = document.createRange().createContextualFragment(response.text);
const fragment = document.createRange().createContextualFragment(responseText);

node.parentNode?.insertBefore(fragment, node);
node.nodeValue = node.nodeValue.substring(nextLatexPosition.start, nextLatexPosition.end);
Expand Down
4 changes: 2 additions & 2 deletions packages/viewer/src/mathml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export async function renderMathML(properties: Properties, root: HTMLElement): P
const img = await setImageProperties(properties, imgSource, mml);
// Replace the MathML for the generated formula image.
mathElement.parentNode?.replaceChild(img, mathElement);
} catch {
console.error(`Cannot render ${mml}: invalid MathML format.`);
} catch (e) {
console.error(`Cannot render ${mml}: ${e}`);
continue;
}
}
Expand Down
96 changes: 44 additions & 52 deletions packages/viewer/src/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,19 @@ export class StatusError extends Error {
* Helper function to process responses from the editor services.
* These usually come wrapped in a JSON with a status field that can be either "ok" or "warning".
* If status is "ok", return the result value along it. Otherwise, throw a StatusError.
* @param {Promise<Response>} response - The response given by the service.
* @param {Response} response - The response given by the service.
* @returns {Promise<any>} The unwrapped result of the response, if valid.
* @throws {StatusError} Service responded with a non-ok status.
* If the response.json() fails, it'll return a generic exception.
*/
export async function processJsonResponse(response: Promise<Response>): Promise<any> {
try {
const { status, result } = await (await response).json();

if (status !== "ok") {
throw new StatusError("Service responded with a non-ok status");
}
async function processJsonResponse(response: Response): Promise<any> {
const { status, result } = await response.json();

return result;
} catch (e) {
// TODO manage network and status non-ok errors
throw e;
if (status !== "ok") {
throw new StatusError("Service responded with a non-ok status");
}

return result;
}

/**
Expand All @@ -54,36 +50,31 @@ export async function callService(
serverURL: string,
extension: string,
): Promise<any> {
try {
const url = new URL(serviceName + extension, serverURL);

// Getting the configuration is asynchronous since we make some requests.
const properties = await Properties.getInstance();
const headers = {
"Content-type": "application/x-www-form-urlencoded; charset=utf-8",
...properties.config.backendConfig.wiriscustomheaders,
};

const init: RequestInit = {
method,
headers,
};

if (method === MethodType.Get) {
// Add the query as search params
for (const [key, value] of Object.entries(query)) {
url.searchParams.set(key, value);
}
} else {
// Add the query as the body of the request
init.body = new URLSearchParams({ ...query });
}
const url = new URL(serviceName + extension, serverURL);

return fetch(url.toString(), init);
} catch (e) {
// TODO manage network and status non-ok errors
throw e;
// Getting the configuration is asynchronous since we make some requests.
const properties = await Properties.getInstance();
const headers = {
"Content-type": "application/x-www-form-urlencoded; charset=utf-8",
...properties.config.backendConfig.wiriscustomheaders,
};

const init: RequestInit = {
method,
headers,
};

if (method === MethodType.Get) {
// Add the query as search params
for (const [key, value] of Object.entries(query)) {
url.searchParams.set(key, value);
}
} else {
// Add the query as the body of the request
init.body = new URLSearchParams({ ...query });
}

return await fetch(url.toString(), init);
}

/**
Expand All @@ -105,7 +96,7 @@ export async function mathml2accessible(mml: string, lang: string, url: string,
ignoreStyles: "true",
};

const response = callService(params, "service", MethodType.Post, url, extension);
const response = await callService(params, "service", MethodType.Post, url, extension);
return processJsonResponse(response);
}

Expand All @@ -127,20 +118,17 @@ export async function showImage(mml: string, lang: string, url: string, extensio

// Try to obtain the image via GET
const getParams = Parser.createShowImageSrcData(params, params.lang);
const getResponse = callService(getParams, "showimage", MethodType.Get, url, extension);
const showImageResponse = await callService(getParams, "showimage", MethodType.Get, url, extension);
try {
return await processJsonResponse(getResponse);
return await processJsonResponse(showImageResponse);
} catch (e) {
if (e instanceof StatusError) {
// Formula was not in cache; proceed with calling showimage via POST
// If GET request fails, it means that the formula was not in cache. Proceed to create the image:
return createImage(mml, lang, url, extension);
} else {
throw e;
}
}

// If GET request fails, it means that the formula was not in cache. Proceed with POST:
const response = callService(params, "showimage", MethodType.Post, url, extension);
return processJsonResponse(response);
}

/**
Expand All @@ -160,7 +148,7 @@ export async function createImage(mml: string, lang: string, url: string, extens
};

// POST request to retrieve the corresponding image.
const response = callService(params, "showimage", MethodType.Post, url, extension);
const response = await callService(params, "showimage", MethodType.Post, url, extension);
return processJsonResponse(response);
}

Expand All @@ -177,7 +165,7 @@ export async function latexToMathml(latex: string, url: string, extension: strin
latex: latex,
};

const response = callService(params, "service", MethodType.Post, url, extension);
const response = await callService(params, "service", MethodType.Post, url, extension);
return processJsonResponse(response);
}

Expand All @@ -192,6 +180,10 @@ export async function configurationJson(variablekeys: string[], url: string, ext
variablekeys: variablekeys.join(","),
};

const response = callService(params, "configurationjson", MethodType.Get, url, extension);
return processJsonResponse(response);
try {
const response = await callService(params, "configurationjson", MethodType.Get, url, extension);
return processJsonResponse(response);
} catch (e) {
return e;
}
}
Loading