8 Commits

Author SHA1 Message Date
Roman Shtylman
174e7f3982 1.0.0 2014-02-14 00:37:45 -05:00
Roman Shtylman
44be55cd7b readme: fix markdown table
[ci skip]
2014-02-14 00:36:53 -05:00
Roman Shtylman
5c6cd2359c add travis badge
- remove node 0.8
- add node 0.10
2014-02-14 00:34:40 -05:00
Roman Shtylman
2f6f9459ad change main export signature to localtunnel(port, opt, fn)
Makes for a simpler hello world app
2014-02-14 00:32:43 -05:00
Roman Shtylman
7217a08a05 add history.md to track changes 2014-02-13 23:52:12 -05:00
Roman Shtylman
fbfc923a7e remove connect export in favor of single function
Since connect was the only function exported, we can just export the
function directly to make things simpler.
2014-02-13 23:51:29 -05:00
Roman Shtylman
d9bc11b520 default host to localtuunel.me
If no host specified, then default to localtunnel.me

close #31
2014-02-13 23:43:54 -05:00
Roman Shtylman
ad64611bd1 add tests 2014-02-13 23:41:49 -05:00
7 changed files with 146 additions and 33 deletions

View File

@@ -1,4 +1,3 @@
language: node_js language: node_js
node_js: node_js:
- 0.8 - "0.10"
- 0.9

7
History.md Normal file
View File

@@ -0,0 +1,7 @@
# 1.0.0 / 2014-02-14
* default to localltunnel.me for host
* remove exported `connect` method (just export one function that does the same thing)
* change localtunnel signature to (port, opt, fn)
# 0.2.2 / 2014-01-09

View File

@@ -1,4 +1,4 @@
# localtunnel # # localtunnel [![Build Status](https://travis-ci.org/defunctzombie/localtunnel.png?branch=master)](https://travis-ci.org/defunctzombie/localtunnel) #
localtunnel exposes your localhost to the world for easy testing and sharing! No need to mess with DNS or deploy just to have others test out your changes. localtunnel exposes your localhost to the world for easy testing and sharing! No need to mess with DNS or deploy just to have others test out your changes.
@@ -28,27 +28,41 @@ You can restart your local server all you want, ```lt``` is smart enough to dete
The localtunnel client is also usable through an API (for test integration, automation, etc) The localtunnel client is also usable through an API (for test integration, automation, etc)
### localtunnel(port [,opts], fn)
Creates a new localtunnel to the specified local `port`. `fn` will be called once you have been assigned a public localtunnel url. `opts` can be used to request a specific `subdomain`.
```javascript ```javascript
var localtunnel = require('localtunnel'); var localtunnel = require('localtunnel');
var client = localtunnel.connect({ localtunnel(port, function(err, tunnel) {
// the localtunnel server if (err) ...
host: 'http://localtunnel.me',
// your local application port
port: 12345
});
// when your are assigned a url // the assigned public url for your tunnel
client.on('url', function(url) { // i.e. https://abcdefgjhij.localtunnel.me
// you can now make http requests to the url tunnel.url;
// they will be proxied to your local server on port [12345]
});
client.on('error', function(err) {
// uh oh!
}); });
``` ```
### opts
* `subdomain` A *string* value requesting a specific subdomain on the proxy server. **Note** You may not actually receive this name depending on availablily.
### Tunnel
The `tunnel` instance returned to your callback emits the following events
|event|args|description|
|----|----|----|
|error|err|fires when an error happens on the tunnel|
|close||fires when the tunnel has closed|
The `tunnel instance has the following methods
|method|args|description|
|----|----|----|
|close||close the tunnel|
## other clients ## ## other clients ##
Clients in other languages Clients in other languages
@@ -57,7 +71,7 @@ Clients in other languages
## server ## ## server ##
See shtylman/localtunnel-server for details on the server that powers localtunnel. See defunctzombie/localtunnel-server for details on the server that powers localtunnel.
## License ## ## License ##
MIT MIT

View File

@@ -25,15 +25,17 @@ var opt = {
subdomain: argv.subdomain, subdomain: argv.subdomain,
} }
var client = lt_client.connect(opt); lt_client(opt.port, opt, function(err, tunnel) {
if (err) {
console.error(err);
return process.exit(1);
}
// only emitted when the url changes console.log('your url is: %s', tunnel.url);
client.on('url', function(url) {
console.log('your url is: %s', url);
});
client.on('error', function(err) { tunnel.on('error', function(err) {
console.error(err); console.error(err);
});
}); });
// vim: ft=javascript // vim: ft=javascript

View File

@@ -116,7 +116,9 @@ var Tunnel = function(opt) {
var self = this; var self = this;
self._closed = false; self._closed = false;
self._opt = opt; self._opt = opt || {};
self._opt.host = self._opt.host || 'https://localtunnel.me';
}; };
Tunnel.prototype.__proto__ = EventEmitter.prototype; Tunnel.prototype.__proto__ = EventEmitter.prototype;
@@ -220,15 +222,17 @@ Tunnel.prototype._establish = function(info) {
} }
}; };
Tunnel.prototype.open = function() { Tunnel.prototype.open = function(cb) {
var self = this; var self = this;
self._init(function(err, info) { self._init(function(err, info) {
if (err) { if (err) {
return self.emit('error', err); return cb(err);
} }
self.url = info.url;
self._establish(info); self._establish(info);
cb();
}); });
}; };
@@ -240,8 +244,21 @@ Tunnel.prototype.close = function() {
self.emit('close'); self.emit('close');
}; };
module.exports.connect = function(opt) { module.exports = function localtunnel(port, opt, fn) {
if (typeof opt === 'function') {
fn = opt;
opt = {};
}
opt = opt || {};
opt.port = port;
var client = Tunnel(opt); var client = Tunnel(opt);
client.open(); client.open(function(err) {
return client; if (err) {
return fn(err);
}
fn(null, client);
});
}; };

View File

@@ -2,7 +2,7 @@
"author": "Roman Shtylman <shtylman@gmail.com>", "author": "Roman Shtylman <shtylman@gmail.com>",
"name": "localtunnel", "name": "localtunnel",
"description": "expose localhost to the world", "description": "expose localhost to the world",
"version": "0.2.2", "version": "1.0.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/shtylman/localtunnel.git" "url": "git://github.com/shtylman/localtunnel.git"
@@ -12,7 +12,12 @@
"optimist": "0.3.4", "optimist": "0.3.4",
"debug": "0.7.4" "debug": "0.7.4"
}, },
"devDependencies": {}, "devDependencies": {
"mocha": "~1.17.0"
},
"scripts": {
"test": "mocha --ui qunit --reporter list -- test/index.js"
},
"bin": { "bin": {
"lt": "./bin/client" "lt": "./bin/client"
}, },

69
test/index.js Normal file
View File

@@ -0,0 +1,69 @@
var http = require('http');
var https = require('https');
var url = require('url');
var assert = require('assert');
var localtunnel = require('../');
test('setup local http server', function(done) {
var server = http.createServer();
server.on('request', function(req, res) {
res.write('foo');
res.end();
});
server.listen(function() {
var port = server.address().port;
test._fake_port = port;
console.log('local http on:', port);
done();
});
});
test('setup localtunnel client', function(done) {
localtunnel(test._fake_port, function(err, tunnel) {
assert.ifError(err);
assert.ok(new RegExp('^https:\/\/.*localtunnel.me' + '$').test(tunnel.url));
test._fake_url = tunnel.url;
done();
});
});
test('query localtunnel server w/ ident', function(done) {
var uri = test._fake_url;
var parsed = url.parse(uri);
var opt = {
host: parsed.host,
port: 443,
headers: {
host: parsed.hostname
},
path: '/'
};
var req = https.request(opt, function(res) {
res.setEncoding('utf8');
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
assert.equal('foo', body);
done();
});
});
req.end();
});
test('request specific domain', function(done) {
localtunnel(test._fake_port, { subdomain: 'abcd' }, function(err, tunnel) {
assert.ifError(err);
assert.ok(new RegExp('^https:\/\/abcd.localtunnel.me' + '$').test(tunnel.url));
tunnel.close();
done();
});
});