main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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, enabled := range outs {
  72. if stream, exists := state.Streams[name]; exists {
  73. if stream.State != enabled {
  74. stream.State = enabled
  75. changed = true
  76. }
  77. state.Streams[name] = stream
  78. } else {
  79. state.Streams[name] = liquidsoap.Stream{State: enabled}
  80. changed = true
  81. }
  82. }
  83. t.Close()
  84. fmt.Println(changed, "state=", state)
  85. if changed {
  86. netUI.Update()
  87. }
  88. }
  89. }()
  90. for {
  91. select {
  92. case how := <-exit: // liquidsoap exits
  93. if !how.Success() {
  94. fmt.Fprintln(os.Stderr, "liquidsoap terminated,", how.Err)
  95. netUI.Close()
  96. os.Exit(1)
  97. }
  98. os.Exit(0)
  99. case <-killed: // we receive a SIGINT: ask liquidsoap to die is enough
  100. netUI.Close()
  101. close(killLs)
  102. fmt.Println("Closed by user interaction, waiting for liquidsoap to exit")
  103. // TODO: schedule a more aggressive SIGKILL if liquidsoap doesn't
  104. // exit soon
  105. }
  106. }
  107. }