I am using SocketIO and redis based on the following code,
var sub = redis.createClient();
var pub = redis.createClient();
sub.subscribe('chat');
io.use(socketHandshake({store: sessionStore, key:'jsessionid', secret:'secret', parser:cookieParser()}));
io.on('connection', function (socket) {
socket.on('chat', function (message) {
// io.emit('chat', "hello world");
pub.publish('chat', "hello world");
});
sub.on('message', function (channel, message) {
io.emit(channel, message);
});
});
This is the base code. I have modified the code so that if any user goes offline, in server side I am storing the messages in RSMQ(Redis Simple Message Queue) and when user comes online, the message is fetched from queue and emits to the user.I have used the following code to achieve this.I have stored the user status in an array.
var fs = require('fs')
, http = require('http')
, socketio = require('socket.io');
var redis = require('redis');
var store = redis.createClient();
var pub = redis.createClient();
var sub = redis.createClient();
RedisSMQ = require("rsmq");
rsmq = new RedisSMQ( {host: "127.0.0.1", port: 6379, ns: "rsmq"} );
var active_users=[];
var inactive_users=[];
var user_status=[];
var channel_users=[];
var users_queue=[];
var socket_ids=[];
var cname,qn;
var clients=[];
var server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-type': 'text/html'});
res.end(fs.readFileSync(__dirname + '/index.html'));
}).listen(9000, function() {
console.log('Listening at: http://localhost:9000');
});
socketio.listen(server).on('connection', function (socket) {
socket.on('login', function(data){
console.log('a user ' + data.userId + ' connected'+socket.id);
//saving userId to array with socket ID
active_users[socket.id] = data.userId;
socket_ids[data.userId]=socket.id;
clients[socket.id] = socket;
user_status[data.userId]="online";
});
socket.on('message', function (msg) {
console.log('Message Received: ', msg);
socket.broadcast.emit('message', msg);
});
socket.on('json', function (msg) {
if(msg.channel_name=='UserState'){
rsmq.listQueues(function(err,resp){
//console.log("QUEUES LIST"+resp);
});
if(msg.user_state=='active'){
store.hmset("active_users."+msg.sender_id,{"user":"online"});
user_status[msg.sender_id]="online";console.log(user_status);
if(users_queue[msg.sender_id]!=undefined && users_queue[msg.sender_id].length>0){
console.log("USERS QUEUE:"+users_queue[msg.sender_id]['0']);
for(var i=0;i<users_queue[msg.sender_id].length;i++){
cname=users_queue[msg.sender_id][i].split('_')[0];//get channel name from queue name
qn=users_queue[msg.sender_id][i];
rsmq.getQueueAttributes({qname:users_queue[msg.sender_id][i]},function(err,resp){
console.log("RESP:"+resp.msgs);
if(resp.msgs>0){ //if there are messages in queue......
for(var j=0;j<resp.msgs;j++){
rsmq.popMessage({qname:qn},function(err,resp){
console.log(resp);
var sid=socket_ids[msg.sender_id]; console.log("SOCKETID:"+sid); //get socket.id for the user
pub.publish(cname,resp.message);
});
}
}
});
}
}
}
else{
store.hmset("active_users."+msg.sender_id,{"status":"offline"});
user_status[msg.sender_id]="offline";
}
}
if(msg.channel_name=='ShareConversation'){
var channel=msg.conversations_data.conversation_id;//have to change to conversation_id or whatever channel.....
sub.subscribe(channel);
channel_users[channel]=[];
var m=msg.conversations_data.users.split(',');
for(var i=0;i<m.length;i++){
channel_users[channel].push(m[i]);
}
for(var i=0;i<channel_users[channel].length;i++){
var q=channel_users[channel][i].split('#')[0].replace(/(^\s+|\s+$)/g, '');
var queue_name=channel+"_"+q;console.log(queue_name);
var uname=channel_users[channel][i].replace(/(^\s+|\s+$)/g, '');
users_queue[uname]=[];
users_queue[uname].push(queue_name);
rsmq.createQueue({qname:queue_name}, function (err, resp) {
console.log(err);
console.log(queue_name);
if (resp===1) {
console.log("queue created");
}
});
}
}
socket.broadcast.emit('json', msg);
});
sub.on('message', function (channel, message) {
console.log("Message: " + message);
for(var i=0;i<channel_users[channel].length;i++){
var c=channel_users[channel][i].replace(/(^\s+|\s+$)/g, '');console.log("channel_users:"+channel_users[channel][i]);console.log("USER STATE :"+ user_status[c]);
if(user_status[c]=='offline'){
//send notification.........
//put messages in queue.......
var q=channel_users[channel][i].split('#')[0].replace(/(^\s+|\s+$)/g, '');
var queue_name=channel+"_"+q;console.log(queue_name);
rsmq.sendMessage({qname:queue_name, message:message}, function (err, resp) {
console.log(err);
if (resp) {
console.log("Message sent. ID:", resp);
}
});
}
}
socket.emit(channel, message);
});
});
This is my entire code. Here the issue is when the user goes offline, the message gets saved in queue multiple times and when the user comes online, the messages are received multiple times as there are duplicate messages saved in queue. How to overcome this.Please help....
Related
Below I try to respond with a stream when I receive ticker updates.
+page.server.js:
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(ticker.price);
});
}
});
export async function load() {
return response????
};
Note: The YahooFinanceTicker can't run in the browser.
How to handle / set the response in the Sveltekit load function.
To my knowledge, the load functions cannot be used for this as their responses are JS/JSON serialized. You can use an endpoint in +server to return a Response object which can be constructed from a ReadableStream.
Solution: H.B. comment showed me the right direction to push unsollicited price ticker updates the client.
api route: yahoo-finance-ticker +server.js
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
/** #type {import('./$types').RequestHandler} */
export function GET({ request }) {
const ac = new AbortController();
console.log("GET api: yahoo-finance-ticker")
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(String(ticker.price));
}, { signal: ac.signal });
},
cancel() {
console.log("cancel and abort");
ac.abort();
},
})
return new Response(stream, {
headers: {
'content-type': 'text/event-stream',
}
});
}
page route: +page.svelte
<script>
let result = "";
async function getStream() {
const response = await fetch("/api/yahoo-finance-ticker");
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const { value, done } = await reader.read();
console.log("resp", done, value);
if (done) break;
result += `${value}<br>`;
}
}
getStream();
</script>
<section>
<p>{#html result}</p>
</section>
I am building an Expo App for IOS Phone. I have added login page which provides reset password mechanism. I have used Node.js program to reset the password and the new resetted password is saved as hash password using bcrypt (ex: $2b$05$cMUtC/1WHxzGNqDTJcCBJOf9i7D6ad57jKyYqChLF0Vvji1A2mzIq for Test123456) inside Mysql database. This is working well and good. Below is the node.js program:
users.js:
var express = require('express');
var router = express.Router();
var connection = require('../database.js');
var nodemailer = require('nodemailer');
var bcrypt = require('bcrypt');
var randtoken = require('rand-token');
//send email
function sendEmail(email, token) {
var email = email;
var token = token;
var mail = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '*******#gmail.com', // Your email id
pass: '*******' // Your password
}
});
var mailOptions = {
from: 'abc#tech.com',
to: email,
subject: 'Reset Password Link - Tutsmake.com',
html: '<p>You requested for reset password, kindly use this link to reset
your password</p>'
};
mail.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(1)
} else {
console.log(0)
}
});
}
/* home page */
router.get('/', function(req, res, next) {
res.render('index', {
title: 'Forget Password Page'
});
});
/* send reset password link in email */
router.post('/reset-password-email', function(req, res, next) {
var email = req.body.email;
connection.query('SELECT * FROM JTGDB.UserInfo WHERE email ="' + email + '"',
function(err, result) {
if (err) throw err;
var type = ''
var msg = ''
console.log(result[0]);
if (result[0].Email.length > 0) {
var token = randtoken.generate(20);
var sent = sendEmail(email, token);
if (sent != '0') {
var data = {
token: token
}
connection.query('UPDATE JTGDB.UserInfo SET ? WHERE email ="' + email + '"', data,
function(err, result) {
if(err) throw err
})
type = 'success';
msg = 'The reset password link has been sent to your email address';
} else {
type = 'error';
msg = 'Something goes to wrong. Please try again';
}
} else {
console.log('2');
type = 'error';
msg = 'The Email is not registered with us';
}
req.flash(type, msg);
res.redirect('/');
});
})
/* reset page */
router.get('/reset-password', function(req, res, next) {
res.render('reset-password', {
title: 'Reset Password Page',
token: req.query.token
});
});
/* update password to database */
router.post('/update-password', function(req, res, next) {
var token = req.body.token;
var password = req.body.password;
connection.query('SELECT * FROM JTGDB.UserInfo WHERE token ="' + token + '"',
function(err, result) {
if (err) throw err;
var type
var msg
if (result.length > 0) {
var saltRounds = 5;
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
var data = {
password: hash
}
connection.query('UPDATE JTGDB.UserInfo SET ? WHERE email ="' + result[0].Email +
'"', data, function(err, result) {
if(err) throw err
});
});
});
type = 'success';
msg = 'Your password has been updated successfully';
} else {
console.log('2');
type = 'success';
msg = 'Invalid link; please try again';
}
req.flash(type, msg);
res.redirect('/');
});
})
module.exports = router;
But in Expo App, I want to hash the password that we enter in the login page and compare with the database hash password and then let the user to log into the App.
I have added a post request in app.js to get password from expo app and convert to hash code and compare it with database password to let user log in.Below is the app.js code .
app.js:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var flash = require('express-flash');
var session = require('express-session');
var bodyParser = require('body-parser');
const createError = require('http-errors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var bcrypt = require('bcrypt');
var app = express();
/* hash password from database to expo App */
app.post('/hash-password', function(req, res, next) {
const password = req.body.password;
console.log('Password is '+password)
var saltRounds = 5;
//var hash = bcrypt.hash(password, saltRounds);
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
var data = {
password: hash
}
console.log(data);
})
})
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: '********',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash());
app.use('/', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err :
{};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(4000, function () {
console.log('Node app is running on port 4000');
});
module.exports = app;
I checked the code by sending password from postman ,but I am getting the below error:
I have an operator table as follows:
id, code, name
And I have a table for the logged in user:
id, code, userid
I want the same chat codes to see each other.
in my chathub:
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
and in my view:
$(function () {
var chat = $.connection.chatHub;
chat.client.broadcastMessage = function (name, message) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
$('#discussion').append('<li style="background-color: #dfdfed;margin-bottom:2px;border-radius:4px;padding:10px;"><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
var scr = $('#uDIV')[0].scrollHeight;
$('#uDIV').animate({ scrollTop: scr });
};
$('#message').focus();
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
chat.server.send($('#displayname').val(), $('#message').val());
$('#message').val('').focus();
});
});
});
Can i fix my problems and what wrong in my code?
Problems
i use application for call to my clients from twilio number
When my managers call to US phone number, client see incoming call as "Unknown name"
When my manager calls - silence before connect to client in browser
Then client accepts call - and all ok
Server code
generateToken: () {
let clientName = 'twilio_agent';
let _id = req.body._id;
let phoneno = req.body.phoneno;
//
realmsProvider.get({_id: _id})
.then(data => {
if (!data) {
return res.status(404).json({ message: 'Account not found with _id:'+ _id });
}
var capability = new ClientCapability({
accountSid: data.sid,
authToken: data.authToken,
ttl: config.twilio.ttl
});
capability.addScope(
new ClientCapability.OutgoingClientScope({
applicationSid: data.application.sid,
clientName: data.name,
callerId: phoneno
}));
// incoming call
if (phoneno != null) {
capability.addScope(
new ClientCapability.IncomingClientScope(phoneno));
}
else {
capability.addScope(
new ClientCapability.IncomingClientScope(clientName));
}
var token = capability.toJwt();
return res.status(200).json({ token: token });
})
.catch(err => {
return utils.handleError(res, err);
});
}
voice: () {
let phoneNumber = req.body.PhoneNumber;
let callerId = req.body.CallerId;
let twiml = new VoiceResponse();
let dial = twiml.dial({
//https://www.twilio.com/docs/api/twiml/dial
answerOnBridge: true,
//phone number from
callerId : callerId,
//record all calls
record: 'record-from-answer-dual'
});
if (phoneNumber != null) {
dial.number(phoneNumber);
}
dial.client(callerId.replace(/\+/, ''));
res.type('text/xml');
res.send(twiml.toString());
}
Browser code
Twilio.Device.setup(token, {
debug: true,
enableRingingState: true,
sounds: {
incoming: 'URL-TO-MP3.mp3',
outgoing: 'URL-TO-MP3.mp3',
dtmf8: 'URL-TO-MP3.mp3'
}
});
function call(currentPhoneno, phoneTo, companyNameInTwilio) {
$scope.calling = 1;
if (!validatePhoneno(phoneTo)) {
growl.error('Bad phone number');
return;
}
var connection = Twilio.Device.connect({ // Connect our call.
CallerId: currentPhoneno, // Your Twilio number (Format: +15556667777).
PhoneNumber: phoneTo, // Number to call (Format: +15556667777).
From: companyNameInTwilio
});
connection.on('ringing', function(hasEarlyMedia) {
// some code for ringing
});
}
Is that possible to upload any file(doc,pdf,img) in xamarin android using web service in c#. i am using sql server for data connection.
Use MediaFile from the Xamarin.Plugins.Media Library.
public static void upload(MediaFile mediaFile)
{
try
{
StreamContent scontent = new StreamContent(mediaFile.GetStream());
scontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = "newimage",
Name = "image"
};
scontent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
var client = new HttpClient();
var multi = new MultipartFormDataContent();
multi.Add(scontent);
client.BaseAddress = new Uri(Constants.API_ROOT_URL);
var result = client.PostAsync("api/photo", multi).Result;
Debug.WriteLine(result.ReasonPhrase);
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
And node.js code to receive request.
var formidable = require('formidable');
var util = require('util');
var fs = require('fs');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
console.log(file.fieldname);
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage: storage }).single('image');
exports.post = function (req, res) {
upload(req, res, function (err) {
console.log(req.file);
if (err) {
console.log("ERROR : "+err);
return res.end("Error uploading file.");
}
console.log("SUCCESS");
res.end("File is uploaded");
});
};
See complete information from below thread
https://forums.xamarin.com/discussion/18649/best-practice-to-upload-image-selected-to-a-web-api
https://forums.xamarin.com/discussion/5033/upload-file-from-device-to-server