326 lines
13 KiB
QML
326 lines
13 KiB
QML
import QtQuick 2.15
|
|
import QtWebView 1.15
|
|
// TODO #12434: remove debugging WebEngineView code
|
|
// import QtWebEngine 1.10
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
|
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
|
|
|
// Control used to instantiate and run the the WalletConnect web SDK
|
|
// The view is not used to draw anything, but has to be visible to be able to run JS code
|
|
// Use the \c backgroundColor property to blend in with the background
|
|
// \warning A too smaller height might cause rendering errors
|
|
// TODO #12434: remove debugging WebEngineView code
|
|
WebView {
|
|
//WebEngineView {
|
|
id: root
|
|
|
|
implicitWidth: 1
|
|
implicitHeight: 1
|
|
|
|
required property string projectId
|
|
required property color backgroundColor
|
|
|
|
readonly property alias sdkReady: d.sdkReady
|
|
readonly property alias pairingsModel: d.pairingsModel
|
|
|
|
signal sdkInit(bool success, var result)
|
|
signal pairSessionProposal(bool success, var sessionProposal)
|
|
signal pairAcceptedResult(bool success, var sessionType)
|
|
signal pairRejectedResult(bool success, var result)
|
|
signal sessionRequestEvent(var sessionRequest)
|
|
signal sessionRequestUserAnswerResult(bool accept, string error)
|
|
signal responseTimeout()
|
|
|
|
// TODO: proper report
|
|
signal statusChanged(string message)
|
|
|
|
function pair(pairLink) {
|
|
let callStr = d.generateSdkCall("pair", `"${pairLink}"`, RequestCodes.PairSuccess, RequestCodes.PairError)
|
|
d.requestSdkAsync(callStr)
|
|
}
|
|
|
|
function approvePairSession(sessionProposal, supportedNamespaces) {
|
|
let callStr = d.generateSdkCall("approvePairSession", `${JSON.stringify(sessionProposal)}, ${JSON.stringify(supportedNamespaces)}`, RequestCodes.ApprovePairSuccess, RequestCodes.ApprovePairSuccess)
|
|
|
|
d.requestSdkAsync(callStr)
|
|
}
|
|
|
|
function rejectPairSession(id) {
|
|
let callStr = d.generateSdkCall("rejectPairSession", id, RequestCodes.RejectPairSuccess, RequestCodes.RejectPairError)
|
|
|
|
d.requestSdkAsync(callStr)
|
|
}
|
|
|
|
function acceptSessionRequest(topic, id, signature) {
|
|
let callStr = d.generateSdkCall("respondSessionRequest", `"${topic}", ${id}, "${signature}"`, RequestCodes.AcceptSessionSuccess, RequestCodes.AcceptSessionError)
|
|
|
|
d.requestSdkAsync(callStr)
|
|
}
|
|
|
|
function rejectSessionRequest(topic, id, error) {
|
|
let callStr = d.generateSdkCall("rejectSessionRequest", `"${topic}", ${id}, ${error}`, RequestCodes.RejectSessionSuccess, RequestCodes.RejectSessionError)
|
|
|
|
d.requestSdkAsync(callStr)
|
|
}
|
|
|
|
// TODO #12434: remove debugging WebEngineView code
|
|
onLoadingChanged: function(loadRequest) {
|
|
console.debug(`@dd WalletConnectSDK.onLoadingChanged; status: ${loadRequest.status}; error: ${loadRequest.errorString}`)
|
|
switch(loadRequest.status) {
|
|
case WebView.LoadSucceededStatus:
|
|
// case WebEngineView.LoadSucceededStatus:
|
|
d.init(root.projectId)
|
|
break
|
|
case WebView.LoadFailedStatus:
|
|
// case WebEngineView.LoadFailedStatus:
|
|
root.statusChanged(`<font color="red">Failed loading SDK JS code; error: "${loadRequest.errorString}"</font>`)
|
|
break
|
|
case WebView.LoadStartedStatus:
|
|
// case WebEngineView.LoadStartedStatus:
|
|
root.statusChanged(`<font color="blue">Loading SDK JS code</font>`)
|
|
break
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
console.debug(`@dd WalletConnectSDK onCompleted`)
|
|
var scriptSrc = SQUtils.StringUtils.readTextFile(":/app/AppLayouts/Wallet/views/walletconnect/sdk/generated/bundle.js")
|
|
// Load bundle from disk if not found in resources (Storybook)
|
|
if (scriptSrc === "") {
|
|
scriptSrc = SQUtils.StringUtils.readTextFile("./AppLayouts/Wallet/views/walletconnect/sdk/generated/bundle.js")
|
|
if (scriptSrc === "") {
|
|
console.error("Failed to read WalletConnect SDK bundle")
|
|
return
|
|
}
|
|
}
|
|
|
|
let htmlSrc = `<!DOCTYPE html><html><head><!--<title>TODO: Test</title>--><script type='text/javascript'>${scriptSrc}</script></head><body style='background-color: ${root.backgroundColor.toString()};'></body></html>`
|
|
|
|
console.debug(`@dd WalletConnectSDK.loadHtml; htmlSrc len: ${htmlSrc.length}`)
|
|
root.loadHtml(htmlSrc, "https://status.app")
|
|
}
|
|
|
|
Timer {
|
|
id: timer
|
|
|
|
interval: 100
|
|
repeat: true
|
|
running: false
|
|
triggeredOnStart: true
|
|
|
|
property int errorCount: 0
|
|
|
|
onTriggered: {
|
|
root.runJavaScript(
|
|
"wcResult",
|
|
function(wcResult) {
|
|
if (!wcResult) {
|
|
return
|
|
}
|
|
|
|
let done = false
|
|
if (wcResult.error) {
|
|
console.debug(`WC JS error response - ${JSON.stringify(wcResult)}`)
|
|
done = true
|
|
if (!d.sdkReady) {
|
|
root.statusChanged(`<font color="red">[${timer.errorCount++}] Failed SDK init; error: ${wcResult.error}</font>`)
|
|
} else {
|
|
root.statusChanged(`<font color="red">[${timer.errorCount++}] Operation error: ${wcResult.error}</font>`)
|
|
}
|
|
}
|
|
|
|
if (wcResult.state !== undefined) {
|
|
switch (wcResult.state) {
|
|
case RequestCodes.SdkInitSuccess:
|
|
d.sdkReady = true
|
|
root.sdkInit(true, "")
|
|
d.startListeningForEvents()
|
|
break
|
|
case RequestCodes.SdkInitError:
|
|
d.sdkReady = false
|
|
root.sdkInit(false, wcResult.error)
|
|
break
|
|
case RequestCodes.PairSuccess:
|
|
root.pairSessionProposal(true, wcResult.result)
|
|
d.getPairings()
|
|
break
|
|
case RequestCodes.PairError:
|
|
root.pairSessionProposal(false, wcResult.error)
|
|
break
|
|
case RequestCodes.ApprovePairSuccess:
|
|
root.pairAcceptedResult(true, "")
|
|
d.getPairings()
|
|
break
|
|
case RequestCodes.ApprovePairError:
|
|
root.pairAcceptedResult(false, wcResult.error)
|
|
d.getPairings()
|
|
break
|
|
case RequestCodes.RejectPairSuccess:
|
|
root.pairRejectedResult(true, "")
|
|
break
|
|
case RequestCodes.RejectPairError:
|
|
root.pairRejectedResult(false, wcResult.error)
|
|
break
|
|
case RequestCodes.AcceptSessionSuccess:
|
|
root.sessionRequestUserAnswerResult(true, "")
|
|
break
|
|
case RequestCodes.AcceptSessionError:
|
|
root.sessionRequestUserAnswerResult(true, wcResult.error)
|
|
break
|
|
case RequestCodes.RejectSessionSuccess:
|
|
root.sessionRequestUserAnswerResult(false, "")
|
|
break
|
|
case RequestCodes.RejectSessionError:
|
|
root.sessionRequestUserAnswerResult(false, wcResult.error)
|
|
break
|
|
case RequestCodes.GetPairings:
|
|
d.populatePairingsModel(wcResult.result)
|
|
break
|
|
case RequestCodes.GetPairingsError:
|
|
console.error(`WalletConnectSDK - getPairings error: ${wcResult.error}`)
|
|
break
|
|
default: {
|
|
root.statusChanged(`<font color="red">[${timer.errorCount++}] Unknown state: ${wcResult.state}</font>`)
|
|
}
|
|
}
|
|
|
|
done = true
|
|
}
|
|
|
|
if (done) {
|
|
timer.stop()
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: responseTimeoutTimer
|
|
|
|
interval: 10000
|
|
repeat: false
|
|
running: timer.running
|
|
|
|
onTriggered: {
|
|
timer.stop()
|
|
root.responseTimeout()
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: eventsTimer
|
|
|
|
interval: 100
|
|
repeat: true
|
|
running: false
|
|
|
|
onTriggered: {
|
|
root.runJavaScript("window.wcEventResult ? window.wcEventResult.shift() : null", function(event) {
|
|
if (event) {
|
|
switch(event.name) {
|
|
case "session_request":
|
|
root.sessionRequestEvent(event.payload)
|
|
break
|
|
default:
|
|
console.error("WC unknown event type: ", event.type)
|
|
break
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
property var sessionProposal: null
|
|
property var sessionType: null
|
|
property bool sdkReady: false
|
|
|
|
property ListModel pairingsModel: pairings
|
|
|
|
onSdkReadyChanged: {
|
|
if (sdkReady) {
|
|
d.getPairings()
|
|
}
|
|
}
|
|
|
|
function populatePairingsModel(pairList) {
|
|
pairings.clear();
|
|
for (let i = 0; i < pairList.length; i++) {
|
|
pairings.append({
|
|
active: pairList[i].active,
|
|
topic: pairList[i].topic,
|
|
expiry: pairList[i].expiry
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
function isWaitingForSdk() {
|
|
return timer.running
|
|
}
|
|
|
|
function generateSdkCall(methodName, paramsStr, successState, errorState) {
|
|
return "wcResult = {}; try { wc." + methodName + "(" + paramsStr + ").then((callRes) => { wcResult = {state: " + successState + ", error: null, result: callRes}; }).catch((error) => { wcResult = {state: " + errorState + ", error: error}; }); } catch (e) { wcResult = {state: " + errorState + ", error: \"Exception: \" + e.message}; }; wcResult"
|
|
}
|
|
function requestSdkAsync(jsCode) {
|
|
root.runJavaScript(jsCode,
|
|
function(result) {
|
|
timer.restart()
|
|
}
|
|
)
|
|
}
|
|
|
|
function requestSdk(methodName, paramsStr, successState, errorState) {
|
|
const jsCode = "wcResult = {}; try { const callRes = wc." + methodName + "(" + (paramsStr ? (paramsStr) : "") + "); wcResult = {state: " + successState + ", error: null, result: callRes}; } catch (e) { wcResult = {state: " + errorState + ", error: \"Exception: \" + e.message}; }; wcResult"
|
|
root.runJavaScript(jsCode,
|
|
function(result) {
|
|
timer.restart()
|
|
}
|
|
)
|
|
}
|
|
|
|
function startListeningForEvents() {
|
|
const jsCode = "
|
|
try {
|
|
function processWCEvents() {
|
|
window.wcEventResult = [];
|
|
window.wcEventError = null
|
|
window.wc.registerForSessionRequest((event) => {
|
|
window.wcEventResult.push({name: 'session_request', payload: event});
|
|
});
|
|
}
|
|
processWCEvents();
|
|
} catch (e) {
|
|
window.wcEventError = e
|
|
}
|
|
window.wcEventError"
|
|
|
|
root.runJavaScript(jsCode,
|
|
function(result) {
|
|
if (result) {
|
|
console.error("startListeningForEvents: processWCEvents error", result)
|
|
return
|
|
}
|
|
}
|
|
)
|
|
eventsTimer.start()
|
|
}
|
|
|
|
function init(projectId) {
|
|
d.requestSdkAsync(generateSdkCall("init", `"${projectId}"`, RequestCodes.SdkInitSuccess, RequestCodes.SdkInitError))
|
|
}
|
|
|
|
function getPairings(projectId) {
|
|
d.requestSdk("getPairings", `null`, RequestCodes.GetPairings, RequestCodes.GetPairingsError)
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
id: pairings
|
|
}
|
|
} |