mirror of
https://github.com/minio/minio.git
synced 2024-12-31 17:43:21 -05:00
61175ef091
- over the course of a project history every maintainer needs to update its dependency packages, the problem essentially with godep is manipulating GOPATH - this manipulation leads to static objects created at different locations which end up conflicting with the overall functionality of golang. This also leads to broken builds. There is no easier way out of this other than asking developers to do 'godep restore' all the time. Which perhaps as a practice doesn't sound like a clean solution. On the other hand 'godep restore' has its own set of problems. - govendor is a right tool but a stop gap tool until we wait for golangs official 1.5 version which fixes this vendoring issue once and for all. - govendor provides consistency in terms of how import paths should be handled unlike manipulation GOPATH. This has advantages - no more compiled objects being referenced in GOPATH and build time GOPATH manging which leads to conflicts. - proper import paths referencing the exact package a project is dependent on. govendor is simple and provides the minimal necessary tooling to achieve this. For now this is the right solution.
165 lines
4.6 KiB
Go
165 lines
4.6 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Copyright 2012 The Gorilla Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package rpc
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
var (
|
|
// Precompute the reflect.Type of error and http.Request
|
|
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
|
typeOfRequest = reflect.TypeOf((*http.Request)(nil)).Elem()
|
|
)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// service
|
|
// ----------------------------------------------------------------------------
|
|
|
|
type service struct {
|
|
name string // name of service
|
|
rcvr reflect.Value // receiver of methods for the service
|
|
rcvrType reflect.Type // type of the receiver
|
|
methods map[string]*serviceMethod // registered methods
|
|
}
|
|
|
|
type serviceMethod struct {
|
|
method reflect.Method // receiver method
|
|
argsType reflect.Type // type of the request argument
|
|
replyType reflect.Type // type of the response argument
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// serviceMap
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// serviceMap is a registry for services.
|
|
type serviceMap struct {
|
|
mutex sync.Mutex
|
|
services map[string]*service
|
|
}
|
|
|
|
// register adds a new service using reflection to extract its methods.
|
|
func (m *serviceMap) register(rcvr interface{}, name string) error {
|
|
// Setup service.
|
|
s := &service{
|
|
name: name,
|
|
rcvr: reflect.ValueOf(rcvr),
|
|
rcvrType: reflect.TypeOf(rcvr),
|
|
methods: make(map[string]*serviceMethod),
|
|
}
|
|
if name == "" {
|
|
s.name = reflect.Indirect(s.rcvr).Type().Name()
|
|
if !isExported(s.name) {
|
|
return fmt.Errorf("rpc: type %q is not exported", s.name)
|
|
}
|
|
}
|
|
if s.name == "" {
|
|
return fmt.Errorf("rpc: no service name for type %q",
|
|
s.rcvrType.String())
|
|
}
|
|
// Setup methods.
|
|
for i := 0; i < s.rcvrType.NumMethod(); i++ {
|
|
method := s.rcvrType.Method(i)
|
|
mtype := method.Type
|
|
// Method must be exported.
|
|
if method.PkgPath != "" {
|
|
continue
|
|
}
|
|
// Method needs four ins: receiver, *http.Request, *args, *reply.
|
|
if mtype.NumIn() != 4 {
|
|
continue
|
|
}
|
|
// First argument must be a pointer and must be http.Request.
|
|
reqType := mtype.In(1)
|
|
if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfRequest {
|
|
continue
|
|
}
|
|
// Second argument must be a pointer and must be exported.
|
|
args := mtype.In(2)
|
|
if args.Kind() != reflect.Ptr || !isExportedOrBuiltin(args) {
|
|
continue
|
|
}
|
|
// Third argument must be a pointer and must be exported.
|
|
reply := mtype.In(3)
|
|
if reply.Kind() != reflect.Ptr || !isExportedOrBuiltin(reply) {
|
|
continue
|
|
}
|
|
// Method needs one out: error.
|
|
if mtype.NumOut() != 1 {
|
|
continue
|
|
}
|
|
if returnType := mtype.Out(0); returnType != typeOfError {
|
|
continue
|
|
}
|
|
s.methods[method.Name] = &serviceMethod{
|
|
method: method,
|
|
argsType: args.Elem(),
|
|
replyType: reply.Elem(),
|
|
}
|
|
}
|
|
if len(s.methods) == 0 {
|
|
return fmt.Errorf("rpc: %q has no exported methods of suitable type",
|
|
s.name)
|
|
}
|
|
// Add to the map.
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
if m.services == nil {
|
|
m.services = make(map[string]*service)
|
|
} else if _, ok := m.services[s.name]; ok {
|
|
return fmt.Errorf("rpc: service already defined: %q", s.name)
|
|
}
|
|
m.services[s.name] = s
|
|
return nil
|
|
}
|
|
|
|
// get returns a registered service given a method name.
|
|
//
|
|
// The method name uses a dotted notation as in "Service.Method".
|
|
func (m *serviceMap) get(method string) (*service, *serviceMethod, error) {
|
|
parts := strings.Split(method, ".")
|
|
if len(parts) != 2 {
|
|
err := fmt.Errorf("rpc: service/method request ill-formed: %q", method)
|
|
return nil, nil, err
|
|
}
|
|
m.mutex.Lock()
|
|
service := m.services[parts[0]]
|
|
m.mutex.Unlock()
|
|
if service == nil {
|
|
err := fmt.Errorf("rpc: can't find service %q", method)
|
|
return nil, nil, err
|
|
}
|
|
serviceMethod := service.methods[parts[1]]
|
|
if serviceMethod == nil {
|
|
err := fmt.Errorf("rpc: can't find method %q", method)
|
|
return nil, nil, err
|
|
}
|
|
return service, serviceMethod, nil
|
|
}
|
|
|
|
// isExported returns true of a string is an exported (upper case) name.
|
|
func isExported(name string) bool {
|
|
rune, _ := utf8.DecodeRuneInString(name)
|
|
return unicode.IsUpper(rune)
|
|
}
|
|
|
|
// isExportedOrBuiltin returns true if a type is exported or a builtin.
|
|
func isExportedOrBuiltin(t reflect.Type) bool {
|
|
for t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
// PkgPath will be non-empty even for an exported type,
|
|
// so we need to check the type name as well.
|
|
return isExported(t.Name()) || t.PkgPath() == ""
|
|
}
|