// getBroker gets or creates a broker association and returns the broker // the first time it also starts a goroutine that receives downlink from the broker func (r *router) getBroker(brokerAnnouncement *pb_discovery.Announcement) (*broker, error) { // We're going to be optimistic and guess that the broker is already active r.brokersLock.RLock() brk, ok := r.brokers[brokerAnnouncement.Id] r.brokersLock.RUnlock() if ok { return brk, nil } // If it doesn't we still have to lock r.brokersLock.Lock() defer r.brokersLock.Unlock() if _, ok := r.brokers[brokerAnnouncement.Id]; !ok { // Connect to the server // TODO(htdvisser): This is blocking conn, err := brokerAnnouncement.Dial() if err != nil { return nil, err } client := pb_broker.NewBrokerClient(conn) association := pb_broker.NewMonitoredRouterStream(client, func() context.Context { return r.GetContext("") }) downlink := association.Channel() brk := &broker{ conn: conn, association: association, client: client, uplink: make(chan *pb_broker.UplinkMessage), } go func() { for { select { case message := <-brk.uplink: association.Send(message) case message := <-downlink: go r.HandleDownlink(message) } } }() r.brokers[brokerAnnouncement.Id] = brk } return r.brokers[brokerAnnouncement.Id], nil }
func (d *discoveryServer) Announce(ctx context.Context, announcement *pb.Announcement) (*empty.Empty, error) { claims, err := d.discovery.ValidateTTNAuthContext(ctx) if err != nil { return nil, err } // If not in development mode if d.discovery.Component.Identity.Id != "dev" { if !d.discovery.IsMasterAuthServer(claims.Issuer) { return nil, errPermissionDeniedf("Token issuer %s is not allowed to make changes to the network settings", claims.Issuer) } // Can't announce development components if claims.Subject == "dev" { return nil, errPermissionDeniedf("Can't announce development components to production networks") } } if claims.Subject != announcement.Id { return nil, errPermissionDeniedf("Token subject %s does not correspond with announcement ID %s", claims.Subject, announcement.Id) } if claims.Type != announcement.ServiceName { return nil, errPermissionDeniedf("Token type %s does not correspond with announcement service type %s", claims.Type, announcement.ServiceName) } announcementCopy := *announcement announcement.Metadata = []*pb.Metadata{} // This will be taken from existing announcement err = d.discovery.Announce(&announcementCopy) if err != nil { return nil, err } return &empty.Empty{}, nil }