| /* | 
 | Copyright 2017 Google Inc. | 
 |  | 
 | Licensed under the Apache License, Version 2.0 (the "License"); | 
 | you may not use this file except in compliance with the License. | 
 | You may obtain a copy of the License at | 
 |  | 
 |     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  | 
 | Unless required by applicable law or agreed to in writing, software | 
 | distributed under the License is distributed on an "AS IS" BASIS, | 
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | See the License for the specific language governing permissions and | 
 | limitations under the License. | 
 | */ | 
 |  | 
 | package adapter | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"net/http" | 
 | 	"sync" | 
 | 	"time" | 
 |  | 
 | 	"github.com/apid/istioApigeeAdapter/common" | 
 | ) | 
 |  | 
 | const ( | 
 | 	defaultProductsFetch = time.Minute | 
 | ) | 
 |  | 
 | type productManager struct { | 
 | 	fetchURL   string | 
 | 	products   map[string]*common.APIProduct | 
 | 	refresh    time.Duration | 
 | 	expiration time.Time | 
 | 	latch      *sync.Mutex | 
 | } | 
 |  | 
 | func newProductManager(fetchURL string, refreshTime time.Duration) *productManager { | 
 | 	return &productManager{ | 
 | 		fetchURL: fetchURL, | 
 | 		refresh:  refreshTime, | 
 | 		latch:    &sync.Mutex{}, | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 | getProducts returns the products that match a list of names. For now it is simple -- we will | 
 | use a mutex and update the list when it's expired. In the future we can be fancier with | 
 | periodic refresh. | 
 | */ | 
 | func (m *productManager) getProducts(names []string) ([]common.APIProduct, error) { | 
 | 	m.latch.Lock() | 
 | 	defer m.latch.Unlock() | 
 |  | 
 | 	if m.products == nil || m.expiration.Before(time.Now()) { | 
 | 		err := m.fetchProductList() | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 	} | 
 |  | 
 | 	var products []common.APIProduct | 
 | 	for _, name := range names { | 
 | 		p := m.products[name] | 
 | 		if p != nil { | 
 | 			products = append(products, *p) | 
 | 		} | 
 | 	} | 
 | 	return products, nil | 
 | } | 
 |  | 
 | func (m *productManager) fetchProductList() error { | 
 | 	resp, err := http.Get(m.fetchURL) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	defer resp.Body.Close() | 
 | 	if resp.StatusCode != 200 { | 
 | 		return fmt.Errorf("HTTP error %d fetching API product list", resp.StatusCode) | 
 | 	} | 
 |  | 
 | 	var pl common.APIProductResponse | 
 | 	jr := json.NewDecoder(resp.Body) | 
 | 	err = jr.Decode(&pl) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	m.products = make(map[string]*common.APIProduct) | 
 | 	for _, p := range pl.Products { | 
 | 		m.products[p.Name] = &p | 
 | 	} | 
 | 	m.expiration = time.Now().Add(m.refresh) | 
 | 	return nil | 
 | } |