Blog by nkzawa

  • Archive
  • RSS

I’m writing an Engine.IO Java Client

I’ve been working for the Engine.IO client library for Java. This Library was simply ported from the JS client, which means it supports most features the original library supports. It already can communicate with a server, although is still in development phase.

https://github.com/nkzawa/engine.io-client.java

Simple Example

Socket is an abstract class, so you have to implement some callback methods. Then just call open.

Socket socket = new Socket("ws://localhost") {
    @Override
    public void onopen() {}

    @Override
    public void onmessage(String data) {}

    @Override
    public void onclose() {}
};
socket.open();

Of course, we need a Socket.IO Java client too. I’m working on it, and it will be built on top of this Engine.IO Client.

    • #socket.io
  • nkzawa Avatar Posted by nkzawa
  • 1 month ago
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Connecting to a Socket.IO server from Android

Socket.IO has a specified protocol on the top of WebSocket, so you have to use a client for Socket.IO, not for WebSocket. There are some Socket.IO clients in Java and Android, but you will find socket.io-java-client is the best way to go.

https://github.com/Gottox/socket.io-java-client

Since socket.io-java-client doesn’t support Maven, you have to use a forked version of it if you use with Maven. The forked version is slightly different than the original. (e.g., It uses Gson instead of org.json package)

https://github.com/fatshotty/socket.io-java-client

Simple Usage

An example to send and receive events. The following is a code of a simple echo server in Node.

io.sockets.on('connection', function(socket) {
  socket.on('echo', function(data) {
    socket.emit('echo back', data);
  });
});

The next is a Java code to connect to the server from Android. The usage of the client is similar to the Socket.IO client for JavaScript. You can send a message via SocketIO#emit or SocketIO#send method, and can receive data via IOCallback#on and IOCallback#onMessage callbacks.

SocketIO socket = new SocketIO("http://127.0.0.1:3001");
socket.connect(new IOCallback() {
    @Override
    public void on(String event, IOAcknowledge ack, Object... args) {
        if ("echo back".equals(event) && args.length > 0) {
            Log.d("SocketIO", "" + args[0]);
            // -> "hello"
        }
    }

    @Override
    public void onMessage(JSONObject json, IOAcknowledge ack) {}
    @Override
    public void onMessage(String data, IOAcknowledge ack) {}
    @Override
    public void onError(SocketIOException socketIOException) {}
    @Override
    public void onDisconnect() {}
    @Override
    public void onConnect() {}
});
socket.emit("echo", "hello");

Headers and Cookie

This is an example to send cookie when handshaking.

String host = "http://127.0.0.1:3001";
String cookie = CookieManager.getInstance().getCookie(host);

SocketIO socket = new SocketIO(host);
socket.addHeader("Cookie", cookie);
socket.connect(new IOCallback() { ... });

Acknowledge

Acknowledge is the way to get a response corresponding to a sent message. The following is a code snippet for server-side.

io.sockets.on('connection', function(socket) {
  socket.on('echo', function(data, callback) {
    callback(data);
  });
});

The next is for client-side. Use an instance of an IOAcknowledge implementation with SocketIO#emit or SocketIO#send method.

IOAcknowledge ack = new IOAcknowledge() {
    @Override
    public void ack(Object... args) {
        if (args.length > 0) {
            Log.d("SocketIO", "" + args[0]);
            // -> "hello"
        }
    }
}
socket.emit("echo", ack, "hello");
    • #socket.io
    • #android
  • nkzawa Avatar Posted by nkzawa
  • 1 month ago
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

How to write native Node addons

Node addons are written in C++ with V8 Library. Compiled files (.node) can be used directly from JS code with require function. V8 simply represents JavaScript concepts and its values in C++ classes one for one. It’s very intuitive, so writing addons is not so difficult if these aren’t complex ones.

Hello world in C++

What we have to do is just to write C++ like JS in V8 way. The code in comments are JavaScript equivalent:

// hello.cc
#include <node.h>
#include <v8.h>

using namespace v8;

/**
 * function Hello() {
 *   var hello = 'hello ';
 *   var arg = arguments[0];
 *   return hello + arg;
 * }
 */
Handle<Value> Hello(const Arguments& args) {
  HandleScope scope;

  Local<String> hello = String::New("hello ");
  Local<String> arg = args[0]->ToString();
  return scope.Close(String::Concat(hello, arg));
}

/**
 * function Init(exports) {
 *   var hello = Hello;
 *   exports.hello = hello;
 * }
 */
void Init(Handle<Object> exports) {
  Local<Function> hello = FunctionTemplate::New(Hello)->GetFunction();
  exports->Set(String::NewSymbol("hello"), hello);
}

NODE_MODULE(hello, Init)

NODE_MUDULE is a macro defined at node.h. The first argument of NODE_MUDULE is the module name (the file created at compile time).

Compile

We need to compile the above code by using node-gyp and its configuration file binding.gyp. binding.gyp has a JSON-Like format:

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "hello.cc" ]
    }
  ]
}

Install node-gyp and compile:

$ npm install -g node-gyp
$ node-gyp configure build

Then build/Release/hello.node would be created.

Use the addon

You can now use hello.node as always.

// hello.js
var addon = require('./build/Release/hello');

console.log(addon.hello('world'));  // 'hello world'

References:

  • http://nodejs.org/api/addons.html
  • http://izs.me/v8-docs/main.html
    • #node
    • #nodejs
    • #c++
    • #v8
  • nkzawa Avatar Posted by nkzawa
  • 2 months ago
  • 1
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Released a mongoose plugin to limit json fields

I have released a simple mongoose plugin to limit fields when calling toJSON. It includes/excludes json properties in the same syntax with mongoose’s field selection.

var jsonSelect = require('mongoose-json-select');

var schema = Schema({
  name: String,
  email: String,
  created: {type: Date, 'default': Date.now}
});
schema.plugin(jsonSelect, 'name created');
var User = mongoose.model('User', schema);

var user = User({name: 'alice', email: 'alice@example.com'});
JSON.stringify(user);
// -> '{"_id": "51466baedf03a52e9b000001", "name": "alice", "created": "2013-03-16T16:08:38.065Z"}'

JSON.stringify(user.toJSON({select: 'name email'}));
// -> '{"_id": "51466baedf03a52e9b000001", "name": "alice", "email": "alice@example.com"}'

See the following link for the details.

https://github.com/nkzawa/mongoose-json-select

    • #mongoose
    • #mongodb
  • nkzawa Avatar Posted by nkzawa
  • 2 months ago
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Middlewares for Socket.io

http://www.danielbaulig.de/socket-ioexpress/

The above link leads you to a great article which explains the way to share Express’s sessions with Socket.io. That works fine, but I feel it’s a bit messy and not easy to add more functions. So what if we could use middlewares like that of how Express and Connect do for this purpose?

Handler

To achieve using middlewares, you need a manager which would add each middlewares to a stack by “use” method.

# middleware-handler.coffee
module.exports = class MiddlewareHandler
  constructor: ->
    @stack = []

  use: (middleware) ->
    @stack.push middleware

  handle: (args, callback) ->
    index = 0

    next = (err) =>
      middleware = @stack[index++]
      if not middleware or err
        return callback.apply null, [err].concat(args)

      middleware.apply null, args.concat(next)

    next()

Middlewares

Not like middlewares for Express/Connect, middlewares for Socket.io accept handshake’s data as the argument. Since most properties are the same with a request object, you can easily share Express/Connect’s middlewares for Socket.io too.

# cookieParser.coffee
express = require 'express'

module.exports = (secret) ->
  _cookieParser = express.cookieParser secret

  (handshake, next) ->
    _cookieParser handshake, {}, next
# session.coffee
express = require 'express'
connect = require 'express/node_modules/connect'


{Cookie, Session, MemoryStore} = express.session

# Ported from connect.session
module.exports = (options={}) ->
  key = options.key or 'connect.sid'
  store = options.store or new MemoryStore
  cookie = options.cookie or {}

  store.generate = (handshake) ->
    handshake.sessionID = connect.utils.uid 24
    handshake.session = new Session handshake
    handshake.session.cookie = new Cookie cookie

  (handshake, next) ->
    handshake.sessionStore = store
    unsignedCookie = handshake.signedCookies[key]

    generate = ->
      store.generate handshake

    handshake.sessionID = unsignedCookie
    unless handshake.sessionID
      generate()
      next()
      return

    store.get handshake.sessionID, (err, session) ->
      return next err if err
      if session
        store.createSession handshake, session
      else
        generate()

      next()

Using middlewares

Use the handler and middlewares with the authorization like the following.

# io.coffee
socketio = require 'socket.io'
MiddlewareHandler = require './middleware-handler'
cookieParser = require './cookieParser'
session = require './session'

io = module.exports = socketio.listen 8080
io.configure ->
  # Set middlewares
  middlewareHandler = new MiddlewareHandler()
  middlewareHandler.use cookieParser('secret value')
  middlewareHandler.use session()

  io.set 'authorization', (handshake, callback) ->
    # Dispatch middlewares with handshake's data as the argument.
    middlewareHandler.handle [handshake], (err) ->
      console.log handshake.session
      callback err, not err
    • #socket.io
    • #express
    • #nodejs
  • nkzawa Avatar Posted by nkzawa
  • 2 months ago
  • 1
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Simple Configuration Management for Node Applications

How to control node environment settings simply. Create the following file in an empty directory (“environment” in this case).

# environment/index.coffee
environment = process.env.NODE_ENV or 'development'
module.exports = require "./#{environment}"

Create setting files with environment names.

# environment/development.coffee
exports.foo = 'a value for development'
# environment/production.coffee
exports.foo = 'a value for production'

And read configurations like:

# app.coffee
environment = require './environment'
console.log environment.foo
$ export NODE_ENV=production; coffee app.coffee
a value for production
    • #node
  • nkzawa Avatar Posted by nkzawa
  • 2 months ago
  • 2
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

IntelliJ IDEA over Eclipse

Recently, I tried Android Bootstrap, then I had to struggle with Eclipse and Maven for hours. They simply didn’t work properly. Android Bootstrap looked splendid, and I have been tired of Eclipse’s strange bahaviors, so I decided to look for other IDEs.

IntelliJ IDEA

Finally, IntelliJ IDEA was the best solution for me.

  • It works fine with Android and Maven without any configurations.
  • Works faster than Eclipse.
  • Has sufficient plugins, although lesser than that of Eclipse`s. I use Ideavim for vim-like key mappings and Solarized color scheme.
  • It has a free community edition which has enough functionalities for Android development.

You can also find the Github people use IntelliJ from their Android app repositories (see .idea directory). That fact encouraged me, even though changing IDE was a big deal.

    • #intellij
    • #eclipse
  • nkzawa Avatar Posted by nkzawa
  • 3 months ago
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Testing mongoose models with mocha

I couldn’t find any good mocks for moongoose, so direct access to empty database would be one of the easiest ways to test mongoose models for now.

Model

# user.coffee
mongoose = require 'mongoose'

schema = new mongoose.Schema
  email: String
  created: {type: Date, default: Date.now}
module.exports = mongoose.model 'User', schema

Test

A simple test for the above model will be like this.

# test-user.coffee
{expect} = require 'chai'
db = require './db'
User = require './user'

describe 'User', ->
  # call while testing db
  db()

  describe '#save', ->

    it 'should save user', (done) ->
      data = {email: 'foo@example.com'}
      user = new User data
      user.save (err, user) ->
        done err if err
        expect(user.email).to.equal data.email
        expect(user.created).to.exist
        done()

Setup

Prepare a configuration file. This will set up a connection to a empty database, and clean up the database after each tests.

# db.coffee
mongoose = require 'mongoose'

# Connect to a database which is for test
mongoose.connect 'mongodb://localhost/test'
connection = mongoose.connection

before (done) ->
  connection.on 'open', ->
    connection.db.dropDatabase done

after (done) ->
  connection.close done

module.exports = ->
  afterEach (done) ->
    connection.db.dropDatabase done

Run

Add the following line to the “scripts” member of the package.json.

"scripts": {
  "test": "PATH=./node_modules/.bin:$PATH; mocha --compilers coffee:coffee-script src"
},

And run:

$ npm test

Travis CI

Travis supports MongoDB as a service, so you can easily run this test without mess setup. Travis will call “npm test” for node by default.

# .travis.yml
language: node_js
node_js:
  - 0.8
services:
  - mongodb

All files here

    • #mongoose
    • #mocha
    • #test
    • #mongodb
  • nkzawa Avatar Posted by nkzawa
  • 3 months ago
  • 2
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

Can I write code on tumblr?

Hello, world.

var http = require('http');
http.createServer(function (req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
  • nkzawa Avatar Posted by nkzawa
  • 3 months ago
  • 1
  • Comments
  • Permalink
Share

Short URL

TwitterFacebookPinterestGoogle+

About

Avatar

Me, Elsewhere

  • @nkzawa on Twitter
  • nkzawa on github

Following

  • nyxmichaelis
  • mongodb
  • jsism
  • bulknews
  • bulknews-podcast
  • shyouhei
  • swdyh
  • forbeslindesay
  • izs
  • engineering
  • badassjs
  • mongoosejs
  • tjholowaychuk
  • instagram-engineering
  • RSS
  • Random
  • Archive
  • Mobile
Effector Theme by Pixel Union