I have an UI app on port 8001 and an app named contract on port 7001. I have 'cluster' installed and working. I have a subscription and insert method defined in 'contract' app.
'contract' server/app.js
Cluster.connect("mongodb://<username>:<passwd>#URL");
var options = {
endpoint: "http://localhost:7001",
balancer: "http://localhost:7001", // optional
uiService: "web" // (optional) read to the end for more info
};
Cluster.register("contracts", options);
var Contracts = new Meteor.Collection('contracts');
Meteor.methods({
addContract: addContract,
findContracts: findContracts
});
Meteor.publish("getContracts", function () {
return Contracts.find({});
});
function addContract(c){
var data = {
id: c.id,
type: c.type
};
Contracts.insert(data);
}
function findContracts(){
var contracts = Contracts.find().fetch();
return contracts;
}
I am accessing the methods from an angular controller in my UI app.
UI app server/app.js
Cluster.connect(mongodb://<username>:<passwd>#URL");
var options = {
endpoint: "http://localhost:8001",
balancer: "http://localhost:8001" // optional
//uiService: "web" // (optional) read to the end for more info
};
Cluster.register("web", options);
Cluster.allowPublicAccess("contracts");
UI app controller code
var contractConn = Cluster.discoverConnection('contracts');
contractConn.subscribe('getContracts');
var SubscribedContracts = new Mongo.Collection('SubscribedContracts', {connection: contractConn});
console.log('status', contractConn.status());
vm.contracts = SubscribedContracts.find({}).count();
contractConn.call("findContracts", function(err, result) {
if(err) {
throw err ;
}
else {
console.log(result);
}
});
This is what is happening:
* I can access methods on the contract server
* I can insert or find contracts using these methods
* My subscription is not working. fetch on the cursor shows 0 and count shows 0
* Status on the connection shows 'connecting'
What am I doing wrong with my subscription?
Sudi
I had to change the name of the client mongo collection to the same name as the name of the collection on the service.
Related
I am new to AppMaker but I have developer experience.
The application is a Project Tracker Application
What I expect to happen: When creating a project the user uses a User Picker to select the users associated with that project. When the project is created I want to email the users associated with that project.
The issue: On clicking the Add button addProject(addButton) client script function is called.
Inside this function sendEmailToAssignees(project, assignees) is called which should reach out to the Server script and run the notifyAboutProjectCreated(project, assignees) but that is not happening.
Things to know: With logging I never reach 'Trying to send email' so I seem to never reach my server script. Also, On client script when I comment out sendEmailToAssignees function everything runs smooth. I have looked at this documentation as a resource so I feel my implementation is okay. https://developers.google.com/appmaker/scripting/client#client_script_examples
The final error message I get is:
Failed due to illegal value in property: a at addProject
(AddProject:110:24) at
AddProject.Container.PanelAddProject.Form1.Spring.ButtonAdd.onClick:1:1
Am I missing something here? Any help would be greatly appreciated. Thank you!
Client Script
function sendEmailToAssignees(project, assignees) {
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(project, assignees);
}
function addProject(addButton) {
if (!addButton.root.validate()) {
return;
}
addButton.datasource.createItem(function(record) {
var page = app.pages.AddProject;
var pageWidgets = page.descendants;
var trainees = pageWidgets.AssigneesGrid.datasource.items;
var traineesEmails = trainees.map(function(trainee) {
return trainee.PrimaryEmail;
});
record.Assignee = traineesEmails.toString();
var assignees = traineesEmails.toString();
var project = record;
updateAllProjects(record);
console.log('update all projects done');
sendEmailToAssignees(project, assignees);
console.log('Send Email done');
if (app.currentPage !== app.pages.ViewProject) {
return;
}
gotoViewProjectPageByKey(record._key, true);
});
gotoViewProjectPageByParams();
}
Server Script
function notifyAboutProjectCreated(project, assignees) {
console.log('Trying to send email');
if (!project) {
return;
}
var settings = getAppSettingsRecord_()[0];
if (!settings.EnableEmailNotifications) {
return;
}
var data = {
appUrl: settings.AppUrl,
assignee: project.Assignee,
owner: project.Owner,
startDate: project.StartDate,
endDate: project.EndDate,
jobType: project.Type,
jobId: project.Id
};
// Email Subject
var subjectTemplate = HtmlService.createTemplate(settings.NotificationEmailSubjectJob);
subjectTemplate.data = data;
var subject = subjectTemplate.evaluate().getContent();
// Email Body
var emailTemplate =
HtmlService.createTemplate(settings.NotificationEmailBodyJob);
emailTemplate.data = data;
var htmlBody = emailTemplate.evaluate().getContent();
console.log('About to send email to:', assignees);
sendEmail_(null, assignees, subject, htmlBody);
}
The reason you are getting this error is because you are trying to pass the client "project record" to the server. If you need to access the project, then pass the record key to the server and then access the record on the server using the key.
CLIENT:
function sendEmailToAssignees(project, assignees) {
var projectKey = project._key;
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(projectKey , assignees);
}
SERVER:
function notifyAboutProjectCreated(projectKey, assignees) {
console.log('Trying to send email');
var project = app.models.<PROJECTSMODEL>.getRecord(projectKey);
if (!project) {
return;
}
//Rest of the logic
}
The project record object in the client is not the same as the project record object in the server; hence the ilegal property value error.
This is my first question ever here:-)
I need to list users in our Cognito use pool. Seems this can be done only using the aws-sdk CognitoIdentityServiceProvider APIs. I got the below code to work perfectly from my local node.js. It lists all users as expected.
However, the same code behaves differently when put into an AWS lambda function. It still runs, but it never waits for the Cognito listUsers() call to return. It just simply completes, like the "await" is not waiting at all. None of the console.log() is invoked from the client.listUsers(params, function(err, data)..._ block.
I tested this inside Lambda directly as well as from AWS API gateway. The same null is return. The call itself is successful, just no data is returned.
See log at the end.
BTW, I did create a role and add a policy giving the role full access to the cognito user pool.
What did I miss? Appreciate your help!
Martin C.
-----------------code------------------------
async function getUserList() {
console.log("enter LAMDA function**********");
var aws = require('aws-sdk');
aws.config.update({accessKeyId: 'xxxxxxxx', secretAccessKey: 'xxxxxxxxxxx'});
var CognitoIdentityServiceProvider = aws.CognitoIdentityServiceProvider;
var client = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: 'us-east-2' });
var params = {
UserPoolId: 'us-east-xxxxxxxx', /* required */
AttributesToGet: [
'given_name','family_name','phone_number','email','profile'
],
Filter: null,
Limit: 0,
PaginationToken: null
};
console.log("Right before call the listUser method");
let result = await client.listUsers(params, function(err, data) {
console.log("call back reached!");
if (err) {
console.log(err, err.stack); // an error occurred
const response = {
statusCode: 500,
body: JSON.stringify('An error occurred.'),
}
return response;
}
else {
console.log(data);
var count = data.Users.length;
// successful response
const response = {
statusCode: 200,
body: JSON.stringify("sucessful list users! User count="+count)
}
return response;
}
});
console.log("no waiting here. async!!!")
}
getUserList();
***************Lambda log*****************
**************Log when called from node.js****************
getUserList is your lambda function? I don't know why you call it by your self getUserList().
I see, you are using lambda runtime is nodejs version > 8, you use await keyword with a callback function(fail) => you not wait anything.
When a function call by Lambda, the function (async function) will finish when get a return or run to end of function (without return), in your case the function finish when console.log("no waiting here. async!!!") has been executed. In local environment, the funciton finishs when callstack has been clear (do not have any callback function in callstack).
Right way, you have use promise version of aws-sdk then use await syntax to get a result. Relate to How to use Async and Await with AWS SDK Javascript
async function getUserList() {
console.log("enter LAMDA function**********");
var aws = require('aws-sdk');
aws.config.update({ accessKeyId: 'xxxxxxxx', secretAccessKey: 'xxxxxxxxxxx' });
var CognitoIdentityServiceProvider = aws.CognitoIdentityServiceProvider;
var client = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: 'us-east-2' });
var params = {
UserPoolId: 'us-east-xxxxxxxx', /* required */
AttributesToGet: [
'given_name', 'family_name', 'phone_number', 'email', 'profile'
],
Filter: null,
Limit: 0,
PaginationToken: null
};
console.log("Right before call the listUser method");
try {
let result = await client.listUsers(params).promise(); // use Promise style
console.log(data);
var count = data.Users.length;
// successful response
const response = {
statusCode: 200,
body: JSON.stringify("sucessful list users! User count=" + count)
}
return response; // return to finish function
} catch (err) {
console.log(err, err.stack); // an error occurred
const response = {
statusCode: 500,
body: JSON.stringify('An error occurred.'),
}
return response;
}
}
getUserList(); // remove this line when deploy funtion to Lambda.
I have created a server side route (using iron-router). Code is as follows :
Router.route( "/apiCall/:username", function(){
var id = this.params.username;
},{ where: "server" } )
.post( function(req, res) {
// If a POST request is made, create the user's profile.
//check for legit request
console.log('post detected')
var userId = Meteor.users.findOne({username : id})._id;
})
.delete( function() {
// If a DELETE request is made, delete the user's profile.
});
This app is running on port 3000 on my local. Now I have created another dummy app running on port 5000. Frrom the dummy app, I am firing a http.post request and then listening it on the app on 3000 port. I fire the http.post request via dummy app using the below code :
apiTest : function(){
console.log('apiTest called')
HTTP.post("http://192.168.1.5:3000/apiCall/testUser", {
data: [
{
"name" : "test"
}
]
}, function (err, res) {
if(!err)
console.log("succesfully posted"); // 4
else
console.log('err',err)
});
return true;
}
But I get the following error on the callback :
err { [Error: socket hang up] code: 'ECONNRESET' }
Not able to figure out whats the problem here.
The server side route is successfully called, but the .post() method is not being entered.
Using meteor version 1.6
192.168.1.5 is my ip addr
Okay so if I use Router.map function, the issue is resolved.
Router.map(function () {
this.route("apiRoute", {path: "/apiCall/:username",
where: "server",
action: function(){
// console.log('------------------------------');
// console.log('apiRoute');
// console.log((this.params));
// console.log(this.request.body);
var id = this.params.username;
this.response.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
if (this.request.method == 'POST') {
// console.log('POST');
var user = Meteor.users.findOne({username : id});
// console.log(user)
if(!user){
return 'no user found'
}
else{
var userId = user._id;
}
}
});
});
It looks like the content type is not set the application/json. So you should do that...
Setting the "Content-Type" header in HTTP.call on client side in Meteor
I have a running multichannelapplication connceted via wcf service to a sqlserver 2012. When I stopp the service the app keep running and the data is stored in the entity manager of breeze:
(function () {
var oldClient = OData.defaultHttpClient;
var myClient = {
request: function (request, success, error) {
if (request.requestUri.indexOf("$metadata", request.requestUri.length - "$metadata".length) !== -1) {
request.headers.Accept = "application/xml";
}
return oldClient.request(request, success, error);
}
};
OData.defaultHttpClient = myClient;
breeze.config.initializeAdapterInstance("dataService", "OData", false);
var dataNS = DevExpress.data;
var manager = new breeze.EntityManager({
dataService: new breeze.DataService({
serviceName: "http://localhost:57049/DataService.svc",
hasServerMetadata: false,
adapterName: "OData"
})
});
App.db = {
tblInvoice: new dataNS.BreezeStore({
entityManager: manager,
resourceName: "tblInvoice",
autoCommit: true,
}),
when i restart the service the data should be synchronized but it doesn't do this automaticly. The Breeze api says saveChanges() to save to entity manager. How to sync the entities with the server if the service is available again?
A user saves a trip (from a city to another one) and before storing it into the mongo collection, my app have to fetch the trip distance and time from the mapquest api.
How and where would you put the HTTP.call ? Server side ? Client side ?
Install http module:
meteor add http
Create a server method to call web service. Here is my example where the user put URL and the code returns title of page.
Server code:
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Meteor.methods({
getTitle: function(url) {
var response = Meteor.http.call("GET", url);
return response;
}
});
And here is a client code:
Template.new_bookmark.events({
// add new bookmark
'keyup #add-bookmark' : function(e,t) {
if(e.which === 13)
{
var url = String(e.target.value || "");
if(url) {
Meteor.call("getTitle", url, function(err, response) {
var url_title = response.content.match(/<title[^>]*>([^<]+)<\/title>/)[1];
var timestamp = new Date().getTime();
bookmarks.insert({Name:url_title,URL:url,tags:["empty"], Timestamp: timestamp});
});
}
}
}
});
If the user press "enter" in the #add-bookmark field, I get fields value and pass it to server method. The sever method returns page HTML source and I parse it on client, get title and store it on my collection.