use inject to short code

master
hzsunshx 9 years ago
parent 3bb24809fe
commit ed028d1000

5
Godeps/Godeps.json generated

@ -11,6 +11,11 @@
"Comment": "1.2.0-139-g142e6cd",
"Rev": "142e6cd241a4dfbf7f07a018f1f8225180018da4"
},
{
"ImportPath": "github.com/codegangsta/inject",
"Comment": "v1.0-rc1-10-g33e0aa1",
"Rev": "33e0aa1cb7c019ccc3fbe049a8262a6403d30504"
},
{
"ImportPath": "github.com/codeskyblue/kproc",
"Rev": "fcb55eb35ab6b7290f395ad596e80e8355d52d69"

@ -0,0 +1,2 @@
inject
inject.test

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Jeremy Saenz
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,92 @@
# inject
--
import "github.com/codegangsta/inject"
Package inject provides utilities for mapping and injecting dependencies in
various ways.
Language Translations:
* [简体中文](translations/README_zh_cn.md)
## Usage
#### func InterfaceOf
```go
func InterfaceOf(value interface{}) reflect.Type
```
InterfaceOf dereferences a pointer to an Interface type. It panics if value is
not an pointer to an interface.
#### type Applicator
```go
type Applicator interface {
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'. Returns an error if the injection
// fails.
Apply(interface{}) error
}
```
Applicator represents an interface for mapping dependencies to a struct.
#### type Injector
```go
type Injector interface {
Applicator
Invoker
TypeMapper
// SetParent sets the parent of the injector. If the injector cannot find a
// dependency in its Type map it will check its parent before returning an
// error.
SetParent(Injector)
}
```
Injector represents an interface for mapping and injecting dependencies into
structs and function arguments.
#### func New
```go
func New() Injector
```
New returns a new Injector.
#### type Invoker
```go
type Invoker interface {
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type. Returns
// a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke(interface{}) ([]reflect.Value, error)
}
```
Invoker represents an interface for calling functions via reflection.
#### type TypeMapper
```go
type TypeMapper interface {
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
Map(interface{}) TypeMapper
// Maps the interface{} value based on the pointer of an Interface provided.
// This is really only useful for mapping a value as an interface, as interfaces
// cannot at this time be referenced directly without a pointer.
MapTo(interface{}, interface{}) TypeMapper
// Provides a possibility to directly insert a mapping based on type and value.
// This makes it possible to directly map type arguments not possible to instantiate
// with reflect like unidirectional channels.
Set(reflect.Type, reflect.Value) TypeMapper
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
// the Type has not been mapped.
Get(reflect.Type) reflect.Value
}
```
TypeMapper represents an interface for mapping interface{} values based on type.

@ -0,0 +1,187 @@
// Package inject provides utilities for mapping and injecting dependencies in various ways.
package inject
import (
"fmt"
"reflect"
)
// Injector represents an interface for mapping and injecting dependencies into structs
// and function arguments.
type Injector interface {
Applicator
Invoker
TypeMapper
// SetParent sets the parent of the injector. If the injector cannot find a
// dependency in its Type map it will check its parent before returning an
// error.
SetParent(Injector)
}
// Applicator represents an interface for mapping dependencies to a struct.
type Applicator interface {
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'. Returns an error if the injection
// fails.
Apply(interface{}) error
}
// Invoker represents an interface for calling functions via reflection.
type Invoker interface {
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type. Returns
// a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke(interface{}) ([]reflect.Value, error)
}
// TypeMapper represents an interface for mapping interface{} values based on type.
type TypeMapper interface {
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
Map(interface{}) TypeMapper
// Maps the interface{} value based on the pointer of an Interface provided.
// This is really only useful for mapping a value as an interface, as interfaces
// cannot at this time be referenced directly without a pointer.
MapTo(interface{}, interface{}) TypeMapper
// Provides a possibility to directly insert a mapping based on type and value.
// This makes it possible to directly map type arguments not possible to instantiate
// with reflect like unidirectional channels.
Set(reflect.Type, reflect.Value) TypeMapper
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
// the Type has not been mapped.
Get(reflect.Type) reflect.Value
}
type injector struct {
values map[reflect.Type]reflect.Value
parent Injector
}
// InterfaceOf dereferences a pointer to an Interface type.
// It panics if value is not an pointer to an interface.
func InterfaceOf(value interface{}) reflect.Type {
t := reflect.TypeOf(value)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Interface {
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
}
return t
}
// New returns a new Injector.
func New() Injector {
return &injector{
values: make(map[reflect.Type]reflect.Value),
}
}
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type.
// Returns a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
// It panics if f is not a function
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
t := reflect.TypeOf(f)
var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func
for i := 0; i < t.NumIn(); i++ {
argType := t.In(i)
val := inj.Get(argType)
if !val.IsValid() {
return nil, fmt.Errorf("Value not found for type %v", argType)
}
in[i] = val
}
return reflect.ValueOf(f).Call(in), nil
}
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'.
// Returns an error if the injection fails.
func (inj *injector) Apply(val interface{}) error {
v := reflect.ValueOf(val)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil // Should not panic here ?
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
structField := t.Field(i)
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
ft := f.Type()
v := inj.Get(ft)
if !v.IsValid() {
return fmt.Errorf("Value not found for type %v", ft)
}
f.Set(v)
}
}
return nil
}
// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
// It returns the TypeMapper registered in.
func (i *injector) Map(val interface{}) TypeMapper {
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
return i
}
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
return i
}
// Maps the given reflect.Type to the given reflect.Value and returns
// the Typemapper the mapping has been registered in.
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
i.values[typ] = val
return i
}
func (i *injector) Get(t reflect.Type) reflect.Value {
val := i.values[t]
if val.IsValid() {
return val
}
// no concrete types found, try to find implementors
// if t is an interface
if t.Kind() == reflect.Interface {
for k, v := range i.values {
if k.Implements(t) {
val = v
break
}
}
}
// Still no type found, try to look it up on the parent
if !val.IsValid() && i.parent != nil {
val = i.parent.Get(t)
}
return val
}
func (i *injector) SetParent(parent Injector) {
i.parent = parent
}

@ -0,0 +1,159 @@
package inject_test
import (
"fmt"
"github.com/codegangsta/inject"
"reflect"
"testing"
)
type SpecialString interface {
}
type TestStruct struct {
Dep1 string `inject:"t" json:"-"`
Dep2 SpecialString `inject`
Dep3 string
}
type Greeter struct {
Name string
}
func (g *Greeter) String() string {
return "Hello, My name is" + g.Name
}
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func Test_InjectorInvoke(t *testing.T) {
injector := inject.New()
expect(t, injector == nil, false)
dep := "some dependency"
injector.Map(dep)
dep2 := "another dep"
injector.MapTo(dep2, (*SpecialString)(nil))
dep3 := make(chan *SpecialString)
dep4 := make(chan *SpecialString)
typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
injector.Set(typRecv, reflect.ValueOf(dep3))
injector.Set(typSend, reflect.ValueOf(dep4))
_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
expect(t, d1, dep)
expect(t, d2, dep2)
expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem())
expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem())
expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir)
expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir)
})
expect(t, err, nil)
}
func Test_InjectorInvokeReturnValues(t *testing.T) {
injector := inject.New()
expect(t, injector == nil, false)
dep := "some dependency"
injector.Map(dep)
dep2 := "another dep"
injector.MapTo(dep2, (*SpecialString)(nil))
result, err := injector.Invoke(func(d1 string, d2 SpecialString) string {
expect(t, d1, dep)
expect(t, d2, dep2)
return "Hello world"
})
expect(t, result[0].String(), "Hello world")
expect(t, err, nil)
}
func Test_InjectorApply(t *testing.T) {
injector := inject.New()
injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil))
s := TestStruct{}
err := injector.Apply(&s)
expect(t, err, nil)
expect(t, s.Dep1, "a dep")
expect(t, s.Dep2, "another dep")
expect(t, s.Dep3, "")
}
func Test_InterfaceOf(t *testing.T) {
iType := inject.InterfaceOf((*SpecialString)(nil))
expect(t, iType.Kind(), reflect.Interface)
iType = inject.InterfaceOf((**SpecialString)(nil))
expect(t, iType.Kind(), reflect.Interface)
// Expecting nil
defer func() {
rec := recover()
refute(t, rec, nil)
}()
iType = inject.InterfaceOf((*testing.T)(nil))
}
func Test_InjectorSet(t *testing.T) {
injector := inject.New()
typ := reflect.TypeOf("string")
typSend := reflect.ChanOf(reflect.SendDir, typ)
typRecv := reflect.ChanOf(reflect.RecvDir, typ)
// instantiating unidirectional channels is not possible using reflect
// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
injector.Set(typSend, chanSend)
injector.Set(typRecv, chanRecv)
expect(t, injector.Get(typSend).IsValid(), true)
expect(t, injector.Get(typRecv).IsValid(), true)
expect(t, injector.Get(chanSend.Type()).IsValid(), false)
}
func Test_InjectorGet(t *testing.T) {
injector := inject.New()
injector.Map("some dependency")
expect(t, injector.Get(reflect.TypeOf("string")).IsValid(), true)
expect(t, injector.Get(reflect.TypeOf(11)).IsValid(), false)
}
func Test_InjectorSetParent(t *testing.T) {
injector := inject.New()
injector.MapTo("another dep", (*SpecialString)(nil))
injector2 := inject.New()
injector2.SetParent(injector)
expect(t, injector2.Get(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true)
}
func TestInjectImplementors(t *testing.T) {
injector := inject.New()
g := &Greeter{"Jeremy"}
injector.Map(g)
expect(t, injector.Get(inject.InterfaceOf((*fmt.Stringer)(nil))).IsValid(), true)
}

@ -0,0 +1,85 @@
# inject
--
import "github.com/codegangsta/inject"
inject包提供了多种对实体的映射和依赖注入方式。
## 用法
#### func InterfaceOf
```go
func InterfaceOf(value interface{}) reflect.Type
```
函数InterfaceOf返回指向接口类型的指针。如果传入的value值不是指向接口的指针将抛出一个panic异常。
#### type Applicator
```go
type Applicator interface {
// 在Type map中维持对结构体中每个域的引用并用'inject'来标记
// 如果注入失败将会返回一个error.
Apply(interface{}) error
}
```
Applicator接口表示到结构体的依赖映射关系。
#### type Injector
```go
type Injector interface {
Applicator
Invoker
TypeMapper
// SetParent用来设置父injector. 如果在当前injector的Type map中找不到依赖
// 将会继续从它的父injector中找直到返回error.
SetParent(Injector)
}
```
Injector接口表示对结构体、函数参数的映射和依赖注入。
#### func New
```go
func New() Injector
```
New创建并返回一个Injector.
#### type Invoker
```go
type Invoker interface {
// Invoke尝试将interface{}作为一个函数来调用并基于Type为函数提供参数。
// 它将返回reflect.Value的切片其中存放原函数的返回值。
// 如果注入失败则返回error.
Invoke(interface{}) ([]reflect.Value, error)
}
```
Invoker接口表示通过反射进行函数调用。
#### type TypeMapper
```go
type TypeMapper interface {
// 基于调用reflect.TypeOf得到的类型映射interface{}的值。
Map(interface{}) TypeMapper
// 基于提供的接口的指针映射interface{}的值。
// 该函数仅用来将一个值映射为接口,因为接口无法不通过指针而直接引用到。
MapTo(interface{}, interface{}) TypeMapper
// 为直接插入基于类型和值的map提供一种可能性。
// 它使得这一类直接映射成为可能:无法通过反射直接实例化的类型参数,如单向管道。
Set(reflect.Type, reflect.Value) TypeMapper
// 返回映射到当前类型的Value. 如果Type没被映射将返回对应的零值。
Get(reflect.Type) reflect.Value
}
```
TypeMapper接口用来表示基于类型到接口值的映射。
## 译者
张强 (qqbunny@yeah.net)

@ -0,0 +1,3 @@
#!/bin/bash
go get github.com/robertkrimen/godocdown/godocdown
godocdown > README.md

@ -12,6 +12,7 @@ import (
"time"
"github.com/codegangsta/cli"
"github.com/codegangsta/inject"
pb "github.com/codeskyblue/gosuv/gosuvpb"
"github.com/franela/goreq"
"github.com/golang/protobuf/proto"
@ -32,42 +33,55 @@ func MkdirIfNoExists(dir string) error {
return nil
}
func wrapAction(f func(*cli.Context)) func(*cli.Context) {
return func(c *cli.Context) {
// check if server alive
_, err := goreq.Request{
Method: "GET",
Uri: buildURI(c, "/api/version"),
}.Do()
if err != nil {
go exec.Command(os.Args[0], "serv").Run()
time.Sleep(time.Millisecond * 500)
func init() {
log.SetOutputLevel(log.Ldebug)
}
func connect(ctx *cli.Context) (cc *grpc.ClientConn, err error) {
sockPath := filepath.Join(GOSUV_HOME, "gosuv.sock")
conn, err := grpcDial("unix", sockPath)
return conn, err
}
func testConnection(network, address string) error {
log.Debugf("test connection")
testconn, err := net.DialTimeout(network, address, time.Millisecond*100)
if err != nil {
log.Debugf("start run server")
cmd := exec.Command(os.Args[0], "serv")
timeout := time.Millisecond * 500
er := <-GoTimeoutFunc(timeout, cmd.Run)
if er == ErrGoTimeout {
fmt.Println("server started")
} else {
return fmt.Errorf("server stared failed, %v", er)
}
f(c)
} else {
testconn.Close()
}
return nil
}
func wrapPbProgramAction(f func(*cli.Context, pb.ProgramClient)) func(*cli.Context) {
func wrap(f interface{}) func(*cli.Context) {
return func(ctx *cli.Context) {
conn, err := connect(ctx)
if err != nil {
sockPath := filepath.Join(GOSUV_HOME, "gosuv.sock")
if err := testConnection("unix", sockPath); err != nil {
log.Fatal(err)
}
defer conn.Close()
client := pb.NewProgramClient(conn)
f(ctx, client)
}
}
func wrapPbServerAction(f func(*cli.Context, pb.GoSuvClient)) func(*cli.Context) {
return func(ctx *cli.Context) {
conn, err := connect(ctx)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := pb.NewGoSuvClient(conn)
f(ctx, client)
programClient := pb.NewProgramClient(conn)
gosuvClient := pb.NewGoSuvClient(conn)
inj := inject.New()
inj.Map(programClient)
inj.Map(gosuvClient)
inj.Map(ctx)
inj.Invoke(f)
}
}
@ -190,12 +204,6 @@ func grpcDial(network, addr string) (*grpc.ClientConn, error) {
}))
}
func connect(ctx *cli.Context) (cc *grpc.ClientConn, err error) {
sockPath := filepath.Join(GOSUV_HOME, "gosuv.sock")
conn, err := grpcDial("unix", sockPath)
return conn, err
}
func ShutdownAction(ctx *cli.Context, client pb.GoSuvClient) {
res, err := client.Shutdown(context.Background(), &pb.NopRequest{})
if err != nil {
@ -234,13 +242,13 @@ func initCli() {
{
Name: "version",
Usage: "Show version",
Action: wrapPbServerAction(VersionAction),
Action: wrap(VersionAction),
},
{
Name: "status",
Aliases: []string{"st"},
Usage: "show program status",
Action: wrapAction(StatusAction),
Action: wrap(StatusAction),
},
{
Name: "add",
@ -255,22 +263,22 @@ func initCli() {
Usage: "Specify environ",
},
},
Action: wrapAction(AddAction),
Action: wrap(AddAction),
},
{
Name: "start",
Usage: "start a not running program",
Action: wrapAction(StartAction),
Action: wrap(StartAction),
},
{
Name: "stop",
Usage: "Stop running program",
Action: wrapAction(StopAction),
Action: wrap(StopAction),
},
{
Name: "shutdown",
Usage: "Shutdown server",
Action: wrapPbServerAction(ShutdownAction),
Action: wrap(ShutdownAction),
},
{
Name: "serv",
@ -286,9 +294,6 @@ func initCli() {
if !finfo.IsDir() {
continue
}
//modeExec := os.FileMode(0500)
//if strings.HasPrefix(finfo.Name(), "gosuv-") && (finfo.Mode()&modeExec) == modeExec {
//cmdName := string(finfo.Name()[6:])
cmdName := finfo.Name()
app.Commands = append(app.Commands, cli.Command{
Name: cmdName,

@ -14,6 +14,7 @@ It has these top-level messages:
NopRequest
Response
Request
StatusResponse
*/
package gosuvpb
@ -119,6 +120,38 @@ func (m *Request) GetName() string {
return ""
}
type StatusResponse struct {
Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
Status *string `protobuf:"bytes,2,req,name=status" json:"status,omitempty"`
Extra *string `protobuf:"bytes,3,opt,name=extra" json:"extra,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *StatusResponse) Reset() { *m = StatusResponse{} }
func (m *StatusResponse) String() string { return proto.CompactTextString(m) }
func (*StatusResponse) ProtoMessage() {}
func (m *StatusResponse) GetName() string {
if m != nil && m.Name != nil {
return *m.Name
}
return ""
}
func (m *StatusResponse) GetStatus() string {
if m != nil && m.Status != nil {
return *m.Status
}
return ""
}
func (m *StatusResponse) GetExtra() string {
if m != nil && m.Extra != nil {
return *m.Extra
}
return ""
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
@ -129,6 +162,7 @@ type GoSuvClient interface {
Control(ctx context.Context, in *CtrlRequest, opts ...grpc.CallOption) (*CtrlResponse, error)
Shutdown(ctx context.Context, in *NopRequest, opts ...grpc.CallOption) (*Response, error)
Version(ctx context.Context, in *NopRequest, opts ...grpc.CallOption) (*Response, error)
Status(ctx context.Context, in *NopRequest, opts ...grpc.CallOption) (*StatusResponse, error)
}
type goSuvClient struct {
@ -166,12 +200,22 @@ func (c *goSuvClient) Version(ctx context.Context, in *NopRequest, opts ...grpc.
return out, nil
}
func (c *goSuvClient) Status(ctx context.Context, in *NopRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
out := new(StatusResponse)
err := grpc.Invoke(ctx, "/gosuvpb.GoSuv/Status", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for GoSuv service
type GoSuvServer interface {
Control(context.Context, *CtrlRequest) (*CtrlResponse, error)
Shutdown(context.Context, *NopRequest) (*Response, error)
Version(context.Context, *NopRequest) (*Response, error)
Status(context.Context, *NopRequest) (*StatusResponse, error)
}
func RegisterGoSuvServer(s *grpc.Server, srv GoSuvServer) {
@ -214,6 +258,18 @@ func _GoSuv_Version_Handler(srv interface{}, ctx context.Context, codec grpc.Cod
return out, nil
}
func _GoSuv_Status_Handler(srv interface{}, ctx context.Context, codec grpc.Codec, buf []byte) (interface{}, error) {
in := new(NopRequest)
if err := codec.Unmarshal(buf, in); err != nil {
return nil, err
}
out, err := srv.(GoSuvServer).Status(ctx, in)
if err != nil {
return nil, err
}
return out, nil
}
var _GoSuv_serviceDesc = grpc.ServiceDesc{
ServiceName: "gosuvpb.GoSuv",
HandlerType: (*GoSuvServer)(nil),
@ -230,6 +286,10 @@ var _GoSuv_serviceDesc = grpc.ServiceDesc{
MethodName: "Version",
Handler: _GoSuv_Version_Handler,
},
{
MethodName: "Status",
Handler: _GoSuv_Status_Handler,
},
},
Streams: []grpc.StreamDesc{},
}

@ -21,13 +21,20 @@ message Request {
required string name = 1;
}
message StatusResponse {
required string name = 1;
required string status = 2;
optional string extra = 3;
}
service GoSuv {
rpc Control(CtrlRequest) returns (CtrlResponse) {};
rpc Shutdown(NopRequest) returns (Response) {};
rpc Version(NopRequest) returns (Response) {};
rpc Status(NopRequest) returns (StatusResponse) {};
}
service Program {
rpc Start(Request) returns (Response) {};
rpc Stop(Request) returns (Response) {};
}
}

@ -16,6 +16,8 @@ import (
"github.com/qiniu/log"
)
var ErrGoTimeout = errors.New("GoTimeoutFunc")
func GoFunc(f func() error) chan error {
ch := make(chan error)
go func() {
@ -24,6 +26,21 @@ func GoFunc(f func() error) chan error {
return ch
}
func GoTimeoutFunc(timeout time.Duration, f func() error) chan error {
ch := make(chan error)
go func() {
var err error
select {
case err = <-GoFunc(f):
ch <- err
case <-time.After(timeout):
log.Debugf("timeout: %v", f)
ch <- ErrGoTimeout
}
}()
return ch
}
const (
ST_STANDBY = "STANDBY"
ST_RUNNING = "RUNNING"

@ -63,3 +63,7 @@ func (s *PbSuvServer) Version(ctx context.Context, in *pb.NopRequest) (res *pb.R
}
return
}
func (s *PbSuvServer) Status(ctx context.Context, in *pb.NopRequest) (res *pb.StatusResponse, err error) {
return
}

Loading…
Cancel
Save