npm package: @lakutata-component/tunnel
Description: Lakutata Tunnel Component
Author: alex.ma
Latest version: 1.0.25

<div style="text-align:center">
    <img src="https://gitee.com/nnxr/lakutata-component-tunnel/raw/master/assets/lakutata-banner.png" />
</div>

[![NPM Version](https://img.shields.io/npm/v/@lakutata-component/tunnel?color=informational&style=flat-square)](https://npmjs.org/package/@lakutata-component/tunnel)
[![NODE Version](https://img.shields.io/node/v/@lakutata-component/tunnel?color=informational&style=flat-square)](https://npmjs.org/package/@lakutata-component/tunnel)
[![Known Vulnerabilities](https://snyk.io/test/npm/@lakutata-component/tunnel/badge.svg?style=flat-square)](https://snyk.io/test/npm/@lakutata-component/tunnel)
[![NPM Download](https://img.shields.io/npm/dm/@lakutata-component/tunnel?style=flat-square)](https://npmjs.org/package/@lakutata-component/tunnel)

## Features

- Internet Penetration
- Integrate server side & client side
- Support cluster (Share TCP stream via redis pub/sub)
- Based on WebSocket transport
- Support HTTP Basic Auth

## Quickstart

### How to use

```typescript
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))
```

## Server-Side Events

```typescript
/**
 * 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

Examples can be found in project [src/tests](https://gitee.com/nnxr/lakutata-component-tunnel/tree/master/src/tests).

## How to Contribute

Please let us know how can we help. Do check out [issues](https://gitee.com/nnxr/lakutata-component-tunnel/issues) for
bug reports
or suggestions first.

## License

[MIT](LICENSE)