topnic-https 0.2.12 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "topnic-https",
3
- "version": "0.2.12",
3
+ "version": "1.2.1",
4
4
  "main": "./src/main/index.js",
5
5
  "type": "commonjs",
6
6
  "scripts": {
@@ -96,6 +96,7 @@
96
96
  "https": "^1.0.0",
97
97
  "localtunnel": "^2.0.2",
98
98
  "nanoid": "^5.0.8",
99
+ "ngrok": "^5.0.0-beta.2",
99
100
  "os": "^0.1.2",
100
101
  "path": "^0.12.7",
101
102
  "uuid": "^11.0.3",
@@ -1,37 +1,39 @@
1
- const localtunnel = require('localtunnel');
1
+ const TunnelServer = require('./tunnelServer');
2
2
  const { nanoid } = require('nanoid/non-secure');
3
3
 
4
4
  class ShareManager {
5
5
  constructor() {
6
6
  this.activeShares = new Map();
7
+ this.tunnelServer = TunnelServer;
8
+ }
9
+
10
+ async init() {
11
+ await this.tunnelServer.start();
7
12
  }
8
13
 
9
14
  async createShare(port, duration) {
10
15
  try {
11
- const tunnel = await localtunnel({
12
- port,
13
- subdomain: nanoid(6)
14
- });
15
-
16
- const shareId = tunnel.url.split('https://')[1].split('.')[0];
16
+ const tunnelId = await this.tunnelServer.createTunnel(port);
17
+ const publicIp = this.tunnelServer.publicIp;
18
+ const shareUrl = `http://${publicIp}:8000`;
17
19
 
18
20
  const share = {
19
- id: shareId,
20
- url: tunnel.url,
21
- tunnel,
21
+ id: tunnelId,
22
+ url: shareUrl,
22
23
  startTime: Date.now(),
23
24
  duration: duration * 60 * 1000
24
25
  };
25
26
 
26
- this.activeShares.set(shareId, share);
27
+ this.activeShares.set(tunnelId, share);
27
28
 
28
29
  setTimeout(() => {
29
- this.closeShare(shareId);
30
+ this.closeShare(tunnelId);
30
31
  }, share.duration);
31
32
 
32
33
  return {
33
- id: shareId,
34
- url: tunnel.url
34
+ id: tunnelId,
35
+ url: shareUrl,
36
+ localUrl: `http://localhost:8000`
35
37
  };
36
38
  } catch (error) {
37
39
  throw new Error(`فشل إنشاء المشاركة: ${error.message}`);
@@ -44,7 +46,7 @@ class ShareManager {
44
46
  throw new Error('لم يتم العثور على المشاركة');
45
47
  }
46
48
 
47
- await share.tunnel.close();
49
+ this.tunnelServer.closeTunnel(shareId);
48
50
  this.activeShares.delete(shareId);
49
51
  }
50
52
 
@@ -0,0 +1,110 @@
1
+ const http = require('http');
2
+ const https = require('https');
3
+ const WebSocket = require('ws');
4
+ const { nanoid } = require('nanoid/non-secure');
5
+ const os = require('os');
6
+
7
+ class TunnelServer {
8
+ constructor() {
9
+ this.tunnels = new Map();
10
+ this.server = http.createServer(this.handleRequest.bind(this));
11
+ this.wss = new WebSocket.Server({ server: this.server });
12
+ this.publicIp = this.getPublicIp();
13
+ }
14
+
15
+ getPublicIp() {
16
+ const interfaces = os.networkInterfaces();
17
+ let address;
18
+
19
+ for (const iface of Object.values(interfaces)) {
20
+ for (const alias of iface) {
21
+ if (alias.family === 'IPv4' && !alias.internal) {
22
+ address = alias.address;
23
+ break;
24
+ }
25
+ }
26
+ if (address) break;
27
+ }
28
+
29
+ return address;
30
+ }
31
+
32
+ async start(port = 8000) {
33
+ return new Promise((resolve) => {
34
+ this.server.listen(port, '0.0.0.0', () => {
35
+ console.log(`🚀 خادم النفق يعمل على المنفذ ${port}`);
36
+ console.log(`📡 عنوان IP العام: ${this.publicIp}`);
37
+ resolve();
38
+ });
39
+ });
40
+ }
41
+
42
+ async createTunnel(targetPort) {
43
+ const tunnelId = nanoid(6);
44
+ const tunnel = {
45
+ id: tunnelId,
46
+ targetPort,
47
+ clients: new Set(),
48
+ createdAt: Date.now()
49
+ };
50
+
51
+ this.tunnels.set(tunnelId, tunnel);
52
+ return tunnelId;
53
+ }
54
+
55
+ async handleRequest(req, res) {
56
+ const tunnelId = req.headers.host.split('.')[0];
57
+ const tunnel = this.tunnels.get(tunnelId);
58
+
59
+ if (!tunnel) {
60
+ res.writeHead(404);
61
+ res.end('النفق غير موجود');
62
+ return;
63
+ }
64
+
65
+ // إعادة توجيه الطلب إلى الخادم المحلي
66
+ const options = {
67
+ hostname: 'localhost',
68
+ port: tunnel.targetPort,
69
+ path: req.url,
70
+ method: req.method,
71
+ headers: req.headers
72
+ };
73
+
74
+ const proxyReq = http.request(options, (proxyRes) => {
75
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
76
+ proxyRes.pipe(res);
77
+ });
78
+
79
+ req.pipe(proxyReq);
80
+
81
+ proxyReq.on('error', (error) => {
82
+ console.error('خطأ في النفق:', error);
83
+ res.writeHead(502);
84
+ res.end('خطأ في الاتصال بالخادم المحلي');
85
+ });
86
+ }
87
+
88
+ handleConnection(ws, req) {
89
+ const tunnelId = req.headers.host.split('.')[0];
90
+ const tunnel = this.tunnels.get(tunnelId);
91
+
92
+ if (tunnel) {
93
+ tunnel.clients.add(ws);
94
+
95
+ ws.on('close', () => {
96
+ tunnel.clients.delete(ws);
97
+ });
98
+ }
99
+ }
100
+
101
+ closeTunnel(tunnelId) {
102
+ const tunnel = this.tunnels.get(tunnelId);
103
+ if (tunnel) {
104
+ tunnel.clients.forEach(client => client.close());
105
+ this.tunnels.delete(tunnelId);
106
+ }
107
+ }
108
+ }
109
+
110
+ module.exports = new TunnelServer();