mirror of
https://github.com/lush2020/edgetunnel.git
synced 2026-03-23 16:38:34 +08:00
Dev (#65)
* chaneg deno code * enhance logic * chaneg to remove eol * add cient code * remove end call * enhance logger * add doc
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
一个无比简单安全,基于 edge 的 tunnel 。
|
一个无比简单安全,基于 edge 的 tunnel 。
|
||||||
|
|
||||||
**v2ray-heroku 由于 heroku 取消免费,项目已经死了。 这是新的项目。**
|
**v2ray-heroku 由于 heroku 取消免费,项目已经死了。如果你还需要 v2ray-heroku, 请访问 [yaolin-0/v2ray-heroku](https://github.com/yaolin-0/v2ray-heroku)**
|
||||||
|
|
||||||
> 项目正在开发,基本可用,会有 bug。。
|
> 项目正在开发,基本可用,会有 bug。。
|
||||||
> **请定期按照 github 的提示,只同步到自己的项目。只需要在乎下图红框的提示,其他提示不要点击**。
|
> **请定期按照 github 的提示,只同步到自己的项目。只需要在乎下图红框的提示,其他提示不要点击**。
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"port": "",
|
"port": "",
|
||||||
"address": "",
|
"address": "",
|
||||||
"uuid": ""
|
"uuid": "",
|
||||||
|
"logLevel": "DEBUG"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
import { writeFileSync, existsSync, readFileSync } from 'fs';
|
import { writeFileSync, existsSync, readFileSync } from 'fs';
|
||||||
import { exit } from 'node:process';
|
import { exit } from 'node:process';
|
||||||
|
import { env } from 'process';
|
||||||
let config: {
|
let config: {
|
||||||
port: string;
|
port: string;
|
||||||
address: string;
|
address: string;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
config: string;
|
logLevel: string;
|
||||||
} = null;
|
} = null;
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
program.option('-v').action((options) => {
|
program.option('-v').action((options) => {
|
||||||
@@ -54,5 +55,6 @@ program
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
program.parse();
|
program.parse();
|
||||||
|
env.NODE_ENV = env.NODE_ENV || 'production';
|
||||||
|
|
||||||
export { config };
|
export { config };
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IncomingMessage } from 'http';
|
import { IncomingMessage } from 'http';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as url from 'node:url';
|
import * as url from 'node:url';
|
||||||
|
import { config } from './cmd';
|
||||||
|
|
||||||
async function* concatStreams(readables: any[]) {
|
async function* concatStreams(readables: any[]) {
|
||||||
for (const readable of readables) {
|
for (const readable of readables) {
|
||||||
@@ -57,9 +58,37 @@ function rawHTTPPackageWithDelay(req: IncomingMessage) {
|
|||||||
return concatStreams([[rawHttpHeader], req, deplay(500)]);
|
return concatStreams([[rawHttpHeader], req, deplay(500)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function errorHandler() {
|
||||||
|
process
|
||||||
|
.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.error(reason, 'Unhandled Rejection at Promise', p);
|
||||||
|
})
|
||||||
|
.on('uncaughtException', (err) => {
|
||||||
|
console.error(err, 'Uncaught Exception thrown');
|
||||||
|
// should exit node.js, but anyway
|
||||||
|
// process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loghelper(...args) {
|
||||||
|
let logs = args;
|
||||||
|
if (config.logLevel?.toUpperCase() !== 'DEBUG') {
|
||||||
|
logs = args.map((item) => {
|
||||||
|
if (item instanceof Error) {
|
||||||
|
return `${item.message}`;
|
||||||
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log('', ...logs);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
concatStreams,
|
concatStreams,
|
||||||
rawHTTPPackage,
|
rawHTTPPackage,
|
||||||
rawHTTPHeader,
|
rawHTTPHeader,
|
||||||
rawHTTPPackageWithDelay,
|
rawHTTPPackageWithDelay,
|
||||||
|
errorHandler,
|
||||||
|
loghelper,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,21 +3,33 @@ import { pipeline, Readable } from 'node:stream';
|
|||||||
import { config } from './lib/cmd';
|
import { config } from './lib/cmd';
|
||||||
import * as url from 'node:url';
|
import * as url from 'node:url';
|
||||||
import * as undici from 'undici';
|
import * as undici from 'undici';
|
||||||
import { concatStreams, rawHTTPPackage } from './lib/helper';
|
import {
|
||||||
|
concatStreams,
|
||||||
|
rawHTTPPackage,
|
||||||
|
errorHandler,
|
||||||
|
loghelper,
|
||||||
|
} from './lib/helper';
|
||||||
|
|
||||||
const isLocal = process.env.LOCAL === 'true';
|
errorHandler();
|
||||||
|
|
||||||
|
const isLocal = process.env.DEBUG === 'true';
|
||||||
const httpProxyServer = createServer(async (req, resp) => {
|
const httpProxyServer = createServer(async (req, resp) => {
|
||||||
const reqUrl = url.parse(req.url);
|
const reqUrl = url.parse(req.url);
|
||||||
const clientSocketLoggerInfo = `[proxy to ${req.url}](http)`;
|
const clientSocketLoggerInfo = `[proxy to ${req.url}](http)`;
|
||||||
try {
|
try {
|
||||||
console.log(`${clientSocketLoggerInfo} Client use HTTP/${req.httpVersion}`);
|
loghelper(`${clientSocketLoggerInfo} Client use HTTP/${req.httpVersion}`);
|
||||||
|
|
||||||
// for await (const chunk of req.socket) {
|
|
||||||
// console.log(chunk.toString());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// make call to edge http server
|
// make call to edge http server
|
||||||
// 1. forward all package remote, socket over http body
|
// 1. forward all package remote, socket over http body
|
||||||
|
const fromClientReq = Readable.from(rawHTTPPackage(req)).on(
|
||||||
|
'error',
|
||||||
|
(error) => {
|
||||||
|
loghelper(
|
||||||
|
`${clientSocketLoggerInfo} client socket to remote http body has error`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
req.destroy();
|
||||||
|
}
|
||||||
|
);
|
||||||
const { body, headers, statusCode, trailers } = await undici.request(
|
const { body, headers, statusCode, trailers } = await undici.request(
|
||||||
config.address,
|
config.address,
|
||||||
{
|
{
|
||||||
@@ -28,30 +40,32 @@ const httpProxyServer = createServer(async (req, resp) => {
|
|||||||
'x-http': 'true',
|
'x-http': 'true',
|
||||||
},
|
},
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: Readable.from(rawHTTPPackage(req)),
|
body: fromClientReq,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(
|
loghelper(
|
||||||
`${clientSocketLoggerInfo} remote server return ${statusCode} Connected To Proxy`
|
`${clientSocketLoggerInfo} remote server return ${statusCode} Connected To Proxy`
|
||||||
);
|
);
|
||||||
// 2. forward remote reponse body to clientSocket
|
// 2. forward remote reponse body to clientSocket
|
||||||
for await (const chunk of body) {
|
for await (const chunk of body) {
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
console.log(chunk.toString());
|
loghelper(chunk.toString());
|
||||||
}
|
}
|
||||||
req.socket.write(chunk);
|
req.socket.write(chunk);
|
||||||
|
// resp.write(chunk);
|
||||||
}
|
}
|
||||||
|
// resp.end();
|
||||||
body.on('error', (err) => {
|
body.on('error', (err) => {
|
||||||
console.log(
|
loghelper(
|
||||||
`${clientSocketLoggerInfo} remote server response body has error`,
|
`${clientSocketLoggerInfo} remote server response body has error`,
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
req.socket.destroy();
|
req.destroy();
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
req.destroy();
|
||||||
req.socket?.end();
|
req.socket?.end();
|
||||||
req.socket?.destroy();
|
loghelper(`${clientSocketLoggerInfo} has error `, error);
|
||||||
console.log(`${clientSocketLoggerInfo} has error `, error);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,8 +73,9 @@ const httpProxyServer = createServer(async (req, resp) => {
|
|||||||
httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
||||||
const reqUrl = url.parse('https://' + req.url);
|
const reqUrl = url.parse('https://' + req.url);
|
||||||
const clientSocketLoggerInfo = `[proxy to ${req.url}]`;
|
const clientSocketLoggerInfo = `[proxy to ${req.url}]`;
|
||||||
|
let fromClientSocket = null;
|
||||||
try {
|
try {
|
||||||
console.log(
|
loghelper(
|
||||||
`${clientSocketLoggerInfo} Client use HTTP/${
|
`${clientSocketLoggerInfo} Client use HTTP/${
|
||||||
req.httpVersion
|
req.httpVersion
|
||||||
} Connected To Proxy, head on connect is ${head.toString() || 'empty'}`
|
} Connected To Proxy, head on connect is ${head.toString() || 'empty'}`
|
||||||
@@ -70,18 +85,10 @@ httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
|||||||
`HTTP/${req.httpVersion} 200 Connection Established\r\n\r\n`
|
`HTTP/${req.httpVersion} 200 Connection Established\r\n\r\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
// console.log(config);
|
// loghelper(config);
|
||||||
// make call to edge http server
|
// make call to edge http server
|
||||||
// 1. forward all package remote, socket over http body
|
// 1. forward all package remote, socket over http body
|
||||||
const fromClientSocket = Readable.from(
|
fromClientSocket = Readable.from(concatStreams([head, clientSocket]));
|
||||||
concatStreams([head, clientSocket])
|
|
||||||
).on('error', (error) => {
|
|
||||||
console.log(
|
|
||||||
`${clientSocketLoggerInfo} client socket to remote http body has error`,
|
|
||||||
error
|
|
||||||
);
|
|
||||||
clientSocket.destroy();
|
|
||||||
});
|
|
||||||
const { body, headers, statusCode, trailers } = await undici.request(
|
const { body, headers, statusCode, trailers } = await undici.request(
|
||||||
config.address,
|
config.address,
|
||||||
{
|
{
|
||||||
@@ -95,46 +102,57 @@ httpProxyServer.on('connect', async (req, clientSocket, head) => {
|
|||||||
body: fromClientSocket,
|
body: fromClientSocket,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(`${clientSocketLoggerInfo} remote server return ${statusCode}`);
|
fromClientSocket.on('error', (error) => {
|
||||||
|
loghelper(
|
||||||
|
`${clientSocketLoggerInfo} client socket to remote http body has error`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
//
|
||||||
|
fromClientSocket.push(null);
|
||||||
|
clientSocket.destroy();
|
||||||
|
});
|
||||||
|
loghelper(`${clientSocketLoggerInfo} remote server return ${statusCode}`);
|
||||||
// 2. forward remote reponse body to clientSocket
|
// 2. forward remote reponse body to clientSocket
|
||||||
for await (const chunk of body) {
|
for await (const chunk of body) {
|
||||||
clientSocket.write(chunk);
|
clientSocket.write(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.on('error', (err) => {
|
body.on('error', (err) => {
|
||||||
console.log(
|
loghelper(
|
||||||
`${clientSocketLoggerInfo} remote response body has error`,
|
`${clientSocketLoggerInfo} remote response body has error`,
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
|
fromClientSocket.push(null);
|
||||||
clientSocket.destroy();
|
clientSocket.destroy();
|
||||||
});
|
});
|
||||||
clientSocket.on('error', (e) => {
|
clientSocket.on('error', (e) => {
|
||||||
body?.destroy();
|
body?.destroy();
|
||||||
clientSocket.destroy();
|
fromClientSocket.push(null);
|
||||||
console.log(`${clientSocketLoggerInfo} clientSocket has error: ` + e);
|
clientSocket.end();
|
||||||
|
loghelper(`${clientSocketLoggerInfo} clientSocket has error: ` + e);
|
||||||
});
|
});
|
||||||
clientSocket.on('end', () => {
|
clientSocket.on('end', () => {
|
||||||
console.log(`${clientSocketLoggerInfo} has done and end.`);
|
loghelper(`${clientSocketLoggerInfo} has done and end.`);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clientSocket.destroy();
|
fromClientSocket?.push(null);
|
||||||
console.log(`${clientSocketLoggerInfo} has error `, error);
|
clientSocket.end();
|
||||||
|
loghelper(`${clientSocketLoggerInfo} has error `, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
httpProxyServer.on('error', (err) => {
|
httpProxyServer.on('error', (err) => {
|
||||||
console.log('SERVER ERROR');
|
loghelper('SERVER ERROR', err);
|
||||||
console.log(err);
|
|
||||||
throw err;
|
|
||||||
});
|
});
|
||||||
httpProxyServer.on('clientError', (err, clientSocket) => {
|
httpProxyServer.on('clientError', (err, clientSocket) => {
|
||||||
console.log('client error: ' + err);
|
loghelper('client error: ' + err);
|
||||||
clientSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
clientSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
httpProxyServer.on('close', () => {
|
httpProxyServer.on('close', () => {
|
||||||
console.log('Server close');
|
loghelper('Server close');
|
||||||
});
|
});
|
||||||
|
|
||||||
httpProxyServer.listen(Number(config.port), () => {
|
httpProxyServer.listen(Number(config.port), () => {
|
||||||
console.log('Server runnig at http://localhost:' + config.port);
|
loghelper('Server runnig at http://localhost:' + config.port);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user