Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

works on windows too if you can get localtunnel to work at all

  • Loading branch information...
commit dbaf904b12754dd84d30953f58524162bc46619f 1 parent 74d9661
@pghalliday authored
View
2  .gitignore
@@ -0,0 +1,2 @@
+node_modules
+.DS_Store
View
22 LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Peter Halliday
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
34 README.md
@@ -1,2 +1,34 @@
node-localtunnel
-================
+=========
+
+Node.js wrapper for the localtunnel ruby client
+
+## Features
+
+- List features
+
+## Installation
+
+```
+npm install node-localtunnel
+```
+
+## API
+
+```javascript
+var SOMETHING = require('node-localtunnel');
+```
+
+## Roadmap
+
+- List backlog items
+
+## Contributing
+In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using ``./grunt.sh`` or ``.\grunt.bat``.
+
+## Release History
+_(Nothing yet)_
+
+## License
+Copyright (c) 2012 Peter Halliday
+Licensed under the MIT license.
View
1  grunt.bat
@@ -0,0 +1 @@
+node_modules\.bin\grunt.cmd %*
View
80 grunt.js
@@ -0,0 +1,80 @@
+module.exports = function(grunt) {
+
+ grunt.loadNpmTasks('grunt-mocha-test');
+
+ function getLintConfig() {
+ return {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true,
+ es5: true,
+ strict: false
+ },
+ globals: {
+ }
+ };
+ }
+
+ function getNodeLintConfig() {
+ var config = getLintConfig();
+ config.options.node = true;
+ return config;
+ }
+
+ function getNodeTestLintConfig() {
+ var config = getNodeLintConfig();
+ config.globals.describe = false;
+ config.globals.it = false;
+ config.globals.before = false;
+ config.globals.after = false;
+ config.globals.beforeEach = false;
+ config.globals.afterEach = false;
+ return config;
+ }
+
+ // Project configuration.
+ grunt.initConfig({
+ lint: {
+ node: ['grunt.js', 'src/**/*.js'],
+ nodeTest: ['test/src/**/*.js']
+ },
+ jshint: {
+ node: getNodeLintConfig(),
+ nodeTest: getNodeTestLintConfig()
+ },
+ mochaTest: {
+ test: ['test/src/**/*.js'],
+ doc: ['test/src/**/*.js']
+ },
+ mochaTestConfig: {
+ test: {
+ options: {
+ reporter: 'nyan'
+ }
+ },
+ doc: {
+ options: {
+ reporter: 'doc'
+ }
+ }
+ },
+ watch: {
+ files: ['grunt.js', 'src/**/*.js', 'test/src/**/*.js'],
+ tasks: ['default']
+ }
+ });
+
+ // Default task.
+ grunt.registerTask('default', 'lint mochaTest:test');
+
+ // Documentation task.
+ grunt.registerTask('doc', 'mochaTest:doc');
+};
View
1  grunt.sh
@@ -0,0 +1 @@
+node_modules/.bin/grunt $*
View
41 package.json
@@ -0,0 +1,41 @@
+{
+ "name": "node-localtunnel",
+ "description": "Node.js wrapper for the localtunnel ruby client",
+ "version": "0.0.0",
+ "homepage": "https://github.com/pghalliday/node-localtunnel.git",
+ "author": {
+ "name": "Peter Halliday",
+ "email": "pghalliday@gmail.com",
+ "url": "http://stuffpetedoes.blogspot.nl/"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/pghalliday/node-localtunnel.git"
+ },
+ "bugs": {
+ "url": "https://github.com/pghalliday/node-localtunnel/issues"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/pghalliday/node-localtunnel/blob/master/LICENSE-MIT"
+ }
+ ],
+ "main": "src/index.js",
+ "engines": {
+ "node": ">= 0.8.12"
+ },
+ "scripts": {
+ "test": "grunt"
+ },
+ "dependencies": {},
+ "optionalDependencies": {
+ "pty.js": "0.1.2"
+ },
+ "devDependencies": {
+ "grunt": "0.3.17",
+ "grunt-mocha-test": "0.0.1",
+ "expect.js": "~0.2.0"
+ },
+ "keywords": []
+}
View
69 src/LocalTunnel.js
@@ -0,0 +1,69 @@
+function LocalTunnel(port, binary) {
+ var self = this,
+ child,
+ started = false;
+
+ if (!binary) {
+ binary = 'localtunnel';
+ }
+
+ process.on("exit", function(code, signal) {
+ if (child) {
+ child.kill(signal);
+ }
+ });
+
+ self.start = function(callback) {
+ if (started) {
+ callback(new Error('local tunnel already started'));
+ } else {
+ var stdoutData = '';
+ var stdout;
+
+ if (process.platform === 'win32') {
+ child = require('child_process').spawn('cmd', ['/s', '/c', binary, port]);
+ stdout = child.stdout;
+ child.stderr.on('data', function(data) {
+ stdoutData += data;
+ });
+ } else {
+ stdout = child = require('pty.js').spawn(binary, [port], {
+ name: 'localtunnel',
+ cols: 80,
+ rows: 30
+ });
+ }
+
+ child.on('exit', function(code, signal) {
+ if (!started) {
+ callback(new Error('localtunnel failed to start:\n' + stdoutData));
+ }
+ child = null;
+ });
+
+ stdout.setEncoding();
+ stdout.on('data', function(data) {
+ stdoutData += data.toString();
+ var match = stdoutData.match(/[a-z0-9]{4}\.localtunnel\.com/g);
+ if (match) {
+ started = true;
+ callback(null, match[0]);
+ }
+ });
+ }
+ };
+
+ self.stop = function(callback) {
+ if (!started) {
+ callback(new Error('localtunnel not active'));
+ } else {
+ child.on('exit', function(code, signal) {
+ started = false;
+ callback();
+ });
+ child.kill();
+ }
+ };
+}
+
+module.exports = LocalTunnel;
View
1  src/index.js
@@ -0,0 +1 @@
+module.exports = require('./LocalTunnel');
View
73 test/src/LocalTunnel.js
@@ -0,0 +1,73 @@
+var expect = require('expect.js'),
+ LocalTunnel = require('../../'),
+ http = require('http');
+
+var PORT = 8080;
+var TEST_RESPONSE = "This is a test";
+
+describe('LocalTunnel', function() {
+ it('should error if the binary does not exist', function(done) {
+ var localTunnel = new LocalTunnel(PORT, 'blahblah');
+ localTunnel.start(function(error, hostname) {
+ expect(error.toString()).to.contain('localtunnel failed to start');
+ done();
+ });
+ });
+
+ it('should error if stopped before started', function(done) {
+ var localTunnel = new LocalTunnel(PORT);
+ localTunnel.stop(function(error) {
+ expect(error.toString()).to.contain('localtunnel not active');
+ done();
+ });
+ });
+
+ it('should start a localtunnel', function(done) {
+ this.timeout(10000);
+ var localTunnel = new LocalTunnel(PORT);
+ localTunnel.start(function(error, hostname) {
+ if (error) {
+ expect().fail('Error encountered starting the tunnel:\n' + error);
+ }
+ expect(hostname).to.contain('localtunnel.com');
+
+ var server = http.createServer(function(request, response) {
+ response.end(TEST_RESPONSE);
+ });
+ server.listen(PORT, function() {
+ http.get({
+ hostname: hostname
+ }, function(response) {
+ expect(response.statusCode).to.equal(200);
+
+ response.setEncoding();
+ var responseData = '';
+ response.on('data', function(data) {
+ responseData += data;
+ });
+ response.on('end', function() {
+ expect(responseData).to.equal(TEST_RESPONSE);
+
+ server.close(function() {
+ localTunnel.stop(done);
+ });
+ });
+ }).on('error', function(error) {
+ server.close(function() {
+ localTunnel.stop(function() {
+ done(error);
+ });
+ });
+ });
+ });
+ });
+ });
+
+ it.skip('should error if started when already running', function(done) {
+ done();
+ });
+
+ it.skip('should stop when the process exits', function(done) {
+ done();
+ });
+});
Please sign in to comment.
Something went wrong with that request. Please try again.