I've been studying kafkajs and socket.io I'm am very new to it and i cant seem to understand some things.
I have created a chat application that basically by opening a browser(client) you can type messages and they get displayed in a chat-window.
I found a tutorial that makes kafka print "this message + i".
I want to instead of sending to the topic and printing message+i to print what people type in chat and I'm not sure how I'm supposed to do that.
This is my consumer.js:
const { Kafka } = require("kafkajs")
const clientId = "my-app"
const brokers = ["localhost:9092"]
const topic = "message-log"
const kafka = new Kafka({ clientId, brokers })
// create a new consumer from the kafka client, and set its group ID
// the group ID helps Kafka keep track of the messages that this client
// is yet to receive
const consumer = kafka.consumer({ groupId: clientId })
const consume = async () => {
// first, we wait for the client to connect and subscribe to the given topic
await consumer.connect()
await consumer.subscribe({ topic })
await consumer.run({
// this function is called every time the consumer gets a new message
eachMessage: ({ message }) => {
// here, we just log the message to the standard output
console.log(`received message: ${message.value}`)
},
})
}
module.exports = consume
This is my producer.js:
// import the `Kafka` instance from the kafkajs library
const { Kafka } = require("kafkajs")
// the client ID lets kafka know who's producing the messages
const clientId = "my-app"
// we can define the list of brokers in the cluster
const brokers = ["localhost:9092"]
// this is the topic to which we want to write messages
const topic = "message-log"
// initialize a new kafka client and initialize a producer from it
const kafka = new Kafka({ clientId, brokers })
const producer = kafka.producer()
// we define an async function that writes a new message each second
const produce = async () => {
await producer.connect()
let i = 0
// after the produce has connected, we start an interval timer
setInterval(async () => {
try {
// send a message to the configured topic with
// the key and value formed from the current value of `i`
await producer.send({
topic,
messages: [
{
key: String(i),
value: "this is message " + i,
},
],
})
// if the message is written successfully, log it and increment `i`
console.log("writes: ", i)
i++
} catch (err) {
console.error("could not write message " + err)
}
}, 1000)
}
module.exports = produce
I know I'm supposed to somehow connect the topics brokers and clients with the socket.io but I'm not sure how.
Here is my chat.js:
/* Kane connection sto server opos prin
exw tin ikanotita na xrhsimopoihsw to io logo tou library pou phra apo to documentation*/
var socket = io.connect('http://localhost:8000');
// linking Variables toy indexhtml
var message = document.getElementById('message');
var username = document.getElementById('username');
var btn = document.getElementById('send');
var output = document.getElementById('output');
var feedback = document.getElementById('feedback');
// Stelnw events pou ginonte apo ton xristi kai stelnonte ston server
btn.addEventListener('click', function(){
socket.emit('chat', {
message: message.value,
username: username.value
});
message.value = "";
});
message.addEventListener('keypress', function(){
socket.emit('typing', username.value);
})
// Events wste na perimenw to data apo ton server
socket.on('chat', function(data){
feedback.innerHTML = '';
output.innerHTML += '<p><strong>' + data.username + ': </strong>' + data.message + '</p>';
});
socket.on('typing', function(data){
feedback.innerHTML = '<p><em>' + data + ' is typing a message...</em></p>';
});
You'll need a socket.io server.
Example:
const consume = require('consumer.js');
const produce = require('producer.js');
const { Server } = require('socket.io');
const io = new Server();
consume(({ from, to, message }) => {
io.sockets.emit('newMessage', { from, to, message });
})
io.on('connection', function(socket) {
socket.emit('Hi!', { message: 'Chat connected', id: socket.id });
socket.on('sendMessage', ({ message, to }) => {
produce({ from: socket.id, to, message });
});
});
You also need to modify your consumer & producer to accept parameters and callbacks.
Consumer Example:
...
const consume = async cb => {
// first, we wait for the client to connect and subscribe to the given topic
await consumer.connect()
await consumer.subscribe({ topic })
await consumer.run({
// this function is called every time the consumer gets a new message
eachMessage: ({ from, to, message }) => {
cb({ from, to, message });
},
});
}
Producer Example:
const produce = async ({ from, to, message }) => {
producer.send(topic, { from, to, message });
}
Don't forget to modify your chat.js on the client side
All of this can be optimized and is just a brief example
Related
I am trying to create a slackbot for private channel.I have set it up as an app and created a bot. But, whenI am trying to post the message in private channel it's not working. It works for the public channels. I have added the app/bot in the private channel. I am using Bot User OAuth Access Token in my code.
const axios = require('axios');
const bot = new SlackBot({
token: 'already-given',
name: 'bot'
});
// Start Handler
bot.on('start', () => {
const params = {
icon_emoji: ':smiley:'
};
bot.postMessageToChannel(
'pvtchannel',
'I will assign a member soon!',
params
);
});
// Error Handle
bot.on('error', err => console.log(err));
// Message Handler
bot.on('message', data => {
if (data.type !== 'message') {
return;
}
handleMessage(data.text);
});
// Response to Data
function handleMessage(message) {
if (message.includes('newspin')) {
newSpin();
} else (message.includes('help')) {
runHelp();
}
}
// Pick a team member randomly
function newSpin() {
const params = {
icon_emoji: ':laughing:'
};
var members=['1','2','3','4','5','6','7'];
var assignee = members[Math.floor(Math.random()*members.length)];
bot.postMessageToChannel('pvtchannel', `It's ${assignee}'s turn today!`, params);
}
// Show Help Text
function runHelp() {
const params = {
icon_emoji: ':question:'
};
bot.postMessageToChannel(
'pvtchannel',
`Type #bot with either 'newspin' for new spinning again,
params
);
}
Is this how we need to post messages to private channel?
bot.postMessageToChannel('pvtchannel', 'It's ${assignee}'s turn today!', params);
I am confused if I need to add anything before the pvtchannel as it's private.
I am trying to learn Google Assistant integration using DialogFlow, I have written the following code which works like charm when I test in dialogFlow but fails when I test the same on Google Assistant (i.e. Context passed from Intent getBillingInfo becomes null when accessed in payBill intent). Kindly help me understand where I am going wrong.
Code:
var https = require ('https');
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// // below to get this function to be run when a Dialogflow intent is matched
function getBillingInfoHandler(agent) {
const parameters = request.body.queryResult.parameters;
var phoneNumber = parameters['phone-number'];
console.log("Phone Number: "+ phoneNumber);
let url = "https://testapi.io/api/shwej//getBillingInfo";
return new Promise((resolve, reject) => {
https.get(url, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (chunk) => {body += chunk; });
res.on('end', () => {
// After all the data has been received, parse the JSON for desired data
let response = JSON.parse(body);
let output = response.billing_amount;
// Resolve the promise with the output text
console.log(body);
agent.add("Your bill for " + phoneNumber + " is " + output + " ₹ ");
agent.add(new Suggestion(`Click to Pay`));
//agent.setContext('billing_context');
//const context = {'phoneNumber': phoneNumber, 'billAmount': output};
//agent.setContext(context);
agent.setContext({
'name':'billing-context',
'lifespan': 50,
'parameters':{
'phoneNumber': phoneNumber,
'billAmount': output
}
});
resolve();
});
res.on('error', (error) => {
agent.add("Error occurred while calling API.");
console.log(`Error calling the API: ${error}`);
reject();
});
});
});
}
function payBillHandler(agent) {
let billingContext = agent.getContext('billing-context');
if (typeof billingContext === 'undefined' || billingContext === null){
agent.add("Some error with passing context!!!");
}else{
agent.add("Your payment is successful! ");
agent.add(" Phone Number : " + billingContext.parameters.phoneNumber);
agent.add(" Amount paid : " + billingContext.parameters.billAmount + " ₹ ");
}
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('getBillingInfo', getBillingInfoHandler);
intentMap.set('payBill', payBillHandler);
agent.handleRequest(intentMap);
});
It doesn't look like you're importing the Actions on Google client library. Try replacing the first few lines of your fulfillment with:
// Import the Dialogflow module and response creation dependencies
// from the Actions on Google client library.
const {
dialogflow,
BasicCard,
Permission,
Suggestions,
} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});
You can also try out the Actions on Google codelabs (level 1, level 2) or review the Actions on Google github repos.
I'm trying to send ethereum transaction that sends ERC20 tokens to someone with Ledger Nano S through Node.JS but I'm not able to successfully sign and send this transaction.
First of all, I signed the transaction through the method, signTransaction, of ledgerhq API and then after signing it, I sended it to the main net by using sendSignedTransaction. When I execute below code, Ledger receives request and shows details of a transaction. However, after pressing Ledger's confirm button, the console returns error 'Returned error: Invalid signature: Crypto error (Invalid EC signature)'.
import AppEth from "#ledgerhq/hw-app-eth";
import TransportU2F from "#ledgerhq/hw-transport-u2f";
import TransportNodeHid from "#ledgerhq/hw-transport-node-hid";
import EthereumTx from "ethereumjs-tx"
const Web3 = require('web3');
import { addHexPrefix, bufferToHex, toBuffer } from 'ethereumjs-util';
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var destAddresses = ['0xa6acFa18468786473269Dc1521fd4ff40F6481D9'];
var amount = 1000000000000;
var i=0;
var contract = new web3.eth.Contract([token contract ABI... ], '0x74a...');
const data1 = contract.methods.transfer(destAddresses[0], amount).encodeABI();
const exParams = {
gasLimit: 6e6,
gasPrice: 3e9,
from: '0x1A...',
data : data1,
to: '0x74a...',
value: '0x00',
nonce: "0x0",
chainId: 1,
v: "0x01",
r: "0x00",
s: "0x00"
}
async function makeSign(txParams) {
const tx = new EthereumTx(txParams);
const txHex = tx.serialize().toString("hex");
const signedTransaction = '0x' + txHex;
let transport;
try {
transport = await TransportNodeHid.create();
let eth2 = new AppEth(transport);
const result = await eth2.signTransaction("m/44'/60'/0'/0", txHex).then(result => {
web3.eth.sendSignedTransaction('0x' + txHex)
.then(res => {
console.log(res);
}).catch(err => {
console.log('sendSignedTransaction');
console.log(err);
});
}).catch(err => {
console.log('signTransaction');
console.log(err);
});
txParams.r = `0x${result.r, 'hex'}`;
txParams.s = `0x${result.s, 'hex'}`;
txParams.v = `0x${result.v, 'hex'}`;
return result;
} catch (e) {
console.log(e);
}
}
makeSign(exParams).then(function () {
console.log("Promise Resolved2");
}.catch(function () {
console.log("Promise Rejected2");
});
When I only use signTransaction function, I can confirm the transaction in the ledger device and return txhash on the console. However, ultimately I want to broadcast a transaction to the main net. Could you please give me any idea? I want any feedback. Also, if there are any examples of creating and broadcasting a raw transaction by using the ledger, notice me please.
Your code already sends the transaction to the network. However, just awaiting the "send" promise only gives you the transaction hash, not the receipt. You need to treat it as an event emitter and wait for the 'confirmation' event.
const serializedTx = tx.serialize();
web3.eth.sendSignedTransaction(serializedTx.toString('hex'))
.once('transactionHash', hash => console.log('Tx hash', hash))
.on('confirmation', (confNumber, receipt) => {
console.log(`Confirmation #${confNumber}`, receipt);
})
.on('error', console.error);
To send it to mainnet as you mention, you can either run a local geth node on port 8545 and use your code unchanged, or point web3 at infura or similar.
I am experimenting with push-notifications sent from a Node.js app.
Following some tutorial and examples, I now have a working mini-application to start with.
What it does is very basic, when it is loaded into the browser, a notification is fired and the user sees a message popping up.
It is basically composed of four files:
index.js, index.html, worker.js and client.js.
As a first experiment, I would like to implement some slightly more sophisticated behavior.
The app should fire a notification of type A when it starts (as it is already doing) and then fire a notification of type B every 121 minutes.
Is this kind of thing possible or just impossible?
If it is possible, how can I do it?
For reference I put here the two relevant files:
index.js:
const express = require('express'),
webPush = require('web-push'),
bodyParser = require('body-parser'),
path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'client')));
app.use(bodyParser.json());
const privateVapIdKey = process.env.privVapIdKey,
publicVapIdKey = process.env.pubVapIdKey;
webPush.setVapidDetails(
'mailto:myemail#example.com',
publicVapIdKey,privateVapIdKey);
// Subscribe Route.
app.post('/subscribe',(req,res) => {
const subscription = req.body; // Get Push Subscription Object.
res.status(201).json({}); // Send 201. Resource created.
// Do a lot of useful things ......
.......
// Create the PayLoad.
const payload = JSON.stringify({
title:'A big title!',
........
});
// Pass Object to sendNotification.
webPush.sendNotification(subscription,payload).catch(err => console.error(err));
});
const port = 5003;
const PORT = process.env.PORT || port;
app.listen(PORT, () => console.log(`Listening on ${ PORT }`));
client.js:
const publicVapIdKey = 'my-secret-3453754...pubVapIdKey';
// Chec for ServiceWorker.
if ('serviceWorker' in navigator) {
send().catch(err => console.error(err));
}
// Register ServiceWorker, Register Push, Send Push.
async function send() {
console.log("Registering ServiceWorker.");
const register = await navigator.serviceWorker.register('/worker.js', {
scope: "/"
});
console.log('ServiceWorker registered.');
console.log("Registering Push.");
//register.pushManager.uns
const subscription = await register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapIdKey)
});
console.log('Push registered.');
console.log("Sending Push.");
await fetch('/subscribe', {
method: 'POST',
body: JSON.stringify(subscription),
headers: {
'content-type': 'application/json'
}
});
console.log('Push sent.');
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
Simple event timing can be achieved with setTimeout and setInterval: https://nodejs.org/api/timers.html
They work the same as in browser side JavaScript.
For something more advanced, try node-cron
To be able to send notifications to an endpoint, you need its subscription, so we have to store the clients subscriptions:
const subscriptions = [];
app.post('/subscribe',(req,res) => {
const subscription = req.body;
// FIXME: Validate subscription!!!
subscriptions.push(subscription);
res.status(201).json({});
webPush.sendNotification(subscription, { title: "A" });
});
Now every 121 minutes, we go over all subscriptions and deliver our message B:
const MINS = 60 * 1000;
setInterval(() => {
for(const subscription of subscriptions) {
webPush.sendNotification(subscription, {title: "B" });
}
}, 121 * MINS);
PS: You should probably also add an "unsubscribe" endpoint, as you would otherwise deliver notifications to dead endpoints somewhen
Its possible! but i would suggest you use Admin FCM for server side its more latest library than web-push and its way easier to push notification.
//node.js serverside code
const FCM = require("firebase-admin");
//fcm-push-notification.json is where all the configurations are
const serviceAccount = require("fcm-push-notification.json");
FCM.initializeApp({
credential: SERVICE_ACCOUNT,
databaseURL: DBURL
});
// In your Subscribe Route.
app.post('/subscribe',(req,res) => {
FCM.messaging()
.sendToDevice(
DEVICE_TOKEN,
{
data: DATA,
notification: {
title: "A big title!",
body: "HELLO PUSH!"
}
}
)
.then(res => {
// do something here
})
});
here is the service worker
// put firebase-messaging-sw.js service worker
// this is to get notified in the background when the tab is closed on not active
(global => {
importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js");
importScripts(
"https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js"
);
firebase.initializeApp({
messagingSenderId: SENDER_ID
});
const messaging = firebase.messaging();
console.log("Service Worker started!");
messaging.setBackgroundMessageHandler(payload => {
console.log("Message received In background");
// Customize notification here
const notificationOptions = {
body: "Background Message body.",
icon: "/firebase-logo.png"
};
return global.registration.showNotification("TITLE", notificationOptions);
});
})(self);
in your javascript
//to get notified in forground just do this
import firebase from "firebase";
firebase.initializeApp(FCM_CONF);
let messaging = firebase.messaging();
messaging.usePublicVapidKey(VAPID_KEY);
messaging.onMessage(payload => {
console.log("Message received from foreground ");
});
finally create a manifest.json
//create manifest.json with content like this
{
"gcm_sender_id": SENDER_ID
}
and to fire a notification of type B every 121 minutes. use something like later.js
var later = require('later');
var schedule = later.parse.text('every 121 min');
var timer = later.setTimeout(() => {
// fired every 121 minutes
FCM.messaging()
.sendToDevice(
DEVICE_TOKEN,
{
data: DATA,
notification: {
title: "A big title!",
body: "HELLO PUSH!"
}
}
)
}, schedule);
I'm building an app with Firebase and as they added functions I wanted to try this out but ran into a few errors as I am unfamiliar with this language... I'm trying to send an FCM to every user of a group (when a new one is added to the database) and I used the example I found online but still ran into some trouble.
exports.sendPush = functions.database.ref('/groups/{groupId}').onWrite(event => {
const groupId = event.params.groupId;
... // defining constants like msg
const participators = admin.database().ref('/groups/' + groupId + '/users').once('value');
let getDeviceTokensPromise = []
for (let part in participators) {
getDeviceTokensPromise.push(admin.database().ref('/users/' + part + '/notificationtoken')).once('value');
}
return Promise.all([getDeviceTokensPromise, participators]).then(results => {
const tokensSnapshot = results[0];
const follower = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched follower profile', follower);
// Notification details.
const payload = {
notification: {
title: 'New meeting!',
body: msg
}
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
...
So I guess my mistake must be in the first few lines as all the rest follows this code (I left out the unimportant bits)... Here is my firebase architecture:
The groups branch of the firebase database
One user under the branch users
Regards
Your code is fine. Just change the following
const participators = admin.database().ref('/groups/' + groupId + '/users').once('value');
and
getDeviceTokensPromise.push(admin.database().ref('/users/' + part + '/notificationtoken')).once('value');
to these :-
const participators = admin.database().ref(`/groups/${groupId}/users`).once('value');
and
getDeviceTokensPromise.push(admin.database().ref(`/users/${part}/notificationtoken`)).once('value');
Also, make sure that you use `` and not ' ' inside the ref part.