cli.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package client
  2. import (
  3. "errors"
  4. "flag"
  5. "fmt"
  6. "os"
  7. "strconv"
  8. "strings"
  9. )
  10. var (
  11. PORT_OUT_OF_RANGE error = errors.New("Port number must be between 1 and 65535")
  12. )
  13. type Options struct {
  14. server string
  15. auth string
  16. hostname string
  17. localaddr string
  18. protocol string
  19. url string
  20. subdomain string
  21. historySize int
  22. }
  23. func fail(msg string, args ...interface{}) {
  24. //log.Error(msg, args..)
  25. fmt.Printf(msg, args...)
  26. flag.PrintDefaults()
  27. os.Exit(1)
  28. }
  29. func parsePort(portString string) (err error) {
  30. var port int
  31. if port, err = strconv.Atoi(portString); err != nil {
  32. return err
  33. }
  34. if port < 1 || port > 65535 {
  35. return PORT_OUT_OF_RANGE
  36. }
  37. return
  38. }
  39. // Local address could be a port of a host:port string
  40. // we always return a host:port string from this function or fail
  41. func parseLocalAddr() string {
  42. if flag.NArg() == 0 {
  43. fail("LOCAL not specified, specify a port number or host:port connection string")
  44. }
  45. if flag.NArg() > 1 {
  46. fail("Only one LOCAL may be specified, not %d", flag.NArg())
  47. }
  48. addr := flag.Arg(0)
  49. // try to parse as a port number
  50. if err := parsePort(addr); err == nil {
  51. return fmt.Sprintf("127.0.0.1:%s", addr)
  52. } else if err == PORT_OUT_OF_RANGE {
  53. fail("%s is not in the valid port range 1-65535")
  54. }
  55. // try to parse as a connection string
  56. parts := strings.Split(addr, ":")
  57. if len(parts) != 2 {
  58. fail("%s is not a port number of a host:port connection string", addr)
  59. }
  60. if parsePort(parts[1]) != nil {
  61. fail("The port of the connection string '%s' is not a valid port number (1-65535)",
  62. parts[1])
  63. }
  64. return addr
  65. }
  66. func parseProtocol(proto string) string {
  67. switch proto {
  68. case "http":
  69. fallthrough
  70. case "tcp":
  71. return proto
  72. default:
  73. fail("%s is not a valid protocol", proto)
  74. }
  75. panic("unreachable")
  76. }
  77. func parseArgs() *Options {
  78. server := flag.String(
  79. "server",
  80. "ngrok.com:2280",
  81. "The remote ngrok server")
  82. auth := flag.String(
  83. "auth",
  84. "",
  85. "username:password HTTP basic auth creds protecting the public tunnel endpoint")
  86. hostname := flag.String(
  87. "hostname",
  88. "",
  89. "A full DNS hostname to identify public tunnel endpoint. (Advanced, requires you CNAME your DNS)")
  90. subdomain := flag.String(
  91. "subdomain",
  92. "",
  93. "Request a custom subdomain from the ngrok server. (HTTP mode only)")
  94. protocol := flag.String(
  95. "proto",
  96. "http",
  97. "The protocol of the traffic over the tunnel {'http', 'tcp'} (default: 'http')")
  98. historySize := flag.Int(
  99. "history",
  100. 20,
  101. "The number of previous requests to keep in your history")
  102. flag.Parse()
  103. return &Options{
  104. server: *server,
  105. auth: *auth,
  106. hostname: *hostname,
  107. subdomain: *subdomain,
  108. localaddr: parseLocalAddr(),
  109. protocol: parseProtocol(*protocol),
  110. historySize: *historySize,
  111. }
  112. }