Yiiframework message pop up - javascript

He there!
If have a question that is related to two different issues I currently have in an application I'm working on.
Issue 1:
- There is a message system. Users are able to send each other messages. I would like to have a real time pop up when the user gets a new message and is not on the inbox page.
Issue 2:
- I would like to create a basic achievement system, one of the achievements could (for example) be: "Receive a message."
Now I think both functionalities can be achieved through the same way. Anyone of you has any experience with this type of real time communication? I really have no idea where to start. I would really love it if it is not to heavy.
Thanks a lot.

Here's a boilerplate you might use for long polling (using jQuery and Yii):
Server-side:
class MessagesController extends CController {
public function actionPoll( $sincePk, $userPk ) {
while (true) {
$messages = Message::model()->findAll([
'condition' => '`t`.`userId` = :userPk AND `t`.`id` > :sincePk',
'order' => '`t`.`id` ASC',
'params' => [ ':userPk' => (int)$userPk, ':sincePk' => (int)$sincePk ],
]);
if ($messages) {
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array_map(function($message){
return array(
'pk' => $message->primaryKey,
'from' => $message->from,
'text' => $message->text,
/* and whatever more information you want to send */
);
}, $messages));
}
sleep(1);
}
}
}
Client-side:
<?php
$userPk = 1;
$lastMessage = Messages::model()->findByAttributes([ 'userId' => $userId ], [ 'order' => 'id ASC' ]);
$lastPk = $lastMessage ? $lastMessage->primaryKey : 0;
?>
var poll = function( sincePk ) {
$.get('/messages/poll?sincePk='+sincePk+'&userPk=<?=$userPk?>').then(function(data) {
// the request ended, parse messages and poll again
for (var i = 0;i < data.length;i++)
alert(data[i].from+': '+data[i].text);
poll(data ? data[i].pk : sincePk);
}, function(){
// a HTTP error occurred (probable a timeout), just repoll
poll(sincePk);
});
}
poll(<?=$lastPk?>);
Remember to implement some kind of authentication to avoid users reading each others messages.

Related

WebPush data is null

im busy with Webpush to WebRTC application and need some help understanding the way some of it fits together.
After looking at the RFC: https://www.rfc-editor.org/rfc/rfc8599#section-12
I see that in Section 12 :
The value of the 'pn-provider' URI parameter is "webpush".
The value of the 'pn-param' URI parameter MUST NOT be used.
The value of the 'pn-prid' URI parameter is the push subscription
URI.
So, in my app.js I have implemented this something like this:
var pubKey = urlBase64ToUint8Array(<publicKey>)
var o = { userVisibleOnly: true, applicationServerKey: pubKey }
swg.pushManager.subscribe(o).then(function(sub){
var contact-params = {
"pn-provider" : "webpush"
"pn-prid" : sub.endpoint
}
// apply contact-params, and register
}
So as we can see above, the RFC specifies, 'pn-provider' and 'pn-prid' are to be used with your register. The pushManager.subscribe() provides me with this information, great... so far so good.
I have a Pubic key that I use above (with is corresponding private key that I have not used yet).
Now on the server my PHP code from here: https://github.com/web-push-libs/web-push-php
specifies a sample like the following:
$prid = $_GET['prid'];
$payload = '{ "text" : "Incoming Call !!" }';
$auth = array(
'VAPID' => array(
'subject' => $vapidSubject,
'publicKey' => $publicKey, // Same as in app.js
'privateKey' => $privateKey,
)
);
$subscription = Subscription::create(
array(
'endpoint' => $prid,
'contentEncoding' => 'aesgcm'
)
);
$webPush = new WebPush($auth);
$report = $webPush -> sendOneNotification($subscription, $payload);
The above php code works!... but, the payload (event.data) is null.
If I test with: https://web-push-codelab.glitch.me/ and give it the full subscription, with (the exact string of the sub from the app.js) it also works (as expected).
The same thing for my PHP code - If I add the keys:
$subscription = Subscription::create(
array(
'endpoint' => $prid,
'keys' => [
'p256dh' => '<sub.keys.p256dh>',
'auth' => '<sub.keys.auth>'
],
'contentEncoding' => 'aesgcm'
)
);
Then it work fine, and my payload is delivered.
So you can see, the problem is that the Push RFC says I only need to store 1 piece of information (endpoint), then have 1 common piece of information (public key) and 1 private piece of information (private key).
But in order for the the push code to work it needs 3 pieces of information, the endpoint, p256dh, auth, and then the public key and private key. (The p256dh and auth is of corse different with each endpoint.)
I think i'm missing something here, can someone help me understand this?

PUB/SUB Api doesn't send messages back, what might be the problem?

I have almost completed pub/sub fake-server, that requests user password and email (from the client), compares this info with database and returns data back. It has 'api_in' and 'api_out' frames and then the JSON.
The publisher takes and processes all the info without a hitch, but it doesn't seem to send anything back to the client (subscriber) and I don't know why, cause it is connected to the subsequent port.
And I know that this implementation is not a classic PUB/SUB pattern, but that was prerequisite, to do it like that.
I tried different pub/sub options, but nothing has changed.
Server
let zmq = require('zeromq');
const sqlite3 = require('sqlite3').verbose();
const DBSOURCE = "./db.sqlite";
let db = new sqlite3.Database(DBSOURCE, (err) => {
if(err) {
console.error(err.message);
throw err;
} else {
console.log('Connected to SQLite database');
db.run(`CREATE TABLE users (
user_id INTEGER,
email TEXT,
passw TEXT)`,
(err) => {
if (err) {
// Table already created
} else {
// Creating rows
let insert = 'INSERT INTO users (user_id, email, passw) VALUES (?,?,?)';
db.run(insert, [123098, 'phillCollins#gmail.com','5502013']);
db.run(insert, [42424242,'dukenukem3d#mustdie.com','RodriguesShallLiveLong']);
db.run(insert, [5,'yourchick#yandex.ru','semolinaAndPain666']);
}
})
}
});
const args = require('minimist')(process.argv.slice(2));
const pubSocket = zmq.socket('pub', null);
pubSocket.bindSync(`tcp://127.0.0.1:${args['pub']}`);
const subSocket = zmq.socket('sub', null);
subSocket.subscribe('api_in');
subSocket.on('message', function(data) {
let message = data.toString().replace(/api_in/g, '');
let mes = JSON.parse(message);
let api_out = 'api_out';
let errorWrongPWD = 'WRONG_PWD';
let errorWrongFormat = 'WRONG_FORMAT';
if(mes.type = 'login') {
db.get(`SELECT user_id from users WHERE email = ? and passw = ?`, [mes.email, mes.pwd], function(err, row) {
if(err) {
console.log(err);
} else {
if(row) {
let msg = {
msg_id: mes.msg_id,
user_id: row.user_id,
status: 'ok'
}
let outMessage = api_out + JSON.stringify(msg);
console.log(outMessage);
subSocket.send(outMessage);
} else {
let msg = {
msg_id: mes.msg_id,
status: 'error',
error: mes.email == '' || mes.pwd == '' ? errorWrongFormat : errorWrongPWD
}
console.log(msg);
let outMessage = api_out + JSON.stringify(msg);
subSocket.send(outMessage);
}
}
});
}
});
subSocket.bindSync(`tcp://127.0.0.1:${args['sub']}`);
client
let zmq = require('zeromq');
let uniqid = require('uniqid');
let readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
const args = require('minimist')(process.argv.slice(2));
const pubSocket = zmq.socket('pub', null);
let pubSocketTCP = `tcp://127.0.0.1:${args['sub']}`;
pubSocket.connect(pubSocketTCP);
const subSocket = zmq.socket('sub', null);
let subSocketTCP = `tcp://127.0.0.1:${args['pub']}`;
subSocket.connect(subSocketTCP);
let api_in = 'api_in';
let secondFrame = {
type: 'login',
email: '',
pwd: '',
msg_id: uniqid()
}
readline.question('What is your email? \n', (email) => {
secondFrame.email = email;
readline.question('What is your password \n', (pwd) => {
secondFrame.pwd = pwd;
let msg = api_in + JSON.stringify(secondFrame);
console.log(msg);
pubSocket.send(msg);
});
});
subSocket.subscribe('api_out');
subSocket.on('message', (response) => {
/* let res = response.toString().replace('api_out');
let responseParsed = JSON.parse(res);
console.log(responseParsed.status);
if(response.status == 'error') console.log(response.error); */
console.log(response);
});
I want the server side to send info back.
Well, first of all, welcome to the Zen-of-Zero domain. ZeroMQ is a powerful tool for smart signaling / messaging, so if you pay attention to all its internal beauties, there will be no such thing you will not be able to do with it ( nightmares still not avoided on this way forward ). If feeling to be new to this domain, one may enjoy a short read into "ZeroMQ Principles in less than Five Seconds" before diving into further details on subject, or re-use some of tricks posted here
Q : it doesn't seem to send anything back to the client (subscriber) and I don't know why
There are two pieces of code, that seem to use both PUB and SUB Scalable Formal Communication Pattern Archetypes, yet have some glitches on how these get configured.
The server-code :
seems to try to instantiate PUB-archetype and equips that instance with a single AccessPoint, using .bindSync()-method and cli-parameter args['pub'] for accepting connections over a plain and commontcp://-transport-class.
After defining the event-handler .on( 'message', ... ) for the second instance, being the SUB-archetype, this one becomes .bindSync()-equipped with a single AccessPoint, using tcp://-transport-class, for receiving connections using tcp://-transport-class.
If you indeed have to make a .send() over a SUB-alike archetype, you have to use XSUB alternative, where you can send data and perform some tricks with the actual payload on the PUB-side or XPUB-side ( ref. API documentation for details about ZMQ_XPUB_MANUAL mode capabilities and limits for some wilder data-mangling on the XPUB-side )
ZMQ_XSUB
Same as ZMQ_SUB except that you subscribe by sending subscription messages to the socket. Subscription message is a byte 1 (for subscriptions) or byte 0 (for unsubscriptions) followed by the subscription body. Messages without a sub/unsub prefix may also be sent, but have no effect on subscription status.
The client-code :
Seems to instantiate and .connect() both the client-local PUB and SUB Archetypes over tcp://-transport-class to the server-side AccessPoints ( which both ought to set ZMQ_LINGER to 0, so as to avoid infinitely hanging orphans ( version dependent defaults do not have other solution but an explicit setting on this ) ).
Possible improvements :
XPUB/XSUB with ZMQ_XPUB_MANUAL may solve the sending via SUB-archetype
XPUB/SUB with ZMQ_XPUB_MANUAL may solve the sending via SUB-archetype with less comfort of masquerading the messages to be sent via the .subscribe()-method
PUB/SUB with making all .send()-s strictly via a local PUB-archetype instance.
be explicit with ZMQ_SNDHWM and ZMQ_RCVHWM parameters if still loosing messages
be explicit on setting .subscribe() only after a successfully completed { .bind() + .connect() }-methods ( systematically using original zmq_errno() and zmq_strerror() functions for actively detecting and repairing the potential colliding states )
may request to work with only completed connections ( distributed systems have zero-warranty of an order of operations autonomous distributed (many) agents perform ) using .setsockopt( ZMQ_IMMEDIATE, 1 )
Your server is trying to send on the sub socket
subSocket.send(outMessage);
You can't send on the sub socket. It should be sending on a pub socket.

how can I create my mongodb query based on the input from the user in node.js?

Currently in my app I store different forum posts. Users can add new messages and create new posts.
Other users - while displaying the content - can filter it so that they will not see the content uploaded by specific users that they blocked earlier.
Each user is represented as a combination of device_id and display_name.
When users are fetching content, they do a post query and include an array of previously blocked users:
"blockedUsers": (
{
"device_id" = "XXX";
"display_name" = XXX;
},
{
"device_id" = "YYY";
"display_name" = YYY;
}
)
Currently there's a possibility of adding content with some registered display_name or anonymously.
Right now I support only filtering users with some display_name:
if(blockedUsers) {
var excludedUsernames = [];
for(var i in blockedUsers) {
excludedUsernames.push(blockedUsers[i]['display_name']);
}
query.$and.push({ 'display_name': { $nin: excludedUsernames } });
}
That works fine - when user is registered and has some display_name (that is different than anonymous) - I don't care about his device_id, all I care is to block him by his display_name.
But, when some anonymous users has been blocked before:
"blockedUsers": (
{
"device_id" = "XXX";
"display_name" = "anonymous"; //represents anonymous user
},
{
"device_id" = "YYY";
"display_name" = "anonymous"; //represents anonymous user
}
)
I need to exclude his posts by device_id and the display_name == anonymous. In that case when there's some device_id but contains display_name != anonymous - I don't want to block that.
I don't know how to update my query so that it covers the requirement from above, could you help me with that? Thanks!
If I understood well:
If user has a banned device_id, then block him
If user has a banned display_name, then block him
In that case, it does not really matter if he is anonymous or not.
let excludedUsernames, excludedDevices;
blockedUsers.forEach((e) => {
excludedUsernames.puhs({ e["display_name"] });
excludedDevices.push({ e["device_id"] });
});
query.$and.push({ 'display_name' : { $nin: excludedUsernames } });
query.$and.push({ 'device_id' : { $nin: excludedDevices } });
EDIT
query.$or.push({
$and: [
{ 'device_id' : { $nin: excludedDevices }},
{ 'display_name' : "anonymous" }
]
});
query.$or.push({ 'display_name' : { $nin: excludedUsernames } });

How do I use a php array within an array returned to Javascript?

I've been at this for more than half a day trying to figure out this problem and I swear I've tried every possible thing. So here's the idea behind what I'm trying to do... Every 10 seconds Javascript performs an AJAX call to see if you have any friends online, then returns a list of users, their status etc... Instead of formatting everything from PHP, I'll be formatting it from Javascript for various reasons... So here's what happens:
Javascript
// Let's get the data from the controller
$.post('/pagething', { datastuff }, function(data){
if(data.status == 'ok'){
// Magic nonsense here that can translate the array example:
var keys = Object.keys(data.allfriends);
}
} etc...
PHP
// Let's skip other code in the controller and focus on the important stuff
$friends_information = array(
'userid' => array();
'username' => array();
'avatar' => array();
'status' => array();
);
foreach($result_from_my_friends_model as $row){
// For ease of read, i'll just associate things with $row
$friends_information["userid"][] = $row->user_id;
$friends_information["username"][] = $row->username;
$friends_information["avatar"][] = $row->avatar;
$friends_information["status"][] = $row->status;
}
$result = array('status' => 'ok', 'allfriends' => $friends_information);
return json_encode($result);
exit();
The closest I've gotten is to either get the results by say username, or userid for example through a new object or getting the entire result but unable to distinguish between keys since object[0][1] for instance would return undefined.
Thank you in advanced, this stuff is tough to understand :/
There's no need to put each column into a separate element of $friend_array, things are generally easier if you keep all the data related to a particular friend together in an object. So do:
$result = array('status' => 'ok', 'allfriends' => $result_from_my_friends_model);
echo json_encode($result);
In the Javascript, make sure you specify that the result is JSON:
$.post('/pagething', { datastuff }, function(data) {
if (data.status == 'ok') {
$.each(data.allfriends, function(i, friend) {
// do stuff with friend.userid, friend.username, friend.avator, friend.status
});
}
}, 'json');
You already have your list_of_friend in your keysvariable of js. Just iterate through it then you will get your desired result. Best of luck

How to get display the facebook response on the page/obtain the data of facebook user?

I am a beginner to create a Facebook tab.
I try to use the Facebook Javascript SDK (https://developers.facebook.com/docs/reference/javascript/) to create it. I know that when the user has authorized his/her information, there is a response stored this information. However, I don't know how to obtain this value in order to display on the webpage. I only know that ajax should be used in this case, but I have nearly no knowledge about ajax. Therefore, I want to know whether there is any sample code to solve this problem. Thank you.
There is a part of code in the index.php. I am using Slim framework and RedBeans.
$app->map('/intro', function () use($app) {
$app_id = "XXXXXXXXX";
$app_secret = "XXXXXXXXXXX";
$introduction = R::findOne('introduction', 'id = 1');
$name = $introduction->name;
$description = $introduction->description;
$req = $app->request();
$var = $req->post('args');
print_r($var);
$data = array(
'title' => $name,
'heading' => $description,
'app_id' => $app_id,
'app_secret' => $app_secret,
'uid' => $var.id
);
$app->render('/question/tpl_intro.php', $data);
})->via('GET', 'POST');
the facebook api uses an event based system. what this means to you, is that you need to register callback functions that facebook can call when certain events happen on their system.
the first thing you need to do after linking in the fb jssdk is to add the FB.init() call. after this call is done, you can hook into whatever javascript of yours you want to load details for the user.
<script type='text/javacript'>
function AttachHandlers() {
// getLoginStatus checks if the user is logged in and authorized your app, just
// logged in and hasn't authorized your app, or isn't logged in.
FB.getLoginStatus(function(response) {
if (response.status == 'connected') {
// if they're logged in and you're authorized, you can actually
// query facebook for details on the user.
FB.api('/me', function(data) {
//data will have user details in it.
//console.log(data);
local args = {name: ''};
if (data.email)
args.email = data.email;
if (data.first_name)
args.name = data.first_name;
if (data.last_name)
args.name += ' ' + data.last_name;
// and on and on for as many properties as you need
$.post('http://www.yoursite.com/posthandler.php',
args,
function (d, status, xhr) { console.log(d); });
});
}
});
}
window.fbAsyncInit = function () {
FB.init({appId: 'yourID', status: true, cookie: true, oauth: true, xfbml: true});
// now the facebook api is loaded properly, you can now start using it.
AttachHandlers();
}
</script>
Essentially, once the library is loaded - you just pass it some of your own functions that it can call to update you when things happen with that user on facebook (logging in/out, authorizing/unauthorizing your app, etc).

Categories