Impossible to join room with socket io 2.2.0 - express

I am trying to join a room with socket io :
socket.join(to, async () => {
console.log('ici')
if (!room) return
try {
const user = await ChatRedis.getUser(room, username)
await ChatRedis.setUser(room, username, { ...user, conference: to })
console.log(admin
? `Conference - User "${username}" opened a conference`
: `Conference - User "${username}" joined the "${to}" conference`)
namespace.in(to).emit('joinConference', { username, to, room, from })
} catch (error) {
console.log(error)
}
})
But the callback version is not working. I am using workspace I do not know if it is the issue
Socket io version : 2.2.0
Express: 4.17.1

Related

Node-redis client hang and never return so my express app also

I have an express app where I use Redis for cashing with Redis v4.1.0, at first it works fine and after some time, it doesn't give a response, and my whole app endpoint.
After debugging, I found that it hangs (like infinite) at redis.get(key) and everything below that never gets executed.
And also I tried adding legacyMode:true according to this: redis freezes node server when connected ,here it doesn't crush, but it never caches my content or executes any command.
Here is my configuration
import { createClient } from "redis";
import dotenv from "dotenv";
dotenv.config();
const redisClient = createClient({
url: `redis://:${process.env.REDIS_PASSWORD}#${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
// legacyMode: true, // https://stackoverflow.com/questions/70178133/redis-freezes-node-server-when-connected
});
redisClient
.connect()
.catch((err) => console.log("Connection to failed: ", err))
.then(() => {});
redisClient.on("connect", () => console.log("Redis Server Connected"));
redisClient.on("error", (err) => {
console.log("Redis Server Connection Error ", err.message);
});
redisClient.on("SIGINT", () => {
redisClient.quit();
});
export { redisClient };
And this is my redis use
static async getCacheData(key) {
try {
console.log("Get redis key: ", key);
const redisData = await redisClient.get(key);
console.log("Redis key found: ", typeof redisData);
if (redisData != null) return JSON.parse(redisData);
return null;
} catch (error) {
console.log("Error getting redis cache key: ", key, " ", error);
return null;
}
}

How to access SEA module in GUNJS without using dynamic require in React Native expo

So I've started this new project using React Native(Expo), and I've imported all packages including GunJS and SEA, however, when I run the app, I get the error that dynamic require is not supported by Metro. I checked the sea.js file and found that the devs use require(arg), which is not supported by React Native. This is a huge bummer and I haven't found any workaround. Is there any other way to access SEA?
import GUN from "gun";
import "gun/sea";
import { userContext } from "../global";
export const gun = GUN();
The below snippet is the sea.js file, which uses dynamic require.
/* UNBUILD */
function USE(arg, req){
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
arg(mod = {exports: {}});
USE[R(path)] = mod.exports;
}
We got this fixed in the latest GitHub main (hopefully published soon).
Thanks to Aethiop! Who also wrote a great tutorial on this:
https://github.com/aethiop/jot
if you need to use SEA in react-native now without wait the gun community to fix this problem do this build API with nodejs and install gun in after going in your react-native app call this API
see ex:
//nodejs that manage sea so in my case I use auth feature sea
const fastify = require("fastify")();
const Gun = require('gun'); // in NodeJS
require('./sea/sae');
const gun = new Gun ({
peers: ['https://gun-serve.herokuapp.com/gun'],
})
const user = gun.user()
const ADDRESS = "0.0.0.0";
const PORT = process.env.PORT || 3000;
fastify.get("/", function (req, reply) {
reply.send("wellcome");
});
fastify.post('/userregist', async (request, reply) => {
try {
user.create(`${request.body.user}`,`${request.body.password}`, ({ err , pub}) => {
if (err) {
return reply.code(200).send({ "err": `${err}`})
} else {
return reply.code(200).send({"pub": `${pub}`})
}
});
} catch (error) {
request.log.error(error);
return reply.send(500);
}
})
fastify.post('/userlogin', async (request, reply) => {
try{
user.auth(`${request.body.user}`,`${request.body.password}`, ({ err, get, }) => {
if (err) {
return reply.code(200).send({ "err": `${err}`})
} else {
console.log('joshau get', get)
return reply.code(200).send({"pub": `${get}`})
}
});
} catch (error) {
request.log.error(error);
return reply.send(500);
}
})
fastify.listen(PORT, ADDRESS, (err, address) => {
if (err) {
console.log(err);
process.exit(1);
}
});
so i call api my app like that:
//my call api
const loginRequest = async (email, password) => {
try {
return await fetch('https://locahost:3000/userlogin', {
mode: 'no-cors', method: 'POST',
headers: {
'Content-type': 'application/json',
'Accept': ' application/json'
},
body: JSON.stringify({
user: email,
password: password,
}),
})
} catch (error) {
return error;
}
};
// here is way i call it i comp
LoginRequest(email, password)
.then((res)=> {
res.json().then(function (text) {
if(text.err){
LOADING_STOP()
alert(`${text.err}`)
console.log('error message',text.err)
}else{
console.log('public key',text.pub)
LOADING_STOP()
navigation.replace("Dashboard");
}
}).catch((e)=> {
LOADING_STOP()
alert(e)
})
put import shim from "gun/lib/mobile"
at the top of your file. (before the SEA import) :D !
import shim from "gun/lib/mobile"
import SEA from 'gun/sea'

Keep client connected to WebSocket in react native and express server

I have a react native application where i have two users using the app (customer and restaurant)
So on checkout I connect the customer to websocket on the express server and once the order is placed i send a message to the restaurant which is supposed to be connected to websocket all time.
However, sometimes the restaurant is disconnected somehow, so I am trying to keep the restaurant connected, and if disconnected then reconnect again automatically.
In react native restaurant side implementation i have the following code :
this is useWebSocketLite hook to handle connection, send, receive messages and retry connection to server when closed:
function useWebSocketLite({ socketUrl, retry: defaultRetry = 3, retryInterval = 1000 }) {
const [data, setData] = useState();
const [send, setSend] = useState(() => () => undefined);
const [retry, setRetry] = useState(defaultRetry);
const [readyState, setReadyState] = useState(false);
useEffect(() => {
const ws = new WebSocket(socketUrl);
ws.onopen = () => {
setReadyState(true);
setSend(() => {
return (data) => {
try {
const d = JSON.stringify(data);
ws.send(d);
return true;
} catch (err) {
return false;
}
};
});
ws.onmessage = (event) => {
const msg = formatMessage(event.data);
setData({ message: msg, timestamp: getTimestamp() });
};
};
ws.onclose = () => {
setReadyState(false);
if (retry > 0) {
setTimeout(() => {
setRetry((retry) => retry - 1);
}, retryInterval);
}
};
return () => {
ws.close();
};
}, [retry]);
return { send, data, readyState };
}
So based on this, every-time the connection is closed, the connection will retry again.
Besides, when a restaurant launches the app the following code will be implemented:
const ws = useWebSocketLite({
socketUrl: `wss://${url}/id=${user.user_id}&role=restaurant`
});
This useEffect to establish the connection:
useEffect(() => {
if (ws.readyState === true) {
setConnectionOpen(true);
}
}, [ws.readyState]);
and this useEffect to handle incoming messages
useEffect(() => {
if (ws.data) {
const message = ws.data;
//dispatch...
}
}, [ws.data]);
Express server implementation:
This is the code where i handle socket connections and messages in express server:
var webSockets = {}
function setupWebSocket(server) {
server.on('connection', (socket, req) => {
if (req) {
var clientId = req.url
let regexReplace = /[\[\]/]/g
let regex = /([^=#&]+)=([^?&#]*)/g,
params = {},
match;
while ((match = regex.exec(clientId))) {
params[decodeURIComponent(match[1]).replace(regexReplace, '')] = decodeURIComponent(match[2])
}
if (params.role === 'restaurant') {
webSockets[params.id] = socket
}
}
socket.on('message', data => {
let sData = JSON.parse(JSON.parse(data))
let {id, data} = sData.data
sendToClient(id, 'order', data)
})
socket.on('error', (err) => {
console.log(err)
})
socket.on('close', (code, req) => {
var clientId = req.url
let regexReplace = /[\[\]/]/g
let regex = /([^=#&]+)=([^?&#]*)/g,
params = {},
match;
while ((match = regex.exec(clientId))) {
params[decodeURIComponent(match[1]).replace(regexReplace, '')] = decodeURIComponent(match[2])
}
if (params.role === 'restaurant') {
delete webSockets[clientId]
console.log(`${webSockets[clientId]} disconnected with code ${code} !`);
}
});
});
// sends a message to a specific client
const sendToClient = (clientId, type, data = {}) => {
const payload = { type, data }
const messageToSend = JSON.stringify({ error: false, message: payload })
if (webSockets[clientId]) {
webSockets[clientId].send(messageToSend)
console.log(`${clientId} client notified with this order`)
} else {
console.log(`${clientId} websocket client is not connected.`)
}
}
}
So most of the time I get 13 websocket client is not connected. which means the restaurant has already been deleted from the webSockets object and its connection already closed.
Apologise for long question and hope someone can help me regarding this.
First of all, you should know that this is not a good practice of websockets, where you are forcing the client (the restaurant) to be connected.
Whatever, at the current state of your code, there is an illogical behavior: at the end of the useEffect of your “useWebSocketLite” function, you are closing the socket connection:
return () => {
ws.close();
};
Knowing that the useEffect hook is called twice: after the first render of the component, and then after every change of the dependencies (the “retry” state in your case); Your code can be ridden like so: everytime the “retry” state changes, we will close the socket! So for me that is why you got the client disconnected.

React-native-agora remote video quality very poor, only freezing

I am working on a react native video call app, I use react-native-agora, everything works fine except the
remote video quality is extremely bad, I can see nothing, it is only freezing.
I use react native agora version : 3.2.2
My rtcEngine init function :
/**
* #name init
* #description Function to initialize the Rtc Engine, attach event listeners and actions
*/
const init = async () => {
const {token, appId} = await getToken();
setAppId(appId);
setToken(token);
engine = await RtcEngine.create(appId);
await engine.enableVideo();
await engine.enableAudio();
await engine?.joinChannel(token, `${session.id}`, null, 0);
engine.addListener('Warning', (warn) => {
console.log('Warning', warn);
});
engine.addListener('Error', async (err) => {
if(err === 17){
if(!engine){
engine = await RtcEngine.create(appId);
}
await engine?.leaveChannel();
setPeerIds(peerIds => []);
await engine?.joinChannel(token, `${session.id}`, null, 0);
}
console.log('Error', err);
});
engine.addListener('UserJoined', async (uid, elapsed) => {
console.log('UserJoined', uid, elapsed);
// Get current peer IDs
// If new user
if (peerIds.indexOf(uid) === -1) {
setPeerIds(peerIds => [...peerIds, uid]);
}
});
engine.addListener('UserOffline', (uid, reason) => {
console.log('UserOffline', uid, reason);
setPeerIds(peerIds => [...peerIds.filter((id) => id !== uid)]);
});
// If Local user joins RTC channel
engine.addListener('JoinChannelSuccess', (channel, uid, elapsed) => {
console.log('JoinChannelSuccess', channel, uid, elapsed);
// Set state variable to true
setJoinSucceed(true);
});
}
Thanks in advance.
I finally solved my problem, for those who have the same issue, I let here my solution:
I just make this videoEncoderConfiguration :
await engine.setVideoEncoderConfiguration(new VideoEncoderConfiguration({
dimensions: new VideoDimensions(320, 240),
bitrate: 140,
frameRate: VideoFrameRate.Fps30,
degradationPrefer: 0
}))

Detox with Mirage.js [Mock API Call] React-Native

I'm working on some tests using Detox for my React-Native application, one of those test is a flow where I need to check that the user's session is secured. If not, I'm sending an SMS Verification Code.
Test : Success to mock the POST API Call api/sessions/:sessionId, {code : 123456}
Problem : Mirage is not catching the call, so of course my Saga return an error for the fake code 123456, where I want instead Mirage.JS to return true to continue the flow.
Here are the file (file.spec.js):
import { Server } from "miragejs"
import { makeServer } from "./server";
let server;
beforeEach(() => {
server = makeServer({ environment: "development" });
})
afterEach(() => {
server.shutdown()
})
describe('SecureFlow', () => {
it("should do nav to a project and start Investment Flow", async () => {
server.get("https://random-api.eu/sessions/:sessionId", () => {
return new Response( 200, {}, { ok: true });
});
await basicNavigation(); //randomNavigation until the secure part (Screen)
await element(by.id('Accept-andLend')).tap();
await element(by.id('textInput-SMSCode')).typeText("123456");
})
})
server.js
import { Server, Model, Factory } from "miragejs";
export function makeServer({ environment = "development" } = {}) {
let server = new Server({
environment,
models: {
},
routes() {
this.post("https://random-api.eu/sessions/:sessionId", schema => {
return [{ok: true}];
});
}
});
return server;
}