Базовое Node.JS приложение с использованием express

Всем привет.
Искал статью, как сделать базовое Node.JS приложение с использованием express, точнее какая базовая структура должна быть у проекта, но так ничего похожего для меня не нашел.
Потому решил написать собственную, дабы объяснить таким же как и я как это сделать и как это должно выглядеть.

Подробности под катом. Осторожно. Много текста и кода.

Перед тем как начать, хочу отметить, что это моя первая статья. Я, быть может, что-то не учту, или наоборот, акцентирую на чем-то больше внимания, буду благодарен за поправки и уточнения по статье, а также подходу.

Задача была следующей: сделать базовое приложение, которое смогло бы обрабатывать запросы, и выводить правильные страницы, либо же правильные ответы на запросы.

Итак. Начнем, пожалуй, с используемых модулей внутри приложения:

express - базовый пакет, для создания http-сервера mongoose - фреймверк, для удобной работы с MongoDB mongodb - native-driver для работы с MongoDB напрямую connect-mongo - нужно для работы express с session node-uuid - для генерирования токенов для авторизации (в случае использования веб-сервисов) async - для работы с цепочкой асинхронных вызовов, ака Promise ejs-locals - движок рендеринга, который поддерживает наследование шаблонов nconf - для удобной работы с настройками приложения (собственный config.json) string - для более удобной работы со строками, также очистка строк от ненужных вещей, типа html тегов и тд validator - валидация данных winston - для продвинутого логирования ошибок 

Каждый из модулей можно установив используя команду:
npm install <<module_name>> —save

—save нужен для сохранения модуля в dependency (package.json), для дальнейшего развертывания приложения на других машинах.

Структура приложения получается следующей:

	/config 		config.json 		index.js 	/middleware 		checkAuth.js 		errorHandler.js 		index.js 	/models 		user.js 	/public 		/*JS, CSS, HTML static files*/ 	/routes 		authentication.js 		error.js 		index.js 		main.js 		register.js 	/utils 		index.js 		log.js 		mongoose.js 		validate.js 	/views 		index.ejs 	manage.js 	package.json 	server.js 

Сейчас, собственно говоря, объясню в чем соль каждой из директорий и ее скриптов.
Начнем с самого главного скрипта, инициирующего все наше приложение.

server.js

var express = require('express'),     middleware = require('./middleware'),     http = require('http'),     app = express(),     config = require('./config'),     log = require('./utils/log')(app, module);  middleware.registerMiddleware(app, express);  http.createServer(app).listen(config.get('port'), function(){     log.info('Express server listening on port ' + config.get('port')); }); 

В server.js создаем приложение epxress app, подключаем модуль middleware, в методе registerMiddleware подключаются все нужные middleware приложения.
Дальше создаем сервер, который будет обрабатывать все входящие подключения через порт, который указан в конфиге.

package.json

{   "name": "test_express_app",   "version": "0.0.1",   "private": true,   "scripts": {     "start": "node server.js"   },   "dependencies": {     "express": "~3.4.6",     "mongoose": "~3.8.1",     "node-uuid": "~1.4.1",     "nconf": "~0.6.9",     "winston": "~0.7.2",     "async": "~0.2.9",     "mongodb": "~1.3.22",     "ejs-locals": "~1.0.2",     "connect-mongo": "~0.4.0",     "validator": "~2.0.0",     "string": "~1.7.0"   } }  

Содержит в себе всю нужную информацию о проекте, а также все требуемые пакеты.

manage.js

var mongoose = require('./utils/mongoose'),     async = require('async'),     User = require('./models/user'),     log = require('./utils/log')(null, module),     config = require('./config');  function openConnection(cb) {     mongoose.connection.on('open', function () {         log.info('connected to database ' + config.get('db:name'));         cb();     }); }  function dropDatabase(cb) {     var db = mongoose.connection.db;     db.dropDatabase(function () {         log.info('dropped database ' + config.get('db:name'));         cb();     }); }  function createBaseUser(cb) {     var admin = new User({         username: 'admin',         password: config.get('project:admin:password'),         email: config.get('project:admin:email'),         role: 1     });     admin.save(function () {         log.info('created database ' + config.get('db:name'));         log.info('created base admin user');         cb();     }); }  function ensureIndexes(cb) {     async.each(Object.keys(mongoose.models), function (model, callback) {         mongoose.models[model].ensureIndexes(callback);     }, function () {         log.info('indexes ensured completely');         cb();     }); }  function closeConnection() {     mongoose.disconnect();     log.info('disconnected'); }  async.series(     [         openConnection,         dropDatabase,          createBaseUser,          ensureIndexes     ],     closeConnection ); 

Нужен для инициализации базы данных, заполнение default информацией, которой сервер будет оперировать.

config

config.json

{ 	"port": 3000,     "db": {         "connection": "mongodb://localhost",         "name": "db_name",         "options": {             "server": {                 "socketOptions": {                     "keepAlive": 1                 }             }         }     },     "session": {         "secret": "secret_key",         "key": "cid",         "cookie": {             "path": "/",             "httpOnly": true,             "maxAge": null         }     } } 

index.js

var nconf = require('nconf'); var path = require('path');  nconf.argv()     .env()     .file({file: path.join(__dirname, 'config.json')});  module.exports = nconf; 

В файле config.js содержится информация о настройках соединения с базой данных, а также настройки сессии.
Для работы с config используется пакет nconf, который позволяет через getter и setter манипулировать с объектом настроек. Также можно использовать вложенные объекты через символ ::

config.get('session:secret'); config.get('session:cookie:path'); 

middleware

exports.registerMiddleware = function (app, express) {     var ejs = require('ejs-locals'),         path = require('path'),         config = require('../config'),          mongoose = require('../utils/mongoose'),         MongoStore = require('connect-mongo')(express),          router = require('../routes'),         errorHandler = require('./errorHandler')(app, express),          checkAuth = require('./checkAuth');      /**      * Page Rendering      * */     app.engine('html', ejs);     app.engine('ejs', ejs);     app.set('views', path.join(__dirname, '../views'));     app.set('view engine', 'ejs');       /**      * Public directory      * */     app.use(express.static(path.join(__dirname, '../public')));     app.use("/public", express.static(path.join(__dirname, '../public')));       /**      * Favicon      * */     app.use(express.favicon('public/images/favicon.ico'));       /**      * Logger      * */     if (app.get('env') == 'development') {         app.use(express.logger('dev'));     }       /**      * Session      * */     app.use(express.bodyParser());     app.use(express.cookieParser());     app.use(express.session({         secret: config.get('session:secret'),         key: config.get('session:key'),         cookie: config.get('session:cookie'),         store: new MongoStore({mongoose_connection: mongoose.connection})     }));      /**      * Authorization Access      * */     app.use(checkAuth);       /**      * Routing      * */     app.use(app.router);     router(app);       /**      * Error handing      * */     app.use(errorHandler); }; 

Таким образом будем подключать все middleware не засоряя основную часть кода сервера, быть может, ее прийдется расширить, по ходу написания приложения.

Хочу также отметить — errorHandler middleware предназначен для собственного handling ошибок сервера, и вывода страницы ошибки

errorHandler

var config = require('../config');  var sendHttpError = function (error, res) {     res.status(error.status);      if (res.req.headers['x-requested-width'] === 'XMLHttpRequest') {         res.json(error);     } else {         res.render('error', {             error: {                 status: error.status,                 message: error.message,                 stack: config.get('debug') ? error.stack : ''             },             project: config.get('project')         });     } };  module.exports = function (app, express) {     var log = require('../utils/log')(app, module),         HttpError = require('../error').HttpError;      return function(err, req, res, next) {         if (typeof err === 'number') {             err = new HttpError(err);         }         if (err instanceof HttpError) {             sendHttpError(err, res);         } else {             if (app.get('env') === 'development') {                 express.errorHandler()(err, req, res, next);             } else {                 log.error(err);                 err = new HttpError(500);                 sendHttpError(err, res);             }         }     }; }; 

Также хочется отметить middleware checkAuth

var HttpError = require('../error').HttpError;  module.exports =  function (req, res, next) {     if (!req.session.user) {         return next(new HttpError(401, "You are not authorized!"));     }     next(); }; 

Который будет проверять запросы на наличие сессии и, в случае ее отсутствия, будет бросать ошибку. Его можно использовать как глобальный middleware или же указать конкретно метод, где он будет использоваться:

app.get('/user-info', checkAuth, function (req, res, next) {     //do your staff }); 

models

C помощью Mongoose мы будем создавать собственные модели для работы с данными. Пример модели может выглядеть следующим образом:

var crypto = require('crypto'),     mongoose = require('../utils/mongoose'),     Schema = mongoose.Schema,     async = require('async');  var User = new Schema({     username: {         type: String,         unique: true,         required: true     },     hashedPassword: {         type: String,         required: true     },     salt: {         type: String,         required: true     } });  User.methods.encryptPassword = function (password) {     return crypto.createHmac('sha1', this.salt).update(password).digest('hex'); };  User.virtual('password')     .set(function (password) {         this._plainPassword = password;         this.salt = Math.random() + '';         this.hashedPassword = this.encryptPassword(password);     })     .get(function () {         return this._plainPassword;     });  User.methods.checkPassword = function (password) {     return this.encryptPassword(password) === this.hashedPassword; };  module.exports = mongoose.model('User', User);  

public

В данной директории будут содержаться все скрипты и css файлы, доступные извне. Осуществляется данная опция с помощью следующей настройки:

/**  * Public directory  * */ app.use(express.static(path.join(__dirname, '../public'))); app.use("/public", express.static(path.join(__dirname, '../public'))); 

routes

Cамое, пожалуй, интересное. В данной директории, мы объявляем модуль, который будет отвечает за роутинг. файл index.js

var main = require('./main'),     register = require('./register'),     authentication = require('./authentication'),     error = require('./error');  module.exports = function (app) {     app.get('/', main.home);      app.post('/register', register.requestRegistration);      app.get('/users', authentication.users);     app.get('/users/:id', authentication.user);      app.get('*', error['404']); }; 

Здесь мы просто объявляем наши роуты, и просто делегируем выполенение другим модулям. Например, route "/":

/**  * Method: GET  * URI: /  * */ exports.home = function(req, res, next) {     res.render('index'); }; 

Cобственно говоря и все. В данном случае, как база приложение будет работать. Для поддержки сессии включаем соответствующий middleware. Всю бизнес логику, связанную с пользователем, переносим в models/user.js, в частности валидацию и регистрацию, к примеру.

PS:
В написании данной статьи была использована информация из скринкастов И.Кантора. Ссылка на скринкаст.
Также использовалась информация из курсов по MongoDB

ссылка на оригинал статьи http://habrahabr.ru/post/207930/

Intellij IDEA: Oracle Cloud Integration

Не секрет, что Oracle претендует на звание крупнейшего в мире корпоративного облака. Oracle Public Cloud, пригоден, по утверждениям компании, для переноса в себя всех приложений и бизнес-процессов предприятия.

Недавно пришлось попробовать Oracle Java Cloud Service в работе. Впечатления, в общем — положительные, но был немного расстроен, т.к не имел возможности работать с этим сервисом в своей любимой среде разработки — Intellij IDEA.
И вот два дня назад появился плагин Oracle Cloud integration. О том, какие возможности он нам предоставляет, я и хотел рассказать в этой статье.

image

Установка

Первым делом нам необходимо установить плагин:

1)Скачиваем к себе наш плагин: Oracle Cloud integration;
2)Переходим “File”>”Settings”>”Plugins” и нажимаем “Install plugin from disk”, и указываем путь к скачанному jar файлу;
3)Перезагружаем Intellij IDEA.

Настройка Cloud Configuration

После установки плагина нам необходимо создать Application Server configuration.
1)Переходим в “Run/Debug Configurations”;
2)Нажимаем “Add new configuration” и выбираем “Oracle Cloud Deployment”;
3)Нажимаем кнопку “…”, и появляется окно конфигурации облака;
4)Нажимаем кнопку “+”, задаем имя нашей конфигурации и заполняем все поля;
5)Нажимаем “Test connection”. После того как мы увидим “Connection successful” мы можем перейти к настройке Run/Debug Configurations;
6)Нажимаем “OK” и сохраняем наши настройки.

Пример:

image

Настройка Run/Debug Configurations

Этот плагин позволяет нам загружать на сервер war и ear артефакты.
1) “Deployment” комбобокс предлагает нам сделать выбор из уже существующих артефактов. Если “Deployment” комбобокс пустой, переходим
“File” > “Project structure” > “Artifacts” и создаем нужный нам артефакт. Теперь у нас все готово к загрузке приложения на сервер.

image

Загрузка приложения на сервер

Теперь у нас все готово к отправке приложения на сервер.
Выбираем созданный нами Run Configuration и нажимаем кнопку “Run” или “Debug”. После этого стартует процедура загрузки приложения на сервер.
Oracle Cloud Integration создаст нам приложение с именем, аналогичным имени артефакта.

Access to remote logs

Кроме возможности отправлять на сервер артефакты, плагин также предоставляет нам доступ к логам приложения.

После завершения отправки артефакта на сервер, мы можем просмотреть информацию о процессе загрузки в Event Log-e.
Также там печатается URL, по которому доступно приложение.

image

Virus-scan Log

Этот лог предоставляет нам результат проверки приложения на вирусы.
image

Whitelist Log

Этот лог отвечает за валидность отправляемого на сервер приложения. В роли сервера нам дается WebLogic server 10.3.6. Если вы будете пытаться загрузить на сервер приложение, несовместимое с данной версией WebLogic, — whitelist сообщит вам об этом. Также, он замечает ошибки в конфигурационных файлах, будь то weblogic.xml или web.xml.
image

Deploy/Redeploy Log

Данный лог выводит информацию о процессе deploy/redeploy приложения. При возникновении каких-либо ошибок в процессе отправки, вы увидите их именно здесь.
image

Service instance Log

Этот лог выводит нам сообщения сервера. Message types: ERROR, NOTIFICATION, WARNING, TRACE, UNKNOWN, INCIDENT ERROR.
image

Заключение

В итоге мы имеем возможность работать с Oracle Java Cloud Service непосредственно из Intellij IDEA.
Надеемся, что в ближайшее время будут добавлены новые возможности.

Из моих экспериментов можно подвести следующие итоги:
1)Не поддерживает отправку JavaEE6 приложений;
2)Не поддерживает отправку Web 3.0 и выше;
3)Поддерживает JavaEE5;
3)Поддерживает Web 2.4, 2.5

ссылка на оригинал статьи http://habrahabr.ru/post/207924/

Робот-паук, вооружённый лазером

На Ютубе появился видеоролик, в котором молодой человек демонстрирует самодельного робота-паука, вооружённого синим лазером достаточной мощности, чтобы от его воздействия лопались надувные шарики.
«Я представляю свою самую опасную лазерную разработку на сегодняшний день… дистанционно управляемого дрона! Это чудовище оснащено двухваттным синим лазером, сжигающим всё на своём пути.»

ссылка на оригинал статьи http://habrahabr.ru/post/207940/

Новогодний подарок от Nokia

Кучка подарковДва месяца назад прочитал новость на хабре, о том, что для россиян доступна программа поддержки разработчиков DVLUP. Стало интересно узнать больше об этой программе, так как в то время разработка для Windows Phone еще была моим хобби, а на маркете было опубликовано несколько приложений. В общем именно тогда мне как раз был нужен миллион…

Зарегистрировался в программе и осмотрелся, все оказалось просто, выполняешь задание, получаешь очки, которые можно тратить в магазине. Набор призов достаточно разнообразен, от бестолковых купонов на подписку IVI, до топовых устройств компании Nokia. Для меня особый интерес представляли телефоны и лицензии на программное обеспечение. Определившись с призами приступил к детальному изучению заданий, среди всего представленного разнообразия выделил задания, на качество приложений. Суть заданий сводилась к тому, что необходимо предоставить приложение с оценкой больше 4. А от количества голосов зависело количество балов которые можно получить.

Задания на качество приложенийПервая проблема появилась сразу после регистрации, мои приложения не были автоматически подключены сайтом. Выждав отведенное время и на всякий случай еще столько же, написал в поддержку. Ответ пришел очень быстро: «Я использовал всю свою магию вудду и ваши приложения появились в списке приложений». Ответ в таком стиле очень хорошо поднял мне настроение и я не откладывая приступил к реализации обновлений как того требовали правила.

На данном этапе порадовала команда сертификации Маркета, приложение которое проходило сертификацию в течении года не раз, вдруг оказалось нарушающим правила. Пришлось осваивать на практике оформление технических исключений в процессе сертификации. Следующим камнем преткновения стала система подсчета голосов на сайте DVLUP, но с помощью команды поддержки и эта проблема была решена.

Пройдя этим путем выполнил задания и получил на свой счет заветные балы, которые в тот же момент были обличены в заказ телефонов. Через день со мной связался работник компании и попросил предоставить данные для уплаты налогов, как оказалось DVLUP помимо призов уплачивает НДФЛ, за эти призы, так что получая призы не приходится получать с ними обременения в виде 35% налогов.

Сегодня утром 31 декабря мне позвонил курьер и привез мой заказ, фото его содержимого представлено на первой фотографии. Получился истинный новогодний подарок от компании Nokia.

Проблема с тестовыми телефонами для меня решена, теперь надо решать вопрос лицензирования инструментов разработки, очень хочется видеть в каталоге призов лицензию на Unity 3D Pro

Поздравляю всех хаброжителей с новым годом, желаю всем исполнения и реализации всех планов, как обычных так и самых, самых грандиозных!

ссылка на оригинал статьи http://habrahabr.ru/post/207938/

Коротко о новом: Samsung разработала первый в мире 8-гигабитный модуль мобильной DRAM-памяти LPDDR4

Добрый день, Хабр!

Samsung Electronics объявила о своих успехах в разработке первого промышленного энергоэффективного 8-гигабитного модуля мобильной DRAM-памяти, соответствующего стандарту LPDDR4.

Новая память производится на базе тех. процесса 20-нм класса и несет по одному гигабайту на кристалле, что является самым высоким показателем плотности для DRAM-компонентов на сегодняшнем рынке.

image

Благодаря новому интерфейсу ввода/вывода LVSTL (Low Voltage Swing Terminated Logic), чип LPDDR4 обеспечивает скорость передачи данных 3200 Мбит/сек на контакт, что в два раза быстрее показателей LPDDR3 DRAM-памяти предыдущего поколения. Помимо этого, новый интерфейс LPDDR4 обеспечит на 50% более высокую производительность, чем любые образцы памяти LPDDR3 или DDR3. При всем этом энергопотребление новой памяти снизилось примерно на 40% при напряжении 1,1 вольт.

Несомненно, своим новым чипом Samsung будет оснащать премиум-модели нового поколения смартфонов, планшетов и ультратонких ноутбуков в 2014 году.

ссылка на оригинал статьи http://habrahabr.ru/company/samsung/blog/207910/