forked from Qortal/qortal-ui
missing files
This commit is contained in:
parent
bb46b7c3d5
commit
e9cb8a5be8
101
qortal-ui-plugins/plugins/core/streams/AddressWatcher.js
Normal file
101
qortal-ui-plugins/plugins/core/streams/AddressWatcher.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { parentEpml } from '../connect.js'
|
||||||
|
|
||||||
|
// Tests to see if a block or transaction should trigger an address reload...but we're not doing that yet, because of no time for good testing
|
||||||
|
const transactionTests = []
|
||||||
|
const blockTests = []
|
||||||
|
|
||||||
|
const DEFAULT_ADDRESS_INFO = {}
|
||||||
|
|
||||||
|
transactionTests.push((tx, addr) => {
|
||||||
|
return tx.recipient === addr || tx.sender === addr
|
||||||
|
})
|
||||||
|
|
||||||
|
blockTests.push((block, addr) => {
|
||||||
|
return block.generator === addr
|
||||||
|
})
|
||||||
|
|
||||||
|
export class AddressWatcher {
|
||||||
|
constructor (addresses) {
|
||||||
|
addresses = addresses || []
|
||||||
|
this.reset()
|
||||||
|
|
||||||
|
addresses.forEach(addr => this.addAddress(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
reset () {
|
||||||
|
this._addresses = {}
|
||||||
|
this._addressStreams = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an address to watch
|
||||||
|
addAddress (address) {
|
||||||
|
const addr = address.address
|
||||||
|
this._addresses[addr] = address
|
||||||
|
|
||||||
|
this._addressStreams[addr] = new EpmlStream(`address/${addr}`, () => this._addresses[addr])
|
||||||
|
|
||||||
|
this.updateAddress(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
async testBlock (block) {
|
||||||
|
// console.log('TESTING BLOCK')
|
||||||
|
const pendingUpdateAddresses = []
|
||||||
|
|
||||||
|
// blockTests.forEach(fn => {
|
||||||
|
|
||||||
|
// })
|
||||||
|
// transactionTests.forEach(fn => {
|
||||||
|
//
|
||||||
|
const transactions = await parentEpml.request('apiCall', { url: `/transactions/block/${block.signature}` })
|
||||||
|
transactions.forEach(transaction => {
|
||||||
|
// console.log(this)
|
||||||
|
// fn(transaction, Object.keys(this._addresses))
|
||||||
|
// Guess the block needs transactions
|
||||||
|
for (const addr of Object.keys(this._addresses)) {
|
||||||
|
// const addrChanged = transactionTests.some(fn => {
|
||||||
|
// return fn(transaction, addr)
|
||||||
|
// })
|
||||||
|
// console.log('checking ' + addr)
|
||||||
|
const addrChanged = true // Just update it every block...for now
|
||||||
|
if (!addrChanged) return
|
||||||
|
|
||||||
|
if (!(addr in pendingUpdateAddresses)) pendingUpdateAddresses.push(addr)
|
||||||
|
/**
|
||||||
|
* In the future transactions are potentially stored from here...and address is updated excluding transactions...and also somehow manage tx pages...
|
||||||
|
* Probably will just make wallet etc. listen for address change and then do the api call itself. If tx. page is on, say, page 3...and there's a new transaction...
|
||||||
|
* it will refresh, changing the "page" to have 1 extra transaction at the top and losing 1 at the bottom (pushed to next page)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pendingUpdateAddresses.forEach(addr => this.updateAddress(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAddress (addr) {
|
||||||
|
// console.log('UPPPDDAAATTTINGGG AADDDRRR', addr)
|
||||||
|
let addressRequest = await parentEpml.request('apiCall', {
|
||||||
|
type: 'explorer',
|
||||||
|
data: {
|
||||||
|
addr: addr,
|
||||||
|
txOnPage: 10
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// addressRequest = JSON.parse(addressRequest)
|
||||||
|
// console.log(addressRequest, 'AAADDDREESS REQQUEESTT')
|
||||||
|
// console.log('response: ', addressRequest)
|
||||||
|
|
||||||
|
const addressInfo = addressRequest.success ? addressRequest.data : DEFAULT_ADDRESS_INFO
|
||||||
|
// const addressInfo = addressRequest.success ? addressRequest.data : DEFAULT_ADDRESS_INFO
|
||||||
|
addressInfo.transactions = []
|
||||||
|
|
||||||
|
for (let i = addressInfo.start; i >= addressInfo.end; i--) {
|
||||||
|
addressInfo.transactions.push(addressInfo[i])
|
||||||
|
delete addressInfo[i]
|
||||||
|
}
|
||||||
|
// console.log('ADDRESS INFO', addressInfo)
|
||||||
|
if (!(addr in this._addresses)) return
|
||||||
|
|
||||||
|
this._addresses[addr] = addressInfo
|
||||||
|
// console.log('---------------------------Emitting-----------------------------', this._addresses[addr], this._addressStreams[addr])
|
||||||
|
this._addressStreams[addr].emit(addressInfo)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
import { parentEpml } from '../connect.js'
|
||||||
|
// import { EpmlStream } from 'epml' maybe not needed...loaded for me
|
||||||
|
|
||||||
|
export class UnconfirmedTransactionWatcher {
|
||||||
|
constructor () {
|
||||||
|
this._unconfirmedTransactionStreams = {}
|
||||||
|
this.reset() // Sets defaults
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
Object.entries(this._addresses).forEach((addr) => this._addressTransactionCheck(addr[0]))
|
||||||
|
}, 10 * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
reset () {
|
||||||
|
this._addresses = {}
|
||||||
|
this._addressesUnconfirmedTransactions = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an address to watch
|
||||||
|
addAddress (address) {
|
||||||
|
// console.log("Added address", address)
|
||||||
|
const addr = address.address
|
||||||
|
this._addresses[addr] = address
|
||||||
|
this._addressesUnconfirmedTransactions[addr] = []
|
||||||
|
|
||||||
|
if (this._unconfirmedTransactionStreams[addr]) return
|
||||||
|
// console.log("CREATING A STRTRREEAAAMMMM")
|
||||||
|
this._unconfirmedTransactionStreams[addr] = new EpmlStream(`unconfirmedOfAddress/${addr}`, () => this._addressesUnconfirmedTransactions[addr])
|
||||||
|
|
||||||
|
// this.updateAddress(address.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
check () {
|
||||||
|
// console.log("checkin for unconfirmed")
|
||||||
|
const c = this._addressTransactionCheck()
|
||||||
|
.then(() => setTimeout(() => this.check(), 5000))
|
||||||
|
.catch(() => setTimeout(() => this.check(), 5000))
|
||||||
|
// console.log(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
async _addressTransactionCheck () {
|
||||||
|
// console.log("Checking for unconfirmed transactions")
|
||||||
|
// console.log(this._addresses, Object.keys(this._addresses))
|
||||||
|
return Promise.all(Object.keys(this._addresses).map(addr => {
|
||||||
|
// console.log(`checking ${addr}`)
|
||||||
|
return parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
// url: `transactions/unconfirmedof/${addr}`
|
||||||
|
url: `/transactions/unconfirmed`
|
||||||
|
}).then(unconfirmedTransactions => {
|
||||||
|
// unconfirmedTransactions = JSON.parse(unconfirmedTransactions)
|
||||||
|
// console.log(unconfirmedTransactions)
|
||||||
|
unconfirmedTransactions.filter(tx => {
|
||||||
|
tx.creatorAddress === addr || tx.recipient === addr
|
||||||
|
})
|
||||||
|
// console.log(unconfirmedTransactions, unconfirmedTransactions.length)
|
||||||
|
// if(unconfirmedTransactions.length === 0) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
this._unconfirmedTransactionStreams[addr].emit(unconfirmedTransactions)
|
||||||
|
// console.log(this._unconfirmedTransactionStreams[addr])
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
336
qortal-ui-plugins/plugins/core/streams/onNewBlock.js
Normal file
336
qortal-ui-plugins/plugins/core/streams/onNewBlock.js
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
import { parentEpml } from '../connect.js'
|
||||||
|
|
||||||
|
let socketObject
|
||||||
|
let activeBlockSocketTimeout
|
||||||
|
let initial = 0
|
||||||
|
let closeGracefully = false
|
||||||
|
let isCalled = false
|
||||||
|
let retryOnClose = false
|
||||||
|
let blockFirstCall = true
|
||||||
|
|
||||||
|
let nodeStatusSocketObject
|
||||||
|
let nodeStatusSocketTimeout
|
||||||
|
let nodeStatusSocketcloseGracefully = false
|
||||||
|
let nodeStatusCount = 0
|
||||||
|
let nodeStatusRetryOnClose = false
|
||||||
|
let nodeStateCall = false
|
||||||
|
|
||||||
|
let isLoggedIn = false
|
||||||
|
|
||||||
|
let oldAccountInfo
|
||||||
|
|
||||||
|
parentEpml.subscribe('logged_in', loggedIn => {
|
||||||
|
|
||||||
|
if (loggedIn === 'true') {
|
||||||
|
isLoggedIn = true
|
||||||
|
} else {
|
||||||
|
isLoggedIn = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const setAccountInfo = async (addr) => {
|
||||||
|
|
||||||
|
const names = await parentEpml.request('apiCall', {
|
||||||
|
url: `/names/address/${addr}`
|
||||||
|
})
|
||||||
|
const addressInfo = await parentEpml.request('apiCall', {
|
||||||
|
url: `/addresses/${addr}`
|
||||||
|
})
|
||||||
|
|
||||||
|
let accountInfo = {
|
||||||
|
names: names,
|
||||||
|
addressInfo: addressInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.parent._.isEqual(oldAccountInfo, accountInfo) === true) {
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
|
||||||
|
parentEpml.request('setAccountInfo', accountInfo)
|
||||||
|
oldAccountInfo = accountInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doNodeInfo = async () => {
|
||||||
|
|
||||||
|
const nodeInfo = await parentEpml.request('apiCall', {
|
||||||
|
url: '/admin/info'
|
||||||
|
})
|
||||||
|
|
||||||
|
parentEpml.request('updateNodeInfo', nodeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
let initStateCount = 0
|
||||||
|
let oldState
|
||||||
|
|
||||||
|
const closeSockets = () => {
|
||||||
|
|
||||||
|
socketObject.close();
|
||||||
|
closeGracefully = true
|
||||||
|
|
||||||
|
nodeStatusSocketObject.close();
|
||||||
|
nodeStatusSocketcloseGracefully = true
|
||||||
|
}
|
||||||
|
|
||||||
|
export const startConfigWatcher = () => {
|
||||||
|
|
||||||
|
parentEpml.ready().then(() => {
|
||||||
|
parentEpml.subscribe('node_config', c => {
|
||||||
|
|
||||||
|
if (initStateCount === 0) {
|
||||||
|
let _oldState = JSON.parse(c)
|
||||||
|
oldState = { node: _oldState.node, knownNodes: _oldState.knownNodes }
|
||||||
|
initStateCount = initStateCount + 1
|
||||||
|
|
||||||
|
nodeStateCall = true
|
||||||
|
isCalled = true
|
||||||
|
socketObject !== undefined ? closeSockets() : undefined;
|
||||||
|
nodeStatusSocketObject !== undefined ? closeSockets() : undefined;
|
||||||
|
initNodeStatusCall(oldState)
|
||||||
|
pingactiveBlockSocket()
|
||||||
|
|
||||||
|
// Call doNodeInfo
|
||||||
|
doNodeInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
let _newState = JSON.parse(c);
|
||||||
|
let newState = { node: _newState.node, knownNodes: _newState.knownNodes }
|
||||||
|
|
||||||
|
if (window.parent._.isEqual(oldState, newState) === true) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
oldState = newState
|
||||||
|
nodeStateCall = true
|
||||||
|
isCalled = true
|
||||||
|
socketObject !== undefined ? closeSockets() : undefined;
|
||||||
|
nodeStatusSocketObject !== undefined ? closeSockets() : undefined;
|
||||||
|
initNodeStatusCall(newState)
|
||||||
|
pingactiveBlockSocket()
|
||||||
|
|
||||||
|
// Call doNodeInfo
|
||||||
|
doNodeInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
parentEpml.imReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
const processBlock = (blockObject) => {
|
||||||
|
|
||||||
|
parentEpml.request('updateBlockInfo', blockObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
const doNodeStatus = async (nodeStatusObject) => {
|
||||||
|
|
||||||
|
parentEpml.request('updateNodeStatus', nodeStatusObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const initNodeStatusCall = (nodeConfig) => {
|
||||||
|
|
||||||
|
if (nodeConfig.node == 0) {
|
||||||
|
pingNodeStatusSocket()
|
||||||
|
} else if (nodeConfig.node == 1) {
|
||||||
|
pingNodeStatusSocket()
|
||||||
|
} else if (nodeStatusSocketObject !== undefined) {
|
||||||
|
nodeStatusSocketObject.close()
|
||||||
|
nodeStatusSocketcloseGracefully = true
|
||||||
|
} else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initBlockSocket = () => {
|
||||||
|
|
||||||
|
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
|
let nodeUrl = myNode.domain + ":" + myNode.port
|
||||||
|
|
||||||
|
let activeBlockSocketLink
|
||||||
|
|
||||||
|
if (window.parent.location.protocol === "https:") {
|
||||||
|
|
||||||
|
activeBlockSocketLink = `wss://${nodeUrl}/websockets/blocks`;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
activeBlockSocketLink = `ws://${nodeUrl}/websockets/blocks`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeBlockSocket = new WebSocket(activeBlockSocketLink);
|
||||||
|
|
||||||
|
// Open Connection
|
||||||
|
activeBlockSocket.onopen = (e) => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-BLOCKS]: Connected.`);
|
||||||
|
closeGracefully = false
|
||||||
|
socketObject = activeBlockSocket
|
||||||
|
|
||||||
|
initial = initial + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message Event
|
||||||
|
activeBlockSocket.onmessage = (e) => {
|
||||||
|
|
||||||
|
processBlock(JSON.parse(e.data));
|
||||||
|
|
||||||
|
if (isLoggedIn) {
|
||||||
|
|
||||||
|
// Call Set Account Info...
|
||||||
|
setAccountInfo(window.parent.reduxStore.getState().app.selectedAddress.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closed Event
|
||||||
|
activeBlockSocket.onclose = () => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-BLOCKS]: CLOSED`);
|
||||||
|
|
||||||
|
processBlock({});
|
||||||
|
blockFirstCall = true
|
||||||
|
clearInterval(activeBlockSocketTimeout)
|
||||||
|
|
||||||
|
if (closeGracefully === false && initial <= 52) {
|
||||||
|
|
||||||
|
if (initial <= 52) {
|
||||||
|
|
||||||
|
retryOnClose = true
|
||||||
|
setTimeout(pingactiveBlockSocket, 10000)
|
||||||
|
initial = initial + 1
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// ... Stop retrying...
|
||||||
|
retryOnClose = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error Event
|
||||||
|
activeBlockSocket.onerror = (e) => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-BLOCKS]: ${e.type}`);
|
||||||
|
blockFirstCall = true
|
||||||
|
processBlock({});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockFirstCall) {
|
||||||
|
|
||||||
|
parentEpml.request('apiCall', {
|
||||||
|
url: '/blocks/last'
|
||||||
|
}).then(res => {
|
||||||
|
|
||||||
|
processBlock(res)
|
||||||
|
blockFirstCall = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const pingactiveBlockSocket = () => {
|
||||||
|
|
||||||
|
if (isCalled) {
|
||||||
|
|
||||||
|
isCalled = false
|
||||||
|
|
||||||
|
initBlockSocket()
|
||||||
|
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
|
||||||
|
} else if (retryOnClose) {
|
||||||
|
|
||||||
|
retryOnClose = false
|
||||||
|
clearTimeout(activeBlockSocketTimeout)
|
||||||
|
initBlockSocket()
|
||||||
|
isCalled = true
|
||||||
|
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
socketObject.send("non-integer ping")
|
||||||
|
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const initNodeStatusSocket = () => {
|
||||||
|
|
||||||
|
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
|
let nodeUrl = myNode.domain + ":" + myNode.port
|
||||||
|
|
||||||
|
let activeNodeStatusSocketLink
|
||||||
|
|
||||||
|
if (window.parent.location.protocol === "https:") {
|
||||||
|
|
||||||
|
activeNodeStatusSocketLink = `wss://${nodeUrl}/websockets/admin/status`;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
activeNodeStatusSocketLink = `ws://${nodeUrl}/websockets/admin/status`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeNodeStatusSocket = new WebSocket(activeNodeStatusSocketLink);
|
||||||
|
|
||||||
|
// Open Connection
|
||||||
|
activeNodeStatusSocket.onopen = (e) => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-NODE-STATUS]: Connected.`);
|
||||||
|
nodeStatusSocketcloseGracefully = false
|
||||||
|
nodeStatusSocketObject = activeNodeStatusSocket
|
||||||
|
|
||||||
|
nodeStatusCount = nodeStatusCount + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message Event
|
||||||
|
activeNodeStatusSocket.onmessage = (e) => {
|
||||||
|
|
||||||
|
doNodeStatus(JSON.parse(e.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closed Event
|
||||||
|
activeNodeStatusSocket.onclose = () => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-NODE-STATUS]: CLOSED`);
|
||||||
|
|
||||||
|
doNodeStatus({});
|
||||||
|
clearInterval(nodeStatusSocketTimeout)
|
||||||
|
|
||||||
|
if (nodeStatusSocketcloseGracefully === false && nodeStatusCount <= 52) {
|
||||||
|
|
||||||
|
if (nodeStatusCount <= 52) {
|
||||||
|
|
||||||
|
nodeStatusRetryOnClose = true
|
||||||
|
setTimeout(pingNodeStatusSocket, 10000)
|
||||||
|
nodeStatusCount = nodeStatusCount + 1
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// ... Stop retrying...
|
||||||
|
nodeStatusRetryOnClose = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error Event
|
||||||
|
activeNodeStatusSocket.onerror = (e) => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET-NODE-STATUS]: ${e.type}`);
|
||||||
|
doNodeStatus({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const pingNodeStatusSocket = () => {
|
||||||
|
|
||||||
|
if (nodeStateCall) {
|
||||||
|
|
||||||
|
clearTimeout(nodeStatusSocketTimeout)
|
||||||
|
initNodeStatusSocket()
|
||||||
|
nodeStateCall = false
|
||||||
|
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
|
||||||
|
} else if (nodeStatusRetryOnClose) {
|
||||||
|
|
||||||
|
nodeStatusRetryOnClose = false
|
||||||
|
clearTimeout(nodeStatusSocketTimeout)
|
||||||
|
initNodeStatusSocket()
|
||||||
|
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
nodeStatusSocketObject.send("non-integer ping")
|
||||||
|
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
|
||||||
|
}
|
||||||
|
}
|
241
qortal-ui-plugins/plugins/core/streams/streams.js
Normal file
241
qortal-ui-plugins/plugins/core/streams/streams.js
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import { parentEpml } from '../connect.js'
|
||||||
|
|
||||||
|
import { startConfigWatcher } from './onNewBlock.js'
|
||||||
|
|
||||||
|
const setAccountInfo = async (addr) => {
|
||||||
|
|
||||||
|
const names = await parentEpml.request('apiCall', {
|
||||||
|
url: `/names/address/${addr}`
|
||||||
|
})
|
||||||
|
const addressInfo = await parentEpml.request('apiCall', {
|
||||||
|
url: `/addresses/${addr}`
|
||||||
|
})
|
||||||
|
|
||||||
|
let accountInfo = {
|
||||||
|
names: names,
|
||||||
|
addressInfo: addressInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
parentEpml.request('setAccountInfo', accountInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const objectToArray = (object) => {
|
||||||
|
|
||||||
|
let groupList = object.groups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", sender: group.sender, senderName: group.senderName, timestamp: group.timestamp === undefined ? 1 : group.timestamp } : { ...group, url: `group/${group.groupId}` })
|
||||||
|
let directList = object.direct.map(dc => {
|
||||||
|
return { ...dc, url: `direct/${dc.address}` }
|
||||||
|
})
|
||||||
|
let chatHeadMasterList = [...groupList, ...directList]
|
||||||
|
|
||||||
|
return chatHeadMasterList
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortActiveChat = (activeChatObject, localChatHeads) => {
|
||||||
|
|
||||||
|
let oldChatHeads = JSON.parse(localChatHeads)
|
||||||
|
|
||||||
|
if (window.parent._.isEqual(oldChatHeads, activeChatObject) === true) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let oldActiveChats = objectToArray(oldChatHeads)
|
||||||
|
let newActiveChats = objectToArray(activeChatObject)
|
||||||
|
|
||||||
|
let results = newActiveChats.filter(newChat => {
|
||||||
|
let value = oldActiveChats.some(oldChat => newChat.timestamp === oldChat.timestamp)
|
||||||
|
return !value
|
||||||
|
});
|
||||||
|
|
||||||
|
results.forEach(chat => {
|
||||||
|
|
||||||
|
if (chat.sender !== window.parent.reduxStore.getState().app.selectedAddress.address) {
|
||||||
|
|
||||||
|
if (chat.sender !== undefined) parentEpml.request('showNotification', chat)
|
||||||
|
} else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let initialChatWatch = 0
|
||||||
|
|
||||||
|
const chatHeadWatcher = (activeChats) => {
|
||||||
|
|
||||||
|
let addr = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||||
|
|
||||||
|
let key = `${addr.substr(0, 10)}_chat-heads`
|
||||||
|
|
||||||
|
try {
|
||||||
|
let localChatHeads = localStorage.getItem(key)
|
||||||
|
|
||||||
|
if (localChatHeads === null) {
|
||||||
|
parentEpml.request('setLocalStorage', {
|
||||||
|
key: key,
|
||||||
|
dataObj: activeChats
|
||||||
|
}).then(ms => {
|
||||||
|
parentEpml.request('setChatHeads', activeChats).then(ret => {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
|
||||||
|
parentEpml.request('setLocalStorage', {
|
||||||
|
key: key,
|
||||||
|
dataObj: activeChats
|
||||||
|
}).then(ms => {
|
||||||
|
parentEpml.request('setChatHeads', activeChats).then(ret => {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (initialChatWatch >= 1) {
|
||||||
|
|
||||||
|
sortActiveChat(activeChats, localChatHeads)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
initialChatWatch = initialChatWatch + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let socketObject
|
||||||
|
let activeChatSocketTimeout
|
||||||
|
let initial = 0
|
||||||
|
let closeGracefully = false
|
||||||
|
let onceLoggedIn = false
|
||||||
|
let retryOnClose = false
|
||||||
|
let canPing = false
|
||||||
|
|
||||||
|
parentEpml.subscribe('logged_in', async isLoggedIn => {
|
||||||
|
|
||||||
|
const initChatHeadSocket = () => {
|
||||||
|
|
||||||
|
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
|
let nodeUrl = myNode.domain + ":" + myNode.port
|
||||||
|
|
||||||
|
let activeChatSocketLink
|
||||||
|
|
||||||
|
if (window.parent.location.protocol === "https:") {
|
||||||
|
|
||||||
|
activeChatSocketLink = `wss://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}`;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
activeChatSocketLink = `ws://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeChatSocket = new WebSocket(activeChatSocketLink);
|
||||||
|
|
||||||
|
// Open Connection
|
||||||
|
activeChatSocket.onopen = () => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET]: Connected.`);
|
||||||
|
socketObject = activeChatSocket
|
||||||
|
|
||||||
|
initial = initial + 1
|
||||||
|
canPing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message Event
|
||||||
|
activeChatSocket.onmessage = (e) => {
|
||||||
|
|
||||||
|
chatHeadWatcher(JSON.parse(e.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closed Event
|
||||||
|
activeChatSocket.onclose = () => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET]: CLOSED`);
|
||||||
|
clearInterval(activeChatSocketTimeout)
|
||||||
|
|
||||||
|
if (closeGracefully === false && initial <= 52) {
|
||||||
|
|
||||||
|
if (initial <= 52) {
|
||||||
|
|
||||||
|
parentEpml.request('showSnackBar', "Connection to the Qortal Core was lost, is your Core running ?")
|
||||||
|
retryOnClose = true
|
||||||
|
setTimeout(pingActiveChatSocket, 10000)
|
||||||
|
initial = initial + 1
|
||||||
|
} else {
|
||||||
|
|
||||||
|
parentEpml.request('showSnackBar', "Cannot connect to the Qortal Core, restart UI and Core!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error Event
|
||||||
|
activeChatSocket.onerror = (e) => {
|
||||||
|
|
||||||
|
console.log(`[SOCKET]: ${e.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const pingActiveChatSocket = () => {
|
||||||
|
|
||||||
|
if (window.parent.reduxStore.getState().app.loggedIn === true) {
|
||||||
|
|
||||||
|
if (!onceLoggedIn) {
|
||||||
|
|
||||||
|
initChatHeadSocket()
|
||||||
|
onceLoggedIn = true
|
||||||
|
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000)
|
||||||
|
} else if (retryOnClose) {
|
||||||
|
|
||||||
|
retryOnClose = false
|
||||||
|
clearTimeout(activeChatSocketTimeout)
|
||||||
|
initChatHeadSocket()
|
||||||
|
onceLoggedIn = true
|
||||||
|
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000)
|
||||||
|
} else if (canPing) {
|
||||||
|
|
||||||
|
socketObject.send('ping')
|
||||||
|
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (onceLoggedIn && !closeGracefully) {
|
||||||
|
|
||||||
|
closeGracefully = true
|
||||||
|
socketObject.close()
|
||||||
|
clearTimeout(activeChatSocketTimeout)
|
||||||
|
onceLoggedIn = false
|
||||||
|
canPing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isLoggedIn === 'true') {
|
||||||
|
|
||||||
|
// Call Set Account Info...
|
||||||
|
setAccountInfo(window.parent.reduxStore.getState().app.selectedAddress.address)
|
||||||
|
|
||||||
|
// Start Chat Watcher Socket
|
||||||
|
pingActiveChatSocket()
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (onceLoggedIn) {
|
||||||
|
|
||||||
|
closeGracefully = true
|
||||||
|
socketObject.close()
|
||||||
|
clearTimeout(activeChatSocketTimeout)
|
||||||
|
onceLoggedIn = false
|
||||||
|
canPing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
initialChatWatch = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
startConfigWatcher()
|
Loading…
x
Reference in New Issue
Block a user