orztv commited on
Commit
37635f4
·
1 Parent(s): 615586d
Files changed (1) hide show
  1. src/sshx.tsx +47 -11
src/sshx.tsx CHANGED
@@ -41,7 +41,7 @@ export const action: ActionFunction = async ({ request }) => {
41
  const action = formData.get('action');
42
 
43
  if (action === 'start' && !sshxProcess) {
44
- sshxProcess = spawn('/home/pn/sshx/sshx', []);
45
  sshxProcess.stdout?.on('data', handleProcessOutput);
46
  sshxProcess.stderr?.on('data', handleProcessOutput);
47
  sshxProcess.on('close', handleProcessClose);
@@ -60,20 +60,45 @@ export default function Sshx() {
60
  const submit = useSubmit();
61
  const navigation = useNavigation();
62
  const [localOutput, setLocalOutput] = useState(output);
 
63
 
64
  const refreshData = useCallback(() => {
65
  submit(null, { method: 'get', replace: true });
66
  }, [submit]);
67
 
 
 
 
 
 
68
  useEffect(() => {
69
  let interval: NodeJS.Timeout | null = null;
 
 
70
  if (status === 'running') {
71
  interval = setInterval(refreshData, 60000); // 每60秒更新一次
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  }
 
73
  return () => {
74
  if (interval) clearInterval(interval);
 
75
  };
76
- }, [refreshData, status]);
77
 
78
  useEffect(() => {
79
  setLocalOutput(output);
@@ -82,16 +107,24 @@ export default function Sshx() {
82
  const isLoading = navigation.state === 'submitting' || navigation.state === 'loading';
83
 
84
  const handleAction = (action: 'start' | 'stop') => {
 
 
 
 
 
85
  submit({ action }, { method: 'post' });
86
  setTimeout(refreshData, 100);
87
  };
88
 
 
 
 
89
  return (
90
  <div className="container mx-auto px-4 py-8 max-w-3xl">
91
  <h1 className="text-3xl font-bold text-primary mb-6 pb-2 border-b-2 border-primary">SSHX控制面板</h1>
92
  <div className="mb-6">
93
  <p className="text-lg font-semibold">
94
- 状态: <span className={`${status === 'running' ? 'text-green-600' : 'text-red-600'}`}>
95
  {status === 'running' ? '运行中' : '已停止'}
96
  </span>
97
  </p>
@@ -121,26 +154,29 @@ export default function Sshx() {
121
  </button>
122
  </div>
123
  {status === 'running' && (
124
- <div className="bg-blue-50 border border-blue-200 rounded-md p-4 mb-6">
125
- <p className="mb-2">
126
  <strong className="font-semibold">链接:</strong>{' '}
127
  {link ? (
128
- <a href={link} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">
129
  {link}
130
  </a>
131
  ) : (
132
- '暂不可用'
133
  )}
134
  </p>
135
- <p>
136
- <strong className="font-semibold">Shell:</strong> {shell || '暂不可用'}
 
 
 
137
  </p>
138
  </div>
139
  )}
140
  <h2 className="text-2xl font-semibold text-secondary mb-4">输出:</h2>
141
- <pre className="bg-gray-100 p-4 rounded-md border border-gray-300 font-mono text-sm whitespace-pre-wrap overflow-x-auto max-h-96 overflow-y-auto">
142
  {localOutput}
143
  </pre>
144
  </div>
145
  );
146
- }
 
41
  const action = formData.get('action');
42
 
43
  if (action === 'start' && !sshxProcess) {
44
+ sshxProcess = spawn('/home/pn/sshx/sshx', ['-q']); // 修改这里,添加 '-q' 参数
45
  sshxProcess.stdout?.on('data', handleProcessOutput);
46
  sshxProcess.stderr?.on('data', handleProcessOutput);
47
  sshxProcess.on('close', handleProcessClose);
 
60
  const submit = useSubmit();
61
  const navigation = useNavigation();
62
  const [localOutput, setLocalOutput] = useState(output);
63
+ const [startTime, setStartTime] = useState<number | null>(null);
64
 
65
  const refreshData = useCallback(() => {
66
  submit(null, { method: 'get', replace: true });
67
  }, [submit]);
68
 
69
+ const stopSshx = useCallback(() => {
70
+ submit({ action: 'stop' }, { method: 'post' });
71
+ setStartTime(null);
72
+ }, [submit]);
73
+
74
  useEffect(() => {
75
  let interval: NodeJS.Timeout | null = null;
76
+ let timer: NodeJS.Timeout | null = null;
77
+
78
  if (status === 'running') {
79
  interval = setInterval(refreshData, 60000); // 每60秒更新一次
80
+
81
+ if (startTime === null) {
82
+ setStartTime(Date.now());
83
+ } else {
84
+ const elapsedTime = Date.now() - startTime;
85
+ const remainingTime = 600000 - elapsedTime; // 10分钟 = 600000毫秒
86
+
87
+ if (remainingTime > 0) {
88
+ timer = setTimeout(stopSshx, remainingTime);
89
+ } else {
90
+ stopSshx();
91
+ }
92
+ }
93
+ } else {
94
+ setStartTime(null);
95
  }
96
+
97
  return () => {
98
  if (interval) clearInterval(interval);
99
+ if (timer) clearTimeout(timer);
100
  };
101
+ }, [refreshData, status, startTime, stopSshx]);
102
 
103
  useEffect(() => {
104
  setLocalOutput(output);
 
107
  const isLoading = navigation.state === 'submitting' || navigation.state === 'loading';
108
 
109
  const handleAction = (action: 'start' | 'stop') => {
110
+ if (action === 'start') {
111
+ setStartTime(Date.now());
112
+ } else {
113
+ setStartTime(null);
114
+ }
115
  submit({ action }, { method: 'post' });
116
  setTimeout(refreshData, 100);
117
  };
118
 
119
+ // 计算剩余时间
120
+ const remainingTime = startTime ? Math.max(0, 600 - Math.floor((Date.now() - startTime) / 1000)) : 0;
121
+
122
  return (
123
  <div className="container mx-auto px-4 py-8 max-w-3xl">
124
  <h1 className="text-3xl font-bold text-primary mb-6 pb-2 border-b-2 border-primary">SSHX控制面板</h1>
125
  <div className="mb-6">
126
  <p className="text-lg font-semibold">
127
+ 状态: <span className={`${status === 'running' ? 'text-green-600' : 'text-red-600'} font-bold`}>
128
  {status === 'running' ? '运行中' : '已停止'}
129
  </span>
130
  </p>
 
154
  </button>
155
  </div>
156
  {status === 'running' && (
157
+ <div className="bg-blue-100 border border-blue-300 rounded-md p-4 mb-6">
158
+ <p className="mb-2 text-blue-800">
159
  <strong className="font-semibold">链接:</strong>{' '}
160
  {link ? (
161
+ <a href={link} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline font-medium">
162
  {link}
163
  </a>
164
  ) : (
165
+ <span className="text-gray-600">暂不可用</span>
166
  )}
167
  </p>
168
+ <p className="text-blue-800">
169
+ <strong className="font-semibold">Shell:</strong> <span className="font-medium">{shell || '暂不可用'}</span>
170
+ </p>
171
+ <p className="text-blue-800">
172
+ <strong className="font-semibold">剩余时间:</strong> <span className="font-medium">{remainingTime} 秒</span>
173
  </p>
174
  </div>
175
  )}
176
  <h2 className="text-2xl font-semibold text-secondary mb-4">输出:</h2>
177
+ <pre className="bg-gray-800 text-blue-600 p-4 rounded-md border border-gray-600 font-mono text-sm whitespace-pre-wrap overflow-x-auto max-h-96 overflow-y-auto">
178
  {localOutput}
179
  </pre>
180
  </div>
181
  );
182
+ }