Skip to content

Commit

Permalink
refactor(rpc)!: inline extra helpers
Browse files Browse the repository at this point in the history
BREAKING CHANGE: RPC helpers are not exposed anymore
Use own implementation instead of `isInIframe`, `sendMessage`, `getHandler`, `message`,
`responseMessage`, `sendResponseMessage`, `isValidAccounts`
  • Loading branch information
davidyuk committed May 24, 2022
1 parent 7b04e5a commit 9a0a2eb
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 99 deletions.
Expand Up @@ -29,7 +29,7 @@
import stampit from '@stamp/it'
import WalletConnection from '.'
import { MESSAGE_DIRECTION } from '../schema'
import { getBrowserAPI, isInIframe } from '../helpers'
import { getBrowserAPI } from '../helpers'
import {
AlreadyConnectedError,
NoWalletConnectedError,
Expand Down Expand Up @@ -111,7 +111,8 @@ const getTarget = () => {
// When we is the main page we need to decide the target by our self
// Probably can be implemented some algo for checking DOM for Iframes and somehow decide which
// Iframe to talk
return isInIframe() ? window.parent : undefined
const isInIframe = window !== window.parent
return isInIframe ? window.parent : undefined
}

/**
Expand Down
46 changes: 0 additions & 46 deletions src/utils/aepp-wallet-communication/helpers.js
Expand Up @@ -12,49 +12,3 @@ export const getBrowserAPI = (force = false) => {
if (!force) throw new NoBrowserFoundError()
return {}
}

export const isInIframe = () => window !== window.parent

/**
* RPC helper functions
*/
export const sendMessage = (connection) => {
let messageId = 0

return ({ id, method, params, result, error }, isNotificationOrResponse = false) => {
// Increment id for each request
isNotificationOrResponse || (messageId += 1)
id = isNotificationOrResponse ? (id || null) : messageId
const msgData = params
? { params }
: result
? { result }
: { error }
connection.sendMessage({
jsonrpc: '2.0',
...id ? { id } : {},
method,
...msgData
})
return id
}
}

export const getHandler = (schema, msg, { debug = false } = {}) => {
const handler = schema[msg.method]
if (!handler || typeof handler !== 'function') {
debug && console.log(`Unknown message method ${msg.method}`)
return () => async () => true
}
return handler
}

export const message = (method, params = {}) => ({ method, params })

export const responseMessage = (id, method, { error, result } = {}) =>
({ id, method, ...(error ? { error } : { result }) })

export const sendResponseMessage = (client) => (id, method, data) =>
client.sendMessage(responseMessage(id, method, data), true)

export const isValidAccounts = (accounts) => (['', 'connected', 'current'].filter(k => typeof (k ? accounts[k] : accounts) === 'object')).length === 3
12 changes: 6 additions & 6 deletions src/utils/aepp-wallet-communication/rpc/aepp-rpc.js
Expand Up @@ -13,7 +13,6 @@ import AccountRpc from '../../../account/rpc'
import { decode } from '../../encoder'
import AsyncInit from '../../../utils/async-init'
import RpcClient from './rpc-client'
import { getHandler, message } from '../helpers'
import { METHODS, RPC_STATUS, VERSION } from '../schema'
import {
AlreadyConnectedError,
Expand Down Expand Up @@ -41,7 +40,8 @@ const NOTIFICATIONS = {
(msg) => {
instance.disconnectWallet()
instance.onDisconnect(msg.params)
}
},
[METHODS.readyToConnect]: () => () => {}
}

const RESPONSES = {
Expand Down Expand Up @@ -81,11 +81,11 @@ const REQUESTS = {}

const handleMessage = (instance) => async (msg) => {
if (!msg.id) {
return getHandler(NOTIFICATIONS, msg, { debug: instance.debug })(instance)(msg)
return NOTIFICATIONS[msg.method](instance)(msg)
} else if (Object.prototype.hasOwnProperty.call(instance.rpcClient.callbacks, msg.id)) {
return getHandler(RESPONSES, msg, { debug: instance.debug })(instance)(msg)
return RESPONSES[msg.method](instance)(msg)
} else {
return getHandler(REQUESTS, msg, { debug: instance.debug })(instance)(msg)
return REQUESTS[msg.method](instance)(msg)
}
}

Expand Down Expand Up @@ -181,7 +181,7 @@ export default AccountResolver.compose(AsyncInit, {
async disconnectWallet (sendDisconnect = true) {
this._ensureConnected()
if (sendDisconnect) {
this.rpcClient.sendMessage(message(METHODS.closeConnection, { reason: 'bye' }), true)
this.rpcClient.sendMessage({ method: METHODS.closeConnection, params: { reason: 'bye' } }, true)
}
this.rpcClient.disconnect()
this.rpcClient = null
Expand Down
27 changes: 19 additions & 8 deletions src/utils/aepp-wallet-communication/rpc/rpc-client.js
Expand Up @@ -9,10 +9,8 @@
import stampit from '@stamp/it'

import { METHODS, RPC_STATUS, SUBSCRIPTION_TYPES } from '../schema'
import { sendMessage, message, isValidAccounts } from '../helpers'
import {
InvalidRpcMessageError,
TypeError,
DuplicateCallbackError,
MissingCallbackError
} from '../../errors'
Expand Down Expand Up @@ -47,7 +45,7 @@ export default stampit({
// }
this.accounts = {}

this.sendMessage = sendMessage(this.connection)
this._messageId = 0

const handleMessage = (msg, origin) => {
if (!msg || !msg.jsonrpc || msg.jsonrpc !== '2.0' || !msg.method) {
Expand Down Expand Up @@ -91,6 +89,22 @@ export default stampit({
}
},
methods: {
sendMessage ({ id, method, params, result, error }, isNotificationOrResponse = false) {
if (!isNotificationOrResponse) this._messageId += 1
id = isNotificationOrResponse ? (id ?? null) : this._messageId
const msgData = params
? { params }
: result
? { result }
: { error }
this.connection.sendMessage({
jsonrpc: '2.0',
...id ? { id } : {},
method,
...msgData
})
return id
},
/**
* Update info
* @function updateInfo
Expand Down Expand Up @@ -163,13 +177,10 @@ export default stampit({
* @param {Boolean} [options.forceNotification] Don't sent update notification to AEPP
*/
setAccounts (accounts, { forceNotification } = {}) {
if (!isValidAccounts(accounts)) {
throw new TypeError('Invalid accounts object. Should be object like: `{ connected: {}, selected: {} }`')
}
this.accounts = accounts
if (!forceNotification) {
// Sent notification about account updates
this.sendMessage(message(METHODS.updateAddress, this.accounts), true)
this.sendMessage({ method: METHODS.updateAddress, params: this.accounts }, true)
}
},
/**
Expand Down Expand Up @@ -200,7 +211,7 @@ export default stampit({
* @return {Promise} Promise which will be resolved after receiving response message
*/
request (name, params) {
const msgId = this.sendMessage(message(name, params))
const msgId = this.sendMessage({ method: name, params })
if (Object.prototype.hasOwnProperty.call(this.callbacks, msgId)) {
throw new DuplicateCallbackError()
}
Expand Down
29 changes: 13 additions & 16 deletions src/utils/aepp-wallet-communication/rpc/wallet-rpc.js
Expand Up @@ -11,7 +11,7 @@ import Ae from '../../../ae'
import verifyTransaction from '../../../tx/validator'
import AccountMultiple from '../../../account/multiple'
import RpcClient from './rpc-client'
import { getBrowserAPI, getHandler, isValidAccounts, message, sendResponseMessage } from '../helpers'
import { getBrowserAPI } from '../helpers'
import { ERRORS, METHODS, RPC_STATUS, VERSION, WALLET_TYPE } from '../schema'
import { ArgumentError, TypeError, UnknownRpcClientError } from '../../errors'
import { isAccountBase } from '../../../account/base'
Expand Down Expand Up @@ -85,9 +85,6 @@ const REQUESTS = {
async ({ accounts } = {}) => {
try {
const clientAccounts = accounts || instance.getAccounts()
if (!isValidAccounts(clientAccounts)) {
throw new TypeError('Invalid provided accounts object')
}
const subscription = client.updateSubscription(type, value)
client.setAccounts(clientAccounts, { forceNotification: true })
return {
Expand Down Expand Up @@ -195,12 +192,10 @@ const REQUESTS = {
const handleMessage = (instance, id) => async (msg, origin) => {
const client = instance.rpcClients[id]
if (!msg.id) {
return getHandler(
NOTIFICATIONS, msg, { debug: instance.debug }
)(instance, { client })(msg, origin)
return NOTIFICATIONS[msg.method](instance, { client })(msg, origin)
}
if (Object.prototype.hasOwnProperty.call(client.callbacks, msg.id)) {
return getHandler(RESPONSES, msg, { debug: instance.debug })(instance, { client })(msg, origin)
return RESPONSES[msg.method](instance, { client })(msg, origin)
} else {
const { id, method } = msg
const callInstance = (methodName, params, accept, deny) => () => new Promise(resolve => {
Expand All @@ -217,11 +212,10 @@ const handleMessage = (instance, id) => async (msg, origin) => {
)
})
// TODO make one structure for handler functions
const errorObjectOrHandler = getHandler(REQUESTS, msg, { debug: instance.debug })(
callInstance, instance, client, msg.params
)
const errorObjectOrHandler = REQUESTS[msg.method](callInstance, instance, client, msg.params)
const response = typeof errorObjectOrHandler === 'function' ? await errorObjectOrHandler() : errorObjectOrHandler
sendResponseMessage(client)(id, method, response)
const { error, result } = response ?? {}
client.sendMessage({ id, method, ...error ? { error } : { result } }, true)
}
}

Expand Down Expand Up @@ -298,11 +292,13 @@ export default Ae.compose(AccountMultiple, {
Object.values(this.rpcClients)
.filter(client => client.isConnected())
.forEach(client => {
client.sendMessage(
message(METHODS.updateNetwork, {
client.sendMessage({
method: METHODS.updateNetwork,
params: {
networkId: this.getNetworkId(),
...client.info.status === RPC_STATUS.NODE_BINDED && { node: this.selectedNode }
}), true)
}
}, true)
})
}
},
Expand Down Expand Up @@ -354,7 +350,8 @@ export default Ae.compose(AccountMultiple, {
shareWalletInfo (postFn) {
postFn({
jsonrpc: '2.0',
...message(METHODS.readyToConnect, this.getWalletInfo())
method: METHODS.readyToConnect,
params: this.getWalletInfo()
})
},
/**
Expand Down
22 changes: 1 addition & 21 deletions test/integration/rpc.js
Expand Up @@ -22,7 +22,7 @@ import { concatBuffers } from '../../src/utils/other'
import { unpackTx } from '../../src/tx/builder'
import { decode } from '../../src/tx/builder/helpers'
import BrowserWindowMessageConnection from '../../src/utils/aepp-wallet-communication/connection/browser-window-message'
import { getBrowserAPI, getHandler } from '../../src/utils/aepp-wallet-communication/helpers'
import { getBrowserAPI } from '../../src/utils/aepp-wallet-communication/helpers'
import { METHODS, RPC_STATUS } from '../../src/utils/aepp-wallet-communication/schema'
import { generateKeyPair, verify, hash } from '../../src/utils/crypto'
import { compilerUrl, account, networkId, url, ignoreVersion, spendPromise } from './'
Expand Down Expand Up @@ -154,14 +154,6 @@ describe('Aepp<->Wallet', function () {
.rejectedWith('Operation rejected by user').with.property('code', 4)
})

it('Subscribe to address: invalid accounts', async () => {
wallet.onSubscription = (aepp, actions) => {
actions.accept({ accounts: {} })
}
await expect(aepp.subscribeAddress('subscribe', 'connected'))
.to.be.rejectedWith('Invalid provided accounts object')
})

it('Subscribe to address: wallet accept', async () => {
const accounts = {
connected: { [keypair.publicKey]: {} },
Expand Down Expand Up @@ -397,14 +389,6 @@ describe('Aepp<->Wallet', function () {
received.should.be.equal(true)
})

it('RPC client set invalid account', () => {
const current = aepp.rpcClient.getCurrentAccount()
current.should.be.equal(aepp.rpcClient.currentAccount)
aepp.rpcClient.origin.should.be.an('object')
expect(() => aepp.rpcClient.setAccounts(true))
.to.throw(TypeError, 'Invalid accounts object. Should be object like: `{ connected: {}, selected: {} }`')
})

it('Resolve/Reject callback for undefined message', async () => {
expect(() => aepp.rpcClient.processResponse({ id: 0 }))
.to.throw('Can\'t find callback for this messageId 0')
Expand Down Expand Up @@ -468,10 +452,6 @@ describe('Aepp<->Wallet', function () {
connectionFromAeppToWallet.disconnect()
})

it('receive unknown method', async () => {
(await getHandler({}, { method: 'hey' })()()).should.be.equal(true)
})

it('getBrowserAPI: not in browser', () => {
global.window = {}
expect(() => getBrowserAPI()).to.throw(NoBrowserFoundError, 'Browser is not detected')
Expand Down

0 comments on commit 9a0a2eb

Please sign in to comment.