- Internet Penetration
- Integrate server side & client side
- Support cluster (Share TCP stream via redis pub/sub)
- Based on WebSocket transport
- Support HTTP Basic Auth
import {Application, createApp} from '@lakutata/core'
import {AllowCallback, Tunnel, TunnelClientComponent, TunnelServerComponent} from '@lakutata-component/tunnel'
import {createServer, IncomingMessage} from 'http'
import {WebSocketServer} from 'ws'
const app = await createApp({
id: 'test.app',
name: 'tester',
components: {
server: {
class: TunnelServerComponent,
//Server bind port
port: 80,
//Server bind address
address: '0.0.0.0',
//Server bind domain
domain: 'tunnel.example.com',
//Server name
serverName: 'ThisIsServerName',
//On client connect to server callback
allowConnect: (app: Application, tunnel: Tunnel, callback: AllowCallback) => {
callback(null)
},
//On client request received callback
allowRequest: (app: Application, tunnel: Tunnel, req: IncomingMessage, callback: AllowCallback) => {
callback(null)
},
//On client upgrade request received callback
allowUpgrade: (app: Application, tunnel: Tunnel, req: IncomingMessage, callback: AllowCallback) => {
callback(null)
},
//Redis is optional, if redis options not set, the server will be single server mode, else the server support HA mode
redisOptions: {
port: 6379,
host: 'localhost',
db: 13
}
},
client: {
class: TunnelClientComponent
}
},
workflows: [() => {
//Establish a local server listen port 8080 for test
const testServer = createServer((req, res) => {
res.write('OK')
res.end()
}).listen(8080, '0.0.0.0')
//Add websocket support for test
const wss = new WebSocketServer({noServer: true, path: '/ws'})
testServer.on('upgrade', (req, socket, head) => {
wss.handleUpgrade(req, socket, head, client => {
setInterval(() => {
client.send(`timestamp:${Date.now()}`)
}, 1000)
})
})
}]
})
const serverComponent: TunnelServerComponent = app.Components.get<TunnelServerComponent>('server')
serverComponent.on('upgrade_connection_close', (tunnel: Tunnel) => {
//On http upgrade socket closed
console.log('upgrade_connection_close', tunnel)
})
serverComponent.on('upgrade_connection_open', (tunnel: Tunnel) => {
//On http upgrade socket established
console.log('upgrade_connection_open', tunnel)
})
serverComponent.on('connection_close', (tunnel: Tunnel) => {
//On http request socket closed
console.log('connection_close', tunnel)
})
serverComponent.on('connection_open', (tunnel: Tunnel) => {
//On received http request
console.log('connection_open', tunnel)
})
const clientComponent: TunnelClientComponent = app.Components.get<TunnelClientComponent>('client')
const tunnelSocket: TunnelSocket = clientComponent.open({
//Tunnel server URL
server: 'http://tunnel.example.com',
//Assign a subdomain
subdomain: 'this-is-a-test',
//Local service port
port: 8080,
//Local IP or hostname
hostname: '127.0.0.1',
//If local server listening tls port, set it true
tls: false,
//Rewrite host in headers when forward request to local
rewriteHost: false,
//Is allow wildcard domain request proxy
allowWildcard: true,
//Use HTTP basic auth to protect local service
authorization: {
//Username for Basic Auth
username: 'user',
//Password for Basic Auth
password: 'pass',
//Whether add username field and password field to HTTP header
extract: false
}
})
//Print URL
tunnel.on('url', (url: string) => console.log('URL:', url))//this-is-a-test.tunnel.example.com
//On open event
tunnel.on('open', (tunnelSocket: TunnelSocket) => console.log(tunnelSocket))
//On close event
tunnel.on('close', (tunnelSocket: TunnelSocket) => console.log(tunnelSocket))
//On destroy event
tunnel.on('destroy', () => console.log('destroyed'))
//On error handler
tunnel.on('error', (exception: Exception) => console.error(exception))
/**
* On http upgrade socket closed
*/
on('upgrade_connection_close', (tunnel: Tunnel) => {
//Client information
})
/**
* On http upgrade socket established
*/
on('upgrade_connection_open', (tunnel: Tunnel) => {
//Client information
})
/**
* On http request socket closed
*/
on('connection_close', (tunnel: Tunnel) => {
//Client information
})
/**
* On received http request
*/
on('connection_open', (tunnel: Tunnel) => {
//Client information
})
Examples can be found in project src/tests.
Please let us know how can we help. Do check out issues for bug reports or suggestions first.