You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 9 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package livereload
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "sync"
  6. "github.com/gorilla/websocket"
  7. )
  8. /* ----------------------------------------------------------------------
  9. * WebSocket Server
  10. * ----------------------------------------------------------------------*/
  11. var (
  12. once sync.Once
  13. broadcast chan []byte
  14. tunnels map[*tunnel]bool
  15. in chan *tunnel
  16. out chan *tunnel
  17. mutex sync.RWMutex
  18. upgrader = websocket.Upgrader{
  19. ReadBufferSize: 1024,
  20. WriteBufferSize: 1024,
  21. }
  22. URL = struct {
  23. WebSocket string
  24. JavaScript string
  25. }{
  26. WebSocket: "/livereload",
  27. JavaScript: "/livereload.js",
  28. }
  29. )
  30. // Alert sends a notice message to browser's livereload.js.
  31. func Alert(message string) {
  32. go func() {
  33. var bytes, _ = json.Marshal(&alert{
  34. Command: "alert",
  35. Message: message,
  36. })
  37. broadcast <- bytes
  38. }()
  39. }
  40. // Reload sends a reload message to browser's livereload.js.
  41. func Reload() {
  42. go func() {
  43. var bytes, _ = json.Marshal(&reload{
  44. Command: "reload",
  45. Path: URL.WebSocket,
  46. LiveCSS: true,
  47. })
  48. broadcast <- bytes
  49. }()
  50. }
  51. // run watches/dispatches all tunnel & tunnel messages.
  52. func run() {
  53. for {
  54. select {
  55. case tunnel := <-in:
  56. mutex.Lock()
  57. defer mutex.Unlock()
  58. tunnels[tunnel] = true
  59. case tunnel := <-out:
  60. mutex.Lock()
  61. defer mutex.Unlock()
  62. delete(tunnels, tunnel)
  63. close(tunnel.message)
  64. case m := <-broadcast:
  65. for tunnel := range tunnels {
  66. select {
  67. case tunnel.message <- m:
  68. default:
  69. mutex.Lock()
  70. defer mutex.Unlock()
  71. delete(tunnels, tunnel)
  72. close(tunnel.message)
  73. }
  74. }
  75. }
  76. }
  77. }
  78. // Serve serves as a livereload server for accepting I/O tunnel messages.
  79. func ServeWebSocket(w http.ResponseWriter, r *http.Request) {
  80. var socket, err = upgrader.Upgrade(w, r, nil)
  81. if err != nil {
  82. return
  83. }
  84. tunnel := new(tunnel)
  85. tunnel.socket = socket
  86. tunnel.message = make(chan []byte, 256)
  87. in <- tunnel
  88. defer func() { out <- tunnel }()
  89. tunnel.connect()
  90. }
  91. // ServeJavaScript serves livereload.js for browser.
  92. func ServeJavaScript(w http.ResponseWriter, r *http.Request) {
  93. w.Header().Set("Content-Type", "application/javascript")
  94. w.Write(javascript)
  95. }
  96. // Start activates livereload server for accepting tunnel messages.
  97. func Start() {
  98. once.Do(func() {
  99. broadcast = make(chan []byte)
  100. tunnels = make(map[*tunnel]bool)
  101. in = make(chan *tunnel)
  102. out = make(chan *tunnel)
  103. go run()
  104. })
  105. }