github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/internal/internal.go (about) 1 // Copyright 2011 Google Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 // Package internal provides support for package appengine. 6 // 7 // Programs should not use this package directly. Its API is not stable. 8 // Use packages appengine and appengine/* instead. 9 package internal 10 11 import ( 12 "fmt" 13 "io" 14 "log" 15 "net/http" 16 "net/url" 17 "os" 18 19 "github.com/golang/protobuf/proto" 20 21 remotepb "google.golang.org/appengine/internal/remote_api" 22 ) 23 24 // errorCodeMaps is a map of service name to the error code map for the service. 25 var errorCodeMaps = make(map[string]map[int32]string) 26 27 // RegisterErrorCodeMap is called from API implementations to register their 28 // error code map. This should only be called from init functions. 29 func RegisterErrorCodeMap(service string, m map[int32]string) { 30 errorCodeMaps[service] = m 31 } 32 33 type timeoutCodeKey struct { 34 service string 35 code int32 36 } 37 38 // timeoutCodes is the set of service+code pairs that represent timeouts. 39 var timeoutCodes = make(map[timeoutCodeKey]bool) 40 41 func RegisterTimeoutErrorCode(service string, code int32) { 42 timeoutCodes[timeoutCodeKey{service, code}] = true 43 } 44 45 // APIError is the type returned by appengine.Context's Call method 46 // when an API call fails in an API-specific way. This may be, for instance, 47 // a taskqueue API call failing with TaskQueueServiceError::UNKNOWN_QUEUE. 48 type APIError struct { 49 Service string 50 Detail string 51 Code int32 // API-specific error code 52 } 53 54 func (e *APIError) Error() string { 55 if e.Code == 0 { 56 if e.Detail == "" { 57 return "APIError <empty>" 58 } 59 return e.Detail 60 } 61 s := fmt.Sprintf("API error %d", e.Code) 62 if m, ok := errorCodeMaps[e.Service]; ok { 63 s += " (" + e.Service + ": " + m[e.Code] + ")" 64 } else { 65 // Shouldn't happen, but provide a bit more detail if it does. 66 s = e.Service + " " + s 67 } 68 if e.Detail != "" { 69 s += ": " + e.Detail 70 } 71 return s 72 } 73 74 func (e *APIError) IsTimeout() bool { 75 return timeoutCodes[timeoutCodeKey{e.Service, e.Code}] 76 } 77 78 // CallError is the type returned by appengine.Context's Call method when an 79 // API call fails in a generic way, such as RpcError::CAPABILITY_DISABLED. 80 type CallError struct { 81 Detail string 82 Code int32 83 // TODO: Remove this if we get a distinguishable error code. 84 Timeout bool 85 } 86 87 func (e *CallError) Error() string { 88 var msg string 89 switch remotepb.RpcError_ErrorCode(e.Code) { 90 case remotepb.RpcError_UNKNOWN: 91 return e.Detail 92 case remotepb.RpcError_OVER_QUOTA: 93 msg = "Over quota" 94 case remotepb.RpcError_CAPABILITY_DISABLED: 95 msg = "Capability disabled" 96 case remotepb.RpcError_CANCELLED: 97 msg = "Canceled" 98 default: 99 msg = fmt.Sprintf("Call error %d", e.Code) 100 } 101 s := msg + ": " + e.Detail 102 if e.Timeout { 103 s += " (timeout)" 104 } 105 return s 106 } 107 108 func (e *CallError) IsTimeout() bool { 109 return e.Timeout 110 } 111 112 func Main() { 113 installHealthChecker(http.DefaultServeMux) 114 115 port := "8080" 116 if s := os.Getenv("PORT"); s != "" { 117 port = s 118 } 119 120 if err := http.ListenAndServe(":"+port, http.HandlerFunc(handleHTTP)); err != nil { 121 log.Fatalf("http.ListenAndServe: %v", err) 122 } 123 } 124 125 func installHealthChecker(mux *http.ServeMux) { 126 // If no health check handler has been installed by this point, add a trivial one. 127 const healthPath = "/_ah/health" 128 hreq := &http.Request{ 129 Method: "GET", 130 URL: &url.URL{ 131 Path: healthPath, 132 }, 133 } 134 if _, pat := mux.Handler(hreq); pat != healthPath { 135 mux.HandleFunc(healthPath, func(w http.ResponseWriter, r *http.Request) { 136 io.WriteString(w, "ok") 137 }) 138 } 139 } 140 141 // NamespaceMods is a map from API service to a function that will mutate an RPC request to attach a namespace. 142 // The function should be prepared to be called on the same message more than once; it should only modify the 143 // RPC request the first time. 144 var NamespaceMods = make(map[string]func(m proto.Message, namespace string))