Browse Source

first commit

HonorLee 8 years ago
commit
44c9411c24
10 changed files with 415 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 0 0
      README.md
  3. 44 0
      config.js
  4. 22 0
      core/lib/Logger.js
  5. 50 0
      core/lib/router.js
  6. 56 0
      core/lib/static.js
  7. 125 0
      handler/api.js
  8. 29 0
      handler/jumper.js
  9. 66 0
      main.js
  10. 21 0
      package.json

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules/
+log/

+ 0 - 0
README.md


+ 44 - 0
config.js

@@ -0,0 +1,44 @@
+/** Core Configs **/
+global.URL      = require('url');
+global.FILE     = require('fs-extra');
+global.Format   = require('util').format;
+// global.EJS  = require('ejs');
+
+//Core Paths
+global.LIBPATH      = ROOTPATH+'/core/lib';
+global.HELPERPATH   = ROOTPATH+'/core/helper';
+global.HANDLERPATH  = ROOTPATH+'/handler';
+global.LOGPATH      = ROOTPATH+'/log',
+
+//Init Path
+FILE.mkdirsSync(LOGPATH);
+
+//Core Libs
+global.Logger = require(LIBPATH+'/Logger.js');
+global.ROUTER = require(LIBPATH+'/router.js');
+global.STATIC = require(LIBPATH+'/static.js');
+global.JUMPER = require(HANDLERPATH+'/jumper.js');
+global.APIHandle = require(HANDLERPATH+'/api.js');
+
+global.CONFIG = {
+
+    //DatabasePath:ROOTPATH+'/fulldata.db',
+    // LOGPATH:ROOTPATH+'/log',
+    //SnifferJsHandler:HANDLERPATH+'/sniffer/sniffer.js',
+    //StaticRules:['js','img','css','favicon.ico'],
+    StaticRules:{'static':true,'images':true,'robots.txt':true,'crossdomain.xml':true,'favicon.ico':true},
+    HandlerRules:{'user':true,'index':true}
+}
+
+global.COUNT = {
+    LinkDefault:415,       //Default Start For 1A0(HEX)=416
+    link:0,
+    user:0
+}
+
+/** Online Mongodb **/
+// global.MongoURL = 'mongodb://l2sServer:129810lh@dds-bp10931c06c465142.mongodb.rds.aliyuncs.com:3717/l2s';
+
+/** Localhost Mongodb **/
+global.MongoURL = 'mongodb://localhost:27017/l2s';
+

+ 22 - 0
core/lib/Logger.js

@@ -0,0 +1,22 @@
+/** Logger **/
+const tracer = require('tracer').dailyfile({root:LOGPATH,format : "{{timestamp}} <{{title}}> {{file}}:{{line}} {{message}}", dateformat : "HH:MM:ss.L"});
+
+var Logger = {
+    log:function(msg,toFile){
+        console.log('[LOG]',msg);
+        if(toFile) this.out(msg);
+    },
+    error:function(msg,toFile){
+        console.log('\x1B[31m[ERROR]',msg,'\x1B[39m');
+        if(toFile) this.out(msg);
+    },
+    info:function(msg,toFile){
+        console.log('\x1B[32m[INFO]',msg,'\x1B[39m');
+        if(toFile) this.out(msg);
+    },
+    out:function(msg){
+        tracer.log(msg);
+    }
+}
+
+module.exports = Logger;

+ 50 - 0
core/lib/router.js

@@ -0,0 +1,50 @@
+var Router ={
+    go:function(url,res,req){
+        var URLParse = URL.parse(url,true);
+        var URLArr = URLParse.pathname.split('/');
+        var query = URLParse.query;
+        //console.log(query);
+        // console.log(URLArr[1]);
+        if(CONFIG.HandlerRules[URLArr[1]]){
+            return Router.getHandler(url,res,req);
+        }else if(CONFIG.StaticRules[URLArr[1]]){
+            //Router._error();
+            //return;
+            return STATIC.load(ROOTPATH+URLParse.pathname,query,res);
+        }else{
+            // Router._error('Router Go ERROR:'+url,res);
+            // Logger.error(url+' request error!');
+            JUMPER.go(url,URLArr[1],res);
+        }
+        
+    },
+    getHandler:function(url,res,req){
+        var URLParse = URL.parse(HANDLERPATH+url,true);
+        var URLArr = URLParse.pathname.split('/');
+//console.log(URLArr)
+        if(URLArr[URLArr.length-1]=='') URLArr[URLArr.length-1]='index';
+        var FileName = URLArr.join('/')+'.js';
+        var mod,call='index';
+        if(!FILE.existsSync(FileName)){
+            call = URLArr.pop();
+            FileName = URLArr.join('/')+'.js';
+        }
+        //console.log(FileName);
+        // console.log(url);
+        try{
+            mod = require(FileName);
+            mod[call](res,req,URLParse.query);
+        }catch(err){
+            Logger.error(url+' load error');
+            Logger.out(err);
+            res.writeHead(404, {'Content-Type': 'text/html'});
+            res.end('404');
+        }
+    },
+    _error:function(log,res,req){
+        res.writeHead(404, {'Content-Type': 'text/html'});
+        res.end();
+    }
+}
+
+module.exports = Router;

+ 56 - 0
core/lib/static.js

@@ -0,0 +1,56 @@
+var Path = require('path');
+var mime = require('mime-types');
+var ZLIB = require('zlib');
+var Static = {
+    load:function(url,query,res){
+        var ext = Path.extname(url);
+        if(!ext||ext==''){
+            res.writeHead(404, {'Content-Type': 'text/html'});
+            res.end();
+            return false;  
+        }
+        if(ext.match(/png|jpg|jpeg|gif/)){
+            res.writeHead(404, {'Content-Type': 'text/html'});
+            res.end(404);
+            //return IMAGE.load(URL.parse(REQUEST.url,true).pathname,ext,query,res);
+        }else if(FILE.existsSync(url)){
+            var data;
+            if(ext.match(/txt|js|css|html|json/)){
+                try{
+                    data = FILE.readFileSync(url,'utf-8');
+                }catch(err){
+                    res.writeHead(404, {'Content-Type': 'text/html'});
+                    res.end();
+                    return false;            
+                }
+                if(ext.match(/json/)){
+                    res.writeHead(200, { "Content-Type": mime.lookup(ext)+';charset=utf-8'});
+                    res.end(data,'utf-8');
+                }else{
+                    res.writeHead(200, { "Content-Type": mime.lookup(ext)+';charset=utf-8','Content-Encoding':'gzip'});
+                    res.end(ZLIB.gzipSync(data),'utf-8');
+                }
+                 //console.log(query)   
+            }else if(ext.match(/json/)){
+            }else{
+                try{
+                    data = FILE.readFileSync(url,'binary');
+                }catch(err){
+                    res.writeHead(404, {'Content-Type': 'text/html'});
+                    res.end();
+                    return false;            
+                }
+                res.writeHead(200, { "Content-Type": mime.lookup(ext),"Access-Control-Allow-Origin":"*"});
+                res.end(data,'binary');
+            }
+            return true;
+            
+        }else{
+            res.writeHead(404, {'Content-Type': 'text/html'});
+            res.end();
+            return false;
+        }
+    }
+}
+
+module.exports=Static;

+ 125 - 0
handler/api.js

@@ -0,0 +1,125 @@
+const query  = require("querystring");
+const base64 = require('js-base64').Base64;
+
+var API = {
+    parse:function(req,res){
+        var url = req.url;
+        var URLParse = URL.parse(url,true);
+        var URLArr = URLParse.pathname.split('/');
+        //Only GET
+        req.param = URLParse.query;
+        // console.log(URLParse.query);
+        API._checkRouter(URLArr[1],req,res);
+        // }else{
+        //     var postdata = "";
+        //     req.addListener("data",function(postchunk){
+        //         postdata += postchunk;
+        //     })
+
+        //     //POST结束输出结果
+        //     req.addListener("end",function(){
+        //         req.param = query.parse(postdata);
+        //         API._checkRouter(URLArr[1],req,res);
+        //     })
+        // }
+    },
+    _checkRouter:function(path,req,res){
+        // console.log(req.param);
+        switch(path){
+            case 'getlink':
+                if(req.param['key'] && req.param['key']!='' && req.param['url'] && req.param['url']!=''){
+                    UserDB.findOne({key:req.param['key']},function(err,data){
+                        if(!err && data){
+                            var oldLink = req.param['url'];
+                            if(req.param['base64'] && req.param['base64']==0){
+                                if(oldLink.match(/http:\/\//)){
+                                    MongoHandler.getlink(req.param['key'],oldLink,res);
+                                }else{
+                                    API._onError(ErrorMsg.URL_WRONG,res);
+                                    return;
+                                }
+                            }else{
+                                oldLink = base64.decode(oldLink);
+                                if(oldLink.match(/http:\/\//)){
+                                    MongoHandler.getlink(req.param['key'],oldLink,res);
+                                }else{
+                                    API._onError(ErrorMsg.URL_WRONG,res);
+                                    return;
+                                }
+                            }
+                        }else{
+                            API._onError(ErrorMsg.KEY_WRONG,res);
+                        }
+                    });
+                }else{
+                    if(!req.param['key']){
+                        API._onError(ErrorMsg.KEY_LOST,res);
+                        return;
+                    }
+                    if(!req.param['url']){
+                        API._onError(ErrorMsg.URL_LOST,res);
+                        return;
+                    }
+                }
+                break;
+            case 'check':
+                break;
+            default:
+                res.writeHead(404, {'Content-Type': 'text/html'});
+                res.end('404');
+        }
+    },
+    _onError:function(msg,res){
+        var data = {success:0,msg:msg,short:'',long:''};
+        res.writeHead(200, {'Content-Type': 'text/json'});
+        res.write(JSON.stringify(data));
+        res.end();
+    }
+}
+
+var MongoHandler = {
+    getlink:function(key,url,res){
+        var baseLink;
+        baseLink = base64.encode(url);
+        // console.log(baseLink,newLink);
+        LinkDB.findOne({long:baseLink},function(err,oldOne){
+            if(!err){
+                var data = {success:1,msg:'',short:'http://l2s.ch/',long:url};
+                if(oldOne){
+                    data.short += oldOne.short;
+                    res.writeHead(200, {'Content-Type': 'text/json'});
+                    res.write(JSON.stringify(data));
+                    res.end();
+                }else{
+                    var newLink,count = COUNT.link+1;
+                    newLink = count.toString(16);
+                    LinkDB.update({key:key,long:baseLink},{$set:{short:newLink}},{upsert:true},function(err,result){
+                        if(!err && result){
+                            data.short += newLink;
+                            res.writeHead(200, {'Content-Type': 'text/json'});
+                            res.write(JSON.stringify(data));
+                            res.end();
+                            COUNT.link++;
+                            CountDB.update({},{$inc:{link:1}},{upsert:true});
+                        }else{
+                            API._onError(ErrorMsg.MAKE_ERROR,res);
+                        }
+                    });
+                }
+            }else{
+                API._onError(ErrorMsg.MAKE_ERROR,res);
+            }
+        });
+    }
+}
+
+const ErrorMsg = {
+    NONE:'',
+    KEY_LOST    :'Key is missing',
+    KEY_WRONG   :'Key is incorrect',
+    URL_LOST    :'URL is missing ',
+    URL_WRONG   :'URL must start with "http://"',
+    MAKE_ERROR  :'Short link generate error,please contact with l2s.ch'
+}
+
+module.exports = API;

+ 29 - 0
handler/jumper.js

@@ -0,0 +1,29 @@
+const base64 = require('js-base64').Base64;
+
+var Jumper = {
+    go:function(url,uri,res){
+        if(uri&&uri!=''){
+            LinkDB.findOne({short:uri},function(err,data){
+                if(!err && data){
+                    var link = data['long'];
+                    link = base64.decode(link);
+                    res.writeHead(301, {'Location': link});
+                    res.end();
+                }else{
+                    Jumper._error(url,res);
+                }
+            });
+        }else{
+            Jumper._error(url,res);
+        }
+    },
+    _error:function(url,res){
+        Router._error('Router Go ERROR:'+url,res);
+        Logger.error(url+' request error!');
+        res.writeHead(404, {'Content-Type': 'text/html'});
+        res.end('404');
+    }
+}
+
+
+module.exports = Jumper;

+ 66 - 0
main.js

@@ -0,0 +1,66 @@
+/** Initialization Libs/Databases **/
+// Load Library of node
+const http = require('http');
+
+// Load Core & Variables
+global.ROOTPATH = __dirname;
+require('./config.js');
+
+
+//Init Mongo Database & start server
+require('mongodb').MongoClient.connect(MongoURL,function(err,db){
+    if(err) {
+        Logger.error('MongoDB connect error!',true);
+        Logger.error('Server start failed. Log has been saved!');
+        Logger.out(err);
+        return;
+    }
+    global.MongoDB = db;
+    // global.tracerDB = db.collection('usertracer');
+    global.CountDB = db.collection('count');
+    global.LinkDB = db.collection('link');
+    global.UserDB = db.collection('user');
+    
+//Start Services
+    Init();
+});
+
+/** Init Web & API Server **/
+function Init(){
+    // CountDB.update({},{$inc:{link:1}},{upsert:true});
+    CountDB.findOne({},function(err,data){
+        if(data && data['link']){
+            COUNT.link = Number(data['link']);
+        }else{
+            COUNT.link = COUNT.LinkDefault;
+            CountDB.update({},{$set:{link:COUNT.link}},{upsert:true});
+        }
+
+        require('http').createServer(WebServer).listen(3230);
+        require('http').createServer(APIServer).listen(3231);
+
+        Logger.info('MongoDB connected!',true);
+        Logger.info('Web Server Start at port:['+3230+']',true);
+        Logger.info('API Server Start at port:['+3231+']',true);
+        Logger.log('\n------------------[Count]------------------\nLink:['+(COUNT.link-COUNT.LinkDefault)+']\tUser:['+COUNT.user+']\n-------------------------------------------',true);
+    });
+
+}
+
+//Web Server
+function WebServer(req,res){
+    var COOKIE = {};
+    req.headers.cookie && req.headers.cookie.split(';').forEach(function( Cookie ) {
+        var parts = Cookie.split('=');
+        COOKIE[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
+    });
+    var requestFile = req.url=='/'?'/index':req.url;
+    req.cookie = COOKIE;
+    ROUTER.go(requestFile,res,req,COOKIE);
+}
+
+
+//API Server
+function APIServer(req,res){
+    APIHandle.parse(req,res);
+}

+ 21 - 0
package.json

@@ -0,0 +1,21 @@
+{
+  "name": "L2S.ch",
+  "version": "1.0.0",
+  "description": "Long To Short Link Generate",
+  "main": "main.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "dependencies": {
+    "tracer":">=0.8.0",
+    "mongodb":"latest",
+    "fs-extra":"latest",
+    "mime-types":"latest",
+    "js-base64":"latest"
+  },
+  "engines": {
+    "node": ">=0.12.5"
+  },
+  "author": "HonorLee",
+  "license": "ISC"
+}