Saturday, 1 September 2012

Try protojs serials : C. return protocol buffer from web service

I will implement a web app using CppCMS framework. Yes, it's a C++ framework.
The basic idea is to generate the binary stream, send it via response to browser, set the content type to
application/x-protobuf.

This post doesn't describe the usage of CppCMS. Please refer to cppcms.com if needed.

In web service constructor, map the url request to test_group member function.

dispatcher().assign("/testGroup" , &kaimei_web_site::test_group , this);

Some part  of test_group codes list here:


void kaimei_web_site::test_group() {
  kaimei::response res;
  try {
    ....
    response().content_type("application/x-protobuf");
    freebird::group g;
    g.set_id("1");
    g.set_name("a");
    g.set_description("d");
    g.set_device_number("5");
    g.SerializePartialToOstream(&response().out());

  } catch(std::exception const& ex) {
    ...
  }
}

That's all. Now launch browser, access the web site using /testGroup path. Browser will download a file called testGroup.


Unfortunately, the protojs can't parse the stream transferred from server.
Chrome always says:ArrayBuffer values are deprecated ...

I will update this post later.


Friday, 31 August 2012

Try protojs serials : B. support C++

I will develop a web site using C++. I need a compiler for generating C++ codes from group.proto file.
A standard protocol buffer from google will be installed. I didn't describe how to install this here. Please refer to the official site:
http://code.google.com/p/protobuf/

Create a build.sh file under proto folder. Add some scripts into it.


rm output/js/*
rm output/c++/*
protoc --proto_path=./input --cpp_out=./output/c++ ./input/group.proto
pbj input/group.proto output/js/group.js

chmod +x ./build.sh

Now execute build.sh, you will see C++ and JavaScript files are both generated.

proto/
├── build.sh
├── input
│   └── group.proto
└── output
    ├── c++
    │   ├── group.pb.cc
    │   └── group.pb.h
    └── js
        └── group.js

4 directories, 5 files

Try protojs serials : A. install

Protojs is a JavaScript add-on for protocol buffer. I try it because I want to replace JSON with protocol buffer when developing web site later.

This article shows how to setup protojs and test it on Ubuntu.

Clone the repository from github first:
sudo -s
cd /usr/src
git clone https://github.com/sirikata/protojs.git

Compile it.
curl is required.install it using 'apt-get install curl'.
cd protojs
./bootstrap.sh  (This will download antlr-3.2 from antlr.org)
make

After a while, I got pbj binary. It's a protojs compiler.

Add the following into ~/.bashrc file

export PBJ_HOME=/usr/src/protojs
export PATH=$PBJ_HOME:$PATH


source ~/.bashrc


Let's use it. I have a folder tree looks like so:


proto/
├── input
│   └── group.proto
└── output
    ├── c++
    └── js

4 directories, 1 file

I defined a group.proto for generating C++ and JavaScript files.

package freebird;

message group {
  required string id = 1;
  required string name = 2;
  required string description = 3;
  required string device_number = 4;
}

In proto folder, execute the following command to generate js file:
pbj input/group.proto output/js/group.js

group.js 's content:



"use strict";
/** @suppress {duplicate}*/var freebird;
if (typeof(freebird)=="undefined") {freebird = {};}

freebird.group = PROTO.Message("freebird.group",{
id: {
options: {},
multiplicity: PROTO.required,
type: function(){return PROTO.string;},
id: 1
},
name: {
options: {},
multiplicity: PROTO.required,
type: function(){return PROTO.string;},
id: 2
},
description: {
options: {},
multiplicity: PROTO.required,
type: function(){return PROTO.string;},
id: 3
},
device_number: {
options: {},
multiplicity: PROTO.required,
type: function(){return PROTO.string;},
id: 4
}});








Monday, 27 August 2012

Nginx with basic authentication

Assume we have Nginx installed on Ubuntu 12.04 server. Now I will show you how to configure HTTP basic authentication in Nginx.

step1:
Open conf/nginx.conf file, and add some directives into locatiion / section:

        location / {
            auth_basic "Restricted";
            auth_basic_user_file pwd;
            ...
        }

"Restricted" word will appear in the popup dialog when you try to access the Nginx site the first time.
pwd is a file located at conf folder. Note if you type conf/pwd here, the pwd file must be located at /conf/conf folder.

step2:
Create a pwd file. Add your user name and password(plaintext).
The password should be replaced by the step3.
chenshu:770328

step3:
Install Apache2 tools.
apt-get install apache2-utils

step4:
Update password using apache2 tools.
htpasswd /usr/nginx/conf/pwd chenshu
You will be asked to input password twice.
Now the pwd file's content changed:
chenshu:$apr1$I2FIVtPG$I51oSU4eatH.tJdnmxG6K0

step5:Restart Nginx service.
service nginx restart

step6: Log in your site.
Very easy!




Saturday, 25 August 2012

Flexigrid example two:in-place editor

Sometimes we want to edit the flexigrid' data. An in-place editor is required, don't need to pop up a dialog any more. I will show you how to do this here.

I use jquery-in-place-editor library. Please refer to the official site:
http://code.google.com/p/jquery-in-place-editor/

step1: add a process function for the column of flexigrid when you define the flexigrid model.


$(document).ready ( function() {
    $("#displays").flexigrid (
{
   url: '<%=jsonp%>/bindedDisplays',
   method:'POST',
   dataType: 'json',
   width: 400,
   height: 300,
   colModel : [
{hide: '<%=check%>', name: 'check', width: 30, sortable: true, align: 'left'},
{display: 'ID', name: 'id', width: 90, sortable: true, align: 'left'},
{display: '<%=description%>', name: 'description', width: 110, sortable: true, align: 'left',process:editDescription},
{display: '<%=status%>', name: 'status', width: 20, sortable: true, align: 'left'},
{display: '<%=unbind%>', name: 'unbind', width: 20, sortable: true, align: 'left',process:unbindDisplay}
   ]
}
    );
}
 );

step2:Implement the editDescription function using jquery-in-place-editor


function editDescription(celDiv, id){
    $( celDiv ).click( function() {
var idTd = $(celDiv).parent().parent().children()[1];
$(celDiv).editInPlace({
   url: "update_description",
   params: "address="+$(idTd.children).html(),
   error:function(obj){
alert(JSON.stringify(obj));
   },
   success:function(obj){
var str = m[JSON.parse(obj).status+""][window.curLanguage];
alert(str);
$("#displays").flexReload();
   }
});
    });
}

$(celDiv).editInPlace will let see an in-place editor effect in web page.
Ajax request will be sent to the web server's ./update_description path via jquery-in-place-editor.

Very easy! You also need to include the necessary js file like so:

 <script type="text/javascript" src="script/jquery.editinplace.js"></script>



Flexigrid example one: load data without binding server-side request

Let me explain my term here-- bind flexigrid to server-side request
You will find there are a lot examples on Internet, they all use url property like so:

$("#displays").flexigrid(
{
url: 'load_all_displays',
method:'POST',
dataType: 'json',
width: 400,
height: 420,
colModel:[
{display: 'check', name: 'check', width: 30, sortable: true, align: 'left'},
{display: 'ID', name: 'id', width: 90, sortable: true, align: 'left'},
{display: 'description', name: 'description', width: 110, sortable: true, align: 'left'}
]
}
);

The above red words means flexigrid will send a POST request to the load_all_displays path of current web server. Server side should return the data to flexigrid as expected format.

This is easy to understand and good example. But I have good reasons to avoid this way.
Reason 1:
I develop a web service, it will send data to client( browser or not browser). Web server is responsible for generating data, and the client should convert it into expected format for rendering. Maybe one developer use flexigrid to present its data, another guy prefers to use HTML5 table.

Reason 2:
I need a way to add/delete/modify the flexigrid's row without calling server-side API. All these operations should only occur in client-side. After all these are done, client calls server-side API to update data one time.

In my way, JavaScript codes will get all data from web server, translate it into correct format, add the value into flexigrid. Let's see my example below:


var testData = {
"page": 1,
"total": 20,
"rows":
[
{"cell" : ["A", "a group", "0", "d"]},
{"cell" : ["B", "b group", "0", "d"]},
{"cell" : ["C", "c group", "0", "d"]},
{"cell" : ["D", "d group", "0", "d"]}
]
}

function config(groupName, description, deviceNumber, del) {
$("#groups").flexigrid (
{
dataType: 'json',
width: 580,
height: 300,
colModel : [
{display: groupName, name: 'groupName', width: 160, sortable: true, align: 'left'},
{display: description, name: 'description', width: 200, sortable: true, align: 'left'},
{display: deviceNumber, name: 'deviceNumber', width: 100, sortable: true, align: 'left'},
{display: del, name: 'del', width: 40, sortable: true, align: 'left'}
]
}
);
}

function fillData() {
$("#groups").flexAddData(testData);
}


The config function will be called after page loading is done. You will see the simple format for flexigrid in testData variable.
If JavaScript calls fillData function, the testData will be added into flexigrid. Also we need to define a table in web page as following:

<table id="groups" style="display:none" bgcolor="#c4c4c4"></table>

My solution needs more codes, but it also let you control all things when developing your own web site.



Wednesday, 22 August 2012

Installing Jenkins plugin manually

We used Jenkins as our main CI management tools. It worked fine. But today I found two Jenkins can't upgrade/install plugins.
No way to fix this problem, because we didn't change the configuration , they worked fine before.
After searching in google for a while, I found I can install plugins manually. Let's do it.
Refer to the wiki:https://wiki.jenkins-ci.org/display/JENKINS/Plugins
Log into Jenkins server via SSH, we have tomcat7 installed on Ubuntu server. The Jenkins home folder is located at /usr/share/tomcat7/.jenkins
Enter the plugins folder under Jenkins' home folder.
Download the plugin's hpi file here, e.g.
wget http://mirror.xmission.com/jenkins/plugins/pathignore/0.6/pathignore.hpi

Then reload Jenkins app in tomcat7 admin page, go to the Jenkins page to watch if the plugin is installed or not. I can't see the pathignore plugin in installed tab. Why?
Because pathignore plugin depends on another plugin called ruby-runtime.
Download this plugin using the same way.
wget http://updates.jenkins-ci.org/download/plugins/ruby-runtime/0.10/ruby-runtime.hpi

Reload Jenkins again, it works.


Followers

Contributors