<commit_before>package management

import (
	"fmt"
)

type Linkable interface {
	Link() map[string]map[string]interface{}
}

type EntryFields map[string]map[string]interface{}

type NewEntry struct {
	Fields EntryFields `json:"fields"`
}

// Validate validates the entry
func (c *NewEntry) Validate() error {
	if c.Fields == nil || len(c.Fields) == 0 {
		return fmt.Errorf("NewEntry.Fields cannot be empty!")
	}

	return nil
}

// Entry represent textual content in a space. An entry's data adheres to a
// certain content type.
type Entry struct {
	System `json:"sys"`
	Fields EntryFields `json:"fields"`
}

// Validate will validate the entry. An error is returned if the entry
// is not  valid.
func (c *Entry) Validate() error {
	if c.Space == nil || c.Space.ID == "" {
		return fmt.Errorf("Entry must have a valid Space associated with it!")
	}

	if c.System.ID == "" {
		return fmt.Errorf("Entry.System.ID cannot be empty!")
	}

	if c.Fields == nil || len(c.Fields) == 0 {
		return fmt.Errorf("Entry.Fields cannot be empty!")
	}

	return nil
}

// Link represents a link to the Entry and implements the Linkable interface
func (c *Entry) Link() map[string]map[string]interface{} {
	return map[string]map[string]interface{}{
		"sys": map[string]interface{}{
			"id":       c.ID,
			"linkType": "Entry",
			"type":     LinkType,
		},
	}
}

// QueryEntries returns all entries for the given space and parameters.
func (c *Client) QueryEntries(spaceID string, params map[string]string, limit int, offset int) (entries []*Entry, pagination *Pagination, err error) {
	if spaceID == "" {
		return nil, nil, fmt.Errorf("FetchEntries failed. Space identifier is not valid!")
	}

	if limit < 0 {
		return nil, nil, fmt.Errorf("FetchEntries failed. Limit must be greater than 0")
	}

	if limit > 100 {
		limit = 100
	}

	c.rl.Wait()

	type entriesResponse struct {
		*Pagination
		Items []*Entry `json:"items"`
	}

	results := new(entriesResponse)
	results.Items = []*Entry{}
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries", spaceID)
	req, err := c.sling.New().
		Get(path).
		Request()

	if err != nil {
		return
	}

	// Add query parameters
	q := req.URL.Query()
	for k, v := range params {
		q.Set(k, v)
	}

	q.Set("skip", fmt.Sprintf("%v", offset))
	q.Set("limit", fmt.Sprintf("%v", limit))
	req.URL.RawQuery = q.Encode()

	// Perform request
	_, err = c.sling.Do(req, results, contentfulError)

	return results.Items, results.Pagination, handleError(err, contentfulError)
}

// FetchEntry returns a single entry for the given space and entry identifier
func (c *Client) FetchEntry(spaceID string, entryID string) (entry *Entry, err error) {
	if spaceID == "" || entryID == "" {
		err = fmt.Errorf("FetchContentType failed. Invalid spaceID or contentTypeID.")
		return
	}

	c.rl.Wait()

	entry = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", spaceID, entryID)
	_, err = c.sling.New().Get(path).Receive(entry, contentfulError)

	return entry, handleError(err, contentfulError)
}

// CreateEntry will create a new entry with an ID specified by the user or
// generated by the system
func (c *Client) CreateEntry(entry *NewEntry, contentType *ContentType) (created *Entry, err error) {
	if entry == nil || contentType == nil {
		err = fmt.Errorf("CreateEntry failed, entry and contentType cannot be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	if err = contentType.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	created = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries", contentType.Space.ID)
	_, err = c.sling.New().
		Post(path).
		Set("X-Contentful-Content-Type", contentType.ID).
		BodyJSON(entry).
		Receive(created, contentfulError)

	return created, handleError(err, contentfulError)
}

// UpdateEntry will update the specified entry with any changes that you have
// made.
func (c *Client) UpdateEntry(entry *Entry) (updated *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("CreateEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	updated = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Set("X-Contentful-Version", fmt.Sprintf("%v", entry.System.Version)).
		BodyJSON(entry).
		Receive(updated, contentfulError)

	return updated, handleError(err, contentfulError)
}

// DeleteEntry will delete the specified entry
func (c *Client) DeleteEntry(entryID string, spaceID string) (err error) {

	c.rl.Wait()

	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", spaceID, entryID)
	_, err = c.sling.New().
		Delete(path).
		Receive(nil, contentfulError)

	return handleError(err, contentfulError)
}

// PublishEntry makes the entry available via the Content Delivery API
func (c *Client) PublishEntry(entry *Entry) (published *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("PublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	published = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/published", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Set("X-Contentful-Version", fmt.Sprintf("%v", entry.System.Version)).
		Receive(published, contentfulError)

	return published, handleError(err, contentfulError)
}

// UnpublishEntry makes the entry unavailable via the Content Delivery API
func (c *Client) UnpublishEntry(entry *Entry) (unpublished *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("UnpublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	unpublished = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/published", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Delete(path).
		Receive(unpublished, contentfulError)

	return unpublished, handleError(err, contentfulError)
}

// ArchiveEntry will archive the specified entry. An entry can only be archived
// when it's not published.
func (c *Client) ArchiveEntry(entry *Entry) (archived *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("PublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	archived = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/archived", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Receive(archived, contentfulError)

	return archived, handleError(err, contentfulError)
}

// UnarchiveEntry unarchives the specified entry.
func (c *Client) UnarchiveEntry(entry *Entry) (unarchived *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("UnpublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	unarchived = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/archived", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Delete(path).
		Receive(unarchived, contentfulError)

	return unarchived, handleError(err, contentfulError)
}
<commit_msg>Changing entry fields typealias<commit_after>package management

import (
	"fmt"
)

type Linkable interface {
	Link() map[string]map[string]interface{}
}

type EntryFields map[string]interface{}

type NewEntry struct {
	Fields EntryFields `json:"fields"`
}

// Validate validates the entry
func (c *NewEntry) Validate() error {
	if c.Fields == nil || len(c.Fields) == 0 {
		return fmt.Errorf("NewEntry.Fields cannot be empty!")
	}

	return nil
}

// Entry represent textual content in a space. An entry's data adheres to a
// certain content type.
type Entry struct {
	System `json:"sys"`
	Fields EntryFields `json:"fields"`
}

// Validate will validate the entry. An error is returned if the entry
// is not  valid.
func (c *Entry) Validate() error {
	if c.Space == nil || c.Space.ID == "" {
		return fmt.Errorf("Entry must have a valid Space associated with it!")
	}

	if c.System.ID == "" {
		return fmt.Errorf("Entry.System.ID cannot be empty!")
	}

	if c.Fields == nil || len(c.Fields) == 0 {
		return fmt.Errorf("Entry.Fields cannot be empty!")
	}

	return nil
}

// Link represents a link to the Entry and implements the Linkable interface
func (c *Entry) Link() map[string]map[string]interface{} {
	return map[string]map[string]interface{}{
		"sys": map[string]interface{}{
			"id":       c.ID,
			"linkType": "Entry",
			"type":     LinkType,
		},
	}
}

// QueryEntries returns all entries for the given space and parameters.
func (c *Client) QueryEntries(spaceID string, params map[string]string, limit int, offset int) (entries []*Entry, pagination *Pagination, err error) {
	if spaceID == "" {
		return nil, nil, fmt.Errorf("FetchEntries failed. Space identifier is not valid!")
	}

	if limit < 0 {
		return nil, nil, fmt.Errorf("FetchEntries failed. Limit must be greater than 0")
	}

	if limit > 100 {
		limit = 100
	}

	c.rl.Wait()

	type entriesResponse struct {
		*Pagination
		Items []*Entry `json:"items"`
	}

	results := new(entriesResponse)
	results.Items = []*Entry{}
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries", spaceID)
	req, err := c.sling.New().
		Get(path).
		Request()

	if err != nil {
		return
	}

	// Add query parameters
	q := req.URL.Query()
	for k, v := range params {
		q.Set(k, v)
	}

	q.Set("skip", fmt.Sprintf("%v", offset))
	q.Set("limit", fmt.Sprintf("%v", limit))
	req.URL.RawQuery = q.Encode()

	// Perform request
	_, err = c.sling.Do(req, results, contentfulError)

	return results.Items, results.Pagination, handleError(err, contentfulError)
}

// FetchEntry returns a single entry for the given space and entry identifier
func (c *Client) FetchEntry(spaceID string, entryID string) (entry *Entry, err error) {
	if spaceID == "" || entryID == "" {
		err = fmt.Errorf("FetchContentType failed. Invalid spaceID or contentTypeID.")
		return
	}

	c.rl.Wait()

	entry = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", spaceID, entryID)
	_, err = c.sling.New().Get(path).Receive(entry, contentfulError)

	return entry, handleError(err, contentfulError)
}

// CreateEntry will create a new entry with an ID specified by the user or
// generated by the system
func (c *Client) CreateEntry(entry *NewEntry, contentType *ContentType) (created *Entry, err error) {
	if entry == nil || contentType == nil {
		err = fmt.Errorf("CreateEntry failed, entry and contentType cannot be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	if err = contentType.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	created = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries", contentType.Space.ID)
	_, err = c.sling.New().
		Post(path).
		Set("X-Contentful-Content-Type", contentType.ID).
		BodyJSON(entry).
		Receive(created, contentfulError)

	return created, handleError(err, contentfulError)
}

// UpdateEntry will update the specified entry with any changes that you have
// made.
func (c *Client) UpdateEntry(entry *Entry) (updated *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("CreateEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	updated = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Set("X-Contentful-Version", fmt.Sprintf("%v", entry.System.Version)).
		BodyJSON(entry).
		Receive(updated, contentfulError)

	return updated, handleError(err, contentfulError)
}

// DeleteEntry will delete the specified entry
func (c *Client) DeleteEntry(entryID string, spaceID string) (err error) {

	c.rl.Wait()

	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v", spaceID, entryID)
	_, err = c.sling.New().
		Delete(path).
		Receive(nil, contentfulError)

	return handleError(err, contentfulError)
}

// PublishEntry makes the entry available via the Content Delivery API
func (c *Client) PublishEntry(entry *Entry) (published *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("PublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	published = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/published", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Set("X-Contentful-Version", fmt.Sprintf("%v", entry.System.Version)).
		Receive(published, contentfulError)

	return published, handleError(err, contentfulError)
}

// UnpublishEntry makes the entry unavailable via the Content Delivery API
func (c *Client) UnpublishEntry(entry *Entry) (unpublished *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("UnpublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	unpublished = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/published", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Delete(path).
		Receive(unpublished, contentfulError)

	return unpublished, handleError(err, contentfulError)
}

// ArchiveEntry will archive the specified entry. An entry can only be archived
// when it's not published.
func (c *Client) ArchiveEntry(entry *Entry) (archived *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("PublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	archived = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/archived", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Put(path).
		Receive(archived, contentfulError)

	return archived, handleError(err, contentfulError)
}

// UnarchiveEntry unarchives the specified entry.
func (c *Client) UnarchiveEntry(entry *Entry) (unarchived *Entry, err error) {
	if entry == nil {
		err = fmt.Errorf("UnpublishEntry failed. Entry must not be nil!")
		return
	}

	if err = entry.Validate(); err != nil {
		return
	}

	c.rl.Wait()

	unarchived = new(Entry)
	contentfulError := new(ContentfulError)
	path := fmt.Sprintf("spaces/%v/entries/%v/archived", entry.Space.ID, entry.System.ID)
	_, err = c.sling.New().
		Delete(path).
		Receive(unarchived, contentfulError)

	return unarchived, handleError(err, contentfulError)
}
<|endoftext|>


<commit_before>package webext

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/mongo"
	"github.com/eaciit/knot/knot.v1"
	"github.com/eaciit/orm"
	. "github.com/eaciit/powerplant/sec/webapp/controllers"
)

var (
	wd = func() string {
		d, _ := os.Getwd()
		return d + "/"
	}()
)

func init() {
	conn, err := PrepareConnection()
	if err != nil {
		fmt.Println(err)
	}
	ctx := orm.New(conn)

	baseCont := new(BaseController)
	baseCont.Ctx = ctx

	app := knot.NewApp("sec")
	app.ViewsPath = wd + "views/"

	// register controllers
	app.Register(&LoginController{baseCont})
	app.Register(&DashboardController{baseCont})
	app.Register(&DataBrowserController{baseCont})
	app.Register(&ValueEquationController{baseCont})
	app.Register(&ValueEquationComparisonController{baseCont})
	app.Register(&HistoricalValueEquationController{baseCont})
	app.Register(&HypothesisController{baseCont})
	app.Register(&ScenarioSimulation{baseCont})
	app.Register(&UploadDataController{baseCont})
	/*app.Register(&InitController{baseCont})
	app.Register(&OrganizationController{baseCont})
	app.Register(&InventoryController{baseCont})
	app.Register(&UomController{baseCont})*/

	app.Static("static", wd+"assets")
	app.LayoutTemplate = "shared/layout.html"
	app.DefaultOutputType = knot.OutputJson
	knot.RegisterApp(app)
}

func PrepareConnection() (dbox.IConnection, error) {
	config := ReadConfig()
	ci := &dbox.ConnectionInfo{config["host"], config["database"], config["username"], config["password"], nil}
	c, e := dbox.NewConnection("mongo", ci)

	if e != nil {
		return nil, e
	}

	e = c.Connect()
	if e != nil {
		return nil, e
	}

	return c, nil
}

func ReadConfig() map[string]string {
	ret := make(map[string]string)
	fmt.Println(wd, "conf/app.conf")
	file, err := os.Open(wd + "conf/app.conf")
	if err == nil {
		defer file.Close()

		reader := bufio.NewReader(file)
		for {
			line, _, e := reader.ReadLine()
			if e != nil {
				break
			}

			sval := strings.Split(string(line), "=")
			ret[sval[0]] = sval[1]
		}
	} else {
		fmt.Println(err.Error())
	}

	return ret
}
<commit_msg>change connection type into mssql<commit_after>package webext

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/mongo"
	"github.com/eaciit/knot/knot.v1"
	"github.com/eaciit/orm"
	. "github.com/eaciit/powerplant/sec/webapp/controllers"
)

var (
	wd = func() string {
		d, _ := os.Getwd()
		return d + "/"
	}()
)

func init() {
	conn, err := PrepareConnection()
	if err != nil {
		fmt.Println(err)
	}
	ctx := orm.New(conn)

	baseCont := new(BaseController)
	baseCont.Ctx = ctx

	app := knot.NewApp("sec")
	app.ViewsPath = wd + "views/"

	// register controllers
	app.Register(&LoginController{baseCont})
	app.Register(&DashboardController{baseCont})
	app.Register(&DataBrowserController{baseCont})
	app.Register(&ValueEquationController{baseCont})
	app.Register(&ValueEquationComparisonController{baseCont})
	app.Register(&HistoricalValueEquationController{baseCont})
	app.Register(&HypothesisController{baseCont})
	app.Register(&ScenarioSimulation{baseCont})
	app.Register(&UploadDataController{baseCont})
	/*app.Register(&InitController{baseCont})
	app.Register(&OrganizationController{baseCont})
	app.Register(&InventoryController{baseCont})
	app.Register(&UomController{baseCont})*/

	app.Static("static", wd+"assets")
	app.LayoutTemplate = "shared/layout.html"
	app.DefaultOutputType = knot.OutputJson
	knot.RegisterApp(app)
}

func PrepareConnection() (dbox.IConnection, error) {
	config := ReadConfig()
	ci := &dbox.ConnectionInfo{config["host"], config["database"], config["username"], config["password"], nil}
	c, e := dbox.NewConnection("mssql", ci)
	// c, e := dbox.NewConnection("mongo", ci)

	if e != nil {
		return nil, e
	}

	e = c.Connect()
	if e != nil {
		return nil, e
	}

	return c, nil
}

func ReadConfig() map[string]string {
	ret := make(map[string]string)
	fmt.Println(wd, "conf/app.conf")
	file, err := os.Open(wd + "conf/app.conf")
	if err == nil {
		defer file.Close()

		reader := bufio.NewReader(file)
		for {
			line, _, e := reader.ReadLine()
			if e != nil {
				break
			}

			sval := strings.Split(string(line), "=")
			ret[sval[0]] = sval[1]
		}
	} else {
		fmt.Println(err.Error())
	}

	return ret
}
<|endoftext|>


<commit_before><commit_msg>Updated target lock with cluster member id.<commit_after><|endoftext|>


<commit_before>package mch

import (
	"net/http"
	"time"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"bytes"
	"sync"
	"strings"
	"io"
	"crypto/tls"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
)

const API_URL = "https://api.mch.weixin.qq.com"

type Client struct {
	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	signType string // 签名类型，目前支持HMAC-SHA256和MD5，默认为MD5

	client    *http.Client
	tlsClient *http.Client

	*zap.SugaredLogger
}

func New(appID, mchID, apiKey string, timeout ...time.Duration) *Client {
	client := &Client{
		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
	if len(timeout) > 0 {
		client.client = &http.Client{
			Timeout: timeout[0],
		}
	}
	return client
}

func NewWithSubMch(appID, mchID, apiKey, subAppID, subMchID string, timeout ...time.Duration) *Client {
	client := &Client{
		appID:    appID,
		mchID:    mchID,
		apiKey:   apiKey,
		subAppID: subAppID,
		subMchID: subMchID,

		SugaredLogger: wechat.Sugar,
	}
	if len(timeout) > 0 {
		client.client = &http.Client{
			Timeout: timeout[0],
		}
	}
	return client
}

func (client *Client) SetCert(certPEMBlock, keyPEMBlock []byte) error {
	cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
	if err != nil {
		return err
	}
	return client.setCert(cert)
}

func (client *Client) SetCertFromFile(certFile, keyFile string) error {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}
	return client.setCert(cert)
}

func (client *Client) setCert(cert tls.Certificate) error {
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	transport := *http.DefaultTransport.(*http.Transport)
	transport.TLSClientConfig = tlsConfig
	client.tlsClient = &http.Client{
		Transport: &transport,
		Timeout:   client.client.Timeout,
	}
	return nil
}

func (client *Client) SetSignType(signType string) error {
	if signType != SignTypeHMAC_SHA256 && signType != SignTypeMD5 {
		return fmt.Errorf("unsupported sign type: %s", signType)
	}
	client.signType = signType
	return nil
}

var pool = sync.Pool{
	New: func() interface{} {
		return bytes.NewBuffer(make([]byte, 0, 4<<10)) // 4KB
	},
}

func (client *Client) PostXML(relativeURL string, req map[string]string) (rep map[string]string, err error) {
	return client.postXML(false, relativeURL, req)
}

func (client *Client) PostXMLWithCert(relativeURL string, req map[string]string) (rep map[string]string, err error) {
	return client.postXML(true, relativeURL, req)
}

func (client *Client) postXML(withCert bool, relativeURL string, req map[string]string) (rep map[string]string, err error) {
	buffer, err := client.makeRequest(req)
	defer pool.Put(buffer)
	if err != nil {
		return nil, err
	}

	url := API_URL + relativeURL
	rep, err = client.postToMap(withCert, url, buffer)
	if err != nil {
		bizError, ok := err.(*BizError)
		if !ok || bizError.ErrCode != ErrCodeSYSTEMERROR {
			return
		}
		url = switchReqURL(url)
		return client.postToMap(withCert, url, buffer) // retry
	}
	return
}

func (client *Client) makeRequest(req map[string]string) (*bytes.Buffer, error) {
	_, isEnterprisePay := req["mch_appid"]

	if !isEnterprisePay {
		req["appid"] = client.appID
		req["mch_id"] = client.mchID
	}
	if client.subAppID != "" {
		req["sub_appid"] = client.subAppID
	}
	if client.subMchID != "" {
		req["sub_mch_id"] = client.subMchID
	}

	req["nonce_str"] = RandString(32)

	switch client.signType {
	case "", SignTypeMD5:
		if !isEnterprisePay {
			req["sign_type"] = SignTypeMD5
		}
		req["sign"] = Sign(req, client.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		if !isEnterprisePay {
			req["sign_type"] = SignTypeHMAC_SHA256
		}
		req["sign"] = Sign(req, client.apiKey, hmac.New(sha256.New, []byte(client.apiKey)))
	}
	fmt.Printf("req: %v\n", req)

	buffer := pool.Get().(*bytes.Buffer)
	buffer.Reset()

	err := EncodeXML(buffer, req)
	return buffer, err
}

func (client *Client) postToMap(withCert bool, url string, body io.Reader) (rep map[string]string, err error) {
	repBody, err := client.post(withCert, url, body)
	if err != nil {
		return nil, err
	}
	defer repBody.Close()
	return client.toMap(repBody)
}

func (client *Client) post(withCert bool, url string, body io.Reader) (io.ReadCloser, error) {
	c := client.client
	if withCert {
		c = client.tlsClient
	}
	rep, err := c.Post(url, "text/xml; charset=utf-8", body)
	if err != nil {
		return nil, err
	}
	if rep.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http status: %s", rep.Status)
	}

	return rep.Body, nil
}

func (client *Client) toMap(repBody io.Reader) (rep map[string]string, err error) {
	if closer, ok := repBody.(io.Closer); ok {
		defer closer.Close()
	}

	rep, err = DecodeXML(repBody)
	if err != nil {
		return nil, err
	}
	fmt.Printf("toMap rep: %v\n", rep)

	returnCode := rep["return_code"]
	if returnCode != ReturnCodeSuccess {
		return nil, &Error{
			ReturnCode: returnCode,
			ReturnMsg:  rep["return_msg"],
		}
	}

	resultCode := rep["result_code"]
	if resultCode != ResultCodeSuccess {
		return nil, &BizError{
			ResultCode:  resultCode,
			ErrCode:     rep["err_code"],
			ErrCodeDesc: rep["err_code_des"],
		}
	}

	appId := rep["appid"]
	if appId != client.appID {
		return nil, fmt.Errorf("appid mismatch, have: %s, want: %s", appId, client.appID)
	}
	mchId := rep["mch_id"]
	if mchId != client.mchID {
		return nil, fmt.Errorf("mch_id mismatch, have: %s, want: %s", mchId, client.mchID)
	}

	if client.subAppID != "" {
		subAppId := rep["sub_appid"]
		subMchId := rep["sub_mch_id"]
		if subAppId != "" && subAppId != client.subAppID {
			return nil, fmt.Errorf("sub_appid mismatch, have: %s, want: %s", subAppId, client.subAppID)
		}
		if subMchId != client.subMchID {
			return nil, fmt.Errorf("sub_mch_id mismatch, have: %s, want: %s", subMchId, client.subMchID)
		}
	}

	var signWant string
	signHave := rep["sign"]
	repSignType := rep["sign_type"]
	switch repSignType {
	case "", SignTypeMD5:
		signWant = Sign(rep, client.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		signWant = Sign(rep, client.apiKey, hmac.New(sha256.New, []byte(client.apiKey)))
	default:
		err = fmt.Errorf("unsupported response sign_type: %s", repSignType)
		return nil, err
	}
	if signHave != signWant {
		return nil, fmt.Errorf("sign mismatch,\nhave: %s,\nwant: %s", signHave, signWant)
	}

	return rep, nil
}

func switchReqURL(url string) string {
	switch {
	case strings.HasPrefix(url, "https://api.mch.weixin.qq.com/"):
		return "https://api2.mch.weixin.qq.com/" + url[len("https://api.mch.weixin.qq.com/"):]
	case strings.HasPrefix(url, "https://api2.mch.weixin.qq.com/"):
		return "https://api.mch.weixin.qq.com/" + url[len("https://api2.mch.weixin.qq.com/"):]
	default:
		return url
	}
}
<commit_msg>Update files<commit_after>package mch

import (
	"net/http"
	"time"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"bytes"
	"sync"
	"strings"
	"io"
	"crypto/tls"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
)

const API_URL = "https://api.mch.weixin.qq.com"

type Client struct {
	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	signType string // 签名类型，目前支持HMAC-SHA256和MD5，默认为MD5

	client    *http.Client
	tlsClient *http.Client

	*zap.SugaredLogger
}

func New(appID, mchID, apiKey string, timeout ...time.Duration) *Client {
	client := &Client{
		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
	if len(timeout) > 0 {
		client.client = &http.Client{
			Timeout: timeout[0],
		}
	}
	return client
}

func NewWithSubMch(appID, mchID, apiKey, subAppID, subMchID string, timeout ...time.Duration) *Client {
	client := &Client{
		appID:    appID,
		mchID:    mchID,
		apiKey:   apiKey,
		subAppID: subAppID,
		subMchID: subMchID,

		SugaredLogger: wechat.Sugar,
	}
	if len(timeout) > 0 {
		client.client = &http.Client{
			Timeout: timeout[0],
		}
	}
	return client
}

func (client *Client) SetCert(certPEMBlock, keyPEMBlock []byte) error {
	cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
	if err != nil {
		return err
	}
	return client.setCert(cert)
}

func (client *Client) SetCertFromFile(certFile, keyFile string) error {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}
	return client.setCert(cert)
}

func (client *Client) setCert(cert tls.Certificate) error {
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	transport := *http.DefaultTransport.(*http.Transport)
	transport.TLSClientConfig = tlsConfig
	client.tlsClient = &http.Client{
		Transport: &transport,
		Timeout:   client.client.Timeout,
	}
	return nil
}

func (client *Client) SetSignType(signType string) error {
	if signType != SignTypeHMAC_SHA256 && signType != SignTypeMD5 {
		return fmt.Errorf("unsupported sign type: %s", signType)
	}
	client.signType = signType
	return nil
}

var pool = sync.Pool{
	New: func() interface{} {
		return bytes.NewBuffer(make([]byte, 0, 4<<10)) // 4KB
	},
}

func (client *Client) PostXML(relativeURL string, req map[string]string) (rep map[string]string, err error) {
	return client.postXML(false, relativeURL, req)
}

func (client *Client) PostXMLWithCert(relativeURL string, req map[string]string) (rep map[string]string, err error) {
	return client.postXML(true, relativeURL, req)
}

func (client *Client) postXML(withCert bool, relativeURL string, req map[string]string) (rep map[string]string, err error) {
	buffer, err := client.makeRequest(req)
	defer pool.Put(buffer)
	if err != nil {
		return nil, err
	}

	url := API_URL + relativeURL
	rep, err = client.postToMap(withCert, url, buffer)
	if err != nil {
		bizError, ok := err.(*BizError)
		if !ok || bizError.ErrCode != ErrCodeSYSTEMERROR {
			return
		}
		url = switchReqURL(url)
		return client.postToMap(withCert, url, buffer) // retry
	}
	return
}

func (client *Client) makeRequest(req map[string]string) (*bytes.Buffer, error) {
	_, isEnterprisePay := req["mch_appid"]

	if !isEnterprisePay {
		req["appid"] = client.appID
		req["mch_id"] = client.mchID
	}
	if client.subAppID != "" {
		req["sub_appid"] = client.subAppID
	}
	if client.subMchID != "" {
		req["sub_mch_id"] = client.subMchID
	}

	req["nonce_str"] = RandString(32)

	switch client.signType {
	case "", SignTypeMD5:
		if !isEnterprisePay {
			req["sign_type"] = SignTypeMD5
		}
		req["sign"] = Sign(req, client.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		if !isEnterprisePay {
			req["sign_type"] = SignTypeHMAC_SHA256
		}
		req["sign"] = Sign(req, client.apiKey, hmac.New(sha256.New, []byte(client.apiKey)))
	}
	fmt.Printf("req: %v\n", req)

	buffer := pool.Get().(*bytes.Buffer)
	buffer.Reset()

	err := EncodeXML(buffer, req)
	return buffer, err
}

func (client *Client) postToMap(withCert bool, url string, body io.Reader) (rep map[string]string, err error) {
	repBody, err := client.post(withCert, url, body)
	if err != nil {
		return nil, err
	}
	defer repBody.Close()
	return client.toMap(repBody)
}

func (client *Client) post(withCert bool, url string, body io.Reader) (io.ReadCloser, error) {
	c := client.client
	if withCert {
		c = client.tlsClient
	}
	rep, err := c.Post(url, "text/xml; charset=utf-8", body)
	if err != nil {
		return nil, err
	}
	if rep.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http status: %s", rep.Status)
	}

	return rep.Body, nil
}

func (client *Client) toMap(repBody io.Reader) (rep map[string]string, err error) {
	if closer, ok := repBody.(io.Closer); ok {
		defer closer.Close()
	}

	rep, err = DecodeXML(repBody)
	if err != nil {
		return nil, err
	}
	fmt.Printf("toMap rep: %v\n", rep)

	returnCode := rep["return_code"]
	if returnCode != ReturnCodeSuccess {
		return nil, &Error{
			ReturnCode: returnCode,
			ReturnMsg:  rep["return_msg"],
		}
	}

	resultCode := rep["result_code"]
	if resultCode != ResultCodeSuccess {
		return nil, &BizError{
			ResultCode:  resultCode,
			ErrCode:     rep["err_code"],
			ErrCodeDesc: rep["err_code_des"],
		}
	}

	appId := rep["appid"]
	if appId != "" && appId != client.appID {
		return nil, fmt.Errorf("appid mismatch, have: %s, want: %s", appId, client.appID)
	}
	mchId := rep["mch_id"]
	if mchId == "" {
		mchId = rep["mchid"]
	}
	if mchId != "" && mchId != client.mchID {
		return nil, fmt.Errorf("mch_id mismatch, have: %s, want: %s", mchId, client.mchID)
	}

	if client.subAppID != "" {
		subAppId := rep["sub_appid"]
		subMchId := rep["sub_mch_id"]
		if subAppId != "" && subAppId != client.subAppID {
			return nil, fmt.Errorf("sub_appid mismatch, have: %s, want: %s", subAppId, client.subAppID)
		}
		if subMchId != client.subMchID {
			return nil, fmt.Errorf("sub_mch_id mismatch, have: %s, want: %s", subMchId, client.subMchID)
		}
	}

	var signWant string
	signHave := rep["sign"]
	repSignType := rep["sign_type"]
	switch repSignType {
	case "", SignTypeMD5:
		signWant = Sign(rep, client.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		signWant = Sign(rep, client.apiKey, hmac.New(sha256.New, []byte(client.apiKey)))
	default:
		err = fmt.Errorf("unsupported response sign_type: %s", repSignType)
		return nil, err
	}
	if signHave != signWant {
		return nil, fmt.Errorf("sign mismatch,\nhave: %s,\nwant: %s", signHave, signWant)
	}

	return rep, nil
}

func switchReqURL(url string) string {
	switch {
	case strings.HasPrefix(url, "https://api.mch.weixin.qq.com/"):
		return "https://api2.mch.weixin.qq.com/" + url[len("https://api.mch.weixin.qq.com/"):]
	case strings.HasPrefix(url, "https://api2.mch.weixin.qq.com/"):
		return "https://api.mch.weixin.qq.com/" + url[len("https://api2.mch.weixin.qq.com/"):]
	default:
		return url
	}
}
<|endoftext|>


<commit_before>package water

import (
	"net"
	"testing"
	"time"

	"github.com/songgao/water/waterutil"
)

const BUFFERSIZE = 1522

func startRead(ch chan<- []byte, ifce *Interface) {
	go func() {
		for {
			buffer := make([]byte, BUFFERSIZE)
			n, err := ifce.Read(buffer)
			if err == nil {
				buffer = buffer[:n:n]
				ch <- buffer
			}
		}
	}()
}

func TestBroadcast(t *testing.T) {
	var (
		self = net.IPv4(10, 0, 42, 1)
		mask = net.IPv4Mask(255, 255, 255, 0)
		brd  = net.IPv4(10, 0, 42, 255)
	)

	ifce, err := NewTAP("test")
	if err != nil {
		t.Fatalf("creating TAP error: %v\n", err)
	}

	setupIfce(t, net.IPNet{IP: self, Mask: mask}, ifce.Name())
	startBroadcast(t, brd)

	dataCh := make(chan []byte, 8)
	startRead(dataCh, ifce)

	timeout := time.NewTimer(8 * time.Second).C

readFrame:
	for {
		select {
		case buffer := <-dataCh:
			ethertype := waterutil.MACEthertype(buffer)
			if ethertype != waterutil.IPv4 {
				continue readFrame
			}
			if !waterutil.IsBroadcast(waterutil.MACDestination(buffer)) {
				continue readFrame
			}
			packet := waterutil.MACPayload(buffer)
			if !waterutil.IsIPv4(packet) {
				continue readFrame
			}
			if !waterutil.IPv4Source(packet).Equal(self) {
				continue readFrame
			}
			if !waterutil.IPv4Destination(packet).Equal(brd) {
				continue readFrame
			}
			if waterutil.IPv4Protocol(packet) != waterutil.ICMP {
				continue readFrame
			}
			t.Logf("received broadcast frame: %#v\n", buffer)
			break readFrame
		case <-timeout:
			t.Fatal("Waiting for broadcast packet timeout")
		}
	}
}
<commit_msg>Adjusts Tests with Changes<commit_after>package water

import (
	"net"
	"testing"
	"time"

	"github.com/songgao/water/waterutil"
)

const BUFFERSIZE = 1522

func startRead(ch chan<- []byte, ifce *Interface) {
	go func() {
		for {
			buffer := make([]byte, BUFFERSIZE)
			n, err := ifce.Read(buffer)
			if err == nil {
				buffer = buffer[:n:n]
				ch <- buffer
			}
		}
	}()
}

func TestBroadcast(t *testing.T) {
	var (
		self = net.IPv4(10, 0, 42, 1)
		mask = net.IPv4Mask(255, 255, 255, 0)
		brd  = net.IPv4(10, 0, 42, 255)
	)

	ifce, err := New(Config{DeviceType: TAP})
	if err != nil {
		t.Fatalf("creating TAP error: %v\n", err)
	}

	setupIfce(t, net.IPNet{IP: self, Mask: mask}, ifce.Name())
	startBroadcast(t, brd)

	dataCh := make(chan []byte, 8)
	startRead(dataCh, ifce)

	timeout := time.NewTimer(8 * time.Second).C

readFrame:
	for {
		select {
		case buffer := <-dataCh:
			ethertype := waterutil.MACEthertype(buffer)
			if ethertype != waterutil.IPv4 {
				continue readFrame
			}
			if !waterutil.IsBroadcast(waterutil.MACDestination(buffer)) {
				continue readFrame
			}
			packet := waterutil.MACPayload(buffer)
			if !waterutil.IsIPv4(packet) {
				continue readFrame
			}
			if !waterutil.IPv4Source(packet).Equal(self) {
				continue readFrame
			}
			if !waterutil.IPv4Destination(packet).Equal(brd) {
				continue readFrame
			}
			if waterutil.IPv4Protocol(packet) != waterutil.ICMP {
				continue readFrame
			}
			t.Logf("received broadcast frame: %#v\n", buffer)
			break readFrame
		case <-timeout:
			t.Fatal("Waiting for broadcast packet timeout")
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>insert into t_xunsou_index_log db_log db<commit_after><|endoftext|>


<commit_before>package tablestorageproxy

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"gohavestorage/gohavestoragecommon"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"
)

type GoHaveStorage interface {
	GetKey() []byte
	GetAccount() string
	DumpSessions() bool
}

type TableStorageProxy struct {
	goHaveStorage GoHaveStorage
	baseUrl       string
}

func New(goHaveStorage GoHaveStorage) *TableStorageProxy {
	var tableStorageProxy TableStorageProxy

	tableStorageProxy.goHaveStorage = goHaveStorage
	tableStorageProxy.baseUrl = "https://" + goHaveStorage.GetAccount() + ".table.core.windows.net/"

	return &tableStorageProxy
}

func (tableStorageProxy *TableStorageProxy) GetTableACL() {
	tableStorageProxy.executeCommonRequest("HEAD", "?comp=acl", "", nil, false, false, false)
}

func (tableStorageProxy *TableStorageProxy) GetTableServiceProperties() (*gohavestoragecommon.StorageServiceProperties, int) {
	body, httpStatusCode := tableStorageProxy.executeCommonRequest("GET", "?comp=properties", "&restype=service", nil, false, false, true)

	response := &gohavestoragecommon.StorageServiceProperties{}
	err := xml.Unmarshal([]byte(body), &response)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}

	return response, httpStatusCode
}

func (tableStorageProxy *TableStorageProxy) SetTableServiceProperties(storageServiceProperties *gohavestoragecommon.StorageServiceProperties) int {
	xmlBytes, _ := xml.MarshalIndent(storageServiceProperties, "", "")
	_, httpStatusCode := tableStorageProxy.executeCommonRequest("PUT", "?comp=properties", "&restype=service", append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>"), xmlBytes...), false, false, false)
	return httpStatusCode
}

func (tableStorageProxy *TableStorageProxy) GetTableServiceStats() {
	tableStorageProxy.executeCommonRequest("GET", "?comp=properties", "&restype=stats", nil, false, false, false)
}

func (tableStorageProxy *TableStorageProxy) QueryTables() {
	tableStorageProxy.executeCommonRequest("GET", "Tables", "", nil, false, true, false)
}

func (tableStorageProxy *TableStorageProxy) QueryEntity(tableName string, partitionKey string, rowKey string, selects string) {
	tableStorageProxy.executeCommonRequest("GET", tableName+"%28PartitionKey=%27"+partitionKey+"%27,RowKey=%27"+rowKey+"%27%29", "?$select="+selects, nil, false, true, false)
}

func (tableStorageProxy *TableStorageProxy) QueryEntities(tableName string, selects string, filter string, top string) {
	tableStorageProxy.executeCommonRequest("GET", tableName, "?$filter="+filter+"&$select="+selects+"&$top="+top, nil, false, true, false)
}

func (tableStorageProxy *TableStorageProxy) DeleteEntity(tableName string, partitionKey string, rowKey string) {
	tableStorageProxy.executeEntityRequest("DELETE", tableName, partitionKey, rowKey, nil, true)
}

func (tableStorageProxy *TableStorageProxy) UpdateEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("PUT", tableName, partitionKey, rowKey, json, true)
}

func (tableStorageProxy *TableStorageProxy) MergeEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("MERGE", tableName, partitionKey, rowKey, json, true)
}

func (tableStorageProxy *TableStorageProxy) InsertOrMergeEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("MERGE", tableName, partitionKey, rowKey, json, false)
}

func (tableStorageProxy *TableStorageProxy) InsertOrReplaceEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("PUT", tableName, partitionKey, rowKey, json, false)
}

func (tableStorageProxy *TableStorageProxy) DeleteTable(tableName string) {
	tableStorageProxy.executeCommonRequest("DELETE", tableName, "", nil, false, false, true)
}

type CreateTableArgs struct {
	TableName string
}

func (tableStorageProxy *TableStorageProxy) CreateTable(tableName string) {
	json, _ := json.Marshal(CreateTableArgs{TableName: tableName})
	tableStorageProxy.executeCommonRequest("POST", "Tables", "", json, false, true, false)
}

func (tableStorageProxy *TableStorageProxy) InsertEntity(tableName string, json []byte) {
	tableStorageProxy.executeCommonRequest("POST", tableName, "", json, false, true, false)
}

func (tableStorageProxy *TableStorageProxy) executeEntityRequest(httpVerb string, tableName string, partitionKey string, rowKey string, json []byte, useIfMatch bool) {
	tableStorageProxy.executeCommonRequest(httpVerb, tableName+"%28PartitionKey=%27"+partitionKey+"%27,RowKey=%27"+rowKey+"%27%29", "", json, useIfMatch, false, false)
}

func (tableStorageProxy *TableStorageProxy) executeCommonRequest(httpVerb string, target string, query string, json []byte, useIfMatch bool, useAccept bool, useContentTypeXML bool) ([]byte, int) {
	xmsdate, Authentication := tableStorageProxy.calculateDateAndAuthentication(target)

	client := &http.Client{}
	request, _ := http.NewRequest(httpVerb, tableStorageProxy.baseUrl+target+query, bytes.NewBuffer(json))

	if json != nil {
		request.Header.Set("Content-Type", "application/json")
		request.Header.Set("Content-Length", string(len(json)))
	}

	if useContentTypeXML {
		request.Header.Set("Content-Type", "application/atom+xml")
	}

	if useIfMatch {
		request.Header.Set("If-Match", "*")
	}

	if useAccept {
		request.Header.Set("Accept", "application/json;odata=nometadata")
	}

	request.Header.Set("x-ms-date", xmsdate)
	request.Header.Set("x-ms-version", "2013-08-15")
	request.Header.Set("Authorization", Authentication)

	response, _ := client.Do(request)

	if tableStorageProxy.goHaveStorage.DumpSessions() {
		responseDump, _ := httputil.DumpResponse(response, true)
		requestDump, _ := httputil.DumpRequest(request, true)

		fmt.Printf("Request: %s\n", requestDump)
		fmt.Printf("%s\n", string(json))
		fmt.Printf("Response: %s\n", responseDump)
	}

	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}

	return contents, response.StatusCode
}

func (tableStorageProxy *TableStorageProxy) calculateDateAndAuthentication(target string) (string, string) {
	xmsdate := strings.Replace(time.Now().UTC().Add(-time.Minute).Format(time.RFC1123), "UTC", "GMT", -1)
	SignatureString := xmsdate + "\n/" + tableStorageProxy.goHaveStorage.GetAccount() + "/" + target
	Authentication := "SharedKeyLite " + tableStorageProxy.goHaveStorage.GetAccount() + ":" + computeHmac256(SignatureString, tableStorageProxy.goHaveStorage.GetKey())
	return xmsdate, Authentication
}

func computeHmac256(message string, key []byte) string {
	h := hmac.New(sha256.New, key)
	h.Write([]byte(message))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
<commit_msg>Handling of secondary<commit_after>package tablestorageproxy

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"gohavestorage/gohavestoragecommon"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"
)

type GoHaveStorage interface {
	GetKey() []byte
	GetAccount() string
	DumpSessions() bool
}

type TableStorageProxy struct {
	goHaveStorage    GoHaveStorage
	baseUrl          string
	secondaryBaseUrl string
}

func New(goHaveStorage GoHaveStorage) *TableStorageProxy {
	var tableStorageProxy TableStorageProxy

	tableStorageProxy.goHaveStorage = goHaveStorage
	tableStorageProxy.baseUrl = "https://" + goHaveStorage.GetAccount() + ".table.core.windows.net/"
	tableStorageProxy.secondaryBaseUrl = "https://" + goHaveStorage.GetAccount() + "-secondary.table.core.windows.net/"

	return &tableStorageProxy
}

func (tableStorageProxy *TableStorageProxy) GetTableACL() {
	tableStorageProxy.executeCommonRequest("HEAD", "?comp=acl", "", nil, false, false, false, false)
}

func (tableStorageProxy *TableStorageProxy) GetTableServiceProperties() (*gohavestoragecommon.StorageServiceProperties, int) {
	body, httpStatusCode := tableStorageProxy.executeCommonRequest("GET", "?comp=properties", "&restype=service", nil, false, false, true, false)

	response := &gohavestoragecommon.StorageServiceProperties{}
	err := xml.Unmarshal([]byte(body), &response)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}

	return response, httpStatusCode
}

func (tableStorageProxy *TableStorageProxy) SetTableServiceProperties(storageServiceProperties *gohavestoragecommon.StorageServiceProperties) int {
	xmlBytes, _ := xml.MarshalIndent(storageServiceProperties, "", "")
	_, httpStatusCode := tableStorageProxy.executeCommonRequest("PUT", "?comp=properties", "&restype=service", append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>"), xmlBytes...), false, false, false, false)
	return httpStatusCode
}

func (tableStorageProxy *TableStorageProxy) GetTableServiceStats() {
	body, httpStatusCode := tableStorageProxy.executeCommonRequest("GET", "?comp=stats", "&restype=service", nil, false, false, false, true)
}

func (tableStorageProxy *TableStorageProxy) QueryTables() {
	tableStorageProxy.executeCommonRequest("GET", "Tables", "", nil, false, true, false, false)
}

func (tableStorageProxy *TableStorageProxy) QueryEntity(tableName string, partitionKey string, rowKey string, selects string) {
	tableStorageProxy.executeCommonRequest("GET", tableName+"%28PartitionKey=%27"+partitionKey+"%27,RowKey=%27"+rowKey+"%27%29", "?$select="+selects, nil, false, true, false, false)
}

func (tableStorageProxy *TableStorageProxy) QueryEntities(tableName string, selects string, filter string, top string) {
	tableStorageProxy.executeCommonRequest("GET", tableName, "?$filter="+filter+"&$select="+selects+"&$top="+top, nil, false, true, false, false)
}

func (tableStorageProxy *TableStorageProxy) DeleteEntity(tableName string, partitionKey string, rowKey string) {
	tableStorageProxy.executeEntityRequest("DELETE", tableName, partitionKey, rowKey, nil, true)
}

func (tableStorageProxy *TableStorageProxy) UpdateEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("PUT", tableName, partitionKey, rowKey, json, true)
}

func (tableStorageProxy *TableStorageProxy) MergeEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("MERGE", tableName, partitionKey, rowKey, json, true)
}

func (tableStorageProxy *TableStorageProxy) InsertOrMergeEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("MERGE", tableName, partitionKey, rowKey, json, false)
}

func (tableStorageProxy *TableStorageProxy) InsertOrReplaceEntity(tableName string, partitionKey string, rowKey string, json []byte) {
	tableStorageProxy.executeEntityRequest("PUT", tableName, partitionKey, rowKey, json, false)
}

func (tableStorageProxy *TableStorageProxy) DeleteTable(tableName string) {
	tableStorageProxy.executeCommonRequest("DELETE", tableName, "", nil, false, false, true, false)
}

type CreateTableArgs struct {
	TableName string
}

func (tableStorageProxy *TableStorageProxy) CreateTable(tableName string) {
	json, _ := json.Marshal(CreateTableArgs{TableName: tableName})
	tableStorageProxy.executeCommonRequest("POST", "Tables", "", json, false, true, false, false)
}

func (tableStorageProxy *TableStorageProxy) InsertEntity(tableName string, json []byte) {
	tableStorageProxy.executeCommonRequest("POST", tableName, "", json, false, true, false, false)
}

func (tableStorageProxy *TableStorageProxy) executeEntityRequest(httpVerb string, tableName string, partitionKey string, rowKey string, json []byte, useIfMatch bool) {
	tableStorageProxy.executeCommonRequest(httpVerb, tableName+"%28PartitionKey=%27"+partitionKey+"%27,RowKey=%27"+rowKey+"%27%29", "", json, useIfMatch, false, false, false)
}

func (tableStorageProxy *TableStorageProxy) executeCommonRequest(httpVerb string, target string, query string, json []byte, useIfMatch bool, useAccept bool, useContentTypeXML bool, useSecondary bool) ([]byte, int) {
	xmsdate, Authentication := tableStorageProxy.calculateDateAndAuthentication(target)

	baseUrl := ""
	if useSecondary {
		baseUrl = tableStorageProxy.secondaryBaseUrl
	} else {
		baseUrl = tableStorageProxy.baseUrl
	}

	client := &http.Client{}
	request, _ := http.NewRequest(httpVerb, baseUrl+target+query, bytes.NewBuffer(json))

	if json != nil {
		request.Header.Set("Content-Type", "application/json")
		request.Header.Set("Content-Length", string(len(json)))
	}

	if useContentTypeXML {
		request.Header.Set("Content-Type", "application/atom+xml")
	}

	if useIfMatch {
		request.Header.Set("If-Match", "*")
	}

	if useAccept {
		request.Header.Set("Accept", "application/json;odata=nometadata")
	}

	request.Header.Set("x-ms-date", xmsdate)
	request.Header.Set("x-ms-version", "2013-08-15")
	request.Header.Set("Authorization", Authentication)

	response, err := client.Do(request)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}

	if tableStorageProxy.goHaveStorage.DumpSessions() {
		responseDump, _ := httputil.DumpResponse(response, true)
		requestDump, _ := httputil.DumpRequest(request, true)

		fmt.Printf("Request: %s\n", requestDump)
		fmt.Printf("%s\n", string(json))
		fmt.Printf("Response: %s\n", responseDump)
	}

	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}

	return contents, response.StatusCode
}

func (tableStorageProxy *TableStorageProxy) calculateDateAndAuthentication(target string) (string, string) {
	xmsdate := strings.Replace(time.Now().UTC().Add(-time.Minute).Format(time.RFC1123), "UTC", "GMT", -1)
	SignatureString := xmsdate + "\n/" + tableStorageProxy.goHaveStorage.GetAccount() + "/" + target
	Authentication := "SharedKeyLite " + tableStorageProxy.goHaveStorage.GetAccount() + ":" + computeHmac256(SignatureString, tableStorageProxy.goHaveStorage.GetKey())
	return xmsdate, Authentication
}

func computeHmac256(message string, key []byte) string {
	h := hmac.New(sha256.New, key)
	h.Write([]byte(message))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
<|endoftext|>


<commit_before><commit_msg>[go][tour] Finished up to "Exercise: Errors"<commit_after><|endoftext|>


<commit_before>package graphite

import (
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/influxdb/influxdb/models"
)

var (
	defaultTemplate *template
	MinDate         = time.Date(1901, 12, 13, 0, 0, 0, 0, time.UTC)
	MaxDate         = time.Date(2038, 1, 19, 0, 0, 0, 0, time.UTC)
)

func init() {
	var err error
	defaultTemplate, err = NewTemplate("measurement*", nil, DefaultSeparator)
	if err != nil {
		panic(err)
	}
}

// Parser encapsulates a Graphite Parser.
type Parser struct {
	matcher *matcher
	tags    models.Tags
}

// Options are configurable values that can be provided to a Parser
type Options struct {
	Separator   string
	Templates   []string
	DefaultTags models.Tags
}

// NewParserWithOptions returns a graphite parser using the given options
func NewParserWithOptions(options Options) (*Parser, error) {

	matcher := newMatcher()
	matcher.AddDefaultTemplate(defaultTemplate)

	for _, pattern := range options.Templates {

		template := pattern
		filter := ""
		// Format is [filter] <template> [tag1=value1,tag2=value2]
		parts := strings.Fields(pattern)
		if len(parts) >= 2 {
			if strings.Contains(parts[1], "=") {
				template = parts[0]
			} else {
				filter = parts[0]
				template = parts[1]
			}
		}

		// Parse out the default tags specific to this template
		tags := models.Tags{}
		if strings.Contains(parts[len(parts)-1], "=") {
			tagStrs := strings.Split(parts[len(parts)-1], ",")
			for _, kv := range tagStrs {
				parts := strings.Split(kv, "=")
				tags[parts[0]] = parts[1]
			}
		}

		tmpl, err := NewTemplate(template, tags, options.Separator)
		if err != nil {
			return nil, err
		}
		matcher.Add(filter, tmpl)
	}
	return &Parser{matcher: matcher, tags: options.DefaultTags}, nil
}

// NewParser returns a GraphiteParser instance.
func NewParser(templates []string, defaultTags models.Tags) (*Parser, error) {
	return NewParserWithOptions(
		Options{
			Templates:   templates,
			DefaultTags: defaultTags,
			Separator:   DefaultSeparator,
		})
}

// Parse performs Graphite parsing of a single line.
func (p *Parser) Parse(line string) (models.Point, error) {
	// Break into 3 fields (name, value, timestamp).
	fields := strings.Fields(line)
	if len(fields) != 2 && len(fields) != 3 {
		return nil, fmt.Errorf("received %q which doesn't have required fields", line)
	}

	// decode the name and tags
	matcher := p.matcher.Match(fields[0])
	measurement, tags, field := matcher.Apply(fields[0])

	// Could not extract measurement, use the raw value
	if measurement == "" {
		measurement = fields[0]
	}

	// Parse value.
	v, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, fmt.Errorf(`field "%s" value: %s`, fields[0], err)
	}

	if field != "" {
		fieldValues := map[string]interface{}{field: v}
	} else {
		fieldValues := map[string]interface{}{"value": v}
	}

	// If no 3rd field, use now as timestamp
	timestamp := time.Now().UTC()

	if len(fields) == 3 {
		// Parse timestamp.
		unixTime, err := strconv.ParseFloat(fields[2], 64)
		if err != nil {
			return nil, fmt.Errorf(`field "%s" time: %s`, fields[0], err)
		}

		// -1 is a special value that gets converted to current UTC time
		// See https://github.com/graphite-project/carbon/issues/54
		if unixTime != float64(-1) {
			// Check if we have fractional seconds
			timestamp = time.Unix(int64(unixTime), int64((unixTime-math.Floor(unixTime))*float64(time.Second)))
			if timestamp.Before(MinDate) || timestamp.After(MaxDate) {
				return nil, fmt.Errorf("timestamp out of range")
			}
		}
	}

	// Set the default tags on the point if they are not already set
	for k, v := range p.tags {
		if _, ok := tags[k]; !ok {
			tags[k] = v
		}
	}
	point := models.NewPoint(measurement, tags, fieldValues, timestamp)

	return point, nil
}

// template represents a pattern and tags to map a graphite metric string to a influxdb Point
type template struct {
	tags              []string
	defaultTags       models.Tags
	greedyMeasurement bool
	separator         string
}

func NewTemplate(pattern string, defaultTags models.Tags, separator string) (*template, error) {
	tags := strings.Split(pattern, ".")
	hasMeasurement := false
	template := &template{tags: tags, defaultTags: defaultTags, separator: separator}

	for _, tag := range tags {
		if strings.HasPrefix(tag, "measurement") {
			hasMeasurement = true
		}
		if tag == "measurement*" {
			template.greedyMeasurement = true
		}
	}

	if !hasMeasurement {
		return nil, fmt.Errorf("no measurement specified for template. %q", pattern)
	}

	return template, nil
}

// Apply extracts the template fields form the given line and returns the measurement
// name and tags
func (t *template) Apply(line string) (string, map[string]string, string) {
	fields := strings.Split(line, ".")
	var (
		measurement []string
		tags        = make(map[string]string)
		field       string
	)

	// Set any default tags
	for k, v := range t.defaultTags {
		tags[k] = v
	}

	for i, tag := range t.tags {
		if i >= len(fields) {
			continue
		}

		if tag == "measurement" {
			measurement = append(measurement, fields[i])
		} else if tag == "field" {
      // FIXME: cant add error here..
      //if len(field) == 0 {
      //  // FIXME - more informative error message
			//	return nil, fmt.Errorf("template can only have one field defined")
			//}
			field = field
		} else if tag == "measurement*" {
			measurement = append(measurement, fields[i:]...)
			break
		} else if tag != "" {
			tags[tag] = fields[i]
		}
	}

	return strings.Join(measurement, t.separator), tags, field
}

// matcher determines which template should be applied to a given metric
// based on a filter tree.
type matcher struct {
	root            *node
	defaultTemplate *template
}

func newMatcher() *matcher {
	return &matcher{
		root: &node{},
	}
}

// Add inserts the template in the filter tree based the given filter
func (m *matcher) Add(filter string, template *template) {
	if filter == "" {
		m.AddDefaultTemplate(template)
		return
	}
	m.root.Insert(filter, template)
}

func (m *matcher) AddDefaultTemplate(template *template) {
	m.defaultTemplate = template
}

// Match returns the template that matches the given graphite line
func (m *matcher) Match(line string) *template {
	tmpl := m.root.Search(line)
	if tmpl != nil {
		return tmpl
	}

	return m.defaultTemplate
}

// node is an item in a sorted k-ary tree.  Each child is sorted by its value.
// The special value of "*", is always last.
type node struct {
	value    string
	children nodes
	template *template
}

func (n *node) insert(values []string, template *template) {
	// Add the end, set the template
	if len(values) == 0 {
		n.template = template
		return
	}

	// See if the the current element already exists in the tree. If so, insert the
	// into that sub-tree
	for _, v := range n.children {
		if v.value == values[0] {
			v.insert(values[1:], template)
			return
		}
	}

	// New element, add it to the tree and sort the children
	newNode := &node{value: values[0]}
	n.children = append(n.children, newNode)
	sort.Sort(&n.children)

	// Now insert the rest of the tree into the new element
	newNode.insert(values[1:], template)
}

// Insert inserts the given string template into the tree.  The filter string is separated
// on "." and each part is used as the path in the tree.
func (n *node) Insert(filter string, template *template) {
	n.insert(strings.Split(filter, "."), template)
}

func (n *node) search(lineParts []string) *template {
	// Nothing to search
	if len(lineParts) == 0 || len(n.children) == 0 {
		return n.template
	}

	// If last element is a wildcard, don't include in this search since it's sorted
	// to the end but lexicographically it would not always be and sort.Search assumes
	// the slice is sorted.
	length := len(n.children)
	if n.children[length-1].value == "*" {
		length -= 1
	}

	// Find the index of child with an exact match
	i := sort.Search(length, func(i int) bool {
		return n.children[i].value >= lineParts[0]
	})

	// Found an exact match, so search that child sub-tree
	if i < len(n.children) && n.children[i].value == lineParts[0] {
		return n.children[i].search(lineParts[1:])
	}
	// Not an exact match, see if we have a wildcard child to search
	if n.children[len(n.children)-1].value == "*" {
		return n.children[len(n.children)-1].search(lineParts[1:])
	}
	return n.template
}

func (n *node) Search(line string) *template {
	return n.search(strings.Split(line, "."))
}

type nodes []*node

// Less returns a boolean indicating whether the filter at position j
// is less than the filter at position k.  Filters are order by string
// comparison of each component parts.  A wildcard value "*" is never
// less than a non-wildcard value.
//
// For example, the filters:
//             "*.*"
//             "servers.*"
//             "servers.localhost"
//             "*.localhost"
//
// Would be sorted as:
//             "servers.localhost"
//             "servers.*"
//             "*.localhost"
//             "*.*"
func (n *nodes) Less(j, k int) bool {
	if (*n)[j].value == "*" && (*n)[k].value != "*" {
		return false
	}

	if (*n)[j].value != "*" && (*n)[k].value == "*" {
		return true
	}

	return (*n)[j].value < (*n)[k].value
}

func (n *nodes) Swap(i, j int) { (*n)[i], (*n)[j] = (*n)[j], (*n)[i] }
func (n *nodes) Len() int      { return len(*n) }
<commit_msg>Working prototype..<commit_after>package graphite

import (
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/influxdb/influxdb/models"
)

var (
	defaultTemplate *template
	MinDate         = time.Date(1901, 12, 13, 0, 0, 0, 0, time.UTC)
	MaxDate         = time.Date(2038, 1, 19, 0, 0, 0, 0, time.UTC)
)

func init() {
	var err error
	defaultTemplate, err = NewTemplate("measurement*", nil, DefaultSeparator)
	if err != nil {
		panic(err)
	}
}

// Parser encapsulates a Graphite Parser.
type Parser struct {
	matcher *matcher
	tags    models.Tags
}

// Options are configurable values that can be provided to a Parser
type Options struct {
	Separator   string
	Templates   []string
	DefaultTags models.Tags
}

// NewParserWithOptions returns a graphite parser using the given options
func NewParserWithOptions(options Options) (*Parser, error) {

	matcher := newMatcher()
	matcher.AddDefaultTemplate(defaultTemplate)

	for _, pattern := range options.Templates {

		template := pattern
		filter := ""
		// Format is [filter] <template> [tag1=value1,tag2=value2]
		parts := strings.Fields(pattern)
		if len(parts) >= 2 {
			if strings.Contains(parts[1], "=") {
				template = parts[0]
			} else {
				filter = parts[0]
				template = parts[1]
			}
		}

		// Parse out the default tags specific to this template
		tags := models.Tags{}
		if strings.Contains(parts[len(parts)-1], "=") {
			tagStrs := strings.Split(parts[len(parts)-1], ",")
			for _, kv := range tagStrs {
				parts := strings.Split(kv, "=")
				tags[parts[0]] = parts[1]
			}
		}

		tmpl, err := NewTemplate(template, tags, options.Separator)
		if err != nil {
			return nil, err
		}
		matcher.Add(filter, tmpl)
	}
	return &Parser{matcher: matcher, tags: options.DefaultTags}, nil
}

// NewParser returns a GraphiteParser instance.
func NewParser(templates []string, defaultTags models.Tags) (*Parser, error) {
	return NewParserWithOptions(
		Options{
			Templates:   templates,
			DefaultTags: defaultTags,
			Separator:   DefaultSeparator,
		})
}

// Parse performs Graphite parsing of a single line.
func (p *Parser) Parse(line string) (models.Point, error) {
	// Break into 3 fields (name, value, timestamp).
	fields := strings.Fields(line)
	if len(fields) != 2 && len(fields) != 3 {
		return nil, fmt.Errorf("received %q which doesn't have required fields", line)
	}

	// decode the name and tags
	matcher := p.matcher.Match(fields[0])
	measurement, tags, field := matcher.Apply(fields[0])

	// Could not extract measurement, use the raw value
	if measurement == "" {
		measurement = fields[0]
	}

	// Parse value.
	v, err := strconv.ParseFloat(fields[1], 64)
	if err != nil {
		return nil, fmt.Errorf(`field "%s" value: %s`, fields[0], err)
	}

  fieldValues := map[string]interface{}{}
	if field != "" {
    fieldValues[field] = v
	} else {
    fieldValues["value"] = v
	}

	// If no 3rd field, use now as timestamp
	timestamp := time.Now().UTC()

	if len(fields) == 3 {
		// Parse timestamp.
		unixTime, err := strconv.ParseFloat(fields[2], 64)
		if err != nil {
			return nil, fmt.Errorf(`field "%s" time: %s`, fields[0], err)
		}

		// -1 is a special value that gets converted to current UTC time
		// See https://github.com/graphite-project/carbon/issues/54
		if unixTime != float64(-1) {
			// Check if we have fractional seconds
			timestamp = time.Unix(int64(unixTime), int64((unixTime-math.Floor(unixTime))*float64(time.Second)))
			if timestamp.Before(MinDate) || timestamp.After(MaxDate) {
				return nil, fmt.Errorf("timestamp out of range")
			}
		}
	}

	// Set the default tags on the point if they are not already set
	for k, v := range p.tags {
		if _, ok := tags[k]; !ok {
			tags[k] = v
		}
	}
	point := models.NewPoint(measurement, tags, fieldValues, timestamp)

	return point, nil
}

// template represents a pattern and tags to map a graphite metric string to a influxdb Point
type template struct {
	tags              []string
	defaultTags       models.Tags
	greedyMeasurement bool
	separator         string
}

func NewTemplate(pattern string, defaultTags models.Tags, separator string) (*template, error) {
	tags := strings.Split(pattern, ".")
	hasMeasurement := false
	template := &template{tags: tags, defaultTags: defaultTags, separator: separator}

	for _, tag := range tags {
		if strings.HasPrefix(tag, "measurement") {
			hasMeasurement = true
		}
		if tag == "measurement*" {
			template.greedyMeasurement = true
		}
	}

	if !hasMeasurement {
		return nil, fmt.Errorf("no measurement specified for template. %q", pattern)
	}

	return template, nil
}

// Apply extracts the template fields form the given line and returns the measurement
// name and tags
func (t *template) Apply(line string) (string, map[string]string, string) {
	fields := strings.Split(line, ".")
	var (
		measurement []string
		tags        = make(map[string]string)
		field       string
	)

	// Set any default tags
	for k, v := range t.defaultTags {
		tags[k] = v
	}

	for i, tag := range t.tags {
		if i >= len(fields) {
			continue
		}

		if tag == "measurement" {
			measurement = append(measurement, fields[i])
		} else if tag == "field" {
			field = fields[i]
		} else if tag == "measurement*" {
			measurement = append(measurement, fields[i:]...)
			break
		} else if tag != "" {
			tags[tag] = fields[i]
		}
	}

	return strings.Join(measurement, t.separator), tags, field
}

// matcher determines which template should be applied to a given metric
// based on a filter tree.
type matcher struct {
	root            *node
	defaultTemplate *template
}

func newMatcher() *matcher {
	return &matcher{
		root: &node{},
	}
}

// Add inserts the template in the filter tree based the given filter
func (m *matcher) Add(filter string, template *template) {
	if filter == "" {
		m.AddDefaultTemplate(template)
		return
	}
	m.root.Insert(filter, template)
}

func (m *matcher) AddDefaultTemplate(template *template) {
	m.defaultTemplate = template
}

// Match returns the template that matches the given graphite line
func (m *matcher) Match(line string) *template {
	tmpl := m.root.Search(line)
	if tmpl != nil {
		return tmpl
	}

	return m.defaultTemplate
}

// node is an item in a sorted k-ary tree.  Each child is sorted by its value.
// The special value of "*", is always last.
type node struct {
	value    string
	children nodes
	template *template
}

func (n *node) insert(values []string, template *template) {
	// Add the end, set the template
	if len(values) == 0 {
		n.template = template
		return
	}

	// See if the the current element already exists in the tree. If so, insert the
	// into that sub-tree
	for _, v := range n.children {
		if v.value == values[0] {
			v.insert(values[1:], template)
			return
		}
	}

	// New element, add it to the tree and sort the children
	newNode := &node{value: values[0]}
	n.children = append(n.children, newNode)
	sort.Sort(&n.children)

	// Now insert the rest of the tree into the new element
	newNode.insert(values[1:], template)
}

// Insert inserts the given string template into the tree.  The filter string is separated
// on "." and each part is used as the path in the tree.
func (n *node) Insert(filter string, template *template) {
	n.insert(strings.Split(filter, "."), template)
}

func (n *node) search(lineParts []string) *template {
	// Nothing to search
	if len(lineParts) == 0 || len(n.children) == 0 {
		return n.template
	}

	// If last element is a wildcard, don't include in this search since it's sorted
	// to the end but lexicographically it would not always be and sort.Search assumes
	// the slice is sorted.
	length := len(n.children)
	if n.children[length-1].value == "*" {
		length -= 1
	}

	// Find the index of child with an exact match
	i := sort.Search(length, func(i int) bool {
		return n.children[i].value >= lineParts[0]
	})

	// Found an exact match, so search that child sub-tree
	if i < len(n.children) && n.children[i].value == lineParts[0] {
		return n.children[i].search(lineParts[1:])
	}
	// Not an exact match, see if we have a wildcard child to search
	if n.children[len(n.children)-1].value == "*" {
		return n.children[len(n.children)-1].search(lineParts[1:])
	}
	return n.template
}

func (n *node) Search(line string) *template {
	return n.search(strings.Split(line, "."))
}

type nodes []*node

// Less returns a boolean indicating whether the filter at position j
// is less than the filter at position k.  Filters are order by string
// comparison of each component parts.  A wildcard value "*" is never
// less than a non-wildcard value.
//
// For example, the filters:
//             "*.*"
//             "servers.*"
//             "servers.localhost"
//             "*.localhost"
//
// Would be sorted as:
//             "servers.localhost"
//             "servers.*"
//             "*.localhost"
//             "*.*"
func (n *nodes) Less(j, k int) bool {
	if (*n)[j].value == "*" && (*n)[k].value != "*" {
		return false
	}

	if (*n)[j].value != "*" && (*n)[k].value == "*" {
		return true
	}

	return (*n)[j].value < (*n)[k].value
}

func (n *nodes) Swap(i, j int) { (*n)[i], (*n)[j] = (*n)[j], (*n)[i] }
func (n *nodes) Len() int      { return len(*n) }
<|endoftext|>


<commit_before>// 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.

// +build ignore

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"v.io/v23/naming"

	_ "v.io/x/ref/runtime/factories/generic"
)

var protocolFlag = protocolFlagVar{"tcp"}
var hostPortFlags = hostPortFlagVar{}

type protocolFlagVar struct {
	protocol string
}

func (pf *protocolFlagVar) Set(v string) error {
	pf.protocol = v
	return nil
}

func (pf *protocolFlagVar) String() string {
	return pf.protocol
}

type addrSpec struct {
	protocol, address string
}

type hostPortFlagVar struct {
	addrs []addrSpec
}

func (hpf *hostPortFlagVar) Set(v string) error {
	hpf.addrs = append(hpf.addrs, addrSpec{protocol: protocolFlag.String(), address: v})
	return nil
}

func (hpf *hostPortFlagVar) String() string {
	r := ""
	for _, a := range hpf.addrs {
		r += fmt.Sprintf("%s %s\n", a.protocol, a.address)
	}
	return strings.TrimRight(r, "\n")
}

func init() {
	flag.Var(&protocolFlag, "protocol", "protocol to use for subsequent host args")
	flag.Var(&hostPortFlags, "address", "<host:port>...")
}

func main() {
	ctx, shutdown := v23.Init()
	defer shutdown()

	for _, a := range hostPortFlags.addrs {
		ep, err := runtime.NewEndpoint(naming.FormatEndpoint(a.protocol, a.address))
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: %s\n", ep, err)
			os.Exit(1)
		}
		fmt.Printf("%s\n", ep)
	}
}
<commit_msg>naming: Remove unused tool.<commit_after><|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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 mount

import (
	"fmt"
	"os"
	"syscall"

	"k8s.io/klog"
)

// UnmountPath is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
func UnmountPath(mountPath string, mounter Interface) error {
	return UnmountMountPoint(mountPath, mounter, false /* extensiveMountPointCheck */)
}

// UnmountMountPoint is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts.
func UnmountMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error {
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists {
		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}
	return doUnmountMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt)
}

// doUnmountMountPoint is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts.
// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, Take it as an argument for convenience of testing
func doUnmountMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error {
	if !corruptedMnt {
		var notMnt bool
		var err error
		if extensiveMountPointCheck {
			notMnt, err = IsNotMountPoint(mounter, mountPath)
		} else {
			notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
		}

		if err != nil {
			return err
		}

		if notMnt {
			klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
			return os.Remove(mountPath)
		}
	}

	// Unmount the mount path
	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}

	notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
	if mntErr != nil {
		return mntErr
	}
	if notMnt {
		klog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
		return os.Remove(mountPath)
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// PathExists returns true if the specified path exists.
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else if IsCorruptedMnt(err) {
		return true, err
	} else {
		return false, err
	}
}

// IsCorruptedMnt return true if err is about corrupted mount point
func IsCorruptedMnt(err error) bool {
	if err == nil {
		return false
	}
	var underlyingError error
	switch pe := err.(type) {
	case nil:
		return false
	case *os.PathError:
		underlyingError = pe.Err
	case *os.LinkError:
		underlyingError = pe.Err
	case *os.SyscallError:
		underlyingError = pe.Err
	}

	return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO
}
<commit_msg>Add comments around use of PathExists<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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 mount

import (
	"fmt"
	"os"
	"syscall"

	"k8s.io/klog"
)

// UnmountPath is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
func UnmountPath(mountPath string, mounter Interface) error {
	return UnmountMountPoint(mountPath, mounter, false /* extensiveMountPointCheck */)
}

// UnmountMountPoint is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts.
func UnmountMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error {
	// mounter.ExistsPath cannot be used because for containerized kubelet, we need to check
	// the path in the kubelet container, not on the host.
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists {
		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}
	return doUnmountMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt)
}

// doUnmountMountPoint is a common unmount routine that unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts.
// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, Take it as an argument for convenience of testing
func doUnmountMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error {
	if !corruptedMnt {
		var notMnt bool
		var err error
		if extensiveMountPointCheck {
			notMnt, err = IsNotMountPoint(mounter, mountPath)
		} else {
			notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
		}

		if err != nil {
			return err
		}

		if notMnt {
			klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
			return os.Remove(mountPath)
		}
	}

	// Unmount the mount path
	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}

	notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
	if mntErr != nil {
		return mntErr
	}
	if notMnt {
		klog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
		return os.Remove(mountPath)
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// TODO: clean this up to use pkg/util/file/FileExists
// PathExists returns true if the specified path exists.
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else if IsCorruptedMnt(err) {
		return true, err
	} else {
		return false, err
	}
}

// IsCorruptedMnt return true if err is about corrupted mount point
func IsCorruptedMnt(err error) bool {
	if err == nil {
		return false
	}
	var underlyingError error
	switch pe := err.(type) {
	case nil:
		return false
	case *os.PathError:
		underlyingError = pe.Err
	case *os.LinkError:
		underlyingError = pe.Err
	case *os.SyscallError:
		underlyingError = pe.Err
	}

	return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO
}
<|endoftext|>


<commit_before>// +build !consulent

package state

import (
	"fmt"

	"github.com/hashicorp/consul/agent/structs"
	memdb "github.com/hashicorp/go-memdb"
)

// servicesTableSchema returns a new table schema used to store information
// about services.
func servicesTableSchema() *memdb.TableSchema {
	return &memdb.TableSchema{
		Name: "services",
		Indexes: map[string]*memdb.IndexSchema{
			"id": &memdb.IndexSchema{
				Name:         "id",
				AllowMissing: false,
				Unique:       true,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "ServiceID",
							Lowercase: true,
						},
					},
				},
			},
			"node": &memdb.IndexSchema{
				Name:         "node",
				AllowMissing: false,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Node",
					Lowercase: true,
				},
			},
			"service": &memdb.IndexSchema{
				Name:         "service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "ServiceName",
					Lowercase: true,
				},
			},
			"connect": &memdb.IndexSchema{
				Name:         "connect",
				AllowMissing: true,
				Unique:       false,
				Indexer:      &IndexConnectService{},
			},
			"kind": &memdb.IndexSchema{
				Name:         "kind",
				AllowMissing: false,
				Unique:       false,
				Indexer:      &IndexServiceKind{},
			},
		},
	}
}

// checksTableSchema returns a new table schema used for storing and indexing
// health check information. Health checks have a number of different attributes
// we want to filter by, so this table is a bit more complex.
func checksTableSchema() *memdb.TableSchema {
	return &memdb.TableSchema{
		Name: "checks",
		Indexes: map[string]*memdb.IndexSchema{
			"id": &memdb.IndexSchema{
				Name:         "id",
				AllowMissing: false,
				Unique:       true,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "CheckID",
							Lowercase: true,
						},
					},
				},
			},
			"status": &memdb.IndexSchema{
				Name:         "status",
				AllowMissing: false,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Status",
					Lowercase: false,
				},
			},
			"service": &memdb.IndexSchema{
				Name:         "service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "ServiceName",
					Lowercase: true,
				},
			},
			"node": &memdb.IndexSchema{
				Name:         "node",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Node",
					Lowercase: true,
				},
			},
			"node_service_check": &memdb.IndexSchema{
				Name:         "node_service_check",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.FieldSetIndex{
							Field: "ServiceID",
						},
					},
				},
			},
			"node_service": &memdb.IndexSchema{
				Name:         "node_service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "ServiceID",
							Lowercase: true,
						},
					},
				},
			},
		},
	}
}

func serviceIndexName(name string, _ *structs.EnterpriseMeta) string {
	return fmt.Sprintf("service.%s", name)
}

func serviceKindIndexName(kind structs.ServiceKind, _ *structs.EnterpriseMeta) string {
	switch kind {
	case structs.ServiceKindTypical:
		// needs a special case here
		return "service_kind.typical"
	default:
		return "service_kind." + string(kind)
	}
}

func (s *Store) catalogUpdateServicesIndexes(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	// overall services index
	if err := indexUpdateMaxTxn(tx, idx, "services"); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceKindIndexes(tx *memdb.Txn, kind structs.ServiceKind, idx uint64, _ *structs.EnterpriseMeta) error {
	// service-kind index
	if err := indexUpdateMaxTxn(tx, idx, serviceKindIndexName(kind, nil)); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceIndexes(tx *memdb.Txn, serviceName string, idx uint64, _ *structs.EnterpriseMeta) error {
	// per-service index
	if err := indexUpdateMaxTxn(tx, idx, serviceIndexName(serviceName, nil)); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceExtinctionIndex(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	if err := tx.Insert("index", &IndexEntry{serviceLastExtinctionIndexName, idx}); err != nil {
		return fmt.Errorf("failed updating missing service extinction index: %s", err)
	}
	return nil
}

func (s *Store) catalogInsertService(tx *memdb.Txn, svc *structs.ServiceNode) error {
	// Insert the service and update the index
	if err := tx.Insert("services", svc); err != nil {
		return fmt.Errorf("failed inserting service: %s", err)
	}

	// overall services index
	if err := tx.Insert("index", &IndexEntry{"services", svc.ModifyIndex}); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	if err := s.catalogUpdateServiceIndexes(tx, svc.ServiceName, svc.ModifyIndex, &svc.EnterpriseMeta); err != nil {
		return err
	}
	return nil
}

func (s *Store) catalogServicesMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) uint64 {
	return maxIndexTxn(tx, "services")
}

func (s *Store) catalogServiceMaxIndex(tx *memdb.Txn, serviceName string, _ *structs.EnterpriseMeta) (<-chan struct{}, interface{}, error) {
	return tx.FirstWatch("index", "id", serviceIndexName(serviceName, nil))
}

func (s *Store) catalogServiceKindMaxIndex(tx *memdb.Txn, ws memdb.WatchSet, kind structs.ServiceKind, entMeta *structs.EnterpriseMeta) uint64 {
	return maxIndexWatchTxn(tx, ws, serviceKindIndexName(kind, nil))
}

func (s *Store) catalogServiceList(tx *memdb.Txn, _ *structs.EnterpriseMeta, _ bool) (memdb.ResultIterator, error) {
	return tx.Get("services", "id")
}

func (s *Store) catalogServiceListByKind(tx *memdb.Txn, kind structs.ServiceKind, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("services", "kind", string(kind))
}

func (s *Store) catalogServiceListByNode(tx *memdb.Txn, node string, _ *structs.EnterpriseMeta, _ bool) (memdb.ResultIterator, error) {
	return tx.Get("services", "node", node)
}

func (s *Store) catalogServiceNodeList(tx *memdb.Txn, name string, index string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("services", index, name)
}

func (s *Store) catalogServiceLastExtinctionIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) (interface{}, error) {
	return tx.First("index", "id", serviceLastExtinctionIndexName)
}

func (s *Store) catalogMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta, checks bool) uint64 {
	if checks {
		return maxIndexTxn(tx, "nodes", "services", "checks")
	}
	return maxIndexTxn(tx, "nodes", "services")
}

func (s *Store) catalogUpdateCheckIndexes(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	// update the universal index entry
	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}
	return nil
}

func (s *Store) catalogChecksMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) uint64 {
	return maxIndexTxn(tx, "checks")
}

func (s *Store) catalogListChecksByNode(tx *memdb.Txn, node string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node", node)
}

func (s *Store) catalogListChecksByService(tx *memdb.Txn, service string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "service", service)
}

func (s *Store) catalogListChecksInState(tx *memdb.Txn, state string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	// simpler than normal due to the use of the CompoundMultiIndex
	return tx.Get("checks", "status", state)
}

func (s *Store) catalogListChecks(tx *memdb.Txn, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "id")
}

func (s *Store) catalogListNodeChecks(tx *memdb.Txn, node string) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service_check", node, false)
}

func (s *Store) catalogListServiceChecks(tx *memdb.Txn, node string, service string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service", node, service)
}

func (s *Store) catalogInsertCheck(tx *memdb.Txn, chk *structs.HealthCheck, idx uint64) error {
	// Insert the check
	if err := tx.Insert("checks", chk); err != nil {
		return fmt.Errorf("failed inserting check: %s", err)
	}

	if err := s.catalogUpdateCheckIndexes(tx, idx, &chk.EnterpriseMeta); err != nil {
		return err
	}

	return nil
}

func (s *Store) catalogChecksForNodeService(tx *memdb.Txn, node string, service string, entMeta *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service", node, service)
}

func (s *Store) validateRegisterRequestTxn(tx *memdb.Txn, args *structs.RegisterRequest) (*structs.EnterpriseMeta, error) {
	return nil, nil
}

func (s *Store) ValidateRegisterRequest(args *structs.RegisterRequest) (*structs.EnterpriseMeta, error) {
	return nil, nil
}
<commit_msg>Fix blocking for ServiceDumping by kind (#6919)<commit_after>// +build !consulent

package state

import (
	"fmt"

	"github.com/hashicorp/consul/agent/structs"
	memdb "github.com/hashicorp/go-memdb"
)

// servicesTableSchema returns a new table schema used to store information
// about services.
func servicesTableSchema() *memdb.TableSchema {
	return &memdb.TableSchema{
		Name: "services",
		Indexes: map[string]*memdb.IndexSchema{
			"id": &memdb.IndexSchema{
				Name:         "id",
				AllowMissing: false,
				Unique:       true,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "ServiceID",
							Lowercase: true,
						},
					},
				},
			},
			"node": &memdb.IndexSchema{
				Name:         "node",
				AllowMissing: false,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Node",
					Lowercase: true,
				},
			},
			"service": &memdb.IndexSchema{
				Name:         "service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "ServiceName",
					Lowercase: true,
				},
			},
			"connect": &memdb.IndexSchema{
				Name:         "connect",
				AllowMissing: true,
				Unique:       false,
				Indexer:      &IndexConnectService{},
			},
			"kind": &memdb.IndexSchema{
				Name:         "kind",
				AllowMissing: false,
				Unique:       false,
				Indexer:      &IndexServiceKind{},
			},
		},
	}
}

// checksTableSchema returns a new table schema used for storing and indexing
// health check information. Health checks have a number of different attributes
// we want to filter by, so this table is a bit more complex.
func checksTableSchema() *memdb.TableSchema {
	return &memdb.TableSchema{
		Name: "checks",
		Indexes: map[string]*memdb.IndexSchema{
			"id": &memdb.IndexSchema{
				Name:         "id",
				AllowMissing: false,
				Unique:       true,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "CheckID",
							Lowercase: true,
						},
					},
				},
			},
			"status": &memdb.IndexSchema{
				Name:         "status",
				AllowMissing: false,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Status",
					Lowercase: false,
				},
			},
			"service": &memdb.IndexSchema{
				Name:         "service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "ServiceName",
					Lowercase: true,
				},
			},
			"node": &memdb.IndexSchema{
				Name:         "node",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.StringFieldIndex{
					Field:     "Node",
					Lowercase: true,
				},
			},
			"node_service_check": &memdb.IndexSchema{
				Name:         "node_service_check",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.FieldSetIndex{
							Field: "ServiceID",
						},
					},
				},
			},
			"node_service": &memdb.IndexSchema{
				Name:         "node_service",
				AllowMissing: true,
				Unique:       false,
				Indexer: &memdb.CompoundIndex{
					Indexes: []memdb.Indexer{
						&memdb.StringFieldIndex{
							Field:     "Node",
							Lowercase: true,
						},
						&memdb.StringFieldIndex{
							Field:     "ServiceID",
							Lowercase: true,
						},
					},
				},
			},
		},
	}
}

func serviceIndexName(name string, _ *structs.EnterpriseMeta) string {
	return fmt.Sprintf("service.%s", name)
}

func serviceKindIndexName(kind structs.ServiceKind, _ *structs.EnterpriseMeta) string {
	switch kind {
	case structs.ServiceKindTypical:
		// needs a special case here
		return "service_kind.typical"
	default:
		return "service_kind." + string(kind)
	}
}

func (s *Store) catalogUpdateServicesIndexes(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	// overall services index
	if err := indexUpdateMaxTxn(tx, idx, "services"); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceKindIndexes(tx *memdb.Txn, kind structs.ServiceKind, idx uint64, _ *structs.EnterpriseMeta) error {
	// service-kind index
	if err := indexUpdateMaxTxn(tx, idx, serviceKindIndexName(kind, nil)); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceIndexes(tx *memdb.Txn, serviceName string, idx uint64, _ *structs.EnterpriseMeta) error {
	// per-service index
	if err := indexUpdateMaxTxn(tx, idx, serviceIndexName(serviceName, nil)); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}

	return nil
}

func (s *Store) catalogUpdateServiceExtinctionIndex(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	if err := tx.Insert("index", &IndexEntry{serviceLastExtinctionIndexName, idx}); err != nil {
		return fmt.Errorf("failed updating missing service extinction index: %s", err)
	}
	return nil
}

func (s *Store) catalogInsertService(tx *memdb.Txn, svc *structs.ServiceNode) error {
	// Insert the service and update the index
	if err := tx.Insert("services", svc); err != nil {
		return fmt.Errorf("failed inserting service: %s", err)
	}

	if err := s.catalogUpdateServicesIndexes(tx, svc.ModifyIndex, &svc.EnterpriseMeta); err != nil {
		return err
	}

	if err := s.catalogUpdateServiceIndexes(tx, svc.ServiceName, svc.ModifyIndex, &svc.EnterpriseMeta); err != nil {
		return err
	}

	if err := s.catalogUpdateServiceKindIndexes(tx, svc.ServiceKind, svc.ModifyIndex, &svc.EnterpriseMeta); err != nil {
		return err
	}

	return nil
}

func (s *Store) catalogServicesMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) uint64 {
	return maxIndexTxn(tx, "services")
}

func (s *Store) catalogServiceMaxIndex(tx *memdb.Txn, serviceName string, _ *structs.EnterpriseMeta) (<-chan struct{}, interface{}, error) {
	return tx.FirstWatch("index", "id", serviceIndexName(serviceName, nil))
}

func (s *Store) catalogServiceKindMaxIndex(tx *memdb.Txn, ws memdb.WatchSet, kind structs.ServiceKind, entMeta *structs.EnterpriseMeta) uint64 {
	return maxIndexWatchTxn(tx, ws, serviceKindIndexName(kind, nil))
}

func (s *Store) catalogServiceList(tx *memdb.Txn, _ *structs.EnterpriseMeta, _ bool) (memdb.ResultIterator, error) {
	return tx.Get("services", "id")
}

func (s *Store) catalogServiceListByKind(tx *memdb.Txn, kind structs.ServiceKind, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("services", "kind", string(kind))
}

func (s *Store) catalogServiceListByNode(tx *memdb.Txn, node string, _ *structs.EnterpriseMeta, _ bool) (memdb.ResultIterator, error) {
	return tx.Get("services", "node", node)
}

func (s *Store) catalogServiceNodeList(tx *memdb.Txn, name string, index string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("services", index, name)
}

func (s *Store) catalogServiceLastExtinctionIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) (interface{}, error) {
	return tx.First("index", "id", serviceLastExtinctionIndexName)
}

func (s *Store) catalogMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta, checks bool) uint64 {
	if checks {
		return maxIndexTxn(tx, "nodes", "services", "checks")
	}
	return maxIndexTxn(tx, "nodes", "services")
}

func (s *Store) catalogUpdateCheckIndexes(tx *memdb.Txn, idx uint64, _ *structs.EnterpriseMeta) error {
	// update the universal index entry
	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
		return fmt.Errorf("failed updating index: %s", err)
	}
	return nil
}

func (s *Store) catalogChecksMaxIndex(tx *memdb.Txn, _ *structs.EnterpriseMeta) uint64 {
	return maxIndexTxn(tx, "checks")
}

func (s *Store) catalogListChecksByNode(tx *memdb.Txn, node string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node", node)
}

func (s *Store) catalogListChecksByService(tx *memdb.Txn, service string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "service", service)
}

func (s *Store) catalogListChecksInState(tx *memdb.Txn, state string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	// simpler than normal due to the use of the CompoundMultiIndex
	return tx.Get("checks", "status", state)
}

func (s *Store) catalogListChecks(tx *memdb.Txn, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "id")
}

func (s *Store) catalogListNodeChecks(tx *memdb.Txn, node string) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service_check", node, false)
}

func (s *Store) catalogListServiceChecks(tx *memdb.Txn, node string, service string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service", node, service)
}

func (s *Store) catalogInsertCheck(tx *memdb.Txn, chk *structs.HealthCheck, idx uint64) error {
	// Insert the check
	if err := tx.Insert("checks", chk); err != nil {
		return fmt.Errorf("failed inserting check: %s", err)
	}

	if err := s.catalogUpdateCheckIndexes(tx, idx, &chk.EnterpriseMeta); err != nil {
		return err
	}

	return nil
}

func (s *Store) catalogChecksForNodeService(tx *memdb.Txn, node string, service string, entMeta *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
	return tx.Get("checks", "node_service", node, service)
}

func (s *Store) validateRegisterRequestTxn(tx *memdb.Txn, args *structs.RegisterRequest) (*structs.EnterpriseMeta, error) {
	return nil, nil
}

func (s *Store) ValidateRegisterRequest(args *structs.RegisterRequest) (*structs.EnterpriseMeta, error) {
	return nil, nil
}
<|endoftext|>