/usr/share/gocode/src/github.com/smartystreets/goconvey/web/server/api/server.go is in golang-github-smartystreets-goconvey-dev 1.6.1-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | package api
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"time"
"github.com/smartystreets/goconvey/web/server/contract"
"github.com/smartystreets/goconvey/web/server/messaging"
)
type HTTPServer struct {
watcher chan messaging.WatcherCommand
executor contract.Executor
latest *contract.CompleteOutput
currentRoot string
longpoll chan chan string
paused bool
}
func (self *HTTPServer) ReceiveUpdate(root string, update *contract.CompleteOutput) {
self.currentRoot = root
self.latest = update
}
func (self *HTTPServer) Watch(response http.ResponseWriter, request *http.Request) {
if request.Method == "POST" {
self.adjustRoot(response, request)
} else if request.Method == "GET" {
response.Write([]byte(self.currentRoot))
}
}
func (self *HTTPServer) adjustRoot(response http.ResponseWriter, request *http.Request) {
newRoot := self.parseQueryString("root", response, request)
if newRoot == "" {
return
}
info, err := os.Stat(newRoot) // TODO: how to unit test?
if !info.IsDir() || err != nil {
http.Error(response, err.Error(), http.StatusNotFound)
return
}
self.watcher <- messaging.WatcherCommand{
Instruction: messaging.WatcherAdjustRoot,
Details: newRoot,
}
}
func (self *HTTPServer) Ignore(response http.ResponseWriter, request *http.Request) {
paths := self.parseQueryString("paths", response, request)
if paths != "" {
self.watcher <- messaging.WatcherCommand{
Instruction: messaging.WatcherIgnore,
Details: paths,
}
}
}
func (self *HTTPServer) Reinstate(response http.ResponseWriter, request *http.Request) {
paths := self.parseQueryString("paths", response, request)
if paths != "" {
self.watcher <- messaging.WatcherCommand{
Instruction: messaging.WatcherReinstate,
Details: paths,
}
}
}
func (self *HTTPServer) parseQueryString(key string, response http.ResponseWriter, request *http.Request) string {
value := request.URL.Query()[key]
if len(value) == 0 {
http.Error(response, fmt.Sprintf("No '%s' query string parameter included!", key), http.StatusBadRequest)
return ""
}
path := value[0]
if path == "" {
http.Error(response, "You must provide a non-blank path.", http.StatusBadRequest)
}
return path
}
func (self *HTTPServer) Status(response http.ResponseWriter, request *http.Request) {
status := self.executor.Status()
response.Write([]byte(status))
}
func (self *HTTPServer) LongPollStatus(response http.ResponseWriter, request *http.Request) {
if self.executor.ClearStatusFlag() {
response.Write([]byte(self.executor.Status()))
return
}
timeout, err := strconv.Atoi(request.URL.Query().Get("timeout"))
if err != nil || timeout > 180000 || timeout < 0 {
timeout = 60000 // default timeout is 60 seconds
}
myReqChan := make(chan string)
select {
case self.longpoll <- myReqChan: // this case means the executor's status is changing
case <-time.After(time.Duration(timeout) * time.Millisecond): // this case means the executor hasn't changed status
return
}
out := <-myReqChan
if out != "" { // TODO: Why is this check necessary? Sometimes it writes empty string...
response.Write([]byte(out))
}
}
func (self *HTTPServer) Results(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "application/json")
response.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
response.Header().Set("Pragma", "no-cache")
response.Header().Set("Expires", "0")
if self.latest != nil {
self.latest.Paused = self.paused
}
stuff, _ := json.Marshal(self.latest)
response.Write(stuff)
}
func (self *HTTPServer) Execute(response http.ResponseWriter, request *http.Request) {
go self.execute()
}
func (self *HTTPServer) execute() {
self.watcher <- messaging.WatcherCommand{Instruction: messaging.WatcherExecute}
}
func (self *HTTPServer) TogglePause(response http.ResponseWriter, request *http.Request) {
instruction := messaging.WatcherPause
if self.paused {
instruction = messaging.WatcherResume
}
self.watcher <- messaging.WatcherCommand{Instruction: instruction}
self.paused = !self.paused
fmt.Fprint(response, self.paused) // we could write out whatever helps keep the UI honest...
}
func NewHTTPServer(
root string,
watcher chan messaging.WatcherCommand,
executor contract.Executor,
status chan chan string) *HTTPServer {
self := new(HTTPServer)
self.currentRoot = root
self.watcher = watcher
self.executor = executor
self.longpoll = status
return self
}
|