main.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/signal"
  8. "time"
  9. "git.lattuga.net/boyska/direttoforo/liquidsoap"
  10. "git.lattuga.net/boyska/direttoforo/uiserver"
  11. )
  12. type State struct {
  13. Streams map[string]liquidsoap.Stream
  14. }
  15. func NewState() State {
  16. s := State{}
  17. s.Streams = make(map[string]liquidsoap.Stream)
  18. return s
  19. }
  20. func main() {
  21. liqfile := flag.String("liq", "foo.liq", "Path to liquidsoap script to run")
  22. bindpath := flag.String("bindpath", "/var/lib/direttoforo/ui.sock", "UNIX domain socket path for UIs")
  23. flag.Parse()
  24. state := NewState()
  25. netUIsock, err := net.Listen("unix", *bindpath)
  26. if err != nil {
  27. fmt.Fprintln(os.Stderr, "error binding UI socket!")
  28. fmt.Fprintln(os.Stderr, err)
  29. os.Exit(1)
  30. return
  31. }
  32. netUI := uiserver.NewNetUI(&state)
  33. go func() {
  34. err := netUI.Run(netUIsock)
  35. if err != nil {
  36. fmt.Fprintln(os.Stderr, "NetUI error", err)
  37. }
  38. }()
  39. killLs := make(chan struct{}) // when it is closed, liquidsoap will die
  40. killed := make(chan os.Signal, 1)
  41. signal.Notify(killed, os.Interrupt) // ctrl-c
  42. output, exit, err := liquidsoap.RunLiquidsoap(*liqfile, killLs)
  43. if err != nil {
  44. fmt.Fprintln(os.Stderr, "Error spawning liquidsoap", err)
  45. os.Exit(1)
  46. }
  47. go func(log <-chan liquidsoap.Output) {
  48. for {
  49. msg := <-log
  50. if msg.Msg != "" && msg.Level < 3 {
  51. fmt.Println("msg", msg)
  52. }
  53. }
  54. }(output)
  55. go func() {
  56. tick := time.Tick(3 * time.Second)
  57. for {
  58. <-tick
  59. t, err := liquidsoap.NewTelnet("localhost", 1234)
  60. if err != nil {
  61. fmt.Println("telnet connection errored", err)
  62. continue
  63. }
  64. t.Conn.SetDeadline(time.Now().Add(3 * time.Second))
  65. outs, err := t.Outputs()
  66. if err != nil {
  67. fmt.Println("telnet cmd errored", err)
  68. continue
  69. }
  70. changed := false
  71. for name, newstream := range outs {
  72. if stream, exists := state.Streams[name]; exists {
  73. if newstream != stream {
  74. state.Streams[name] = newstream
  75. changed = true
  76. }
  77. } else {
  78. state.Streams[name] = newstream
  79. changed = true
  80. }
  81. }
  82. t.Close()
  83. if changed {
  84. fmt.Println("state=", state)
  85. netUI.Update()
  86. }
  87. }
  88. }()
  89. for {
  90. select {
  91. case how := <-exit: // liquidsoap exits
  92. if !how.Success() {
  93. fmt.Fprintln(os.Stderr, "liquidsoap terminated,", how.Err)
  94. netUI.Close()
  95. os.Exit(1)
  96. }
  97. os.Exit(0)
  98. case <-killed: // we receive a SIGINT: ask liquidsoap to die is enough
  99. netUI.Close()
  100. close(killLs)
  101. fmt.Println("Closed by user interaction, waiting for liquidsoap to exit")
  102. // TODO: schedule a more aggressive SIGKILL if liquidsoap doesn't
  103. // exit soon
  104. }
  105. }
  106. }