Skip to content

Commit

Permalink
feat(headers): Add default headers and merging of request headers.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSharpieOne committed May 28, 2015
1 parent d086135 commit ffb337f
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 62 deletions.
7 changes: 4 additions & 3 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "angular-sails",
"version": "1.1.0",
"version": "2.0.0-beta.2",
"authors": [
"Jan-Oliver Pantel <info@janpantel.de>"
"Jan-Oliver Pantel <jan.pantel@gmail.com>",
"Evan Sharp <dumbdrum@gmail.com>"
],
"description": "An angular provider for using the sails socket.io api",
"main": "./dist/angular-sails.js",
Expand All @@ -16,7 +17,7 @@
"api"
],
"license": "MIT",
"homepage": "https://github.com/kyjan/angular-sails",
"homepage": "https://github.com/janpantel/angular-sails",
"dependencies": {
"angular": ">=1.2.*",
"socket.io-client": ">=1.3.0"
Expand Down
10 changes: 10 additions & 0 deletions mock/socket-io.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ function createMockSocketObject() {
delete this._listeners[ev];
}
},
off: function(ev, fn) {
if (fn) {
var index = this._listeners[ev].indexOf(fn);
if (index > -1) {
this._listeners[ev].splice(index, 1);
}
} else {
delete this._listeners[ev];
}
},
removeAllListeners: function(ev) {
if (ev) {
delete this._listeners[ev];
Expand Down
15 changes: 10 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
{
"name": "angular-sails",
"private": true,
"version": "1.1.0",
"version": "2.0.0-beta.2",
"description": "An angular provider for using the sails socket.io api",
"scripts": {
"build": "gulp build-js",
"build": "gulp build",
"test": "gulp test"
},
"main": "dist/angular-sails.js",
"repository": {
"type": "git",
"url": "https://github.com/kyjan/angular-sails.git"
},
"author": "Jan-Oliver Pantel <info@janpantel.de>",
"author": "Jan-Oliver Pantel <jan.pantel@gmail.com>",
"contributors": [
"Jan-Oliver Pantel <jan.pantel@gmail.com>",
"Evan Sharp <dumbdrum@gmail.com>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/kyjan/angular-sails/issues"
"url": "https://github.com/janpantel/angular-sails/issues"
},
"homepage": "https://github.com/kyjan/angular-sails",
"homepage": "https://github.com/janpantel/angular-sails",
"devDependencies": {
"chai": "^1.10.0",
"gulp": "^3.5.6",
Expand Down
113 changes: 62 additions & 51 deletions src/service/$sails.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

/* jshint newcap: false */
/* global headersGetter: true,
mergeHeaders: true,
arrIndexOf: true,
isFile: true,
isBlob: true
Expand All @@ -26,9 +27,9 @@ function $sails($sailsInterceptorProvider, $sailsIoProvider) {
};

provider.defaults = {
transformResponse: [],
transformRequest: [],
headers: {} // TODO: default headers
transformResponse: [],
transformRequest: [],
headers: {} // TODO: what should the default default headers
};

provider.interceptors = $sailsInterceptorProvider.interceptors = [
Expand All @@ -42,17 +43,17 @@ function $sails($sailsInterceptorProvider, $sailsIoProvider) {
}*/
];

this.$get = function($q, $log, $timeout, $sailsIo, $sailsInterceptor) {
this.$get = function($rootScope, $q, $log, $timeout, $sailsIo, $sailsInterceptor) {
var socket = new $sailsIo(provider.socket || provider.url, provider.config);
var socketFunctions = ['connect','disconnect','isConnected'];
var socketFunctions = ['connect', 'disconnect', 'isConnected'];

function $sails(config) {
return $sails[config.method](config.url, config);
}

$sails._socket = socket;

function exposeSocketFunction(fnName){
function exposeSocketFunction(fnName) {
$sails[fnName] = socket[fnName].bind(socket);
}

Expand All @@ -62,8 +63,7 @@ function $sails($sailsInterceptorProvider, $sailsIoProvider) {
var config = {
method: methodName,
transformRequest: provider.defaults.transformRequest,
transformResponse: provider.defaults.transformResponse,
headers: {}// TODO: default headers
transformResponse: provider.defaults.transformResponse
};

requestConfig = requestConfig || {};
Expand All @@ -76,9 +76,14 @@ function $sails($sailsInterceptorProvider, $sailsIoProvider) {
requestConfig.data = data;
}

angular.extend(config, requestConfig);
config = angular.extend({}, config, requestConfig);
config.headers = mergeHeaders(requestConfig, provider.defaults.headers);
config.url = (provider.urlPrefix || '') + (url || config.url);
config.method = (config.method || methodName).toUpperCase();
config.method = angular.uppercase(config.method || methodName);

if (angular.isUndefined(config.withCredentials) && !angular.isUndefined(provider.defaults.withCredentials)) {
config.withCredentials = provider.defaults.withCredentials;
}

var promise = $sailsInterceptor(socket[methodName].bind(socket), config);

Expand Down Expand Up @@ -113,56 +118,62 @@ function $sails($sailsInterceptorProvider, $sailsIoProvider) {
* Update a model on sails pushes
* @param {String} name Sails model name
* @param {Array} models Array with model objects
* @returns {Function} Function to remove the model updater instance
*/
$sails.$modelUpdater = function(name, models) {

socket.on(name, function(message) {
var i;
var update = function(message) {

if (provider.debug) {
$log.info('$sails ' + name + ' model ' + message.verb + ' id: ' + message.id, message.data);
}
$rootScope.$evalAsync(function() {
var i;

switch (message.verb) {
switch (message.verb) {

case "created":
// create new model item
models.push(message.data);
break;
case "created":
// create new model item
models.push(message.data);
break;

case "updated":
var obj;
for (i = 0; i < models.length; i++) {
if (models[i].id === message.id) {
obj = models[i];
break;
case "updated":
var obj;
for (i = 0; i < models.length; i++) {
if (models[i].id === message.id) {
obj = models[i];
break;
}
}
}

// cant update if the angular-model does not have the item and the
// sails message does not give us the previous record
if (!obj && !message.previous) return;

if (!obj) {
// sails has given us the previous record, create it in our model
obj = message.previous;
models.push(obj);
}

// update the model item
angular.extend(obj, message.data);
break;

case "destroyed":
for (i = 0; i < models.length; i++) {
if (models[i].id === message.id) {
models.splice(i, 1);
break;

// cant update if the angular-model does not have the item and the
// sails message does not give us the previous record
if (!obj && !message.previous) return;

if (!obj) {
// sails has given us the previous record, create it in our model
obj = message.previous;
models.push(obj);
}
}
break;
}
});

// update the model item
angular.extend(obj, message.data);
break;

case "destroyed":
for (i = 0; i < models.length; i++) {
if (models[i].id === message.id) {
models.splice(i, 1);
break;
}
}
break;
}
});
};

socket._socket.on(name, update);

return function() {
socket._socket.off(name, update);
};
};

$sails.defaults = this.defaults;
Expand Down
4 changes: 2 additions & 2 deletions src/service/$sailsIo.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function $sailsIo() {

SailsIo.prototype._send = function(req, res) {
var self = this;
var sailsEndpoint = req.method.toLowerCase();
var sailsEndpoint = angular.lowercase(req.method);

self.connectDefer.promise.then(function sendRequest() {
if (provider.debug) {
Expand Down Expand Up @@ -132,7 +132,7 @@ function $sailsIo() {
req.url = buildUrl(req.url.replace(/^(.+)\/*\s*$/, '$1'), req.params);
req.headers = req.headers || {};
req.data = req.data || {};
req.method = req.method.toUpperCase();
req.method = angular.uppercase(req.method);

if (typeof req.url !== 'string') {
throw new Error('Invalid or missing URL!');
Expand Down
61 changes: 61 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,67 @@ function parseHeaders(headers) {
return parsed;
}

function executeHeaderFns(headers, config) {
var headerContent, processedHeaders = {};

angular.forEach(headers, function(headerFn, header) {
if (angular.isFunction(headerFn)) {
headerContent = headerFn(config);
if (headerContent != null) {
processedHeaders[header] = headerContent;
}
} else {
processedHeaders[header] = headerFn;
}
});

return processedHeaders;
}

function mergeHeaders(config, defHeaders) {
var reqHeaders = angular.extend({}, config.headers),
defHeaderName, lowercaseDefHeaderName, reqHeaderName;

defHeaders = angular.extend({}, defHeaders.common, defHeaders[angular.lowercase(config.method)]);

// using for-in instead of forEach to avoid unecessary iteration after header has been found
defaultHeadersIteration:
for (defHeaderName in defHeaders) {
lowercaseDefHeaderName = angular.lowercase(defHeaderName);

for (reqHeaderName in reqHeaders) {
if (angular.lowercase(reqHeaderName) === lowercaseDefHeaderName) {
continue defaultHeadersIteration;
}
}

reqHeaders[defHeaderName] = defHeaders[defHeaderName];
}

// execute if header value is a function for merged headers
return executeHeaderFns(reqHeaders, shallowCopy(config));
}

function shallowCopy(src, dst) {
if (angular.isArray(src)) {
dst = dst || [];

for (var i = 0, ii = src.length; i < ii; i++) {
dst[i] = src[i];
}
} else if (angular.isObject(src)) {
dst = dst || {};

for (var key in src) {
if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
}

return dst || src;
}

function trim(value) {
return angular.isString(value) ? value.trim() : value;
}
Expand Down
25 changes: 24 additions & 1 deletion test/angular-sails-service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,11 @@ describe('Agnular Sails service', function() {

var models;
var modelResponse;
var removeUpdater;

beforeEach(function() {
models = [];
$sails.$modelUpdater('user', models);
removeUpdater = $sails.$modelUpdater('user', models);
modelResponse = {
created:{
data: {
Expand Down Expand Up @@ -291,6 +292,28 @@ describe('Agnular Sails service', function() {
expect(models[0].name).to.equal(modelResponse.updated.data.name);
});

describe('returned function', function(){
it('should remove the socket listener', function () {
removeUpdater();
$scope.$digest();
mockIoSocket.emit('user', modelResponse.created);
$scope.$digest();
expect(models).to.be.empty();
});

it('should remove only the socket listener it is called on', function () {
var tasks = [];
$sails.$modelUpdater('tasks', tasks);
removeUpdater();
$scope.$digest();
mockIoSocket.emit('user', modelResponse.created);
mockIoSocket.emit('tasks', modelResponse.created);
$scope.$digest();
expect(tasks).to.contain(modelResponse.created.data);
expect(models).to.be.empty();
});
});

});

});

0 comments on commit ffb337f

Please sign in to comment.