Docpad: using extendTemplateData via mongoose callback - mongodb

I'm trying to build a simple plugin to get get data from Mongo into an object over which I can iterate when rendering. The full code is in my project, but the essence of it is a failed attempt to emulate the feedr example. I know the mongoose stuff is working as the console log works, but getting the content sent to the docpad object is defeating me
class mongoPlugin extends BasePlugin
name: 'mongo'
# Fetch list of Gigs
getGigsData: (opts) ->
mongoose.connect ('mongodb://localhost/test')
db = mongoose.connection;
db.on 'error', console.error.bind(console, 'connection error:')
db.once 'open', () ->
gigsSchema = mongoose.Schema {
date : String,
location : String
}
Gigs = mongoose.model 'Gigs', gigsSchema
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
if err then console.error "db error"
else
console.dir gigs
opts["getGigsData"] = gigs
opts.templateData["getGigsData"] = gigs
return gigs
extendTemplateData: (opts) ->
opts.templateData["getGigsData"] = #getGigsData()
Using node-inspector and triggering a regeneration by editing docpad.coffee, I can see that opts has a field templateData, but it is empty, and is very different from docpad.templateData, so I am picking up the wrong object in the plugin. I can see others did a trick of placing a name in { } but I don't know what that does.
After completing the plugin code I see that my database data becomes the argument to a promise, so perhaps that's where it is supposed to be reintegrated with the docpad.config.templateData but that does not seem to happen in practise

So the main issue here is that we have an asynchronous function getGetsData being executed inside a synchronous function, your templating engine. This simply, isn't possible, as the templating engine will go on and do its thing, while the synchronous stuff happens in the background. This is just an issue with just writing node.js/asynchronous code in general.
The fixes for this is pretty easy to do.
opts.templateData["getGigsData"] = #getGigsData() calls getGigsData without passing over the opts, so that when getGigsData tries and uses the opts, it can't, so that would throw an error. The fix for this is to do #getGigsData(opts)
opts.templateData["getGigsData"] = #getGigsData(opts) assigns the return value of #getGigsData(opts) to the template data, however, the result of this is the result of the db.once call, as that is what will be returned in that scope. When you do return gigs, that's actually the return value for the (err, gigs) -> callback on the Gigs.find call, rather than the return value for the getGigsData. It's all about scopes.
As the database stuff is asynchronous, we need to make getGigsData asynchronous. To do this, we change extendTemplateData: (opts) -> to extendTemplateData: (opts,next) -> to make it asynchronous, and change opts.templateData["getGigsData"] = #getGigsData() to simply return #getGigsData(opts,next)
Now that we have the event and call asynchronous. We now need to make the definition of getGigsData support it. So lets change getGigsData: (opts) -> to getGigsData: (opts,next) -> to take in the completion callback (next) that we defined in step 3. And what we will do, is we will call next where we have return gigs, so lets change return gigs to return next()
It should now work. But as a little bit of cleaning, we can make the error handling better by changing if err then console.error "db error" to return next(err) if err. You will need to fix up the indentation as we will need to remove the else block.
Considering all that, and with a bit more cleaning applied, you'll end up with this:
class mongoPlugin extends BasePlugin
name: 'mongo'
config:
hostname: 'mongodb://localhost/test'
# Fetch list of Gigs
getGigsData: (opts={}, next) ->
config = #getConfig()
docpad = #docpad
mongoose.connect(config.hostname)
db = mongoose.connection
db.on 'error', (err) ->
docpad.error(err) # you may want to change this to `return next(err)`
db.once 'open', ->
gigsSchema = mongoose.Schema {
date: String,
location: String
}
Gigs = mongoose.model('Gigs', gigsSchema)
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
return next(err) if err
return next(null, gigs)
# Chain
#
extendTemplateData: (opts,next) ->
#getGigsData null, (err, gigs) ->
return next(err) if err
opts.templateData.gigs = gigs
# Chain
#

Related

Flutter Future timeouts not always working correctly

Hey I need some help here for How to use timeouts in flutter correctly. First of all to explain what the main goal is:
I want to recive data from my Firebase RealTime Database but need to secure this request api call with an time out of 15 sec. So after 15 sec my timeout should throw an exception that will return to the Users frontend the alert for reasons of time out.
So I used the simple way to call timeouts on future functions:
This functions should only check if on some firebase node an ID is existing or not:
Inside this class where I have declared this functions I also have an instance which called : timeoutControl this is a class which contains a duration and some reasons for the exceptions.
Future<bool> isUserCheckedIn(String oid, String maybeCheckedInUserIdentifier, String onGateId) async {
try {
databaseReference = _firebaseDatabase.ref("Boarding").child(oid).child(onGateId);
final snapshot = await databaseReference.get().timeout(Duration(seconds: timeoutControl.durationForTimeOutInSec), onTimeout: () => timeoutControl.onEppTimeoutForTask());
if(snapshot.hasChild(maybeCheckedInUserIdentifier)) {
return true;
}
else {
return false;
}
}
catch (exception) {
return false;
}
}
The TimeOutClass where the instance timeoutControl comes from:
class CustomTimeouts {
int durationForTimeOutInSec = 15; // The seconds for how long to try until we throw an timeout exception
CustomTimeouts();
// TODO: Implement the exception reasons here later ...
onEppTimeoutForUpload() {
throw Exception("Some reason ...");
}
onEppTimeoutForTask() {
throw Exception("Some reason ...");
}
onEppTimeoutForDownload() {
throw Exception("Some reason ...");
}
}
So as you can see for example I tried to use this implementation above. This works fine ... sometimes I need to fight with un explain able things -_-. Let me try to introduce what in somecases are the problem:
Inside the frontend class make this call:
bool isUserCheckedIn = await service.isUserCheckedIn(placeIdentifier, userId, gateId);
Map<String, dynamic> data = {"gateIdActive" : isUserCheckedIn};
/*
The response here is an Custom transaction handler which contains an error or an returned param
etc. so this isn't relevant for you ...
*/
_gateService.updateGate(placeIdentifier, gateId, data).then((response) {
if(response.hasError()) {
setState(() {
EppDialog.showErrorToast(response.getErrorMessage()); // Shows an error message
isSendButtonDiabled = false; /*Reset buttons state*/
});
}
else {
// Create an gate process here ...
createGateEntrys(); // <-- If the closures update was successful we also handle some
// other data inside the RTDB for other reasons here ...
}
});
IMPORTANT to know for you guys is that I am gonna use the returned "boolean" value from this function call to update some other data which will be pushed and uploaded into another RTDB other node location for other reasons. And if this was also successful the application is going on to update some entrys also inside the RTDB -->createGateEntrys()<-- This function is called as the last one and is also marked as an async function and called with its closures context and no await statement.
The Data inside my Firebase RTDB:
"GateCheckIns" / "4mrithabdaofgnL39238nH" (The place identifier) / "NFdxcfadaies45a" (The Gate Identifier)/ "nHz2mhagadzadzgadHjoeua334" : 1 (as top of the key some users id who is checked in)
So on real devices this works always without any problems... But the case of an real device or simulator could not be the reason why I'am faceing with this problem now. Sometimes inside the Simulator this Function returns always false no matter if the currentUsers Identifier is inside the this child nodes or not. Therefore I realized the timeout is always called immediately so right after 1-2 sec because the exception was always one of these I was calling from my CustomTimeouts class and the function which throws the exception inside the .timeout(duration, onTimeout: () => ...) call. I couldn't figure it out because as I said on real devices I was not faceing with this problem.
Hope I was able to explain the problem it's a little bit complicated I know but for me is important that someone could explain me for what should I pay attention to if I am useing timeouts in this style etc.
( This is my first question here on StackOverFlow :) )

Why 'link' variable gets changed to null even after i assign it a value

private fun shareOperation(file: File) {
val uri = Uri.fromFile(file)
val storage = FirebaseStorage.getInstance()
val pdfRef = storage.reference.child("pdf/${uri.lastPathSegment}")
pdfRef.putFile(uri).addOnFailureListener { e ->
Log.e(TAG, "Couldn't share " + e.message)
}.addOnCompleteListener{
it.addOnCompleteListener {
pdfRef.downloadUrl.addOnSuccessListener { e ->
run {
link = e.toString()
Log.i(TAG,link!!) // Here i get the link to file in firebase storage
}
}
}
}
// Here link gets null
}
i was expecting somehow i can get the link to the file and can use it for sharing intent
You are performing an asynchronous call to upload the file, that is correct since any UI blocking action must be performed in background. The variable link will be null until the run code is executed in the background thread.
You need to code inside the run block whatever you want to happen when the link is available.
BTW looks weird what you are doing with the nested addOnCompleteListener, there should be an easier way to code that. You should probably spend time learning how to code with listeners and background threads.

AWS Lambda callback being blocked by open mongodb connection?

I have setup an AWS lambda to do some data saving for me to MongoDB. I'd like to reuse the connection so I dont have to create a new connection every time the lambda is invoked. But if I leave the db connection open, the callback for the Lambda handler doesnt work!
Is there something I'm doing wrong thats creating this behavior? Here is my code:
var MongoClient = require('mongodb').MongoClient
exports.handler = (event, context, callback) => {
MongoClient.connect(process.env.MONGOURL, function (err, database) {
//database.close();
callback(null, "Successful db connection")
});
}
This is caused by not setting context.callbackWaitsForEmptyEventLoop = false. If left at the default true, the callback does not cause Lambda to return the response because your database connection is keeping the event loop from being empty.
http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html

Q.defer workaround in Bluebird

I am migrating coffeeScript code from Q to Bluebird and it looks like I have been using promises all wrong, since Bluebird's documentation clearly discourages the use of Promise.defer
The simplified version of my client-server with Q is as follows:
Q = require 'q'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
deferred = Q.defer()
setTimeout () ->
deferred.resolve "bar"
, 2000
deferred.promise
handleRequest "foo"
.then (msg) ->
console.log msg
Basically I have a function with a promise that will be resolved asynchronously after 2 seconds.
When trying the same approach in Bluebird I get a TypeError saying that the Object function Promise(resolver) has no method 'then' (whole error code is at the end of this post)
Promise = require 'bluebird'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
new Promise (resolve) ->
"bar"
setTimeout () ->
Promise.resolve()
, 2000
Promise
handleRequest "foo"
.then (msg) ->
console.log msg
I don't know where I am messing it up since Bluebird's documentation for creating a new Promise seems to be just that, a function with resolve/reject functions.
I haven't been able to find any similar approach of promises creation without using promisify.
EventEmitters can do the trick but I really need to use promises in the big version.
There are some other bits of code where the same flow is used: a function where a defer is created/returned and it will be resolved/rejected at some stage.
Thank you very much in advance!!! :)
I have been struggling with this the whole morning.
Server received foo
TypeError: Object function Promise(resolver) {
if (typeof resolver !== "function") {
throw new TypeError("the promise constructor requires a resolver function");
}
if (this.constructor !== Promise) {
throw new TypeError("the promise constructor cannot be invoked directly");
}
this._bitField = 0;
this._fulfillmentHandler0 = void 0;
this._rejectionHandler0 = void 0;
this._promise0 = void 0;
this._receiver0 = void 0;
this._settledValue = void 0;
this._boundTo = void 0;
if (resolver !== INTERNAL) this._resolveFromResolver(resolver);
} has no method 'then'
Googling the error led me to this page of Bluebird's documentation.
So I understand that the async part of the code is the resolution of the promise itself, thus rewriting the code like shown below fixes this issue:
Promise = require 'bluebird'
handleRequest = (msg) ->
new Promise (resolve) ->
setTimeout () ->
resolve "bar"
, 2000
handleRequest "foo"
.then (msg) ->
console.log msg

Iced coffee script with multiple callbacks

I'm using Iced coffescript with upshot js when I am refreshing multiple data sources. The refresh method has TWo call backs one for success and one for error and I want to wait for each call to make either callback.
I can't see how to do this with idced coffescript without making an additional function. My question is - is there a more elegant way that I can defer to one of multiple callbacks?
This is the code I have currently:
refreshMe = (key, value, result) =>
value.refresh(
(success)=>
result success
,
(fail, reason, error)=>
result undefined, fail
)
#refresh = () =>
success={}
fail={}
await
for key, value of #dataSources
refreshMe key, value, defer success[key], fail[key]
This is the only way I have found to do it too. I'm using it in Backbone and wrap (for example) a model's #save function with an #icedSave:
# An IcedCoffeescript friendly version of save
icedSave: (callback) ->
#save {},
success: (model, response) -> callback(true, model, response)
error: (model, response) -> callback(false, model, response)
Here's some code I use for converting Promises .then (-> onSuccess), (-> onError) to errbacks (err, result) ->:
# You can write like this:
await value.refresh esc defer e, result
# onError - function to be called when promise rejected.
# onSuccess - function to be called when promise is fulfilled.
module.exports = esc = (onError, onSuccess) ->
util = require 'util'
return (result) ->
if util.isError result
# Always send back an error to first handler.
onError? result
else if onSuccess?
console.log onSuccess, result
# `await fn esc done, defer result`
onSuccess? result
else
# `await fn esc done`
onError? null, result
You could modify the esc function a bit to handle multiple arguments for each callback.
iced.Rendezvous lib is made explicitly for this case: return at the first of multiple callbacks. From the docs:
Here is an example that shows off the different inputs and outputs of
a Rendezvous. It does two parallel DNS lookups, and reports only when
the first returns:
hosts = [ "okcupid.com", "google.com" ];
ips = errs = []
rv = new iced.Rendezvous
for h,i in hosts
dns.resolve hosts[i], rv.id(i).defer errs[i], ips[i]
await rv.wait defer which
console.log "#{hosts[which]} -> #{ips[which]}"