Skip to content

Commit

Permalink
fix(pss): subscribe in browsers, removed readable in browsers (#180)
Browse files Browse the repository at this point in the history
* fix: pss subscribe in browsers

* chore: return type on isBufferArray function

* test: browser pss send and receive

* chore: removed unnecessary comment in config

* chore: applied PR review suggestions

Co-authored-by: nugaon <50576770+nugaon@users.noreply.github.com>

* chore: implemented PR review suggestions

* refactor: removed readable-stream since streaming for requests is not supported

Co-authored-by: nugaon <50576770+nugaon@users.noreply.github.com>
  • Loading branch information
vojtechsimetka and nugaon authored Mar 10, 2021
1 parent ff8d178 commit a88277d
Show file tree
Hide file tree
Showing 8 changed files with 13,429 additions and 47 deletions.
5 changes: 5 additions & 0 deletions jest-puppeteer.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
launch: {
dumpio: true, // Forwards browser console into test console for easier debugging
},
}
13,310 changes: 13,287 additions & 23 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"browser": {
"./dist/index.min.js": "./dist/index.browser.min.js",
"stream": "readable-stream"
"data": "data.browser"
},
"types": "dist/index.d.ts",
"typings": "dist/index.d.ts",
Expand Down
8 changes: 5 additions & 3 deletions src/bee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,12 @@ export class Bee {
const cancel = () => {
if (cancelled === false) {
cancelled = true

// although the WebSocket API offers a `close` function, it seems that
// with the library that we are using (isomorphic-ws) it doesn't close
// the websocket properly, whereas `terminate` does
ws.terminate()
if (ws.terminate) ws.terminate()
else ws.close() // standard Websocket in browser does not have terminate function
}
}

Expand All @@ -292,8 +294,8 @@ export class Bee {
cancel,
}

ws.onmessage = ev => {
const data = prepareWebsocketData(ev.data)
ws.onmessage = async ev => {
const data = await prepareWebsocketData(ev.data)

// ignore empty messages
if (data.length > 0) {
Expand Down
24 changes: 24 additions & 0 deletions src/utils/data.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Validates input and converts to Uint8Array
*
* @param data any string, ArrayBuffer or Uint8Array
*/
export function prepareData(data: string | ArrayBuffer | Uint8Array): Uint8Array | never {
if (typeof data === 'string') return new TextEncoder().encode(data)

if (data instanceof ArrayBuffer) return new Uint8Array(data)

if (data instanceof Uint8Array) return data

throw new TypeError('unknown data type')
}

export async function prepareWebsocketData(data: string | ArrayBuffer | Blob): Promise<Uint8Array> | never {
if (typeof data === 'string') return new TextEncoder().encode(data)

if (data instanceof ArrayBuffer) return new Uint8Array(data)

if (data instanceof Blob) return new Uint8Array(await new Response(data as Blob).arrayBuffer())

throw new TypeError('unknown websocket data type')
}
47 changes: 29 additions & 18 deletions src/utils/data.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
import type { Readable } from 'stream'
import { Readable } from 'stream'
import type { Data } from 'ws'

export function prepareData(data: string | ArrayBuffer | Uint8Array | Readable): Uint8Array | Readable {
if (typeof data === 'string') {
return new TextEncoder().encode(data)
} else if (data instanceof ArrayBuffer) {
return new Uint8Array(data)
}
/**
* Validates input and converts to Uint8Array or Readable
*
* @param data any string, ArrayBuffer, Uint8Array or Readable
*/
export function prepareData(data: string | ArrayBuffer | Uint8Array | Readable): Uint8Array | Readable | never {
if (typeof data === 'string') return new TextEncoder().encode(data)

return data
if (data instanceof ArrayBuffer) return new Uint8Array(data)

if (data instanceof Uint8Array || data instanceof Readable) return data

throw new TypeError('unknown data type')
}

export function prepareWebsocketData(data: Data): Uint8Array {
if (typeof data === 'string') {
return new TextEncoder().encode(data)
} else if (data instanceof Buffer) {
return new Uint8Array(data)
} else if (data instanceof ArrayBuffer) {
return new Uint8Array(data)
} else {
return new Uint8Array(Buffer.concat(data))
}
function isBufferArray(buffer: unknown): buffer is Buffer[] {
return Array.isArray(buffer) && buffer.length > 0 && buffer.every(data => data instanceof Buffer)
}

export async function prepareWebsocketData(data: Data | Blob): Promise<Uint8Array> | never {
if (typeof data === 'string') return new TextEncoder().encode(data)

if (data instanceof Buffer) return new Uint8Array(data)

if (data instanceof ArrayBuffer) return new Uint8Array(data)

if (data instanceof Blob) return new Uint8Array(await new Response(data as Blob).arrayBuffer())

if (isBufferArray(data)) return new Uint8Array(Buffer.concat(data))

throw new TypeError('unknown websocket data type')
}
78 changes: 77 additions & 1 deletion test/bee-class.browser.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { join } from 'path'
import { beeUrl, commonMatchers } from './utils'
import { beeDebugUrl, beePeerUrl, beeUrl, commonMatchers, PSS_TIMEOUT } from './utils'
import '../src'

commonMatchers()

describe('Bee class - in browser', () => {
const BEE_URL = beeUrl()
const BEE_DEBUG_URL = beeDebugUrl()
const BEE_PEER_URL = beePeerUrl()

beforeAll(async done => {
await jestPuppeteer.resetPage()
const testPage = join(__dirname, 'testpage', 'testpage.html')
await page.goto(`file://${testPage}`)

Expand Down Expand Up @@ -80,4 +83,77 @@ describe('Bee class - in browser', () => {

expect(uploadEvent).toEqual({ loaded: 4, total: 4 })
})

describe('pss', () => {
it(
'should send and receive pss message',
async done => {
const message = '1234'

const result = await page.evaluate(
async (BEE_URL, BEE_DEBUG_URL, BEE_PEER_URL, message) => {
const topic = 'bee-class-topic'

const bee = new window.BeeJs.Bee(BEE_URL)
const beeDebug = new window.BeeJs.BeeDebug(BEE_DEBUG_URL)

const address = await beeDebug.getOverlayAddress()
const beePeer = new window.BeeJs.Bee(BEE_PEER_URL)

const receive = bee.pssReceive(topic)
await beePeer.pssSend(topic, address, message)

const msg = await receive

// Need to pass it back as string
return new TextDecoder('utf-8').decode(new Uint8Array(msg))
},
BEE_URL,
BEE_DEBUG_URL,
BEE_PEER_URL,
message,
)

expect(result).toEqual(message)
done()
},
PSS_TIMEOUT,
)

it(
'should send and receive pss message encrypted with PSS key',
async done => {
const message = '1234'

const result = await page.evaluate(
async (BEE_URL, BEE_DEBUG_URL, BEE_PEER_URL, message) => {
const topic = 'bee-class-topic'

const bee = new window.BeeJs.Bee(BEE_URL)
const beeDebug = new window.BeeJs.BeeDebug(BEE_DEBUG_URL)

const pssPublicKey = await beeDebug.getPssPublicKey()
const address = await beeDebug.getOverlayAddress()
const beePeer = new window.BeeJs.Bee(BEE_PEER_URL)

const receive = bee.pssReceive(topic)
await beePeer.pssSend(topic, address, message, pssPublicKey)

const msg = await receive

// Need to pass it back as string
return new TextDecoder('utf-8').decode(new Uint8Array(msg))
},
BEE_URL,
BEE_DEBUG_URL,
BEE_PEER_URL,
message,
)

expect(result).toEqual(message)
done()
},
PSS_TIMEOUT,
)
})
})
2 changes: 1 addition & 1 deletion test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const okResponse: BeeResponse = {
code: 200,
message: 'OK',
}
export const PSS_TIMEOUT = 60000
export const PSS_TIMEOUT = 120000
export const FEED_TIMEOUT = 120000

export const testChunkPayload = new Uint8Array([1, 2, 3])
Expand Down

0 comments on commit a88277d

Please sign in to comment.