понедельник, 20 апреля 2015 г.

Node JS - Полные Client и Server

Клиент

Файл initRequest.js

var request = require('./request');
var cheerio = require('cheerio');

var data = JSON.stringify({
      'key1': 'value1'
    , 'key2': 'value2'
});

request.httpRequest({
      host: '127.0.0.1'
    , port: 80
    , url: '/'
    , username: 'boris'
    , password: '12345'
    , type: 'get'
    , cache: false
    , headers: {
                          'Content-Type': 'application/x-www-form-urlencoded'
                        , 'Content-Length': data.length
                    }
    , data: data
    , dataType: 'html'
    , timeout: 120000
    , success: function (data) {
        var $ = cheerio.load(data);
        console.log('Request body text inside <p></p>: ' + $('p').first().text());
      }
    , error: function (error) {console.log('New request error');}
});

Файл request.js

var http = require('http');

function randomNumber (min, max) {
    min = parseInt(min, 10);
    max = parseInt(max, 10);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

var commonHeaders = {
      'Accept': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.' + randomNumber(2, 5)
    , 'Accept-Language': 'en-us,en;q=0.' + randomNumber(5, 9)
    , 'Accept-Charset': 'utf-8,windows-1251;q=0.7,*;q=0.' + randomNumber(5, 7)
    , 'Keep-Alive': '300'
    , 'Expect': ''
};

function httpRequest (options) {
    options = options || {};

    if (!options.hasOwnProperty('host')) {options.host = 'localhost';}
    if (!options.hasOwnProperty('port')) {options.port = 80;}
    if (!options.hasOwnProperty('url')) {options.url = '/';}
    if (!options.hasOwnProperty('type')) {options.type = 'GET';}
    if (!options.hasOwnProperty('headers')) {options.headers = {};}
    if (!options.hasOwnProperty('username')) {options.username = '';}
    if (!options.hasOwnProperty('password')) {options.password = '';}
    if (!options.hasOwnProperty('data')) {options.data = {};}
    if (!options.hasOwnProperty('dataType')) {options.dataType = 'text';}
    if (!options.hasOwnProperty('cache')) {options.cache = true;}
    if (!options.hasOwnProperty('timeout')) {options.timeout = 120000;}
    if (!options.hasOwnProperty('success')) {options.success = function(){};}
    if (!options.hasOwnProperty('error')) {options.error = function(error){console.log('Request error: ' + error);};}

    for (var key in options.headers) {
        commonHeaders[key] = options.headers[key];
    }
    
    options.type = options.type.toUpperCase();
    
    if (options.type === 'GET' && options.data.length > 0) {
        options.url += '?' + options.data;
    }
    
    if (options.cache === false) {
        options.url += ( (/\?/).test(options.url) ? '&' : '?' ) + "_=" + randomNumber(1000000000, 9999999999);
    }
    
    if (options.data.length > 0 && options.headers['Content-Type'] === undefined) {
        options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }

    var requestOptions = {
          hostname: options.host
        , port: options.port
        , path: options.url
        , method: options.type
        , headers: options.headers
    };
    
    if (options.username !== '') {
        requestOptions.auth = options.username + ':' + options.password;
    }

    var request = http.request(requestOptions, function(response) {
        console.log('Response status code: ' + response.statusCode);
        console.log('Response headers: ' + JSON.stringify(response.headers));
        response.setEncoding('utf8');
        var data = '';
        response.on('data', function(chunk){
            data += chunk;
        });
        response.on('end', function(){
            if (options.dataType === 'json') {
                data = JSON.parse(data);
            }
            options.success(data);
        });
    });

    request.setTimeout(options.timeout, function(){
        request.abort();
        console.log('Request timeout');
    });
    
    request.on('error', options.error);

    // write data to request body
    if (options.type === 'POST' && options.data.length > 0) {
        request.write(options.data);
    }
    request.end(); // Always need to write request.end();
}

exports.httpRequest = httpRequest;

Сервер

Файл startServer.js

var http = require('http')
    , url = require('url')
    , router = require('./router');

function onRequest (request, response) {
    console.log('Request received.');
    
    var pathname = url.parse(request.url).pathname
        , postData = '';
        
    request.setEncoding('utf8');
    
    request.addListener('data', function(postDataChunk){
        postData += postDataChunk;
        console.log('Received POST data chunk ' + postDataChunk);
    });
    
    request.addListener('end', function(){
        router(pathname, request, response, postData);
    });
}

http.createServer(onRequest).listen(80);

console.log('Server has started at 127.0.0.1:80');

Файл router.js

var urls = require('./urls');

function router (pathname, request, response, postData) {
    console.log('pathname: ' + pathname);
    if (pathname.length > 1 && pathname.slice(-1) === '/') {
        pathname = pathname.slice(0, -1);
    }
    console.log('pathname after slice: ' + pathname);
    if (typeof urls[pathname] === 'function') {
        return urls[pathname](request, response, postData);
    } else {
        console.log('No request urls for ' + pathname);
        urls['404'](request, response, postData);
    }
}

exports.router = router;

Файл urls.js

var requestHandlers = require('./requestHandlers')
    , urls = {};
    
urls['/'] = requestHandlers.start;
urls['/start'] = requestHandlers.start;
urls['/upload'] = requestHandlers.upload;
urls['/form'] = requestHandlers.form;
urls['/send'] = requestHandlers.send;
urls['/upload_file_form'] = requestHandlers.uploadFileForm;
urls['/receive_file'] = requestHandlers.receiveFile;
urls['/show'] = requestHandlers.show;
urls['/send_html'] = requestHandlers.sendHTML;
urls['404'] = requestHandlers.notFound;

exports.urls = urls;

Файл requestHandlers.js

var querystring = require('querystring')
    , fs = require('fs')
    , exec = require('child_process').exec;
    
function sleep (milliseconds) {
    var startTime = (new Date()).getTime()
        , endTime = startTime + milliseconds;
    while ((new Date()).getTime() < endTime) {}
}
    
var requestHandlers = {
      start: function (request, response, postData) {
        console.log('Request "start" was called.');
        sleep(5000);
        response.writeHead(200, {'Content-Type': 'text/plain', 'Cache-Control': 'max-age=3600'});
        response.setHeader('name', 'value');
        response.removeHeader('name', 'value');
        response.write('Hello!');
        response.write(' | pathname: ' + pathname);
        if (postData) {response.write(postData);}
        response.end(' | The end.');
      }
      
    , upload: function (request, response, postData) {
        console.log('Request "upload" was called.');
        var content = 'empty';
        exec('dir', function(error, stdout, stderr){
            content = stdout;
            console.log(1);
        });
        console.log(2);
        return content;
      }
      
    , form: function (request, response, postData) {
        var html = '<!doctype html><html><head><meta charset="utf-8" /><title>FORM</title></head><body><form method="post" action="/send"><textarea name="text" rows="20" cols="60"></textarea><input type="submit" value="Send text" /></form></body></html>';
        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write(html);
        response.end();
      }
      
    , send: function (request, response, postData) {
        console.log('Request urlsr "send" was called.');
        var query = querystring.parse(postData).text;
        response.writeHead(200, {'Content-Type': 'text/plain'});
        response.write('You sent: ' + query);
        response.end();
      }
      
    , uploadFileForm: function (request, response, postData) {
        var html = '<!doctype html><html><head><meta charset="utf-8" /><title>FORM</title></head><body><form method="post" enctype="multipart/form-data" action="/receive_file"><input type="text" name="title" /><br /><input type="file" name="upload" /><br /><input type="submit" value="Upload" /></form></body></html>';
        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write(html);
        response.end();
      }
      
    , receiveFile: function (request, response, postData) {
        if (request.method.toLowerCase() === 'post') {
            response.writeHead(200, {'Content-Type': 'text/plain'});
            response.write('File uploaded');
           
            response.end();
        }
      }
      
    , show: function(request, response, postData) {
        console.log('Request urlsr "show" was called.');
        fs.readFile('./tmp/test.png', 'binary', function(error, fileData){
            if (error) {
                response.writeHead(500, {'Content-Type': 'text/plain'});
                response.write(error + '\n');
                response.end();
            } else {
                response.writeHead(200, {'Content-Type': 'image/png'});
                response.write(fileData, 'binary');
                response.end();
            }
        });
      }
      
    , sendHTML: function (request, response, postData) {
        console.log('Request urlsr "sendHTML" was called.');
        fs.readFile('./tmp/index.html', function(error, fileData){
            if (error) {
                response.writeHead(500, {'Content-Type': 'text/plain'});
                response.write(error + '\n');
                response.end();
            } else {
                response.writeHead(200, {'Content-Type': 'text/html'});
                response.write(fileData);
                response.end();
            }
        });
      }
      
    , notFound: function (request, response, postData) {
        console.log('Request "404 - Not Found" was called.');
        response.writeHead(404, {'Content-Type': 'text/plain'});
        response.write('404 Not found');
        response.end();
      }
      
};

exports.requestHandlers = requestHandlers;

Файл filesystem.js

// НЕ ЗАБЫТЬ ЧТО ВЕСЬ КОД РАБОТАЕТ АСИНХРОННО

var fs = require('fs');

// Создать
var fileNameAndPath = './tmp/test.txt'
    , fileData = 'Hello!';
    
fs.writeFile(fileNameAndPath, fileData, function (error) {
    if (error) {throw error;}
    console.log('Done');
});

// Прочитать
fs.exists(fileNameAndPath, function(exists){
    if (exists) {
        fs.stat(fileNameAndPath, function(error, stats){
            fs.open(fileNameAndPath, 'r', function(error, fileData){
                if (error) {throw error;}
                var readBuffer = new Buffer(stats.size)
                    , bufferOffset = 0
                    , bufferLength = readBuffer.length
                    , filePosition = 0;
                fs.read(fileData, readBuffer, bufferOffset, bufferLength, filePosition, function(error, readBytes){
                    if (error) {throw error;}
                    var fileDataChunk = readBuffer.toString('utf8', 0, bufferLength);
                    console.log(fileDataChunk);
                    console.log(readBuffer.slice(0, readBytes));
                    fs.close(fileData);
                });
            });
        });
    }
});

// Записать
fs.exists(fileNameAndPath, function(exists){
    if (exists) {
        fs.open(fileNameAndPath, 'a', function(error, fileData){
            if (error) {throw error;}
            var writeBufferData = new Buffer(' World!')
                , bufferPosition = 0
                , bufferLength = writeBufferData.length
                , filePosition = 0;
            fs.write(fileData, writeBufferData, bufferPosition, bufferLength, filePosition, function(error, written){
                if (error) {
                    throw error;
                } else {
                    fs.close(fileData, function(){
                        console.log('Wrote ' + written + ' bytes.');
                    });
                }
            });
        });
    }
});

// Переименовать
var oldPath = './tmp/test.txt'
    , newPath = './tmp/newtest.txt';

fs.rename(oldPath, newPath, function (error) {
    // В Windows возможна ошибка при попытке переименования уже существующего файла
    if (error) {
        // throw error;
        fs.unlink(newPath);
        fs.rename(oldPath, newPath);
    }
    console.log('Done');
});

// Удалить
fs.unlink(newPath, function (error) {
    if (error) {throw error;}
    console.log('Done');
});

Файл index.html

<html><head><title>Zagolovok</title></head></body>Telo</body></html>