blob: 9e9a73a016a76325b42cec19acedd936b159064d [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 advertisement. It uses
// the server's endpoints and the given suffix as the advertisement addresses,
// and the addresses will be updated automatically when the underlying network
// are changed.
//
// The advertisement should not be changed while it is being advertised.
//
// Advertising will continue until the context is canceled or exceeds its deadline
// and the returned channel will be closed when it stops.
//
// If a discovery instance is not provided, this will create a new one.
func AdvertiseServer(ctx *context.T, d discovery.T, server rpc.Server, suffix string, ad *discovery.Advertisement, visibility []security.BlessingPattern) (<-chan struct{}, error) {
if d == nil {
var err error
d, err = v23.NewDiscovery(ctx)
if err != nil {
return nil, err
}
}
status := server.Status()
curAddrs := sortedNames(status.Endpoints)
stop, err := advertiseServer(ctx, d, ad, curAddrs, suffix, visibility)
if err != nil {
stop()
return nil, err
}
done := make(chan struct{})
go func() {
defer close(done)
for {
select {
case <-status.Dirty:
status = server.Status()
if status.State != rpc.ServerActive {
stop()
return
}
newAddrs := sortedNames(status.Endpoints)
if sortedStringsEqual(curAddrs, newAddrs) {
continue
}
stop() // Stop the previous advertisement.
stop, err = advertiseServer(ctx, d, ad, newAddrs, suffix, visibility)
if err != nil {
stop()
ctx.Error(err)
return
}
curAddrs = newAddrs
case <-ctx.Done():
stop()
return
}
}
}()
return done, nil
}
func advertiseServer(ctx *context.T, d discovery.T, ad *discovery.Advertisement, addrs []string, suffix string, visibility []security.BlessingPattern) (func(), error) {
ad.Addresses = make([]string, len(addrs))
for i, addr := range addrs {
ad.Addresses[i] = naming.JoinAddressName(addr, suffix)
}
ctx, cancel := context.WithCancel(ctx)
done, err := d.Advertise(ctx, ad, visibility)
if err != nil {
cancel()
return nil, err
}
stop := func() {
cancel()
<-done
}
return stop, nil
}