Let's start with simple NodeJS http application.
var http = require('http')
var server = new http.Server(function(req, res){
var body = []
req.on('data', function(data){
body.push(data)
})
req.on('end', function(){
res.writeHead(200, {
'x-any-header': 'x-any-value',
'content-type': 'text/plain'
})
res.end('hello, Cocaine!')
})
})
server.listen(8080)
To get our app working in Cocaine cloud, let's add just a couple of things.
#!/path/to/node
var cocaine = require('cocaine')
var http = cocaine.http // monkey-patches node's original http server
var argv = require('optimist').argv //which is actually a hash
// looking like { opt: 'value'}
var worker = new cocaine.Worker(argv)
var handle = worker.getListenHandle("http") // the handle implements a
// low-level nodejs' listening tcp socket, and it makes nodejs
// understand cocaine streams.
var server = new http.Server(...) // the same thing as above
server.listen(handle) // as per [1], start listening on cocaine handle
To let the cocaine-runtime know what to run in our app, we put manifest.json:
{ "slave":"app.js" }
Since the app.js has to be an executable, we put shebang on first line and don't forget about setting an executable bit.
See the complete app here [2].
git clone url/the_app
cd the_app
npm install
tar -czf ../the_app.tgz
cocaine-tool app upload -n the_app --package ../the_app.tgz --manifest manifest.json
>app the_app has been successfully uploaded
then,
cocaine-tool app start -n the_app -r default
>app the_app started
curl -v http://<cloud.front>/the_app/http/
>...
var cocaine = require("cocaine")
var cli = new cocaine.Client(["localhost", 10053])
var log = new cli.Logger("myprefix") // logs lines like "myprefix/..."
cli.on('error', function(err){
console.log('client error', err)
})
log.on('error', function(err){
console.log('logger error', err)
})
log.connect()
log.on("connect", function() {
cli.getServices(['geobase'], function(err, geo, ua){
var names
log.info("looking up regionId for ip 1.2.3.4")
geo.region_id("1.2.3.4", function(err, regionId) {
if(err) return _handleError(err)
log.debug("found region %d for %s", regionId, "1.2.3.4")
geo.names(regionId, function(err, names){
if(err) return _handleError(err)
log.debug("names for region %d are %s", regionId, names.join())
geo.coordinates(regionId, function(coords){
if(err) return _handleError(err)
log.debug('coordinates for region %d are %s', regionId, coords.join())
})
})
})
})
})
function _handleError(err){
console.log('service error', err)
}
See client-simple for complete source of the simplest cocaine client app.
To fully control a client to services, you can use Client. It resolves services for you, keeps services cache, and resets resolved services cache on locator disconnect.
var cli = new require('cocaine').Client()
var storage = cli.Service('storage')
storage.on('error', function(err){
// reconnect on network error
})
storage.connect()
storage.on('connect', function(){
storage0.write('collection','key','value', function(err){
if(err){
console.log('error writing to storage', err)
return
}
console.log(done 'writing to storage')
})
})
See client-reconnect for example of handling various socket-level failures when connecting and communicating to locator and target services.
var cli = new require('cocaine').Client()
var app = cli.Service('the_app')
app.connect()
app.on('connect', function(){
app.enqueue('handle','anydata', function(err, result){
if(err) {
console.log('app error', err)
} else {
console.log('app response is', result)
}
})
})
[1] http://nodejs.org/api/net.html#net_server_listen_handle_callback