Skip to content

Commit

Permalink
Merge pull request #190 from airgap-it/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
AndreasGassmann authored Apr 15, 2021
2 parents cf64078 + 14d23bb commit f731121
Show file tree
Hide file tree
Showing 24 changed files with 464 additions and 200 deletions.
4 changes: 2 additions & 2 deletions example-dapp.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
const client = new beacon.DAppClient({
name: 'Example DApp', // Name of the DApp,
// preferredNetwork: beacon.NetworkType.DELPHINET
// matrixNodes: ['matrix.papers.tech']
matrixNodes: ['beacon.tztip.me']
matrixNodes: ['matrix.papers.tech']
// matrixNodes: ['beacon.tztip.me']
})

// Display the active account in the UI
Expand Down
12 changes: 12 additions & 0 deletions example-wallet.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
<body>
Beacon Example Wallet
<br /><br />
<div id="status"></div>
<br /><br />
<button id="paste">Paste Sync Code</button>
<br /><br />
---
Expand All @@ -36,6 +38,10 @@
// matrixNodes: ['beacon.tztip.me']
})

const setStatus = (status) => {
document.getElementById('status').innerHTML = status ? 'Status: ' + status : status
}

// Add event listener to the button
document.getElementById('paste').addEventListener('click', () => {
navigator.clipboard.readText().then((clipText) => {
Expand All @@ -44,7 +50,9 @@
.deserialize(clipText)
.then((peer) => {
console.log('Adding peer', peer)
setStatus('Connecting...')
client.addPeer(peer).then(() => {
setStatus('')
console.log('Peer added')
})
})
Expand All @@ -56,6 +64,8 @@
console.log('init')
client
.connect(async (message) => {
setStatus('Handling request...')

console.log('message', message)
// Example: Handle PermissionRequest. A wallet should handle all request types
if (message.type === beacon.BeaconMessageType.PermissionRequest) {
Expand Down Expand Up @@ -84,6 +94,8 @@
}
client.respond(response)
}

setStatus('')
})
.catch((error) => console.error('connect error', error))
}) // Establish P2P connection
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@airgap/beacon-sdk",
"version": "2.2.3",
"version": "2.2.4",
"description": "The beacon-sdk allows you to easily connect DApps with Wallets through P2P communication or a chrome extension.",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
3 changes: 2 additions & 1 deletion scripts/generate-wallet-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export const webList: WebApp[] = [
links: {
[NetworkType.MAINNET]: 'https://wallet.kukai.app',
[NetworkType.DELPHINET]: 'https://testnet.kukai.app',
[NetworkType.EDONET]: 'https://edonet.kukai.app'
[NetworkType.EDONET]: 'https://edonet.kukai.app',
[NetworkType.FLORENCENET]: 'https://florencenet.kukai.app'
}
}
]
Expand Down
7 changes: 7 additions & 0 deletions src/clients/client/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ export abstract class Client extends BeaconClient {
return (await this.transport).addPeer(peer)
}

public async destroy(): Promise<void> {
if (this._transport.status === ExposedPromiseStatus.RESOLVED) {
await (await this.transport).disconnect()
}
await super.destroy()
}

/**
* A "setter" for when the transport needs to be changed.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const SDK_VERSION: string = '2.2.3'
export const SDK_VERSION: string = '2.2.4'
export const BEACON_VERSION: string = '2'
1 change: 1 addition & 0 deletions src/examples/custom-block-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class TzStatsBlockExplorer extends BlockExplorer {
[NetworkType.MAINNET]: 'https://tzstats.com/',
[NetworkType.DELPHINET]: 'https://delphi.tzstats.com/',
[NetworkType.EDONET]: 'https://edo.tzstats.com/',
[NetworkType.FLORENCENET]: 'https://florencenet.tzstats.com/',
[NetworkType.CUSTOM]: 'https://edo.tzstats.com/'
}
) {
Expand Down
135 changes: 101 additions & 34 deletions src/matrix-client/MatrixClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Storage } from '../storage/Storage'
import { Logger } from '../utils/Logger'
import { ExposedPromise } from '../utils/exposed-promise'
import { MatrixClientStore } from './MatrixClientStore'
import { MatrixHttpClient } from './MatrixHttpClient'
import { MatrixRoom, MatrixRoomStatus } from './models/MatrixRoom'
Expand Down Expand Up @@ -29,6 +30,22 @@ const MAX_POLLING_RETRIES = 3
* The matrix client used to connect to the matrix network
*/
export class MatrixClient {
private isActive: boolean = true
private _isReady: ExposedPromise<void> = new ExposedPromise()

constructor(
private readonly store: MatrixClientStore,
private readonly eventEmitter: MatrixClientEventEmitter,
private readonly userService: MatrixUserService,
private readonly roomService: MatrixRoomService,
private readonly eventService: MatrixEventService,
private readonly httpClient: MatrixHttpClient
) {
this.store.onStateChanged((oldState, newState, stateChange) => {
this.eventEmitter.onStateChanged(oldState, newState, stateChange)
}, 'rooms')
}

/**
* Create a matrix client based on the options provided
*
Expand All @@ -44,46 +61,59 @@ export class MatrixClient {
const roomService = new MatrixRoomService(httpClient)
const eventService = new MatrixEventService(httpClient)

return new MatrixClient(store, eventEmitter, accountService, roomService, eventService)
return new MatrixClient(
store,
eventEmitter,
accountService,
roomService,
eventService,
httpClient
)
}

/**
* Return all the rooms we are currently part of
*/
public get joinedRooms(): MatrixRoom[] {
return Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.JOINED
)
public get joinedRooms(): Promise<MatrixRoom[]> {
return new Promise(async (resolve) => {
await this.isConnected()

resolve(
Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.JOINED
)
)
})
}

/**
* Return all the rooms to which we have received invitations
*/
public get invitedRooms(): MatrixRoom[] {
return Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.INVITED
)
public get invitedRooms(): Promise<MatrixRoom[]> {
return new Promise(async (resolve) => {
await this.isConnected()

resolve(
Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.INVITED
)
)
})
}

/**
* Return all the rooms that we left
*/
public get leftRooms(): MatrixRoom[] {
return Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.LEFT
)
}

constructor(
private readonly store: MatrixClientStore,
private readonly eventEmitter: MatrixClientEventEmitter,
private readonly userService: MatrixUserService,
private readonly roomService: MatrixRoomService,
private readonly eventService: MatrixEventService
) {
this.store.onStateChanged((oldState, newState, stateChange) => {
this.eventEmitter.onStateChanged(oldState, newState, stateChange)
}, 'rooms')
public get leftRooms(): Promise<MatrixRoom[]> {
return new Promise(async (resolve) => {
await this.isConnected()

resolve(
Object.values(this.store.get('rooms')).filter(
(room) => room.status === MatrixRoomStatus.LEFT
)
)
})
}

/**
Expand All @@ -98,7 +128,7 @@ export class MatrixClient {
accessToken: response.access_token
})

return new Promise(async (resolve, reject) => {
const initialPollingResult = new Promise<void>(async (resolve, reject) => {
await this.poll(
0,
async (pollingResponse: MatrixSyncResponse) => {
Expand All @@ -124,6 +154,29 @@ export class MatrixClient {
}
)
})

initialPollingResult
.then(() => {
this._isReady.resolve()
})
.catch(console.error)

return initialPollingResult
}

public async isConnected(): Promise<void> {
return this._isReady.promise
}

/**
* Stop all running requests
*/
public async stop(): Promise<void> {
logger.log(`MATRIX CLIENT STOPPED`)
this.isActive = false
this._isReady = new ExposedPromise()

return this.httpClient.cancelAllRequests()
}

/**
Expand Down Expand Up @@ -156,7 +209,9 @@ export class MatrixClient {
}
}

public getRoomById(id: string): MatrixRoom {
public async getRoomById(id: string): Promise<MatrixRoom> {
await this.isConnected()

return this.store.getRoom(id)
}

Expand All @@ -166,6 +221,8 @@ export class MatrixClient {
* @param members Members that will be in the room
*/
public async createTrustedPrivateRoom(...members: string[]): Promise<string> {
await this.isConnected()

return this.requiresAuthorization('createRoom', async (accessToken) => {
const response = await this.roomService.createRoom(accessToken, {
invite: members,
Expand All @@ -184,6 +241,8 @@ export class MatrixClient {
* @param roomsOrIds The rooms the user will be invited to
*/
public async inviteToRooms(user: string, ...roomsOrIds: string[] | MatrixRoom[]): Promise<void> {
await this.isConnected()

await this.requiresAuthorization('invite', (accessToken) =>
Promise.all(
(roomsOrIds as any[]).map((roomOrId) => {
Expand All @@ -202,12 +261,14 @@ export class MatrixClient {
* @param roomsOrIds
*/
public async joinRooms(...roomsOrIds: string[] | MatrixRoom[]): Promise<void> {
await this.isConnected()

await this.requiresAuthorization('join', (accessToken) =>
Promise.all(
(roomsOrIds as any[]).map((roomOrId) => {
const room = this.store.getRoom(roomOrId)

return this.roomService.joinRoom(accessToken, room).catch((error) => console.warn(error))
return this.roomService.joinRoom(accessToken, room)
})
)
)
Expand All @@ -220,6 +281,8 @@ export class MatrixClient {
* @param message
*/
public async sendTextMessage(roomId: string, message: string): Promise<void> {
await this.isConnected()

await this.requiresAuthorization('send', async (accessToken) => {
const txnId = await this.createTxnId()

Expand Down Expand Up @@ -265,16 +328,20 @@ export class MatrixClient {

continueSyncing = store.get('pollingRetries') < MAX_POLLING_RETRIES
// console.warn('Could not sync:', error)
if (continueSyncing) {
if (continueSyncing && this.isActive) {
logger.log('Retry syncing...')
}
} finally {
if (continueSyncing) {
setTimeout(async () => {
await pollSync(resolve, reject)
}, interval)
if (this.isActive) {
if (continueSyncing) {
setTimeout(async () => {
await pollSync(resolve, reject)
}, interval)
} else {
reject(new Error(`Max polling retries exeeded: ${MAX_POLLING_RETRIES}`))
}
} else {
reject(new Error(`Max polling retries exeeded: ${MAX_POLLING_RETRIES}`))
reject(new Error(`Syncing stopped manually.`))
}
}
}
Expand Down
25 changes: 17 additions & 8 deletions src/matrix-client/MatrixClientEventEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ export class MatrixClientEventEmitter extends EventEmitter {
*/
private emitClientEvent<T extends MatrixClientEventType>(
eventType: T,
content: MatrixClientEventContent<T>
content: MatrixClientEventContent<T>,
timestamp?: number
): void {
this.emit(eventType, {
type: eventType,
content
content,
timestamp
})
}

Expand Down Expand Up @@ -123,14 +125,21 @@ export class MatrixClientEventEmitter extends EventEmitter {
stateChange.rooms
.filter((room) => room.messages.length > 0)
.map((room) =>
room.messages.map((message) => [room.id, message] as [string, MatrixMessage<any>])
room.messages.map(
(message) =>
[room.id, message, message.timestamp] as [string, MatrixMessage<unknown>, number]
)
)
.reduce((flatten, toFlatten) => flatten.concat(toFlatten), [])
.forEach(([roomId, message]) => {
this.emitClientEvent(eventType, {
roomId,
message
})
.forEach(([roomId, message, timestamp]) => {
this.emitClientEvent(
eventType,
{
roomId,
message
},
timestamp
)
})
}
}
Loading

0 comments on commit f731121

Please sign in to comment.