topnic-https 0.0.6 → 0.1.8

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/bin/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { program } = require('commander');
4
4
  const server = require('../src/main/index.js');
5
+ const shareManager = require('../src/sharing/shareManager');
5
6
 
6
7
  program
7
8
  .version('1.0.0')
@@ -35,4 +36,56 @@ program
35
36
  server.changePort(port);
36
37
  });
37
38
 
39
+ program
40
+ .command('share')
41
+ .description('Share your local server temporarily')
42
+ .option('-p, --port <number>', 'Port to share', 3000)
43
+ .option('-d, --duration <minutes>', 'Share duration in minutes', 60)
44
+ .action(async (options) => {
45
+ try {
46
+ const share = await shareManager.createShare(options.port, options.duration);
47
+ console.log('\n📢 Share Information:');
48
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
49
+ console.log(`🔗 Public URL: ${share.url}`);
50
+ console.log(`🆔 Share ID: ${share.id}`);
51
+ console.log(`⏱️ Duration: ${options.duration} minutes`);
52
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
53
+ } catch (error) {
54
+ console.error('❌ Failed to create share:', error.message);
55
+ }
56
+ });
57
+
58
+ program
59
+ .command('shares')
60
+ .description('List all active shares')
61
+ .action(() => {
62
+ const shares = shareManager.getActiveShares();
63
+ if (shares.length === 0) {
64
+ console.log('📭 No active shares');
65
+ return;
66
+ }
67
+
68
+ console.log('\n📋 Active Shares:');
69
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
70
+ shares.forEach(share => {
71
+ console.log(`🔗 URL: ${share.url}`);
72
+ console.log(`🆔 ID: ${share.id}`);
73
+ console.log(`⏱️ Remaining: ${share.remainingMinutes} minutes`);
74
+ console.log('────────────────────────────────────────');
75
+ });
76
+ console.log('');
77
+ });
78
+
79
+ program
80
+ .command('unshare <shareId>')
81
+ .description('Stop sharing a specific server')
82
+ .action(async (shareId) => {
83
+ try {
84
+ await shareManager.closeShare(shareId);
85
+ console.log(`✅ Share ${shareId} has been stopped`);
86
+ } catch (error) {
87
+ console.error('❌ Failed to stop share:', error.message);
88
+ }
89
+ });
90
+
38
91
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "topnic-https",
3
- "version": "0.0.6",
3
+ "version": "0.1.8",
4
4
  "main": "./src/main/index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -89,8 +89,12 @@
89
89
  "dependencies": {
90
90
  "chokidar": "^4.0.1",
91
91
  "commander": "^12.1.0",
92
+ "electron": "^33.2.0",
92
93
  "fs": "^0.0.1-security",
93
94
  "https": "^1.0.0",
94
- "path": "^0.12.7"
95
+ "localtunnel": "^2.0.2",
96
+ "nanoid": "^5.0.8",
97
+ "path": "^0.12.7",
98
+ "ws": "^8.18.0"
95
99
  }
96
100
  }
package/readme CHANGED
@@ -15,11 +15,23 @@ $ npm install -g topnic-https
15
15
  - يدعم الخادم المنطق البسيط
16
16
  - يدعم الخادم التوجيه الأساسي
17
17
  - يدعم الخادم الإختصارات المخصصة
18
+ - يدعم الخادم المشاركة في الويب لمده مؤقتة
18
19
 
19
20
  ## الإختصارات
20
- - CommandOrControl+Shift+H+R - لتشغيل الخادم
21
- - CommandOrControl+Shift+H+S - لإيقاف الخادم
22
- - CommandOrControl+Shift+H+R+R - لإعادة تشغيل الخادم
21
+ - CommandOrControl+H+R - لتشغيل الخادم
22
+ - CommandOrControl+H+S - لإيقاف الخادم
23
+ - CommandOrControl+H+R+R - لإعادة تشغيل الخادم
24
+ - httpst share - لإنشاء مشاركة في الويب لمده مؤقتة
25
+
26
+ ## أمثلة
27
+ ```bash
28
+ $ httpst share -p 3000 -d 60 # مشاركة لمدة 60 دقيقة
29
+ $ httpst run #تشغيل الخادم
30
+ $ httpst stop #إيقاف الخادم
31
+ $ httpst restart #إعادة تشغيل الخادم
32
+ $ httpst change 3000 #تغيير بورت الخادم
33
+ ```
34
+ - لإنشاء مشاركة في الويب لمده مؤقتة
23
35
 
24
36
  # المطور
25
37
  - ManKTrip
@@ -0,0 +1,72 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const defaultConfig = {
5
+ port: 3000,
6
+ ssl: {
7
+ enabled: true,
8
+ key: './ssl/key.pem',
9
+ cert: './ssl/cert.pem'
10
+ },
11
+ cors: {
12
+ enabled: true,
13
+ origin: '*',
14
+ methods: ['GET', 'POST', 'OPTIONS']
15
+ },
16
+ compression: {
17
+ enabled: true,
18
+ level: 6
19
+ },
20
+ cache: {
21
+ enabled: true,
22
+ maxAge: 31536000
23
+ },
24
+ hotReload: {
25
+ enabled: true,
26
+ ignore: ['.git', 'node_modules']
27
+ },
28
+ logging: {
29
+ enabled: true,
30
+ level: 'info'
31
+ },
32
+ shortcuts: {
33
+ enabled: true,
34
+ custom: {}
35
+ }
36
+ };
37
+
38
+ class Config {
39
+ static load(configPath) {
40
+ try {
41
+ const userConfig = fs.existsSync(configPath)
42
+ ? JSON.parse(fs.readFileSync(configPath))
43
+ : {};
44
+ return { ...defaultConfig, ...userConfig };
45
+ } catch (error) {
46
+ Logger.error(`Error loading config: ${error.message}`);
47
+ return defaultConfig;
48
+ }
49
+ }
50
+
51
+ static save(config, configPath) {
52
+ try {
53
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
54
+ Logger.success('Config saved successfully');
55
+ } catch (error) {
56
+ Logger.error(`Error saving config: ${error.message}`);
57
+ }
58
+ }
59
+
60
+ static configure(options) {
61
+ try {
62
+ const newConfig = { ...defaultConfig, ...options };
63
+ Logger.info('Configuration updated');
64
+ return newConfig;
65
+ } catch (error) {
66
+ Logger.error(`Error configuring: ${error.message}`);
67
+ return defaultConfig;
68
+ }
69
+ }
70
+ }
71
+
72
+ module.exports = Config;
package/src/main/index.js CHANGED
@@ -3,9 +3,9 @@ const fs = require('fs');
3
3
  const path = require('path');
4
4
  const zlib = require('zlib');
5
5
  const { globalShortcut } = require('electron');
6
- const server = require('../main/index.js');
6
+ const Config = require('../config/index.js');
7
7
 
8
- let server;
8
+ let httpServer;
9
9
  let currentPort = 3000;
10
10
 
11
11
  const defaultOptions = {
@@ -244,18 +244,18 @@ function serveStaticFile(req, res) {
244
244
  }
245
245
 
246
246
  function start() {
247
- server = https.createServer(defaultOptions, (req, res) => {
247
+ httpServer = https.createServer(defaultOptions, (req, res) => {
248
248
  serveStaticFile(req, res);
249
249
  });
250
250
 
251
- server.listen(currentPort, () => {
251
+ httpServer.listen(currentPort, () => {
252
252
  console.log(`🚀 Server running on https://localhost:${currentPort}`);
253
253
  });
254
254
  }
255
255
 
256
256
  function stop() {
257
- if (server) {
258
- server.close(() => {
257
+ if (httpServer) {
258
+ httpServer.close(() => {
259
259
  console.log('Server stopped');
260
260
  });
261
261
  }
@@ -269,7 +269,7 @@ function restart() {
269
269
 
270
270
  function changePort(newPort) {
271
271
  currentPort = parseInt(newPort) || 3000;
272
- if (server) {
272
+ if (httpServer) {
273
273
  restart();
274
274
  }
275
275
  console.log(`Port changed to ${currentPort}`);
@@ -278,17 +278,17 @@ function changePort(newPort) {
278
278
  function registerShortcuts() {
279
279
  globalShortcut.register('CommandOrControl+Shift+H+R', () => {
280
280
  console.log('🚀 Starting server via shortcut...');
281
- server.start();
281
+ httpServer.start();
282
282
  });
283
283
 
284
284
  globalShortcut.register('CommandOrControl+Shift+H+S', () => {
285
285
  console.log('🛑 Stopping server via shortcut...');
286
- server.stop();
286
+ httpServer.stop();
287
287
  });
288
288
 
289
289
  globalShortcut.register('CommandOrControl+Shift+H+R+R', () => {
290
290
  console.log('🔄 Restarting server via shortcut...');
291
- server.restart();
291
+ httpServer.restart();
292
292
  });
293
293
  }
294
294
 
@@ -0,0 +1,25 @@
1
+ const WebSocket = require('ws');
2
+
3
+ function setupWebSocket(server) {
4
+ const wss = new WebSocket.Server({ server });
5
+
6
+ wss.on('connection', (ws) => {
7
+ console.log('🔌 New client connected');
8
+
9
+ ws.on('close', () => {
10
+ console.log('Client disconnected');
11
+ });
12
+ });
13
+
14
+ return wss;
15
+ }
16
+
17
+ function notifyClients(wss, message) {
18
+ wss.clients.forEach((client) => {
19
+ if (client.readyState === WebSocket.OPEN) {
20
+ client.send(JSON.stringify(message));
21
+ }
22
+ });
23
+ }
24
+
25
+ module.exports = { setupWebSocket, notifyClients };
@@ -0,0 +1,66 @@
1
+ const localtunnel = require('localtunnel');
2
+ const { nanoid } = require('nanoid');
3
+ const Logger = require('../utils/logger');
4
+
5
+ class ShareManager {
6
+ constructor() {
7
+ this.activeShares = new Map();
8
+ }
9
+
10
+ async createShare(port, duration) {
11
+ try {
12
+ const shareId = nanoid(8);
13
+
14
+ const tunnel = await localtunnel({ port });
15
+
16
+ const shareInfo = {
17
+ id: shareId,
18
+ url: tunnel.url,
19
+ startTime: Date.now(),
20
+ duration: duration * 60 * 1000,
21
+ tunnel
22
+ };
23
+
24
+ this.activeShares.set(shareId, shareInfo);
25
+
26
+ setTimeout(() => {
27
+ this.closeShare(shareId);
28
+ }, shareInfo.duration);
29
+
30
+ Logger.success(`🌍 Share created: ${tunnel.url}`);
31
+ Logger.info(`⏱️ Share will expire in ${duration} minutes`);
32
+
33
+ return shareInfo;
34
+ } catch (error) {
35
+ Logger.error(`Share creation failed: ${error.message}`);
36
+ throw error;
37
+ }
38
+ }
39
+
40
+ async closeShare(shareId) {
41
+ const share = this.activeShares.get(shareId);
42
+ if (share) {
43
+ await share.tunnel.close();
44
+ this.activeShares.delete(shareId);
45
+ Logger.info(`🔒 Share ${shareId} closed`);
46
+ }
47
+ }
48
+
49
+ getActiveShares() {
50
+ const shares = [];
51
+ for (const [id, share] of this.activeShares) {
52
+ const remainingTime = Math.max(0,
53
+ (share.startTime + share.duration - Date.now()) / 1000 / 60
54
+ );
55
+
56
+ shares.push({
57
+ id: share.id,
58
+ url: share.url,
59
+ remainingMinutes: Math.round(remainingTime)
60
+ });
61
+ }
62
+ return shares;
63
+ }
64
+ }
65
+
66
+ module.exports = new ShareManager();
@@ -0,0 +1,38 @@
1
+ const os = require('os');
2
+
3
+ class ServerMonitor {
4
+ constructor() {
5
+ this.stats = {
6
+ startTime: Date.now(),
7
+ requests: 0,
8
+ errors: 0,
9
+ bytesTransferred: 0
10
+ };
11
+ }
12
+
13
+ recordRequest() {
14
+ this.stats.requests++;
15
+ }
16
+
17
+ recordError() {
18
+ this.stats.errors++;
19
+ }
20
+
21
+ recordTransfer(bytes) {
22
+ this.stats.bytesTransferred += bytes;
23
+ }
24
+
25
+ getStats() {
26
+ const uptime = (Date.now() - this.stats.startTime) / 1000;
27
+ return {
28
+ uptime: uptime.toFixed(2) + 's',
29
+ requests: this.stats.requests,
30
+ errors: this.stats.errors,
31
+ bytesTransferred: (this.stats.bytesTransferred / 1024 / 1024).toFixed(2) + 'MB',
32
+ memory: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + 'MB',
33
+ cpu: os.loadavg()[0].toFixed(2) + '%'
34
+ };
35
+ }
36
+ }
37
+
38
+ module.exports = new ServerMonitor();