<commit_before>// Copyright 2014 The oauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package oauth2 provides support for making
// OAuth2 authorized and authenticated HTTP requests.
// It can additionally grant authorization with Bearer JWT.
package oauth2

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type tokenRespBody struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"` // in seconds
	IdToken      string `json:"id_token"`
}

// TokenFetcher refreshes or fetches a new access token from the
// provider. It should return an error if it's not capable of
// retrieving a token.
type TokenFetcher interface {
	// FetchToken retrieves a new access token for the provider.
	// If the implementation doesn't know how to retrieve a new token,
	// it returns an error. The existing token may be nil.
	FetchToken(existing *Token) (*Token, error)
}

// Options represents options to provide OAuth 2.0 client credentials
// and access level. A sample configuration:
type Options struct {
	// ClientID is the OAuth client identifier used when communicating with
	// the configured OAuth provider.
	ClientID string `json:"client_id"`

	// ClientSecret is the OAuth client secret used when communicating with
	// the configured OAuth provider.
	ClientSecret string `json:"client_secret"`

	// RedirectURL is the URL to which the user will be returned after
	// granting (or denying) access.
	RedirectURL string `json:"redirect_url"`

	// Scopes optionally specifies a list of requested permission scopes.
	Scopes []string `json:"scopes,omitempty"`
}

// NewConfig creates a generic OAuth 2.0 configuration that talks
// to an OAuth 2.0 provider specified with authURL and tokenURL.
func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) {
	aURL, err := url.Parse(authURL)
	if err != nil {
		return nil, err
	}
	tURL, err := url.Parse(tokenURL)
	if err != nil {
		return nil, err
	}
	if opts.ClientID == "" {
		return nil, errors.New("oauth2: missing client ID")
	}
	return &Config{
		opts:     opts,
		authURL:  aURL,
		tokenURL: tURL,
	}, nil
}

// Config represents the configuration of an OAuth 2.0 consumer client.
type Config struct {
	// Client is the HTTP client to be used to retrieve
	// tokens from the OAuth 2.0 provider.
	Client *http.Client

	// Transport is the http.RoundTripper to be used
	// to construct new oauth2.Transport instances from
	// this configuration.
	Transport http.RoundTripper

	opts *Options
	// AuthURL is the URL the user will be directed to
	// in order to grant access.
	authURL *url.URL
	// TokenURL is the URL used to retrieve OAuth tokens.
	tokenURL *url.URL
}

// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
// that asks for permissions for the required scopes explicitly.
//
// State is a token to protect the user from CSRF attacks. You must
// always provide a non-zero string and validate that it matches the
// the state query parameter on your redirect callback.
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
//
// Access type is an OAuth extension that gets sent as the
// "access_type" field in the URL from AuthCodeURL.
// It may be "online" (default) or "offline".
// If your application needs to refresh access tokens when the
// user is not present at the browser, then use offline. This
// will result in your application obtaining a refresh token
// the first time your application exchanges an authorization
// code for a user.
//
// Approval prompt indicates whether the user should be
// re-prompted for consent. If set to "auto" (default) the
// user will be prompted only if they haven't previously
// granted consent and the code can only be exchanged for an
// access token. If set to "force" the user will always be prompted,
// and the code can be exchanged for a refresh token.
func (c *Config) AuthCodeURL(state, accessType, prompt string) (authURL string) {
	u := *c.authURL
	v := url.Values{
		"response_type":   {"code"},
		"client_id":       {c.opts.ClientID},
		"redirect_uri":    condVal(c.opts.RedirectURL),
		"scope":           condVal(strings.Join(c.opts.Scopes, " ")),
		"state":           condVal(state),
		"access_type":     condVal(accessType),
		"approval_prompt": condVal(prompt),
	}
	q := v.Encode()
	if u.RawQuery == "" {
		u.RawQuery = q
	} else {
		u.RawQuery += "&" + q
	}
	return u.String()
}

// NewTransport creates a new authorizable transport. It doesn't
// initialize the new transport with a token, so after creation,
// you need to set a valid token (or an expired token with a valid
// refresh token) in order to be able to do authorized requests.
func (c *Config) NewTransport() *Transport {
	return NewTransport(c.transport(), c, nil)
}

// NewTransportWithCode exchanges the OAuth 2.0 authorization code with
// the provider to fetch a new access token (and refresh token). Once
// it succesffully retrieves a new token, creates a new transport
// authorized with it.
func (c *Config) NewTransportWithCode(code string) (*Transport, error) {
	token, err := c.Exchange(code)
	if err != nil {
		return nil, err
	}
	return NewTransport(c.transport(), c, token), nil
}

// FetchToken retrieves a new access token and updates the existing token
// with the newly fetched credentials. If existing token doesn't
// contain a refresh token, it returns an error.
func (c *Config) FetchToken(existing *Token) (*Token, error) {
	if existing == nil || existing.RefreshToken == "" {
		return nil, errors.New("oauth2: cannot fetch access token without refresh token")
	}
	return c.retrieveToken(url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {existing.RefreshToken},
	})
}

// Exchange exchanges the authorization code with the OAuth 2.0 provider
// to retrieve a new access token.
func (c *Config) Exchange(code string) (*Token, error) {
	return c.retrieveToken(url.Values{
		"grant_type":   {"authorization_code"},
		"code":         {code},
		"redirect_uri": condVal(c.opts.RedirectURL),
		"scope":        condVal(strings.Join(c.opts.Scopes, " ")),
	})
}

func (c *Config) retrieveToken(v url.Values) (*Token, error) {
	v.Set("client_id", c.opts.ClientID)
	bustedAuth := !providerAuthHeaderWorks(c.tokenURL.String())
	if bustedAuth && c.opts.ClientSecret != "" {
		v.Set("client_secret", c.opts.ClientSecret)
	}
	req, err := http.NewRequest("POST", c.tokenURL.String(), strings.NewReader(v.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	if !bustedAuth && c.opts.ClientSecret != "" {
		req.SetBasicAuth(c.opts.ClientID, c.opts.ClientSecret)
	}
	r, err := c.client().Do(req)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
	}
	if c := r.StatusCode; c < 200 || c > 299 {
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
	}

	resp := &tokenRespBody{}
	content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
	switch content {
	case "application/x-www-form-urlencoded", "text/plain":
		vals, err := url.ParseQuery(string(body))
		if err != nil {
			return nil, err
		}
		resp.AccessToken = vals.Get("access_token")
		resp.TokenType = vals.Get("token_type")
		resp.RefreshToken = vals.Get("refresh_token")
		resp.ExpiresIn, _ = strconv.ParseInt(vals.Get("expires_in"), 10, 64)
		resp.IdToken = vals.Get("id_token")
	default:
		if err = json.Unmarshal(body, &resp); err != nil {
			return nil, err
		}
	}
	token := &Token{
		AccessToken:  resp.AccessToken,
		TokenType:    resp.TokenType,
		RefreshToken: resp.RefreshToken,
	}
	// Don't overwrite `RefreshToken` with an empty value
	// if this was a token refreshing request.
	if resp.RefreshToken == "" {
		token.RefreshToken = v.Get("refresh_token")
	}
	if resp.ExpiresIn == 0 {
		token.Expiry = time.Time{}
	} else {
		token.Expiry = time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second)
	}
	if resp.IdToken != "" {
		if token.Extra == nil {
			token.Extra = make(map[string]string)
		}
		token.Extra["id_token"] = resp.IdToken
	}
	return token, nil
}

func (c *Config) transport() http.RoundTripper {
	if c.Transport != nil {
		return c.Transport
	}
	return http.DefaultTransport
}

func (c *Config) client() *http.Client {
	if c.Client != nil {
		return c.Client
	}
	return http.DefaultClient
}

func condVal(v string) []string {
	if v == "" {
		return nil
	}
	return []string{v}
}

// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
// implements the OAuth2 spec correctly
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
func providerAuthHeaderWorks(tokenURL string) bool {
	if strings.HasPrefix(tokenURL, "https://accounts.google.com/") ||
		strings.HasPrefix(tokenURL, "https://github.com/") ||
		strings.HasPrefix(tokenURL, "https://api.instagram.com/") ||
		strings.HasPrefix(tokenURL, "https://www.douban.com/") ||
		strings.HasPrefix(tokenURL, "https://api.dropbox.com/") {
		// Some sites fail to implement the OAuth2 spec fully.
		return false
	}

	// Assume the provider implements the spec properly
	// otherwise. We can add more exceptions as they're
	// discovered. We will _not_ be adding configurable hooks
	// to this package to let users select server bugs.
	return true
}
<commit_msg>Add Linkedin to the providers not supporting Auth headers.<commit_after>// Copyright 2014 The oauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package oauth2 provides support for making
// OAuth2 authorized and authenticated HTTP requests.
// It can additionally grant authorization with Bearer JWT.
package oauth2

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type tokenRespBody struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"` // in seconds
	IdToken      string `json:"id_token"`
}

// TokenFetcher refreshes or fetches a new access token from the
// provider. It should return an error if it's not capable of
// retrieving a token.
type TokenFetcher interface {
	// FetchToken retrieves a new access token for the provider.
	// If the implementation doesn't know how to retrieve a new token,
	// it returns an error. The existing token may be nil.
	FetchToken(existing *Token) (*Token, error)
}

// Options represents options to provide OAuth 2.0 client credentials
// and access level. A sample configuration:
type Options struct {
	// ClientID is the OAuth client identifier used when communicating with
	// the configured OAuth provider.
	ClientID string `json:"client_id"`

	// ClientSecret is the OAuth client secret used when communicating with
	// the configured OAuth provider.
	ClientSecret string `json:"client_secret"`

	// RedirectURL is the URL to which the user will be returned after
	// granting (or denying) access.
	RedirectURL string `json:"redirect_url"`

	// Scopes optionally specifies a list of requested permission scopes.
	Scopes []string `json:"scopes,omitempty"`
}

// NewConfig creates a generic OAuth 2.0 configuration that talks
// to an OAuth 2.0 provider specified with authURL and tokenURL.
func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) {
	aURL, err := url.Parse(authURL)
	if err != nil {
		return nil, err
	}
	tURL, err := url.Parse(tokenURL)
	if err != nil {
		return nil, err
	}
	if opts.ClientID == "" {
		return nil, errors.New("oauth2: missing client ID")
	}
	return &Config{
		opts:     opts,
		authURL:  aURL,
		tokenURL: tURL,
	}, nil
}

// Config represents the configuration of an OAuth 2.0 consumer client.
type Config struct {
	// Client is the HTTP client to be used to retrieve
	// tokens from the OAuth 2.0 provider.
	Client *http.Client

	// Transport is the http.RoundTripper to be used
	// to construct new oauth2.Transport instances from
	// this configuration.
	Transport http.RoundTripper

	opts *Options
	// AuthURL is the URL the user will be directed to
	// in order to grant access.
	authURL *url.URL
	// TokenURL is the URL used to retrieve OAuth tokens.
	tokenURL *url.URL
}

// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
// that asks for permissions for the required scopes explicitly.
//
// State is a token to protect the user from CSRF attacks. You must
// always provide a non-zero string and validate that it matches the
// the state query parameter on your redirect callback.
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
//
// Access type is an OAuth extension that gets sent as the
// "access_type" field in the URL from AuthCodeURL.
// It may be "online" (default) or "offline".
// If your application needs to refresh access tokens when the
// user is not present at the browser, then use offline. This
// will result in your application obtaining a refresh token
// the first time your application exchanges an authorization
// code for a user.
//
// Approval prompt indicates whether the user should be
// re-prompted for consent. If set to "auto" (default) the
// user will be prompted only if they haven't previously
// granted consent and the code can only be exchanged for an
// access token. If set to "force" the user will always be prompted,
// and the code can be exchanged for a refresh token.
func (c *Config) AuthCodeURL(state, accessType, prompt string) (authURL string) {
	u := *c.authURL
	v := url.Values{
		"response_type":   {"code"},
		"client_id":       {c.opts.ClientID},
		"redirect_uri":    condVal(c.opts.RedirectURL),
		"scope":           condVal(strings.Join(c.opts.Scopes, " ")),
		"state":           condVal(state),
		"access_type":     condVal(accessType),
		"approval_prompt": condVal(prompt),
	}
	q := v.Encode()
	if u.RawQuery == "" {
		u.RawQuery = q
	} else {
		u.RawQuery += "&" + q
	}
	return u.String()
}

// NewTransport creates a new authorizable transport. It doesn't
// initialize the new transport with a token, so after creation,
// you need to set a valid token (or an expired token with a valid
// refresh token) in order to be able to do authorized requests.
func (c *Config) NewTransport() *Transport {
	return NewTransport(c.transport(), c, nil)
}

// NewTransportWithCode exchanges the OAuth 2.0 authorization code with
// the provider to fetch a new access token (and refresh token). Once
// it succesffully retrieves a new token, creates a new transport
// authorized with it.
func (c *Config) NewTransportWithCode(code string) (*Transport, error) {
	token, err := c.Exchange(code)
	if err != nil {
		return nil, err
	}
	return NewTransport(c.transport(), c, token), nil
}

// FetchToken retrieves a new access token and updates the existing token
// with the newly fetched credentials. If existing token doesn't
// contain a refresh token, it returns an error.
func (c *Config) FetchToken(existing *Token) (*Token, error) {
	if existing == nil || existing.RefreshToken == "" {
		return nil, errors.New("oauth2: cannot fetch access token without refresh token")
	}
	return c.retrieveToken(url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {existing.RefreshToken},
	})
}

// Exchange exchanges the authorization code with the OAuth 2.0 provider
// to retrieve a new access token.
func (c *Config) Exchange(code string) (*Token, error) {
	return c.retrieveToken(url.Values{
		"grant_type":   {"authorization_code"},
		"code":         {code},
		"redirect_uri": condVal(c.opts.RedirectURL),
		"scope":        condVal(strings.Join(c.opts.Scopes, " ")),
	})
}

func (c *Config) retrieveToken(v url.Values) (*Token, error) {
	v.Set("client_id", c.opts.ClientID)
	bustedAuth := !providerAuthHeaderWorks(c.tokenURL.String())
	if bustedAuth && c.opts.ClientSecret != "" {
		v.Set("client_secret", c.opts.ClientSecret)
	}
	req, err := http.NewRequest("POST", c.tokenURL.String(), strings.NewReader(v.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	if !bustedAuth && c.opts.ClientSecret != "" {
		req.SetBasicAuth(c.opts.ClientID, c.opts.ClientSecret)
	}
	r, err := c.client().Do(req)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
	}
	if c := r.StatusCode; c < 200 || c > 299 {
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
	}

	resp := &tokenRespBody{}
	content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
	switch content {
	case "application/x-www-form-urlencoded", "text/plain":
		vals, err := url.ParseQuery(string(body))
		if err != nil {
			return nil, err
		}
		resp.AccessToken = vals.Get("access_token")
		resp.TokenType = vals.Get("token_type")
		resp.RefreshToken = vals.Get("refresh_token")
		resp.ExpiresIn, _ = strconv.ParseInt(vals.Get("expires_in"), 10, 64)
		resp.IdToken = vals.Get("id_token")
	default:
		if err = json.Unmarshal(body, &resp); err != nil {
			return nil, err
		}
	}
	token := &Token{
		AccessToken:  resp.AccessToken,
		TokenType:    resp.TokenType,
		RefreshToken: resp.RefreshToken,
	}
	// Don't overwrite `RefreshToken` with an empty value
	// if this was a token refreshing request.
	if resp.RefreshToken == "" {
		token.RefreshToken = v.Get("refresh_token")
	}
	if resp.ExpiresIn == 0 {
		token.Expiry = time.Time{}
	} else {
		token.Expiry = time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second)
	}
	if resp.IdToken != "" {
		if token.Extra == nil {
			token.Extra = make(map[string]string)
		}
		token.Extra["id_token"] = resp.IdToken
	}
	return token, nil
}

func (c *Config) transport() http.RoundTripper {
	if c.Transport != nil {
		return c.Transport
	}
	return http.DefaultTransport
}

func (c *Config) client() *http.Client {
	if c.Client != nil {
		return c.Client
	}
	return http.DefaultClient
}

func condVal(v string) []string {
	if v == "" {
		return nil
	}
	return []string{v}
}

// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
// implements the OAuth2 spec correctly
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
func providerAuthHeaderWorks(tokenURL string) bool {
	if strings.HasPrefix(tokenURL, "https://accounts.google.com/") ||
		strings.HasPrefix(tokenURL, "https://github.com/") ||
		strings.HasPrefix(tokenURL, "https://api.instagram.com/") ||
		strings.HasPrefix(tokenURL, "https://www.douban.com/") ||
		strings.HasPrefix(tokenURL, "https://api.dropbox.com/") ||
		strings.HasPrefix(tokenURL, "https://www.linkedin.com/") {
		// Some sites fail to implement the OAuth2 spec fully.
		return false
	}

	// Assume the provider implements the spec properly
	// otherwise. We can add more exceptions as they're
	// discovered. We will _not_ be adding configurable hooks
	// to this package to let users select server bugs.
	return true
}
<|endoftext|>


<commit_before>package hamster

import (
	"errors"
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"net/http"
	"time"
)

var oName = "objects"

type HamsterObject struct {
	//default fields
	Id             bson.ObjectId `bson:"_id" json:"-"`
	ParentId       bson.ObjectId `bson:"parentId" json:"-"`
	ObjectId       string        `bson:"-" json:"object_id"`
	ParentObjectId string        `bson:"-" json:"parent_id"`
	Created        time.Time     `bson:"created" json:"created"`
	Updated        time.Time     `bson:"updated" json:"updated"`
	//unknown fields
	M map[string]interface{} `bson:",inline" json:"-"`
}

//create new user defined object
func (s *Server) CreateObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("CreateObject: ")
	//get objectName
	object_name := s.getObjectName(w, r)
	//get app object id
	app_id := s.getAppObjectId(w, r)
	//verify app object id valid
	//get apps collection
	session := s.db.GetSession()
	defer session.Close()
	a := session.DB("").C(aName)

	//change
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"updated": time.Now(),
			},
			"$addToSet": bson.M{
				"objects": object_name,
			}}}

	//if app id exists, update
	app := App{}
	if _, err := a.FindId(bson.ObjectIdHex(app_id)).Apply(change, &app); err != nil {
		s.notFound(r, w, err, app_id+" : id not found")
		return
	}

	//fmt.Printf("app: %v\n", app)

	//parse body
	var obj interface{}
	s.readJson(&obj, r, w)

	//and marshal into hamster object
	hamster_obj := HamsterObject{}

	h, err := bson.Marshal(obj)
	if err != nil {
		s.internalError(r, w, err, "error marshalling hamster object")
	}
	bson.Unmarshal(h, &hamster_obj)

	//set fields
	hamster_obj.Id = bson.NewObjectId()
	hamster_obj.ParentId = bson.ObjectIdHex(app_id)
	hamster_obj.Created = time.Now()
	hamster_obj.Updated = time.Now()

	//get objects collection
	c := session.DB("").C(object_name)

	//then insert object
	if insert_err := c.Insert(hamster_obj); insert_err != nil {

		s.internalError(r, w, insert_err, "error inserting: "+fmt.Sprintf("%v", hamster_obj))

	} else {

		//find inlined object
		var result map[string]interface{}
		if err := c.FindId(hamster_obj.Id).Limit(1).One(&result); err != nil {
			s.notFound(r, w, err, hamster_obj.Id.Hex()+" : id not found")
			return
		}

		//append object_id,parent_id
		delete(result, "_id")
		result["object_id"] = encodeBase64Token(hamster_obj.Id.Hex())
		delete(result, "parentId")
		result["parent_id"] = encodeBase64Token(hamster_obj.ParentId.Hex())

		s.logger.Printf("created new object: %+v, id: %v\n", result)
		s.serveJson(w, &result)
	}

}

func (s *Server) CreateObjects(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("CreateObjects: ")
	//get param
	app_id := s.getAppObjectId(w, r)
	//parse body
	var obj map[string]interface{}
	s.readJson(&obj, r, w)

	if obj["__op"] != "InsertBatch" {
		s.badRequest(r, w, errors.New("expected batch insert op"), fmt.Sprintf("%v", obj["__op"]))
	}

	var object_name string
	object_name = obj["objectName"].(string)
	if obj["objectName"] == "" {
		s.badRequest(r, w, errors.New("expected objectName"), "")
	}

	//get apps collection
	session := s.db.GetSession()
	defer session.Close()
	a := session.DB("").C(aName)

	//change
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"updated": time.Now(),
			},
			"$addToSet": bson.M{
				"objects": object_name,
			}}}

	//if app id exists, update
	app := App{}
	if _, err := a.FindId(bson.ObjectIdHex(app_id)).Apply(change, &app); err != nil {
		s.notFound(r, w, err, app_id+" : id not found")
		return
	}

	var objects []map[string]interface{}
	objects = obj["objects"].([]map[string]interface{})

	hamster_objects := []HamsterObject{}

	//marshal incoming objects
	for _, object := range objects {
		hamster_obj := HamsterObject{}
		h, err := bson.Marshal(obj)
		if err != nil {
			s.internalError(r, w, err, "error marshalling hamster object: "+fmt.Sprintf("%v", object))
		}
		bson.Unmarshal(h, &hamster_obj)
		hamster_objects = append(hamster_objects, hamster_obj)

	}

	//set fields
	time_now := time.Now()
	for _, hamster_obj := range hamster_objects {
		hamster_obj.Id = bson.NewObjectId()
		hamster_obj.ParentId = bson.ObjectIdHex(app_id)
		hamster_obj.Created = time_now
		hamster_obj.Updated = time_now

	}

	//get objects collection
	c := session.DB("").C(object_name)

	//then insert object
	if insert_err := c.Insert(hamster_objects); insert_err != nil {

		s.internalError(r, w, insert_err, "error inserting: "+fmt.Sprintf("%v", hamster_objects))

	} else {

		//find inlined objects
		var results []map[string]interface{}
		if err := c.Find(bson.M{"created": bson.M{"$gte": time_now, "$lt": time.Now()}}).All(&results); err != nil {
			s.notFound(r, w, err, " : objects not found")
			return
		}

		for _, result := range results {
			//append object_id,parent_id
			//convert object id to base64
			result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
			delete(result, "_id")
			result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
			delete(result, "parentId")
		}

		s.logger.Printf("created new objects: %+v, id: %v\n", results)
		s.serveJson(w, &results)
	}

}

//query object
func (s *Server) QueryObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("QueryObject: ")
	object_name, object_id := s.getObjectParams(w, r)

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//find object
	var result map[string]interface{}
	if err := c.FindId(bson.ObjectIdHex(object_id)).Limit(1).One(&result); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//append object_id,parent_id
	//convert object id to base64
	result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
	delete(result, "_id")
	result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
	delete(result, "parentId")

	s.serveJson(w, &result)

}

//query objects
func (s *Server) QueryObjects(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("QueryObjects: ")

	object_name := s.getObjectName(w, r)

	//get collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//find apps
	var result []map[string]interface{}
	iter := c.Find(nil).Iter()
	err := iter.All(&result)
	if err != nil {
		s.internalError(r, w, err, "error iterating "+object_name+" documents")
	}

	//convert object id to base64
	for _, object := range result {
		object["object_id"] = encodeBase64Token(object["_id"].(bson.ObjectId).Hex())
		delete(object, "_id")
		object["parent_id"] = encodeBase64Token(object["parentId"].(bson.ObjectId).Hex())
		delete(object, "parentId")

	}

	s.serveJson(w, &result)

}

//update object
func (s *Server) UpdateObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("UpdateObject: ")
	object_name, object_id := s.getObjectParams(w, r)

	//parse body
	var u map[string]interface{}
	if err := s.readJson(&u, r, w); err != nil {
		s.badRequest(r, w, err, "malformed update request body")
		return
	}

	//add update field
	u["updated"] = time.Now()

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//change
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": u}}

	//find and update
	var result map[string]interface{}
	if _, err := c.FindId(bson.ObjectIdHex(object_id)).Apply(change, &result); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//append object_id,parent_id
	//convert object id to base64
	result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
	delete(result, "_id")
	result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
	delete(result, "parentId")

	s.serveJson(w, &result)

}

//delete object
func (s *Server) DeleteObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("DeleteObject: ")

	//get params
	object_name, object_id := s.getObjectParams(w, r)

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//delete
	if err := c.RemoveId(bson.ObjectIdHex(object_id)); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//respond
	response := DeleteResponse{Status: "ok"}
	s.serveJson(w, &response)

}
<commit_msg>descriptive comment<commit_after>package hamster

import (
	"errors"
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"net/http"
	"time"
)

var oName = "objects"

type HamsterObject struct {
	//default fields
	Id             bson.ObjectId `bson:"_id" json:"-"`
	ParentId       bson.ObjectId `bson:"parentId" json:"-"`
	ObjectId       string        `bson:"-" json:"object_id"`
	ParentObjectId string        `bson:"-" json:"parent_id"`
	Created        time.Time     `bson:"created" json:"created"`
	Updated        time.Time     `bson:"updated" json:"updated"`
	//unknown fields
	M map[string]interface{} `bson:",inline" json:"-"`
}

//create new user defined object
func (s *Server) CreateObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("CreateObject: ")
	//get objectName
	object_name := s.getObjectName(w, r)
	//get app object id
	app_id := s.getAppObjectId(w, r)
	//verify app object id valid
	//get apps collection
	session := s.db.GetSession()
	defer session.Close()
	a := session.DB("").C(aName)

	//change:update new object type name in app if it doesn't exist
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"updated": time.Now(),
			},
			"$addToSet": bson.M{
				"objects": object_name,
			}}}

	//if app id exists, update
	app := App{}
	if _, err := a.FindId(bson.ObjectIdHex(app_id)).Apply(change, &app); err != nil {
		s.notFound(r, w, err, app_id+" : id not found")
		return
	}

	//fmt.Printf("app: %v\n", app)

	//parse body
	var obj interface{}
	s.readJson(&obj, r, w)

	//and marshal into hamster object
	hamster_obj := HamsterObject{}

	h, err := bson.Marshal(obj)
	if err != nil {
		s.internalError(r, w, err, "error marshalling hamster object")
	}
	bson.Unmarshal(h, &hamster_obj)

	//set fields
	hamster_obj.Id = bson.NewObjectId()
	hamster_obj.ParentId = bson.ObjectIdHex(app_id)
	hamster_obj.Created = time.Now()
	hamster_obj.Updated = time.Now()

	//get objects collection
	c := session.DB("").C(object_name)

	//then insert object
	if insert_err := c.Insert(hamster_obj); insert_err != nil {

		s.internalError(r, w, insert_err, "error inserting: "+fmt.Sprintf("%v", hamster_obj))

	} else {

		//find inlined object
		var result map[string]interface{}
		if err := c.FindId(hamster_obj.Id).Limit(1).One(&result); err != nil {
			s.notFound(r, w, err, hamster_obj.Id.Hex()+" : id not found")
			return
		}

		//append object_id,parent_id
		delete(result, "_id")
		result["object_id"] = encodeBase64Token(hamster_obj.Id.Hex())
		delete(result, "parentId")
		result["parent_id"] = encodeBase64Token(hamster_obj.ParentId.Hex())

		s.logger.Printf("created new object: %+v, id: %v\n", result)
		s.serveJson(w, &result)
	}

}

func (s *Server) CreateObjects(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("CreateObjects: ")
	//get param
	app_id := s.getAppObjectId(w, r)
	//parse body
	var obj map[string]interface{}
	s.readJson(&obj, r, w)

	if obj["__op"] != "InsertBatch" {
		s.badRequest(r, w, errors.New("expected batch insert op"), fmt.Sprintf("%v", obj["__op"]))
	}

	var object_name string
	object_name = obj["objectName"].(string)
	if obj["objectName"] == "" {
		s.badRequest(r, w, errors.New("expected objectName"), "")
	}

	//get apps collection
	session := s.db.GetSession()
	defer session.Close()
	a := session.DB("").C(aName)

	//change:update new object type name in app if it doesn't exist
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"updated": time.Now(),
			},
			"$addToSet": bson.M{
				"objects": object_name,
			}}}

	//if app id exists, update
	app := App{}
	if _, err := a.FindId(bson.ObjectIdHex(app_id)).Apply(change, &app); err != nil {
		s.notFound(r, w, err, app_id+" : id not found")
		return
	}

	var objects []map[string]interface{}
	objects = obj["objects"].([]map[string]interface{})

	hamster_objects := []HamsterObject{}

	//marshal incoming objects
	for _, object := range objects {
		hamster_obj := HamsterObject{}
		h, err := bson.Marshal(obj)
		if err != nil {
			s.internalError(r, w, err, "error marshalling hamster object: "+fmt.Sprintf("%v", object))
		}
		bson.Unmarshal(h, &hamster_obj)
		hamster_objects = append(hamster_objects, hamster_obj)

	}

	//set fields
	time_now := time.Now()
	for _, hamster_obj := range hamster_objects {
		hamster_obj.Id = bson.NewObjectId()
		hamster_obj.ParentId = bson.ObjectIdHex(app_id)
		hamster_obj.Created = time_now
		hamster_obj.Updated = time_now

	}

	//get objects collection
	c := session.DB("").C(object_name)

	//then insert object
	if insert_err := c.Insert(hamster_objects); insert_err != nil {

		s.internalError(r, w, insert_err, "error inserting: "+fmt.Sprintf("%v", hamster_objects))

	} else {

		//find inlined objects
		var results []map[string]interface{}
		if err := c.Find(bson.M{"created": bson.M{"$gte": time_now, "$lt": time.Now()}}).All(&results); err != nil {
			s.notFound(r, w, err, " : objects not found")
			return
		}

		for _, result := range results {
			//append object_id,parent_id
			//convert object id to base64
			result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
			delete(result, "_id")
			result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
			delete(result, "parentId")
		}

		s.logger.Printf("created new objects: %+v, id: %v\n", results)
		s.serveJson(w, &results)
	}

}

//query object
func (s *Server) QueryObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("QueryObject: ")
	object_name, object_id := s.getObjectParams(w, r)

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//find object
	var result map[string]interface{}
	if err := c.FindId(bson.ObjectIdHex(object_id)).Limit(1).One(&result); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//append object_id,parent_id
	//convert object id to base64
	result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
	delete(result, "_id")
	result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
	delete(result, "parentId")

	s.serveJson(w, &result)

}

//query objects
func (s *Server) QueryObjects(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("QueryObjects: ")

	object_name := s.getObjectName(w, r)

	//get collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//find apps
	var result []map[string]interface{}
	iter := c.Find(nil).Iter()
	err := iter.All(&result)
	if err != nil {
		s.internalError(r, w, err, "error iterating "+object_name+" documents")
	}

	//convert object id to base64
	for _, object := range result {
		object["object_id"] = encodeBase64Token(object["_id"].(bson.ObjectId).Hex())
		delete(object, "_id")
		object["parent_id"] = encodeBase64Token(object["parentId"].(bson.ObjectId).Hex())
		delete(object, "parentId")

	}

	s.serveJson(w, &result)

}

//update object
func (s *Server) UpdateObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("UpdateObject: ")
	object_name, object_id := s.getObjectParams(w, r)

	//parse body
	var u map[string]interface{}
	if err := s.readJson(&u, r, w); err != nil {
		s.badRequest(r, w, err, "malformed update request body")
		return
	}

	//add update field
	u["updated"] = time.Now()

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//change
	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": u}}

	//find and update
	var result map[string]interface{}
	if _, err := c.FindId(bson.ObjectIdHex(object_id)).Apply(change, &result); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//append object_id,parent_id
	//convert object id to base64
	result["object_id"] = encodeBase64Token(result["_id"].(bson.ObjectId).Hex())
	delete(result, "_id")
	result["parent_id"] = encodeBase64Token(result["parentId"].(bson.ObjectId).Hex())
	delete(result, "parentId")

	s.serveJson(w, &result)

}

//delete object
func (s *Server) DeleteObject(w http.ResponseWriter, r *http.Request) {
	s.logger.SetPrefix("DeleteObject: ")

	//get params
	object_name, object_id := s.getObjectParams(w, r)

	//get object collection
	session := s.db.GetSession()
	defer session.Close()
	c := session.DB("").C(object_name)

	//delete
	if err := c.RemoveId(bson.ObjectIdHex(object_id)); err != nil {
		s.notFound(r, w, err, object_id+" : id not found")
		return
	}

	//respond
	response := DeleteResponse{Status: "ok"}
	s.serveJson(w, &response)

}
<|endoftext|>


<commit_before>package rados

/*
#cgo LDFLAGS: -lrados
#include "stdlib.h"
#include "stdint.h"
#include "rados/librados.h"
*/
import "C"

import (
    "fmt"
    "os"
    "time"
    "unsafe"
)

/* Object in a Ceph pool.
 *
 * Note on Ceph IO context: Object stores its last-used context for
 * filesystem-like access, however advanced users may read/write using
 * a specific context.
 */
type sys struct {
    ctx  C.rados_ioctx_t
    pool string
}

type Object struct {
    name    string
    size    int64
    modTime time.Time

    sys
}

/* Functions Size(), Mode(), ModTime(), Sys(), IsDir() used to fulfill os.FileStat interface. */

func (o *Object) Name() string {
    return o.name
}

func (o *Object) Size() int64 {
    return o.size
}

func (o *Object) Mode() os.FileMode {
    return 0 // Currently not used by RADOS
}

func (o *Object) ModTime() time.Time {
    return o.modTime
}

func (o *Object) Sys() interface{} {
    return o.sys
}

func (o *Object) IsDir() bool {
    return false
}

func (c *Context) Create(name string) (*Object, error) {
    err := c.Put(name, make([]byte, 0))

    if err != nil {
        return nil, err
    }

    // Stat the object to fill in the object structure
    obj, err := c.Stat(name)

    if err != nil {
        return nil, err
    }

    return obj.(*Object), nil
}

func (c *Context) Open(name string) (*Object, error) {
    objInfo, err := c.Stat(name)

    if err == nil {
        // Object exists, return a handle to it.
        return objInfo.(*Object), nil
    }

    // Stat failed, attempt to create the object
    obj, err := c.Create(name)

    if err != nil {
        return nil, err
    }

    return obj, nil
}

func (c *Context) Remove(name string) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_remove(c.ctx, cname); cerr != 0 {
        return fmt.Errorf("RADOS remove: %s: %s", name, strerror(cerr))
    }

    return nil
}

func (c *Context) Truncate(name string, size int64) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_trunc(c.ctx, cname, C.uint64_t(size)); cerr != 0 {
        return fmt.Errorf("RADOS trunc: %s: %s", name, strerror(cerr))
    }

    return nil
}

func byteSliceToBuffer(data []byte) (*C.char, C.size_t) {
    if len(data) > 0 {
        return (*C.char)(unsafe.Pointer(&data[0])), C.size_t(len(data))
    } else {
        return (*C.char)(unsafe.Pointer(&data)), C.size_t(0)
    }
}

func (c *Context) Put(name string, data []byte) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    cdata, cdatalen := byteSliceToBuffer(data)

    if cerr := C.rados_write_full(c.ctx, cname, cdata, cdatalen); cerr < 0 {
        return fmt.Errorf("RADOS put %s: %s", name, strerror(cerr))
    }

    return nil
}

func (c *Context) Get(name string) ([]byte, error) {
    obj, err := c.Stat(name)

    if err != nil {
        return nil, err
    }

    if obj.Size() == 0 {
        // Return an empty slice
        return make([]byte, 0), nil
    }

    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    data := make([]byte, obj.Size())
    cdata, cdatalen := byteSliceToBuffer(data)

    if cerr := C.rados_read(c.ctx, cname, cdata, cdatalen, 0); cerr < 0 {
        return nil, fmt.Errorf("RADOS get %s: %s", name, strerror(cerr))
    }

    return data, nil
}

func (c *Context) Stat(name string) (os.FileInfo, error) {
    var csize C.uint64_t
    var ctime C.time_t
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_stat(c.ctx, cname, &csize, &ctime); cerr < 0 {
        return nil, fmt.Errorf("RADOS stat %s: %s", name, strerror(cerr))
    }

    return &Object{
        name:    name,
        size:    int64(csize),
        modTime: time.Unix(int64(ctime), int64(0)),
        sys:     sys{ctx: c.ctx, pool: c.Pool},
    }, nil
}

// func (o *Object) WriteInContext(Context *c, ...)
// func (o *Object) ReadInContext(Context *c, ...)
<commit_msg>Implement ReadAt() and WriteAt() functions for object type.<commit_after>package rados

/*
#cgo LDFLAGS: -lrados
#include "stdlib.h"
#include "stdint.h"
#include "rados/librados.h"
*/
import "C"

import (
    "fmt"
    "io"
    "os"
    "time"
    "unsafe"
)

/* Object in a Ceph pool.
 *
 * Note on Ceph IO context: Object stores its last-used context for
 * filesystem-like access, however advanced users may read/write using
 * a specific context.
 */
type sys struct {
    ctx  C.rados_ioctx_t
    pool string
}

type Object struct {
    name    string
    size    int64
    modTime time.Time

    sys
}

/* Functions Size(), Mode(), ModTime(), Sys(), IsDir() used to fulfill os.FileStat interface. */

func (o *Object) Name() string {
    return o.name
}

func (o *Object) Size() int64 {
    return o.size
}

func (o *Object) Mode() os.FileMode {
    return 0 // Currently not used by RADOS
}

func (o *Object) ModTime() time.Time {
    return o.modTime
}

func (o *Object) Sys() interface{} {
    return o.sys
}

func (o *Object) IsDir() bool {
    return false
}

func (c *Context) Create(name string) (*Object, error) {
    err := c.Put(name, make([]byte, 0))

    if err != nil {
        return nil, err
    }

    // Stat the object to fill in the object structure
    obj, err := c.Stat(name)

    if err != nil {
        return nil, err
    }

    return obj.(*Object), nil
}

func (c *Context) Open(name string) (*Object, error) {
    objInfo, err := c.Stat(name)

    if err == nil {
        // Object exists, return a handle to it.
        return objInfo.(*Object), nil
    }

    // Stat failed, attempt to create the object
    obj, err := c.Create(name)

    if err != nil {
        return nil, err
    }

    return obj, nil
}

func (c *Context) Remove(name string) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_remove(c.ctx, cname); cerr != 0 {
        return fmt.Errorf("RADOS remove: %s: %s", name, strerror(cerr))
    }

    return nil
}

func (c *Context) Truncate(name string, size int64) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_trunc(c.ctx, cname, C.uint64_t(size)); cerr != 0 {
        return fmt.Errorf("RADOS trunc: %s: %s", name, strerror(cerr))
    }

    return nil
}

func byteSliceToBuffer(data []byte) (*C.char, C.size_t) {
    if len(data) > 0 {
        return (*C.char)(unsafe.Pointer(&data[0])), C.size_t(len(data))
    } else {
        return (*C.char)(unsafe.Pointer(&data)), C.size_t(0)
    }
}

func (c *Context) Put(name string, data []byte) error {
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    cdata, cdatalen := byteSliceToBuffer(data)

    if cerr := C.rados_write_full(c.ctx, cname, cdata, cdatalen); cerr < 0 {
        return fmt.Errorf("RADOS put %s: %s", name, strerror(cerr))
    }

    return nil
}

func (c *Context) Get(name string) ([]byte, error) {
    obj, err := c.Stat(name)

    if err != nil {
        return nil, err
    }

    if obj.Size() == 0 {
        // Return an empty slice
        return make([]byte, 0), nil
    }

    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    data := make([]byte, obj.Size())
    cdata, cdatalen := byteSliceToBuffer(data)

    if cerr := C.rados_read(c.ctx, cname, cdata, cdatalen, 0); cerr < 0 {
        return nil, fmt.Errorf("RADOS get %s: %s", name, strerror(cerr))
    }

    return data, nil
}

func (c *Context) Stat(name string) (os.FileInfo, error) {
    var csize C.uint64_t
    var ctime C.time_t
    cname := C.CString(name)
    defer C.free(unsafe.Pointer(cname))

    if cerr := C.rados_stat(c.ctx, cname, &csize, &ctime); cerr < 0 {
        return nil, fmt.Errorf("RADOS stat %s: %s", name, strerror(cerr))
    }

    return &Object{
        name:    name,
        size:    int64(csize),
        modTime: time.Unix(int64(ctime), int64(0)),
        sys:     sys{ctx: c.ctx, pool: c.Pool},
    }, nil
}

/* ReadAt reads len(data) bytes from the given RADOS object at the byte
 * offset off. It returns the number of bytes read and the error, if any.
 * ReadAt always returns a non-nil error when n < len(data).
 * At the end of file, that error is io.EOF.
 *
 * This function adopted from the Go os.ReadAt() function.
 */
func (o *Object) ReadAt(data []byte, off int64) (n int, err error) {
    cname := C.CString(o.name)
    defer C.free(unsafe.Pointer(cname))

    for len(data) > 0 {
        cdata, cdatalen := byteSliceToBuffer(data)
        coff := C.uint64_t(off)

        cerr := C.rados_read(o.ctx, cname, cdata, cdatalen, coff)

        if cerr == 0 {
            return n, io.EOF
        }

        if cerr < 0 {
            err = fmt.Errorf("RADOS read %s: %s", o.name, strerror(cerr))
            break
        }

        n += int(cerr)
        data = data[cerr:]
        off += int64(cerr)
    }

    return
}

/* WriteAt writes len(data) bytes to the RADOS object at the byte offset
 * off. It returns the number of bytes written and an error, if any.
 * Write returns a non-nil error when n < len(data).
 */
func (o *Object) WriteAt(data []byte, off int64) (n int, err error) {
    cname := C.CString(o.name)
    defer C.free(unsafe.Pointer(cname))

    for len(data) > 0 {
        cdata, cdatalen := byteSliceToBuffer(data)
        coff := C.uint64_t(off)

        cerr := C.rados_write(o.ctx, cname, cdata, cdatalen, coff)

        if cerr < 0 {
            err = fmt.Errorf("RADOS write %s: %s", o.name, strerror(cerr))
            break
        }

        n += int(cerr)
        data = data[cerr:]
        off += int64(cerr)
    }

    return
}

// func (o *Object) WriteInContext(Context *c, ...)
// func (o *Object) ReadInContext(Context *c, ...)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"code.google.com/p/gofpdf"

	"bitbucket.org/johnsto/ocrpdf/internal"
)

type Document struct {
	*gofpdf.Fpdf
	ocrLayerId  int
	scanLayerId int
}

func NewDocument(size string) *Document {
	pdf := gofpdf.New("P", "mm", size, "")
	pdf.SetAutoPageBreak(false, 0)
	ocrLayerId := pdf.AddLayer("OCR", true)
	scanLayerId := pdf.AddLayer("Scan", true)
	return &Document{
		Fpdf:        pdf,
		ocrLayerId:  ocrLayerId,
		scanLayerId: scanLayerId,
	}
}

func (d *Document) AddPage(imagename string, image internal.Image, words []internal.Word, format string) error {
	pdf := d.Fpdf

	pdf.AddPage()

	imageWidth, imageHeight, _ := image.Dimensions()
	iw, ih := float64(imageWidth), float64(imageHeight)
	w, h := pdf.GetPageSize()
	mx, my := 1.0, 1.0

	if iw*h < ih*w {
		w = h * iw / ih
	} else {
		h = w * ih / iw
	}
	mx = w / iw
	my = h / ih

	pdf.Write(8, "This line belongs to layer 1.\n")

	pdf.BeginLayer(d.ocrLayerId)
	pdf.SetFont("Arial", "B", 10)
	for _, word := range words {
		ww := float64(word.Right-word.Left) * mx
		wh := float64(word.Bottom-word.Top) * my
		_, _ = ww, wh
		pdf.SetXY(float64(word.Left)*mx, float64(word.Top)*my)
		pdf.Cell(ww, wh, word.Text)
	}
	pdf.EndLayer()

	pdf.BeginLayer(d.scanLayerId)
	reader, err := image.Reader(format)
	if err != nil {
		log.Fatalln(err)
	}
	pdf.RegisterImageReader(imagename, format, reader)
	pdf.Image(imagename, 0, 0, w, h, false, format, 0, "")
	pdf.EndLayer()

	return nil
}

func main() {

	tessData := flag.String("tess-data", "/usr/share/tesseract-ocr/tessdata",
		"Tesseract data directory")
	tessLang := flag.String("tess-lang", "eng",
		"Tesseract language")

	docSize := flag.String("size", "a4",
		"document size, e.g. A4 or 210x297mm")
	docTitle := flag.String("title", "", "document title")
	docKeywords := flag.String("keywords", "",
		"document keywords (space separated)")
	docAuthor := flag.String("author", "", "document author")

	compress := flag.Bool("compress", true, "compress document")

	fontName := flag.String("font-name", "Arial", "OCR layer font")
	fontStyle := flag.String("font-style", "",
		"OCR layer font style, either 'B', 'I' or 'U' (or a combination)")
	fontSize := flag.Float64("font-size", 10, "OCR layer font size")

	force := flag.Bool("force", false, "overwrite output file if necessary")

	imgContrast := flag.Float64("contrast", 0.5,
		"automatic contrast amount (0: none, 1: max)")
	imgFormat := flag.String("format", "jpg",
		"format to use when storing images in PDF (jpg|png)")

	flag.Parse()

	tess, err := internal.NewTess(*tessData, *tessLang)
	if err != nil {
		fmt.Printf("Could not initialise Tesseract: %s\n", err)
		os.Exit(1)
	}

	doc := NewDocument(*docSize)
	doc.SetFont(*fontName, *fontStyle, *fontSize)
	doc.SetTitle(*docTitle, true)
	doc.SetKeywords(*docKeywords, true)
	doc.SetAuthor(*docAuthor, true)
	doc.SetCompression(*compress)

	files := flag.Args()

	if len(files) == 0 {
		fmt.Printf("No file(s) specified!\n")
		flag.Usage()
		os.Exit(1)
	}

	outfn := files[0]
	if len(files) == 1 {
		ext := filepath.Ext(outfn)
		outfn = strings.TrimRight(outfn, ext) + ".pdf"
	}

	openFlags := os.O_RDWR | os.O_CREATE
	if *force {
		openFlags |= os.O_TRUNC
	} else {
		openFlags |= os.O_EXCL
	}

	outfile, err := os.OpenFile(outfn, openFlags, 0666)

	if os.IsExist(err) {
		fmt.Printf("Output file '%s' already exists. Use -force to overwrite.")
		os.Exit(1)
	} else {
		fmt.Printf("Couldn't create output file '%s': %s", outfn, err)
		os.Exit(1)
	}

	for _, fn := range files {
		img := internal.NewImageFromFile(fn)
		img = img.Adjust(float32(*imgContrast))
		tess.SetImagePix(img.CPIX())
		words := tess.Words()
		doc.AddPage(fn, *img, words, *imgFormat)
	}

	doc.OutputAndClose(outfile)
}
<commit_msg>Add more CLI options<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"code.google.com/p/gofpdf"

	"bitbucket.org/johnsto/ocrpdf/internal"
)

type Document struct {
	*gofpdf.Fpdf
	ocrLayerId  int
	scanLayerId int
	orientation string
}

func NewDocument(size string) *Document {
	pdf := gofpdf.New("P", "mm", size, "")
	pdf.SetAutoPageBreak(false, 0)
	ocrLayerId := pdf.AddLayer("OCR", true)
	scanLayerId := pdf.AddLayer("Scan", true)
	return &Document{
		Fpdf:        pdf,
		ocrLayerId:  ocrLayerId,
		scanLayerId: scanLayerId,
	}
}

func (d *Document) SetOrientation(orientation string) error {
	o := strings.ToLower(orientation)
	if o == "p" || o == "portrait" {
		d.orientation = "P"
		return nil
	} else if o == "l" || o == "landscape" {
		d.orientation = "L"
		return nil
	} else if o == "a" || o == "auto" {
		d.orientation = "A"
		return nil
	} else {
		return fmt.Errorf("Unknown orientation '%s'", orientation)
	}
}

func (d *Document) AddPage(imagename string, image internal.Image, words []internal.Word, format string) error {
	pdf := d.Fpdf

	imageWidth, imageHeight, _ := image.Dimensions()
	w, h := pdf.GetPageSize()

	// Add page with correct orientation
	if d.orientation == "A" {
		if imageWidth > imageHeight {
			pdf.AddPageFormat("L", gofpdf.SizeType{w, h})
			w, h = h, w
		} else {
			pdf.AddPageFormat("P", gofpdf.SizeType{w, h})
		}
	} else {
		pdf.AddPageFormat(d.orientation, gofpdf.SizeType{w, h})
	}

	// Determine image scaling factor
	iw, ih := float64(imageWidth), float64(imageHeight)
	mx, my := 1.0, 1.0

	if iw*h < ih*w {
		w = h * iw / ih
	} else {
		h = w * ih / iw
	}
	mx = w / iw
	my = h / ih

	pdf.Write(8, "This line belongs to layer 1.\n")

	// Add words acquired from OCR as bottom layer
	pdf.BeginLayer(d.ocrLayerId)
	pdf.SetFont("Arial", "B", 10)
	for _, word := range words {
		ww := float64(word.Right-word.Left) * mx
		wh := float64(word.Bottom-word.Top) * my
		_, _ = ww, wh
		pdf.SetXY(float64(word.Left)*mx, float64(word.Top)*my)
		pdf.Cell(ww, wh, word.Text)
	}
	pdf.EndLayer()

	// Add image as top layer
	pdf.BeginLayer(d.scanLayerId)
	reader, err := image.Reader(format)
	if err != nil {
		return err
	}
	pdf.RegisterImageReader(imagename, format, reader)
	pdf.Image(imagename, 0, 0, w, h, false, format, 0, "")
	pdf.EndLayer()

	return nil
}

func main() {

	tessData := flag.String("tess-data", "/usr/share/tesseract-ocr/tessdata",
		"Tesseract data directory")
	tessLang := flag.String("tess-lang", "eng",
		"Tesseract language")

	docSize := flag.String("size", "a4",
		"document size, e.g. A4 or 210x297mm")
	docTitle := flag.String("title", "", "document title")
	docKeywords := flag.String("keywords", "",
		"document keywords (space separated)")
	docAuthor := flag.String("author", "", "document author")
	docOrientation := flag.String("orientation", "auto",
		"document orientation (auto/portrait/landscape)")

	compress := flag.Bool("compress", true, "compress document")

	fontName := flag.String("font-name", "Arial", "OCR layer font")
	fontStyle := flag.String("font-style", "",
		"OCR layer font style, either 'B', 'I' or 'U' (or a combination)")
	fontSize := flag.Float64("font-size", 10, "OCR layer font size")

	force := flag.Bool("force", false, "overwrite output file if necessary")

	imgContrast := flag.Float64("contrast", 0.5,
		"automatic contrast amount (0: none, 1: max)")
	imgFormat := flag.String("format", "jpg",
		"format to use when storing images in PDF (jpg|png)")

	flag.Parse()

	tess, err := internal.NewTess(*tessData, *tessLang)
	if err != nil {
		fmt.Printf("Could not initialise Tesseract: %s\n", err)
		os.Exit(1)
	}

	doc := NewDocument(*docSize)
	doc.SetFont(*fontName, *fontStyle, *fontSize)
	doc.SetTitle(*docTitle, true)
	doc.SetKeywords(*docKeywords, true)
	doc.SetAuthor(*docAuthor, true)
	doc.SetCompression(*compress)
	doc.SetOrientation(*docOrientation)

	files := flag.Args()

	if len(files) == 0 {
		fmt.Printf("No file(s) specified!\n")
		flag.Usage()
		os.Exit(1)
	}

	outfn := files[0]
	if len(files) == 1 {
		ext := filepath.Ext(outfn)
		outfn = strings.TrimRight(outfn, ext) + ".pdf"
	}

	openFlags := os.O_RDWR | os.O_CREATE
	if *force {
		openFlags |= os.O_TRUNC
	} else {
		openFlags |= os.O_EXCL
	}

	outfile, err := os.OpenFile(outfn, openFlags, 0666)

	if os.IsExist(err) {
		fmt.Printf("Output file '%s' already exists. Use -force to overwrite.",
			outfn)
		os.Exit(1)
	} else if err != nil {
		fmt.Printf("Couldn't create output file '%s': %s", outfn, err)
		os.Exit(1)
	}

	for _, fn := range files {
		img := internal.NewImageFromFile(fn)
		img = img.Adjust(float32(*imgContrast))
		tess.SetImagePix(img.CPIX())
		words := tess.Words()
		err = doc.AddPage(fn, *img, words, *imgFormat)
		if err != nil {
			log.Fatalln(err)
		}
	}

	doc.OutputAndClose(outfile)
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 gremlin

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"sync"

	"github.com/go-gremlin/gremlin"
	"github.com/gorilla/websocket"

	"github.com/redhat-cip/skydive/logging"
)

type response struct {
	data []byte
	err  error
}

type GremlinClient struct {
	sync.RWMutex
	Addr   string
	Port   int
	wsConn *websocket.Conn
}

type GremlinPropertiesEncoder struct {
	bytes.Buffer
}

type GremlinProperty struct {
	ID    string      `json:"id"`
	Value interface{} `json:"value"`
}

type GremlinProperties map[string][]GremlinProperty

type GremlinID string

type GremlinElement struct {
	ID         GremlinID         `json:"id"`
	Label      string            `json:"label"`
	Type       string            `json:"type"`
	Properties GremlinProperties `json:"properties"`
}

func (i *GremlinID) UnmarshalJSON(b []byte) error {
	var j int64

	if err := json.Unmarshal(b, &j); err == nil {
		*i = GremlinID(strconv.FormatInt(j, 10))
		return nil
	}

	var s string
	if err := json.Unmarshal(b, &s); err == nil {
		*i = GremlinID(s)
		return nil
	}

	return errors.New("cannot unmarshal gremlin id: " + string(b))
}

// avoid loop in UnmarshalJSON
type jproperties GremlinProperties

func (p *GremlinProperties) UnmarshalJSON(b []byte) error {
	jprops := jproperties{}
	if err := json.Unmarshal(b, &jprops); err == nil {
		*p = GremlinProperties(jprops)
		return nil
	}

	hm := make(map[string]interface{})
	if err := json.Unmarshal(b, &hm); err == nil {
		props := GremlinProperties{}

		for k, v := range hm {
			prop := GremlinProperty{
				ID:    "",
				Value: v,
			}

			props[k] = []GremlinProperty{prop}
		}
		*p = props
		return nil
	}

	return errors.New("cannot unmarshal properties: " + string(b))
}

func (p *GremlinPropertiesEncoder) EncodeString(s string) error {
	p.WriteByte('"')
	p.WriteString(s)
	p.WriteByte('"')

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeInt64(i int64) error {
	p.WriteString(strconv.FormatInt(i, 10))

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeUint64(i uint64) error {
	p.WriteString(strconv.FormatUint(i, 10))

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeKVPair(k string, v interface{}) error {
	p.EncodeString(k)
	p.WriteByte(',')
	return p.Encode(v)
}

func (p *GremlinPropertiesEncoder) EncodeMap(m map[string]interface{}) error {
	i := 0
	for k, v := range m {
		if i > 0 {
			p.WriteByte(',')
		}
		err := p.EncodeKVPair(k, v)
		if err != nil {
			return err
		}
		i++
	}

	return nil
}

func (p *GremlinPropertiesEncoder) Encode(v interface{}) error {
	switch v.(type) {
	case string:
		return p.EncodeString(v.(string))
	case int:
		return p.EncodeInt64(int64(v.(int)))
	case int32:
		return p.EncodeInt64(int64(v.(int32)))
	case int64:
		return p.EncodeInt64(v.(int64))
	case uint:
		return p.EncodeUint64(uint64(v.(uint)))
	case uint32:
		return p.EncodeUint64(uint64(v.(uint32)))
	case uint64:
		return p.EncodeUint64(v.(uint64))
	case float64:
		return p.EncodeInt64(int64(v.(float64)))
	case map[string]interface{}:
		return p.EncodeMap(v.(map[string]interface{}))
	}
	return errors.New("type unsupported: " + reflect.TypeOf(v).String())
}

func resultToGremlinElements(result []byte) ([]GremlinElement, error) {
	els := make([]GremlinElement, 0)
	err := json.Unmarshal(result, &els)
	if err != nil {
		return nil, err
	}

	return els, nil
}

func (c *GremlinClient) QueryElements(q string) ([]GremlinElement, error) {
	result, err := c.Query(q)
	if err != nil {
		logging.GetLogger().Error("Gremlin query error: %s, %s", q, err.Error())
		return nil, err
	}

	if len(result) == 0 {
		return make([]GremlinElement, 0), nil
	}

	els, err := resultToGremlinElements(result)
	if err != nil {
		logging.GetLogger().Error("Gremlin query error: %s, %s", q, err.Error())
		return nil, err
	}

	return els, nil
}

func (c *GremlinClient) Query(q string) ([]byte, error) {
	m, err := json.Marshal(gremlin.Query(q))
	if err != nil {
		return nil, err
	}

	c.Lock()
	defer c.Unlock()

	if err = c.sendMessage(string(m)); err != nil {
		return []byte{}, err
	}
	return gremlin.ReadResponse(c.wsConn)
}

func (c *GremlinClient) sendMessage(msg string) error {
	w, err := c.wsConn.NextWriter(websocket.TextMessage)
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, msg)
	if err != nil {
		return err
	}

	err = w.Close()
	if err != nil {
	}

	return err
}

func (c *GremlinClient) Connect() {
	host := c.Addr + ":" + strconv.FormatInt(int64(c.Port), 10)

	conn, err := net.Dial("tcp", host)
	if err != nil {
		logging.GetLogger().Error("Connection to the WebSocket server failed: %s", err.Error())
		return
	}

	endpoint := "ws://" + host
	u, err := url.Parse(endpoint)
	if err != nil {
		logging.GetLogger().Error("Unable to parse the WebSocket Endpoint %s: %s", endpoint, err.Error())
		return
	}

	wsConn, _, err := websocket.NewClient(conn, u, http.Header{}, 0, 4096)
	if err != nil {
		logging.GetLogger().Error("Unable to create a WebSocket connection %s : %s", endpoint, err.Error())
		return
	}

	logging.GetLogger().Info("Connected to gremlin server %s:%d", c.Addr, c.Port)

	c.wsConn = wsConn
}

func (c *GremlinClient) Close() {
	c.wsConn.Close()
}

// Create new chat client.
func NewClient(addr string, port int) *GremlinClient {
	return &GremlinClient{
		Addr: addr,
		Port: port,
	}
}
<commit_msg>[gremlin] remove dead code<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 gremlin

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"sync"

	"github.com/go-gremlin/gremlin"
	"github.com/gorilla/websocket"

	"github.com/redhat-cip/skydive/logging"
)

type GremlinClient struct {
	sync.RWMutex
	Addr   string
	Port   int
	wsConn *websocket.Conn
}

type GremlinPropertiesEncoder struct {
	bytes.Buffer
}

type GremlinProperty struct {
	ID    string      `json:"id"`
	Value interface{} `json:"value"`
}

type GremlinProperties map[string][]GremlinProperty

type GremlinID string

type GremlinElement struct {
	ID         GremlinID         `json:"id"`
	Label      string            `json:"label"`
	Type       string            `json:"type"`
	Properties GremlinProperties `json:"properties"`
}

func (i *GremlinID) UnmarshalJSON(b []byte) error {
	var j int64

	if err := json.Unmarshal(b, &j); err == nil {
		*i = GremlinID(strconv.FormatInt(j, 10))
		return nil
	}

	var s string
	if err := json.Unmarshal(b, &s); err == nil {
		*i = GremlinID(s)
		return nil
	}

	return errors.New("cannot unmarshal gremlin id: " + string(b))
}

// avoid loop in UnmarshalJSON
type jproperties GremlinProperties

func (p *GremlinProperties) UnmarshalJSON(b []byte) error {
	jprops := jproperties{}
	if err := json.Unmarshal(b, &jprops); err == nil {
		*p = GremlinProperties(jprops)
		return nil
	}

	hm := make(map[string]interface{})
	if err := json.Unmarshal(b, &hm); err == nil {
		props := GremlinProperties{}

		for k, v := range hm {
			prop := GremlinProperty{
				ID:    "",
				Value: v,
			}

			props[k] = []GremlinProperty{prop}
		}
		*p = props
		return nil
	}

	return errors.New("cannot unmarshal properties: " + string(b))
}

func (p *GremlinPropertiesEncoder) EncodeString(s string) error {
	p.WriteByte('"')
	p.WriteString(s)
	p.WriteByte('"')

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeInt64(i int64) error {
	p.WriteString(strconv.FormatInt(i, 10))

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeUint64(i uint64) error {
	p.WriteString(strconv.FormatUint(i, 10))

	return nil
}

func (p *GremlinPropertiesEncoder) EncodeKVPair(k string, v interface{}) error {
	p.EncodeString(k)
	p.WriteByte(',')
	return p.Encode(v)
}

func (p *GremlinPropertiesEncoder) EncodeMap(m map[string]interface{}) error {
	i := 0
	for k, v := range m {
		if i > 0 {
			p.WriteByte(',')
		}
		err := p.EncodeKVPair(k, v)
		if err != nil {
			return err
		}
		i++
	}

	return nil
}

func (p *GremlinPropertiesEncoder) Encode(v interface{}) error {
	switch v.(type) {
	case string:
		return p.EncodeString(v.(string))
	case int:
		return p.EncodeInt64(int64(v.(int)))
	case int32:
		return p.EncodeInt64(int64(v.(int32)))
	case int64:
		return p.EncodeInt64(v.(int64))
	case uint:
		return p.EncodeUint64(uint64(v.(uint)))
	case uint32:
		return p.EncodeUint64(uint64(v.(uint32)))
	case uint64:
		return p.EncodeUint64(v.(uint64))
	case float64:
		return p.EncodeInt64(int64(v.(float64)))
	case map[string]interface{}:
		return p.EncodeMap(v.(map[string]interface{}))
	}
	return errors.New("type unsupported: " + reflect.TypeOf(v).String())
}

func resultToGremlinElements(result []byte) ([]GremlinElement, error) {
	els := make([]GremlinElement, 0)
	err := json.Unmarshal(result, &els)
	if err != nil {
		return nil, err
	}

	return els, nil
}

func (c *GremlinClient) QueryElements(q string) ([]GremlinElement, error) {
	result, err := c.Query(q)
	if err != nil {
		logging.GetLogger().Error("Gremlin query error: %s, %s", q, err.Error())
		return nil, err
	}

	if len(result) == 0 {
		return make([]GremlinElement, 0), nil
	}

	els, err := resultToGremlinElements(result)
	if err != nil {
		logging.GetLogger().Error("Gremlin query error: %s, %s", q, err.Error())
		return nil, err
	}

	return els, nil
}

func (c *GremlinClient) Query(q string) ([]byte, error) {
	m, err := json.Marshal(gremlin.Query(q))
	if err != nil {
		return nil, err
	}

	c.Lock()
	defer c.Unlock()

	if err = c.sendMessage(string(m)); err != nil {
		return []byte{}, err
	}
	return gremlin.ReadResponse(c.wsConn)
}

func (c *GremlinClient) sendMessage(msg string) error {
	w, err := c.wsConn.NextWriter(websocket.TextMessage)
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, msg)
	if err != nil {
		return err
	}

	err = w.Close()
	if err != nil {
	}

	return err
}

func (c *GremlinClient) Connect() {
	host := c.Addr + ":" + strconv.FormatInt(int64(c.Port), 10)

	conn, err := net.Dial("tcp", host)
	if err != nil {
		logging.GetLogger().Error("Connection to the WebSocket server failed: %s", err.Error())
		return
	}

	endpoint := "ws://" + host
	u, err := url.Parse(endpoint)
	if err != nil {
		logging.GetLogger().Error("Unable to parse the WebSocket Endpoint %s: %s", endpoint, err.Error())
		return
	}

	wsConn, _, err := websocket.NewClient(conn, u, http.Header{}, 0, 4096)
	if err != nil {
		logging.GetLogger().Error("Unable to create a WebSocket connection %s : %s", endpoint, err.Error())
		return
	}

	logging.GetLogger().Info("Connected to gremlin server %s:%d", c.Addr, c.Port)

	c.wsConn = wsConn
}

func (c *GremlinClient) Close() {
	c.wsConn.Close()
}

// Create new chat client.
func NewClient(addr string, port int) *GremlinClient {
	return &GremlinClient{
		Addr: addr,
		Port: port,
	}
}
<|endoftext|>


<commit_before>package wmenu

//TODO:0 Fix this so that helpers know which option I am talking about issue:1

//Opt is what Menu uses to display options to screen.
//Also holds information on what should run and if it is a default option
type Opt struct {
	ID        int
	Text      string
	function  func()
	isDefault bool
}

func newOption(id int, text string, def bool, function func()) *Opt {
	return &Opt{
		ID:        id,
		Text:      text,
		isDefault: def,
		function:  function,
	}
}
<commit_msg>Removed todo<commit_after>package wmenu

//Opt is what Menu uses to display options to screen.
//Also holds information on what should run and if it is a default option
type Opt struct {
	ID        int
	Text      string
	function  func()
	isDefault bool
}

func newOption(id int, text string, def bool, function func()) *Opt {
	return &Opt{
		ID:        id,
		Text:      text,
		isDefault: def,
		function:  function,
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"golang.org/x/net/context"
)

type CmdChatAPI struct {
	libkb.Contextified
	indent     bool
	inputFile  string
	outputFile string
	message    string
}

func newCmdChatAPI(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:  "api",
		Usage: "JSON api",
		Action: func(c *cli.Context) {
			cmd := &CmdChatAPI{Contextified: libkb.NewContextified(g)}
			cl.ChooseCommand(cmd, "api", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "p, pretty",
				Usage: "Output pretty (indented) JSON.",
			},
			cli.StringFlag{
				Name:  "m",
				Usage: "Specify JSON as string instead of stdin",
			},
			cli.StringFlag{
				Name:  "i, infile",
				Usage: "Specify JSON input file (stdin default)",
			},
			cli.StringFlag{
				Name:  "o, outfile",
				Usage: "Specify output file (stdout default)",
			},
		},
	}
}

func (c *CmdChatAPI) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) != 0 {
		return errors.New("api takes no arguments")
	}
	c.indent = ctx.Bool("pretty")
	c.inputFile = ctx.String("infile")
	c.outputFile = ctx.String("outfile")
	c.message = ctx.String("message")

	if len(c.message) > 0 && len(c.inputFile) > 0 {
		return errors.New("specify -m or -i, but not both")
	}

	return nil
}

func (c *CmdChatAPI) Run() error {
	d := NewChatAPIDecoder(&ChatAPI{svcHandler: c, indent: c.indent})

	var r io.Reader
	r = os.Stdin
	if len(c.message) > 0 {
		r = strings.NewReader(c.message)
	} else if len(c.inputFile) > 0 {
		f, err := os.Open(c.inputFile)
		if err != nil {
			return err
		}
		defer f.Close()
		r = f
	}

	var w io.Writer
	w = os.Stdout
	if len(c.outputFile) > 0 {
		f, err := os.Create(c.outputFile)
		if err != nil {
			return err
		}
		defer f.Close()
		w = f
	}

	if err := d.Decode(context.Background(), r, w); err != nil {
		return err
	}

	return nil
}

func (c *CmdChatAPI) GetUsage() libkb.Usage {
	return libkb.Usage{
		API:       true,
		KbKeyring: true,
		Config:    true,
	}
}

type ConvSummary struct {
	ID      chat1.ConversationID `json:"id"`
	Channel ChatChannel          `json:"channel"`
}

type ChatList struct {
	Conversations []ConvSummary `json:"conversations"`
}

// ListV1 implements ChatServiceHandler.ListV1.
func (c *CmdChatAPI) ListV1(ctx context.Context) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	inbox, err := client.GetInboxLocal(ctx, nil)
	if err != nil {
		return c.errReply(err)
	}

	var cl ChatList
	cl.Conversations = make([]ConvSummary, len(inbox.Conversations))
	for i, conv := range inbox.Conversations {
		if len(conv.MaxMsgs) == 0 {
			return c.errReply(fmt.Errorf("conversation %d had no max msgs", conv.Metadata.ConversationID))
		}
		tlf := conv.MaxMsgs[0].ClientHeader.TlfName
		cl.Conversations[i] = ConvSummary{
			ID: conv.Metadata.ConversationID,
			Channel: ChatChannel{
				Name:      tlf,
				TopicType: strings.ToLower(conv.Metadata.IdTriple.TopicType.String()),
			},
		}
	}

	return Reply{Result: cl}
}

type MsgSender struct {
	UID        string `json:"uid"`
	Username   string `json:"username,omitempty"`
	DeviceID   string `json:"device_id"`
	DeviceName string `json:"device_name,omitempty"`
}

// unfortunately need this...
type MsgContent struct {
	TypeName   string                                `json:"type"`
	Text       *keybase1.MessageText                 `json:"text,omitempty"`
	Attachment *keybase1.MessageAttachment           `json:"attachment,omitempty"`
	Edit       *keybase1.MessageEdit                 `json:"edit,omitempty"`
	Delete     *keybase1.MessageDelete               `json:"delete,omitempty"`
	Metadata   *keybase1.MessageConversationMetadata `json:"metadata,omitempty"`
}

type MsgSummary struct {
	ID       chat1.MessageID `json:"id"`
	Channel  ChatChannel     `json:"channel"`
	Sender   MsgSender       `json:"sender"`
	SentAt   int64           `json:"sent_at"`
	SentAtMs int64           `json:"sent_at_ms"`
	Content  MsgContent      `json:"content"`
}

type Thread struct {
	Messages []MsgSummary `json:"messages"`
}

// ReadV1 implements ChatServiceHandler.ReadV1.
func (c *CmdChatAPI) ReadV1(ctx context.Context, opts readOptionsV1) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	if opts.ConversationID == 0 {
		// resolve conversation id
		cinfo := keybase1.ConversationInfoLocal{
			TlfName:   opts.Channel.Name,
			TopicType: opts.Channel.TopicTypeEnum(),
			TopicName: opts.Channel.TopicName,
		}
		existing, err := client.ResolveConversationLocal(ctx, cinfo)
		if err != nil {
			return c.errReply(err)
		}
		if len(existing) > 1 {
			return c.errReply(fmt.Errorf("multiple conversations matched %q", opts.Channel.Name))
		}
		if len(existing) == 0 {
			return c.errReply(fmt.Errorf("no conversations matched %q", opts.Channel.Name))
		}
		opts.ConversationID = existing[0].Id
	}

	arg := keybase1.GetThreadLocalArg{
		ConversationID: opts.ConversationID,
		MarkAsRead:     true,
	}
	threadView, err := client.GetThreadLocal(ctx, arg)
	if err != nil {
		return c.errReply(err)
	}

	var thread Thread
	thread.Messages = make([]MsgSummary, len(threadView.Messages))
	for i, m := range threadView.Messages {
		thread.Messages[i] = MsgSummary{
			ID: m.ServerHeader.MessageID,
			Channel: ChatChannel{
				Name:      m.MessagePlaintext.ClientHeader.TlfName,
				TopicType: strings.ToLower(m.MessagePlaintext.ClientHeader.Conv.TopicType.String()),
			},
			Sender: MsgSender{
				UID:      m.MessagePlaintext.ClientHeader.Sender.String(),
				DeviceID: m.MessagePlaintext.ClientHeader.SenderDevice.String(),
			},
			SentAt:   int64(m.ServerHeader.Ctime / 1000),
			SentAtMs: int64(m.ServerHeader.Ctime),
		}
		if len(m.MessagePlaintext.MessageBodies) > 0 {
			thread.Messages[i].Content = c.convertMsgBody(m.MessagePlaintext.MessageBodies[0])
		}
		if len(m.MessagePlaintext.MessageBodies) > 1 {
			c.G().Log.Warning("message %v had multiple bodies", m.ServerHeader.MessageID)
		}
	}

	return Reply{Result: thread}
}

// SendV1 implements ChatServiceHandler.SendV1.
func (c *CmdChatAPI) SendV1(ctx context.Context, opts sendOptionsV1) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	var cinfo keybase1.ConversationInfoLocal
	if opts.ConversationID > 0 {
		cinfo = keybase1.ConversationInfoLocal{
			Id: opts.ConversationID,
		}
	} else {
		cinfo = keybase1.ConversationInfoLocal{
			TlfName:   opts.Channel.Name,
			TopicType: opts.Channel.TopicTypeEnum(),
			TopicName: opts.Channel.TopicName,
		}
	}

	// find the conversation
	existing, err := client.ResolveConversationLocal(ctx, cinfo)
	if err != nil {
		return c.errReply(err)
	}
	var conversation keybase1.ConversationInfoLocal
	switch len(existing) {
	case 0:
		conversation, err = client.NewConversationLocal(ctx, cinfo)
		if err != nil {
			return c.errReply(err)
		}
	case 1:
		conversation = existing[0]
	default:
		return c.errReply(fmt.Errorf("multiple conversations matched"))
	}

	// XXX ResolveConversationLocal, NewConversationLocal need to return
	// topic id and tlf id.  In order to fill in conversation id triple
	// below.
	// ticket CORE-3746

	postArg := keybase1.PostLocalArg{
		ConversationID: conversation.Id,
		MessagePlaintext: keybase1.MessagePlaintext{
			ClientHeader: chat1.MessageClientHeader{
				Conv: chat1.ConversationIDTriple{
					TopicType: conversation.TopicType,
				},
				TlfName:     conversation.TlfName,
				MessageType: chat1.MessageType_TEXT,
			},
			MessageBodies: []keybase1.MessageBody{
				keybase1.NewMessageBodyWithText(keybase1.MessageText{Body: opts.Message.Body}),
			},
		},
	}
	if err := client.PostLocal(ctx, postArg); err != nil {
		return c.errReply(err)
	}

	return Reply{Result: "message sent"}
}

func (c *CmdChatAPI) errReply(err error) Reply {
	return Reply{Error: &CallError{Message: err.Error()}}
}

// need this to get message type name
func (c *CmdChatAPI) convertMsgBody(mb keybase1.MessageBody) MsgContent {
	return MsgContent{
		TypeName:   strings.ToLower(chat1.MessageTypeRevMap[mb.MessageType__]),
		Text:       mb.Text__,
		Attachment: mb.Attachment__,
		Edit:       mb.Edit__,
		Delete:     mb.Delete__,
		Metadata:   mb.Metadata__,
	}
}
<commit_msg>Fix rebase changes<commit_after>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"golang.org/x/net/context"
)

type CmdChatAPI struct {
	libkb.Contextified
	indent     bool
	inputFile  string
	outputFile string
	message    string
}

func newCmdChatAPI(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:  "api",
		Usage: "JSON api",
		Action: func(c *cli.Context) {
			cmd := &CmdChatAPI{Contextified: libkb.NewContextified(g)}
			cl.ChooseCommand(cmd, "api", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "p, pretty",
				Usage: "Output pretty (indented) JSON.",
			},
			cli.StringFlag{
				Name:  "m",
				Usage: "Specify JSON as string instead of stdin",
			},
			cli.StringFlag{
				Name:  "i, infile",
				Usage: "Specify JSON input file (stdin default)",
			},
			cli.StringFlag{
				Name:  "o, outfile",
				Usage: "Specify output file (stdout default)",
			},
		},
	}
}

func (c *CmdChatAPI) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) != 0 {
		return errors.New("api takes no arguments")
	}
	c.indent = ctx.Bool("pretty")
	c.inputFile = ctx.String("infile")
	c.outputFile = ctx.String("outfile")
	c.message = ctx.String("message")

	if len(c.message) > 0 && len(c.inputFile) > 0 {
		return errors.New("specify -m or -i, but not both")
	}

	return nil
}

func (c *CmdChatAPI) Run() error {
	d := NewChatAPIDecoder(&ChatAPI{svcHandler: c, indent: c.indent})

	var r io.Reader
	r = os.Stdin
	if len(c.message) > 0 {
		r = strings.NewReader(c.message)
	} else if len(c.inputFile) > 0 {
		f, err := os.Open(c.inputFile)
		if err != nil {
			return err
		}
		defer f.Close()
		r = f
	}

	var w io.Writer
	w = os.Stdout
	if len(c.outputFile) > 0 {
		f, err := os.Create(c.outputFile)
		if err != nil {
			return err
		}
		defer f.Close()
		w = f
	}

	if err := d.Decode(context.Background(), r, w); err != nil {
		return err
	}

	return nil
}

func (c *CmdChatAPI) GetUsage() libkb.Usage {
	return libkb.Usage{
		API:       true,
		KbKeyring: true,
		Config:    true,
	}
}

type ConvSummary struct {
	ID      chat1.ConversationID `json:"id"`
	Channel ChatChannel          `json:"channel"`
}

type ChatList struct {
	Conversations []ConvSummary `json:"conversations"`
}

// ListV1 implements ChatServiceHandler.ListV1.
func (c *CmdChatAPI) ListV1(ctx context.Context) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	inbox, err := client.GetInboxLocal(ctx, keybase1.GetInboxLocalArg{})
	if err != nil {
		return c.errReply(err)
	}

	var cl ChatList
	cl.Conversations = make([]ConvSummary, len(inbox.Conversations))
	for i, conv := range inbox.Conversations {
		if len(conv.MaxMsgs) == 0 {
			return c.errReply(fmt.Errorf("conversation %d had no max msgs", conv.Metadata.ConversationID))
		}
		tlf := conv.MaxMsgs[0].ClientHeader.TlfName
		cl.Conversations[i] = ConvSummary{
			ID: conv.Metadata.ConversationID,
			Channel: ChatChannel{
				Name:      tlf,
				TopicType: strings.ToLower(conv.Metadata.IdTriple.TopicType.String()),
			},
		}
	}

	return Reply{Result: cl}
}

type MsgSender struct {
	UID        string `json:"uid"`
	Username   string `json:"username,omitempty"`
	DeviceID   string `json:"device_id"`
	DeviceName string `json:"device_name,omitempty"`
}

// unfortunately need this...
type MsgContent struct {
	TypeName   string                                `json:"type"`
	Text       *keybase1.MessageText                 `json:"text,omitempty"`
	Attachment *keybase1.MessageAttachment           `json:"attachment,omitempty"`
	Edit       *keybase1.MessageEdit                 `json:"edit,omitempty"`
	Delete     *keybase1.MessageDelete               `json:"delete,omitempty"`
	Metadata   *keybase1.MessageConversationMetadata `json:"metadata,omitempty"`
}

type MsgSummary struct {
	ID       chat1.MessageID `json:"id"`
	Channel  ChatChannel     `json:"channel"`
	Sender   MsgSender       `json:"sender"`
	SentAt   int64           `json:"sent_at"`
	SentAtMs int64           `json:"sent_at_ms"`
	Content  MsgContent      `json:"content"`
}

type Thread struct {
	Messages []MsgSummary `json:"messages"`
}

// ReadV1 implements ChatServiceHandler.ReadV1.
func (c *CmdChatAPI) ReadV1(ctx context.Context, opts readOptionsV1) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	if opts.ConversationID == 0 {
		// resolve conversation id
		cinfo := keybase1.ConversationInfoLocal{
			TlfName:   opts.Channel.Name,
			TopicType: opts.Channel.TopicTypeEnum(),
			TopicName: opts.Channel.TopicName,
		}
		existing, err := client.ResolveConversationLocal(ctx, cinfo)
		if err != nil {
			return c.errReply(err)
		}
		if len(existing) > 1 {
			return c.errReply(fmt.Errorf("multiple conversations matched %q", opts.Channel.Name))
		}
		if len(existing) == 0 {
			return c.errReply(fmt.Errorf("no conversations matched %q", opts.Channel.Name))
		}
		opts.ConversationID = existing[0].Id
	}

	arg := keybase1.GetThreadLocalArg{
		ConversationID: opts.ConversationID,
		Query: &chat1.GetThreadQuery{
			MarkAsRead: true,
		},
	}
	threadView, err := client.GetThreadLocal(ctx, arg)
	if err != nil {
		return c.errReply(err)
	}

	var thread Thread
	thread.Messages = make([]MsgSummary, len(threadView.Messages))
	for i, m := range threadView.Messages {
		thread.Messages[i] = MsgSummary{
			ID: m.ServerHeader.MessageID,
			Channel: ChatChannel{
				Name:      m.MessagePlaintext.ClientHeader.TlfName,
				TopicType: strings.ToLower(m.MessagePlaintext.ClientHeader.Conv.TopicType.String()),
			},
			Sender: MsgSender{
				UID:      m.MessagePlaintext.ClientHeader.Sender.String(),
				DeviceID: m.MessagePlaintext.ClientHeader.SenderDevice.String(),
			},
			SentAt:   int64(m.ServerHeader.Ctime / 1000),
			SentAtMs: int64(m.ServerHeader.Ctime),
		}
		if len(m.MessagePlaintext.MessageBodies) > 0 {
			thread.Messages[i].Content = c.convertMsgBody(m.MessagePlaintext.MessageBodies[0])
		}
		if len(m.MessagePlaintext.MessageBodies) > 1 {
			c.G().Log.Warning("message %v had multiple bodies", m.ServerHeader.MessageID)
		}
	}

	return Reply{Result: thread}
}

// SendV1 implements ChatServiceHandler.SendV1.
func (c *CmdChatAPI) SendV1(ctx context.Context, opts sendOptionsV1) Reply {
	client, err := GetChatLocalClient(c.G())
	if err != nil {
		return c.errReply(err)
	}

	var cinfo keybase1.ConversationInfoLocal
	if opts.ConversationID > 0 {
		cinfo = keybase1.ConversationInfoLocal{
			Id: opts.ConversationID,
		}
	} else {
		cinfo = keybase1.ConversationInfoLocal{
			TlfName:   opts.Channel.Name,
			TopicType: opts.Channel.TopicTypeEnum(),
			TopicName: opts.Channel.TopicName,
		}
	}

	// find the conversation
	existing, err := client.ResolveConversationLocal(ctx, cinfo)
	if err != nil {
		return c.errReply(err)
	}
	var conversation keybase1.ConversationInfoLocal
	switch len(existing) {
	case 0:
		conversation, err = client.NewConversationLocal(ctx, cinfo)
		if err != nil {
			return c.errReply(err)
		}
	case 1:
		conversation = existing[0]
	default:
		return c.errReply(fmt.Errorf("multiple conversations matched"))
	}

	// XXX ResolveConversationLocal, NewConversationLocal need to return
	// topic id and tlf id.  In order to fill in conversation id triple
	// below.
	// ticket CORE-3746

	postArg := keybase1.PostLocalArg{
		ConversationID: conversation.Id,
		MessagePlaintext: keybase1.MessagePlaintext{
			ClientHeader: chat1.MessageClientHeader{
				Conv: chat1.ConversationIDTriple{
					TopicType: conversation.TopicType,
				},
				TlfName:     conversation.TlfName,
				MessageType: chat1.MessageType_TEXT,
			},
			MessageBodies: []keybase1.MessageBody{
				keybase1.NewMessageBodyWithText(keybase1.MessageText{Body: opts.Message.Body}),
			},
		},
	}
	if err := client.PostLocal(ctx, postArg); err != nil {
		return c.errReply(err)
	}

	return Reply{Result: "message sent"}
}

func (c *CmdChatAPI) errReply(err error) Reply {
	return Reply{Error: &CallError{Message: err.Error()}}
}

// need this to get message type name
func (c *CmdChatAPI) convertMsgBody(mb keybase1.MessageBody) MsgContent {
	return MsgContent{
		TypeName:   strings.ToLower(chat1.MessageTypeRevMap[mb.MessageType__]),
		Text:       mb.Text__,
		Attachment: mb.Attachment__,
		Edit:       mb.Edit__,
		Delete:     mb.Delete__,
		Metadata:   mb.Metadata__,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"

	"github.com/youtube/vitess/go/vt/health"
	"github.com/youtube/vitess/go/vt/servenv"
	_ "github.com/youtube/vitess/go/vt/status"
	"github.com/youtube/vitess/go/vt/tabletmanager"
	"github.com/youtube/vitess/go/vt/tabletserver"
)

var (
	// tabletTemplate contains the style sheet and the tablet itself.
	tabletTemplate = `

      Alias: {{github_com_youtube_vitess_vtctld_tablet .Alias.String}}

      Keyspace: {{github_com_youtube_vitess_vtctld_keyspace .Keyspace}} Shard: {{github_com_youtube_vitess_vtctld_shard .Keyspace .Shard}}

      Serving graph: {{github_com_youtube_vitess_vtctld_srv_keyspace .Alias.Cell .Keyspace}} {{github_com_youtube_vitess_vtctld_srv_shard .Alias.Cell .Keyspace .Shard}} {{github_com_youtube_vitess_vtctld_srv_type .Alias.Cell .Keyspace .Shard .Type}}

      Replication graph: {{github_com_youtube_vitess_vtctld_replication .Alias.Cell .Keyspace .Shard}}

      State: {{.State}}

      Schema

      Schema Query Plans

      Schema Query Stats

      Schema Table Stats

      Query Stats

      Consolidations

      Current Query Log

      Current Transaction Log

      Health Check

      Memcache

      Current Stream Queries

`

	// healthTemplate is just about the tablet health
	healthTemplate = `

Current status: {{.Current}}

Polling health information from {{github_com_youtube_vitess_health_html_name}}.

History

    Time
    State

  {{range .Records}}

    {{.Time.Format "Jan 2, 2006 at 15:04:05 (MST)"}}

    {{ if eq "unhealthy" .Class}}
      unhealthy: {{.Error}}
    {{else if eq "unhappy" .Class}}
      unhappy (reasons: {{range $key, $value := .Result}}{{$key}}: {{$value}} {{end}})
    {{else}}
      healthy
    {{end}}

  {{end}}

healthy

serving traffic.

unhappy

will serve traffic only if there are no fully healthy tablets.

unhealthy

will not serve traffic.

`

	// binlogTemplate is about the binlog players
	binlogTemplate = `
{{if .Controllers}}
Binlog player state: {{.State}}

    Index
    SourceShard
    State
    StopAtGroupId
    LastGroupId
    SecondsBehindMaster
    Counts
    Rates
    Last Error

  {{range .Controllers}}

      {{.Index}}
      {{.SourceShard.AsHTML}}
      {{.State}}
        {{if eq .State "Running"}}
          {{if .SourceTablet.IsZero}}
            (picking source tablet)
          {{else}}
            (from {{github_com_youtube_vitess_vtctld_tablet .SourceTablet.String}})
          {{end}}
        {{end}}
      {{if .StopAtGroupId}}{{.StopAtGroupId}}{{end}}
      {{.LastGroupId}}
      {{.SecondsBehindMaster}}
      {{range $key, $value := .Counts}}{{$key}}: {{$value}}
{{end}}
      {{range $key, $values := .Rates}}{{$key}}: {{range $values}}{{.}} {{end}}
{{end}}
      {{.LastError}}

  {{end}}

{{else}}
No binlog player is running.
{{end}}
`
)

type healthStatus struct {
	Records []interface{}
}

func (hs *healthStatus) Current() string {
	if len(hs.Records) > 0 {
		return hs.Records[0].(*tabletmanager.HealthRecord).Class()
	}
	return "unknown"
}

func healthHTMLName() template.HTML {
	return health.HTMLName()
}

// For use by plugins which wish to avoid racing when registering status page parts.
var onStatusRegistered func()

func init() {
	servenv.OnRun(func() {
		servenv.AddStatusPart("Tablet", tabletTemplate, func() interface{} {
			return agent.Tablet()
		})
		if agent.IsRunningHealthCheck() {
			servenv.AddStatusFuncs(template.FuncMap{
				"github_com_youtube_vitess_health_html_name": healthHTMLName,
			})
			servenv.AddStatusPart("Health", healthTemplate, func() interface{} {
				return &healthStatus{Records: agent.History.Records()}
			})
		}
		tabletserver.AddStatusPart()
		servenv.AddStatusPart("Binlog Player", binlogTemplate, func() interface{} {
			return agent.BinlogPlayerMap.Status()
		})
		if onStatusRegistered != nil {
			onStatusRegistered()
		}
	})
}
<commit_msg>Update vttablet status for GTID refactor.<commit_after>package main

import (
	"html/template"

	"github.com/youtube/vitess/go/vt/health"
	"github.com/youtube/vitess/go/vt/servenv"
	_ "github.com/youtube/vitess/go/vt/status"
	"github.com/youtube/vitess/go/vt/tabletmanager"
	"github.com/youtube/vitess/go/vt/tabletserver"
)

var (
	// tabletTemplate contains the style sheet and the tablet itself.
	tabletTemplate = `

      Alias: {{github_com_youtube_vitess_vtctld_tablet .Alias.String}}

      Keyspace: {{github_com_youtube_vitess_vtctld_keyspace .Keyspace}} Shard: {{github_com_youtube_vitess_vtctld_shard .Keyspace .Shard}}

      Serving graph: {{github_com_youtube_vitess_vtctld_srv_keyspace .Alias.Cell .Keyspace}} {{github_com_youtube_vitess_vtctld_srv_shard .Alias.Cell .Keyspace .Shard}} {{github_com_youtube_vitess_vtctld_srv_type .Alias.Cell .Keyspace .Shard .Type}}

      Replication graph: {{github_com_youtube_vitess_vtctld_replication .Alias.Cell .Keyspace .Shard}}

      State: {{.State}}

      Schema

      Schema Query Plans

      Schema Query Stats

      Schema Table Stats

      Query Stats

      Consolidations

      Current Query Log

      Current Transaction Log

      Health Check

      Memcache

      Current Stream Queries

`

	// healthTemplate is just about the tablet health
	healthTemplate = `

Current status: {{.Current}}

Polling health information from {{github_com_youtube_vitess_health_html_name}}.

History

    Time
    State

  {{range .Records}}

    {{.Time.Format "Jan 2, 2006 at 15:04:05 (MST)"}}

    {{ if eq "unhealthy" .Class}}
      unhealthy: {{.Error}}
    {{else if eq "unhappy" .Class}}
      unhappy (reasons: {{range $key, $value := .Result}}{{$key}}: {{$value}} {{end}})
    {{else}}
      healthy
    {{end}}

  {{end}}

healthy

serving traffic.

unhappy

will serve traffic only if there are no fully healthy tablets.

unhealthy

will not serve traffic.

`

	// binlogTemplate is about the binlog players
	binlogTemplate = `
{{if .Controllers}}
Binlog player state: {{.State}}

    Index
    SourceShard
    State
    StopAtGTID
    LastGTID
    SecondsBehindMaster
    Counts
    Rates
    Last Error

  {{range .Controllers}}

      {{.Index}}
      {{.SourceShard.AsHTML}}
      {{.State}}
        {{if eq .State "Running"}}
          {{if .SourceTablet.IsZero}}
            (picking source tablet)
          {{else}}
            (from {{github_com_youtube_vitess_vtctld_tablet .SourceTablet.String}})
          {{end}}
        {{end}}
      {{if .StopAtGTID}}{{.StopAtGTID}}{{end}}
      {{.LastGTID}}
      {{.SecondsBehindMaster}}
      {{range $key, $value := .Counts}}{{$key}}: {{$value}}
{{end}}
      {{range $key, $values := .Rates}}{{$key}}: {{range $values}}{{.}} {{end}}
{{end}}
      {{.LastError}}

  {{end}}

{{else}}
No binlog player is running.
{{end}}
`
)

type healthStatus struct {
	Records []interface{}
}

func (hs *healthStatus) Current() string {
	if len(hs.Records) > 0 {
		return hs.Records[0].(*tabletmanager.HealthRecord).Class()
	}
	return "unknown"
}

func healthHTMLName() template.HTML {
	return health.HTMLName()
}

// For use by plugins which wish to avoid racing when registering status page parts.
var onStatusRegistered func()

func init() {
	servenv.OnRun(func() {
		servenv.AddStatusPart("Tablet", tabletTemplate, func() interface{} {
			return agent.Tablet()
		})
		if agent.IsRunningHealthCheck() {
			servenv.AddStatusFuncs(template.FuncMap{
				"github_com_youtube_vitess_health_html_name": healthHTMLName,
			})
			servenv.AddStatusPart("Health", healthTemplate, func() interface{} {
				return &healthStatus{Records: agent.History.Records()}
			})
		}
		tabletserver.AddStatusPart()
		servenv.AddStatusPart("Binlog Player", binlogTemplate, func() interface{} {
			return agent.BinlogPlayerMap.Status()
		})
		if onStatusRegistered != nil {
			onStatusRegistered()
		}
	})
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

func isExist(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), " exists")
}

func isNotExist(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), "does not exist") || contains(err.Error(), "not found")
}

func isPermission(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), "permission denied")
}

// contains is a local version of strings.Contains. It knows len(sep) > 1.
func contains(s, sep string) bool {
	n := len(sep)
	c := sep[0]
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return true
		}
	}
	return false
}
<commit_msg>os: handle 'has been removed' error as IsNotExist on Plan 9<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

func isExist(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), " exists")
}

func isNotExist(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || contains(err.Error(), "has been removed")
}

func isPermission(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *PathError:
		err = pe.Err
	case *LinkError:
		err = pe.Err
	}
	return contains(err.Error(), "permission denied")
}

// contains is a local version of strings.Contains. It knows len(sep) > 1.
func contains(s, sep string) bool {
	n := len(sep)
	c := sep[0]
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

package user

import (
	"github.com/zenoss/serviced/datastore"

	"strings"
)

//NewStore creates a UserStore
func NewStore() *UserStore {
	return &UserStore{}
}

//UserStore type for interacting with User persistent storage
type UserStore struct {
	datastore.DataStore
}

//Key creates a Key suitable for getting, putting and deleting Users
func Key(id string) datastore.Key {
	id = strings.TrimSpace(id)
	return datastore.NewKey(kind, id)
}

//func convert(results datastore.Results) ([]*User, error) {
//	hosts := make([]*User, results.Len())
//	glog.V(4).Infof("Results are %v", results)
//	for idx := range hosts {
//		var host User
//		err := results.Get(idx, &host)
//		if err != nil {
//			return nil, err
//		}
//		glog.V(4).Infof("Adding %v to hosts", host)
//		hosts[idx] = &host
//	}
//	return hosts, nil
//}

var kind = "user"
<commit_msg>remove unused code<commit_after>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

package user

import (
	"github.com/zenoss/serviced/datastore"

	"strings"
)

//NewStore creates a UserStore
func NewStore() *UserStore {
	return &UserStore{}
}

//UserStore type for interacting with User persistent storage
type UserStore struct {
	datastore.DataStore
}

//Key creates a Key suitable for getting, putting and deleting Users
func Key(id string) datastore.Key {
	id = strings.TrimSpace(id)
	return datastore.NewKey(kind, id)
}

var kind = "user"
<|endoftext|>