Skip to content

Commit

Permalink
Merge pull request #1 from Supernomad/initial
Browse files Browse the repository at this point in the history
Initial
  • Loading branch information
supernomad committed Jun 17, 2015
2 parents c988f19 + d38cbe7 commit d8e22ac
Show file tree
Hide file tree
Showing 13 changed files with 648 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
tmp
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.12"
after_success: 'npm run coveralls'
after_failure: 'npm run coveralls'
Empty file added chunky.js
Empty file.
18 changes: 18 additions & 0 deletions libs/helpers/stringHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var typeHelper = require('./typeHelper');

function stripTrailingSlashes(str) {
if(!typeHelper.isString(str)) return str;
// Match any trailing slash, both '\' and '/', in any quantity as long as they are the last characters in the string.
return str.replace(/[\\\/]+$/g, "");
}

function stripLeadingSlashes(str) {
if(!typeHelper.isString(str)) return str;
// Match any leading slash, both '\' and '/', in any quantity as long as they are the first characters in the string.
return str.replace(/^[\\\/]+/g, "");
}

module.exports = {
stripTrailingSlashes: stripTrailingSlashes,
stripLeadingSlashes: stripLeadingSlashes
};
37 changes: 37 additions & 0 deletions libs/helpers/typeHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function doesExist(obj) {
return obj != null && obj != undefined;
}

function isObject(obj) {
return doesExist(obj) && typeof obj === "object";
}

function isFunction(obj) {
return doesExist(obj) && Object.prototype.toString.call(obj) === '[object Function]';
}

function isString(obj) {
return doesExist(obj) && typeof obj === "string";
}

function isBoolean(obj) {
return doesExist(obj) && typeof obj === "boolean";
}

function isNumber(obj) {
return doesExist(obj) && typeof obj === "number";
}

function isType(obj, typ) {
return obj instanceof typ;
}

module.exports = {
doesExist: doesExist,
isObject: isObject,
isFunction: isFunction,
isString: isString,
isNumber: isNumber,
isBoolean: isBoolean,
isType: isType
};
67 changes: 67 additions & 0 deletions libs/io.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
var fs = require('fs');

function getFileStats(path, callback) {
fs.stat(path, function(error, stats) {
callback(error, stats);
});
}

function createFile(path, buffer, offset, length, callback) {
var stream = getWriteStream(path, 0, 'w');
return stream.write(buffer.slice(offset, offset + length), function(error) {
stream.end();
callback(error);
});
}

function writeFileChunk(path, buffer, offset, length, position, callback) {
var stream = getWriteStream(path, position, 'r+');
return stream.write(buffer.slice(offset, offset + length), function(error) {
stream.end();
callback(error);
});
}

function deleteFile(path, callback) {
fs.unlink(path, function(error) {
callback(error);
});
}

function readFile(path, callback) {
fs.readFile(path, function(error, data){
callback(error, data);
});
}

function readFileChunk(path, buffer, offset, length, position, callback) {
var fd = fs.openSync(path, 'r+');
fs.read(fd, buffer, offset, length, position, function(error, read, buffer){
fs.closeSync(fd);
callback(error, read, buffer);
});
}

function renameFile(path, newPath, callback) {
fs.rename(path, newPath, function(error) {
callback(error);
});
}

function getWriteStream(path, position, type) {
return fs.createWriteStream(path, {
flags: type,
mode: 0666,
start: position
});
}

module.exports = {
GetFileStats: getFileStats,
CreateFile: createFile,
WriteFileChunk: writeFileChunk,
DeleteFile: deleteFile,
ReadFile: readFile,
ReadFileChunk: readFileChunk,
RenameFile: renameFile
};
14 changes: 14 additions & 0 deletions libs/models/apiModels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function routeHandler(uri, handler) {
var self = this;
self.uri = uri;
self.handler = handler;
}
function errorHandler(handler) {
var self = this;
self.handler = handler;
}

module.exports = {
RouteHandler: routeHandler,
ErrorHandler: errorHandler
};
35 changes: 35 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "chunky",
"version": "0.0.1",
"description": "An async upload/download nodejs library leveraging express.js and socket.io. Provides standard, chunked, and udp style transfers.",
"main": "chunky.js",
"scripts": {
"test": "mkdir -p tmp/tests && ./node_modules/istanbul/lib/cli.js cover ./node_modules/.bin/_mocha -- test --ui bdd --reporter spec",
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls"
},
"repository": {
"type": "git",
"url": "https://github.com/Supernomad/chunky.git"
},
"keywords": [
"transfer",
"upload",
"download",
"chunked",
"file",
"multi-part",
"folder"
],
"author": "supernomad <Christian Saide>",
"license": "GPL v3",
"bugs": {
"url": "https://github.com/Supernomad/chunky/issues"
},
"homepage": "https://github.com/Supernomad/chunky",
"devDependencies": {
"mocha": "~2.2.5",
"should": "~6.0.3",
"istanbul": "~0.3.15",
"coveralls": "~2.11.2"
}
}
42 changes: 42 additions & 0 deletions routes/chunked-upload-routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
var apiModels = require('./../libs/models/apiModels'),
typeHelper = require('./../libs/helpers/typeHelper'),
stringHelper = require('./../libs/helpers/stringHelper');

var debug = false,
routePrefix = "/chunked/upload",
io = null,
dataCache = null;

var routes = {
"get": new apiModels.RouteHandler(routePrefix + "/:uploadId", function (req, res) {

}),
"post": new apiModels.RouteHandler(routePrefix, function (req, res) {

}),
"put": new apiModels.RouteHandler(routePrefix + "/:uploadId/:index", function (req, res) {

}),
"delete": new apiModels.RouteHandler(routePrefix + "/:uploadId", function (req, res) {

}),
"error": new apiModels.ErrorHandler(function (error, req, res, next) {

})
};

function configure(cache, storage, options) {
if(typeHelper.isObject(options)) {
if(options.hasOwnProperty('debug') && typeHelper.isBoolean(options.debug)){
debug = options.debug;
}
if(options.hasOwnProperty('routePrefix') && typeHelper.isString(options.routePrefix)){
routePrefix = stringHelper.stripTrailingSlashes(options.routePrefix);
}
}

io = storage;
dataCache = cache;
return routes;
};
module.exports = configure;
110 changes: 110 additions & 0 deletions test/io-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* global describe, it , Buffer */
var io = require('./../libs/io'),
should = require('should'),
tempFile = "./tmp/tests/tmp.temp",
renameFile = "./tmp/tests/temp-rename.temp";

describe('io.js', function() {
describe('#CreateFile', function() {
it('should create a file on the filesystem based on the supplied buffer at the specified path.', function(done) {
var buffer = new Buffer(1000);
buffer.fill(0);
var fullyBuffered = io.CreateFile(tempFile, buffer, 0, buffer.length, function(createError) {
should.not.exist(createError);

io.GetFileStats(tempFile, function(statError, stats) {
should.not.exist(statError);
should.exist(stats);

stats.isFile().should.be.true;
stats.size.should.equal(1000);

done();
});
});
fullyBuffered.should.be.a.Boolean;
});
});

describe('#WriteFileChunk', function() {
it('should update a given file with the supplied buffer at the supplied position.', function(done) {
var buffer = new Buffer(1000);
buffer.fill(0);
var fullyBuffered = io.WriteFileChunk(tempFile, buffer, 0, buffer.length, 500, function(updateError) {
should.not.exist(updateError);
io.GetFileStats(tempFile, function(statError, stats) {
should.not.exist(statError);
should.exist(stats);

stats.isFile().should.be.true;
stats.size.should.equal(1500);

done();
});
});
fullyBuffered.should.be.a.Boolean;
});
});

describe('#ReadFile', function() {
it('should read the entire specified file.', function(done) {
io.ReadFile(tempFile, function(readError, buffer) {
should.not.exist(readError);
should.exist(buffer);

buffer.length.should.equal(1500);

for (var i = buffer.length - 1; i >= 0; i--) {
buffer[i].should.equal(0);
};
done();
});
});
});

describe('#ReadFileChunk', function() {
it('should read a chunk of data from the specified file into the specified buffer within the given bounds.', function(done) {
var buffer = new Buffer(500);
io.ReadFileChunk(tempFile, buffer, 0, buffer.length, 500, function(readError, bytesRead, data) {
should.not.exist(readError);

bytesRead.should.equal(buffer.length);

for (var i = data.length - 1; i >= 0; i--) {
data[i].should.equal(0);
};
done();
});
});
});

describe('#RenameFile', function() {
it('should rename the given file to the new filename supplied.', function(done) {
io.RenameFile(tempFile, renameFile, function(renameError) {
should.not.exist(renameError);
io.GetFileStats(renameFile, function(statError, stats) {
should.not.exist(statError);
should.exist(stats);

stats.isFile().should.be.true;
stats.size.should.equal(1500);

done();
});
});
});
});

describe('#DeleteFile', function() {
it('should delete the given file from the filesystem.', function(done) {
io.DeleteFile(renameFile, function(deleteError) {
should.not.exist(deleteError);
io.GetFileStats(renameFile, function(statError, stats) {
should.exist(statError);
should.not.exist(stats);
done();
});
});
});
});
});
4 changes: 4 additions & 0 deletions test/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* global before, process */
before(function() {
process.stdout.write('\033c');
});
Loading

0 comments on commit d8e22ac

Please sign in to comment.