Add support for copying files and folders.
This commit is contained in:
19
vendor/github.com/jaschaephraim/lrserver/LICENSE
generated
vendored
Normal file
19
vendor/github.com/jaschaephraim/lrserver/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014-2015 Jascha Ephraim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
114
vendor/github.com/jaschaephraim/lrserver/README.md
generated
vendored
Normal file
114
vendor/github.com/jaschaephraim/lrserver/README.md
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
# `lrserver` LiveReload server for Go #
|
||||
|
||||
Golang package that implements a simple LiveReload server as described in the [LiveReload protocol](http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol).
|
||||
|
||||
Using the recommended default port 35729:
|
||||
|
||||
- `http://localhost:35729/livereload.js` serves the LiveReload client JavaScript (https://github.com/livereload/livereload-js)
|
||||
|
||||
- `ws://localhost:35729/livereload` communicates with the client via web socket.
|
||||
|
||||
File watching must be implemented by your own application, and reload/alert
|
||||
requests sent programmatically.
|
||||
|
||||
Multiple servers can be instantiated, and each can support multiple connections.
|
||||
|
||||
## Full Documentation: [](http://godoc.org/github.com/jaschaephraim/lrserver) ##
|
||||
|
||||
## Basic Usage ##
|
||||
|
||||
### Get Package ###
|
||||
|
||||
```bash
|
||||
go get github.com/jaschaephraim/lrserver
|
||||
```
|
||||
|
||||
### Import Package ###
|
||||
|
||||
```go
|
||||
import "github.com/jaschaephraim/lrserver"
|
||||
```
|
||||
|
||||
### Instantiate Server ###
|
||||
|
||||
```go
|
||||
lr := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
|
||||
```
|
||||
|
||||
### Start Server ###
|
||||
|
||||
```go
|
||||
go func() {
|
||||
err := lr.ListenAndServe()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
}()
|
||||
```
|
||||
|
||||
### Send Messages to the Browser ###
|
||||
|
||||
```go
|
||||
lr.Reload("file")
|
||||
lr.Alert("message")
|
||||
```
|
||||
|
||||
## Example ##
|
||||
|
||||
```go
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/jaschaephraim/lrserver"
|
||||
"gopkg.in/fsnotify.v1"
|
||||
)
|
||||
|
||||
// html includes the client JavaScript
|
||||
const html = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="http://localhost:35729/livereload.js"></script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
func Example() {
|
||||
// Create file watcher
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Add dir to watcher
|
||||
err = watcher.Add("/path/to/watched/dir")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Create and start LiveReload server
|
||||
lr := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
|
||||
go lr.ListenAndServe()
|
||||
|
||||
// Start goroutine that requests reload upon watcher event
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
lr.Reload(event.Name)
|
||||
case err := <-watcher.Errors:
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Start serving html
|
||||
http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Write([]byte(html))
|
||||
})
|
||||
http.ListenAndServe(":3000", nil)
|
||||
}
|
||||
```
|
162
vendor/github.com/jaschaephraim/lrserver/connection.go
generated
vendored
Normal file
162
vendor/github.com/jaschaephraim/lrserver/connection.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
package lrserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
conn *websocket.Conn
|
||||
|
||||
server *Server
|
||||
handshake bool
|
||||
|
||||
reloadChan chan string
|
||||
alertChan chan string
|
||||
closeChan chan closeSignal
|
||||
}
|
||||
|
||||
func (c *conn) start() {
|
||||
go c.receive()
|
||||
go c.transmit()
|
||||
|
||||
// Say hello
|
||||
err := c.conn.WriteJSON(makeServerHello(c.server.Name()))
|
||||
if err != nil {
|
||||
c.close(websocket.CloseInternalServerErr, err)
|
||||
}
|
||||
|
||||
// Block until close signal is sent
|
||||
<-c.closeChan
|
||||
}
|
||||
|
||||
func (c *conn) receive() {
|
||||
for {
|
||||
// Get next message
|
||||
msgType, reader, err := c.conn.NextReader()
|
||||
if err != nil {
|
||||
c.close(0, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Close if binary instead of text
|
||||
if msgType == websocket.BinaryMessage {
|
||||
c.close(websocket.CloseUnsupportedData, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Close if it's not JSON
|
||||
hello := new(clientHello)
|
||||
err = json.NewDecoder(reader).Decode(hello)
|
||||
if err != nil {
|
||||
c.close(websocket.ClosePolicyViolation, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Close if missing a command field
|
||||
if hello.Command == "" {
|
||||
c.close(websocket.ClosePolicyViolation, nil)
|
||||
}
|
||||
|
||||
// Validate handshake
|
||||
if !c.handshake {
|
||||
if !validateHello(hello) {
|
||||
c.badHandshake()
|
||||
return
|
||||
}
|
||||
c.handshake = true
|
||||
c.server.logStatus("connected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) transmit() {
|
||||
for {
|
||||
var resp interface{}
|
||||
select {
|
||||
|
||||
// Reload
|
||||
case file := <-c.reloadChan:
|
||||
if !c.handshake {
|
||||
c.badHandshake()
|
||||
return
|
||||
}
|
||||
resp = makeServerReload(file, c.server.LiveCSS())
|
||||
|
||||
// Alert
|
||||
case msg := <-c.alertChan:
|
||||
if !c.handshake {
|
||||
c.badHandshake()
|
||||
return
|
||||
}
|
||||
resp = makeServerAlert(msg)
|
||||
}
|
||||
|
||||
err := c.conn.WriteJSON(resp)
|
||||
if err != nil {
|
||||
c.close(websocket.CloseInternalServerErr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) badHandshake() {
|
||||
c.close(websocket.ClosePolicyViolation, websocket.ErrBadHandshake)
|
||||
}
|
||||
|
||||
func (c *conn) close(closeCode int, closeErr error) error {
|
||||
var err error
|
||||
var errMsg string
|
||||
|
||||
if closeErr != nil {
|
||||
errMsg = closeErr.Error()
|
||||
c.server.logError(closeErr)
|
||||
|
||||
// Attempt to set close code from error message
|
||||
errMsgLen := len(errMsg)
|
||||
if errMsgLen >= 21 && errMsg[:17] == "websocket: close " {
|
||||
closeCode, _ = strconv.Atoi(errMsg[17:21])
|
||||
if errMsgLen > 21 {
|
||||
errMsg = errMsg[22:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default close code
|
||||
if closeCode == 0 {
|
||||
closeCode = websocket.CloseNoStatusReceived
|
||||
}
|
||||
|
||||
// Send close message
|
||||
closeMessage := websocket.FormatCloseMessage(closeCode, errMsg)
|
||||
deadline := time.Now().Add(time.Second)
|
||||
err = c.conn.WriteControl(websocket.CloseMessage, closeMessage, deadline)
|
||||
|
||||
// Kill and remove connection
|
||||
c.closeChan <- closeSignal{}
|
||||
c.server.connSet.remove(c)
|
||||
return err
|
||||
}
|
||||
|
||||
type connSet struct {
|
||||
conns map[*conn]struct{}
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (cs *connSet) add(c *conn) {
|
||||
cs.m.Lock()
|
||||
cs.conns[c] = struct{}{}
|
||||
cs.m.Unlock()
|
||||
}
|
||||
|
||||
func (cs *connSet) remove(c *conn) {
|
||||
cs.m.Lock()
|
||||
delete(cs.conns, c)
|
||||
cs.m.Unlock()
|
||||
}
|
||||
|
||||
type closeSignal struct{}
|
33
vendor/github.com/jaschaephraim/lrserver/handlers.go
generated
vendored
Normal file
33
vendor/github.com/jaschaephraim/lrserver/handlers.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package lrserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
func jsHandler(s *Server) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Set("Content-Type", "application/javascript")
|
||||
_, err := rw.Write([]byte(s.js))
|
||||
if err != nil {
|
||||
s.logError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func webSocketHandler(s *Server) http.HandlerFunc {
|
||||
// Do not check origin
|
||||
upgrader := websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
}
|
||||
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
conn, err := upgrader.Upgrade(rw, req, nil)
|
||||
if err != nil {
|
||||
s.logError(err)
|
||||
return
|
||||
}
|
||||
s.newConn(conn)
|
||||
}
|
||||
}
|
1206
vendor/github.com/jaschaephraim/lrserver/javascript.go
generated
vendored
Normal file
1206
vendor/github.com/jaschaephraim/lrserver/javascript.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30
vendor/github.com/jaschaephraim/lrserver/lrserver.go
generated
vendored
Normal file
30
vendor/github.com/jaschaephraim/lrserver/lrserver.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Package lrserver implements a basic LiveReload server.
|
||||
|
||||
(See http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol .)
|
||||
|
||||
Using the recommended default port 35729:
|
||||
|
||||
http://localhost:35729/livereload.js
|
||||
|
||||
serves the LiveReload client JavaScript, and:
|
||||
|
||||
ws://localhost:35729/livereload
|
||||
|
||||
communicates with the client via web socket.
|
||||
|
||||
File watching must be implemented by your own application, and reload/alert
|
||||
requests sent programmatically.
|
||||
|
||||
Multiple servers can be instantiated, and each can support multiple connections.
|
||||
*/
|
||||
package lrserver
|
||||
|
||||
const (
|
||||
|
||||
// DefaultName is the livereload Server's default name
|
||||
DefaultName string = "LiveReload"
|
||||
|
||||
// DefaultPort is the livereload Server's default server port
|
||||
DefaultPort uint16 = 35729
|
||||
)
|
68
vendor/github.com/jaschaephraim/lrserver/messages.go
generated
vendored
Normal file
68
vendor/github.com/jaschaephraim/lrserver/messages.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package lrserver
|
||||
|
||||
var protocols = []string{
|
||||
"http://livereload.com/protocols/official-7",
|
||||
"http://livereload.com/protocols/official-8",
|
||||
"http://livereload.com/protocols/official-9",
|
||||
"http://livereload.com/protocols/2.x-origin-version-negotiation",
|
||||
"http://livereload.com/protocols/2.x-remote-control",
|
||||
}
|
||||
|
||||
type clientHello struct {
|
||||
Command string `json:"command"`
|
||||
Protocols []string `json:"protocols"`
|
||||
}
|
||||
|
||||
func validateHello(hello *clientHello) bool {
|
||||
if hello.Command != "hello" {
|
||||
return false
|
||||
}
|
||||
for _, c := range hello.Protocols {
|
||||
for _, s := range protocols {
|
||||
if c == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type serverHello struct {
|
||||
Command string `json:"command"`
|
||||
Protocols []string `json:"protocols"`
|
||||
ServerName string `json:"serverName"`
|
||||
}
|
||||
|
||||
func makeServerHello(name string) *serverHello {
|
||||
return &serverHello{
|
||||
"hello",
|
||||
protocols,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
type serverReload struct {
|
||||
Command string `json:"command"`
|
||||
Path string `json:"path"`
|
||||
LiveCSS bool `json:"liveCSS"`
|
||||
}
|
||||
|
||||
func makeServerReload(file string, liveCSS bool) *serverReload {
|
||||
return &serverReload{
|
||||
Command: "reload",
|
||||
Path: file,
|
||||
LiveCSS: liveCSS,
|
||||
}
|
||||
}
|
||||
|
||||
type serverAlert struct {
|
||||
Command string `json:"command"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func makeServerAlert(msg string) *serverAlert {
|
||||
return &serverAlert{
|
||||
Command: "alert",
|
||||
Message: msg,
|
||||
}
|
||||
}
|
203
vendor/github.com/jaschaephraim/lrserver/server.go
generated
vendored
Normal file
203
vendor/github.com/jaschaephraim/lrserver/server.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package lrserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"context"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Server contains a single lrserver instance's data
|
||||
type Server struct {
|
||||
name string
|
||||
port uint16
|
||||
server *http.Server
|
||||
connSet *connSet
|
||||
js string
|
||||
statusLog *log.Logger
|
||||
liveCSS bool
|
||||
}
|
||||
|
||||
// New creates a new Server instance
|
||||
func New(name string, port uint16) *Server {
|
||||
// Create router
|
||||
router := http.NewServeMux()
|
||||
|
||||
logPrefix := "[" + name + "] "
|
||||
|
||||
// Create server
|
||||
s := &Server{
|
||||
name: name,
|
||||
server: &http.Server{
|
||||
Handler: router,
|
||||
ErrorLog: log.New(os.Stderr, logPrefix, 0),
|
||||
},
|
||||
connSet: &connSet{conns: make(map[*conn]struct{})},
|
||||
statusLog: log.New(os.Stdout, logPrefix, 0),
|
||||
liveCSS: true,
|
||||
}
|
||||
s.setPort(port)
|
||||
|
||||
// Handle JS
|
||||
router.HandleFunc("/livereload.js", jsHandler(s))
|
||||
|
||||
// Handle reload requests
|
||||
router.HandleFunc("/livereload", webSocketHandler(s))
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
if s.server != nil {
|
||||
return s.server.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown(ctx context.Context) error {
|
||||
if s.server != nil {
|
||||
return s.server.Shutdown(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) ListenAndServe() error {
|
||||
// Create listener
|
||||
l, err := net.Listen("tcp", makeAddr(s.port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set assigned port if necessary
|
||||
if s.port == 0 {
|
||||
port, err := makePort(l.Addr().String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.setPort(port)
|
||||
}
|
||||
|
||||
s.logStatus("listening on " + s.server.Addr)
|
||||
return s.server.Serve(l)
|
||||
}
|
||||
|
||||
// Reload sends a reload message to the client
|
||||
func (s *Server) Reload(file string) {
|
||||
s.logStatus("requesting reload: " + file)
|
||||
for conn := range s.connSet.conns {
|
||||
conn.reloadChan <- file
|
||||
}
|
||||
}
|
||||
|
||||
// Alert sends an alert message to the client
|
||||
func (s *Server) Alert(msg string) {
|
||||
s.logStatus("requesting alert: " + msg)
|
||||
for conn := range s.connSet.conns {
|
||||
conn.alertChan <- msg
|
||||
}
|
||||
}
|
||||
|
||||
// Name gets the server name
|
||||
func (s *Server) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Port gets the port that the server is listening on
|
||||
func (s *Server) Port() uint16 {
|
||||
return s.port
|
||||
}
|
||||
|
||||
// LiveCSS gets the live CSS preference
|
||||
func (s *Server) LiveCSS() bool {
|
||||
return s.liveCSS
|
||||
}
|
||||
|
||||
// StatusLog gets the server's status logger,
|
||||
// which writes to os.Stdout by default
|
||||
func (s *Server) StatusLog() *log.Logger {
|
||||
return s.statusLog
|
||||
}
|
||||
|
||||
// ErrorLog gets the server's error logger,
|
||||
// which writes to os.Stderr by default
|
||||
func (s *Server) ErrorLog() *log.Logger {
|
||||
return s.server.ErrorLog
|
||||
}
|
||||
|
||||
// SetLiveCSS sets the live CSS preference
|
||||
func (s *Server) SetLiveCSS(n bool) {
|
||||
s.liveCSS = n
|
||||
}
|
||||
|
||||
// SetStatusLog sets the server's status logger,
|
||||
// which can be set to nil
|
||||
func (s *Server) SetStatusLog(l *log.Logger) {
|
||||
s.statusLog = l
|
||||
}
|
||||
|
||||
// SetErrorLog sets the server's error logger,
|
||||
// which can be set to nil
|
||||
func (s *Server) SetErrorLog(l *log.Logger) {
|
||||
s.server.ErrorLog = l
|
||||
}
|
||||
|
||||
func (s *Server) setPort(port uint16) {
|
||||
s.port = port
|
||||
s.server.Addr = makeAddr(port)
|
||||
|
||||
if port != 0 {
|
||||
s.js = fmt.Sprintf(js, s.port)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) newConn(wsConn *websocket.Conn) {
|
||||
c := &conn{
|
||||
conn: wsConn,
|
||||
|
||||
server: s,
|
||||
handshake: false,
|
||||
|
||||
reloadChan: make(chan string),
|
||||
alertChan: make(chan string),
|
||||
closeChan: make(chan closeSignal),
|
||||
}
|
||||
s.connSet.add(c)
|
||||
go c.start()
|
||||
}
|
||||
|
||||
func (s *Server) logStatus(msg ...interface{}) {
|
||||
if s.statusLog != nil {
|
||||
s.statusLog.Println(msg...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) logError(msg ...interface{}) {
|
||||
if s.server.ErrorLog != nil {
|
||||
s.server.ErrorLog.Println(msg...)
|
||||
}
|
||||
}
|
||||
|
||||
// makeAddr converts uint16(x) to ":x"
|
||||
func makeAddr(port uint16) string {
|
||||
return fmt.Sprintf(":%d", port)
|
||||
}
|
||||
|
||||
// makePort converts ":x" to uint16(x)
|
||||
func makePort(addr string) (uint16, error) {
|
||||
_, portString, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
port64, err := strconv.ParseUint(portString, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(port64), nil
|
||||
}
|
Reference in New Issue
Block a user