@serverpanel/tcp v1.0.2
TCP
This is a utility package which helps simplify secure communication between a client and a server over TCP. It transmits values over channels, similar to event emitters, and offers a connection guard on the server.
Overview
When a connection is first established, the client sends an identity (such as a username) to the server. The server's guard will receive the connection and identity, and may accept or reject the connection.
Approved connections become active and can actively transmit values back and forth between the client and server. These transactions are automatically encrypted with RSA public keys which are exchanged when the connection is accepted.
Each transaction is also encrypted with AES256. For this to work, both the server and client must already know the password. The server's guard can set a different password for each client, but a connection will not establish unless both sides agree on a password.
Server
The server binds to a port and uses the connection
event as a guard. You can accept incoming connections by calling
connection.accept()
with a 32-character password for AES256 encryption.
const server = new Server(12345);
server.on('connection', async connection => {
let ip = connection.getAddress();
let identity = connection.getIdentity();
if (identity == 'baileyherbert') {
await connection.accept('00a3ac30ef0b23da56f09fc5b68f40fa');
await connection.send('notification', 'Welcome back!');
}
});
server.start();
Client
The client connects directly to the server given the port, host, and an identity string. When starting the client with
start()
, a 32-character password must be supplied which must match the password provided by the server with accept()
.
const client = new Client(12345, '127.0.0.1', 'baileyherbert');
client.start('00a3ac30ef0b23da56f09fc5b68f40fa').then(async () => {
client.listen('notification', message => {
console.log('The server said:', message);
});
await client.send('event', 'signed_in');
});
Data
Many different types of data can be sent. They are encoded to JSON while transmitting over encryption, and are decoded before triggering listeners. For instance, all of the following are supported:
client.send('channel', true);
client.send('channel', 'some text');
client.send('channel', 125.3);
client.send('channel', { name: 'John Doe' });
Buffering
The internal socket is configured to send data without delay on both sides of a connection. However, Node will sometimes emit data in chunks. To address this, the package implements a newline buffer. It is important to note that this is managed internally, and you do not need to manually append a new line character to the end of your data payloads.
Calls
This package supports a call
method which works similarly to send
, but gives us the return value of the remote
function which listened to it.
// Server can return immediately or through a promise:
connection.listen('updateProfile', changes => {
return { id: 42 };
return new Promise(resolve => {
resolve({ id: 42 });
});
});
// The client gets it back when using call():
client.call('updateProfile', { name: 'John Smith' }).then(profile => {
console.log('Profile updated for user', profile.id); // 42
});
TypeScript
When working with TypeScript, you can use generics to constrain data types.
client.send<boolean>('channel', true); // valid
client.send<boolean>('channel', 'string'); // error
client.listen<{ name: string }>('channel', info => {
let { name } = info; // valid, recognizes as string
let { age } = info; // error, age not found
});
client.call<boolean>('channel').then(bool => ...);
client.call<boolean, string>('channel', str).then(bool => ...);