nbd-wtf / nostr-tools

Tools for developing Nostr clients.
The Unlicense
685 stars 188 forks source link

React Native: ReferenceError: Property 'MessageChannel' doesn't exist #374

Open damiandizeo opened 6 months ago

damiandizeo commented 6 months ago

In React Native, i get a crash here: https://github.com/nbd-wtf/nostr-tools/blob/master/helpers.ts#L5 when do relay.subscribe, i get event btw.

Looks like class MessageChannel is not part of React Native.

alexgleason commented 6 months ago

Lol I saw that. I think that function should be replaced with return new Promise(resolve => setTimeout(resolve)) for basically the same effect.

But you are still going to have the problems in #80. Try downgrading to 1.x and see if you can get it to work at all.

damiandizeo commented 6 months ago

Well recreated the class that mimics the behavior of MessageChannel in React Native, leave it here if helps someone.

class MessageChannel {
  constructor() {
    this.port1 = new MessagePort();
    this.port2 = new MessagePort();
    this.port1.setOtherPort(this.port2);
    this.port2.setOtherPort(this.port1);
  }
}

class MessagePort {
  constructor() {
    this.otherPort = null;
    this.listeners = new Map();
  }

  setOtherPort(otherPort) {
    this.otherPort = otherPort;
  }

  addEventListener(event, listener) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event).push(listener);
  }

  removeEventListener(event, listener) {
    const eventListeners = this.listeners.get(event);
    if (eventListeners) {
      const index = eventListeners.indexOf(listener);
      if (index !== -1) {
        eventListeners.splice(index, 1);
      }
    }
  }

  postMessage(data) {
    this.otherPort.dispatchEvent('message', { data });
  }

  start() {
    // No-op in React Native
  }

  dispatchEvent(event, data) {
    const eventListeners = this.listeners.get(event);
    if (eventListeners) {
      eventListeners.forEach(listener => listener(data));
    }
  }
}

global.MessageChannel = MessageChannel;

global.MessageChannel is now compatible with yieldThread function in helper.ts

The crash gone and i get all events now, will be testing... Thanks @alexgleason.

abhay-raizada commented 5 months ago

Used @damiandizeo 's workaround and it works!, can't evaluate the stability yet, will update if it breaks elsewhere! But thank you for posting! ❤️

tempo-beme commented 4 months ago

Well recreated the class that mimics the behavior of MessageChannel in React Native, leave it here if helps someone.

class MessageChannel {
  constructor() {
    this.port1 = new MessagePort();
    this.port2 = new MessagePort();
    this.port1.setOtherPort(this.port2);
    this.port2.setOtherPort(this.port1);
  }
}

class MessagePort {
  constructor() {
    this.otherPort = null;
    this.listeners = new Map();
  }

  setOtherPort(otherPort) {
    this.otherPort = otherPort;
  }

  addEventListener(event, listener) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event).push(listener);
  }

  removeEventListener(event, listener) {
    const eventListeners = this.listeners.get(event);
    if (eventListeners) {
      const index = eventListeners.indexOf(listener);
      if (index !== -1) {
        eventListeners.splice(index, 1);
      }
    }
  }

  postMessage(data) {
    this.otherPort.dispatchEvent('message', { data });
  }

  start() {
    // No-op in React Native
  }

  dispatchEvent(event, data) {
    const eventListeners = this.listeners.get(event);
    if (eventListeners) {
      eventListeners.forEach(listener => listener(data));
    }
  }
}

global.MessageChannel = MessageChannel;

global.MessageChannel is now compatible with yieldThread function in helper.ts

The crash gone and i get all events now, will be testing... Thanks @alexgleason.

This is awesome, thanks for posting this solution

mrkvon commented 4 months ago

The solution of @damiandizeo worked for me, but isn't TypeScript typed, so I had to put a bunch of @ts-ignore in.

Alternatively, I was also able to solve the issue by installing MessageChannel polyfill message-port-polyfill:

npm i message-port-polyfill

and importing it before nostr-tools:

import 'message-port-polyfill'