I'm having trouble trying to connect with websocket server.
I need to subscribe to get the current price of EUR/USD but I keep reciving this object : {topic: "keepalive"}.
It should return the price and the latest timestamp;
This is my code :
import { w3cwebsocket as W3CWebSocket } from "websocket";
export default function LogIn() {
const client = new W3CWebSocket('ws://stream.tradingeconomics.com/?client=guest:guest');
useEffect(()=>{
client.onopen = function(e) {
console.log("Connection established!");
client.send(JSON.stringify({topic: "subscribe", to: "EURUSD:CUR"}))
client.onmessage = function(e) { console.log(e); };
};
},[])
I would appreciate the help !
The problem is that you are sending a Stringified Object instead of a String:
You are sending
client.send(JSON.stringify({topic: "subscribe", to: "EURUSD:CUR"}))
You need to send
client.send('{"topic": "subscribe", "to": "EURUSD:CUR"}')
Related
I'm currently using socket.io for real time alerts in my app. I'm developing it using React Native with Expo.
I import this instance of the socket into required components:
socketInstance.js
import io from 'socket.io-client';
import { url } from './url';
const socket = io(url, { secure: true });
export default socket;
And then use it to emit data to the server, for example, when the payment for an order has been completed:
OrderPurchaseScreen.js
const openPaymentSheet = async () => {
const { error } = await presentPaymentSheet();
if (error) {
Alert.alert(`Error code: ${error.code}`, error.message, [
{
text: "Try Again",
onPress: () => openPaymentSheet(),
},
{
text: "Cancel Order",
onPress: () => handleExit(),
style: "cancel",
},
]);
} else {
Alert.alert(
"Payment Successful",
"Your payment has successfully been processed."
);
socket.emit("order-purchase-complete", Store.getState().orderReducer.orderTicket.restaurantId);
setActive(false);
navigation.navigate('OrderCompleteScreen');
}
In the node server
server.js
io.on('connection', (socket) => {
socket.on("logIn", (userId) => {
console.log("new user logged in. - " + userId.toString());
socket.join(userId.toString());
socket.on("order-cancelled", (userId) => {
console.log("order cancelled");
io.to(userId.toString()).emit("order-cancelled", createNotificationObject("Order Cancelled", "The restaurant has cancelled your order. Your money will be refunded."));
});
socket.on("new-order-completed", (userId) => {
console.log("order completed");
io.to(userId.toString()).emit("new-order-completed", createNotificationObject("Order Completed", "Your order has been completed."));
});
});
socket.on("restaurantLogin", (restaurantId) => {
console.log("new restaurant logging in...");
socket.join(restaurantId.toString());
socket.on("new-order-for-approval", (restaurantId) => {
console.log("New Order For Approval!");
io.to(restaurantId.toString()).emit("new-order-for-approval", createNotificationObject("Order Awaiting Approval", "There is a new order awaiting approval. View it in the Restaurant Manager."));
});
socket.on("order-purchase-complete", (restaurantId) => {
console.log("new order purchase completed");
io.to(restaurantId.toString()).emit("order-purchase-complete", createNotificationObject("Order Completed", "A new order has been placed. View it in the Restaurant Manager."));
});
});
}
I have found that in dev mode, everything works fine and as expected. However when I switch to prod mode for IOS (have not tested Android), it only seems to be able to handle the user logging in. When it comes to emitting data after the order being completed for example, nothing gets emitted. Anyone know what I can do to debug this to help me find out the problem or have a potential solution?
Found the answer while browsing the socket.io documentation:
https://socket.io/blog/socket-io-on-ios/
"A Note About Multitasking in iOS
As you probably know, iOS is very picky about what you can do in the background. As such, dont expect that your socket connection will survive in the background! Youll probably stop receiving events within seconds of the app going into the background. So its better to create a task that will gracefully close the connection when it enters the background (via AppDelegate), and then reconnect the socket when the app comes back into the foreground."
So all I did was use AppState to get the state of the app, and depending on if it was in the foreground or background I would re connect to the socket or disconnect:
App.js
useEffect(async () => {
const subscription = AppState.addEventListener(
"change",
async (nextAppState) => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === "active"
) {
if (_userToken !== null && email !== null && password !== null) {
socket.connect();
socket.emit("logIn", Store.getState().userReducer._id);
}
appState.current = nextAppState;
setAppStateVisible(appState.current);
if (appState.current === "background") {
socket.disconnect();
}
//console.log("AppState", appState.current);
}
);
Here is my Socket connectivity and forward Message function:
const MessageForward = () => {
const token = accessToken;
socketRef.current = io.connect('http://159.203.8.120:3001', {
query: { token }
});
socketRef.current.on("profile", id => {
const conne = { profileId: id.id }
socketRef.current.emit('myProfileId', conne)
setYourID(id.id)
})
socketRef.current.on('forward-message', (message) => {
console.log("Forwarded-Message", message);
})
};
function forwardMessage(e) {
e.preventDefault();
var receiverProfileId;
if (yourID == yourID) {
receiverProfileId = selectedId
}
else {
receiverProfileId = yourID
}
const messageObjects = {
senderProfileId: yourID,
receiverProfileId: receiverProfileId,
message: message,
type: msgType,
AdId: AdId,
AdTitle: AdTitle,
AdDescription: AdDescription,
AdImage: AdImage,
username: name,
};
navigation.navigate("NewChat",
{ Id: selectedId, Name: userName, ProfileImage: selectImage })
socketRef.current.emit("forward-message", messageObjects);
};
The senderProfileId is my Id from Socket and receiverProfileId i am taking from Api by selecting user and its Id. But if i select user and forward message to selected user its not getting send but if i send it second time its getting send. Same forward-message socket i am using to get the response from the socket but first time it is not forwarding seconds time it is getting send. I want to know where i am getting struck. if anyone knows please let me know it would be appreciated.
Thankyou
I am writing a chat app. Users can search for other users, and then press the "Message" button. Then I navigate to ChatScreen.js. If both users have been messaging each other, I set the chatId variable accordingly. If they have not messaged each other before I dont create chatId, until the ery first message has been sent. When the first message is sent, I first, create new chat, store its properties (user ids, chatId, etc) in my db and then I sent the first message. The problem is that I store chatId as a state variable, and when I create the chat I call setChatId(id). setChatId() is not synchronous call, so by the time when I need to send message with sendText(text, chatId); my chatId is undefined even though I have already created a chat and I have called setChatId.
How can I avoid this error? Ofc, I can check if chatId == undefined then calling sendText(text, id), otherwise calling sendText(text, chatId). Is there a better/neath way to avoid the undefined check?
Here is part of my code:
...
import {
createChat,
} from "./actions";
...
function ChatScreen(props) {
...
const [chatId, setChatId] = useState(props.route.params.chatId);
...
const setupChat = async () => {
try {
await createChat(user.id, setChatId);
props.fetchUserChats();
} catch (error) {
console.error("Error creating chat: ", error);
}
};
async function handleSend(messages) {
if (!chatId) {
// creating chat
await setupChat();
}
const text = messages[0].text ? messages[0].text : null;
const imageUrl = messages[0].image ? messages[0].image : null;
const videoUrl = messages[0].video ? messages[0].video : null;
const location = messages[0].location ? messages[0].location : null;
//assuming chatId is already setup but it is not
if (imageUrl) {
sendImage(imageUrl, chatId, setSendImageError);
} else if (location) {
sendLocation(location, chatId, setLocationError);
} else if (videoUrl) {
sendVideo(videoUrl, chatId, setSendImageError);
} else {
sendText(text, chatId);
}
}
...
}
My createChat function from actions.js file
export async function createChat(otherUid, setChatId) {
let chatId = firebase.auth().currentUser.uid + "_" + otherUid;
await firebase
.firestore()
.collection("Chats")
.doc(chatId)
.set({
users: [firebase.auth().currentUser.uid, otherUid],
lastMessage: "Send the first message",
lastMessageTimestamp: firebase.firestore.FieldValue.serverTimestamp(),
})
.then(() => {
console.log("doc ref for creatign new chat: ", chatId);
setChatId(chatId);
})
.catch((error) => {
console.error("Error creating chat: ", error);
});
}
Instead of using a state variable, I would advise you to use useRef(). This would be a good solution to your problem.Eg Define it this way
const chatId = useRef(null),
then set it this way chatId.current = yourChatId
and get it this way chatId.current. I hope this solves your problem
I am working with React-Redux-Firebase. I implemented signing in with phone number. Now I am trying to implement error handling. When number is invalid I display window alert with error message. The only thing left to do is to reset recaptcha. Without it, I am getting error:
reCAPTCHA has already been rendered in this element
I was trying to do according to Firebase documentation
grecaptcha.reset(window.recaptchaWidgetId);
// Or, if you haven't stored the widget ID:
window.recaptchaVerifier.render().then(function(widgetId) {
grecaptcha.reset(widgetId);
}
but it does not work in my code. I dont have grecaptcha implemented. I tried to add it with react-grecaptcha, but it did not work.
Could someone give me a hint how to reset recaptcha after each error, please?
state = {
phone: "",
confirmationResult: {},
};
handleClick = () => {
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
}
);
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset(); // How can I do that?
});
};
I've been struggling with this problem for several days, maybe my answer will help someone.
export const requestRecaptchVerifier = () => {
window.recaptchaVerifier = new RecaptchaVerifier(
"recapcha-container",
{
size: "invisible",
},
auth
);
};
I then call signInWithPhone from another function and handle the error like this:
await signInWithPhone(formik.values.phone)
.then(() => {
// ... my code
})
.catch(() => {
window.recaptchaVerifier.recaptcha.reset();
window.recaptchaVerifier.clear();
});
All the difference in
window.recaptchaVerifier.recaptcha.reset()
And
window.recaptchaVerifier.clear()
I'm no expert but from the documentation and by talking with you in the comment section I think you need to pass a callback. Like this:
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
// reCAPTCHA solved, allow signInWithPhoneNumber.
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset();
});
}
});
Reference: https://firebase.google.com/docs/auth/web/phone-auth#use-invisible-recaptcha
Hope this helps!
Running into an issue with React/Socket.io. I have two different socket emitters/listeners: one for a chat, and one for keeping track live changes to the application. I have two separate windows running localhost. The issue is when i emit a change on one window, the other window can receive that change the first time but never again (i.e. get first chat message but none that follow). After that first emit/receive, the sending client starts to receive its own emitters.
front end code:
`
socket = io("localhost:3002");
componentDidMount() {
//get id from url
const { id } = this.props.match.params;
//join specific room for project
this.socket.on("connect", () => {
this.socket.emit("room", this.projectId);
});
//listener for incoming messages
this.socket.on("RECEIVE_MESSAGE", (data) => {
this.props.addChat(this.projectId, data);
});
this.socket.on("UPDATE_PROJECT", () => {
console.log("update");
this.props.fetchProject(id);
});
}
emitTaskChange = () => {
this.socket.emit("TASK_CHANGE", { data: null });
};
onChatSubmit = (e) => {
e.preventDefault();
//create object with current user as author, message, and a timestamp
const chat = {
author: this.props.currentUser.name,
message: this.state.newChat,
createdAt: new Date().toLocaleString(),
};
//send message through socket
this.socket.emit("SEND_MESSAGE", chat);
//call action creator to add new chat
this.props.addChat(this.projectId, chat);
this.setState({ currentMessage: "" });
};
handleTaskEdit = (taskId, currentStatus) => {
const newStatus = currentStatus === "todo" ? "inprogress" : "completed";
this.props.editTask(this.projectId, taskId, newStatus);
this.emitTaskChange();
};
`
backend code:
`
const io = socket(server);
//create separate chat rooms using project id
io.on("connection", (socket) => {
socket.on("room", (room) => {
socket.join(room);
socket.in(room).on("SEND_MESSAGE", (message) => {
socket.emit("RECEIVE_MESSAGE", message);
});
socket.in(room).on("TASK_CHANGE", (data) => {
socket.emit("UPDATE_PROJECT", data);
});
});
`
found the error:
had to change the server-side code from socket.on and instead use the io object that was initialized such as io.sockets.on