@kumori/tcp-proxy

Proxy for tunneling TCP connections through Kumori's channels

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@kumori/tcp-proxy
001.0.36 years ago6 years agoMinified + gzip package size for @kumori/tcp-proxy in KB

Readme

semantic-release
Tcp Proxy
Proxy for tunneling TCP connection through Kumori's platform channels

Description

This module proxifies a legacy tcp server connections through Kumori's channels (see Kumori's documentation for more information about channels and Kumori's service application model).

Table of Contents

Installation

Install it as a npm package
npm install -g @kumori/tcp-proxy

Usage

In general, we may have situations in which a component functionality is actually provided by an existing server program, expecting access to IP networks, and such that it is either costly, impractical or outright impossible to carry out any sort of change in their code.
As was the case of the Http Proxy, the component should be properly specified, with the channels that make sense to how it is to be connected, and the configuration needed for semantically consistent set up of the legacy server.
Besides this configuration, however, we will need a way to convert the IP-based configuration directly supported by the legacy server to interact with other roles within the deployed service.
Just as in the case of the web server, the approach will require the component module to act as an adapter, launching the legacy server to interact with the +localhost+ network interface, through adequate network ports.
Unlike the case of the legacy web server, we now can have an arbitrary protocol being spoken by the legacy server, thus we need a "neutral" solution. For this case {ecloud} provides a @kumori/tcp-proxy module that can be used by the adapter/component to tunnel IP protocols through {ecloud} channels transparently to the legacy server code.
In this case, the channel protocol knows nothing about the higher level protocol supported by the server, limiting itself to ship the bytes being pushed back and forth by legacy pieces of software.
The following shows an example of how to generally set up this kind of legacy support.
Component = require 'component'
TcpProxy = require('@kumori/tcp-proxy').TcpProxy  #<1>
child = require 'child-process'

module.exports = class MyComponent extends Component
  ...
  run: () ->
    [server, parameters, channels] = @computeServerParametersAndChannels() #<2>

    @proxy = new TcpProxy @iid, @role, channels      #<3>

    @proxy.on 'ready', (@bindIp) =>                  #<4>
      @startLegacyServer server, bindIp, parameters

    @proxy.on 'error', (err) =>                      #<5>
      @processProxyError err

    @proxy.on 'change', (data) =>                    #<6>
      @reconfigLegacyServer server, bindIp, parameters, data

    @proxy.on 'close', () =>                         #<7>
      @stopLegacyServer server, parameters

  shutdown: ->
    @proxy.shutdown()                                #<8>
  ...

  1. We now require the generic @kumori/tcp-proxy module.
  2. Assuming method computeServerParametersAndChannels returns as in
Http Proxy the server program and parameters to pass to it. But,
in addition, it returns an object relating the component's channels to the
legacy server ports/connections/bindings.
  1. TcpProxy object initialization requires the role and ID of the instance,
and the list of channels (with additional information) to be proxied.
  1. TcpProxy object issues an event when it is ready to process requests,
providing the local IP address to be assigned to the legacy server.
For *TcpProxy* to function properly, legacy server must be bound to that
IP.
  1. TcpProxy object issues an event when an error occurs.
  2. TcpProxy object issues an event, during its life cycle, when any change
occurs that should result in a reconfiguration of the legacy server.
  1. TcpProxy object issues an event when it's closed.
  2. TcpProxy object finalization.

While method computeServerParameters is straightforward to write, needing only to know how to start the legacy server, writing method computeServerParametersAndChannels will require knowing how to configure the TcpProxy object too.

Configuring the TcpProxy object

TcpProxy object initialization requires an object relating the component's channels to the legacy server ports/connections/bindings.
This object is a dictionary whose key is the channel name, and values contains:
  • A reference to the channel object
  • TCP port to be proxied
  • In case of duplex channels, its operating mode (bind/connect)

Example configuration for a TcpProxy that proxies four channels:
{
  'myDuplex1': {
    channel: myDuplex1,
    port: 9100,
    mode: 'bind'
  },
  'myDuplex2': {
    channel: myDuplex2,
    port: 9100,
    mode: 'connect'
  },
  'myRequest3': {
    channel: myRequest3,
    port: 9200
  },
  'myReply4': {
    channel: myReply4,
    port: 9200
  }
}

Ready event

When TcpProxy object is ready to process requests, a 'ready' event is emitted,
Data associated with this event is the local IP address to be used by the legacy server.
Typically, this IP address is used when starting the legacy server with duplex/bind or a reply channels. Typically, this information is not used with duplex/connect or a request channels.
@proxy.on 'ready', (bindIp) =>
  @_startLegacyServer bindIp, ...

Error event

TcpProxy object can issue error events, basically during the creation of internal connections initializing the proxy.
@proxy.on 'error', (err) =>
  ...

Change event

During its life cycle, TcpProxy object emits change events when any change occurs, which may result in a reconfiguration of the legacy server.
Data associated with this event will vary depending on the channel that caused it.
@proxy.on 'change', (data) ->
  @reconfigLegacyServer server, bindIp, parameters, data

Request

When a request channel is proxied, a TCP port is opened in a local IP address. A change event is issued when TcpProxy is ready and listening on this port. An event is issued too, when the port is closed (this happens when the instance is shutting down, so usually an action on the legacy server is not required). Event data contains parameters that legacy server could need to be reconfigured:
  • Listening (true/false)
  • Channel name
  • IP
  • Port

For example:
{
  channel: 'myRequest3',
  listening: true,
  ip: ip:'127.0.0.7',
  port: 9300
}

Reply

Never issues change events.

Duplex

When the set of instances attached to the complete connector (duplex channels) changes, TcpProxy issues a change event. Event data is a list of current members with the information that the legacy server could need to be reconfigured:
  • Channel name
  • Instance ID
  • IP
  • Port

For example:
{
  channel: 'myDuplex1',
  members: [
    {iid:'A_10', ip:'127.0.0.7', port:9100},
    {iid:'A_11', ip:'127.0.0.8', port:9100},
    {iid:'A_12', ip:'127.0.0.9', port:9100}
  ]
]

Close event

After TcpProxy.shutdown() method is invoked, a 'close' event is emitted when operation is finished.
@proxy.on 'close', () =>
  ...

License

MIT © Kumori Systems