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))