• コンセプトと特徴


        Less code, the fastest mock-up.
        - システムの最速モックアップ -
        foonyah はモジュールによるシステムの細分化を可能としたアーキテクチャを採用、実装されており、モジュールの依存性と再利用性を極限まで利用した類のないシステム構築を可能としています。

        モジュールの細分化は3層アーキテクチャによる設計を前提としており、なおかつ分散型システムの構築を想定しています。

        foonyah 自体は実装上、メモリ空間上に展開される名前空間でもあります。この名前空間はサーバーサイド(Node)とクライアントサイド(JavaScript with jQuery) 双方で利用可能です。 foonyah の持つ関数は双方の違いを吸収し、最大の特徴である Plugin クラス及び依存関係読み込みを行うライブラリ群を提供しています。

        関数foonyah() は体系的なアプリケーションの生成を行います。また、foonyah の殆どの関数は pure javascript であり、foonyah にとって重要な関数群以外にも共通で利用出来るLogging関数やEmitterオブジェクトなどのユーティリティを搭載しています。これらは Nodeモジュールでもある foonyah によって立ち上げたサーバー上でない環境や、jQueryを用いない環境でも利用可能です。

      • アーキテクチャ

        • 基盤技術

          foonyah is using node.js and mongodb as a core technology.
          but you never be asserted this environment. Any database, any language or any system can join to foonyah.
          • セキュアな HTTP と WebSocket の標準サポート
          • Java Script, JSON フル実装
          • クラウド, クラスタ特性
        • プラグイン技術

          on foonyah, you can use all plugin very simply and object oriented.
          • 簡潔な読み込みと呼び出し
            you can import modules only call app.prepare function.
              app.prepare('tablify');
            app is an foonyah object. (see more in "practical sample")
            tablify is a preserved module to make table dom structure easily.

            you can retrieve APIs in tablify module not only on browser, but also on server.
              var tablify= foonyah.use('tablify');

            and you can make table dom structure easily.
              var table = tablify(4,5);
            table.find('td').each(function(i){
            $(this).text(i);
            });
            $('body').append(table);

          • 強力な継承性と再利用性

          • 提供されるモジュール
        • コアエンジン

          • DOMWindow
          • Socket Perser
          • GridFS
          • Cluster Session
        • コアライブラリ

          • foonyah
            foonyah is not only the code name of this project but also a namespace for your scripting. In addition, foonyah has many module to implement the idea , foonyah.
          • jQuery
            jQuery is a very popular library and foonyah server preloads this library. Default load version is the latest which can be get from http://jquery.com/. Now, the version is 2.0.3.

            To get/link to original source, access to "http://code.jquery.com/jquery-x.x.x[.min].js" .
            e.g. 1.12.1 ( compressed ) , 2.2.1 ( compressed ) ,
          • xjQuery
            xjQuery is a code name which means "eXtend event engine for jQuery with foonyah".
            Source is published at github with MIT Licenced.
            See detail on xjQuery document.
      • ベンチマーク

        Response Test by httperf

        Total: connections 10 requests 100 replies 100 test-duration 1.039 s

        Connection rate: 9.6 conn/s (103.9 ms/conn, <=10 concurrent connections)
        Connection time [ms]: min 967.6 avg 1003.5 max 1029.7 median 1000.5 stddev 20.9
        Connection time [ms]: connect 0.1
        Connection length [replies/conn]: 10.000

        Request rate: 96.3 req/s (10.4 ms/req)
        Request size [B]: 62.0

        Reply rate [replies/s]: min 0.0 avg 0.0 max 0.0 stddev 0.0 (0 samples)
        Reply time [ms]: response 100.3 transfer 0.0
        Reply size [B]: header 156.0 content 10224.0 footer 2.0 (total 10382.0)
        Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0

        CPU time [s]: user 0.09 system 0.92 (user 8.6% system 89.0% total 97.6%)
        Net I/O: 981.5 KB/s (8.0*10^6 bps)

      • 申請済商標、特許、論文等

        Japan Patent Office Application
        - 2011-102203 (12.04.2011)
        - 2011-223375 (20.09.2011)
        - 2011-223376 (20.09.2011)
        - 2011-223377 (20.09.2011)
        - 2012-130242 (22.05.2012) [Priority Target]
        - 2012-289435 (21.12.2012)

        Japan Patent Office Trademark
        - 2012- 44775 (20.11.2012)

        Patent Cooperation Treaty Application
        - PCT/JP2012/084267
      • 著作権、ライセンス表示

        All sources and plugins are LICENSED by Liberty Technology.
        • start.js

          [ practical source ]
          /***/
          // import configuration files and launch service
          foonyah.start({
          server: require( './configure/server'),
          cluster: require('./configure/cluster')
          });
          • 説明
            モジュール "foonyah" は関数 "start()" を持ち、システムを起動します。
            プロジェクトルートからの起動でない場合、第一引数にはシステムのプロジェクトルートが与えられなければなりません。プロジェクトルートからの起動の場合、プロセスの実行位置は自動で当該ディレクトリに変更されます。
            31 May 17:46:11 - !!! MUST BE ON SERVER's PROJECT HOME !!!
            * Current Working Directory is:
            /home/username/libtech

            更に引数にはクラスタおよびサーバーの設定を与えます。
        • cluster.js

          [ practical source ]
          module.exports = clusterConfig;
          function clusterConfig() {
          var conf = {}, secret_key = '/Users/ystk_skm/.ssh/id_rsa';
          conf.jpcloud = {
          regexp: {
          hostname: /MacBook-Air|GMO-Cloud/,
          },
          forwarded: {
          user: 'jp-admin',
          secret_key: secret_key
          },
          facade: [{
          exp: 'US',
          type: 'encloud'
          }],
          clusterhub: true,
          database: true,
          starts: [{
          ip: '',
          type: 'encloud'
          }]
          };
          conf.encloud = {
          regexp: {
          hostname: /Rackspace-Cloud/,
          },
          forwarded: {
          user: 'us-admin',
          secret_key: secret_key
          },
          facade: [{
          exp: '!US',
          type: 'jpcloud'
          }],
          clusterhub: true,
          database: true
          };
          return conf;
          }
          • 説明
            クラスタの構成オブジェクトを生成し、返します。
            ここでは最もベーシックな日本とアメリカ2国にサーバーを配置する場合を考えます。具体的には、アメリカからのリクエストが来た場合、DSR(ダイナミックサーバーレスポンス)で高速なアプリケーション応答を実現する構成です。
            適切な値を指定しておくだけで、あとは立ち上げる時にDSR実現の為の SSH Port Forwarding プロセスが自動起動します。
        • server.js

          [ practical source ]
          /***/
          var path = require('path');
          /* server configuration for project "sample" */
          module.exports = serverConfig;
          function serverConfig() {
          var rootdir = path.resolve('..'), conf = {};
          var basic = {
          http: [httpSet(80, false, true), httpSet(443, true, false)],
          };
          ['jpcloud', 'encloud'].forEach(function(k) {
          conf[k] = basic;
          });
          return conf;
          }
          function httpSet(port, ssl, ws) {
          var rootdir = path.resolve('..');
          var base = {
          port: port,
          redirect: {
          http2https: {
          regexp: /http:\/\/([^\/]+)\/([^\/]+)\//,
          redirect: function(furl, mtc) {
          return furl.replace(/^http:/, 'https:');
          }
          },
          },
          alias: {
          cloudplus: {
          regexp: /https?:\/\/cloudplus\.me\//,
          replace: ['', '/cloudplus.me'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          }
          },
          websocket: ws,
          fork: false
          };
          var path_to_ssl = null;
          if(ssl === true) {
          path_to_ssl = function(type) {
          return '/home/appadmin/ssl/RapidSSL2013.' + type;
          };
          base.ssl = {
          key: path_to_ssl('key'),
          ca: path_to_ssl('ca'),
          cert: path_to_ssl('cer')
          };
          }
          } else
          delete base.ssl;
          return base;
          };
          • 説明
            アプリケーションサーバーの設定を行うオブジェクトを返します。
            ここにはSSL鍵の指定、リダイレクト、エイリアスやNotFoundページ指定などよくあるサーバーの標準的な設定が出来るだけでなく、Server Type や WebSocket 有無といった Node ならではの設定項目、更にはプラグインディレクトリ指定や読み込むコアモジュールの変更など foonyah の根本的な挙動設定も行えます。
        • setting.js

          [ L1-L4 ]
          It defines some variable for pathname fixing.
          In this sample case, root path ("http://cloudplus.me/") should call file in "(document_root)/coudplus.me" directry.
          In addition, there is no aware of the corresponding OS file system and foonyah grid-fs.
          /***/
          //common
          var name = 'PirtyGoods', pfix = '/cloudplus.me', fix = '/PirtyGoods';
          [ L5-L17 ] Application parameters is defined in this area.
          These parameters ups on memory when application first call (=first launch) or refresh call (=url with "?refresh" query).
          Application
          It will set "foonyah.Application" name space and it also means of MongoDB database name for this application.
          PathnameAdjuster
          It will set for calculate foonyah's internal pathname for dynamic application calling.
          See detail explain below ( [L18-L27] )
          StreamUrlChanger
          It will set for calculate foonyah's internal stream call for save memory use and response improvement.
          See detail explain below ( [L28-L35] )
          CacheTime
          It defines cache time for heavy access to particular url.
          In this time, foonyah outputs same data stream for cacheOut mode.
          //create application
          var app = foonyah({
          Application: name,
          PathnameAdjuster: adjuster,
          CacheTime: 5000,
          ShowDebug: '%_ShowDebug_%',
          Stdout: '%_Stdout_%',
          Stream: '%_Stream_%',
          DbPlugins: false,
          ReleaseDt: '%_ReleaseDt_%'//'2011/09/30 19:40'
          }, opt);
          // pathname adjuster
          function adjuster(pn) {
          if(~pn.indexOf(pfix))
          pn = pn.replace(pfix, '');
          return pn.replace(fix, '');
          }
          //install modules
          var alw = 'htmlgen tablify bootstrap'.split(" ");
          app.prepare('*', alw.concat({
          name: 'Cloudplus_GoogleAnalytics',
          type: 'googleanalytics',
          pack: {
          Default: {
          account: 'UA-17879446-6',
          domain_name: 'cloudplus.me'
          }
          }
          }));
          //titles
          var c = 'Party Goods + me.', Titles = {
          home: {
          en: c + ' ~ Lets\'s get pirty goods!',
          ja: c + ' ~ パーティーゲームで会を盛り上げよう!'
          }
          };
          var keywords = ['Party Goods', 'game', 'party', 'plus', 'me', 'cloud'], descriptions = {
          en: 'Variety of party goods and games for free!',
          ja: 'パーティーグッズ + me で無料の盛り上げツールが手に入る!'
          };
          var lnOrEn = function(tgt, ln) {
          return tgt[ln] || tgt['en'];
          };
          //pages
          var Pages = {
          home: {
          path: '/',
          title: function(ln) {
          return lnOrEn(Titles.home, ln);
          }
          },
          rp: {
          path: '/rp/',
          title: function(ln) {
          return lnOrEn(Titles.home, ln);
          }
          }
          };
          //setting function
          function opt() {
          return {
          '*': {
          // html: ['', ''],
          title: getTitle,
          meta: getMeta,
          rel: getRel,
          css: getCss,
          body: getBody,
          svrjs: getSvrjs,
          wssjs: null,
          fstjs: null,
          bwsjs: getBwsjs,
          //nojs: false,
          cacheKey: getCacheKey,
          // stack: undefined,
          // contentType: 'text/html',
          // charset: null,
          // convert: false
          }
          };
          };
          //title
          function getTitle(res, loc, nav) {
          if(pfix && loc.host.indexOf(pfix.substr(1)) == -1)
          fix = pfix + fix, pfix = '';
          foonyah.simplePages.call(this, Pages, {
          prefix: pfix,
          fix: fix
          });
          return foonyah.simpleTitle.call(this, loc, nav);
          }
          //meta
          function getMeta(res, loc, nav) {
          var ln = nav.language, dev = nav.Device;
          var com = ', initial-scale=1.0, minimum-scale=1.0';
          // meta
          var meta = {
          'http-equiv': [["Cache-Control", "public"]],
          'name': [["robots", "INDEX,FOLLOW"], ["keyword", keywords.join(',')],
          ["description", lnOrEn(descriptions, ln)]]
          };
          // device view port
          if(dev == 'tablet' || dev == 'mobile')
          meta.name.push(["viewport", "width=device-width" + com]);
          return meta;
          }
          //rel
          function getRel(res, loc, nav) {
          var rel = {
          src: {
          'css/images/': [['shortcut icon', 'icon.png', 'image/ico'],
          ['apple-touch-icon', 'icon.png', 'image/png']]
          }
          };
          return rel;
          }
          //css
          function getCss(res, loc, nav) {
          return foonyah.simpleSourceHash.call(this, loc, nav, 'css');
          };
          //body
          function getBody(res, loc, nav) {
          var c = 'class="' + (nav.Compatibility === true ? '': 'no-') + 'html5' + '"';
          return [''];
          }
          //server-side js
          function getSvrjs(res, loc, nav) {
          return foonyah.simpleSourceHash.call(this, loc, nav, 'svrjs');
          };
          //browser-side js
          function getBwsjs(res, loc, nav) {
          var jq = '/jQuery/jquery-';
          var fn = function(key, box, dir, def_fn) {
          box.src[jq] = ['easing.1.3', 'gestures.1.0.1'];
          var jss = key == 'rp' ? ['index-rp']: [];
          def_fn(jss.concat('index'));
          };
          return foonyah.simpleSourceHash.call(this, loc, nav, 'bwsjs', fn);
          }
          //cache
          function getCacheKey(loc, nav) {
          var ck = loc._pathname + ':' + nav.Device + ':'
          + (loc.query.ln || nav.language);
          return foonyah.debug('Use cache key: ' + ck), ck;
          }
          • 説明
            setting.js はアプリケーションごとに指定するファイルです。 foonyah.start() により起動したシステムは、最も単純なコンテンツの seek (探索) に失敗した場合、この setting.js に基づいた実行プロセスを開始します。
            全てのコンテンツは動的に生成可能でありながら、適切にキャッシュされることで集中アクセス時の負荷を軽減します。