dudeldu.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * DudelDu
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. /*
  11. DudelDu main entry point for the standalone server.
  12. Features:
  13. - Supports various streaming clients: VLC, ServeStream, ... and most Icecast clients.
  14. - Supports sending of meta data (sending artist and title to the streaming client).
  15. - Playlists are simple json files and data files are normal media (e.g. .mp3) files on disk.
  16. - Supports basic authentication.
  17. */
  18. package main
  19. import (
  20. "flag"
  21. "fmt"
  22. "log"
  23. "os"
  24. "devt.de/krotik/dudeldu"
  25. "devt.de/krotik/dudeldu/playlist"
  26. )
  27. // Global variables
  28. // ================
  29. /*
  30. ConfigFile is the config file which will be used to configure DudelDu
  31. */
  32. var ConfigFile = "dudeldu.config.json"
  33. /*
  34. Known configuration options for DudelDu
  35. */
  36. const (
  37. ThreadPoolSize = "ThreadPoolSize"
  38. FrameQueueSize = "FrameQueueSize"
  39. ServerPort = "ServerPort"
  40. ServerHost = "ServerHost"
  41. PathPrefix = "PathPrefix"
  42. )
  43. /*
  44. DefaultConfig is the defaut configuration
  45. */
  46. var DefaultConfig = map[string]interface{}{
  47. ThreadPoolSize: 10,
  48. FrameQueueSize: 10000,
  49. ServerPort: "9091",
  50. ServerHost: "127.0.0.1",
  51. PathPrefix: "",
  52. }
  53. type consolelogger func(v ...interface{})
  54. /*
  55. Fatal/print logger methods. Using a custom type so we can test calls with unit
  56. tests.
  57. */
  58. var fatal = consolelogger(log.Fatal)
  59. var print = consolelogger(func(a ...interface{}) {
  60. fmt.Fprint(os.Stderr, a...)
  61. fmt.Fprint(os.Stderr, "\n")
  62. })
  63. var lookupEnv func(string) (string, bool) = os.LookupEnv
  64. /*
  65. DudelDu server instance (used by unit tests)
  66. */
  67. var dds *dudeldu.Server
  68. /*
  69. Main entry point for DudelDu.
  70. */
  71. func main() {
  72. var err error
  73. var plf dudeldu.PlaylistFactory
  74. print(fmt.Sprintf("DudelDu %v", dudeldu.ProductVersion))
  75. auth := flag.String("auth", "", "Authentication as <user>:<pass>")
  76. serverHost := flag.String("host", DefaultConfig[ServerHost].(string), "Server hostname to listen on")
  77. serverPort := flag.String("port", DefaultConfig[ServerPort].(string), "Server port to listen on")
  78. threadPoolSize := flag.Int("tps", DefaultConfig[ThreadPoolSize].(int), "Thread pool size")
  79. frameQueueSize := flag.Int("fqs", DefaultConfig[FrameQueueSize].(int), "Frame queue size")
  80. pathPrefix := flag.String("pp", DefaultConfig[PathPrefix].(string), "Prefix all paths with a string")
  81. enableDebug := flag.Bool("debug", false, "Enable extra debugging output")
  82. loopPlaylist := flag.Bool("loop", false, "Loop playlists")
  83. shufflePlaylist := flag.Bool("shuffle", false, "Shuffle playlists")
  84. showHelp := flag.Bool("?", false, "Show this help message")
  85. flag.Usage = func() {
  86. print(fmt.Sprintf("Usage of %s [options] <playlist>", os.Args[0]))
  87. flag.PrintDefaults()
  88. print()
  89. print(fmt.Sprint("Authentication can also be defined via the environment variable: DUDELDU_AUTH=\"<user>:<pass>\""))
  90. }
  91. flag.Parse()
  92. if len(flag.Args()) != 1 || *showHelp {
  93. flag.Usage()
  94. return
  95. }
  96. // Check for auth environment variable
  97. if envAuth, ok := lookupEnv("DUDELDU_AUTH"); ok && *auth == "" {
  98. *auth = envAuth
  99. }
  100. laddr := fmt.Sprintf("%v:%v", *serverHost, *serverPort)
  101. print(fmt.Sprintf("Serving playlist %v on %v", flag.Arg(0), laddr))
  102. print(fmt.Sprintf("Thread pool size: %v", *threadPoolSize))
  103. print(fmt.Sprintf("Frame queue size: %v", *frameQueueSize))
  104. print(fmt.Sprintf("Loop playlist: %v", *loopPlaylist))
  105. print(fmt.Sprintf("Shuffle playlist: %v", *shufflePlaylist))
  106. print(fmt.Sprintf("Path prefix: %v", *pathPrefix))
  107. if *auth != "" {
  108. print(fmt.Sprintf("Required authentication: %v", *auth))
  109. }
  110. // Create server and listen
  111. plf, err = playlist.NewFilePlaylistFactory(flag.Arg(0), *pathPrefix)
  112. if err == nil {
  113. rh := dudeldu.NewDefaultRequestHandler(plf, *loopPlaylist, *shufflePlaylist, *auth)
  114. dds = dudeldu.NewServer(rh.HandleRequest)
  115. dds.DebugOutput = *enableDebug
  116. rh.SetDebugLogger(dds)
  117. defer print("Shutting down")
  118. err = dds.Run(laddr, nil)
  119. }
  120. if err != nil {
  121. fatal(err)
  122. }
  123. }