|
19 | 19 | package main |
20 | 20 |
|
21 | 21 | import ( |
| 22 | + _ "embed" |
22 | 23 | "encoding/json" |
23 | 24 | "flag" |
24 | 25 | "io/ioutil" |
|
81 | 82 | crashreport = iniConf.Bool("crashreport", false, "enable crashreport logging") |
82 | 83 | ) |
83 | 84 |
|
| 85 | +var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHTML)) |
| 86 | + |
| 87 | +// If you navigate to this server's homepage, you'll get this HTML |
| 88 | +// so you can directly interact with the serial port server |
| 89 | +// |
| 90 | +//go:embed home.html |
| 91 | +var homeTemplateHTML string |
| 92 | + |
84 | 93 | // global clients |
85 | 94 | var ( |
86 | 95 | Tools tools.Tools |
@@ -444,243 +453,6 @@ func loop() { |
444 | 453 | }() |
445 | 454 | } |
446 | 455 |
|
447 | | -var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHTML)) |
448 | | - |
449 | | -// If you navigate to this server's homepage, you'll get this HTML |
450 | | -// so you can directly interact with the serial port server |
451 | | -const homeTemplateHTML = `<!DOCTYPE html> |
452 | | -<html lang="en"> |
453 | | -<head> |
454 | | -<title>Arduino Create Agent Debug Console</title> |
455 | | -<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700&display=swap" rel="stylesheet"> |
456 | | -<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,600,700&display=swap" rel="stylesheet"> |
457 | | -<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> |
458 | | -<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script> |
459 | | -<script type="text/javascript"> |
460 | | - $(function() { |
461 | | - var socket; |
462 | | - var input = $('#input'); |
463 | | - var log = document.getElementById('log'); |
464 | | - var autoscroll = document.getElementById('autoscroll'); |
465 | | - var listenabled = document.getElementById('list'); |
466 | | - var messages = []; |
467 | | - var MESSAGES_MAX_COUNT = 2000; |
468 | | -
|
469 | | - function appendLog(msg) { |
470 | | - let jsonMsg = {}; |
471 | | - let portListing = false; |
472 | | - try { |
473 | | - jsonMsg = JSON.parse(msg); |
474 | | - portsListing = jsonMsg.Ports; |
475 | | - } catch { |
476 | | - // no valid json |
477 | | - } |
478 | | -
|
479 | | - var startsWithList = msg.indexOf('list') == 0; |
480 | | -
|
481 | | - if (listenabled.checked || (!portsListing && !startsWithList)) { |
482 | | - let printMsg = msg; |
483 | | - if (jsonMsg.Ports) { |
484 | | - const validKeys = ['Name', 'SerialNumber', 'IsOpen', 'VendorID', 'ProductID']; |
485 | | - if (jsonMsg.Network) { |
486 | | - printMsg = "<b>Network Ports</b>:<br>"+JSON.stringify(jsonMsg.Ports, validKeys, 2); |
487 | | - } else { |
488 | | - printMsg = "<b>Serial Ports</b>:<br>"+JSON.stringify(jsonMsg.Ports, validKeys, 2); |
489 | | - } |
490 | | - } else if (Object.keys(jsonMsg).length !== 0) { |
491 | | - printMsg = JSON.stringify(jsonMsg, undefined, 2); |
492 | | - } |
493 | | - messages.push(printMsg); |
494 | | - if (messages.length > MESSAGES_MAX_COUNT) { |
495 | | - messages.shift(); |
496 | | - } |
497 | | - log.innerHTML = messages.join('<br><br>'); |
498 | | - if (autoscroll.checked) { |
499 | | - log.scrollTop = log.scrollHeight - log.clientHeight; |
500 | | - } |
501 | | - } |
502 | | - } |
503 | | -
|
504 | | - $('#form').submit(function(e) { |
505 | | - e.preventDefault(); |
506 | | - if (!socket) { |
507 | | - return false; |
508 | | - } |
509 | | - if (!input.val()) { |
510 | | - return false; |
511 | | - } |
512 | | - socket.emit('command', input.val()); |
513 | | - }); |
514 | | -
|
515 | | - $('#export').click(function() { |
516 | | - var link = document.createElement('a'); |
517 | | - link.setAttribute('download', 'agent-log.txt'); |
518 | | - var text = log.innerHTML.replace(/<br>/g, '\n'); |
519 | | - text = text.replace(/<b>|<\/b>/g, ''); |
520 | | - link.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); |
521 | | - link.click(); |
522 | | - }); |
523 | | -
|
524 | | - $('#clear').click(function() { |
525 | | - messages = []; |
526 | | - log.innerHTML = ''; |
527 | | - }); |
528 | | -
|
529 | | - if (window['WebSocket']) { |
530 | | - if (window.location.protocol === 'https:') { |
531 | | - socket = io('https://{{$}}') |
532 | | - } else { |
533 | | - socket = io('http://{{$}}'); |
534 | | - } |
535 | | - socket.on('disconnect', function(evt) { |
536 | | - appendLog($('<div><b>Connection closed.</b></div>')) |
537 | | - }); |
538 | | - socket.on('message', function(evt) { |
539 | | - appendLog(evt); |
540 | | - }); |
541 | | - } else { |
542 | | - appendLog($('<div><b>Your browser does not support WebSockets.</b></div>')) |
543 | | - } |
544 | | - |
545 | | - $("#input").focus(); |
546 | | - }); |
547 | | -</script> |
548 | | -<style type="text/css"> |
549 | | -html, body { |
550 | | - overflow: hidden; |
551 | | - height: 100%; |
552 | | -} |
553 | | -
|
554 | | -body { |
555 | | - margin: 0px; |
556 | | - padding: 0px; |
557 | | - background: #F8F9F9; |
558 | | - font-size: 16px; |
559 | | - font-family: "Open Sans", "Lucida Grande", Lucida, Verdana, sans-serif; |
560 | | -} |
561 | | -
|
562 | | -#container { |
563 | | - display: flex; |
564 | | - flex-direction: column; |
565 | | - height: 100vh; |
566 | | - width: 100%; |
567 | | -} |
568 | | -
|
569 | | -#log { |
570 | | - flex-grow: 1; |
571 | | - font-family: "Roboto Mono", "Courier", "Lucida Grande", Verdana, sans-serif; |
572 | | - background-color: #DAE3E3; |
573 | | - height: calc(100vh - 61px); |
574 | | - margin: 15px 15px 10px; |
575 | | - padding: 8px 10px; |
576 | | - overflow-y: auto; |
577 | | -} |
578 | | -
|
579 | | -#footer { |
580 | | - display: flex; |
581 | | - flex-wrap: wrap; |
582 | | - align-items: flex-start; |
583 | | - justify-content: space-between; |
584 | | - margin: 0px 15px 0px; |
585 | | -} |
586 | | -
|
587 | | -#form { |
588 | | - display: flex; |
589 | | - flex-grow: 1; |
590 | | - margin-bottom: 15px; |
591 | | -} |
592 | | -
|
593 | | -#input { |
594 | | - flex-grow: 1; |
595 | | -} |
596 | | -
|
597 | | -#secondary-controls div { |
598 | | - display: inline-block; |
599 | | - padding: 10px 15px; |
600 | | -} |
601 | | -
|
602 | | -#autoscroll, |
603 | | -#list { |
604 | | - vertical-align: middle; |
605 | | - width: 20px; |
606 | | - height: 20px; |
607 | | -} |
608 | | -
|
609 | | -
|
610 | | -#secondary-controls button { |
611 | | - margin-bottom: 15px; |
612 | | - vertical-align: top; |
613 | | -} |
614 | | -
|
615 | | -.button { |
616 | | - background-color: #b5c8c9; |
617 | | - border: 1px solid #b5c8c9; |
618 | | - border-radius: 2px 2px 0 0; |
619 | | - box-shadow: 0 4px #95a5a6; |
620 | | - margin-bottom: 4px; |
621 | | - color: #000; |
622 | | - cursor: pointer; |
623 | | - font-size: 14px; |
624 | | - letter-spacing: 1.28px; |
625 | | - line-height: normal; |
626 | | - outline: none; |
627 | | - padding: 9px 18px; |
628 | | - text-align: center; |
629 | | - text-transform: uppercase; |
630 | | - transition: box-shadow .1s ease-out, transform .1s ease-out; |
631 | | -} |
632 | | -
|
633 | | -.button:hover { |
634 | | - box-shadow: 0 2px #95a5a6; |
635 | | - outline: none; |
636 | | - transform: translateY(2px); |
637 | | -} |
638 | | -
|
639 | | -.button:active { |
640 | | - box-shadow: none; |
641 | | - transform: translateY(4px); |
642 | | -} |
643 | | -
|
644 | | -.textfield { |
645 | | - background-color: #dae3e3; |
646 | | - width: auto; |
647 | | - height: auto; |
648 | | - padding: 10px 8px; |
649 | | - margin-left: 8px; |
650 | | - vertical-align: top; |
651 | | - border: none; |
652 | | - font-family: "Open Sans", "Lucida Grande", Lucida, Verdana, sans-serif; |
653 | | - font-size: 1em; |
654 | | - outline: none; |
655 | | -} |
656 | | -</style> |
657 | | -</head> |
658 | | - <body> |
659 | | - <div id="container"> |
660 | | - <pre id="log"></pre> |
661 | | - <div id="footer"> |
662 | | - <form id="form"> |
663 | | - <input type="submit" class="button" value="Send" /> |
664 | | - <input type="text" id="input" class="textfield" aria-label="send command" /> |
665 | | - </form> |
666 | | - <div id="secondary-controls"> |
667 | | - <div> |
668 | | - <input name="pause" type="checkbox" checked id="autoscroll" /> |
669 | | - <label for="autoscroll">Autoscroll</label> |
670 | | - </div> |
671 | | - <div> |
672 | | - <input name="list" type="checkbox" checked id="list" /> |
673 | | - <label for="list">Enable List Command</label> |
674 | | - </div> |
675 | | - <button id="clear" class="button">Clear Log</button> |
676 | | - <button id="export" class="button">Export Log</button> |
677 | | - </div> |
678 | | - </div> |
679 | | - </div> |
680 | | - </body> |
681 | | -</html> |
682 | | -` |
683 | | - |
684 | 456 | func parseIni(filename string) (args []string, err error) { |
685 | 457 | cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: false, AllowPythonMultilineValues: true}, filename) |
686 | 458 | if err != nil { |
|
0 commit comments