node-soap - Proper method of calling function - node.js

I know absolutely nothing about SOAP lol, But a vital part of my software requires I use it for a particular webservice. The documentation for the webservice was written for .net so it makes it even harder for me to understand what I need to do here. On top of all that they require authentication.
For the connecting I do not need to authorize so I am able to retreive the describe function result. They are as follows:
I20151214-09:20:20.381(-8)? Getting inside soap client creation method
I20151214-09:20:20.722(-8)? Exception while invoking method 'createSoapClient' TypeError: Cannot call method 'describe' of undefined
I20151214-09:20:20.723(-8)? at Object.Soap.createClient (packages/zardak_soap/packages/zardak_soap.js:37:1)
I20151214-09:20:20.724(-8)? at [object Object].Meteor.methods.createSoapClient (controllers/server/testFiles.js:21:1)
I20151214-09:20:20.724(-8)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20151214-09:20:20.725(-8)? at livedata_server.js:708:19
I20151214-09:20:20.725(-8)? at [object Object]._.extend.withValue (packages/meteor/packages/meteor.js:1013:1)
I20151214-09:20:20.726(-8)? at livedata_server.js:706:40
I20151214-09:20:20.726(-8)? at [object Object]._.extend.withValue (packages/meteor/packages/meteor.js:1013:1)
I20151214-09:20:20.726(-8)? at livedata_server.js:704:46
I20151214-09:20:20.727(-8)? at tryCallTwo (C:\Users\Media Center\AppData\Local\.meteor\packages\promise\0.5.1\npm\node_modules\meteor-promise\node_modules\promise\lib\core.js:45:5)
I20151214-09:20:20.727(-8)? at doResolve (C:\Users\Media Center\AppData\Local\.meteor\packages\promise\0.5.1\npm\node_modules\meteor-promise\node_modules\promise\lib\core.js:171:13)
I20151214-09:20:21.996(-8)? Getting inside the return of the create client
I20151214-09:20:22.007(-8)? { PRIMEStandardV1_1:
I20151214-09:20:22.008(-8)? { PRIMEStandardV1_1Soap:
I20151214-09:20:22.009(-8)? { RunTrip: [Object],
I20151214-09:20:22.009(-8)? ReverseGeocode: [Object],
I20151214-09:20:22.010(-8)? FindLocationsInRadius: [Object],
I20151214-09:20:22.010(-8)? FindLocationsOnRoute: [Object],
I20151214-09:20:22.010(-8)? FindLocationsInState: [Object],
I20151214-09:20:22.011(-8)? GetAverageDieselPriceInState: [Object],
I20151214-09:20:22.012(-8)? TestRadiusGeofence: [Object],
I20151214-09:20:22.012(-8)? TestRouteGeofence: [Object],
I20151214-09:20:22.013(-8)? RunSimpleTrip: [Object],
I20151214-09:20:22.013(-8)? Geocode: [Object],
I20151214-09:20:22.014(-8)? GetTodaysUSDieselAverage: [Object],
I20151214-09:20:22.014(-8)? GetTodaysCanadianDieselAverage: [Object],
I20151214-09:20:22.015(-8)? GetTripDistance: [Object],
I20151214-09:20:22.016(-8)? ValidateLocation: [Object] },
I20151214-09:20:22.017(-8)? PRIMEStandardV1_1Soap12:
I20151214-09:20:22.017(-8)? { RunTrip: [Object],
I20151214-09:20:22.018(-8)? ReverseGeocode: [Object],
I20151214-09:20:22.019(-8)? FindLocationsInRadius: [Object],
I20151214-09:20:22.021(-8)? FindLocationsOnRoute: [Object],
I20151214-09:20:22.021(-8)? FindLocationsInState: [Object],
I20151214-09:20:22.022(-8)? GetAverageDieselPriceInState: [Object],
I20151214-09:20:22.022(-8)? TestRadiusGeofence: [Object],
I20151214-09:20:22.023(-8)? TestRouteGeofence: [Object],
I20151214-09:20:22.023(-8)? RunSimpleTrip: [Object],
I20151214-09:20:22.024(-8)? Geocode: [Object],
I20151214-09:20:22.025(-8)? GetTodaysUSDieselAverage: [Object],
I20151214-09:20:22.025(-8)? GetTodaysCanadianDieselAverage: [Object],
I20151214-09:20:22.026(-8)? GetTripDistance: [Object],
I20151214-09:20:22.026(-8)? ValidateLocation: [Object] } } }
caseless:
I20151216-11:53:14.658(-8)? { dict:
I20151216-11:53:14.658(-8)? { 'cache-control': 'private',
I20151216-11:53:14.659(-8)? 'content-type': 'text/xml; charset=utf- 8',
I20151216-11:53:14.659(-8)? server: 'Microsoft-IIS/7.0',
I20151216-11:53:14.660(-8)? 'x-aspnet-version': '4.0.30319',
I20151216-11:53:14.660(-8)? 'x-powered-by': 'ASP.NET',
I20151216-11:53:14.661(-8)? date: 'Wed, 16 Dec 2015 19:40:29 GMT',
I20151216-11:53:14.661(-8)? connection: 'close',
I20151216-11:53:14.662(-8)? 'content-length': '441' } },
I20151216-11:53:14.662(-8)? pipe: [Function],
I20151216-11:53:14.663(-8)? addListener: [Function: addListener],
I20151216-11:53:14.664(-8)? on: [Function: addListener],
I20151216-11:53:14.665(-8)? pause: [Function],
I20151216-11:53:14.665(-8)? resume: [Function],
I20151216-11:53:14.666(-8)? read: [Function],
I20151216-11:53:14.666(-8)? body: 'soap:ServerServer was unable to process request. ---> Object reference not set to an instance of an object.' }
I20151216-11:53:16.716(-8)? Error: [object Object]
I20151216-11:53:16.722(-8)? { Envelope: { Body: { Fault: [Object] } } }
I20151216-11:53:16.723(-8)? undefined
As you can see I am able to connect. Now the part that is trowing me off is to actually call one of these functions. Below is the code I am using to try to call the "RunSimpleTrip". However when I console log the Result it is a huge jumble of messages that end up running the buffer out on my cmd window and I can only see back a little ways none of it making sense.
var url = 'http://prime.promiles.com/Webservices/v1_1/PRIMEStandardV1_1.asmx?wsdl';
var simpleTrip = {
AvoidTollRoads: false,
BorderOpen: true,
RoutingMethod: "PRACTICAL",
TripLegs: [{LocationText: "77611"},
{LocationText: "90210"}]
}
Soap.createClient(url, function(err, client) {
console.log(client.describe());
client.setSecurity(new Soap.BasicAuthSecurity('hoperd', 'mailaaron', 'bkkyt'));
client.PRIMEStandardV1_1.PRIMEStandardV1_1Soap.RunSimpleTrip(simpleTrip, function(err, result, raw, soapHeader) {
//console.log("Result: ");
console.log(result);
console.log("Error: " + err.root);
console.log(err.root);
console.log(soapHeader);
// result is a javascript object
// raw is the raw response
// soapHeader is the response soap header as a javascript object
})
});
From the API's documentation this is how they call the same function using .net
PRIMEEnterpriseV1 PRIME = new PRIMEEnterpriseV1();
//Authorization Credentials
Credentials c = new Credentials();
c.Username = "MyUsername;
c.Password = "MyPassword";
c.CompanyCode ="MyCompanyCode";
SimpleTrip st = new SimpleTrip();
st.AvoidTollRoads = false;
st.BorderOpen = true;
st.RoutingMethod = com.promiles.PRIME.Enterprise.RouteMethod.PRACTICAL;
TripLeg[] Legs = new TripLeg[2];
//Origin
TripLeg t = new TripLeg();
t.LocationText = "77611";
Legs[0] = t;
//Destination
t = new TripLeg();
t.LocationText = "90210";
Legs[1] = t;
st.TripLegs = Legs;
//Call Function
SimpleTrip rt = PRIME.RunSimpleTrip(c, st);
I am hoping someone our there has a clue to this mystery for me or can point me in the right direction as to how to properly connect this this. Any and all help will be greatly appreciated.

So after much trial and error I was able to figure this out. The below code works to call the SimpleTrip and return a proper response from the server. My TripLegs arg still isn't 100% correct to what the SOAP is looking for but the code and the way to call it is.
var url = 'http://prime.promiles.com/Webservices/v1_1/PRIMEStandardV1_1.asmx?wsdl';
var credentials = { Username: "xxxxx",
Password: "xxxxxx",
CompanyCode: "xxxxx"
};
var simpleTrip = {
AvoidTollRoads: false,
BorderOpen: true,
RoutingMethod: "PRACTICAL",
VehicleType: "Tractor2AxleTrailer2Axle",
TripLegs: [{Location: {LocationText: "77611"}},
{Location: {LocationText: "90210"}}]
}
args = {c: credentials, BasicTrip: simpleTrip};
Soap.createClient(url, function(err, client) {
console.log(err);
console.log(simpleTrip);
client.RunSimpleTrip(args, function(err, result, raw, soapHeader) {
console.log(result);
//console.log(err.root);
console.log(err.root.Envelope);
})
});

Related

Upload image with twitter lite

I'm using twitter-lite library and I want to twit an image with text.
I'm able to twit only text, but My goal is twit with text and image.
At the moment I'm trying to use a static image like:
const fs = require("fs")
const imageData = fs.readFileSync("./public/images/watermark_update_idea.png")
const mediaUploadResponse = await client.post('statuses/upload', {
media:imageData,
}).catch(err => {
console.error(err);
});
But I get that error:
{
_headers: Headers {
[Symbol(map)]: [Object: null prototype] {
'cache-control': [Array],
connection: [Array],
'content-encoding': [Array],
'content-length': [Array],
'content-type': [Array],
date: [Array],
server: [Array],
'set-cookie': [Array],
'strict-transport-security': [Array],
'x-connection-hash': [Array],
'x-response-time': [Array],
'x-tsa-request-body-time': [Array]
}
},
errors: [ { message: 'Sorry, that page does not exist', code: 34 } ]
}
My main goal is to twit with buffer, But I get the same error.
I tried to replicate this test but without lucky.
Potentially two issues here:
Use different subdomains for uploading an image and for posting a tweet:
const Twitter = require("twitter-lite");
const client = Twitter({/* auth data */});
const upload = Twitter({/* auth data */, subdomain: "upload"});
You have to convert your image content to a base64 string:
const imageData = fs.readFileSync("./public/images/watermark_update_idea.png");
const { media_id_string } = await upload.post('media/upload', {
media: imageData.toString("base64")
});

How to parse a json file with nodejs

I got a little problem with the nodejs fetch module and more particularly with the JSON parse. When I want to parse the stock variable, he tells me that the size is equal to 0 ? But my file is not empty and the path is good.
The code is really simple but I don't know why this error append and I spend too much time on this.
Someone know why I get this error and how I can resolve it ?
here the code of my js file :
const fetch = require('node-fetch');
const keyword='test';
const url='http://localhost:8888/test.json';
fetch(url).then((stock) => {
console.log(stock);
const jsonFile = JSON.parse(stock);
const newCategory = jsonFile[test];
console.log(newCategory);
}).catch((e)=>{console.log(e)});
And the error in my terminal with the first console.log() :
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]:
{ body:
PassThrough {
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: true,
_transformState: [Object] },
disturbed: false,
error: null },
[Symbol(Response internals)]:
{ url: 'http://localhost:8888/test.json',
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object] },
counter: 0 } }
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
at fetch.then (/Users/me/Desktop/test_json/index.js:11:30)
at process._tickCallback (internal/process/next_tick.js:68:7)
The fetch api returns a Body object
you can call Body.json()
Using async/await:
const body = await fetch(url);
const json = await body.json();
console.log(json);
Using promises:
fetch(url).then((stock) => {
return stock.json()
}).then(json => {
console.log(json);
});
JSON.parse:
fetch(url).then((stock) => {
return stock.text()
}).then(text => {
console.log(JSON.parse(text));
});
You need to pass the body in json parse like bellow,
JSON.parse(stock.text())
Or you can directly use json data without parsing just using stock.json() function

Get the correct result while executing a find query on mongodb using node

So I am trying to run a nodejs script to make some custom action on a mongo database. The problem I am facing is with the following script -
// a valid id obtained before
collection.find({"id":id}, function(err, result) {
if(err) {
console.log("Could not select");
} else {
console.log("Select successful for id: " + id);
console.log(result);
}
});
Now when I check the result after running this, I only see data about the db, a whole lot of it that is not really concerned with the select query. What I want is what anyone would expect! A list of the documents for that id. Obviously, I am missing something here, could anyone please point me to it?
EDIT:
So when I run the query on the mongo shell, I get the expected result.
db.messages.findOne({"id":"<a random id that has a json inserted in mongo>"})
However, when I run it from the script shown above, all I get is this:
Select successful for id: <random uid from above>
{ db:
{ domain: null,
_events: {},
_maxListeners: 10,
databaseName: 'test',
serverConfig:
{ domain: null,
_events: [Object],
_maxListeners: 10,
_callBackStore: [Object],
_commandsStore: [Object],
auth: [Object],
_dbStore: [Object],
options: [Object],
_serverState: 'connected',
_haProcess: [Object],
servers: [Object],
strategyInstance: [Object],
emitOpen: false,
.....
.....
.....
Thanks
The result parameter that find provides to the callback is a cursor, not an array of results. Call toArray to iterate over the resulting cursor and get an array of docs:
collection.find({"id":id}).toArray(function(err, result) {
if(err) {
console.log("Could not select");
} else {
console.log("Select successful for id: " + id);
console.log(result);
}
});
Or if id uniquely identifies a single doc, use findOne instead:
collection.findOne({"id":id}, function(err, result) {
if(err) {
console.log("Could not select");
} else {
console.log("Select successful for id: " + id);
console.log(result);
}
});

Connected clients in express.io

I'm developing a simple chat app using node.js and express.io
I would like to display a list of the connected clients (or online for chat) all the time.
In express.io's doc, there is no clear way on how to "get" the list of connected clients once a new one has entered the room, i.e there is just the "broadcast" but not the "get".
Have someone done this before?
Any clues will be really helpful.
Thanks!
Edit:
After trying #jibsales's answer. I think we are almost there. What clients returns me is not the actual array of clients but this one:
[ { id: 'OWix3sqoFZAa20NLk304',
namespace:
{ manager: [Object],
name: '',
sockets: [Object],
auth: false,
flags: [Object],
_events: [Object] },
manager:
{ server: [Object],
namespaces: [Object],
sockets: [Object],
_events: [Object],
settings: [Object],
handshaken: [Object],
connected: [Object],
open: [Object],
closed: [Object],
rooms: [Object],
roomClients: [Object],
oldListeners: [Object],
sequenceNumber: 496205112,
router: [Object],
middleware: [],
route: [Function],
use: [Function],
broadcast: [Function],
room: [Function],
gc: [Object] },
disconnected: false,
ackPackets: 0,
acks: {},
flags: { endpoint: '', room: '' },
readable: true,
store: { store: [Object], id: 'OWix3sqoFZAa20NLk304', data: {} },
_events:
{ error: [Function],
ready: [Function],
connection: [Function],
NewChatPrivateLine: [Function],
NewIdea: [Function],
NewChatLine: [Function],
NewPost: [Function] } } ]
The functions are:
var app = require('express.io')();
app.io.route('connection', function(req) {
req.io.join(req.data.room);
var clients = app.io.sockets.clients(req.data.room);
console.log(clients)
app.io.room(req.data.room).broadcast('announce', {
user: req.data.user,
clients: clients
})
});
This actually returns an error ( data = JSON.stringify(ev); TypeError: Converting circular structure to JSON) as the array has several circular objects and hence it cannot be broadcasted.
Any thoughts?
Because express.io is simply glueing express and socket.io, don't forget to look at socket.io's documentation as well. With that said, since socket.io v0.7, we now have an API method to get this information:
var clients = io.sockets.clients('room'); // all users from room `room`
Unfortunately express.io is written in coffeescript (UGGGH!!!) so I'm having a hard time reading the source, but it looks like when you require the express.io module, the socket.io instance is hoisted up as well:
var express = require('express.io');
var clients = express.io.sockets.clients('room'); // all users from room `room`
If this doesn't work, I would ditch express.io for a manual configuration with express and socket.io because it looks like express.io has a VERY opinionated API. Its really not that hard at all as express.io is doing nothing more than creating a pretty interface/abstraction to manual configuration (which is actually hurting you in this use case if the above doesn't work).
I would also checkout SockJS as I (and many other websocket consumers) ditched socket.io for SockJS due to a lack of community support. Not to mention, there is a SEVERE memory leak in IE9 when falling back to xhr-polling.
Well, finally I went with the "tacking" solution proposed by #Brad. It is not the most elegant but, if you can help me improve it, It'd be awesome!!
This is the final code:
Server-side
var app = require('express.io')();
//To broadcast the users online in room sent by the client
var clients = [];
app.io.route('connect', function (req) {
req.io.leave(req.data.room).on('disconnect', function() {
//To remove client from list when disconnected
var index = clients.indexOf(req.data.user);
if (index > -1) {
clients.splice(index, 1);
}
app.io.room(req.data.room).broadcast('announce', {
user: req.data.user,
clients: clients
})
});
req.io.join(req.data.room);
//To avoid repeating the same client with several opened windows/tabs
var index = clients.indexOf(req.data.user);
if (index === -1) {
clients.push(req.data.user);
}
app.io.room(req.data.room).broadcast('announce', {
user: req.data.user,
clients: clients
})
});
Client-side
// Emit ready event with person name and predefined room for who's online
io.emit('connect', {
room: room,
user: user
});
//Get the signal from server and create your list
io.on('announce', function (data){
//Do awesome stuff with data
});

ExpressJS res.render() error (JSON.stringify can't work on circular reference)

What's wrong here?
res.render('/somepage', {user:req.session.user})
It leads to Converting circular structure to JSON errors, (results in session element that has a circular user reference.)
exports.home = function (req, res) {
var entityFactory = new require('../lib/entity-factory.js').EntityFactory();
entityFactory.get_job_task_lists({
callback : function (err, job_task_lists) {
res.render('home.jade', {
locals:{
title: 'Logged in.',
user:req.session.user, // does not work
job_task_lists:job_task_lists || []
}
});
}
});
};
I added some logging in node_modules/express/node_modules/connect/lib/middleware/session/memory.js
MemoryStore.prototype.set = function(sid, sess, fn){
var self = this;
process.nextTick(function(){
console.log(sess); //this is giving the output listed
self.sessions[sid] = JSON.stringify(sess);
...
This is what I expect the session to look like, in terms of structure:
{ lastAccess: 1330979534026,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 06 Mar 2012 00:32:14 GMT,
originalMaxAge: 14399999 },
user: // this is the object I added to the session
{ id: 1,
username: 'admin',
password: '8e3f8d3a98481a9073d2ab69f93ce73b',
creation_date: Mon, 05 Mar 2012 18:08:55 GMT } }
But here's what I find:
{ lastAccess: 1330979534079, // new session
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 06 Mar 2012 00:32:14 GMT,
originalMaxAge: 14399999 },
user: // but here it is again, except now it's a mashup,
// containing members it shouldn't have, like locals,
// and, well, everything but the first 4 properties
{ id: 1,
username: 'admin',
password: '8e3f8d3a98481a9073d2ab69f93ce73b',
creation_date: '2012-03-05T18:08:55.701Z',
locals:
{ title: 'Logged in.',
user: [Circular], //and now it's circular
job_task_lists: [Object] },
title: 'Logged in.',
user: [Circular],
job_task_lists: [ [Object], [Object], [Object], getById: [Function] ],
attempts: [ '/home/dan/development/aqp/views/home.jade' ],
scope: {},
parentView: undefined,
root: '/home/dan/development/aqp/views',
defaultEngine: 'jade',
settings:
{ env: 'development',
hints: true,
views: '/home/dan/development/aqp/views',
'view engine': 'jade' },
app:
{ stack: [Object],
connections: 6,
allowHalfOpen: true,
_handle: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: [Object],
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true },
partial: [Function],
hint: true,
filename: '/home/dan/development/aqp/views/home.jade',
layout: false,
isPartial: true } }
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Converting circular structure to JSON
at Object.stringify (native)
at Array.0 (/home/dan/development/aqp/node_modules/express/node_modules/connect/lib/middleware/session/memory.js:77:31)
at EventEmitter._tickCallback (node.js:192:40)
See how the user object is nested?
Note that this time I did not send values in explicitly with 'locals' but it ended up in one (thats the source of the circular reference.
It looks like the session is being used to transfer objects to the view.
Here's my only middleware (it only reads from the session):
function requiresAuthentication(req, res, next){
if (req.session.user){
next();
} else {
next(new Error('Unauthorized. Please log in with a valid account.'))
}
}
and the only time I modify the req.session is in this route:
app.post('/home', function (req,res,next) {
var auth = require('./lib/authentication');
auth.authenticate_user(req.body.user, function (user) {
if (user){
req.session.user = user;
console.log('authenticated');
res.redirect(req.body.redir || '/home');
//next();
} else {
console.log('not authenticated');
res.render('logins/new.jade', {title: 'Login Failed', redir:''})
}
});
});
I don't have much else going on in my application yet, as it's still quite young. I know I'm not mangling the session anywhere myself; I checked.
I did some more testing, and it appears this is only an issue when I then try to use the local variable on a page. For instance, here is my view home.jade
div(data-role="page")
div(data-role="header")
a(href='/logout', data-icon='delete', data-ajax="false") Log out
h1= title
a(href='/account', data-icon='info', data-ajax="false") Account
!= partial('user', user)
each jtl in job_task_lists
div(id=jtl.name, class = 'draggable_item', style='border:2px solid black;')
#{jtl.name} - #{jtl.description}
a(data-icon='plus')
div(data-role="footer")
h3 footer
script(src="/javascripts/home.js")
If I comment out the user partial, it renders, else I get this Converting circular structure to JSON issue.
UPDATE
So after hooking up eclipse and the v8 debugger, I have been stepping through the code and I know where the mashup of session and user objects is occurring,
in node_modules/connect/lib/middleware/session/session.js
utils.union ends up mashing the members of the user object into the session, causing the circular reference. I'm just not sure why (admittedly probably my code)
This was a problem with session data being modified in a view.
After much digging, I found that it was a bug in the way partials are handled in 2.5.8. I submitted an issue, and subsequently a patch. (in case anyone needs this info at a future date) as npm is still serving up Express 2.5.8 AFAIK.
Thanks for your help #freakish and #Ryan

Resources