How to subscribe to coinbase pro websocket - websocket

I'm trying to subscribe to my user channel on coinbase pro, in order to get message from filled orders I place. However after doing the subscription process without issues I'm not receiving any message from orders I'm creating or placing.
I did the following request to subscribe to my user channel.
const WebSocket = require("ws");
const ws = new WebSocket("wss://ws-feed.exchange.coinbase.com", {
perMessageDeflate: false,
});
ws.on("open", function open() {
const timestamp = Date.now() / 1000;
const key = "my_key";
const passphrase = "my_pass";
const secret = "my_secret";
const method = "GET";
const request_path = "/users/self/verify";
const string_to_sign = `${timestamp}${method}${request_path}`;
const b_secret = Buffer.from(secret, "base64");
const signature = crypto
.createHmac("sha256", b_secret)
.update(string_to_sign)
.digest("base64");
ws.send(
JSON.stringify({
type: "subscribe",
product_ids: ["ETH-USD"],
channels: ["user"],
signature,
key,
passphrase,
timestamp,
})
);
});
Everything is perfect until this point because I got successfully subscribed, but when I place or create a new order for ETH-USD I'm not receiving anything!
Please, can you help me?
I tried this to listen messages:
ws.on("message", function message(data) {
console.log("received: %s", data);
});
No messages received =(

Related

AWS API gateway websocket receives messages inconsistently

I have a websocket in api gateway connected to a lambda that looks like this:
const AWS = require('aws-sdk');
const amqp = require('amqplib');
const api = new AWS.ApiGatewayManagementApi({
endpoint: 'MY_ENDPOINT',
});
async function sendMsgToApp(response, connectionId) {
console.log('=========== posting reply');
const params = {
ConnectionId: connectionId,
Data: Buffer.from(response),
};
return api.postToConnection(params).promise();
}
let rmqServerUrl =
'MY_RMQ_SERVER_URL';
let rmqServerConn = null;
exports.handler = async event => {
console.log('websocket event:', event);
const { routeKey: route, connectionId } = event.requestContext;
switch (route) {
case '$connect':
console.log('user connected');
const creds = event.queryStringParameters.x;
console.log('============ x.length:', creds.length);
const decodedCreds = Buffer.from(creds, 'base64').toString('utf-8');
try {
const conn = await amqp.connect(
`amqps://${decodedCreds}#${rmqServerUrl}`
);
const channel = await conn.createChannel();
console.log('============ created channel successfully:');
rmqServerConn = conn;
const [userId] = decodedCreds.split(':');
const { queue } = await channel.assertQueue(userId, {
durable: true,
autoDelete: false,
});
console.log('============ userId:', userId, 'queue:', queue);
channel.consume(queue, msg => {
console.log('========== msg:', msg);
const { content } = msg;
const msgString = content.toString('utf-8');
console.log('========== msgString:', msgString);
sendMsgToApp(msgString, connectionId)
.then(res => {
console.log(
'================= sent queued message to the app, will ack, outcome:',
res
);
try {
channel.ack(msg);
} catch (e) {
console.log(
'================= error acking message:',
e
);
}
})
.catch(e => {
console.log(
'================= error sending queued message to the app, will not ack, error:',
e
);
});
});
} catch (e) {
console.log(
'=========== error initializing amqp connection',
e
);
if (rmqServerConn) {
await rmqServerConn.close();
}
const response = {
statusCode: 401,
body: JSON.stringify('failed auth!'),
};
return response;
}
break;
case '$disconnect':
console.log('user disconnected');
if (rmqServerConn) {
await rmqServerConn.close();
}
break;
case 'message':
console.log('message route');
await sendMsgToApp('test', connectionId);
break;
default:
console.log('unknown route', route);
break;
}
const response = {
statusCode: 200,
body: JSON.stringify('Hello from websocket Lambda!'),
};
return response;
};
The amqp connection is for a rabbitmq server that's provisioned by amazonmq. The problem I have is that messages published to the queue either do not show up at all in the .consume callback, or they only show up after the websocket is disconnected and reconnected. Essentially they're missing until a point much later after which they show up unexpectedly. That's within the websocket. Even when they do show up, they don't get sent to the client (app in this case) that's connected to the websocket. What could be the problem here?
The problem here is that I had the wrong idea about how API Gateway's websockets work. API gateway maintains the websocket connection but not the lambda itself. I put my .consume subscription logic inside the lambda, which doesn't work because the lambda runs and terminates instead of being kept alive. A better method would be to make the queue an event source for the lambda. However this also didn't work for me because it requires you to know your queues when setting up the lambda. My queues are dynamically created so that violated the requirement. I ended up standing up a rmq server on a vps.

Azure Event Grid Creating subscription : "Does not have authorization to perform action"

I am currently using node js to publish topics to Event Grid, and subscribe to topics through Event Grid. Using the event grid API on https://learn.microsoft.com/en-us/rest/api/eventgrid/ I get an error where I do not have authorization to perform action when creating a subscription. I have created a topic and have access permission to access my Azure account therefore I am confused why I get this rest error.
My code:
const { ClientSecretCredential } = require("#azure/identity");
const { SystemTopicEventSubscriptions, EventGridManagementClientContext, DomainTopics, EventSubscriptions } = require("#azure/arm-eventgrid");
const subscriptionId = "idea number";
const resourceGroupName = "eventgrid-dev";
const domainName = "test-domain";
let tenantId = "idea number";
let clientSecret = "idea number";
let clientId = "idea number";
const firstCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
//const client = new EventGridManagementClient(firstCredential, subscriptionId);
const clientContext = new EventGridManagementClientContext(firstCredential, subscriptionId);
// Topics
let domainTopics = new DomainTopics(clientContext);
domainTopics.beginCreateOrUpdate(resourceGroupName, domainName, "test-topic")
.then(result => {
console.log("result");
console.log(result);
})
.catch(error => {
console.log("Error");
console.log(error);
})
let subscription = new EventSubscriptions(clientContext);
subscription.beginCreateOrUpdate("/subscriptions/subscriptionId/resourceGroups/eventgrid-dev", "test-subscription",{topic: "test-topic"})
.then(result => {
console.log("result");
console.log(result);
})
.catch(error => {
console.log("Error");
console.log(error);
})
Output:
Error
RestError: The client 'subscriptionID' with object id 'subscriptionID' does not have authorization to perform action 'Microsoft.EventGrid/eventSubscriptions/Microsoft.EventGrid/test-subscription/write' over scope '/subscriptions/subscriptionID/resourceGroups/eventgrid-dev/providers/Microsoft.EventGrid/eventSubscriptions/providers/Microsoft.EventGrid/eventSubscriptions' or the scope is invalid. If access was recently granted, please refresh your credentials.
Thank you for the help!
In the case of existing an event grid domain, use the following code for creating an event grid subscription on the requested topic. Note, that the topic is created automatically during its first subscription:
let subscription = new EventSubscriptions(clientContext);
const scope = '/subscriptions/' + subscriptionId + '/resourceGroups/' + resourceGroupName + '/providers/Microsoft.EventGrid/domains/' + domainName + '/topics/test-topic';
const test_webhookEndpointUrl = ' ... ';
subscription.beginCreateOrUpdate(scope, "test-subscription",
{
destination: {
endpointType: "WebHook",
endpointUrl: test_webhookEndpointUrl
}
}
).then(result => {
console.log("result");
console.log(result);
})
.catch(error => {
console.log("Error");
console.log(error);
})

ECONNREFUSED 127.0.0.1:5432 RDS, Postgres

I've been stuck on this error for quite a long time, and am reaching out to see if anyone knows what to do!
I'm making an endpoint using Lambda that I want to, when hit, first insert a contract into a postgres db running on RDS and then insert the contents of a message into the same database (and send an email using SES but I figured that part out already). What I want to do, is pass a new postgres pool into the send message function down below, but every time that I do, and try to reach the database I get a Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16). This is when I run serverless offline. The initial SQL query runs but the second one doesn't.
I would really appreciate any guidance, I've pasted the relevant code snippets below. This is my first time doing anything with JavaScript, so this might be a very dumb question
contracts.js
const db = require('../db_connect');
const messages = require('./messages');
//POST endpoint to create a generic contract, it's worth keeping in mind that whenever we create a contract, it will always default to false for field isFinished
module.exports.createContract = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const reqBody = JSON.parse(event.body);
const influencerID = reqBody.influencerID;
const buyerID = reqBody.buyerID;
const monetaryValue = reqBody.monetaryValue;
const charityID = reqBody.charityID;
db.query('INSERT INTO contracts(influencer_id, buyer_id, monetary_value, charity_id, is_finished) VALUES($1, $2, $3, $4, false)', [influencerID, buyerID, monetaryValue, charityID])
.then(res => {
callback(null, {
statusCode: 200,
body: 'successfully inserted contract'
})
messages.sendMessage(db, reqBody, buyerID, influencerID)
})
.catch(e => {
console.log(e);
callback(null, {
statusCode: e.statusCode || 500,
body: 'Error:' + e
});
});
};
messages.js
var dotenv = require('dotenv').config();
var aws = require('aws-sdk')
const db = require('../db_connect');
function sendMessage(reqBody, senderID, receiverID) {
const messageBody = reqBody.messageBody;
const timestamp = Date.now();
var receiverEmail;
db.query("SELECT e_mail FROM users WHERE user_id = $1", [receiverID])
.then(res => {
console.log(res)
receiverEmail = res.rows[0]
console.log("this is the new email --> ", receiverEmail)
})
.catch(e =>{
throw console.error(e);
})
}

How should a botframework webchat conversation be maintained for over an hour?

I have looked through the documentation for botframework-webchat and have not been able to find any documentation on how conversations over 1 hour should be handled properly. This situation is most likely to occur if a web page is left idle in the background for an extended period of time.
The directline connection is maintained as long as the webchat remains active on a web page. The problem occurs after a page refresh.
The initial short term solution is to store the relevant conversation information in session storage, such as a token. The problem is that the token for the conversation is refreshed every 15 minutes. The refreshed token must be retrieved in order to maintain the conversation upon a page refresh.
I am sure a hacky work around exists for retrieving the refreshed token from the directline client object using an event callback.
Ideally, I am looking for a clean framework designed approach for handling this situation.
Though a working solution is better than no solution.
Relevant Link:
https://github.com/microsoft/BotFramework-WebChat
Thanks.
You can achieve this by implementing cookies in your client side. you can set cookies expiration time to 60 min and you can use watermark to make your chat persistent for one hour.
Passing cookie to and from Bot Service.
You can achieve this by setting up a "token" server. In the example below, I run this locally when I am developing/testing my bot.
You can use whatever package you want, however I landed on "restify" because I include it in the index.js file of my bot. I simply create a new server, separate from the bot's server, and assign it a port of it's own. Then, when I run the bot it runs automatically, as well. Put your appIds, appPasswords, and secrets in a .env file.
Then, in your web page that's hosting your bot, simply call the endpoint to fetch a token. You'll also notice that the code checks if a token already exists. If so, then it set's an interval with a timer for refreshing the token. The interval, at 1500000 ms, is set to run before the token would otherwise expire (1800000 ms). As such, the token is always getting refreshed. (Just popped in my head: may be smart to log the time remaining and the amount of time that passed, if the user navigated away, in order to set the interval to an accurate number so it refreshes when it should. Otherwise, the interval will reset with the expiration time being something much less.)
Also, I included some commented out code. This is if you want your conversations to persist beyond page refreshes or the user navigating away and returning. This way current conversations aren't lost and the token remains live. May not be necessary depending on your needs, but works well with the above.
Hope of help!
Token Server
/**
* Creates token server
*/
const path = require('path');
const restify = require('restify');
const request = require('request');
const bodyParser = require('body-parser');
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
const corsToken = corsMiddleware({
origins: [ '*' ]
});
// Create HTTP server.
let server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
server.use(bodyParser.json({
extended: false
}));
server.listen(process.env.port || process.env.PORT || 3500, function() {
console.log(`\n${ server.name } listening to ${ server.url }.`);
});
// Listen for incoming requests.
server.post('/directline/token', (req, res) => {
// userId must start with `dl_`
const userId = (req.body && req.body.id) ? req.body.id : `dl_${ Date.now() + Math.random().toString(36) }`;
const options = {
method: 'POST',
uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
headers: {
'Authorization': `Bearer ${ process.env.directLineSecret }`
},
json: {
user: {
ID: userId
}
}
};
request.post(options, (error, response, body) => {
// response.statusCode = 400;
if (!error && response.statusCode < 300) {
res.send(body);
console.log('Someone requested a token...');
} else if (response.statusCode === 400) {
res.send(400);
} else {
res.status(500);
res.send('Call to retrieve token from DirectLine failed');
}
});
});
// Listen for incoming requests.
server.post('/directline/refresh', (req, res) => {
// userId must start with `dl_`
const userId = (req.body && req.body.id) ? req.body.id : `dl_${ Date.now() + Math.random().toString(36) }`;
const options = {
method: 'POST',
uri: 'https://directline.botframework.com/v3/directline/tokens/refresh',
headers: {
'Authorization': `Bearer ${ req.body.token }`,
'Content-Type': 'application/json'
},
json: {
user: {
ID: userId
}
}
};
request.post(options, (error, response, body) => {
if (!error && response.statusCode < 300) {
res.send(body);
console.log('Someone refreshed a token...');
} else {
res.status(500);
res.send('Call to retrieve token from DirectLine failed');
}
});
});
webchat.html
<script>
(async function () {
let { token, conversationId } = sessionStorage;
[...]
if ( !token || errorCode === "TokenExpired" ) {
let res = await fetch( 'http://localhost:3500/directline/token', { method: 'POST' } );
const { token: directLineToken, conversationId, error } = await res.json();
// sessionStorage[ 'token' ] = directLineToken;
// sessionStorage[ 'conversationId' ] = conversationId;
token = directLineToken;
}
if (token) {
await setInterval(async () => {
let res = await fetch( 'http://localhost:3500/directline/refresh', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify( { token: token } )
} );
const { token: directLineToken, conversationId } = await res.json();
// sessionStorage[ 'token' ] = directLineToken;
// sessionStorage[ 'conversationId' ] = conversationId;
token = directLineToken;
}, 1500000)
}
// if ( conversationId ) {
// let res = await fetch( `https://webchat.botframework.com/v3/directline/conversations/${ conversationId }`, {
// method: 'GET',
// headers: {
// 'Authorization': `Bearer ${ token }`,
// 'Content-Type': 'application/json'
// },
// } );
// const { conversationId: conversation_Id, error } = await res.json();
// if(error) {
// console.log(error.code)
// errorCode = error.code;
// }
// conversationId = conversation_Id;
// }
[...]
window.ReactDOM.render(
<ReactWebChat
directLine={ window.WebChat.createDirectLine({ token });
/>
),
document.getElementById( 'webchat' );
});
</script>
The solution involved storing the conversation id in session storage instead of the token. Upon a page refresh a new token will be retrieved.
https://github.com/microsoft/BotFramework-WebChat/issues/2899
https://github.com/microsoft/BotFramework-WebChat/issues/2396#issuecomment-530931579
This solution works but it is not optimal. A better solution would be to retrieve the active token in the directline object and store it in session storage. The problem is that a way to cleanly way to retrieve a refreshed token from a directline object does not exist at this point.

Getting error 11200 on every sms message that posts to slack

im trying to send sms message to slack, i have it where the message is posted. the problem im having is that the twilio console gives a 11200 error on every message.
/**
* Dependencies:
* Dotenv, Express, BodyParser, Slack Web Client, Slack Events API
*/
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const createSlackEventAdapter = require('#slack/events-api').createSlackEventAdapter;
//a new export, ErrorCode, is a dictionary of known error types
const { WebClient } = require('#slack/client');
const twilio = require('twilio');
const firebase = require('firebase');
// Creates our express app
const app = express();
// The channel we'll send TalkBot messages to
const channel = 'CBY5883L3';
// The port we'll be using for our Express server
const PORT = 3000;
// Use BodyParser for app
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
/**
* Tokens:
* Slack, Firebase, Twilio
*/
//Retrieve bot token from dotenv file
const bot_token = process.env.SLACK_BOT_TOKEN || '';
// Authorization token
const auth_token = process.env.SLACK_AUTH_TOKEN || '';
// Verification token for Events Adapter
const slackEvents = createSlackEventAdapter(process.env.SLACK_VERIFICATION_TOKEN);
//Slack web client
const web = new WebClient(auth_token);
const bot = new WebClient(bot_token);
//Twilio tokens
const twilio_sid = process.env.TWILIO_SID || '';
const twilio_auth = process.env.TWILIO_AUTH_TOKEN || '';
// Initialize Twilio client using our Twilio SID and Authorization token
const twilioClient = twilio(twilio_sid, twilio_auth);
app.listen(PORT, function (err) {
if (err) {
throw err
}
console.log('Server started on port 3000')
})
// Handles incoming SMS to Twilio number
app.post('/sms', function (req, res) {
const body = req.body.Body
const num = req.body.From
// Sends message to Slack - in format from {
// `res` contains information about the posted message
console.log('Message sent: ', res.ts);
})
.catch(console.error);
}
You get this error
Error - 11200 HTTP retrieval failure
because Twilio expects a response as it makes the POST request to your /sms endpoint.
The response needs to be a valid TwiML (XML).
Change your code:
// Handles incoming SMS to Twilio number
app.post('/sms', function (req, res) {
const body = req.body.Body
const num = req.body.From
// Sends message to Slack - in format from {
// `res` contains information about the posted message
console.log('Message sent: ', res.ts);
})
.catch(console.error);
}
to this:
// Handles incoming SMS to Twilio number
app.post('/sms', function (req, res) {
const body = req.body.Body
const num = req.body.From
// Sends message to Slack - in format from {
// `res` contains information about the posted message
const twiml = new twilio.twiml.MessagingResponse();
twiml.message('Your SMS was forwarded to Slack...');
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(twiml.toString());
});
If don't want to respond to the sender then you just comment out this line
// twiml.message('Your SMS was forwarded to Slack...');
I hope this helps.

Resources