Skip to content

Commit

Permalink
fix: react native adjustments (#2229)
Browse files Browse the repository at this point in the history
- export typed event emitter separately from setMaxListeners
- update react-native overrides in module package.json files
- add react-native-webrtc implementation to WebRTC transport

---------

Co-authored-by: achingbrain <alex@achingbrain.net>
  • Loading branch information
maschad and achingbrain committed Dec 10, 2023
1 parent 6d11e82 commit 3415811
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 132 deletions.
3 changes: 3 additions & 0 deletions packages/interface/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,8 @@
},
"browser": {
"events": "./dist/src/events.browser.js"
},
"react-native": {
"./dist/src/events.js": "./dist/src/events.browser.js"
}
}
116 changes: 116 additions & 0 deletions packages/interface/src/event-target.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
export interface EventCallback<EventType> { (evt: EventType): void }
export interface EventObject<EventType> { handleEvent: EventCallback<EventType> }
export type EventHandler<EventType> = EventCallback<EventType> | EventObject<EventType>

interface Listener {
once: boolean
callback: any
}

/**
* Adds types to the EventTarget class. Hopefully this won't be necessary forever.
*
* https://github.com/microsoft/TypeScript/issues/28357
* https://github.com/microsoft/TypeScript/issues/43477
* https://github.com/microsoft/TypeScript/issues/299
* etc
*/
export interface TypedEventTarget <EventMap extends Record<string, any>> extends EventTarget {
addEventListener<K extends keyof EventMap>(type: K, listener: EventHandler<EventMap[K]> | null, options?: boolean | AddEventListenerOptions): void

listenerCount (type: string): number

removeEventListener<K extends keyof EventMap>(type: K, listener?: EventHandler<EventMap[K]> | null, options?: boolean | EventListenerOptions): void

removeEventListener (type: string, listener?: EventHandler<Event>, options?: boolean | EventListenerOptions): void

safeDispatchEvent<Detail>(type: keyof EventMap, detail: CustomEventInit<Detail>): boolean
}

/**
* An implementation of a typed event target
* etc
*/
export class TypedEventEmitter<EventMap extends Record<string, any>> extends EventTarget implements TypedEventTarget<EventMap> {
#listeners = new Map<any, Listener[]>()

listenerCount (type: string): number {
const listeners = this.#listeners.get(type)

if (listeners == null) {
return 0
}

return listeners.length
}

addEventListener<K extends keyof EventMap>(type: K, listener: EventHandler<EventMap[K]> | null, options?: boolean | AddEventListenerOptions): void
addEventListener (type: string, listener: EventHandler<Event>, options?: boolean | AddEventListenerOptions): void {
super.addEventListener(type, listener, options)

let list = this.#listeners.get(type)

if (list == null) {
list = []
this.#listeners.set(type, list)
}

list.push({
callback: listener,
once: (options !== true && options !== false && options?.once) ?? false
})
}

removeEventListener<K extends keyof EventMap>(type: K, listener?: EventHandler<EventMap[K]> | null, options?: boolean | EventListenerOptions): void
removeEventListener (type: string, listener?: EventHandler<Event>, options?: boolean | EventListenerOptions): void {
super.removeEventListener(type.toString(), listener ?? null, options)

let list = this.#listeners.get(type)

if (list == null) {
return
}

list = list.filter(({ callback }) => callback !== listener)
this.#listeners.set(type, list)
}

dispatchEvent (event: Event): boolean {
const result = super.dispatchEvent(event)

let list = this.#listeners.get(event.type)

if (list == null) {
return result
}

list = list.filter(({ once }) => !once)
this.#listeners.set(event.type, list)

return result
}

safeDispatchEvent<Detail>(type: keyof EventMap, detail: CustomEventInit<Detail>): boolean {
return this.dispatchEvent(new CustomEvent<Detail>(type as string, detail))
}
}

/**
* CustomEvent is a standard event but it's not supported by node.
*
* Remove this when https://github.com/nodejs/node/issues/40678 is closed.
*
* Ref: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
*/
class CustomEventPolyfill<T = any> extends Event {
/** Returns any custom data event was created with. Typically used for synthetic events. */
public detail: T

constructor (message: string, data?: EventInit & { detail: T }) {
super(message, data)
// @ts-expect-error could be undefined
this.detail = data?.detail
}
}

export const CustomEvent = globalThis.CustomEvent ?? CustomEventPolyfill
117 changes: 0 additions & 117 deletions packages/interface/src/events.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,5 @@
import { setMaxListeners as nodeSetMaxListeners } from 'events'

export interface EventCallback<EventType> { (evt: EventType): void }
export interface EventObject<EventType> { handleEvent: EventCallback<EventType> }
export type EventHandler<EventType> = EventCallback<EventType> | EventObject<EventType>

interface Listener {
once: boolean
callback: any
}

/**
* Adds types to the EventTarget class. Hopefully this won't be necessary forever.
*
* https://github.com/microsoft/TypeScript/issues/28357
* https://github.com/microsoft/TypeScript/issues/43477
* https://github.com/microsoft/TypeScript/issues/299
* etc
*/
export interface TypedEventTarget <EventMap extends Record<string, any>> extends EventTarget {
addEventListener<K extends keyof EventMap>(type: K, listener: EventHandler<EventMap[K]> | null, options?: boolean | AddEventListenerOptions): void

listenerCount (type: string): number

removeEventListener<K extends keyof EventMap>(type: K, listener?: EventHandler<EventMap[K]> | null, options?: boolean | EventListenerOptions): void

removeEventListener (type: string, listener?: EventHandler<Event>, options?: boolean | EventListenerOptions): void

safeDispatchEvent<Detail>(type: keyof EventMap, detail: CustomEventInit<Detail>): boolean
}

/**
* An implementation of a typed event target
* etc
*/
export class TypedEventEmitter<EventMap extends Record<string, any>> extends EventTarget implements TypedEventTarget<EventMap> {
#listeners = new Map<any, Listener[]>()

listenerCount (type: string): number {
const listeners = this.#listeners.get(type)

if (listeners == null) {
return 0
}

return listeners.length
}

addEventListener<K extends keyof EventMap>(type: K, listener: EventHandler<EventMap[K]> | null, options?: boolean | AddEventListenerOptions): void
addEventListener (type: string, listener: EventHandler<Event>, options?: boolean | AddEventListenerOptions): void {
super.addEventListener(type, listener, options)

let list = this.#listeners.get(type)

if (list == null) {
list = []
this.#listeners.set(type, list)
}

list.push({
callback: listener,
once: (options !== true && options !== false && options?.once) ?? false
})
}

removeEventListener<K extends keyof EventMap>(type: K, listener?: EventHandler<EventMap[K]> | null, options?: boolean | EventListenerOptions): void
removeEventListener (type: string, listener?: EventHandler<Event>, options?: boolean | EventListenerOptions): void {
super.removeEventListener(type.toString(), listener ?? null, options)

let list = this.#listeners.get(type)

if (list == null) {
return
}

list = list.filter(({ callback }) => callback !== listener)
this.#listeners.set(type, list)
}

dispatchEvent (event: Event): boolean {
const result = super.dispatchEvent(event)

let list = this.#listeners.get(event.type)

if (list == null) {
return result
}

list = list.filter(({ once }) => !once)
this.#listeners.set(event.type, list)

return result
}

safeDispatchEvent<Detail>(type: keyof EventMap, detail: CustomEventInit<Detail>): boolean {
return this.dispatchEvent(new CustomEvent<Detail>(type as string, detail))
}
}

/**
* CustomEvent is a standard event but it's not supported by node.
*
* Remove this when https://github.com/nodejs/node/issues/40678 is closed.
*
* Ref: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
*/
class CustomEventPolyfill<T = any> extends Event {
/** Returns any custom data event was created with. Typically used for synthetic events. */
public detail: T

constructor (message: string, data?: EventInit & { detail: T }) {
super(message, data)
// @ts-expect-error could be undefined
this.detail = data?.detail
}
}

export const CustomEvent = globalThis.CustomEvent ?? CustomEventPolyfill

// create a setMaxListeners that doesn't break browser usage
export const setMaxListeners: typeof nodeSetMaxListeners = (n, ...eventTargets) => {
try {
Expand Down
3 changes: 2 additions & 1 deletion packages/interface/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import type { Connection, NewStreamOptions, Stream } from './connection/index.js'
import type { ContentRouting } from './content-routing/index.js'
import type { TypedEventTarget } from './events.js'
import type { TypedEventTarget } from './event-target.js'
import type { Metrics } from './metrics/index.js'
import type { PeerId } from './peer-id/index.js'
import type { PeerInfo } from './peer-info/index.js'
Expand Down Expand Up @@ -690,5 +690,6 @@ export * from './stream-muxer/index.js'
export * from './topology/index.js'
export * from './transport/index.js'
export * from './errors.js'
export * from './event-target.js'
export * from './events.js'
export * from './startable.js'
2 changes: 1 addition & 1 deletion packages/interface/src/peer-discovery/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TypedEventTarget } from '../events.js'
import type { TypedEventTarget } from '../event-target.js'
import type { PeerInfo } from '../peer-info/index.js'

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/interface/src/pubsub/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Stream } from '../connection/index.js'
import type { TypedEventTarget } from '../events.js'
import type { TypedEventTarget } from '../event-target.js'
import type { PeerId } from '../peer-id/index.js'
import type { Pushable } from 'it-pushable'
import type { Uint8ArrayList } from 'uint8arraylist'
Expand Down
2 changes: 1 addition & 1 deletion packages/interface/src/transport/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Connection, MultiaddrConnection } from '../connection/index.js'
import type { TypedEventTarget } from '../events.js'
import type { TypedEventTarget } from '../event-target.js'
import type { AbortOptions } from '../index.js'
import type { StreamMuxerFactory } from '../stream-muxer/index.js'
import type { Multiaddr } from '@multiformats/multiaddr'
Expand Down
4 changes: 4 additions & 0 deletions packages/libp2p/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,9 @@
"browser": {
"./dist/src/connection-manager/constants.js": "./dist/src/connection-manager/constants.browser.js",
"./dist/src/config/connection-gater.js": "./dist/src/config/connection-gater.browser.js"
},
"react-native": {
"./dist/src/connection-manager/constants.js": "./dist/src/connection-manager/constants.browser.js",
"./dist/src/config/connection-gater.js": "./dist/src/config/connection-gater.browser.js"
}
}
3 changes: 0 additions & 3 deletions packages/stream-multiplexer-mplex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,5 @@
"it-pipe": "^3.0.1",
"p-defer": "^4.0.0",
"random-int": "^3.0.0"
},
"browser": {
"./dist/src/alloc-unsafe.js": "./dist/src/alloc-unsafe-browser.js"
}
}
3 changes: 0 additions & 3 deletions packages/stream-multiplexer-mplex/src/alloc-unsafe-browser.ts

This file was deleted.

3 changes: 0 additions & 3 deletions packages/stream-multiplexer-mplex/src/alloc-unsafe.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/stream-multiplexer-mplex/src/encode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as varint from 'uint8-varint'
import { Uint8ArrayList } from 'uint8arraylist'
import { allocUnsafe } from './alloc-unsafe.js'
import { allocUnsafe } from 'uint8arrays/alloc'
import { type Message, MessageTypes } from './message-types.js'
import type { Source } from 'it-stream-types'

Expand Down
4 changes: 4 additions & 0 deletions packages/transport-webrtc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"p-timeout": "^6.1.2",
"protons-runtime": "^5.0.0",
"race-signal": "^1.0.0",
"react-native-webrtc": "^118.0.0",
"uint8arraylist": "^2.4.3",
"uint8arrays": "^5.0.0"
},
Expand All @@ -97,5 +98,8 @@
},
"browser": {
"./dist/src/webrtc/index.js": "./dist/src/webrtc/index.browser.js"
},
"react-native": {
"./dist/src/webrtc/index.js": "./dist/src/webrtc/index.react-native.js"
}
}
5 changes: 5 additions & 0 deletions packages/transport-webrtc/src/webrtc/index.react-native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
RTCIceCandidate,
RTCPeerConnection,
RTCSessionDescription
} from 'react-native-webrtc'
2 changes: 1 addition & 1 deletion packages/transport-websockets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"@multiformats/multiaddr": "^12.1.10",
"@multiformats/multiaddr-to-uri": "^9.0.2",
"@types/ws": "^8.5.4",
"it-ws": "^6.0.0",
"it-ws": "^6.1.0",
"p-defer": "^4.0.0",
"wherearewe": "^2.0.1",
"ws": "^8.12.1"
Expand Down
3 changes: 3 additions & 0 deletions packages/transport-webtransport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,8 @@
},
"browser": {
"./dist/src/listener.js": "./dist/src/listener.browser.js"
},
"react-native": {
"./dist/src/listener.js": "./dist/src/listener.browser.js"
}
}

0 comments on commit 3415811

Please sign in to comment.