-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
144 lines (139 loc) · 3.74 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env node
/**
* @author SusonJohn <[email protected]>
*/
const Redis = require('ioredis');
const Client = require('ssh2').Client;
const net = require('net');
const fs = require('fs');
function connectToSSH(options) {
return new Promise((resolve, reject) => {
const connection = new Client();
connection.once('ready', () => resolve(connection));
connection.once('error', reject);
connection.connect(options);
});
}
function connectToRedis(options) {
const redis = new Redis(options);
return new Promise((resolve, reject) => {
redis.once('error', reject);
redis.once('ready', () => resolve(redis));
});
}
function createIntermediateServer(connectionListener) {
return new Promise((resolve, reject) => {
const server = net.createServer(connectionListener);
server.once('error', reject);
server.listen(0, () => resolve(server));
});
}
async function connect(sshConfig, redisConfig) {
let redis, server, sshConnection, sshDefualt
sshDefualt = {
host: sshConfig.host,
port: sshConfig.port,
username: sshConfig.user
}
if (sshConfig.password) {
sshDefualt = {
...sshDefualt,
password: sshConfig.password
}
}
if (sshConfig.privateKey) {
sshDefualt = {
...sshDefualt,
privateKey: sshConfig.privateKey
}
}
try {
sshConnection = await connectToSSH({
...sshDefualt
});
} catch (err) {
throw new Error(`sshConnection failed ${err}`)
}
tunnel._conn = sshConnection
try {
server = await createIntermediateServer(socket => {
sshConnection.forwardOut(
socket.remoteAddress,
socket.remotePort,
redisConfig.host,
redisConfig.port,
(error, stream) => {
if (error) {
socket.end();
} else {
socket.pipe(stream).pipe(socket);
}
}
);
});
} catch (err) {
throw new Error(`createIntermediateServer failed ${err}`)
}
let sshRedis
sshRedis = {
host: server.address().address,
port: server.address().port,
db: redisConfig.db
}
if (redisConfig.password) {
sshRedis = {
...sshRedis,
password: redisConfig.password
}
}
if (redisConfig.privateKey) {
sshRedis = {
...sshRedis,
privateKey: redisConfig.privateKey
}
}
try {
// Redis specify the address of the intermediate server, not the server
redis = await connectToRedis({
...sshRedis
});
tunnel._redis = redis
return redis
} catch (err) {
throw new Error(`connectToRedis failed ${err}`)
}
}
var tunnel = module.exports = {
/**
* @var ssh2.Connection _conn The SSH connection
*/
_conn: null,
/**
* @var Redis2.Connection _conn The Redis connection
*/
_redis: null,
/**
* @param redis Redis connection
* @param conn ssh connection
* @return Promise <Redis and ssh connection>
*/
connect: function (sshConfig, redisConfig) {
return new Promise((resolve, reject) => {
connect(sshConfig, redisConfig).then(
redis=>{
resolve(redis)
}
).catch(err=>{
reject(err)
})
})
},
close: function () {
if ('end' in tunnel._redis) {
tunnel._redis.end()
}
if ('end' in tunnel._conn) {
tunnel._conn.end()
}
}
}