[Из песочницы] Firebase-queue: стероиды для firebase

Про Firebase уже не раз писали на хабре. Ключевым преимуществом этой системы является то, что в некоторых случаях на ней можно построить завершенное веб-приложение работающее с данными в реальном времени. Располагая возможностью редактирования правил доступа к базе данных и тем что эти правила можно устроить на основе пользователей (которых сюда тоже завезли), в принципе можно обойтись и без какого-либо backend’a. Но обычно возникают такие проблемы, которые лучше решить «со стороны» чем плодить велосипеды в правилах (например).

В середине мая разработчики объявили о выходе firebase-queue. Это javascript-библиотека с помощью которой можно организовать работу с данными в базе, как с задачами. Работает это следующим образом: определяем ячейку задач, используя Queue () на сервере устанавливаем связь. Теперь, когда в этой ячейке появится новый элемент, сервер сделает необходимые действия, если нужно оповестит о прогрессе и ошибках, и по завершению удалит задачу. В итоге мы получаем возможность покрыть много проблем возникающих в разработке с Firebase — согласовать данные, провести их дополнительную валидацию (например проверить на спам и мат) отправить их в другое место (например загрузить картинку на хостинг) и другое.
В качестве примера возьмем вышеупомянутый вопрос из stackoverflow. Имеем объект с n-ым количеством элементов. Хотим после добавления/удаления элемента обновлять счетчик общего количества. В базе определим два объекта: elements и length. Также в правилах укажем ячейки задач addnode и rmnode. В них с клиента будем отправлять тот объект, который хотим получить и удалить соответственно из elements.

var ref = new Firebase('https://***.firebaseio.com');

var addNode = function(text) {
  // используем kriskowal/q для промисов
  var deferred = Q.defer();
  var task = ref.child('addnode').push({ new: text }, function(e) { if (e) {
    deferred.reject(e);
  } else {
    /* Следим за изменениями в нашей задаче. Вызов progress() с сервера
       изменит значение _progress, resolve() - удалит задачу.
    */     
    ref.child('addnode/'+task.key()).on('value', function(d) {
      var v = d.val();
      if(v == null) {
        deferred.resolve();
      } else {
        deferred.notify(v._progress);
      }
    })
  }});
  return deferred.promise;
}

var rmNode = function(k) {
  var deferred = Q.defer();
  var task = ref.child('rmnode').push({ key: k }, function(e) { if (e) {
    deferred.reject(e);
  } else {
    ref.child('addnode/'+task.key()).on('value', function(d) {
      var v = d.val();
      if(v == null) {
        deferred.resolve();
      } else {
        deferred.notify(v._progress);
      }
    })
  }});
  return deferred.promise;
}


Firebase-queue прицепляем на ячейки задач. Как только появляется новая задача, уже на сервере производим необходимые манипуляции:

var ref = new Firebase('https://***.firebaseio.com');

var length;

ref.child('length').once('value', function(d) {
  length = d.val();
});

var addNodeQueue = new Queue(ref.child('addnode'), {}, function(data, progress, resolve, reject) {
  ref.child('elements').push(data.new, function(e) { if (e) {
    reject(e);
  } else {
    progress(50);
    length++;
    ref.child('length').set(length, function(e) { if (e) {
      reject(e.message);
    } else {
      resolve();
    }});
  }});
});

var rmNodeQueue = new Queue(ref.child('rmnode'), {}, function(data, progress, resolve, reject) {
  ref.child('elements/'+data.key).remove(function(e) { if (e) {
    reject(e);
  } else {
    progress(50);
    length--;
    ref.child('length').set(length, function(e) { if (e) {
      reject(e);
    } else {
      resolve();
    }});
  }});
});


Правила будут следующие:

{
  "rules": { 
    "addnode": {
      "$taskId": { 
        "new": {
          ".validate": "newData.isString()"
        }
      }
    },
    "rmnode": {
      "$taskId": { 
        "key": {
          ".validate": "root.child('elements/'+newData.val()).exists()"
          // элемент с этим ключом должен находится в бд
        }
      }
    }
  }
}


Дабы не перегружать и сохранить обзорный характер статьи, решил опустить рассказ о правилах безопасности для задач, спецификациях задач и опциях, которые можно указать для Queue (). Это все прекрасно (как и вся их документация) описано на странице проекта на github’е.

© Habrahabr.ru