mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
1902 lines
47 KiB
JavaScript
Executable File
1902 lines
47 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Listener class
|
|
class Listener {
|
|
|
|
// Public
|
|
|
|
// Constructor
|
|
constructor(settings) {
|
|
|
|
// Set settings
|
|
this.settings = settings;
|
|
|
|
// Set connection to no connection
|
|
this.connection = Listener.NO_CONNECTION;
|
|
|
|
// Set retry delay to initial value
|
|
this.retryDelay = Listener.INITIAL_RETRY_DELAY_MILLISECONDS;
|
|
|
|
// Set request index
|
|
this.requestIndex = 0;
|
|
|
|
// Set reconnect timeout to no timeout
|
|
this.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
|
|
// Set started to false
|
|
this.started = false;
|
|
|
|
// Set connected to false
|
|
this.connected = false;
|
|
|
|
// Set use custom listener to setting's default value
|
|
this.useCustomListener = Listener.SETTINGS_USE_CUSTOM_LISTENER_DEFAULT_VALUE;
|
|
|
|
// Set custom listener address to setting's default value
|
|
this.customListenerAddress = Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_DEFAULT_VALUE;
|
|
|
|
// Set ignore response index
|
|
this.ignoreResponseIndex = 0;
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Once database is initialized
|
|
Database.onceInitialized(function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return creating settings
|
|
return Promise.all([
|
|
|
|
// Use custom listener setting
|
|
self.settings.createValue(Listener.SETTINGS_USE_CUSTOM_LISTENER_NAME, Listener.SETTINGS_USE_CUSTOM_LISTENER_DEFAULT_VALUE),
|
|
|
|
// Custom listener address setting
|
|
self.settings.createValue(Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_NAME, Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_DEFAULT_VALUE)
|
|
|
|
]).then(function() {
|
|
|
|
// Initialize settings
|
|
var settings = [
|
|
|
|
// Use custom listener setting
|
|
Listener.SETTINGS_USE_CUSTOM_LISTENER_NAME,
|
|
|
|
// Custom listener address setting
|
|
Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_NAME
|
|
];
|
|
|
|
// Return getting settings' values
|
|
return Promise.all(settings.map(function(setting) {
|
|
|
|
// Return getting setting's value
|
|
return self.settings.getValue(setting);
|
|
|
|
})).then(function(settingValues) {
|
|
|
|
// Set use custom listener to setting's value
|
|
self.useCustomListener = settingValues[settings.indexOf(Listener.SETTINGS_USE_CUSTOM_LISTENER_NAME)];
|
|
|
|
// Set custom listener address to setting's value
|
|
self.customListenerAddress = settingValues[settings.indexOf(Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_NAME)];
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject
|
|
reject();
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject
|
|
reject();
|
|
});
|
|
});
|
|
});
|
|
|
|
// Settings change event
|
|
$(this.settings).on(Settings.CHANGE_EVENT, function(event, setting) {
|
|
|
|
// Initialize listener setting changes
|
|
var listenerSettingChanged = false;
|
|
|
|
// Check what setting was changes
|
|
switch(setting[Settings.DATABASE_SETTING_NAME]) {
|
|
|
|
// Use custom listener setting
|
|
case Listener.SETTINGS_USE_CUSTOM_LISTENER_NAME:
|
|
|
|
// Set use custom listener to setting's value
|
|
self.useCustomListener = setting[Settings.DATABASE_VALUE_NAME];
|
|
|
|
// Set listener settings changed
|
|
listenerSettingChanged = true;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Custom listener address setting
|
|
case Listener.SETTINGS_CUSTOM_LISTENER_ADDRESS_NAME:
|
|
|
|
// Set custom listener address to setting's value
|
|
self.customListenerAddress = setting[Settings.DATABASE_VALUE_NAME];
|
|
|
|
// Set listener settings changed
|
|
listenerSettingChanged = true;
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
|
|
// Check if a listener setting was changed
|
|
if(listenerSettingChanged === true) {
|
|
|
|
// Check if connected
|
|
if(self.connected === true) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Listener settings changed. Disconnecting from the listener.'));
|
|
}
|
|
|
|
// Check if connection exists
|
|
if(self.connection !== Listener.NO_CONNECTION) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Close connection
|
|
self.connection.close();
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
}
|
|
|
|
// Set connection to no connection
|
|
self.connection = Listener.NO_CONNECTION;
|
|
}
|
|
|
|
// Check if reconnect timeout exists
|
|
if(self.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(self.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
}
|
|
|
|
// Reset retry delay
|
|
self.retryDelay = Listener.INITIAL_RETRY_DELAY_MILLISECONDS;
|
|
|
|
// Trigger settings change event
|
|
$(self).trigger(Listener.SETTINGS_CHANGE_EVENT);
|
|
|
|
// Clear connected
|
|
self.connected = false;
|
|
|
|
// Connect
|
|
self.connect();
|
|
}
|
|
});
|
|
|
|
// Window online event
|
|
$(window).on("online", function() {
|
|
|
|
// Check if reconnect timeout exists
|
|
if(self.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(self.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
|
|
// Reset retry delay
|
|
self.retryDelay = Listener.INITIAL_RETRY_DELAY_MILLISECONDS;
|
|
|
|
// Connect
|
|
self.connect();
|
|
}
|
|
|
|
// Window offline event
|
|
}).on("offline", function() {
|
|
|
|
// Check if started
|
|
if(self.started === true) {
|
|
|
|
// Check if connected
|
|
if(self.connected === true) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Network changed. Disconnecting from the listener.'));
|
|
}
|
|
|
|
// Check if connection exists
|
|
if(self.connection !== Listener.NO_CONNECTION) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Close connection
|
|
self.connection.close();
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
}
|
|
|
|
// Set connection to no connection
|
|
self.connection = Listener.NO_CONNECTION;
|
|
}
|
|
|
|
// Check if reconnect timeout exists
|
|
if(self.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(self.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
}
|
|
|
|
// Reset retry delay
|
|
self.retryDelay = Listener.INITIAL_RETRY_DELAY_MILLISECONDS;
|
|
|
|
// Clear connected
|
|
self.connected = false;
|
|
|
|
// Connect
|
|
self.connect();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Using custom listener
|
|
usingCustomListener() {
|
|
|
|
// Return if using a custom listener
|
|
return this.useCustomListener === true;
|
|
}
|
|
|
|
// Get address
|
|
getAddress() {
|
|
|
|
// Check if not using a custom listener
|
|
if(this.usingCustomListener() === false) {
|
|
|
|
// Return default listener address
|
|
return Listener.DEFAULT_LISTENER_ADDRESS;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Get custom listener address
|
|
var customListenerAddress = this.customListenerAddress.trim();
|
|
|
|
// Check if custom listener address isn't set
|
|
if(customListenerAddress["length"] === 0) {
|
|
|
|
// Return custom listener address
|
|
return customListenerAddress;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if custom listener address doesn't have a protocol
|
|
if(Common.urlContainsProtocol(customListenerAddress) === false) {
|
|
|
|
// Add protocol to custom listener address
|
|
customListenerAddress = Common.WEBSOCKET_PROTOCOL + "//" + customListenerAddress;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Initialize error occurred
|
|
var errorOccurred = false;
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse custom listener address as a URL
|
|
var parsedUrl = new URL(customListenerAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Set error occurred
|
|
errorOccurred = true;
|
|
}
|
|
|
|
// Check if an error didn't occur
|
|
if(errorOccurred === false) {
|
|
|
|
// Check if URL's protocol is HTTP
|
|
if(parsedUrl["protocol"] === Common.HTTP_PROTOCOL) {
|
|
|
|
// Change custom listener address's protocol to WebSocket
|
|
customListenerAddress = Common.WEBSOCKET_PROTOCOL + Common.ltrim(customListenerAddress).substring(Common.HTTP_PROTOCOL["length"]);
|
|
}
|
|
|
|
// Otherwise check if URL's protocol is HTTPS
|
|
else if(parsedUrl["protocol"] === Common.HTTPS_PROTOCOL) {
|
|
|
|
// Change custom listener address's protocol to WebSocket secure
|
|
customListenerAddress = Common.WEBSOCKET_SECURE_PROTOCOL + Common.ltrim(customListenerAddress).substring(Common.HTTPS_PROTOCOL["length"]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return custom listener address upgraded if applicable and without any trailing slashes
|
|
return Common.removeTrailingSlashes(Common.upgradeApplicableInsecureUrl(customListenerAddress));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start
|
|
start() {
|
|
|
|
// Check if not already started
|
|
if(this.started === false) {
|
|
|
|
// Set started
|
|
this.started = true;
|
|
|
|
// Connect
|
|
this.connect();
|
|
}
|
|
}
|
|
|
|
// Create URL
|
|
createUrl() {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return sending request to create URL
|
|
return self.sendRequest({
|
|
|
|
// Request
|
|
"Request": Listener.CREATE_URL_REQUEST_NAME
|
|
|
|
}).then(function(url) {
|
|
|
|
// Check if URL is valid
|
|
if(typeof url === "string")
|
|
|
|
// Resolve URL
|
|
resolve(url);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject("Creating URL failed.");
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject("Connecting to the listener failed.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject("Creating URL timed out.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid response error or default
|
|
case Listener.INVALID_RESPONSE_ERROR:
|
|
default:
|
|
|
|
// Reject error
|
|
reject("Creating URL failed.");
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Change URL
|
|
changeUrl(url) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if connected
|
|
if(self.isConnected() === true) {
|
|
|
|
// Return sending request to change URL
|
|
return self.sendRequest({
|
|
|
|
// Request
|
|
"Request": Listener.CHANGE_URL_REQUEST_NAME,
|
|
|
|
// URL
|
|
"URL": url
|
|
|
|
}).then(function(url) {
|
|
|
|
// Check if URL is valid
|
|
if(typeof url === "string")
|
|
|
|
// Resolve URL
|
|
resolve(url);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject(Message.createText(Language.getDefaultTranslation('Changing the address suffix failed.')));
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject(Message.createText(Language.getDefaultTranslation('Connecting to the listener failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You won\'t be able to change address suffixes without being connected to a listener.')));
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject(Message.createText(Language.getDefaultTranslation('Changing the address suffix timed out.')));
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid response error or default
|
|
case Listener.INVALID_RESPONSE_ERROR:
|
|
default:
|
|
|
|
// Reject error
|
|
reject(Message.createText(Language.getDefaultTranslation('Changing the address suffix failed.')));
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject error
|
|
reject(Message.createText(Language.getDefaultTranslation('You aren\'t connected to a listener.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You won\'t be able to change address suffixes without being connected to a listener.')));
|
|
}
|
|
});
|
|
}
|
|
|
|
// Owns URL
|
|
ownsUrl(url) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return sending request to see if owns the URL
|
|
return self.sendRequest({
|
|
|
|
// Request
|
|
"Request": Listener.OWN_URL_REQUEST_NAME,
|
|
|
|
// URL
|
|
"URL": url
|
|
|
|
}).then(function(ownsUrl) {
|
|
|
|
// Check if owns URL is valid
|
|
if(typeof ownsUrl === "boolean")
|
|
|
|
// Resolve owns URL
|
|
resolve(ownsUrl);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject("Checking if owns URL failed.");
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject("Connecting to the listener failed.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject("Checking if owns URL timed out.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid response error or default
|
|
case Listener.INVALID_RESPONSE_ERROR:
|
|
default:
|
|
|
|
// Reject error
|
|
reject("Checking if owns URL failed.");
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Delete URL
|
|
deleteUrl(url) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return sending request to delete URL
|
|
return self.sendRequest({
|
|
|
|
// Request
|
|
"Request": Listener.DELETE_URL_REQUEST_NAME,
|
|
|
|
// URL
|
|
"URL": url
|
|
|
|
}).then(function(deletedUrl) {
|
|
|
|
// Check if deleted URL is valid
|
|
if(typeof deletedUrl === "boolean")
|
|
|
|
// Resolve deleted URL
|
|
resolve(deletedUrl);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject("Deleting URL failed.");
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject("Connecting to the listener failed.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject("Deleting URL timed out.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid response error
|
|
case Listener.INVALID_RESPONSE_ERROR:
|
|
|
|
// Resolve false
|
|
resolve(false);
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Default
|
|
default:
|
|
|
|
// Reject error
|
|
reject("Deleting URL failed.");
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Respond with data
|
|
respondWithData(interaction, data) {
|
|
|
|
// Turn off status receive listener cancel interaction event
|
|
$(this).off(Listener.STATUS_RECEIVE_EVENT + ".listenerCancel" + interaction.toFixed());
|
|
|
|
// Turn off settings change listener cancel interaction event
|
|
$(this).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerCancel" + interaction.toFixed());
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return sending response
|
|
return self.sendResponse({
|
|
|
|
// Interaction
|
|
"Interaction": interaction,
|
|
|
|
// Type
|
|
"Type": (Object.isObject(data) === true) ? "application/json" : "text/plain",
|
|
|
|
// Data
|
|
"Data": Base64.fromUint8Array((new TextEncoder()).encode((Object.isObject(data) === true) ? JSONBigNumber.stringify(data) : data)),
|
|
|
|
// Status
|
|
"Status": Common.HTTP_OK_STATUS
|
|
|
|
}).then(function(status) {
|
|
|
|
// Check if status is valid
|
|
if(typeof status === "string")
|
|
|
|
// Resolve if status succeeded
|
|
resolve(status === Listener.STATUS_SUCCEEDED_VALUE);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject("Sending response failed.");
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject("Connecting to the listener failed.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject("Sending response timed out.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid status error or default
|
|
case Listener.INVALID_STATUS_ERROR:
|
|
default:
|
|
|
|
// Reject error
|
|
reject("Sending response failed.");
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Respond with error
|
|
respondWithError(interaction, data) {
|
|
|
|
// Turn off status receive listener cancel interaction event
|
|
$(this).off(Listener.STATUS_RECEIVE_EVENT + ".listenerCancel" + interaction.toFixed());
|
|
|
|
// Turn off settings change listener cancel interaction event
|
|
$(this).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerCancel" + interaction.toFixed());
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Set status to HTTP ok status
|
|
var status = Common.HTTP_OK_STATUS;
|
|
|
|
// Check if data is a status response
|
|
if(typeof data === "number") {
|
|
|
|
// Check data
|
|
switch(data) {
|
|
|
|
// Ok response
|
|
case Listener.OK_RESPONSE:
|
|
|
|
// Set status to HTTP ok status
|
|
status = Common.HTTP_OK_STATUS;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Unauthoirzed response
|
|
case Listener.UNAUTHORIZED_RESPONSE:
|
|
|
|
// Set status to HTTP unauthorized status
|
|
status = Common.HTTP_UNAUTHORIZED_STATUS;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Forbidden response
|
|
case Listener.FORBIDDEN_RESPONSE:
|
|
|
|
// Set status to HTTP forbidden status
|
|
status = Common.HTTP_FORBIDDEN_STATUS;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Not found response
|
|
case Listener.NOT_FOUND_RESPONSE:
|
|
|
|
// Set status to HTTP not found status
|
|
status = Common.HTTP_NOT_FOUND_STATUS;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Unsupported media type response
|
|
case Listener.UNSUPPORTED_MEDIA_TYPE_RESPONSE:
|
|
|
|
// Set status to HTTP unsupported media type status
|
|
status = Common.HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS;
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return sending response
|
|
return self.sendResponse({
|
|
|
|
// Interaction
|
|
"Interaction": interaction,
|
|
|
|
// Type
|
|
"Type": (Object.isObject(data) === true) ? "application/json" : "text/plain",
|
|
|
|
// Data
|
|
"Data": Base64.fromUint8Array((new TextEncoder()).encode((Object.isObject(data) === true) ? JSONBigNumber.stringify(data) : ((typeof data === "number") ? "" : data))),
|
|
|
|
// Status
|
|
"Status": status
|
|
|
|
}).then(function(status) {
|
|
|
|
// Check if status is valid
|
|
if(typeof status === "string")
|
|
|
|
// Resolve true
|
|
resolve(true);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Reject error
|
|
reject("Sending response failed.");
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Connection error
|
|
case Listener.CONNECTION_ERROR:
|
|
|
|
// Reject error
|
|
reject("Connecting to the listener failed.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Timeout error
|
|
case Listener.TIMEOUT_ERROR:
|
|
|
|
// Reject error
|
|
reject("Sending response timed out.");
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid status error or default
|
|
case Listener.INVALID_STATUS_ERROR:
|
|
default:
|
|
|
|
// Reject error
|
|
reject("Sending response failed.");
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Connection open event
|
|
static get CONNECTION_OPEN_EVENT() {
|
|
|
|
// Return connection open event
|
|
return "ListenerConnectionOpenEvent";
|
|
}
|
|
|
|
// Connection close event
|
|
static get CONNECTION_CLOSE_EVENT() {
|
|
|
|
// Return connection close event
|
|
return "ListenerConnectionCloseEvent";
|
|
}
|
|
|
|
// Request receive event
|
|
static get REQUEST_RECEIVE_EVENT() {
|
|
|
|
// Return request receive event
|
|
return "ListenerRequestReceiveEvent";
|
|
}
|
|
|
|
// No connection close type
|
|
static get NO_CONNECTION_CLOSE_TYPE() {
|
|
|
|
// Return no connection close type
|
|
return 0;
|
|
}
|
|
|
|
// Disconnected close type
|
|
static get DISCONNECTED_CLOSE_TYPE() {
|
|
|
|
// Return disconnected close type
|
|
return Listener.NO_CONNECTION_CLOSE_TYPE + 1;
|
|
}
|
|
|
|
// Ok response
|
|
static get OK_RESPONSE() {
|
|
|
|
// Return ok response
|
|
return 0;
|
|
}
|
|
|
|
// Unauthorized response
|
|
static get UNAUTHORIZED_RESPONSE() {
|
|
|
|
// Return unauthorized response
|
|
return Listener.OK_RESPONSE + 1;
|
|
}
|
|
|
|
// Forbidden response
|
|
static get FORBIDDEN_RESPONSE() {
|
|
|
|
// Return forbidden response
|
|
return Listener.UNAUTHORIZED_RESPONSE + 1;
|
|
}
|
|
|
|
// Not found response
|
|
static get NOT_FOUND_RESPONSE() {
|
|
|
|
// Return not found response
|
|
return Listener.FORBIDDEN_RESPONSE + 1;
|
|
}
|
|
|
|
// Unsupported media type response
|
|
static get UNSUPPORTED_MEDIA_TYPE_RESPONSE() {
|
|
|
|
// Return unsupported media type response
|
|
return Listener.NOT_FOUND_RESPONSE + 1;
|
|
}
|
|
|
|
// Settings change event
|
|
static get SETTINGS_CHANGE_EVENT() {
|
|
|
|
// Return settings change event
|
|
return "ListenerSettingsChangeEvent";
|
|
}
|
|
|
|
// Promise resolve wallet index
|
|
static get PROMISE_RESOLVE_WALLET_INDEX() {
|
|
|
|
// Return promise resolve wallet index
|
|
return 0;
|
|
}
|
|
|
|
// Promise resolve amount index
|
|
static get PROMISE_RESOLVE_AMOUNT_INDEX() {
|
|
|
|
// Return promise resolve amount index
|
|
return Listener.PROMISE_RESOLVE_WALLET_INDEX + 1;
|
|
}
|
|
|
|
// Promise resolve currency index
|
|
static get PROMISE_RESOLVE_CURRENCY_INDEX() {
|
|
|
|
// Return promise resolve currency index
|
|
return Listener.PROMISE_RESOLVE_AMOUNT_INDEX + 1;
|
|
}
|
|
|
|
// Promise resolve message index
|
|
static get PROMISE_RESOLVE_MESSAGE_INDEX() {
|
|
|
|
// Return promise resolve message index
|
|
return Listener.PROMISE_RESOLVE_CURRENCY_INDEX + 1;
|
|
}
|
|
|
|
// Promise resolve receiver address index
|
|
static get PROMISE_RESOLVE_RECEIVER_ADDRESS_INDEX() {
|
|
|
|
// Return promise resolve receiver address index
|
|
return Listener.PROMISE_RESOLVE_MESSAGE_INDEX + 1;
|
|
}
|
|
|
|
// Promise resolve file response index
|
|
static get PROMISE_RESOLVE_FILE_RESPONSE_INDEX() {
|
|
|
|
// Return promise resolve file response index
|
|
return Listener.PROMISE_RESOLVE_RECEIVER_ADDRESS_INDEX + 1;
|
|
}
|
|
|
|
// Promise resolve ID index
|
|
static get PROMISE_RESOLVE_ID_INDEX() {
|
|
|
|
// Return promise resolve ID index
|
|
return Listener.PROMISE_RESOLVE_FILE_RESPONSE_INDEX + 1;
|
|
}
|
|
|
|
// Private
|
|
|
|
// Connect
|
|
connect() {
|
|
|
|
// Check if reconnect timeout exists
|
|
if(this.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(this.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
this.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
}
|
|
|
|
// Set empty address
|
|
var emptyAddress = this.getAddress()["length"] === 0;
|
|
|
|
// Check if address exists
|
|
if(emptyAddress === false) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Trying to connect to the listener at %1$y.'), [
|
|
|
|
[
|
|
// Text
|
|
this.getAddress(),
|
|
|
|
// Is raw data
|
|
true
|
|
]
|
|
]);
|
|
}
|
|
|
|
// Get current ignore response index
|
|
var index = this.ignoreResponseIndex++;
|
|
|
|
// Check if current ignore resposne index is at the max safe integer
|
|
if(index === Number.MAX_SAFE_INTEGER) {
|
|
|
|
// Reset ignore response index
|
|
this.ignoreResponseIndex = 0;
|
|
}
|
|
|
|
// Set ignore response
|
|
var ignoreResponse = false;
|
|
|
|
// Settings change listener index event
|
|
$(this).one(Listener.SETTINGS_CHANGE_EVENT + ".listener" + index.toFixed(), function() {
|
|
|
|
// Turn off window offline listener index event
|
|
$(window).off("offline" + ".listener" + index.toFixed());
|
|
|
|
// Set ignore response
|
|
ignoreResponse = true;
|
|
});
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Window offline listener index event
|
|
$(window).one("offline" + ".listener" + index.toFixed(), function() {
|
|
|
|
// Turn off settings change listener index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listener" + index.toFixed());
|
|
|
|
// Set ignore response
|
|
ignoreResponse = true;
|
|
});
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Create connection
|
|
this.connection = new WebSocket(this.getAddress());
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Check if not ignoring response
|
|
if(ignoreResponse === false) {
|
|
|
|
// Turn off settings change listener index event
|
|
$(this).off(Listener.SETTINGS_CHANGE_EVENT + ".listener" + index.toFixed());
|
|
|
|
// Turn off window offline listener index event
|
|
$(window).off("offline" + ".listener" + index.toFixed());
|
|
|
|
// Check if address exists
|
|
if(emptyAddress === false) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Connecting to the listener failed.'));
|
|
}
|
|
|
|
// Check if reconnect timeout exists
|
|
if(this.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(this.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
this.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
}
|
|
|
|
// Set reconnect timeout
|
|
this.reconnectTimeout = setTimeout(function() {
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
|
|
// Connect
|
|
self.connect();
|
|
|
|
}, Math.min(Listener.MAXIMUM_RETRY_DELAY_MILLISECONDS, this.retryDelay));
|
|
|
|
// Update retry delay
|
|
this.retryDelay *= Listener.RETRY_DELAY_SCALING_FACTOR;
|
|
|
|
// Trigger connection close event
|
|
$(this).trigger(Listener.CONNECTION_CLOSE_EVENT, (this.connected === false) ? Listener.NO_CONNECTION_CLOSE_TYPE : Listener.DISCONNECTED_CLOSE_TYPE);
|
|
|
|
// Set connection to no connection
|
|
this.connection = Listener.NO_CONNECTION;
|
|
|
|
// Clear connected
|
|
this.connected = false;
|
|
}
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Connection open event
|
|
$(this.connection).on("open", function() {
|
|
|
|
// Check if not ignoring response
|
|
if(ignoreResponse === false) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Successfully connected to the listener.'));
|
|
|
|
// Reset retry delay
|
|
self.retryDelay = Listener.INITIAL_RETRY_DELAY_MILLISECONDS;
|
|
|
|
// Trigger connection open event
|
|
$(self).trigger(Listener.CONNECTION_OPEN_EVENT);
|
|
|
|
// Set connected
|
|
self.connected = true;
|
|
}
|
|
|
|
// Connection error event
|
|
}).on("error", function() {
|
|
|
|
// Check if not ignoring response
|
|
if(ignoreResponse === false) {
|
|
|
|
// Close connection
|
|
self.connection.close();
|
|
}
|
|
|
|
// Connection close event
|
|
}).on("close", function() {
|
|
|
|
// Check if not ignoring response
|
|
if(ignoreResponse === false) {
|
|
|
|
// Turn off settings change listener index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listener" + index.toFixed());
|
|
|
|
// Turn off window offline listener index event
|
|
$(window).off("offline" + ".listener" + index.toFixed());
|
|
|
|
// Check if connected
|
|
if(self.connected === true) {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Disconnected from the listener.'));
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Log message
|
|
Log.logMessage(Language.getDefaultTranslation('Connecting to the listener failed.'));
|
|
}
|
|
|
|
// Check if reconnect timeout exists
|
|
if(self.reconnectTimeout !== Listener.NO_TIMEOUT) {
|
|
|
|
// Clear reconnect timeout
|
|
clearTimeout(self.reconnectTimeout);
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
}
|
|
|
|
// Set reconnect timeout
|
|
self.reconnectTimeout = setTimeout(function() {
|
|
|
|
// Set reconnect timeout to no timeout
|
|
self.reconnectTimeout = Listener.NO_TIMEOUT;
|
|
|
|
// Connect
|
|
self.connect();
|
|
|
|
}, Math.min(Listener.MAXIMUM_RETRY_DELAY_MILLISECONDS, self.retryDelay));
|
|
|
|
// Update retry delay
|
|
self.retryDelay *= Listener.RETRY_DELAY_SCALING_FACTOR;
|
|
|
|
// Trigger connection close event
|
|
$(self).trigger(Listener.CONNECTION_CLOSE_EVENT, (self.connected === false) ? Listener.NO_CONNECTION_CLOSE_TYPE : Listener.DISCONNECTED_CLOSE_TYPE);
|
|
|
|
// Set connection to no connection
|
|
self.connection = Listener.NO_CONNECTION;
|
|
|
|
// Clear connected
|
|
self.connected = false;
|
|
}
|
|
|
|
// Connection message event
|
|
}).on("message", function(event) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse message as JSON
|
|
var message = JSON.parse(event["originalEvent"]["data"]);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Check if message is invalid
|
|
if(Object.isObject(message) === false)
|
|
|
|
// Return
|
|
return;
|
|
|
|
// Check if message is a response
|
|
if("Index" in message === true && typeof message["Index"] === "number")
|
|
|
|
// Trigger response receive event
|
|
$(self).trigger(Listener.RESPONSE_RECEIVE_EVENT, message);
|
|
|
|
// Otherwise check if message is an interaction
|
|
else if("Interaction" in message === true && typeof message["Interaction"] === "number" && "URL" in message === true && "API" in message === true && "Type" in message === true && "Data" in message === true) {
|
|
|
|
// Check if not ignoring response
|
|
if(ignoreResponse === false) {
|
|
|
|
// Check if message's contents are valid
|
|
if(typeof message["URL"] === "string" && typeof message["API"] === "string" && typeof message["Type"] === "string" && typeof message["Data"] === "string") {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Decode message's data
|
|
var data = Base64.toUint8Array(message["Data"]);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Send error
|
|
self.send({
|
|
|
|
// Interaction
|
|
"Interaction": message["Interaction"],
|
|
|
|
// Type
|
|
"Type": "text/plain",
|
|
|
|
// Data
|
|
"Data": Base64.fromUint8Array((new TextEncoder()).encode("")),
|
|
|
|
// Status
|
|
"Status": Common.HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS
|
|
});
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Create interaction from message
|
|
var interaction = new Interaction(message["Interaction"], message["URL"], message["API"], message["Type"], data, self);
|
|
|
|
// Status receive listener cancel interaction event
|
|
$(self).on(Listener.STATUS_RECEIVE_EVENT + ".listenerCancel" + message["Interaction"].toFixed(), function(event, status) {
|
|
|
|
// Check if status is for the interaction
|
|
if(status["Interaction"] === message["Interaction"]) {
|
|
|
|
// Turn off status receive listener cancel interaction event
|
|
$(self).off(Listener.STATUS_RECEIVE_EVENT + ".listenerCancel" + message["Interaction"].toFixed());
|
|
|
|
// Turn off settings change listener cancel interaction event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerCancel" + message["Interaction"].toFixed());
|
|
|
|
// Check if status contains an error, doesn't contain a status, or doesn't contain a succeeded status
|
|
if(Object.isObject(status) === false || "Error" in status === true || "Status" in status === false || status["Status"] !== Listener.STATUS_SUCCEEDED_VALUE) {
|
|
|
|
// Set that interaction is canceled
|
|
interaction.setCanceled();
|
|
}
|
|
}
|
|
|
|
// Settings change listener cancel interaction event
|
|
}).one(Listener.SETTINGS_CHANGE_EVENT + ".listenerCancel" + message["Interaction"].toFixed(), function() {
|
|
|
|
// Turn off status receive listener cancel interaction event
|
|
$(self).off(Listener.STATUS_RECEIVE_EVENT + ".listenerCancel" + message["Interaction"].toFixed());
|
|
|
|
// Set that interaction is canceled
|
|
interaction.setCanceled();
|
|
});
|
|
|
|
// Trigger request receive event
|
|
$(self).trigger(Listener.REQUEST_RECEIVE_EVENT, interaction);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Send error
|
|
self.send({
|
|
|
|
// Interaction
|
|
"Interaction": message["Interaction"],
|
|
|
|
// Type
|
|
"Type": "text/plain",
|
|
|
|
// Data
|
|
"Data": Base64.fromUint8Array((new TextEncoder()).encode("")),
|
|
|
|
// Status
|
|
"Status": Common.HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS
|
|
});
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Send error
|
|
self.send({
|
|
|
|
// Interaction
|
|
"Interaction": message["Interaction"],
|
|
|
|
// Type
|
|
"Type": "text/plain",
|
|
|
|
// Data
|
|
"Data": Base64.fromUint8Array((new TextEncoder()).encode("")),
|
|
|
|
// Status
|
|
"Status": Common.HTTP_NOT_FOUND_STATUS
|
|
});
|
|
}
|
|
}
|
|
|
|
// Otherwise check if message is a status
|
|
else if("Interaction" in message === true && typeof message["Interaction"] === "number")
|
|
|
|
// Trigger status receive event
|
|
$(self).trigger(Listener.STATUS_RECEIVE_EVENT, message);
|
|
});
|
|
}
|
|
|
|
// Is connected
|
|
isConnected() {
|
|
|
|
// Return if connection exists and is open
|
|
return this.connection !== Listener.NO_CONNECTION && this.connection["readyState"] === Listener.WEBSOCKET_OPEN_STATE;
|
|
}
|
|
|
|
// Send
|
|
send(data) {
|
|
|
|
// Send data to connection
|
|
this.connection.send(JSON.stringify(data));
|
|
}
|
|
|
|
// Send request
|
|
sendRequest(request) {
|
|
|
|
// Get current request index
|
|
var index = this.requestIndex++;
|
|
|
|
// Check if current request index is at the max safe integer
|
|
if(index === Number.MAX_SAFE_INTEGER)
|
|
|
|
// Reset request index
|
|
this.requestIndex = 0;
|
|
|
|
// Set index in request
|
|
request["Index"] = index;
|
|
|
|
// Get current ignore response index
|
|
var ignoreResponseIndex = this.ignoreResponseIndex++;
|
|
|
|
// Check if current ignore resposne index is at the max safe integer
|
|
if(ignoreResponseIndex === Number.MAX_SAFE_INTEGER) {
|
|
|
|
// Reset ignore response index
|
|
this.ignoreResponseIndex = 0;
|
|
}
|
|
|
|
// Initialize ignore response
|
|
var ignoreResponse = false;
|
|
|
|
// Settings change listener request ignore response index event
|
|
$(this).on(Listener.SETTINGS_CHANGE_EVENT + ".listenerRequest" + ignoreResponseIndex.toFixed(), function() {
|
|
|
|
// Set ignore response
|
|
ignoreResponse = true;
|
|
});
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Turn off settings change listener request ignore response index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerRequest" + ignoreResponseIndex.toFixed());
|
|
|
|
// Check if ignoring response
|
|
if(ignoreResponse === true) {
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Turn off events
|
|
var turnOffEvents = function() {
|
|
|
|
// Turn off response receive listener request index event
|
|
$(self).off(Listener.RESPONSE_RECEIVE_EVENT + ".listenerRequest" + index.toFixed());
|
|
|
|
// Turn off connection open listener request index event
|
|
$(self).off(Listener.CONNECTION_OPEN_EVENT + ".listenerRequest" + index.toFixed());
|
|
|
|
// Turn off connection close listener request index event
|
|
$(self).off(Listener.CONNECTION_CLOSE_EVENT + ".listenerRequest" + index.toFixed());
|
|
|
|
// Turn off settings change listener request ignore response index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerRequest" + ignoreResponseIndex.toFixed());
|
|
};
|
|
|
|
// Create timeout
|
|
var timeout = setTimeout(function() {
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.TIMEOUT_ERROR);
|
|
|
|
}, Listener.REQUEST_TIMEOUT_SECONDS * Common.MILLISECONDS_IN_A_SECOND);
|
|
|
|
// Initialize close count
|
|
var closeCount = 0;
|
|
|
|
// Response receive listener request index event
|
|
$(self).on(Listener.RESPONSE_RECEIVE_EVENT + ".listenerRequest" + index.toFixed(), function(event, response) {
|
|
|
|
// Check if response contains the index
|
|
if(response["Index"] === index) {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Check if response contains an error or doesn't contain a response
|
|
if(Object.isObject(response) === false || "Error" in response === true || "Response" in response === false)
|
|
|
|
// Reject error
|
|
reject(Listener.INVALID_RESPONSE_ERROR);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Resolve response
|
|
resolve(response["Response"]);
|
|
}
|
|
|
|
// Connection open listener request index event
|
|
}).on(Listener.CONNECTION_OPEN_EVENT + ".listenerRequest" + index.toFixed(), function() {
|
|
|
|
// Send request
|
|
self.send(request);
|
|
|
|
// Connection close listener request index event
|
|
}).on(Listener.CONNECTION_CLOSE_EVENT + ".listenerRequest" + index.toFixed(), function() {
|
|
|
|
// Check if close count is at the fail threshold
|
|
if(++closeCount >= Listener.CONNECTION_CLOSE_FAIL_THRESHOLD) {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
}
|
|
|
|
// Settings change listener request ignore response index event
|
|
}).on(Listener.SETTINGS_CHANGE_EVENT + ".listenerRequest" + ignoreResponseIndex.toFixed(), function() {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
});
|
|
|
|
// Check if connected
|
|
if(self.isConnected() === true) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Send request
|
|
self.send(request);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Send response
|
|
sendResponse(response) {
|
|
|
|
// Get interaction index
|
|
var index = response["Interaction"];
|
|
|
|
// Get current ignore response index
|
|
var ignoreResponseIndex = this.ignoreResponseIndex++;
|
|
|
|
// Check if current ignore resposne index is at the max safe integer
|
|
if(ignoreResponseIndex === Number.MAX_SAFE_INTEGER) {
|
|
|
|
// Reset ignore response index
|
|
this.ignoreResponseIndex = 0;
|
|
}
|
|
|
|
// Initialize ignore response
|
|
var ignoreResponse = false;
|
|
|
|
// Settings change listener response ignore response index event
|
|
$(this).on(Listener.SETTINGS_CHANGE_EVENT + ".listenerResponse" + ignoreResponseIndex.toFixed(), function() {
|
|
|
|
// Set ignore response
|
|
ignoreResponse = true;
|
|
});
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Turn off settings change listener response ignore response index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerResponse" + ignoreResponseIndex.toFixed());
|
|
|
|
// Check if ignoring response
|
|
if(ignoreResponse === true) {
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Turn off events
|
|
var turnOffEvents = function() {
|
|
|
|
// Turn off status receive listener response index event
|
|
$(self).off(Listener.STATUS_RECEIVE_EVENT + ".listenerResponse" + index.toFixed());
|
|
|
|
// Turn off connection open listener response index event
|
|
$(self).off(Listener.CONNECTION_OPEN_EVENT + ".listenerResponse" + index.toFixed());
|
|
|
|
// Turn off connection close listener response index event
|
|
$(self).off(Listener.CONNECTION_CLOSE_EVENT + ".listenerResponse" + index.toFixed());
|
|
|
|
// Turn off settings change listener response ignore response index event
|
|
$(self).off(Listener.SETTINGS_CHANGE_EVENT + ".listenerResponse" + ignoreResponseIndex.toFixed());
|
|
};
|
|
|
|
// Create timeout
|
|
var timeout = setTimeout(function() {
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.TIMEOUT_ERROR);
|
|
|
|
}, Listener.RESPONSE_TIMEOUT_SECONDS * Common.MILLISECONDS_IN_A_SECOND);
|
|
|
|
// Initialize close count
|
|
var closeCount = 0;
|
|
|
|
// Status receive listener response index event
|
|
$(self).on(Listener.STATUS_RECEIVE_EVENT + ".listenerResponse" + index.toFixed(), function(event, status) {
|
|
|
|
// Check if status contains the index
|
|
if(status["Interaction"] === index) {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Check if status contains an error or doesn't contain a status
|
|
if(Object.isObject(status) === false || "Error" in status === true || "Status" in status === false)
|
|
|
|
// Reject error
|
|
reject(Listener.INVALID_STATUS_ERROR);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Resolve status
|
|
resolve(status["Status"]);
|
|
}
|
|
|
|
// Connection open listener response index event
|
|
}).on(Listener.CONNECTION_OPEN_EVENT + ".listenerResponse" + index.toFixed(), function() {
|
|
|
|
// Send response
|
|
self.send(response);
|
|
|
|
// Connection close listener response index event
|
|
}).on(Listener.CONNECTION_CLOSE_EVENT + ".listenerResponse" + index.toFixed(), function() {
|
|
|
|
// Check if close count is at the fail threshold
|
|
if(++closeCount >= Listener.CONNECTION_CLOSE_FAIL_THRESHOLD) {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
}
|
|
|
|
// Settings change listener response ignore response index event
|
|
}).on(Listener.SETTINGS_CHANGE_EVENT + ".listenerResponse" + ignoreResponseIndex.toFixed(), function() {
|
|
|
|
// Stop timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Turn off events
|
|
turnOffEvents();
|
|
|
|
// Reject error
|
|
reject(Listener.CONNECTION_ERROR);
|
|
});
|
|
|
|
// Check if connected
|
|
if(self.isConnected() === true) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Send response
|
|
self.send(response);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initial retry delay milliseconds
|
|
static get INITIAL_RETRY_DELAY_MILLISECONDS() {
|
|
|
|
// Return initial retry delay milliseconds
|
|
return 250;
|
|
}
|
|
|
|
// Maximum retry delay milliseconds
|
|
static get MAXIMUM_RETRY_DELAY_MILLISECONDS() {
|
|
|
|
// Return maximum retry delay milliseconds
|
|
return 10 * Common.MILLISECONDS_IN_A_SECOND;
|
|
}
|
|
|
|
// Retry delay scaling factor
|
|
static get RETRY_DELAY_SCALING_FACTOR() {
|
|
|
|
// Return retry delay scaling factor
|
|
return 2;
|
|
}
|
|
|
|
// Response receive event
|
|
static get RESPONSE_RECEIVE_EVENT() {
|
|
|
|
// Return response receive event
|
|
return "ListenerResponseReceiveEvent";
|
|
}
|
|
|
|
// Status receive event
|
|
static get STATUS_RECEIVE_EVENT() {
|
|
|
|
// Return status receive event
|
|
return "ListenerStatusReceiveEvent";
|
|
}
|
|
|
|
// WebSocket open state
|
|
static get WEBSOCKET_OPEN_STATE() {
|
|
|
|
// Return WebSocket open state
|
|
return 1;
|
|
}
|
|
|
|
// Request timeout seconds
|
|
static get REQUEST_TIMEOUT_SECONDS() {
|
|
|
|
// Return request timeout seconds
|
|
return 2 * Common.SECONDS_IN_A_MINUTE;
|
|
}
|
|
|
|
// Response timeout seconds
|
|
static get RESPONSE_TIMEOUT_SECONDS() {
|
|
|
|
// Return response timeout seconds
|
|
return Listener.REQUEST_TIMEOUT_SECONDS;
|
|
}
|
|
|
|
// No timeout
|
|
static get NO_TIMEOUT() {
|
|
|
|
// Return no timeout
|
|
return null;
|
|
}
|
|
|
|
// Connection close fail threshold
|
|
static get CONNECTION_CLOSE_FAIL_THRESHOLD() {
|
|
|
|
// Return connection close fail threshold
|
|
return 3;
|
|
}
|
|
|
|
// Create URL request name
|
|
static get CREATE_URL_REQUEST_NAME() {
|
|
|
|
// Return create URL request name
|
|
return "Create URL";
|
|
}
|
|
|
|
// Change URL request name
|
|
static get CHANGE_URL_REQUEST_NAME() {
|
|
|
|
// Return change URL request name
|
|
return "Change URL";
|
|
}
|
|
|
|
// Own URL request name
|
|
static get OWN_URL_REQUEST_NAME() {
|
|
|
|
// Return own URL request name
|
|
return "Own URL";
|
|
}
|
|
|
|
// Delete URL request name
|
|
static get DELETE_URL_REQUEST_NAME() {
|
|
|
|
// Return delete URL request name
|
|
return "Delete URL";
|
|
}
|
|
|
|
// Connection error
|
|
static get CONNECTION_ERROR() {
|
|
|
|
// Return connection error
|
|
return 0;
|
|
}
|
|
|
|
// Timeout error
|
|
static get TIMEOUT_ERROR() {
|
|
|
|
// Return timeout error
|
|
return Listener.CONNECTION_ERROR + 1;
|
|
}
|
|
|
|
// Invalid response error
|
|
static get INVALID_RESPONSE_ERROR() {
|
|
|
|
// Return invalid response error
|
|
return Listener.TIMEOUT_ERROR + 1;
|
|
}
|
|
|
|
// Invalid status error
|
|
static get INVALID_STATUS_ERROR() {
|
|
|
|
// Return invalid status error
|
|
return Listener.INVALID_RESPONSE_ERROR + 1;
|
|
}
|
|
|
|
// Status succeeded value
|
|
static get STATUS_SUCCEEDED_VALUE() {
|
|
|
|
// Return status succeeded value
|
|
return "Succeeded";
|
|
}
|
|
|
|
// No connection
|
|
static get NO_CONNECTION() {
|
|
|
|
// Return no connection
|
|
return null;
|
|
}
|
|
|
|
// Settings use custom listener name
|
|
static get SETTINGS_USE_CUSTOM_LISTENER_NAME() {
|
|
|
|
// Return settings use custom listener name
|
|
return "Use Custom Listener";
|
|
}
|
|
|
|
// Settings use custom listener default value
|
|
static get SETTINGS_USE_CUSTOM_LISTENER_DEFAULT_VALUE() {
|
|
|
|
// Return settings use custom listener default value
|
|
return false;
|
|
}
|
|
|
|
// Settings custom listener address name
|
|
static get SETTINGS_CUSTOM_LISTENER_ADDRESS_NAME() {
|
|
|
|
// Return settings custom listener address name
|
|
return "Custom Listener Address";
|
|
}
|
|
|
|
// Settings custom listener address default value
|
|
static get SETTINGS_CUSTOM_LISTENER_ADDRESS_DEFAULT_VALUE() {
|
|
|
|
// Return settings custom listener address default value
|
|
return "";
|
|
}
|
|
|
|
// Default listener address
|
|
static get DEFAULT_LISTENER_ADDRESS() {
|
|
|
|
// Set server
|
|
var server = (Common.isExtension() === true || location["protocol"] === Common.FILE_PROTOCOL) ? new URL(HTTPS_SERVER_ADDRESS) : location;
|
|
|
|
// Return default listener address
|
|
return ((server["protocol"] === Common.HTTPS_PROTOCOL) ? Common.WEBSOCKET_SECURE_PROTOCOL : Common.WEBSOCKET_PROTOCOL) + "//" + server["hostname"] + "/listen";
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's listener
|
|
globalThis["Listener"] = Listener;
|