Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple WebSocket transport from Core #106

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
220 changes: 67 additions & 153 deletions packages/core/src/index.ts
Expand Up @@ -29,6 +29,7 @@ import {
isHexStrict,
convertUtf8ToHex
} from '@walletconnect/utils'
import SocketTransport from './socket'

// -- typeChecks ----------------------------------------------------------- //

Expand Down Expand Up @@ -84,12 +85,10 @@ class Connector {
private _handshakeTopic: string
private _accounts: string[]
private _chainId: number
private _socket: WebSocket | null
private _queue: ISocketMessage[]
private _socket: SocketTransport
private _eventEmitters: IEventEmitter[]
private _connected: boolean
private _browser: boolean
private _pingInterval: any

// -- constructor ----------------------------------------------------- //

Expand All @@ -116,12 +115,9 @@ class Connector {
this._handshakeTopic = ''
this._accounts = []
this._chainId = 0
this._socket = null
this._queue = []
this._eventEmitters = []
this._connected = false
this._browser = browser
this._pingInterval = null

if (
browser &&
Expand Down Expand Up @@ -154,7 +150,7 @@ class Connector {
if (session) {
this.session = session
if (this._browser) {
this._exchangeKey()
// this._exchangeKey()
}
}

Expand All @@ -165,8 +161,20 @@ class Connector {
)
}

this._socket = new SocketTransport({
bridge: this.bridge,
callback: (socketMessage: ISocketMessage) =>
this._handleIncomingMessages(socketMessage)
})

this._subscribeToInternalEvents()
this._socketOpen()
this._socket.open([
{
topic: `${this.clientId}`,
type: 'sub',
payload: ''
}
])
}

// -- setters / getters ----------------------------------------------- //
Expand Down Expand Up @@ -672,11 +680,7 @@ class Connector {
payload
}

if (this._socket && this._socket.readyState === 1) {
this._socketSend(socketMessage)
} else {
this._setToQueue(socketMessage)
}
this._socket.send(socketMessage)
}

private async _sendResponse (
Expand All @@ -695,11 +699,7 @@ class Connector {
payload
}

if (this._socket && this._socket.readyState === 1) {
this._socketSend(socketMessage)
} else {
this._setToQueue(socketMessage)
}
this._socket.send(socketMessage)
}

private async _sendSessionRequest (
Expand Down Expand Up @@ -758,7 +758,7 @@ class Connector {
})
}
this._removeStorageSession()
this._toggleSocketPing()
this._socket.togglePing()
}

private _handleSessionResponse (
Expand Down Expand Up @@ -828,8 +828,33 @@ class Connector {
}
}

private async _handleIncomingMessages (socketMessage: ISocketMessage) {
const activeTopics = [this.clientId, this.handshakeTopic]

if (!activeTopics.includes(socketMessage.topic)) {
return
}

let encryptionPayload: IEncryptionPayload
try {
encryptionPayload = JSON.parse(socketMessage.payload)
} catch (error) {
throw error
}

const payload:
| IJsonRpcRequest
| IJsonRpcResponseSuccess
| IJsonRpcResponseError
| null = await this._decrypt(encryptionPayload)

if (payload) {
this._triggerEvents(payload)
}
}

private _subscribeToSessionRequest () {
this._setToQueue({
this._socket.setToQueue({
topic: `${this.handshakeTopic}`,
type: 'sub',
payload: ''
Expand Down Expand Up @@ -886,7 +911,7 @@ class Connector {
this.peerId = payload.params[0].peerId
this.peerMeta = payload.params[0].peerMeta

this._exchangeKey()
// this._exchangeKey()

const internalPayload = {
...payload,
Expand Down Expand Up @@ -976,27 +1001,27 @@ class Connector {

// -- keyManager ------------------------------------------------------- //

private async _exchangeKey () {
this._nextKey = await this._generateKey()

const request: IJsonRpcRequest = this._formatRequest({
method: 'wc_exchangeKey',
params: [
{
peerId: this.clientId,
peerMeta: this.clientMeta,
nextKey: this.nextKey
}
]
})

try {
await this._sendCallRequest(request)
this._swapKey()
} catch (error) {
throw error
}
}
// private async _exchangeKey () {
// this._nextKey = await this._generateKey()

// const request: IJsonRpcRequest = this._formatRequest({
// method: 'wc_exchangeKey',
// params: [
// {
// peerId: this.clientId,
// peerMeta: this.clientMeta,
// nextKey: this.nextKey
// }
// ]
// })

// try {
// await this._sendCallRequest(request)
// this._swapKey()
// } catch (error) {
// throw error
// }
// }

private async _handleExchangeKeyRequest (payload: IJsonRpcRequest) {
const { peerId, peerMeta, nextKey } = payload.params[0]
Expand All @@ -1020,117 +1045,6 @@ class Connector {
}
}

// -- websocket ------------------------------------------------------- //

private _socketOpen () {
const bridge = this.bridge

const url = bridge.startsWith('https')
? bridge.replace('https', 'wss')
: bridge.startsWith('http')
? bridge.replace('http', 'ws')
: bridge

const socket = new WebSocket(url)

socket.onmessage = (event: MessageEvent) => this._socketReceive(event)

socket.onopen = () => {
this._socket = socket

this._setToQueue({
topic: `${this.clientId}`,
type: 'sub',
payload: ''
})

this._dispatchQueue()
this._toggleSocketPing()
}
}

private _toggleSocketPing () {
if (this._socket && this._socket.readyState === 1) {
this._pingInterval = setInterval(
() => {
if (this._socket) {
this._socket.send('ping')
}
},
10000 // 10 seconds
)
} else {
clearInterval(this._pingInterval)
}
}

private _socketSend (socketMessage: ISocketMessage) {
if (!this._socket) {
throw new Error('Missing socket: required for sending message')
}

const message: string = JSON.stringify(socketMessage)

if (this._socket && this._socket.readyState === 1) {
this._socket.send(message)
} else {
if (this._connected) {
this._setToQueue(socketMessage)
this._socketOpen()
}
}
}

private async _socketReceive (event: MessageEvent) {
let socketMessage: ISocketMessage

if (event.data === 'pong') {
return
}

try {
socketMessage = JSON.parse(event.data)
} catch (error) {
throw error
}

const activeTopics = [this.clientId, this.handshakeTopic]
if (!activeTopics.includes(socketMessage.topic)) {
return
}

let encryptionPayload: IEncryptionPayload
try {
encryptionPayload = JSON.parse(socketMessage.payload)
} catch (error) {
throw error
}

const payload:
| IJsonRpcRequest
| IJsonRpcResponseSuccess
| IJsonRpcResponseError
| null = await this._decrypt(encryptionPayload)

if (payload) {
this._triggerEvents(payload)
}
}

private _setToQueue (socketMessage: ISocketMessage) {
this._queue.push(socketMessage)
}

private _dispatchQueue () {
const queue = this._queue

queue.forEach((socketMessage: ISocketMessage) =>
this._socketSend(socketMessage)
)

this._queue = []
}

// -- uri ------------------------------------------------------------- //

private _formatUri () {
Expand Down