blob: a65b907b83b8b5c46f48e5a7312b7f5476f09430 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 discovery
import (
"v.io/v23"
"v.io/v23/context"
"v.io/v23/discovery"
"v.io/v23/naming"
"v.io/v23/rpc"
"v.io/v23/security"
)
// AdvertiseServer advertises the server with the given service. It uses the
// server's endpoints and the given suffix as the service addresses, and the
// addresses will be updated automatically when the underlying network are
// changed. Advertising will continue until the context is canceled or exceeds
// its deadline and the returned channel will be closed when it stops.
func AdvertiseServer(ctx *context.T, server rpc.Server, suffix string, service *discovery.Service, visibility []security.BlessingPattern) (<-chan struct{}, error) {
// Take a copy of the service to avoid any interference from changes in user side.
copiedService := copyService(service)
eps, valid := getEndpoints(server)
stop, err := advertiseServer(ctx, &copiedService, eps, suffix, visibility)
if err != nil {
return nil, err
}
// Copy back the instance id.
service.InstanceId = copiedService.InstanceId
done := make(chan struct{})
go func() {
for {
select {
case <-valid:
if stop != nil {
stop() // Stop the previous advertisement.
}
eps, valid = getEndpoints(server)
stop, err = advertiseServer(ctx, &copiedService, eps, suffix, visibility)
if err != nil {
ctx.Error(err)
}
case <-ctx.Done():
close(done)
return
}
}
}()
return done, nil
}
func advertiseServer(ctx *context.T, service *discovery.Service, eps []naming.Endpoint, suffix string, visibility []security.BlessingPattern) (func(), error) {
service.Addrs = make([]string, len(eps))
for i, ep := range eps {
service.Addrs[i] = naming.JoinAddressName(ep.Name(), suffix)
}
ds := v23.GetDiscovery(ctx)
ctx, cancel := context.WithCancel(ctx)
done, err := ds.Advertise(ctx, service, visibility)
if err != nil {
cancel()
return nil, err
}
stop := func() {
cancel()
<-done
}
return stop, nil
}
func getEndpoints(server rpc.Server) ([]naming.Endpoint, <-chan struct{}) {
status := server.Status()
return status.Endpoints, status.Valid
}