// watcher for data change in etcd directory func (p *service_pool) watcher() { client := p.client_pool.Get().(*etcd.Client) defer func() { p.client_pool.Put(client) }() for { ch := make(chan *etcd.Response, 10) go func() { for { if resp, ok := <-ch; ok { if resp.Node.Dir { continue } key, value := resp.Node.Key, resp.Node.Value if value == "" { log.Tracef("node delete: %v", key) p.remove_service(key) } else { log.Tracef("node add: %v %v", key, value) p.add_service(key, value) } } else { return } } }() _, err := client.Watch(DEFAULT_SERVICE_PATH, 0, true, ch, nil) if err != nil { log.Critical(err) } <-time.After(RETRY_DELAY) } }
// add a service func (p *service_pool) add_service(key, value string) { p.Lock() defer p.Unlock() service_name := filepath.Dir(key) if p.services[service_name] == nil { p.services[service_name] = &service{} log.Tracef("new service type: %v", service_name) } service := p.services[service_name] if conn, err := grpc.Dial(value, grpc.WithTimeout(DEFAULT_DIAL_TIMEOUT)); err == nil { service.clients = append(service.clients, client{key, conn}) log.Tracef("service added: %v -- %v", key, value) } else { log.Errorf("did not connect: %v -- %v err: %v", key, value, err) } }
// remove a service func (p *service_pool) remove_service(key string) { p.Lock() defer p.Unlock() service_name := filepath.Dir(key) service := p.services[service_name] if service == nil { log.Tracef("no such service %v", service_name) return } for k := range service.clients { if service.clients[k].key == key { // deletion service.clients = append(service.clients[:k], service.clients[k+1:]...) log.Tracef("service removed %v", key) return } } }
// subscribe to an endpoint & receive server streams func (s *server) Subscribe(p *Chat_Id, stream ChatService_SubscribeServer) error { // read endpoint ep := s.read_ep(p.Id) if ep == nil { log.Errorf("cannot find endpoint %v", p) return ERROR_NOT_EXISTS } // send history chat messages msgs := ep.Read() for k := range msgs { if err := stream.Send(&msgs[k]); err != nil { return nil } } // create subscriber e := make(chan error, 1) var once sync.Once f := NewSubscriber(func(msg *Chat_Message) { if err := stream.Send(msg); err != nil { once.Do(func() { // protect for channel blocking e <- err }) } }) // subscribe to the endpoint log.Tracef("subscribe to:%v", p.Id) ep.ps.Sub(f) defer func() { ep.ps.Leave(f) log.Tracef("leave from:%v", p.Id) }() // client send cancel to stop receiving, see service_test.go for example select { case <-stream.Context().Done(): case <-e: log.Error(e) } return nil }
// add a service func (p *service_pool) add_service(key, value string) { p.Lock() defer p.Unlock() service_name := filepath.Dir(key) // name check if p.enable_name_check && !p.service_names[service_name] { log.Warningf("service not in names: %v, ignored", service_name) return } if p.services[service_name] == nil { p.services[service_name] = &service{} log.Tracef("new service type: %v", service_name) } service := p.services[service_name] if conn, err := grpc.Dial(value, grpc.WithTimeout(DEFAULT_DIAL_TIMEOUT), grpc.WithInsecure()); err == nil { service.clients = append(service.clients, client{key, conn}) log.Tracef("service added: %v -- %v", key, value) } else { log.Errorf("did not connect: %v -- %v err: %v", key, value, err) } }