2015-01-13 23:31:27 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2018-03-03 11:53:52 +00:00
|
|
|
"context"
|
2015-06-12 19:52:27 +01:00
|
|
|
"fmt"
|
2015-12-21 17:18:04 +00:00
|
|
|
"runtime/debug"
|
2017-08-24 18:25:05 +10:00
|
|
|
"sort"
|
2015-06-03 01:25:37 +01:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2016-05-12 23:32:58 +01:00
|
|
|
"time"
|
2015-06-03 01:25:37 +01:00
|
|
|
|
2017-05-11 20:43:42 +01:00
|
|
|
"github.com/micro/go-log"
|
2015-11-20 16:17:33 +00:00
|
|
|
"github.com/micro/go-micro/broker"
|
2015-11-28 11:22:29 +00:00
|
|
|
"github.com/micro/go-micro/codec"
|
2016-01-28 17:55:28 +00:00
|
|
|
"github.com/micro/go-micro/metadata"
|
2015-11-20 16:17:33 +00:00
|
|
|
"github.com/micro/go-micro/registry"
|
|
|
|
"github.com/micro/go-micro/transport"
|
2015-05-23 11:53:40 +01:00
|
|
|
|
2017-01-12 13:20:34 +00:00
|
|
|
"github.com/micro/misc/lib/addr"
|
2015-01-13 23:31:27 +00:00
|
|
|
)
|
|
|
|
|
2015-05-23 17:40:53 +01:00
|
|
|
type rpcServer struct {
|
2015-12-01 23:32:23 +00:00
|
|
|
rpc *server
|
2015-05-26 22:39:48 +01:00
|
|
|
exit chan chan error
|
2015-06-03 01:25:37 +01:00
|
|
|
|
|
|
|
sync.RWMutex
|
2015-12-31 18:11:46 +00:00
|
|
|
opts Options
|
2015-06-12 19:52:27 +01:00
|
|
|
handlers map[string]Handler
|
|
|
|
subscribers map[*subscriber][]broker.Subscriber
|
2016-02-15 22:20:54 +00:00
|
|
|
// used for first registration
|
|
|
|
registered bool
|
2017-05-31 19:21:41 +01:00
|
|
|
// graceful exit
|
|
|
|
wg sync.WaitGroup
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-26 22:39:48 +01:00
|
|
|
func newRpcServer(opts ...Option) Server {
|
2015-12-02 00:47:52 +00:00
|
|
|
options := newOptions(opts...)
|
2015-05-23 17:40:53 +01:00
|
|
|
return &rpcServer{
|
2015-12-02 00:47:52 +00:00
|
|
|
opts: options,
|
|
|
|
rpc: &server{
|
2015-12-31 18:11:46 +00:00
|
|
|
name: options.Name,
|
2015-12-02 21:12:09 +00:00
|
|
|
serviceMap: make(map[string]*service),
|
2015-12-31 18:11:46 +00:00
|
|
|
hdlrWrappers: options.HdlrWrappers,
|
2015-12-02 00:47:52 +00:00
|
|
|
},
|
2015-06-12 19:52:27 +01:00
|
|
|
handlers: make(map[string]Handler),
|
|
|
|
subscribers: make(map[*subscriber][]broker.Subscriber),
|
|
|
|
exit: make(chan chan error),
|
2015-05-23 17:40:53 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-13 23:31:27 +00:00
|
|
|
|
2015-05-23 17:40:53 +01:00
|
|
|
func (s *rpcServer) accept(sock transport.Socket) {
|
2015-12-21 17:18:04 +00:00
|
|
|
defer func() {
|
2016-05-10 10:55:18 +01:00
|
|
|
// close socket
|
|
|
|
sock.Close()
|
|
|
|
|
2015-12-21 17:18:04 +00:00
|
|
|
if r := recover(); r != nil {
|
2017-05-16 19:14:00 +01:00
|
|
|
log.Log("panic recovered: ", r)
|
|
|
|
log.Log(string(debug.Stack()))
|
2015-12-21 17:18:04 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
for {
|
|
|
|
var msg transport.Message
|
|
|
|
if err := sock.Recv(&msg); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2015-01-13 23:31:27 +00:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
// we use this Timeout header to set a server deadline
|
|
|
|
to := msg.Header["Timeout"]
|
|
|
|
// we use this Content-Type header to identify the codec needed
|
|
|
|
ct := msg.Header["Content-Type"]
|
|
|
|
|
|
|
|
cf, err := s.newCodec(ct)
|
|
|
|
// TODO: needs better error handling
|
|
|
|
if err != nil {
|
|
|
|
sock.Send(&transport.Message{
|
|
|
|
Header: map[string]string{
|
|
|
|
"Content-Type": "text/plain",
|
|
|
|
},
|
|
|
|
Body: []byte(err.Error()),
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2015-11-25 19:50:05 +00:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
codec := newRpcPlusCodec(&msg, sock, cf)
|
2015-01-13 23:31:27 +00:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
// strip our headers
|
|
|
|
hdr := make(map[string]string)
|
|
|
|
for k, v := range msg.Header {
|
|
|
|
hdr[k] = v
|
|
|
|
}
|
|
|
|
delete(hdr, "Content-Type")
|
|
|
|
delete(hdr, "Timeout")
|
2015-01-13 23:31:27 +00:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
ctx := metadata.NewContext(context.Background(), hdr)
|
2015-12-02 20:56:50 +00:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
// set the timeout if we have it
|
|
|
|
if len(to) > 0 {
|
|
|
|
if n, err := strconv.ParseUint(to, 10, 64); err == nil {
|
|
|
|
ctx, _ = context.WithTimeout(ctx, time.Duration(n))
|
|
|
|
}
|
2016-05-12 23:32:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-31 19:21:41 +01:00
|
|
|
// add to wait group
|
|
|
|
s.wg.Add(1)
|
2017-06-12 14:18:59 +01:00
|
|
|
defer s.wg.Done()
|
2017-05-31 19:21:41 +01:00
|
|
|
|
2016-05-13 15:58:53 +01:00
|
|
|
// TODO: needs better error handling
|
|
|
|
if err := s.rpc.serveRequest(ctx, codec, ct); err != nil {
|
2017-05-11 20:43:42 +01:00
|
|
|
log.Logf("Unexpected error serving request, closing socket: %v", err)
|
2016-05-13 15:58:53 +01:00
|
|
|
return
|
|
|
|
}
|
2015-11-24 00:52:59 +00:00
|
|
|
}
|
2015-05-20 22:57:19 +01:00
|
|
|
}
|
|
|
|
|
2015-11-28 11:22:29 +00:00
|
|
|
func (s *rpcServer) newCodec(contentType string) (codec.NewCodec, error) {
|
2015-12-31 18:11:46 +00:00
|
|
|
if cf, ok := s.opts.Codecs[contentType]; ok {
|
2015-11-28 11:22:29 +00:00
|
|
|
return cf, nil
|
2015-11-25 19:50:05 +00:00
|
|
|
}
|
|
|
|
if cf, ok := defaultCodecs[contentType]; ok {
|
|
|
|
return cf, nil
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
|
|
|
|
}
|
|
|
|
|
2015-12-31 18:11:46 +00:00
|
|
|
func (s *rpcServer) Options() Options {
|
2015-06-03 01:25:37 +01:00
|
|
|
s.RLock()
|
|
|
|
opts := s.opts
|
|
|
|
s.RUnlock()
|
|
|
|
return opts
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 19:12:17 +00:00
|
|
|
func (s *rpcServer) Init(opts ...Option) error {
|
2015-06-03 01:25:37 +01:00
|
|
|
s.Lock()
|
2015-05-26 22:39:48 +01:00
|
|
|
for _, opt := range opts {
|
|
|
|
opt(&s.opts)
|
|
|
|
}
|
2016-02-18 18:08:43 +00:00
|
|
|
// update internal server
|
|
|
|
s.rpc = &server{
|
|
|
|
name: s.opts.Name,
|
|
|
|
serviceMap: s.rpc.serviceMap,
|
|
|
|
hdlrWrappers: s.opts.HdlrWrappers,
|
|
|
|
}
|
2015-06-03 01:25:37 +01:00
|
|
|
s.Unlock()
|
2016-01-02 19:12:17 +00:00
|
|
|
return nil
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 14:02:32 +00:00
|
|
|
func (s *rpcServer) NewHandler(h interface{}, opts ...HandlerOption) Handler {
|
|
|
|
return newRpcHandler(h, opts...)
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
func (s *rpcServer) Handle(h Handler) error {
|
2016-02-18 18:08:43 +00:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
2015-12-02 01:18:32 +00:00
|
|
|
if err := s.rpc.register(h.Handler()); err != nil {
|
2015-06-03 01:25:37 +01:00
|
|
|
return err
|
|
|
|
}
|
2016-02-18 18:08:43 +00:00
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
s.handlers[h.Name()] = h
|
2016-02-18 18:08:43 +00:00
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
return nil
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 14:02:32 +00:00
|
|
|
func (s *rpcServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
|
|
|
|
return newSubscriber(topic, sb, opts...)
|
2015-06-12 19:52:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *rpcServer) Subscribe(sb Subscriber) error {
|
|
|
|
sub, ok := sb.(*subscriber)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("invalid subscriber: expected *subscriber")
|
|
|
|
}
|
|
|
|
if len(sub.handlers) == 0 {
|
|
|
|
return fmt.Errorf("invalid subscriber: no handler functions")
|
|
|
|
}
|
|
|
|
|
2015-12-02 17:42:14 +00:00
|
|
|
if err := validateSubscriber(sb); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-06-12 19:52:27 +01:00
|
|
|
s.Lock()
|
2018-01-01 19:57:13 +01:00
|
|
|
defer s.Unlock()
|
2015-06-12 19:52:27 +01:00
|
|
|
_, ok = s.subscribers[sub]
|
|
|
|
if ok {
|
|
|
|
return fmt.Errorf("subscriber %v already exists", s)
|
|
|
|
}
|
|
|
|
s.subscribers[sub] = nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-01-27 12:23:18 +00:00
|
|
|
func (s *rpcServer) Register() error {
|
2015-06-03 01:25:37 +01:00
|
|
|
// parse address for host, port
|
2015-12-31 18:11:46 +00:00
|
|
|
config := s.Options()
|
2015-11-11 18:22:04 +00:00
|
|
|
var advt, host string
|
2015-06-03 01:25:37 +01:00
|
|
|
var port int
|
2015-11-04 21:53:39 +00:00
|
|
|
|
2015-11-11 18:22:04 +00:00
|
|
|
// check the advertise address first
|
|
|
|
// if it exists then use it, otherwise
|
|
|
|
// use the address
|
2015-12-31 18:11:46 +00:00
|
|
|
if len(config.Advertise) > 0 {
|
|
|
|
advt = config.Advertise
|
2015-11-11 18:22:04 +00:00
|
|
|
} else {
|
2015-12-31 18:11:46 +00:00
|
|
|
advt = config.Address
|
2015-11-11 18:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parts := strings.Split(advt, ":")
|
2015-06-03 01:25:37 +01:00
|
|
|
if len(parts) > 1 {
|
|
|
|
host = strings.Join(parts[:len(parts)-1], ":")
|
|
|
|
port, _ = strconv.Atoi(parts[len(parts)-1])
|
|
|
|
} else {
|
|
|
|
host = parts[0]
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2017-01-12 13:20:34 +00:00
|
|
|
addr, err := addr.Extract(host)
|
2015-11-04 21:53:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
// register service
|
|
|
|
node := ®istry.Node{
|
2016-01-02 00:38:57 +00:00
|
|
|
Id: config.Name + "-" + config.Id,
|
2015-11-04 21:53:39 +00:00
|
|
|
Address: addr,
|
2015-06-03 01:25:37 +01:00
|
|
|
Port: port,
|
2015-12-31 18:11:46 +00:00
|
|
|
Metadata: config.Metadata,
|
2015-06-03 01:25:37 +01:00
|
|
|
}
|
|
|
|
|
2015-12-31 18:11:46 +00:00
|
|
|
node.Metadata["transport"] = config.Transport.String()
|
2016-01-04 01:27:05 +00:00
|
|
|
node.Metadata["broker"] = config.Broker.String()
|
|
|
|
node.Metadata["server"] = s.String()
|
2016-01-04 23:27:44 +00:00
|
|
|
node.Metadata["registry"] = config.Registry.String()
|
2015-12-19 21:56:14 +00:00
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
s.RLock()
|
2017-08-24 18:25:05 +10:00
|
|
|
// Maps are ordered randomly, sort the keys for consistency
|
|
|
|
var handlerList []string
|
|
|
|
for n, e := range s.handlers {
|
2016-01-08 14:02:32 +00:00
|
|
|
// Only advertise non internal handlers
|
|
|
|
if !e.Options().Internal {
|
2017-08-24 18:25:05 +10:00
|
|
|
handlerList = append(handlerList, n)
|
2016-01-08 14:02:32 +00:00
|
|
|
}
|
2015-06-03 01:25:37 +01:00
|
|
|
}
|
2017-08-24 18:25:05 +10:00
|
|
|
sort.Strings(handlerList)
|
|
|
|
|
|
|
|
var subscriberList []*subscriber
|
|
|
|
for e := range s.subscribers {
|
2016-01-08 14:02:32 +00:00
|
|
|
// Only advertise non internal subscribers
|
|
|
|
if !e.Options().Internal {
|
2017-08-24 18:25:05 +10:00
|
|
|
subscriberList = append(subscriberList, e)
|
2016-01-08 14:02:32 +00:00
|
|
|
}
|
2015-06-12 19:52:27 +01:00
|
|
|
}
|
2017-08-24 18:25:05 +10:00
|
|
|
sort.Slice(subscriberList, func(i, j int) bool {
|
|
|
|
return subscriberList[i].topic > subscriberList[j].topic
|
|
|
|
})
|
|
|
|
|
|
|
|
var endpoints []*registry.Endpoint
|
|
|
|
for _, n := range handlerList {
|
|
|
|
endpoints = append(endpoints, s.handlers[n].Endpoints()...)
|
|
|
|
}
|
|
|
|
for _, e := range subscriberList {
|
|
|
|
endpoints = append(endpoints, e.Endpoints()...)
|
|
|
|
}
|
2015-06-03 01:25:37 +01:00
|
|
|
s.RUnlock()
|
|
|
|
|
|
|
|
service := ®istry.Service{
|
2015-12-31 18:11:46 +00:00
|
|
|
Name: config.Name,
|
|
|
|
Version: config.Version,
|
2015-06-03 01:25:37 +01:00
|
|
|
Nodes: []*registry.Node{node},
|
|
|
|
Endpoints: endpoints,
|
|
|
|
}
|
|
|
|
|
2016-02-27 22:14:25 +00:00
|
|
|
s.Lock()
|
|
|
|
registered := s.registered
|
|
|
|
s.Unlock()
|
|
|
|
|
|
|
|
if !registered {
|
2017-05-11 20:43:42 +01:00
|
|
|
log.Logf("Registering node: %s", node.Id)
|
2016-02-27 22:14:25 +00:00
|
|
|
}
|
|
|
|
|
2016-01-27 12:23:18 +00:00
|
|
|
// create registry options
|
Add option to enable TCP check with Consul registry
One disadvantage of using TTL based health check is the high network
traffic between Consul agent (either between servers, or between server
and client).
In order for the services considered alive by Consul, microservices must
send an update TTL to Consul every n seconds (currently 30 seconds).
Here is the explanation about TTL check from Consul documentation [1]
Time to Live (TTL) - These checks retain their last known state for a
given TTL. The state of the check must be updated periodically over
the HTTP interface. If an external system fails to update the status
within a given TTL, the check is set to the failed state. This
mechanism, conceptually similar to a dead man's switch, relies on the
application to directly report its health. For example, a healthy app
can periodically PUT a status update to the HTTP endpoint; if the app
fails, the TTL will expire and the health check enters a critical
state. The endpoints used to update health information for a given
check are the pass endpoint and the fail endpoint. TTL checks also
persist their last known status to disk. This allows the Consul agent
to restore the last known status of the check across restarts.
Persisted check status is valid through the end of the TTL from the
time of the last check.
Hint:
TTL checks also persist their last known status to disk. This allows
the Consul agent to restore the last known status of the check
across restarts.
When microservices update the TTL, Consul will write to disk. Writing to
disk means all other slaves need to replicate it, which means master need
to inform other standby Consul to pull the new catalog. Hence, the
increased traffic.
More information about this issue can be viewed at Consul mailing list [2].
[1] https://www.consul.io/docs/agent/checks.html
[2] https://groups.google.com/forum/#!topic/consul-tool/84h7qmCCpjg
2018-03-14 18:51:38 +07:00
|
|
|
rOpts := []registry.RegisterOption{
|
|
|
|
registry.RegisterTTL(config.RegisterTTL),
|
|
|
|
registry.RegisterTCPCheck(config.RegisterInterval),
|
|
|
|
}
|
2016-01-27 12:23:18 +00:00
|
|
|
|
2016-01-26 23:32:27 +00:00
|
|
|
if err := config.Registry.Register(service, rOpts...); err != nil {
|
2015-06-12 19:52:27 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-02-27 22:14:25 +00:00
|
|
|
// already registered? don't need to register subscribers
|
|
|
|
if registered {
|
2016-02-15 22:20:54 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-02-27 22:14:25 +00:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
2016-02-15 22:20:54 +00:00
|
|
|
s.registered = true
|
|
|
|
|
2015-06-12 19:52:27 +01:00
|
|
|
for sb, _ := range s.subscribers {
|
2015-12-02 19:56:57 +00:00
|
|
|
handler := s.createSubHandler(sb, s.opts)
|
2016-01-22 21:48:43 +00:00
|
|
|
var opts []broker.SubscribeOption
|
|
|
|
if queue := sb.Options().Queue; len(queue) > 0 {
|
2016-05-10 10:55:18 +01:00
|
|
|
opts = append(opts, broker.Queue(queue))
|
2016-01-22 21:48:43 +00:00
|
|
|
}
|
|
|
|
sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
|
2015-06-12 19:52:27 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.subscribers[sb] = []broker.Subscriber{sub}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-06-03 01:25:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *rpcServer) Deregister() error {
|
2015-12-31 18:11:46 +00:00
|
|
|
config := s.Options()
|
2015-11-11 18:22:04 +00:00
|
|
|
var advt, host string
|
2015-06-03 01:25:37 +01:00
|
|
|
var port int
|
2015-11-11 18:22:04 +00:00
|
|
|
|
|
|
|
// check the advertise address first
|
|
|
|
// if it exists then use it, otherwise
|
|
|
|
// use the address
|
2015-12-31 18:11:46 +00:00
|
|
|
if len(config.Advertise) > 0 {
|
|
|
|
advt = config.Advertise
|
2015-11-11 18:22:04 +00:00
|
|
|
} else {
|
2015-12-31 18:11:46 +00:00
|
|
|
advt = config.Address
|
2015-11-11 18:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parts := strings.Split(advt, ":")
|
2015-06-03 01:25:37 +01:00
|
|
|
if len(parts) > 1 {
|
|
|
|
host = strings.Join(parts[:len(parts)-1], ":")
|
|
|
|
port, _ = strconv.Atoi(parts[len(parts)-1])
|
|
|
|
} else {
|
|
|
|
host = parts[0]
|
|
|
|
}
|
|
|
|
|
2017-01-12 13:20:34 +00:00
|
|
|
addr, err := addr.Extract(host)
|
2015-11-04 21:53:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-06-03 01:25:37 +01:00
|
|
|
node := ®istry.Node{
|
2016-01-02 00:38:57 +00:00
|
|
|
Id: config.Name + "-" + config.Id,
|
2015-11-04 21:53:39 +00:00
|
|
|
Address: addr,
|
2015-06-03 01:25:37 +01:00
|
|
|
Port: port,
|
|
|
|
}
|
|
|
|
|
|
|
|
service := ®istry.Service{
|
2015-12-31 18:11:46 +00:00
|
|
|
Name: config.Name,
|
|
|
|
Version: config.Version,
|
2015-06-03 01:25:37 +01:00
|
|
|
Nodes: []*registry.Node{node},
|
|
|
|
}
|
|
|
|
|
2017-05-11 20:43:42 +01:00
|
|
|
log.Logf("Deregistering node: %s", node.Id)
|
2015-12-31 18:11:46 +00:00
|
|
|
if err := config.Registry.Deregister(service); err != nil {
|
2015-06-12 19:52:27 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Lock()
|
2016-02-15 22:20:54 +00:00
|
|
|
|
|
|
|
if !s.registered {
|
|
|
|
s.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
s.registered = false
|
|
|
|
|
2015-06-12 19:52:27 +01:00
|
|
|
for sb, subs := range s.subscribers {
|
|
|
|
for _, sub := range subs {
|
2017-05-11 20:43:42 +01:00
|
|
|
log.Logf("Unsubscribing from topic: %s", sub.Topic())
|
2015-06-12 19:52:27 +01:00
|
|
|
sub.Unsubscribe()
|
|
|
|
}
|
|
|
|
s.subscribers[sb] = nil
|
|
|
|
}
|
2016-02-15 22:20:54 +00:00
|
|
|
|
2015-06-12 19:52:27 +01:00
|
|
|
s.Unlock()
|
|
|
|
return nil
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 17:40:53 +01:00
|
|
|
func (s *rpcServer) Start() error {
|
2016-01-06 19:24:54 +00:00
|
|
|
registerDebugHandler(s)
|
2015-12-31 18:11:46 +00:00
|
|
|
config := s.Options()
|
2015-01-13 23:31:27 +00:00
|
|
|
|
2015-12-31 18:11:46 +00:00
|
|
|
ts, err := config.Transport.Listen(config.Address)
|
2015-01-13 23:31:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-05-11 20:43:42 +01:00
|
|
|
log.Logf("Listening on %s", ts.Addr())
|
2015-06-03 01:25:37 +01:00
|
|
|
s.Lock()
|
2015-12-31 18:11:46 +00:00
|
|
|
s.opts.Address = ts.Addr()
|
2015-06-03 01:25:37 +01:00
|
|
|
s.Unlock()
|
2015-05-16 00:34:02 +01:00
|
|
|
|
2015-05-21 21:08:19 +01:00
|
|
|
go ts.Accept(s.accept)
|
2015-01-13 23:31:27 +00:00
|
|
|
|
|
|
|
go func() {
|
2017-05-31 19:21:41 +01:00
|
|
|
// wait for exit
|
2015-01-13 23:31:27 +00:00
|
|
|
ch := <-s.exit
|
2017-05-31 19:21:41 +01:00
|
|
|
|
|
|
|
// wait for requests to finish
|
|
|
|
if wait(s.opts.Context) {
|
|
|
|
s.wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
// close transport listener
|
2015-05-20 22:57:19 +01:00
|
|
|
ch <- ts.Close()
|
2017-05-31 19:21:41 +01:00
|
|
|
|
|
|
|
// disconnect the broker
|
2015-12-31 18:11:46 +00:00
|
|
|
config.Broker.Disconnect()
|
2015-01-13 23:31:27 +00:00
|
|
|
}()
|
|
|
|
|
2015-06-12 19:52:27 +01:00
|
|
|
// TODO: subscribe to cruft
|
2015-12-31 18:11:46 +00:00
|
|
|
return config.Broker.Connect()
|
2015-01-13 23:31:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 17:40:53 +01:00
|
|
|
func (s *rpcServer) Stop() error {
|
2015-01-13 23:31:27 +00:00
|
|
|
ch := make(chan error)
|
|
|
|
s.exit <- ch
|
|
|
|
return <-ch
|
|
|
|
}
|
2015-12-19 21:56:14 +00:00
|
|
|
|
|
|
|
func (s *rpcServer) String() string {
|
|
|
|
return "rpc"
|
|
|
|
}
|