2023-04-25 08:33:33 +01:00
|
|
|
function httpGet(url) {
|
2023-01-13 17:36:27 +00:00
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
request.open("GET", url, false);
|
|
|
|
request.send(null);
|
|
|
|
return request.responseText;
|
|
|
|
}
|
|
|
|
|
2023-04-02 10:06:02 +01:00
|
|
|
function httpGetAsyncWithEvent(event, url) {
|
|
|
|
fetch(url)
|
|
|
|
.then((response) => response.text())
|
|
|
|
.then((responseText) => {
|
|
|
|
|
|
|
|
if (responseText == null) {
|
|
|
|
// Pass to parent (UI), in case they can fulfil this request
|
|
|
|
event.data.requestedHandler = "UI";
|
|
|
|
parent.postMessage(event.data, '*', [event.ports[0]]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
handleResponse(event, responseText);
|
|
|
|
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
2023-04-11 19:03:56 +01:00
|
|
|
let res = {};
|
2023-04-02 10:06:02 +01:00
|
|
|
res.error = error;
|
2023-04-21 19:27:24 +01:00
|
|
|
handleResponse(event, JSON.stringify(res));
|
2023-04-02 10:06:02 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
function handleResponse(event, response) {
|
|
|
|
if (event == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-02-17 15:40:06 +00:00
|
|
|
// Handle empty or missing responses
|
2023-01-13 17:36:27 +00:00
|
|
|
if (response == null || response.length == 0) {
|
|
|
|
response = "{\"error\": \"Empty response\"}"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse response
|
|
|
|
let responseObj;
|
|
|
|
try {
|
|
|
|
responseObj = JSON.parse(response);
|
|
|
|
} catch (e) {
|
|
|
|
// Not all responses will be JSON
|
|
|
|
responseObj = response;
|
|
|
|
}
|
|
|
|
|
2023-04-21 19:50:01 +01:00
|
|
|
// GET_QDN_RESOURCE_URL has custom handling
|
|
|
|
const data = event.data;
|
|
|
|
if (data.action == "GET_QDN_RESOURCE_URL") {
|
|
|
|
if (responseObj == null || responseObj.status == null || responseObj.status == "NOT_PUBLISHED") {
|
|
|
|
responseObj = {};
|
|
|
|
responseObj.error = "Resource does not exist";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
responseObj = buildResourceUrl(data.service, data.name, data.identifier, data.path, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
// Respond to app
|
|
|
|
if (responseObj.error != null) {
|
|
|
|
event.ports[0].postMessage({
|
|
|
|
result: null,
|
|
|
|
error: responseObj
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
event.ports[0].postMessage({
|
|
|
|
result: responseObj,
|
|
|
|
error: null
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-17 22:58:14 +00:00
|
|
|
function buildResourceUrl(service, name, identifier, path, isLink) {
|
|
|
|
if (isLink == false) {
|
|
|
|
// If this URL isn't being used as a link, then we need to fetch the data
|
|
|
|
// synchronously, instead of showing the loading screen.
|
|
|
|
url = "/arbitrary/" + service + "/" + name;
|
|
|
|
if (identifier != null) url = url.concat("/" + identifier);
|
|
|
|
if (path != null) url = url.concat("?filepath=" + path);
|
|
|
|
}
|
|
|
|
else if (_qdnContext == "render") {
|
2023-01-29 11:18:00 +00:00
|
|
|
url = "/render/" + service + "/" + name;
|
|
|
|
if (path != null) url = url.concat((path.startsWith("/") ? "" : "/") + path);
|
|
|
|
if (identifier != null) url = url.concat("?identifier=" + identifier);
|
|
|
|
}
|
2023-03-03 11:57:07 +00:00
|
|
|
else if (_qdnContext == "gateway") {
|
2023-01-29 11:18:00 +00:00
|
|
|
url = "/" + service + "/" + name;
|
|
|
|
if (identifier != null) url = url.concat("/" + identifier);
|
|
|
|
if (path != null) url = url.concat((path.startsWith("/") ? "" : "/") + path);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// domainMap only serves websites right now
|
|
|
|
url = "/" + name;
|
|
|
|
if (path != null) url = url.concat((path.startsWith("/") ? "" : "/") + path);
|
|
|
|
}
|
2023-03-17 22:58:14 +00:00
|
|
|
|
|
|
|
if (isLink) url = url.concat((url.includes("?") ? "" : "?") + "&theme=" + _qdnTheme);
|
2023-03-03 18:16:35 +00:00
|
|
|
|
2023-01-29 11:18:00 +00:00
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
function extractComponents(url) {
|
2023-01-29 12:04:39 +00:00
|
|
|
if (!url.startsWith("qortal://")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-01-29 11:18:00 +00:00
|
|
|
url = url.replace(/^(qortal\:\/\/)/,"");
|
|
|
|
if (url.includes("/")) {
|
|
|
|
let parts = url.split("/");
|
|
|
|
const service = parts[0].toUpperCase();
|
|
|
|
parts.shift();
|
|
|
|
const name = parts[0];
|
|
|
|
parts.shift();
|
|
|
|
let identifier;
|
|
|
|
|
|
|
|
if (parts.length > 0) {
|
|
|
|
identifier = parts[0]; // Do not shift yet
|
|
|
|
// Check if a resource exists with this service, name and identifier combination
|
|
|
|
const url = "/arbitrary/resource/status/" + service + "/" + name + "/" + identifier;
|
|
|
|
const response = httpGet(url);
|
|
|
|
const responseObj = JSON.parse(response);
|
|
|
|
if (responseObj.totalChunkCount > 0) {
|
|
|
|
// Identifier exists, so don't include it in the path
|
|
|
|
parts.shift();
|
|
|
|
}
|
2023-01-29 13:38:08 +00:00
|
|
|
else {
|
|
|
|
identifier = null;
|
|
|
|
}
|
2023-01-29 11:18:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const path = parts.join("/");
|
|
|
|
|
2023-01-29 13:23:12 +00:00
|
|
|
const components = {};
|
2023-01-29 11:18:00 +00:00
|
|
|
components["service"] = service;
|
|
|
|
components["name"] = name;
|
|
|
|
components["identifier"] = identifier;
|
|
|
|
components["path"] = path;
|
|
|
|
return components;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-03-17 22:58:14 +00:00
|
|
|
function convertToResourceUrl(url, isLink) {
|
2023-01-29 12:04:39 +00:00
|
|
|
if (!url.startsWith("qortal://")) {
|
|
|
|
return null;
|
|
|
|
}
|
2023-01-29 11:18:00 +00:00
|
|
|
const c = extractComponents(url);
|
|
|
|
if (c == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-03-17 22:58:14 +00:00
|
|
|
return buildResourceUrl(c.service, c.name, c.identifier, c.path, isLink);
|
2023-01-29 11:18:00 +00:00
|
|
|
}
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
window.addEventListener("message", (event) => {
|
|
|
|
if (event == null || event.data == null || event.data.length == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (event.data.action == null) {
|
|
|
|
// This could be a response from the UI
|
|
|
|
handleResponse(event, event.data);
|
|
|
|
}
|
|
|
|
if (event.data.requestedHandler != null && event.data.requestedHandler === "UI") {
|
|
|
|
// This request was destined for the UI, so ignore it
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:43:00 +01:00
|
|
|
console.log("Core received action: " + JSON.stringify(event.data.action));
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
let url;
|
|
|
|
let data = event.data;
|
|
|
|
|
|
|
|
switch (data.action) {
|
|
|
|
case "GET_ACCOUNT_DATA":
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, "/addresses/" + data.address);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "GET_ACCOUNT_NAMES":
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, "/names/address/" + data.address);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
2023-05-12 11:17:09 +01:00
|
|
|
case "SEARCH_NAMES":
|
|
|
|
url = "/names/search?";
|
|
|
|
if (data.query != null) url = url.concat("&query=" + data.query);
|
|
|
|
if (data.prefix != null) url = url.concat("&prefix=" + new Boolean(data.prefix).toString());
|
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
|
|
|
return httpGetAsyncWithEvent(event, url);
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
case "GET_NAME_DATA":
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, "/names/" + data.name);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
Added "GET_QDN_RESOURCE_URL" Q-Apps action, to allow a website/app to programmatically determine the URL to retrieve any QDN resource it needs to access.
Examples:
### Get URL to load a QDN resource
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "THUMBNAIL",
name: "QortalDemo",
identifier: "qortal_avatar"
// path: "filename.jpg" // optional - not needed if resource contains only one file
});
```
### Get URL to load a QDN website
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "WEBSITE",
name: "QortalDemo",
});
```
### Get URL to load a specific file from a QDN website
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "WEBSITE",
name: "AlphaX",
path: "/assets/img/logo.png"
});
```
2023-01-29 11:44:59 +00:00
|
|
|
case "GET_QDN_RESOURCE_URL":
|
2023-04-21 20:05:24 +01:00
|
|
|
// Check status first; URL is built and returned automatically after status check
|
2023-04-21 19:50:01 +01:00
|
|
|
url = "/arbitrary/resource/status/" + data.service + "/" + data.name;
|
|
|
|
if (data.identifier != null) url = url.concat("/" + data.identifier);
|
|
|
|
return httpGetAsyncWithEvent(event, url);
|
Added "GET_QDN_RESOURCE_URL" Q-Apps action, to allow a website/app to programmatically determine the URL to retrieve any QDN resource it needs to access.
Examples:
### Get URL to load a QDN resource
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "THUMBNAIL",
name: "QortalDemo",
identifier: "qortal_avatar"
// path: "filename.jpg" // optional - not needed if resource contains only one file
});
```
### Get URL to load a QDN website
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "WEBSITE",
name: "QortalDemo",
});
```
### Get URL to load a specific file from a QDN website
```
let url = await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
service: "WEBSITE",
name: "AlphaX",
path: "/assets/img/logo.png"
});
```
2023-01-29 11:44:59 +00:00
|
|
|
|
2023-01-28 15:22:03 +00:00
|
|
|
case "LINK_TO_QDN_RESOURCE":
|
|
|
|
if (data.service == null) data.service = "WEBSITE"; // Default to WEBSITE
|
2023-03-17 22:58:14 +00:00
|
|
|
window.location = buildResourceUrl(data.service, data.name, data.identifier, data.path, true);
|
2023-04-11 19:03:56 +01:00
|
|
|
return;
|
2023-01-28 15:22:03 +00:00
|
|
|
|
2023-03-17 22:11:34 +00:00
|
|
|
case "LIST_QDN_RESOURCES":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/arbitrary/resources?";
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.service != null) url = url.concat("&service=" + data.service);
|
2023-03-24 10:31:35 +00:00
|
|
|
if (data.name != null) url = url.concat("&name=" + data.name);
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.identifier != null) url = url.concat("&identifier=" + data.identifier);
|
2023-03-17 22:11:34 +00:00
|
|
|
if (data.default != null) url = url.concat("&default=" + new Boolean(data.default).toString());
|
|
|
|
if (data.includeStatus != null) url = url.concat("&includestatus=" + new Boolean(data.includeStatus).toString());
|
|
|
|
if (data.includeMetadata != null) url = url.concat("&includemetadata=" + new Boolean(data.includeMetadata).toString());
|
2023-04-15 16:02:25 +01:00
|
|
|
if (data.nameListFilter != null) url = url.concat("&namefilter=" + data.nameListFilter);
|
2023-04-15 15:24:10 +01:00
|
|
|
if (data.followedOnly != null) url = url.concat("&followedonly=" + new Boolean(data.followedOnly).toString());
|
|
|
|
if (data.excludeBlocked != null) url = url.concat("&excludeblocked=" + new Boolean(data.excludeBlocked).toString());
|
2023-03-17 22:11:34 +00:00
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-03-17 22:11:34 +00:00
|
|
|
|
|
|
|
case "SEARCH_QDN_RESOURCES":
|
|
|
|
url = "/arbitrary/resources/search?";
|
|
|
|
if (data.service != null) url = url.concat("&service=" + data.service);
|
|
|
|
if (data.query != null) url = url.concat("&query=" + data.query);
|
|
|
|
if (data.identifier != null) url = url.concat("&identifier=" + data.identifier);
|
|
|
|
if (data.name != null) url = url.concat("&name=" + data.name);
|
2023-04-14 17:17:05 +01:00
|
|
|
if (data.names != null) data.names.forEach((x, i) => url = url.concat("&name=" + x));
|
2023-05-07 17:57:14 +01:00
|
|
|
if (data.title != null) url = url.concat("&title=" + data.title);
|
|
|
|
if (data.description != null) url = url.concat("&description=" + data.description);
|
2023-03-17 22:11:34 +00:00
|
|
|
if (data.prefix != null) url = url.concat("&prefix=" + new Boolean(data.prefix).toString());
|
2023-04-21 12:55:59 +01:00
|
|
|
if (data.exactMatchNames != null) url = url.concat("&exactmatchnames=" + new Boolean(data.exactMatchNames).toString());
|
2023-03-17 22:11:34 +00:00
|
|
|
if (data.default != null) url = url.concat("&default=" + new Boolean(data.default).toString());
|
2023-05-08 13:41:23 +01:00
|
|
|
if (data.mode != null) url = url.concat("&mode=" + data.mode);
|
2023-06-23 11:55:49 +01:00
|
|
|
if (data.minLevel != null) url = url.concat("&minlevel=" + data.minLevel);
|
2023-01-22 18:59:46 +00:00
|
|
|
if (data.includeStatus != null) url = url.concat("&includestatus=" + new Boolean(data.includeStatus).toString());
|
|
|
|
if (data.includeMetadata != null) url = url.concat("&includemetadata=" + new Boolean(data.includeMetadata).toString());
|
2023-04-15 16:02:25 +01:00
|
|
|
if (data.nameListFilter != null) url = url.concat("&namefilter=" + data.nameListFilter);
|
2023-04-15 15:24:10 +01:00
|
|
|
if (data.followedOnly != null) url = url.concat("&followedonly=" + new Boolean(data.followedOnly).toString());
|
|
|
|
if (data.excludeBlocked != null) url = url.concat("&excludeblocked=" + new Boolean(data.excludeBlocked).toString());
|
2023-05-08 12:46:15 +01:00
|
|
|
if (data.before != null) url = url.concat("&before=" + data.before);
|
|
|
|
if (data.after != null) url = url.concat("&after=" + data.after);
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "FETCH_QDN_RESOURCE":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/arbitrary/" + data.service + "/" + data.name;
|
|
|
|
if (data.identifier != null) url = url.concat("/" + data.identifier);
|
|
|
|
url = url.concat("?");
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.filepath != null) url = url.concat("&filepath=" + data.filepath);
|
2023-05-08 12:15:53 +01:00
|
|
|
if (data.rebuild != null) url = url.concat("&rebuild=" + new Boolean(data.rebuild).toString());
|
2023-03-03 15:39:37 +00:00
|
|
|
if (data.encoding != null) url = url.concat("&encoding=" + data.encoding);
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "GET_QDN_RESOURCE_STATUS":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/arbitrary/resource/status/" + data.service + "/" + data.name;
|
|
|
|
if (data.identifier != null) url = url.concat("/" + data.identifier);
|
2023-05-08 12:15:53 +01:00
|
|
|
url = url.concat("?");
|
|
|
|
if (data.build != null) url = url.concat("&build=" + new Boolean(data.build).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
2023-03-19 08:56:06 +00:00
|
|
|
case "GET_QDN_RESOURCE_PROPERTIES":
|
|
|
|
let identifier = (data.identifier != null) ? data.identifier : "default";
|
|
|
|
url = "/arbitrary/resource/properties/" + data.service + "/" + data.name + "/" + identifier;
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-03-19 08:56:06 +00:00
|
|
|
|
2023-04-28 10:57:04 +01:00
|
|
|
case "GET_QDN_RESOURCE_METADATA":
|
|
|
|
identifier = (data.identifier != null) ? data.identifier : "default";
|
|
|
|
url = "/arbitrary/metadata/" + data.service + "/" + data.name + "/" + identifier;
|
|
|
|
return httpGetAsyncWithEvent(event, url);
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
case "SEARCH_CHAT_MESSAGES":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/chat/messages?";
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.before != null) url = url.concat("&before=" + data.before);
|
|
|
|
if (data.after != null) url = url.concat("&after=" + data.after);
|
|
|
|
if (data.txGroupId != null) url = url.concat("&txGroupId=" + data.txGroupId);
|
|
|
|
if (data.involving != null) data.involving.forEach((x, i) => url = url.concat("&involving=" + x));
|
|
|
|
if (data.reference != null) url = url.concat("&reference=" + data.reference);
|
2023-01-22 18:59:46 +00:00
|
|
|
if (data.chatReference != null) url = url.concat("&chatreference=" + data.chatReference);
|
|
|
|
if (data.hasChatReference != null) url = url.concat("&haschatreference=" + new Boolean(data.hasChatReference).toString());
|
2023-04-29 17:48:58 +01:00
|
|
|
if (data.encoding != null) url = url.concat("&encoding=" + data.encoding);
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "LIST_GROUPS":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/groups?";
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "GET_BALANCE":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/addresses/balance/" + data.address;
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.assetId != null) url = url.concat("&assetId=" + data.assetId);
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "GET_AT":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/at" + data.atAddress;
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "GET_AT_DATA":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/at/" + data.atAddress + "/data";
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
case "LIST_ATS":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/at/byfunction/" + data.codeHash58 + "?";
|
2023-01-13 17:36:27 +00:00
|
|
|
if (data.isExecutable != null) url = url.concat("&isExecutable=" + data.isExecutable);
|
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
2023-01-19 20:05:46 +00:00
|
|
|
case "FETCH_BLOCK":
|
|
|
|
if (data.signature != null) {
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/blocks/" + data.signature;
|
2023-04-02 10:06:02 +01:00
|
|
|
} else if (data.height != null) {
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/blocks/byheight/" + data.height;
|
2023-01-19 20:05:46 +00:00
|
|
|
}
|
2023-01-22 18:59:46 +00:00
|
|
|
url = url.concat("?");
|
2023-01-19 20:05:46 +00:00
|
|
|
if (data.includeOnlineSignatures != null) url = url.concat("&includeOnlineSignatures=" + data.includeOnlineSignatures);
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-19 20:05:46 +00:00
|
|
|
|
|
|
|
case "FETCH_BLOCK_RANGE":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/blocks/range/" + data.height + "?";
|
2023-01-19 20:05:46 +00:00
|
|
|
if (data.count != null) url = url.concat("&count=" + data.count);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + data.reverse);
|
|
|
|
if (data.includeOnlineSignatures != null) url = url.concat("&includeOnlineSignatures=" + data.includeOnlineSignatures);
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-19 20:05:46 +00:00
|
|
|
|
2023-01-19 20:22:29 +00:00
|
|
|
case "SEARCH_TRANSACTIONS":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/transactions/search?";
|
2023-01-19 20:22:29 +00:00
|
|
|
if (data.startBlock != null) url = url.concat("&startBlock=" + data.startBlock);
|
|
|
|
if (data.blockLimit != null) url = url.concat("&blockLimit=" + data.blockLimit);
|
|
|
|
if (data.txGroupId != null) url = url.concat("&txGroupId=" + data.txGroupId);
|
|
|
|
if (data.txType != null) data.txType.forEach((x, i) => url = url.concat("&txType=" + x));
|
2023-01-22 18:59:46 +00:00
|
|
|
if (data.address != null) url = url.concat("&address=" + data.address);
|
2023-01-19 20:22:29 +00:00
|
|
|
if (data.confirmationStatus != null) url = url.concat("&confirmationStatus=" + data.confirmationStatus);
|
|
|
|
if (data.limit != null) url = url.concat("&limit=" + data.limit);
|
|
|
|
if (data.offset != null) url = url.concat("&offset=" + data.offset);
|
|
|
|
if (data.reverse != null) url = url.concat("&reverse=" + new Boolean(data.reverse).toString());
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-19 20:22:29 +00:00
|
|
|
|
2023-01-19 20:47:06 +00:00
|
|
|
case "GET_PRICE":
|
2023-01-22 18:59:46 +00:00
|
|
|
url = "/crosschain/price/" + data.blockchain + "?";
|
2023-01-19 20:47:06 +00:00
|
|
|
if (data.maxtrades != null) url = url.concat("&maxtrades=" + data.maxtrades);
|
|
|
|
if (data.inverse != null) url = url.concat("&inverse=" + data.inverse);
|
2023-04-11 19:03:56 +01:00
|
|
|
return httpGetAsyncWithEvent(event, url);
|
2023-01-19 20:47:06 +00:00
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
default:
|
|
|
|
// Pass to parent (UI), in case they can fulfil this request
|
|
|
|
event.data.requestedHandler = "UI";
|
|
|
|
parent.postMessage(event.data, '*', [event.ports[0]]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}, false);
|
|
|
|
|
2023-01-28 15:22:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Listen for and intercept all link click events
|
|
|
|
*/
|
|
|
|
function interceptClickEvent(e) {
|
|
|
|
var target = e.target || e.srcElement;
|
2023-01-29 11:18:00 +00:00
|
|
|
if (target.tagName !== 'A') {
|
|
|
|
target = target.closest('A');
|
|
|
|
}
|
|
|
|
if (target == null || target.getAttribute('href') == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let href = target.getAttribute('href');
|
|
|
|
if (href.startsWith("qortal://")) {
|
|
|
|
const c = extractComponents(href);
|
|
|
|
if (c != null) {
|
|
|
|
qortalRequest({
|
|
|
|
action: "LINK_TO_QDN_RESOURCE",
|
|
|
|
service: c.service,
|
|
|
|
name: c.name,
|
|
|
|
identifier: c.identifier,
|
|
|
|
path: c.path
|
|
|
|
});
|
2023-01-28 15:22:03 +00:00
|
|
|
}
|
2023-01-29 11:18:00 +00:00
|
|
|
e.preventDefault();
|
2023-01-28 15:22:03 +00:00
|
|
|
}
|
2023-03-31 13:03:46 +01:00
|
|
|
else if (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) {
|
|
|
|
// Block external links
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
2023-01-28 15:22:03 +00:00
|
|
|
}
|
|
|
|
if (document.addEventListener) {
|
|
|
|
document.addEventListener('click', interceptClickEvent);
|
|
|
|
}
|
|
|
|
else if (document.attachEvent) {
|
|
|
|
document.attachEvent('onclick', interceptClickEvent);
|
|
|
|
}
|
|
|
|
|
2023-02-17 15:40:06 +00:00
|
|
|
|
2023-04-09 17:11:20 +01:00
|
|
|
|
2023-01-29 11:18:00 +00:00
|
|
|
/**
|
|
|
|
* Intercept image loads from the DOM
|
|
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
2023-01-29 12:12:47 +00:00
|
|
|
const imgElements = document.querySelectorAll('img');
|
|
|
|
imgElements.forEach((img) => {
|
|
|
|
let url = img.src;
|
2023-03-17 22:58:14 +00:00
|
|
|
const newUrl = convertToResourceUrl(url, false);
|
2023-01-29 12:12:47 +00:00
|
|
|
if (newUrl != null) {
|
|
|
|
document.querySelector('img').src = newUrl;
|
|
|
|
}
|
|
|
|
});
|
2023-01-29 11:18:00 +00:00
|
|
|
});
|
|
|
|
|
2023-01-29 12:04:39 +00:00
|
|
|
/**
|
|
|
|
* Intercept img src updates
|
|
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
2023-01-29 12:12:47 +00:00
|
|
|
const imgElements = document.querySelectorAll('img');
|
|
|
|
imgElements.forEach((img) => {
|
|
|
|
let observer = new MutationObserver((changes) => {
|
|
|
|
changes.forEach(change => {
|
|
|
|
if (change.attributeName.includes('src')) {
|
2023-03-17 22:58:14 +00:00
|
|
|
const newUrl = convertToResourceUrl(img.src, false);
|
2023-01-29 12:12:47 +00:00
|
|
|
if (newUrl != null) {
|
|
|
|
document.querySelector('img').src = newUrl;
|
|
|
|
}
|
2023-01-29 12:04:39 +00:00
|
|
|
}
|
2023-01-29 12:12:47 +00:00
|
|
|
});
|
2023-01-29 12:04:39 +00:00
|
|
|
});
|
2023-01-29 12:12:47 +00:00
|
|
|
observer.observe(img, {attributes: true});
|
2023-01-29 12:04:39 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-01-29 11:18:00 +00:00
|
|
|
|
2023-01-28 15:22:03 +00:00
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
const awaitTimeout = (timeout, reason) =>
|
|
|
|
new Promise((resolve, reject) =>
|
|
|
|
setTimeout(
|
|
|
|
() => (reason === undefined ? resolve() : reject(reason)),
|
|
|
|
timeout
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2023-01-29 13:07:26 +00:00
|
|
|
function getDefaultTimeout(action) {
|
|
|
|
if (action != null) {
|
|
|
|
// Some actions need longer default timeouts, especially those that create transactions
|
|
|
|
switch (action) {
|
2023-03-03 13:20:17 +00:00
|
|
|
case "GET_USER_ACCOUNT":
|
2023-05-05 18:30:14 +01:00
|
|
|
case "SAVE_FILE":
|
|
|
|
case "DECRYPT_DATA":
|
2023-03-03 13:20:17 +00:00
|
|
|
// User may take a long time to accept/deny the popup
|
|
|
|
return 60 * 60 * 1000;
|
|
|
|
|
2023-07-28 21:47:29 +01:00
|
|
|
case "SEARCH_QDN_RESOURCES":
|
|
|
|
// Searching for data can be slow, especially when metadata and statuses are also being included
|
|
|
|
return 30 * 1000;
|
|
|
|
|
2023-01-29 13:07:26 +00:00
|
|
|
case "FETCH_QDN_RESOURCE":
|
|
|
|
// Fetching data can take a while, especially if the status hasn't been checked first
|
|
|
|
return 60 * 1000;
|
|
|
|
|
|
|
|
case "PUBLISH_QDN_RESOURCE":
|
2023-05-05 13:22:14 +01:00
|
|
|
case "PUBLISH_MULTIPLE_QDN_RESOURCES":
|
2023-01-29 13:07:26 +00:00
|
|
|
// Publishing could take a very long time on slow system, due to the proof-of-work computation
|
|
|
|
return 60 * 60 * 1000;
|
|
|
|
|
|
|
|
case "SEND_CHAT_MESSAGE":
|
|
|
|
// Chat messages rely on PoW computations, so allow extra time
|
|
|
|
return 60 * 1000;
|
|
|
|
|
|
|
|
case "JOIN_GROUP":
|
|
|
|
case "DEPLOY_AT":
|
|
|
|
case "SEND_COIN":
|
|
|
|
// Allow extra time for other actions that create transactions, even if there is no PoW
|
2023-03-29 18:47:03 +01:00
|
|
|
return 5 * 60 * 1000;
|
2023-01-29 13:07:26 +00:00
|
|
|
|
2023-05-25 04:41:03 -04:00
|
|
|
case "GET_WALLET_BALANCE":
|
|
|
|
// Getting a wallet balance can take a while, if there are many transactions
|
|
|
|
return 2 * 60 * 1000;
|
|
|
|
|
2023-01-29 13:07:26 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 10 * 1000;
|
|
|
|
}
|
|
|
|
|
2023-01-13 17:36:27 +00:00
|
|
|
/**
|
|
|
|
* Make a Qortal (Q-Apps) request with no timeout
|
|
|
|
*/
|
|
|
|
const qortalRequestWithNoTimeout = (request) => new Promise((res, rej) => {
|
|
|
|
const channel = new MessageChannel();
|
|
|
|
|
|
|
|
channel.port1.onmessage = ({data}) => {
|
|
|
|
channel.port1.close();
|
|
|
|
|
|
|
|
if (data.error) {
|
|
|
|
rej(data.error);
|
|
|
|
} else {
|
|
|
|
res(data.result);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.postMessage(request, '*', [channel.port2]);
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make a Qortal (Q-Apps) request with the default timeout (10 seconds)
|
|
|
|
*/
|
|
|
|
const qortalRequest = (request) =>
|
2023-01-29 13:07:26 +00:00
|
|
|
Promise.race([qortalRequestWithNoTimeout(request), awaitTimeout(getDefaultTimeout(request.action), "The request timed out")]);
|
2023-01-13 17:36:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Make a Qortal (Q-Apps) request with a custom timeout, specified in milliseconds
|
|
|
|
*/
|
|
|
|
const qortalRequestWithTimeout = (request, timeout) =>
|
2023-04-15 09:57:26 +01:00
|
|
|
Promise.race([qortalRequestWithNoTimeout(request), awaitTimeout(timeout, "The request timed out")]);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send current page details to UI
|
|
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
qortalRequest({
|
|
|
|
action: "QDN_RESOURCE_DISPLAYED",
|
|
|
|
service: _qdnService,
|
|
|
|
name: _qdnName,
|
|
|
|
identifier: _qdnIdentifier,
|
|
|
|
path: _qdnPath
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle app navigation
|
|
|
|
*/
|
|
|
|
navigation.addEventListener('navigate', (event) => {
|
|
|
|
const url = new URL(event.destination.url);
|
|
|
|
let fullpath = url.pathname + url.hash;
|
|
|
|
qortalRequest({
|
|
|
|
action: "QDN_RESOURCE_DISPLAYED",
|
|
|
|
service: _qdnService,
|
|
|
|
name: _qdnName,
|
|
|
|
identifier: _qdnIdentifier,
|
|
|
|
path: (fullpath.startsWith(_qdnBase)) ? fullpath.slice(_qdnBase.length) : fullpath
|
|
|
|
});
|
|
|
|
});
|