mardi 10 juin 2014

Resize an image with node js

Resize an image with gm & node js:
var fs = require('fs')
 , gm = require('gm')
 , express = require('express');

var port = (process.env.VCAP_APP_PORT || 3000);

var app = module.exports = express();

app.get('/image', function (req, res) {

 gm('DSC03282.JPG')
  .resize(width, height)
  .noProfile()
  .toBuffer(function (err, buffer) {
   res.writeHead(200, {'Content-Type': 'image/jpeg' });
   res.end(buffer, 'binary');
  });
});

app.listen(port);
console.log("Go Image API : 3000");

Create your own Cloud Image Api in few minutes



Links

heroku-buildpack-graphicsmagick : https://github.com/mcollina/heroku-buildpack-graphicsmagick
heroku-buildpack-multi : https://github.com/ddollar/heroku-buildpack-multi
image resize library for node Js : https://github.com/aheckmann/gm

Requirement:

this article : http://ibmbluemix.blogspot.com/2014/05/tips-if-you-have-problem-to-publish.html
the custom buildpack : https://github.com/dam1/cloudfoundry-custom
the Image Api demo : https://github.com/dam1/Imageapi-cloudfoundry

Tuto:

git clone git@github.com:dam1/Image-Service-Api-Example---Node-Js.git

cf push cloudimageapi --no-manifest  -b git://github.com/dam1/cloudfoundry-custom.git

"-b git://github.com/da..." let us choose a custom buildpacks

try http://cloudimageapi.ng.bluemix.net/image?width=400&height=300


You can create your own CDNConnect, Cloudinary, resrc.it, blitline !

mardi 20 mai 2014

lundi 19 mai 2014

How to Link Domain to a Bluemix app

you can't link a domain to a Bluemix app, you can link a subdomain to a Bluemix app. 

for Gymbirds.com i did a redirection from gymbirds.com to d.gymbirds.com the d.gymbirds.com is linked to gymbirds.ng.bluemix.net

 how to do that with Bluemix / Cloudfoundry ?

cf map-route gymbirds gymbirds.com -n d
"gymbirds" is the name of the App on Bluemix, "gymbirds.com" is the domain and "d" is the subdomain linked to the App


 So what's the new "grunt magic" ?

   changeroutebluemix: {
    command: function () {
     pkg = grunt.file.readJSON("package.json");
     var command =
      'cf map-route gymbirdstmp ng.bluemix.net -n gymbirds; ' +//map route gymbirds.ng.bluemix.net to gymbirds tmp
       'cf map-route gymbirdstmp gymbirds.com -n d; ' +
//map route d.gymbirds.com to gymbirdstmp
       'cf unmap-route gymbirds  ng.bluemix.net -n gymbirds; ' +
// unmap route gymbirds.ng.bluemix.net
       'cf unmap-route gymbirds  gymbirds.com -n d; ' +
// unmap route d.gymbirds.com
       'cf rename gymbirds gymbirds' + pkg.version + ' ;' +    
// rename app gymbirds into gymbirdslast
       'cf rename gymbirdstmp gymbirds'; 
// rename gymbirdstmp to gymbirds
     return command;
    }
   },

Example of "cf start myApp" successfull

Starting app gymbirds in org mail@memail.com / space PROD as mail@memail.com...
OK
-----> Downloaded app package (604K)
-----> Downloaded app buildpack cache (296K)
-----> Buildpack version: 2014.3.31.20140416
-----> Requested node range:  0.8.x
-----> Resolved node version: 0.8.26
-----> Downloading and installing node
-----> Found existing node_modules directory; skipping cache
-----> Rebuilding any native dependencies
       npm WARN package.json gymbirds@0.0.2 No repository field.
       mobile-detect@0.1.0 /tmp/staged/app/node_modules/mobile-detect
-----> Writing a custom .npmrc to circumvent npm bugs
-----> Installing dependencies
       npm WARN package.json gymbirds@0.0.2 No repository field.
       npm http GET https://registry.npmjs.org/express/3.3.8
       npm http 200 https://registry.npmjs.org/express/3.3.8
       npm http GET https://registry.npmjs.org/express/-/express-3.3.8.tgz
       npm http 200 https://registry.npmjs.org/express/-/express-3.3.8.tgz
       npm http GET https://registry.npmjs.org/connect/2.8.8
       npm http GET https://registry.npmjs.org/commander/1.2.0
       npm http GET https://registry.npmjs.org/range-parser/0.0.4
       npm http GET https://registry.npmjs.org/mkdirp/0.3.5
       npm http GET https://registry.npmjs.org/cookie/0.1.0
       npm http GET https://registry.npmjs.org/buffer-crc32/0.2.1
       npm http GET https://registry.npmjs.org/fresh/0.2.0
       npm http GET https://registry.npmjs.org/methods/0.0.1
       npm http GET https://registry.npmjs.org/send/0.1.4
       npm http GET https://registry.npmjs.org/cookie-signature/1.0.1
       npm http GET https://registry.npmjs.org/debug
       npm http 200 https://registry.npmjs.org/commander/1.2.0
       npm http GET https://registry.npmjs.org/commander/-/commander-1.2.0.tgz
       npm http 200 https://registry.npmjs.org/range-parser/0.0.4
       npm http 200 https://registry.npmjs.org/commander/-/commander-1.2.0.tgz
       npm http GET https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz
       npm http 200 https://registry.npmjs.org/buffer-crc32/0.2.1
       npm http GET https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz
       npm http 200 https://registry.npmjs.org/fresh/0.2.0
       npm http GET https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz
       npm http 200 https://registry.npmjs.org/methods/0.0.1
       npm http 200 https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz
       npm http GET https://registry.npmjs.org/methods/-/methods-0.0.1.tgz
       npm http 200 https://registry.npmjs.org/cookie/0.1.0
       npm http 200 https://registry.npmjs.org/methods/-/methods-0.0.1.tgz
       npm http 200 https://registry.npmjs.org/send/0.1.4
       npm WARN package.json range-parser@0.0.4 No repository field.
       npm http GET https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz
       npm http GET https://registry.npmjs.org/send/-/send-0.1.4.tgz
       npm http 200 https://registry.npmjs.org/connect/2.8.8
       npm http 200 https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz
       npm http GET https://registry.npmjs.org/connect/-/connect-2.8.8.tgz
       npm WARN package.json methods@0.0.1 No repository field.
       npm WARN package.json methods@0.0.1 No readme data.
       npm http 200 https://registry.npmjs.org/debug
       npm http GET https://registry.npmjs.org/debug/-/debug-0.8.1.tgz
       npm http 200 https://registry.npmjs.org/cookie-signature/1.0.1
       npm http 200 https://registry.npmjs.org/mkdirp/0.3.5
       npm http 200 https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz
       npm http GET https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz
       npm http GET https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz
       npm http 200 https://registry.npmjs.org/send/-/send-0.1.4.tgz
       npm http 200 https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz
       npm http 200 https://registry.npmjs.org/connect/-/connect-2.8.8.tgz
       npm http 200 https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz
       npm http 200 https://registry.npmjs.org/debug/-/debug-0.8.1.tgz
       npm http 200 https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz
       npm WARN package.json cookie-signature@1.0.1 No repository field.
       npm http GET https://registry.npmjs.org/mime
       npm http GET https://registry.npmjs.org/keypress
       npm http 200 https://registry.npmjs.org/keypress
       npm http GET https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz
       npm http 200 https://registry.npmjs.org/mime
       npm http GET https://registry.npmjs.org/mime/-/mime-1.2.11.tgz
       npm http 200 https://registry.npmjs.org/mime/-/mime-1.2.11.tgz
       npm http GET https://registry.npmjs.org/qs/0.6.5
       npm http GET https://registry.npmjs.org/formidable/1.0.14
       npm http GET https://registry.npmjs.org/bytes/0.2.0
       npm http GET https://registry.npmjs.org/pause/0.0.1
       npm http GET https://registry.npmjs.org/uid2/0.0.2
       npm http 200 https://registry.npmjs.org/uid2/0.0.2
       npm http GET https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz
       npm http 200 https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz
       npm http 200 https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz
       npm WARN package.json uid2@0.0.2 No repository field.
       npm WARN package.json uid2@0.0.2 No readme data.
       npm http 200 https://registry.npmjs.org/bytes/0.2.0
       npm http 200 https://registry.npmjs.org/pause/0.0.1
       npm http GET https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz
       npm http GET https://registry.npmjs.org/pause/-/pause-0.0.1.tgz
       npm http 200 https://registry.npmjs.org/qs/0.6.5
       npm http GET https://registry.npmjs.org/qs/-/qs-0.6.5.tgz
       npm http 200 https://registry.npmjs.org/formidable/1.0.14
       npm http 200 https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz
       npm http GET https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz
       npm http 200 https://registry.npmjs.org/pause/-/pause-0.0.1.tgz
       npm http 200 https://registry.npmjs.org/qs/-/qs-0.6.5.tgz
       npm http 200 https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz
       npm WARN package.json bytes@0.2.0 No repository field.
       npm WARN package.json pause@0.0.1 No repository field.
       express@3.3.8 node_modules/express
       ├── methods@0.0.1
       ├── range-parser@0.0.4
       ├── debug@0.8.1
       ├── cookie-signature@1.0.1
       ├── fresh@0.2.0
       ├── buffer-crc32@0.2.1
       ├── cookie@0.1.0
       ├── mkdirp@0.3.5
       ├── commander@1.2.0 (keypress@0.1.0)
       ├── send@0.1.4 (mime@1.2.11)
       └── connect@2.8.8 (uid2@0.0.2, pause@0.0.1, qs@0.6.5, bytes@0.2.0, formidable@1.0.14)
-----> Caching node_modules directory for future builds
-----> Cleaning up node-gyp and npm artifacts
-----> No Procfile found; Adding npm start to new Procfile
-----> Building runtime environment
-----> Uploading droplet (6.0M)

1 of 1 instances running

App started

Showing health and status for app gymbirds in org mail@memail.com / space PROD as mail@memail.com...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: gymbirds.ng.bluemix.net

     state     since                    cpu    memory        disk          
#0   running   2014-05-18 11:48:10 PM   0.0%   34.2M of 1G   22.9M of 1G   

How to publish / start a NodeJs App on Bluemix



The package.json is important for publish an app on Bluemix

Here is a sample of a package.json,  you should have something like that but with differents dependencies.
When you install a package with npm use "--save"
ex: "npm install stripe --save" automatically save the dependency in the package.json

{
 "name": "myApp",
 "version": "0.0.2",
 "engines": {
  "node":     ">=0.10.0"
 },
 "scripts": {
  "start": "node app.js"
 },
 "dependencies": {
  "stripe": "~2.5.3",
  "cors": "~2.3.1",
  "express": "~4.2.0",
  "body-parser": "~1.2.0",
  "email-templates": "~0.1.8",
  "nodemailer": "~0.6.5",
  "moment": "~2.6.0"
 }
}
the command following just upload you app on bluemix:
cf push myApp --no-manifest --no-start -c "node app.js"
the command following read you package.json, install al the dependencies, and then start your App, so if you forget one you will not be able to start the app:
cf start myApp

How to redirect on the mobile or desktop version ?

https://www.npmjs.org/package/mobile-detect

app.get('*', function (req, res) {
 md = new MobileDetect(req.headers['user-agent']);
 if (md.mobile() != null) {
  res.writeHead(301,
   {Location: 'http://m.gymbirds.com'}
  );
  res.end();
  console.log('mobile');
 }
 else {
  res.sendfile(__dirname + '/' + req.path);
  console.log('desktop');
 }
});

lundi 12 mai 2014

AngularJs Demo on Bluemix

I use yo angular to create your node js App : https://github.com/yeoman/generator-angular
this tool setup all the project and it's ready to use with bluemix 
all the files needed are created ( bower.json, package.json .. )



Links:
Node JS / npm : http://nodejs.org/download/


Javascript Task Runner : automate tasks like build app, push to bluemix, push/commit to git, and everything you want !

make any unix command with grunt

Scaffolding / generator for WebApp

 i use it for setup the AngularJs

CloudFoundry : https://github.com/cloudfoundry/cli
Command line client for CloudFoundry ( for Bluemix )


Source / sample Code : https://github.com/dam1/BluemixSample


Start with
yo angular

(follow instructions)

grunt serve
(angular js app running)

install grunt shell:
npm install --save-dev grunt-shell


build, push, startt app:
grunt magic


And your app is running on Bluemix !

Be sure that the name of the app is not already taken


Basic Commands with CloudFoundry on IBM BLuemix



Upload am App:



cf push myAppName --no-manifest --no-start -c "node app.js"
cf start myAppName

Change route :

cf unmap-route gymbirdsmobile ng.bluemix.net -n gymbirdsmobile

cf map-route gymbirdsmobiletmp ng.bluemix.net -n gymbirdsmobile


Rename App :

cf rename gymbirdstmp gymbirds

Update App  :

i use Grunt to automate these tasks, with these command i can do an update with 2sec downtime, it need to be fixed by IBM

cf push gymbirdsmobiletmp --no-manifest --no-start -c "node app.js" 
// upload the new version

cf start gymbirdsmobiletmp 
// start it

cf unmap-route gymbirdsmobile ng.bluemix.net -n gymbirdsmobile 
// unmap original route

cf map-route gymbirdsmobiletmp ng.bluemix.net -n gymbirdsmobile 
// map the original route to the new

cf rename gymbirdsmobile gymbirdsmobileLast 
// rename the last app

cf rename gymbirdsmobiletmp gymbirdsmobile 
// rename the app uploaded to gymbirdsmobile

I automate there command with grunt

my Gruntfile.js :



shell: {
   pushbluemix: {
    command: function () {
    return 'cd ../dist/web/ ;cf push gymbirdstmp --no-manifest --no-start -c "node app.js"' ;
    }
   },
   startbluemix: {
    command: function () {
     return 'cd ../dist/web/ ;cf start gymbirdstmp ';
    }
   },
   startbluemixtest: {
    command: function () {
     return 'cd ../dist/web/ ;cf start gymbirdstest ';
    }
   },
   changeroutebluemix: {
    command: function () {
     pkg= grunt.file.readJSON("package.json");

     var command =
      'cf unmap-route gymbirds ng.bluemix.net -n gymbirds; ' +
// unmap route gymbirds.ng.bluemix.net
       'cf map-route gymbirdstmp ng.bluemix.net -n gymbirds; ' +
//map route gymbirds.ng.bluemix.net to gymbirds tmp
       ' cf rename gymbirds gymbirds'+ pkg.version+' ;' +    
// rename app gymbirds into gymbirdslast
 'cf rename gymbirdstmp gymbirds'; // rename gymbirdstmp to gymbirds
     return command;
    }
   },
   recoverbluemix: {
    command: function () {
     return   'cf unmap-route gymbirds ng.bluemix.net -n gymbirds; ' +
// unmap route gymbirds.ng.bluemix.net
      'cf map-route gymbirdslast ng.bluemix.net -n gymbirds; ' ;
//map route gymbirds.ng.bluemix.net to gymbirdstmp
    }
   },
   gitcommit: {
    command: function () {
     pkg= grunt.file.readJSON("package.json");

     console.dir(pkg.version);
     var version = pkg.version.split('.');
     var nb = Number(version[2]) +Number(1);
     version = version[0]+'.'+version[1]+'.'+nb;
     pkg.version = version;
     console.log(pkg.version);
     console.log(JSON.stringify(pkg));
     grunt.file.write("package.json", JSON.stringify(pkg));
     return   'git commit -a -m "PUSH '+pkg.name+' - version : ' +pkg.version+'"';

    }
   },
   gitpush: {
    command: function () {
     return   'git push origin master; git push gitlab master';
    }
    }
  }
And the tasks :

 // bluemix
 grunt.registerTask('push bluemix', [
  'shell:pushbluemix',
   'shell:startbluemix'
 ]);

 grunt.registerTask('bluemix', [
  'shell:pushbluemix',
  'shell:startbluemix',
  'shell:changeroutebluemix'
 ]);

 //git
 grunt.registerTask('git', [
  'shell:gitcommit',
  'shell:gitpush'
 ]);

 grunt.registerTask('magic', [
  'build',
  'bluemix',
  'git'
 ]);

'grunt magic' let met update the app on bluemix in One command !

Demo of the app : http://gymbirds.ng.bluemix.net/
mobile version : http://gymbirdsmobile.ng.bluemix.net

Notes :
My Webapp is based on AngularJs, i use bower, npm, grunt, yeoman,.