EmberJS global websocket connection - node.js

Im using EmberJS and im trying to get data from the backend using websocket (socket.io) so i've set this Application Route
App.ApplicationRoute = Ember.Route.extend(
setupController: (controller, data) ->
store = #get 'store'
socket = io.connect "http://localhost:4000/orders" ## Line 4
socket.on "new_order", (order) ->
store.load(App.Order, order)
socket.on "new_billing", (bill) ->
store.load(App.Bill, bill)
socket.on "connected", ->
console.log "Ready"
model: ->
return { title: "Ordenes" }
actions:
markAsDone: (type, type_id) ->
# Send value to backend
socket.emit "confirm_" + type, ## Line 16
id: type_id
# Find record by id
if type == "order"
record = App.Order.find(type_id)
transition = "orders"
else if type == "bill"
record = App.Bill.find(type_id)
transition = "bills"
# Delete from store
record.then( (r) ->
r.deleteRecord()
)
# Display list of record type
#transitionTo(transition)
)
on line 4 the connection is being set and object are being fetched when i hit "/", but after i enter a route "/orders" object are not being fetched anymore, and on line 16 in the code above, i cant use the socket variable
Uncaught ReferenceError: socket is not defined
Is there a better way to manage this ?

so the correct way to use a reusable socket is setting it inside the Store
App.Store = DS.Store.extend(
revision: 12
adapter: adapter
socket: io.connect "http://localhost:4000/orders"
)
so then i can access to it inside any part of the code using
socket = #get 'store.socket'

socket is out of scope once you've hit the markAsDone method, you can set a reference to it on the controller and retrieve it later (pardon my botched coffeescript)
App.ApplicationRoute = Ember.Route.extend(
setupController: (controller, data) ->
store = #get 'store'
socket = io.connect "http://localhost:4000/orders" ## Line 4
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
controller.set 'socket', socket
socket.on "new_order", (order) ->
store.load(App.Order, order)
socket.on "new_billing", (bill) ->
store.load(App.Bill, bill)
socket.on "connected", ->
console.log "Ready"
model: ->
return { title: "Ordenes" }
actions:
markAsDone: (type, type_id) ->
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
socket = #get 'controller.socket'
# Send value to backend
socket.emit "confirm_" + type, ## Line 16
id: type_id
# Find record by id
if type == "order"
record = App.Order.find(type_id)
transition = "orders"
else if type == "bill"
record = App.Bill.find(type_id)
transition = "bills"
# Delete from store
record.then( (r) ->
r.deleteRecord()
)
# Display list of record type
#transitionTo(transition)
)

Related

Dynamic Database name is not allowing connection for SQL Server from Nodejs

I am trying to connect to SQL Server Database by passing in the database name from the front-end. I tried two options one of the is working and another one is not. Lets say
Method 1: The below method is working:
app.post('/getDropDown/crop',async(req,res)=>{
let dropdownModel = {}
await sql.connect(
`Server=cloud.com,1433;
Database=${req.params.crop};
User Id=imuser;Password=abc;
trustServerCertificate=true`,err=>{
if (err) console.log(err)
new sql.Request().query(`
SELECT DISTINCT TBNAME AS "Experiment", TBYEAR AS "Year", TBFLD_NAME AS "Trait"
FROM dbo.EXP01 t1
JOIN dbo.EXP02 t2 ON t1.TBID = t2.TBKEXPT
JOIN dbo.TRD01 t3 ON t2.TBKTRAIT = t3.TBID`,(err,result)=>{
dropdownModel['Year']= Array.from(new Set(result.recordsets[0].map((item)=>item.Year)))
dropdownModel['Trait'] = Array.from(new Set(result.recordsets[0].map((item)=>item.Trait)))
dropdownModel['Exp'] = Array.from(new Set(result.recordsets[0].map((item)=>item.Experiment)))
res.send({"data":dropdownModel})
})
})
})
However, I am trying to separate out the connection to a different function or module so that I do not have to write the whole connection string every time.
Method 2: The below method is not working:
function createDB(dname){
let connection=
`Server=cloud.com,1433,
Database=${dname},
User Id=imuser,Password=abc,
trustServerCertificate=true`
return connection
}
app.get('/getDropDown/:crop',async(req,res)=>{
await sql.connect(createDB(`${req.params.crop}`),err=>{
if (err) console.log(err)
new sql.Request().query(`
SELECT DISTINCT TBNAME AS "Experiment", TBYEAR AS "Year", TBFLD_NAME AS "Trait"
FROM dbo.EXP01 t1
JOIN dbo.EXP02 t2 ON t1.TBID = t2.TBKEXPT
JOIN dbo.TRD01 t3 ON t2.TBKTRAIT = t3.TBID`,(err,result)=>{
console.log(result)
})
}
)
})
I referenced this answer to create Method 2, but has no luck. Any help is appreciated how to separate out the connection string from the service and use it as a function.

Redux unexpected behaviour | create empty object if not found

I am debugging an app, there is an existing redux reducer which sets some data of store object. Now when i dispatch action for this reducer before the relevant object is initialised it still works and create an empty object. This works on our deployment server and do crash on my local machine with correct error that "map is undefined on null". Why is it creating an empty object and not crashing on deployment server and if it is creating an object why is it not assigning the data we pass to it. My reducer is
case ACTIONS.SET_LOCAL_WEIGHTS: {
const { weight } = action;
const drafts = fromJS(state.getIn(['draftData', 'rows']));
const setWeight = drafts.map((row: any) => {
row.data.weight = weight[row.id].weight;
return row;
});
return state
.setIn(['draftData', 'rows'], setWeight)
.setIn(['draftData', 'total'], setWeight.length);
}
It creates: draftData: {} when rows and total is also provided. I have tried it on node 15 and 12 for checking any anomaly on map function.
I get error Cannot read property 'map' of undefined on your code if the initial state doesn't have a property state.draftData.rows. I don't see anywhere where you would be creating an empty object.
The immutable.js fromJS method will create a List if called with an array from state.draftData.rows. But if it is called with undefined then it returns undefined instead of a collection with a .map() method.
I also don't think that you need to be calling fromJS if the rows object is never converted toJS, but it might depend on your initial state.
This code should work. It uses the existing List from state if it exists, or creates an empty List otherwise.
const drafts = state.getIn(["draftData", "rows"]) ?? fromJS([]);
The assignment in row.data.weight = weight[row.id].weight seems like a mutation of state.
I tried to rewrite this, but it seems strange to me that your code doesn't do anything with the weights in the payload unless their index/key matches one that's already in the state.
import { fromJS, List, Map } from "immutable";
interface Row {
data: {
weight: number;
};
id: number;
}
const reducer = (state = Map(), action) => {
switch (action.type) {
case ACTIONS.SET_LOCAL_WEIGHTS: {
const { weight } = action;
const drafts: List<Row> =
state.getIn(["draftData", "rows"]) ?? fromJS([]);
const setWeight = drafts.reduce(
(next, row, index) =>
next.setIn([index, "data", "weight"], weight[row.id]?.weight),
drafts
);
return state
.setIn(["draftData", "rows"], setWeight)
.setIn(["draftData", "total"], setWeight.size);
}
default:
return state;
}
};

Gatling Rest API Testing - retrieve a value from json response and add it to the list, iterate through list

I am new to Gatling, I am trying to do the performance testing for couple of rest calls. In my scenario I need to extract a value from json response of the 1st call and add those values to the list after looping for few times. Again after looping for few times and adding the values into the list, I want to reuse each value in my next rest call by iterating over the values in the list. Can anyone please suggest on how to implement this. I tried something as below,
var datasetIdList = List.empty[String]
val datasetidsFeeder = datasetIdList.map(datasetId => Map("datasetId" -> datasetId)).iterator
def createData() = {
repeat(20){
feed("").exec(http("create dataset").post("/create/data").header("content-type", "application/json")
.body(StringBody("""{"name":"name"}"""))
.asJson.check(jsonPath("$.id").saveAs("userId"))))
.exec(session => { var usrid = session("userId").as[String].trim
datasetIdList:+= usrid session})
}}
def upload()= feed(datasetidsFeeder).exec(http("file upload").post("/compute-metaservice/datasets/${datasetId}/uploadFile")
.formUpload("File","./src/test/resources/data/File.csv")
.header("content-type","multipart/form-data")
.check(status is 200))
val scn = scenario("create data and upload").exec(createData()).exec(upload())
setUp(scn.inject(atOnceUsers(1))).protocols(httpConf)
}
I am seeing an exception that ListFeeder is empty when trying to run above script. Can someone please help
Updated Code:
class ParallelcallsSimulation extends Simulation{
var idNumbers = (1 to 50).iterator
val customFeeder = Iterator.continually(Map(
"name" -> ("test_gatling_"+ idNumbers.next())
))
val httpConf = http.baseUrl("http://localhost:8080")
.header("Authorization","Bearer 6a4aee03-9172-4e31-a784-39dea65e9063")
def createDatasetsAndUpload() = {
repeat(3) {
//create dataset
feed(customFeeder).exec(http("create data").post("/create/data").header("content-type", "application/json")
.body(StringBody("""{ "name": "${name}","description": "create data and upload file"}"""))
.asJson.check(jsonPath("$.id").saveAs("userId")))
.exec(session => {
val name = session("name").asOption[String]
println(name.getOrElse("COULD NOT FIND NAME"))
val userId = session("userId").as[String].trim
println("%%%%% User ID ====>"+userId)
val datasetIdList = session("datasetIdList").asOption[List[_]].getOrElse(Nil)
session.set("datasetIdList", userId :: datasetIdList)
})
}
}
// File Upload
def fileUpload() = foreach("${datasetIdList}","datasetId"){
exec(http("file upload").post("/uploadFile")
.formUpload("File","./src/test/resources/data/File.csv")
.header("content-type","multipart/form-data")
.check(status is 200))
}
def getDataSetId() = foreach("${datasetIdList}","datasetId"){
exec(http("get datasetId")
.get("/get/data/${datasetId}")
.header("content-type","application/json")
.asJson.check(jsonPath("$.dlp.dlp_job_status").optional
.saveAs("dlpJobStatus")).check(status is 200)
).exec(session => {
val datastId = session("datasetId").asOption[String]
println("request for datasetId >>>>>>>>"+datastId.getOrElse("datasetId not found"))
val jobStatus = session("dlpJobStatus").asOption[String]
println("JOB STATUS:::>>>>>>>>>>"+jobStatus.getOrElse("Dlp Job Status not Found"))
println("Time: >>>>>>"+System.currentTimeMillis())
session
}).pause(10)
}
val scn1 = scenario("create multiple datasets and upload").exec(createDatasetsAndUpload()).exec(fileUpload())
val scn2 = scenario("get datasetId").pause(100).exec(getDataSetId())
setUp(scn1.inject(atOnceUsers(1)),scn2.inject(atOnceUsers(1))).protocols(httpConf)
}
I see below error when I try to execute above script
[ERROR] i.g.c.s.LoopBlock$ - Condition evaluation crashed with message 'No attribute named 'datasetIdList' is defined', exiting loop
var datasetIdList = List.empty[String] defines a mutable variable pointing to a immutable list.
val datasetidsFeeder = datasetIdList.map(datasetId => Map("datasetId" -> datasetId)).iterator uses the immutable list. Further changes to datasetIdList is irrelevant to datasetidsFeeder.
Mutating a global variable with your virtual user is usually not a good idea.
You can save the value into the user's session instead.
In the exec block, you can write:
val userId = session("userId").as[String].trim
val datasetIdList = session("datasetIdList").asOption[List[_]].getOrElse(Nil)
session.set("datasetIdList", userId :: datasetIdList)
Then you can use foreach to iterate them all without using a feeder at all.
foreach("${datasetIdList}", "datasetId") {
exec(http("file upload")
...
}
You should put more work in your question.
Your code is not syntax-highlighted, and is formatted poorly.
You said "I am seeing an exception that ListFeeder is empty" but the words "ListFeeder" are not seen anywhere.
You should post the error message so that it's easier to see what went wrong.
In the documentation linked, there is a Warning. Quoted below:
Session instances are immutable!
Why is that so? Because Sessions are messages that are dealt with in a multi-threaded concurrent way, so immutability is the best way to deal with state without relying on synchronization and blocking.
A very common pitfall is to forget that set and setAll actually return new instances.
This is why the code in the updated question doesn't update the list.
session => {
...
session.set("datasetIdList", userId :: datasetIdList)
println("%%%% List =====>>>" + datasetIdList.toString())
session
}
The updated session is simply discarded. And the original session is returned in the anonymous function.

How to filter by string parameter, web3 2.0.0-alpha.1 Solidity events?

I'm trying to filter some events, and I noticed since I updated the web3 to version 2.0.0-alpha 1 the event catch is a little bit different.
I have a Smart Contract with this event:
event catchMeIfYouCan (address indexed a, string indexed b, uint indexed c);
And I want to filter by its parameters, so far so good.
But when I try to filter by b ( the string indexed ), this is not working.
I'm doing that in NodeJS with ExpressJS and the Web3 version mentioned above.
If I do that:
const event = smartContract.events.catchMeIfYouCan({ filter : {
a : accountAddress ,
b : web3.utils.toHex(stringValue) ,
c : web3.utils.toWei("" + numberValue) }
}, (error, event) => {
// do some things
});
I get:
Node error: {"code":-32602,"message":"invalid argument 1: hex has invalid length 96 after decoding"}
Otherwise, if I let the b parameter, in NodeJS event catch as:
b : stringValue,
It doesn't catch the event anymore , same with c ( e.g : no more web3.utils.toWei() ).
Do you have any idea how to filter the event by a string parameter in Web3 2.0.0-Alpha 1 version?
I tested it and I believe its a bug with filter
But I tried use topics and it works
contract.events.CatchMeIfYouCan({
topics: [, web3.utils.sha3(stringValue)], // first element is empty, because its place for `address` index
fromBlock: 2000000
}, (error, event) => {
console.log(event)
})
I have created an issue in the web3.js GitHub repository

GDAX api, create candle graph

I would like to create a candle graph using GDAX api. I am currently using the HTTP request for historical data https://docs.gdax.com/#get-historic-rates bug this is marked that I should use websocket API. Unfortunately I don't know how to handle historic data through Gdax websocket api https://github.com/coinbase/gdax-node. Could someone help me ?
Here are 1m candlesticks built from match channel using GDAX websocket
"use strict";
const
WebSocket = require('ws'),
PRECISION = 8
function _getPair(pair) {
return pair.split('-')
}
let ws = new WebSocket('wss://ws-feed.pro.coinbase.com')
ws.on('open', () => {
ws.send(JSON.stringify({
"type": "subscribe",
"product_ids": [
"ETH-USD",
"BTC-USD"
],
"channels": [
"matches"
]
}))
})
let candles = {}
let lastCandleMap = {}
ws.on('message', msg => {
msg = JSON.parse(msg);
if (!msg.price)
return;
if (!msg.size)
return;
// Price and volume are sent as strings by the API
msg.price = parseFloat(msg.price)
msg.size = parseFloat(msg.size)
let productId = msg.product_id;
let [base, quote] = _getPair(productId);
// Round the time to the nearest minute, Change as per your resolution
let roundedTime = Math.floor(new Date(msg.time) / 60000.0) * 60
// If the candles hashmap doesnt have this product id create an empty object for that id
if (!candles[productId]) {
candles[productId] = {}
}
// If the current product's candle at the latest rounded timestamp doesnt exist, create it
if (!candles[productId][roundedTime]) {
//Before creating a new candle, lets mark the old one as closed
let lastCandle = lastCandleMap[productId]
if (lastCandle) {
lastCandle.closed = true;
delete candles[productId][lastCandle.timestamp]
}
// Set Quote Volume to -1 as GDAX doesnt supply it
candles[productId][roundedTime] = {
timestamp: roundedTime,
open: msg.price,
high: msg.price,
low: msg.price,
close: msg.price,
baseVolume: msg.size,
quoteVolume: -1,
closed: false
}
}
// If this timestamp exists in our map for the product id, we need to update an existing candle
else {
let candle = candles[productId][roundedTime]
candle.high = msg.price > candle.high ? msg.price : candle.high
candle.low = msg.price < candle.low ? msg.price : candle.low
candle.close = msg.price
candle.baseVolume = parseFloat((candle.baseVolume + msg.size).toFixed(PRECISION))
// Set the last candle as the one we just updated
lastCandleMap[productId] = candle
}
})
What they're suggesting is to get the historic rates https://docs.gdax.com/#get-historic-rates from this endpoint, then keep your candles up to date using the Websocket feed messages - whenever a 'match'/ticker message is received, you update the last candle accordingly.
From the docs: "The maximum number of data points for a single request is 300 candles. If your selection of start/end time and granularity will result in more than 300 data points, your request will be rejected." so probably why you can't get more than 2 days worth of data.
ps. I have a live orderbook implemented here and a basic candle stick chart - lots not hooked together fully still but its at least available for preview until its complete https://github.com/robevansuk/gdax-java/

Resources