aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Pubsub subscribe return error on low end device model #5881

Closed richardtks closed 3 years ago

richardtks commented 4 years ago

Describe the bug

To Reproduce Steps to reproduce the behavior:

  1. Enter your email and password to login.
  2. Click Login -> Initialize pubsub -> Subscribe -> Publish
  3. Notice that following error code appeared on the browser console:
    "errorCode":7,
     "errorMessage":"AMQJS0007E Socket error:undefined."

Expected behavior Low end device should be able to subscribe to topic and receive message.

Code Snippet

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {useState, useRef} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Button,
  Text,
  TextInput,
  KeyboardAvoidingView,
  Platform,
  ActivityIndicator,
} from 'react-native';
import axios from 'axios';

import Auth from '@aws-amplify/auth';
import PubSub from '@aws-amplify/pubsub';
import {AWSIoTProvider} from '@aws-amplify/pubsub/lib/Providers';

Auth.configure({
  // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
  identityPoolId: '<identityPoolId>',
  userPoolId: '<userPoolId>,
  userPoolWebClientId: '<userPoolWebClientId>',

  // REQUIRED - Amazon Cognito Region
  region: 'ap-southeast-1',
});

async function attachPolicy({username, IdentityId, idToken}) {
  const result = await axios.post(
    `
  https://<endpoint>/dev/attachpolicy`,
    {
      requestData: {
        username,
        identityID: IdentityId,
      },
    },
    {
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Authorization: idToken,
      },
    },
  );

  console.log('result.data.message: ', result.data.message);

  if (result && result.data && result.data.message !== 'success') {
    throw new Error(result.data.message);
  }

  return result;
}

const App = () => {
  const [loginStatus, setLoginStatus] = useState('N/A');
  const loginParams = useRef();
  const [pubsubStatus, setPubsubStatus] = useState('N/A');
  const [subscribeStatus, setSubscribeStatus] = useState('N/A');
  const [publishStatus, setPublishStatus] = useState('N/A');
  const [debugInfo, setDebugInfo] = useState('');
  const [isLoading, setIsLoading] = useState(false);

  const [username, setUsername] = useState('<email>');
  const [password, setPassword] = useState('password');
  const [thingName, setThingName] = useState('<thingName>');

  const handleLogin = async () => {
    try {
      setIsLoading(true);
      setLoginStatus('N/A');
      const result = await Auth.signIn(username, password);

      const idToken = result.signInUserSession.idToken.jwtToken;

      const credential = await Auth.currentCredentials();

      console.log('credential: ', credential);

      const IdentityId = credential.identityId;

      loginParams.current = {
        username,
        idToken,
        IdentityId,
      };

      setDebugInfo(JSON.stringify(loginParams.current));

      setLoginStatus(`Success, ${username}`);
    } catch (error) {
      console.log('login error: ', error.message);
      setLoginStatus('Failed');
    } finally {
      setIsLoading(false);
    }
  };

  const initPubsub = async () => {
    try {
      setIsLoading(true);
      setPubsubStatus('N/A');
      await attachPolicy(loginParams.current);
      await PubSub.addPluggable(
        new AWSIoTProvider({
          aws_pubsub_region: 'ap-southeast-1',
          aws_pubsub_endpoint:
            'wss://<aws_pubsub_endpoint>.iot.ap-southeast-1.amazonaws.com/mqtt',
        }),
      );

      setPubsubStatus('Success');
    } catch (error) {
      setDebugInfo(`Init pubsub error, ${error.message}`);

      setPubsubStatus('Failed');
    } finally {
      setIsLoading(false);
    }
  };

  const subscribe = async () => {
    try {
      setIsLoading(true);
      setSubscribeStatus('N/A');
      PubSub.subscribe(`$aws/things/${thingName}/shadow/get/accepted`, {
        provider: 'AWSIoTProvider',
      }).subscribe({
        next: data => setDebugInfo(JSON.stringify(data)),
        error: error => {
          setSubscribeStatus('Failed during subscribe');
          setDebugInfo(
            'Subscribe error in subscribe: ',
            typeof error === 'string'
              ? error
              : typeof error.error === 'string'
              ? error.error
              : JSON.stringify(error.error),
          );
        },
        close: () => console.log('Done'),
      });
      setSubscribeStatus('Success');
    } catch (error) {
      setSubscribeStatus('Failed in general');
      const errorContent = error.message || JSON.stringify(error);
      setDebugInfo(`Subscribe error in general:, ${errorContent}`);
    } finally {
      setIsLoading(false);
    }
  };

  const publish = async () => {
    try {
      setIsLoading(true);
      setPublishStatus('N/A');
      await PubSub.publish(`$aws/things/${thingName}/shadow/get`, {
        msg: '',
      });
      setPublishStatus('Success');
    } catch (error) {
      setPublishStatus('Failed');
      const errorContent = error.message || JSON.stringify(error);
      setDebugInfo(`Publish error:, ${errorContent}`);
    } finally {
      setIsLoading(false);
    }
  };
  return (
    <>
      <KeyboardAvoidingView
        enabled
        style={styles.container}
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
        <SafeAreaView style={styles.container}>
          <ScrollView contentContainerStyle={styles.sVContainer}>
            <View style={styles.topSection}>
              <View style={styles.row}>
                <Text style={styles.label}>Login status: </Text>
                <Text style={styles.result}>{loginStatus}</Text>
              </View>
              <View style={styles.row}>
                <Text style={styles.label}>Pubsub init status: </Text>
                <Text style={styles.result}>{pubsubStatus}</Text>
              </View>
              <View style={styles.row}>
                <Text style={styles.label}>Subscribe status: </Text>
                <Text style={styles.result}>{subscribeStatus}</Text>
              </View>
              <View style={styles.row}>
                <Text style={styles.label}>Publish status: </Text>
                <Text style={styles.result}>{publishStatus}</Text>
              </View>
              <View style={styles.debugInfo}>
                <Text style={styles.label}>Debug info</Text>
                <ScrollView style={styles.sVContainer}>
                  <View style={styles.container}>
                    <Text>{debugInfo}</Text>
                  </View>
                </ScrollView>
              </View>
            </View>
            <View style={styles.midSection}>
              <TextInput
                style={styles.input}
                placeholder="Username"
                value={username}
                onChangeText={setUsername}
              />
              <TextInput
                style={styles.input}
                placeholder="Password"
                value={password}
                onChangeText={setPassword}
              />
              <TextInput
                style={styles.input}
                placeholder="ThingName"
                value={thingName}
                onChangeText={setThingName}
              />
            </View>
            <View style={styles.bottomSection}>
              {isLoading ? (
                <ActivityIndicator size="large" />
              ) : (
                <>
                  <Button
                    style={styles.button}
                    title="Login"
                    onPress={handleLogin}
                  />
                  <Button
                    style={styles.button}
                    title="Initialize pubsub"
                    onPress={initPubsub}
                  />
                  <Button
                    style={styles.button}
                    title="Subscribe"
                    onPress={subscribe}
                  />
                  <Button
                    style={styles.button}
                    title="Publish"
                    onPress={publish}
                  />
                </>
              )}
            </View>
          </ScrollView>
        </SafeAreaView>
      </KeyboardAvoidingView>
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  sVContainer: {
    flexGrow: 1,
  },
  topSection: {
    marginBottom: 20,
  },
  midSection: {
    justifyContent: 'space-between',
    marginHorizontal: 10,
    height: 150,
  },
  bottomSection: {
    height: 100,
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingVertical: 10,
    flexDirection: 'row',
  },
  row: {
    flexDirection: 'row',
    marginVertical: 10,
    alignItems: 'center',
  },
  debugInfo: {
    height: 200,
    backgroundColor: 'lightblue',
  },
  label: {
    fontSize: 20,
    textAlign: 'center',
  },
  result: {
    fontSize: 15,
    textAlign: 'center',
  },
  button: {
    height: 100,
    width: 100,
  },
  input: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginBottom: 10,
  },
});

export default App;

Screenshots N/A

What is Configured?

Smartphone (please complete the following information):

Additional context Anyone can help to suggest how can I further debug this issue?

tarunama commented 4 years ago

In progress ?

ericclemmons commented 4 years ago

I was able to reproduce this, but it doesn't appear to be specific to low-powered phones.

For example, running a pubsub app on a Pixel 2 simulator with clock skew (5+ minutes added to the clock) yields the same result.

It's trickier to troubleshoot because it's through a websocket connection, so this might take some time...

ericclemmons commented 4 years ago

Confirmed this happens for web as well when the clock is skewed. Likely the same underlying reason:

{invocationContext: undefined, errorCode: 7, errorMessage: "AMQJS0007E Socket error:undefined."}errorCode: 7errorMessage: "AMQJS0007E Socket error:undefined."invocationContext: undefined__proto__: Object
stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.