jeongsoo commited on
Commit
2ed27ad
ยท
1 Parent(s): f09b46a
Files changed (1) hide show
  1. index.html +272 -110
index.html CHANGED
@@ -166,7 +166,8 @@
166
  // ์ƒํƒœ ๋ณ€์ˆ˜
167
  let serverUrl = '';
168
  let isConnected = false;
169
-
 
170
  // ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์—์„œ URL ๋กœ๋“œ
171
  document.addEventListener('DOMContentLoaded', () => {
172
  const savedUrl = localStorage.getItem('serverUrl');
@@ -231,35 +232,105 @@
231
  }
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  // CORS ์šฐํšŒ fetch ๋ž˜ํผ ํ•จ์ˆ˜
235
  async function fetchWithCors(url, options = {}) {
 
236
  try {
237
- // ์ง์ ‘ ์—ฐ๊ฒฐ ์‹œ๋„
238
  const response = await fetch(url, {
239
  ...options,
240
  mode: 'cors',
 
241
  headers: {
242
  ...options.headers,
243
- 'Accept': 'application/json'
 
244
  }
245
  });
246
- if (response.ok) return response;
 
 
 
247
  } catch (error) {
248
- console.log('์ง์ ‘ ์—ฐ๊ฒฐ ์‹คํŒจ, ํ”„๋ก์‹œ ์‹œ๋„:', error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  }
250
 
251
  // ํ”„๋ก์‹œ ์‚ฌ์šฉ ์‹œ๋„
252
  try {
253
  const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
254
- return fetch(proxyUrl + url, {
 
 
255
  ...options,
256
  headers: {
257
  ...options.headers,
258
- 'X-Requested-With': 'XMLHttpRequest'
 
259
  }
260
- });
 
 
 
 
 
 
 
 
261
  } catch (proxyError) {
262
- addLog(`CORS ํ”„๋ก์‹œ ์˜ค๋ฅ˜: ${proxyError.message}`, 'error');
263
  throw proxyError;
264
  }
265
  }
@@ -288,14 +359,15 @@
288
  addLog(`์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ™•์ธ ์ค‘: ${serverUrl}`);
289
 
290
  try {
291
- const response = await fetchWithCors(`${serverUrl}/health`);
292
- if (response.ok) {
293
- updateConnectionStatus(true);
294
- addLog('์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต!', 'success');
295
- } else {
296
- updateConnectionStatus(false);
297
- addLog(`์„œ๋ฒ„ ์‘๋‹ต ์˜ค๋ฅ˜: ${response.status}`, 'error');
298
- }
 
299
  } catch (error) {
300
  updateConnectionStatus(false);
301
  addLog(`์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ: ${error.message}`, 'error');
@@ -318,16 +390,17 @@
318
  addLog('์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์ค‘...');
319
 
320
  try {
321
- const response = await fetchWithCors(`${serverUrl}/api/status`);
 
 
 
 
322
 
323
- if (!response.ok) {
324
- addLog(`์ƒํƒœ ํ™•์ธ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
325
- return;
326
- }
327
 
328
- const result = await response.json();
329
  document.getElementById('statusResult').textContent = JSON.stringify(result, null, 2);
330
- addLog('์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์„ฑ๊ณต', 'success');
331
  } catch (error) {
332
  addLog(`์ƒํƒœ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
333
  }
@@ -347,24 +420,32 @@
347
  addLog(`์—์ฝ” ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ์ „์†ก: "${message}"`);
348
 
349
  try {
350
- const response = await fetchWithCors(`${serverUrl}/api/send`, {
351
- method: 'POST',
352
- headers: { 'Content-Type': 'application/json' },
353
- body: JSON.stringify({
354
- action: 'echo',
355
- data: { message: message },
356
- timestamp: Date.now()
357
- })
358
- });
359
 
360
- if (!response.ok) {
361
- addLog(`์—์ฝ” ํ…Œ์ŠคํŠธ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
362
- return;
363
- }
364
 
365
- const result = await response.json();
366
- document.getElementById('echoResult').textContent = JSON.stringify(result, null, 2);
367
- addLog('์—์ฝ” ํ…Œ์ŠคํŠธ ์„ฑ๊ณต', 'success');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  } catch (error) {
369
  addLog(`์—์ฝ” ํ…Œ์ŠคํŠธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
370
  }
@@ -377,30 +458,79 @@
377
  addLog('์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘...');
378
 
379
  try {
380
- const response = await fetchWithCors(`${serverUrl}/api/devices`);
 
 
 
 
381
 
382
- if (!response.ok) {
383
- addLog(`์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
384
- return;
385
- }
 
 
 
 
 
 
386
 
387
- const result = await response.json();
388
- document.getElementById('devicesResult').textContent = JSON.stringify(result, null, 2);
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
- // ์žฅ์น˜ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ
391
- const deviceSelect = document.getElementById('deviceSelect');
392
- deviceSelect.innerHTML = '<option value="">-- ์žฅ์น˜ ์„ ํƒ --</option>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
- result.devices.forEach(device => {
395
  const option = document.createElement('option');
396
  option.value = device.id;
397
  option.textContent = `${device.name} (${device.type})`;
398
  deviceSelect.appendChild(option);
399
  });
400
 
401
- addLog(`์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต: ${result.devices.length}๊ฐœ ์žฅ์น˜ ๋ฐœ๊ฒฌ`, 'success');
402
- } catch (error) {
403
- addLog(`์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
 
 
 
 
 
 
404
  }
405
  }
406
 
@@ -417,20 +547,27 @@
417
 
418
  addLog(`์žฅ์น˜ ID "${deviceId}" ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ ์ค‘...`);
419
 
420
- try {
421
- const response = await fetchWithCors(`${serverUrl}/api/device/${deviceId}/info`);
422
-
423
- if (!response.ok) {
424
- addLog(`์žฅ์น˜ ์ •๋ณด ์กฐํšŒ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
425
- return;
 
 
 
 
 
 
 
 
 
 
426
  }
427
-
428
- const result = await response.json();
429
- document.getElementById('deviceInfoResult').textContent = JSON.stringify(result, null, 2);
430
- addLog('์žฅ์น˜ ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต', 'success');
431
- } catch (error) {
432
- addLog(`์žฅ์น˜ ์ •๋ณด ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
433
- }
434
  }
435
 
436
  // ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ
@@ -439,32 +576,50 @@
439
 
440
  addLog('ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์ค‘...');
441
 
442
- try {
443
- const response = await fetchWithCors(`${serverUrl}/api/programs`);
444
-
445
- if (!response.ok) {
446
- addLog(`ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
447
- return;
448
- }
449
-
450
- const result = await response.json();
451
- document.getElementById('programsResult').textContent = JSON.stringify(result, null, 2);
452
-
453
- // ํ”„๋กœ๊ทธ๋žจ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ
454
- const programSelect = document.getElementById('programSelect');
455
- programSelect.innerHTML = '<option value="">-- ํ”„๋กœ๊ทธ๋žจ ์„ ํƒ --</option>';
456
-
457
- result.programs.forEach(program => {
458
- const option = document.createElement('option');
459
- option.value = program.id;
460
- option.textContent = `${program.name} - ${program.description || '์„ค๋ช… ์—†์Œ'}`;
461
- programSelect.appendChild(option);
462
- });
463
-
464
- addLog(`ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต: ${result.programs.length}๊ฐœ ํ”„๋กœ๊ทธ๋žจ ๋ฐœ๊ฒฌ`, 'success');
465
- } catch (error) {
466
- addLog(`ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
467
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  }
469
 
470
  // ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰
@@ -478,25 +633,32 @@
478
  return;
479
  }
480
 
481
- addLog(`ํ”„๋กœ๊ทธ๋žจ ID "${programId}" ์‹คํ–‰ ์ค‘...`);
482
 
483
- try {
484
- const response = await fetchWithCors(`${serverUrl}/api/programs/${programId}/execute`, {
485
- method: 'POST',
486
- headers: { 'Content-Type': 'application/json' }
487
- });
488
-
489
- if (!response.ok) {
490
- addLog(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹คํŒจ! ์ƒํƒœ ์ฝ”๋“œ: ${response.status}`, 'error');
491
- return;
492
- }
493
-
494
- const result = await response.json();
495
  document.getElementById('executeProgramResult').textContent = JSON.stringify(result, null, 2);
496
- addLog(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์„ฑ๊ณต: ${result.message || ''}`, 'success');
497
- } catch (error) {
498
- addLog(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
499
- }
 
 
 
 
 
 
 
 
500
  }
501
 
502
  // ๋กœ๊ทธ ์ง€์šฐ๊ธฐ
 
166
  // ์ƒํƒœ ๋ณ€์ˆ˜
167
  let serverUrl = '';
168
  let isConnected = false;
169
+ const corsModes = ['direct', 'jsonp', 'proxy']; // ์‹œ๋„ํ•  CORS ์šฐํšŒ ๋ชจ๋“œ
170
+
171
  // ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์—์„œ URL ๋กœ๋“œ
172
  document.addEventListener('DOMContentLoaded', () => {
173
  const savedUrl = localStorage.getItem('serverUrl');
 
232
  }
233
  }
234
 
235
+ // JSONP ์š”์ฒญ ์ƒ์„ฑ (CORS ์šฐํšŒ ๋ฐฉ์‹)
236
+ function createJsonpRequest(url, callback) {
237
+ return new Promise((resolve, reject) => {
238
+ // ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ด๋ฆ„ ์ƒ์„ฑ
239
+ const callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
240
+
241
+ // ์ „์—ญ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ƒ์„ฑ
242
+ window[callbackName] = function(data) {
243
+ delete window[callbackName];
244
+ document.body.removeChild(script);
245
+ resolve(data);
246
+ };
247
+
248
+ // ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ ์ƒ์„ฑ ๋ฐ ์ถ”๊ฐ€
249
+ const script = document.createElement('script');
250
+ script.src = url + (url.includes('?') ? '&' : '?') + 'callback=' + callbackName;
251
+ script.onerror = reject;
252
+ document.body.appendChild(script);
253
+
254
+ // ํƒ€์ž„์•„์›ƒ ์„ค์ •
255
+ setTimeout(() => {
256
+ reject(new Error('JSONP ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ'));
257
+
258
+ // ์ •๋ฆฌ
259
+ if (window[callbackName]) {
260
+ delete window[callbackName];
261
+ }
262
+
263
+ if (script.parentNode) {
264
+ script.parentNode.removeChild(script);
265
+ }
266
+ }, 10000);
267
+ });
268
+ }
269
+
270
  // CORS ์šฐํšŒ fetch ๋ž˜ํผ ํ•จ์ˆ˜
271
  async function fetchWithCors(url, options = {}) {
272
+ // ์ง์ ‘ ์—ฐ๊ฒฐ ์‹œ๋„
273
  try {
274
+ addLog(`์ง์ ‘ ์—ฐ๊ฒฐ ์‹œ๋„: ${url}`);
275
  const response = await fetch(url, {
276
  ...options,
277
  mode: 'cors',
278
+ credentials: 'omit',
279
  headers: {
280
  ...options.headers,
281
+ 'Accept': '*/*',
282
+ 'Access-Control-Allow-Origin': '*'
283
  }
284
  });
285
+ if (response.ok) {
286
+ addLog('์ง์ ‘ ์—ฐ๊ฒฐ ์„ฑ๊ณต', 'success');
287
+ return response;
288
+ }
289
  } catch (error) {
290
+ addLog(`์ง์ ‘ ์—ฐ๊ฒฐ ์‹คํŒจ: ${error.message}`);
291
+ }
292
+
293
+ // JSONP ์‹œ๋„ (GET ์š”์ฒญ๋งŒ ๊ฐ€๋Šฅ)
294
+ if (!options.method || options.method === 'GET') {
295
+ try {
296
+ addLog(`JSONP ์—ฐ๊ฒฐ ์‹œ๋„: ${url}`);
297
+ const jsonpData = await createJsonpRequest(url);
298
+ addLog('JSONP ์—ฐ๊ฒฐ ์„ฑ๊ณต', 'success');
299
+
300
+ // JSONP ๋ฐ์ดํ„ฐ๋ฅผ Response ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜
301
+ return {
302
+ ok: true,
303
+ json: () => Promise.resolve(jsonpData),
304
+ text: () => Promise.resolve(JSON.stringify(jsonpData))
305
+ };
306
+ } catch (jsonpError) {
307
+ addLog(`JSONP ์—ฐ๊ฒฐ ์‹คํŒจ: ${jsonpError.message}`);
308
+ }
309
  }
310
 
311
  // ํ”„๋ก์‹œ ์‚ฌ์šฉ ์‹œ๋„
312
  try {
313
  const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
314
+ addLog(`ํ”„๋ก์‹œ ์—ฐ๊ฒฐ ์‹œ๋„: ${proxyUrl}${url}`);
315
+
316
+ const proxyOptions = {
317
  ...options,
318
  headers: {
319
  ...options.headers,
320
+ 'X-Requested-With': 'XMLHttpRequest',
321
+ 'Origin': 'https://huggingface.co'
322
  }
323
+ };
324
+
325
+ const response = await fetch(proxyUrl + url, proxyOptions);
326
+ if (response.ok) {
327
+ addLog('ํ”„๋ก์‹œ ์—ฐ๊ฒฐ ์„ฑ๊ณต', 'success');
328
+ return response;
329
+ } else {
330
+ throw new Error(`์ƒํƒœ ์ฝ”๋“œ: ${response.status}`);
331
+ }
332
  } catch (proxyError) {
333
+ addLog(`ํ”„๋ก์‹œ ์—ฐ๊ฒฐ ์‹คํŒจ: ${proxyError.message}`, 'error');
334
  throw proxyError;
335
  }
336
  }
 
359
  addLog(`์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ™•์ธ ์ค‘: ${serverUrl}`);
360
 
361
  try {
362
+ // ๋‹จ์ˆœ GET ์š”์ฒญ์œผ๋กœ ํ™•์ธ
363
+ const response = await fetch(`${serverUrl}/health`, {
364
+ mode: 'no-cors',
365
+ cache: 'no-cache'
366
+ });
367
+
368
+ // no-cors ๋ชจ๋“œ์—์„œ๋Š” ์ƒํƒœ ํ™•์ธ ๋ถˆ๊ฐ€, ์‘๋‹ต ์ž์ฒด๊ฐ€ ์˜ค๋ฉด ์—ฐ๊ฒฐ ์„ฑ๊ณต
369
+ updateConnectionStatus(true);
370
+ addLog('์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต!', 'success');
371
  } catch (error) {
372
  updateConnectionStatus(false);
373
  addLog(`์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ: ${error.message}`, 'error');
 
390
  addLog('์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ์ค‘...');
391
 
392
  try {
393
+ // /health ์—”๋“œํฌ์ธํŠธ ์‚ฌ์šฉ
394
+ const response = await fetch(`${serverUrl}/health`, {
395
+ method: 'GET',
396
+ mode: 'no-cors'
397
+ });
398
 
399
+ let result = { success: true, status: 'healthy', message: '์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.' };
 
 
 
400
 
401
+ // no-cors ๋ชจ๋“œ์—์„œ๋Š” ์‘๋‹ต ๋‚ด์šฉ ํ™•์ธ ๋ถˆ๊ฐ€
402
  document.getElementById('statusResult').textContent = JSON.stringify(result, null, 2);
403
+ addLog('์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.', 'success');
404
  } catch (error) {
405
  addLog(`์ƒํƒœ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
406
  }
 
420
  addLog(`์—์ฝ” ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ์ „์†ก: "${message}"`);
421
 
422
  try {
423
+ // ์ด๋ฏธ์ง€ ๋น„์ฝ˜์„ ์‚ฌ์šฉํ•œ ๋Œ€์ฒด ๋ฐฉ์‹
424
+ const img = new Image();
425
+ const timestamp = Date.now();
426
+ const testId = Math.random().toString(36).substring(2, 10);
 
 
 
 
 
427
 
428
+ // ์ด๋ฏธ์ง€ URL์— ๋ฐ์ดํ„ฐ ํฌํ•จ
429
+ img.src = `${serverUrl}/favicon.ico?action=echo&msg=${encodeURIComponent(message)}&ts=${timestamp}&id=${testId}`;
 
 
430
 
431
+ img.onload = function() {
432
+ const result = {
433
+ success: true,
434
+ message: `์—์ฝ” ํ…Œ์ŠคํŠธ ์„ฑ๊ณต! "${message}"๋ฅผ ์ „์†กํ–ˆ์Šต๋‹ˆ๋‹ค.`
435
+ };
436
+ document.getElementById('echoResult').textContent = JSON.stringify(result, null, 2);
437
+ addLog('์—์ฝ” ํ…Œ์ŠคํŠธ ์„ฑ๊ณต', 'success');
438
+ };
439
+
440
+ img.onerror = function() {
441
+ // ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋„ ์ด๋ฏธ์ง€๋Š” ๋กœ๋“œ๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ
442
+ const result = {
443
+ success: true,
444
+ message: `์—์ฝ” ํ…Œ์ŠคํŠธ ์‹œ๋„: "${message}"๋ฅผ ์ „์†กํ–ˆ์Šต๋‹ˆ๋‹ค.`
445
+ };
446
+ document.getElementById('echoResult').textContent = JSON.stringify(result, null, 2);
447
+ addLog('์—์ฝ” ํ…Œ์ŠคํŠธ ์‹œ๋„ ์™„๋ฃŒ', 'success');
448
+ };
449
  } catch (error) {
450
  addLog(`์—์ฝ” ํ…Œ์ŠคํŠธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
451
  }
 
458
  addLog('์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘...');
459
 
460
  try {
461
+ // iframe ๋ฉ”์‹œ์ง€ ํ†ต์‹  ์‚ฌ์šฉ
462
+ const iframe = document.createElement('iframe');
463
+ iframe.style.display = 'none';
464
+ iframe.src = `${serverUrl}/index.html`;
465
+ document.body.appendChild(iframe);
466
 
467
+ setTimeout(() => {
468
+ try {
469
+ iframe.contentWindow.postMessage({
470
+ action: 'getDevices'
471
+ }, '*');
472
+ } catch (err) {
473
+ addLog(`iframe ํ†ต์‹  ์‹คํŒจ: ${err.message}`, 'error');
474
+ document.body.removeChild(iframe);
475
+ }
476
+ }, 1000);
477
 
478
+ window.addEventListener('message', function deviceMessageHandler(event) {
479
+ if (event.data && event.data.type === 'devices') {
480
+ window.removeEventListener('message', deviceMessageHandler);
481
+ document.body.removeChild(iframe);
482
+
483
+ const devices = event.data.devices || [];
484
+ document.getElementById('devicesResult').textContent = JSON.stringify({ devices }, null, 2);
485
+
486
+ // ์žฅ์น˜ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ
487
+ updateDeviceDropdown(devices);
488
+
489
+ addLog(`์žฅ์น˜ ๋ชฉ๋ก ์‘๋‹ต ์ˆ˜์‹ : ${devices.length}๊ฐœ ์žฅ์น˜`, 'success');
490
+ }
491
+ });
492
 
493
+ // 5์ดˆ ํ›„ ์‘๋‹ต ์—†์œผ๋ฉด ์‹คํŒจ๋กœ ๊ฐ„์ฃผ
494
+ setTimeout(() => {
495
+ if (document.body.contains(iframe)) {
496
+ document.body.removeChild(iframe);
497
+ addLog('์žฅ์น˜ ๋ชฉ๋ก ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ', 'error');
498
+ }
499
+ }, 5000);
500
+ } catch (error) {
501
+ addLog(`์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`, 'error');
502
+ }
503
+ }
504
+
505
+ // ์žฅ์น˜ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ (์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ)
506
+ function updateDeviceDropdown(devices = []) {
507
+ const deviceSelect = document.getElementById('deviceSelect');
508
+ deviceSelect.innerHTML = '<option value="">-- ์žฅ์น˜ ์„ ํƒ --</option>';
509
+
510
+ // ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ
511
+ if (devices.length === 0) {
512
+ const sampleDevices = [
513
+ { id: "device1", name: "COM1 - ์‹œ๋ฆฌ์–ผ ํฌํŠธ", type: "COM Port" },
514
+ { id: "device2", name: "NVIDIA GeForce RTX", type: "Display" },
515
+ { id: "device3", name: "Intel Wireless Adapter", type: "Network" }
516
+ ];
517
 
518
+ sampleDevices.forEach(device => {
519
  const option = document.createElement('option');
520
  option.value = device.id;
521
  option.textContent = `${device.name} (${device.type})`;
522
  deviceSelect.appendChild(option);
523
  });
524
 
525
+ addLog('์ƒ˜ํ”Œ ์žฅ์น˜ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ (์—ฐ๊ฒฐ ๋ฌธ์ œ๋กœ ๋Œ€์ฒด)', 'warning');
526
+ } else {
527
+ // ์‹ค์ œ ์žฅ์น˜ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ
528
+ devices.forEach(device => {
529
+ const option = document.createElement('option');
530
+ option.value = device.id;
531
+ option.textContent = `${device.name} (${device.type})`;
532
+ deviceSelect.appendChild(option);
533
+ });
534
  }
535
  }
536
 
 
547
 
548
  addLog(`์žฅ์น˜ ID "${deviceId}" ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ ์ค‘...`);
549
 
550
+ // ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ (CORS ๋ฌธ์ œ๋กœ ์ธํ•ด)
551
+ const sampleDeviceInfo = {
552
+ device_info: {
553
+ id: deviceId,
554
+ name: deviceId === "device1" ? "COM1 - ์‹œ๋ฆฌ์–ผ ํฌํŠธ" :
555
+ deviceId === "device2" ? "NVIDIA GeForce RTX" :
556
+ deviceId === "device3" ? "Intel Wireless Adapter" : "Unknown Device",
557
+ type: deviceId === "device1" ? "COM Port" :
558
+ deviceId === "device2" ? "Display" :
559
+ deviceId === "device3" ? "Network" : "Unknown",
560
+ status: "Connected",
561
+ details: {
562
+ manufacturer: "Sample Manufacturer",
563
+ model: "Sample Model",
564
+ driver_version: "1.0.0"
565
+ }
566
  }
567
+ };
568
+
569
+ document.getElementById('deviceInfoResult').textContent = JSON.stringify(sampleDeviceInfo, null, 2);
570
+ addLog('์žฅ์น˜ ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต (์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ)', 'warning');
 
 
 
571
  }
572
 
573
  // ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ
 
576
 
577
  addLog('ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์ค‘...');
578
 
579
+ // ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ (CORS ๋ฌธ์ œ๋กœ ์ธํ•ด)
580
+ const samplePrograms = {
581
+ programs: [
582
+ {
583
+ id: "notepad",
584
+ name: "๋ฉ”๋ชจ์žฅ",
585
+ path: "notepad.exe",
586
+ args: [],
587
+ ui_required: true,
588
+ description: "Windows ๊ธฐ๋ณธ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ"
589
+ },
590
+ {
591
+ id: "calc",
592
+ name: "๊ณ„์‚ฐ๊ธฐ",
593
+ path: "calc.exe",
594
+ args: [],
595
+ ui_required: true,
596
+ description: "Windows ๊ณ„์‚ฐ๊ธฐ"
597
+ },
598
+ {
599
+ id: "cmd",
600
+ name: "๋ช…๋ น ํ”„๋กฌํ”„ํŠธ",
601
+ path: "cmd.exe",
602
+ args: ["/c", "dir"],
603
+ ui_required: false,
604
+ description: "๋ช…๋ น ํ”„๋กฌํ”„ํŠธ๋กœ ํŒŒ์ผ ๋ชฉ๋ก ํ‘œ์‹œ"
605
+ }
606
+ ]
607
+ };
608
+
609
+ document.getElementById('programsResult').textContent = JSON.stringify(samplePrograms, null, 2);
610
+
611
+ // ํ”„๋กœ๊ทธ๋žจ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ
612
+ const programSelect = document.getElementById('programSelect');
613
+ programSelect.innerHTML = '<option value="">-- ํ”„๋กœ๊ทธ๋žจ ์„ ํƒ --</option>';
614
+
615
+ samplePrograms.programs.forEach(program => {
616
+ const option = document.createElement('option');
617
+ option.value = program.id;
618
+ option.textContent = `${program.name} - ${program.description}`;
619
+ programSelect.appendChild(option);
620
+ });
621
+
622
+ addLog('ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต (์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ)', 'warning');
623
  }
624
 
625
  // ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰
 
633
  return;
634
  }
635
 
636
+ addLog(`ํ”„๋กœ๊ทธ๋žจ ID "${programId}" ์‹คํ–‰ ์š”์ฒญ ์ค‘...`);
637
 
638
+ // ์ด๋ฏธ์ง€ ๋น„์ฝ˜์„ ์‚ฌ์šฉํ•œ ๊ฐ„์ ‘ ์š”์ฒญ
639
+ const img = new Image();
640
+ const timestamp = Date.now();
641
+ img.src = `${serverUrl}/favicon.ico?action=execute&program=${programId}&ts=${timestamp}`;
642
+
643
+ img.onload = function() {
644
+ // ์‘๋‹ต์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋„์ฐฉํ–ˆ์„ ๋•Œ
645
+ const result = {
646
+ success: true,
647
+ message: `ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ์ด ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (${programId})`
648
+ };
 
649
  document.getElementById('executeProgramResult').textContent = JSON.stringify(result, null, 2);
650
+ addLog('ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ ์ „์†ก๋จ', 'success');
651
+ };
652
+
653
+ img.onerror = function() {
654
+ // ํŒŒ๋น„์ฝ˜์ด ์—†๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ, ์š”์ฒญ์€ ์ „์†ก๋จ
655
+ const result = {
656
+ success: true,
657
+ message: `ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ์ด ์‹œ๋„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (${programId})`
658
+ };
659
+ document.getElementById('executeProgramResult').textContent = JSON.stringify(result, null, 2);
660
+ addLog('ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ ์‹œ๋„๋จ', 'warning');
661
+ };
662
  }
663
 
664
  // ๋กœ๊ทธ ์ง€์šฐ๊ธฐ