|
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