2

I am trying to catch an error in the controller and send status(500) to the front-end to let the user know that there is a streaming error. But for some reason the error is not caught and I am sending status(200) to the user. Let me know if i am doing something wrong.

file - utils.js

import WebSocket from 'ws';
import Twitter from 'twitter-lite';
import ck from 'ckey';

export const stream = (term, clients, twitterStream) => {
  const twitter = new Twitter({
    // subdomain: 'api', // "api" is the default (change for other subdomains)
    // version: '1.1', // version "1.1" is the default (change for other subdomains)
    version: '2', // version "1.1" is the default (change for v2)
    extension: false, // true is the default (this must be set to false for v2 endpoints)
    consumer_key: ck.TWITTER_CONSUMER_KEY,
    consumer_secret: ck.TWITTER_CONSUMER_SECRET,
    access_token_key: ck.TWITTER_ACCESS_TOKEN_KEY,
    access_token_secret: ck.TWITTER_ACCESS_TOKEN_SECRET,
  });

  let stream = twitter.stream('statuses/filter', { track: term });

  stream.on('data', function (tweet) {
    console.log('tweetsJohn: ');
    broadcast(clients, JSON.stringify(tweet));
  });

  stream.on('error', function (error) {
    console.log('stream error: ', error.source);
  });

  twitterStream = stream;
  return twitterStream;
};

const broadcast = (clients, message) => {
  clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(message);
    }
  });
};

controller

import { stream } from './utils.js';

// Sets search term for twitter stream.
export const setSearchTerm = (req, res) => {
  try {
    const { term } = req.params;
    console.log('setSearchTerm');
    console.log('term: ', term);
    if (twitterStream) {
      console.log('getTweetPause');
      twitterStream.destroy();
    }
    twitterStream = stream(term, req.app.locals.clients, twitterStream);
    res.status(200).json({ message: 'Successful search request' });
  } catch (error) {
    res.status(500).json({ message: error });
    // res.status(500).json({ ex: 'Internal Server Errorr' });
  }
};

Solution

file-utils.js

import WebSocket from 'ws';
import Twitter from 'twitter-lite';
import ck from 'ckey';

export const stream = (clients, term) => {
  const twitter = new Twitter({
    // subdomain: 'api', // "api" is the default (change for other subdomains)
    // version: '1.1', // version "1.1" is the default (change for other subdomains)
    version: '2', // version "1.1" is the default (change for v2)
    extension: false, // true is the default (this must be set to false for v2 endpoints)
    consumer_key: ck.TWITTER_CONSUMER_KEY,
    consumer_secret: ck.TWITTER_CONSUMER_SECRET,
    access_token_key: ck.TWITTER_ACCESS_TOKEN_KEY,
    access_token_secret: ck.TWITTER_ACCESS_TOKEN_SECRET,
  });

  let currentStream = twitter.stream('statuses/filter', { track: term });

  const streamResult = new Promise((resolve, reject) => {
    currentStream.on('data', function (tweet) {
      console.log('tweets: ');
      broadcast(clients, JSON.stringify(tweet));
      resolve(tweet);
    });

    currentStream.on('error', function (error) {
      reject(error);
    });
  });

  return { currentStream, streamResult };
};

const broadcast = (clients, message) => {
  clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(message);
    }
  });
};

controller

import { stream } from './utils.js';

let twitterStream;

// Sets search term for twitter stream.
export const setSearchTerm = async (req, res) => {
  try {
    const { term } = req.params;

    console.log('setSearchTerm');
    console.log('term: ', term);

    if (twitterStream) {
      console.log('getTweetPause');
      twitterStream.destroy();
    }

    const { currentStream, streamResult } = stream(
      req.app.locals.clients,
      term
    );
    twitterStream = currentStream;

    await streamResult;

    res.status(200).json({ message: 'Successful HTTP request' });
  } catch (error) {
    console.log('error catch: ');
    res.status(500).json({ message: error });
  }
};
John John
  • 1,305
  • 2
  • 16
  • 37
  • if you use throw error in ` stream.on('error', function (error) { console.log('stream error: ', error.source); });` is incorrect? – Mohammad Yaser Ahmadi Jan 14 '21 at 06:05
  • triggerUncaughtException – John John Jan 14 '21 at 06:09
  • [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#".] { code: 'ERR_UNHANDLED_REJECTION' } – John John Jan 14 '21 at 06:10
  • You did not design any method for the `stream()` function to communicate back either when it was complete or if it had an error. It needs to either return a promise that is connected to its completion/error or if needs to take a callback that the caller can use to know when its done. You `stream()` function returns LONG before it has completed. So, you aren't getting results or error from its return value. – jfriend00 Jan 14 '21 at 06:43
  • @jfriend00 I do get the stream but I am having problems handling the error correctly. Whenever I am getting one it is treated as status(200) instead of status(500) – John John Jan 14 '21 at 06:54
  • Did you read the question yours is marked a duplicate of? It explains there why you cannot directly return your result or error. Your function returns BEFORE you have a result or error. Thus, all it returns is junk. You have to either return a promise that is connected to your asynchronous operation or you have to accept a callback that you call when your asynchronous operation is complete and you pass error or result to the callback. – jfriend00 Jan 14 '21 at 06:59
  • @jfriend00 ```const errorMessage = await stream.on('error', function (error) { console.log('stream error: ', error); return error; });``` – John John Jan 14 '21 at 07:00
  • Stop guessing. You need to LEARN how to do this stuff. `await` only does something useful when you're awaiting a promise that is connected to your asynchronous operation and `stream.on()` does not return a promise. You will need to spend some time learning. Start by reading and studying the accepted answer to the question yours is marked a duplicate of. If you study that and attempt to implement one of the ideas there and get stuck, then you can post a new question with your attempt. But, don't just guess how to do this. Read, learn, study. – jfriend00 Jan 14 '21 at 07:02
  • Go learn how promises work. Learn how to promisify a stream operation. Then, you can apply that knowledge to this problem. – jfriend00 Jan 14 '21 at 07:02
  • @jfriend00 yes, I am reading the question. You are right. I need to understand instead of guessing. – John John Jan 14 '21 at 07:03
  • @jfriend00 added the solution to the question. – John John Jan 15 '21 at 03:30

0 Answers0