github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/util.go (about) 1 /* 2 Copyright 2013 CoreOS Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "net" 24 "net/http" 25 "net/url" 26 "os" 27 "os/signal" 28 "runtime/pprof" 29 "strconv" 30 "time" 31 32 "github.com/coreos/etcd/web" 33 "github.com/coreos/go-log/log" 34 ) 35 36 //-------------------------------------- 37 // etcd http Helper 38 //-------------------------------------- 39 40 // Convert string duration to time format 41 func durationToExpireTime(strDuration string) (time.Time, error) { 42 if strDuration != "" { 43 duration, err := strconv.Atoi(strDuration) 44 45 if err != nil { 46 return time.Unix(0, 0), err 47 } 48 return time.Now().Add(time.Second * (time.Duration)(duration)), nil 49 50 } else { 51 return time.Unix(0, 0), nil 52 } 53 } 54 55 //-------------------------------------- 56 // Web Helper 57 //-------------------------------------- 58 var storeMsg chan string 59 60 // Help to send msg from store to webHub 61 func webHelper() { 62 storeMsg = make(chan string) 63 etcdStore.SetMessager(storeMsg) 64 for { 65 // transfer the new msg to webHub 66 web.Hub().Send(<-storeMsg) 67 } 68 } 69 70 // startWebInterface starts web interface if webURL is not empty 71 func startWebInterface() { 72 if argInfo.WebURL != "" { 73 // start web 74 go webHelper() 75 go web.Start(r.Server, argInfo.WebURL) 76 } 77 } 78 79 //-------------------------------------- 80 // HTTP Utilities 81 //-------------------------------------- 82 83 func decodeJsonRequest(req *http.Request, data interface{}) error { 84 decoder := json.NewDecoder(req.Body) 85 if err := decoder.Decode(&data); err != nil && err != io.EOF { 86 warnf("Malformed json request: %v", err) 87 return fmt.Errorf("Malformed json request: %v", err) 88 } 89 return nil 90 } 91 92 func encodeJsonResponse(w http.ResponseWriter, status int, data interface{}) { 93 w.Header().Set("Content-Type", "application/json") 94 w.WriteHeader(status) 95 96 if data != nil { 97 encoder := json.NewEncoder(w) 98 encoder.Encode(data) 99 } 100 } 101 102 // sanitizeURL will cleanup a host string in the format hostname:port and 103 // attach a schema. 104 func sanitizeURL(host string, defaultScheme string) string { 105 // Blank URLs are fine input, just return it 106 if len(host) == 0 { 107 return host 108 } 109 110 p, err := url.Parse(host) 111 if err != nil { 112 fatal(err) 113 } 114 115 // Make sure the host is in Host:Port format 116 _, _, err = net.SplitHostPort(host) 117 if err != nil { 118 fatal(err) 119 } 120 121 p = &url.URL{Host: host, Scheme: defaultScheme} 122 123 return p.String() 124 } 125 126 // sanitizeListenHost cleans up the ListenHost parameter and appends a port 127 // if necessary based on the advertised port. 128 func sanitizeListenHost(listen string, advertised string) string { 129 aurl, err := url.Parse(advertised) 130 if err != nil { 131 fatal(err) 132 } 133 134 ahost, aport, err := net.SplitHostPort(aurl.Host) 135 if err != nil { 136 fatal(err) 137 } 138 139 // If the listen host isn't set use the advertised host 140 if listen == "" { 141 listen = ahost 142 } 143 144 return net.JoinHostPort(listen, aport) 145 } 146 147 func redirect(node string, etcd bool, w http.ResponseWriter, req *http.Request) { 148 var url string 149 path := req.URL.Path 150 151 if etcd { 152 etcdAddr, _ := nameToEtcdURL(node) 153 url = etcdAddr + path 154 } else { 155 raftAddr, _ := nameToRaftURL(node) 156 url = raftAddr + path 157 } 158 159 debugf("Redirect to %s", url) 160 161 http.Redirect(w, req, url, http.StatusTemporaryRedirect) 162 } 163 164 func check(err error) { 165 if err != nil { 166 fatal(err) 167 } 168 } 169 170 //-------------------------------------- 171 // Log 172 //-------------------------------------- 173 174 var logger *log.Logger = log.New("etcd", false, 175 log.CombinedSink(os.Stdout, "[%s] %s %-9s | %s\n", []string{"prefix", "time", "priority", "message"})) 176 177 func infof(format string, v ...interface{}) { 178 logger.Infof(format, v...) 179 } 180 181 func debugf(format string, v ...interface{}) { 182 if verbose { 183 logger.Debugf(format, v...) 184 } 185 } 186 187 func debug(v ...interface{}) { 188 if verbose { 189 logger.Debug(v...) 190 } 191 } 192 193 func warnf(format string, v ...interface{}) { 194 logger.Warningf(format, v...) 195 } 196 197 func warn(v ...interface{}) { 198 logger.Warning(v...) 199 } 200 201 func fatalf(format string, v ...interface{}) { 202 logger.Fatalf(format, v...) 203 } 204 205 func fatal(v ...interface{}) { 206 logger.Fatalln(v...) 207 } 208 209 //-------------------------------------- 210 // CPU profile 211 //-------------------------------------- 212 func runCPUProfile() { 213 214 f, err := os.Create(cpuprofile) 215 if err != nil { 216 fatal(err) 217 } 218 pprof.StartCPUProfile(f) 219 220 c := make(chan os.Signal, 1) 221 signal.Notify(c, os.Interrupt) 222 go func() { 223 for sig := range c { 224 infof("captured %v, stopping profiler and exiting..", sig) 225 pprof.StopCPUProfile() 226 os.Exit(1) 227 } 228 }() 229 } 230 231 //-------------------------------------- 232 // Testing 233 //-------------------------------------- 234 func directSet() { 235 c := make(chan bool, 1000) 236 for i := 0; i < 1000; i++ { 237 go send(c) 238 } 239 240 for i := 0; i < 1000; i++ { 241 <-c 242 } 243 } 244 245 func send(c chan bool) { 246 for i := 0; i < 10; i++ { 247 command := &SetCommand{} 248 command.Key = "foo" 249 command.Value = "bar" 250 command.ExpireTime = time.Unix(0, 0) 251 r.Do(command) 252 } 253 c <- true 254 }