<commit_before>package act

import (
	"errors"
	"flag"
	"fmt"
	"log"
)

type Term interface{}
type Tuple []Term
type List []Term
type Atom string

type Pid struct {
	id       uint64
	inChan   chan interface{}
	stopChan chan *stopReq
}

type Opts struct {
	Prefix                   string
	Name                     interface{}
	Chan_size                uint32
	Return_pid_if_registered bool
}

type makePidResp struct {
	pid *Pid
	err error
}

type makePidReq struct {
	opts    *Opts
	replyTo chan<- makePidResp
}

type regNameReq struct {
	prefix  string
	name    interface{}
	pid     *Pid
	replyTo chan<- bool
}

type unregNameReq struct {
	prefix string
	name   interface{}
}

type whereNameReq struct {
	prefix  string
	name    interface{}
	replyTo chan<- *Pid
}

type regMap map[interface{}]*Pid
type wherePrefixReq struct {
	prefix  string
	replyTo chan<- regMap
}

type registryChan struct {
	makePidChan     chan makePidReq
	regNameChan     chan regNameReq
	unregNameChan   chan unregNameReq
	whereNameChan   chan whereNameReq
	wherePrefixChan chan wherePrefixReq
}

type act struct {
	serial     uint64
	registry   *registryChan
	registered map[string]regMap
}

const NoProc string = "no_proc"

// ---------------------------------------------------------------------------
var nTrace bool
var env *act

func init() {
	flag.BoolVar(&nTrace, "trace", false, "trace actors")

	registry := &registryChan{
		makePidChan:     make(chan makePidReq),
		regNameChan:     make(chan regNameReq),
		unregNameChan:   make(chan unregNameReq),
		whereNameChan:   make(chan whereNameReq),
		wherePrefixChan: make(chan wherePrefixReq),
	}

	env = &act{
		registry:   registry,
		registered: make(map[string]regMap),
	}

	// without prefix
	env.registered[""] = make(regMap)

	env.run()
}

func nLog(f string, a ...interface{}) {
	if nTrace {
		log.Printf(f, a...)
	}
}

// ---------------------------------------------------------------------------
// Spawn new GenServer process
// ---------------------------------------------------------------------------
func Spawn(gs GenServer, args ...interface{}) (pid *Pid, err error) {

	pid, err = SpawnOpts(gs, &Opts{}, args...)

	return
}

func SpawnPrefixName(
	gs GenServer,
	prefix string,
	name interface{},
	args ...interface{}) (pid *Pid, err error) {

	opts := &Opts{
		Prefix: prefix,
		Name:   name,
	}
	pid, err = SpawnOpts(gs, opts, args...)

	return
}

func SpawnOpts(gs GenServer, opts *Opts, args ...interface{}) (*Pid, error) {

	if opts.Chan_size == 0 {
		opts.Chan_size = 100
	}

	pid, err := env.makePid(opts)
	if err != nil {
		return nil, err
	}
	pid.inChan = make(chan interface{}, opts.Chan_size)
	pid.stopChan = make(chan *stopReq)

	initChan := make(chan Term)

	go GenServerLoop(gs, opts.Prefix, opts.Name, initChan, pid, args...)
	result := <-initChan

	switch result := result.(type) {
	case *GsInitOk:
	case *GsInitStop:
		return nil, errors.New(result.Reason)
	case error:
		return nil, result
	}

	return pid, nil
}

// Register associates the name with pid
func Register(name interface{}, pid *Pid) error {
	replyChan := make(chan bool, 1)
	r := regNameReq{name: name, pid: pid, replyTo: replyChan}
	env.registry.regNameChan <- r
	reply := <-replyChan

	if reply == true {
		return nil
	}

	return fmt.Errorf("name '%v' already registered", name)
}

func RegisterPrefix(prefix string, name interface{}, pid *Pid) error {
	replyChan := make(chan bool, 1)
	r := regNameReq{prefix: prefix, name: name, pid: pid, replyTo: replyChan}
	env.registry.regNameChan <- r
	reply := <-replyChan

	if reply == true {
		return nil
	}

	return fmt.Errorf("name '%s/%v' already registered", prefix, name)
}

// Unregister removes the registered name
func Unregister(name interface{}) {
	r := unregNameReq{name: name}
	env.registry.unregNameChan <- r
}

func UnregisterPrefix(prefix string, name interface{}) {
	if prefix == "" && name == nil {
		return
	}

	r := unregNameReq{prefix: prefix, name: name}
	env.registry.unregNameChan <- r
}

// Whereis returns pid of registered process
func Whereis(name interface{}) *Pid {
	pid := WhereisPrefix("", name)

	return pid
}

func WhereisPrefix(prefix string, name interface{}) *Pid {
	replyChan := make(chan *Pid, 1)
	r := whereNameReq{prefix: prefix, name: name, replyTo: replyChan}
	env.registry.whereNameChan <- r
	pid := <-replyChan

	return pid
}

// Returns all pids with same prefix
func Whereare(prefix string) regMap {
	replyChan := make(chan regMap, 1)
	r := wherePrefixReq{prefix: prefix, replyTo: replyChan}
	env.registry.wherePrefixChan <- r
	regs := <-replyChan

	return regs
}

// ---------------------------------------------------------------------------
func (n *act) run() {
	go n.registrator()
}

func (n *act) registrator() {
	for {
		select {
		case req := <-n.registry.makePidChan:
			newPidCreated := true

			var newPid Pid
			newPid.id = n.serial + 1

			var resp makePidResp
			resp.pid = &newPid

			// register name with prefix if not empty
			if req.opts.Name != nil {
				if _, ok := n.registered[req.opts.Prefix]; ok {
					// map with prefix exists
					if pid, ok := n.registered[req.opts.Prefix][req.opts.Name]; ok {
						if req.opts.Return_pid_if_registered == true {
							resp.pid = pid
							newPidCreated = false
						} else {
							// name already registered
							resp.pid = nil
							resp.err =
								fmt.Errorf("name '%s/%v' already registered",
									req.opts.Prefix, req.opts.Name)
						}
					} else {
						n.registered[req.opts.Prefix][req.opts.Name] = resp.pid
					}

				} else { // no maps with prefix
					n.registered[req.opts.Prefix] = make(regMap)
					n.registered[req.opts.Prefix][req.opts.Name] = resp.pid
				}
			}

			if newPidCreated {
				n.serial += 1
			}

			req.replyTo <- resp

		case req := <-n.registry.regNameChan:
			if _, ok := n.registered[req.prefix]; !ok {
				n.registered[req.prefix] = make(regMap)
			}
			if _, ok := n.registered[req.prefix][req.name]; ok {
				req.replyTo <- false // name registered
			} else {
				n.registered[req.prefix][req.name] = req.pid
				req.replyTo <- true
			}

		case req := <-n.registry.unregNameChan:
			if _, ok := n.registered[req.prefix]; ok {
				delete(n.registered[req.prefix], req.name)
			}

		case req := <-n.registry.whereNameChan:
			req.replyTo <- n.registered[req.prefix][req.name]

		case req := <-n.registry.wherePrefixChan:
			var rpids regMap
			if pids, ok := n.registered[req.prefix]; ok {
				rpids = make(regMap)
				for k, v := range pids {
					rpids[k] = v
				}
			}
			req.replyTo <- rpids
		}
	}
}

func (n *act) makePid(opts *Opts) (*Pid, error) {
	replyChan := make(chan makePidResp, 1)
	n.registry.makePidChan <- makePidReq{opts: opts, replyTo: replyChan}
	resp := <-replyChan

	return resp.pid, resp.err
}

func (pid *Pid) Id() uint64 {
	if pid == nil {
		return 0
	}

	return pid.id
}
<commit_msg>fix pid id increment if pid registered<commit_after>package act

import (
	"errors"
	"flag"
	"fmt"
	"log"
)

type Term interface{}
type Tuple []Term
type List []Term
type Atom string

type Pid struct {
	id       uint64
	inChan   chan interface{}
	stopChan chan *stopReq
}

type Opts struct {
	Prefix                   string
	Name                     interface{}
	Chan_size                uint32
	Return_pid_if_registered bool
}

type makePidResp struct {
	pid *Pid
	err error
}

type makePidReq struct {
	opts    *Opts
	replyTo chan<- makePidResp
}

type regNameReq struct {
	prefix  string
	name    interface{}
	pid     *Pid
	replyTo chan<- bool
}

type unregNameReq struct {
	prefix string
	name   interface{}
}

type whereNameReq struct {
	prefix  string
	name    interface{}
	replyTo chan<- *Pid
}

type regMap map[interface{}]*Pid
type wherePrefixReq struct {
	prefix  string
	replyTo chan<- regMap
}

type registryChan struct {
	makePidChan     chan makePidReq
	regNameChan     chan regNameReq
	unregNameChan   chan unregNameReq
	whereNameChan   chan whereNameReq
	wherePrefixChan chan wherePrefixReq
}

type act struct {
	serial     uint64
	registry   *registryChan
	registered map[string]regMap
}

const NoProc string = "no_proc"

// ---------------------------------------------------------------------------
var nTrace bool
var env *act

func init() {
	flag.BoolVar(&nTrace, "trace", false, "trace actors")

	registry := &registryChan{
		makePidChan:     make(chan makePidReq),
		regNameChan:     make(chan regNameReq),
		unregNameChan:   make(chan unregNameReq),
		whereNameChan:   make(chan whereNameReq),
		wherePrefixChan: make(chan wherePrefixReq),
	}

	env = &act{
		registry:   registry,
		registered: make(map[string]regMap),
	}

	// without prefix
	env.registered[""] = make(regMap)

	env.run()
}

func nLog(f string, a ...interface{}) {
	if nTrace {
		log.Printf(f, a...)
	}
}

// ---------------------------------------------------------------------------
// Spawn new GenServer process
// ---------------------------------------------------------------------------
func Spawn(gs GenServer, args ...interface{}) (pid *Pid, err error) {

	pid, err = SpawnOpts(gs, &Opts{}, args...)

	return
}

func SpawnPrefixName(
	gs GenServer,
	prefix string,
	name interface{},
	args ...interface{}) (pid *Pid, err error) {

	opts := &Opts{
		Prefix: prefix,
		Name:   name,
	}
	pid, err = SpawnOpts(gs, opts, args...)

	return
}

func SpawnOpts(gs GenServer, opts *Opts, args ...interface{}) (*Pid, error) {

	if opts.Chan_size == 0 {
		opts.Chan_size = 100
	}

	pid, err := env.makePid(opts)
	if err != nil {
		return nil, err
	}
	pid.inChan = make(chan interface{}, opts.Chan_size)
	pid.stopChan = make(chan *stopReq)

	initChan := make(chan Term)

	go GenServerLoop(gs, opts.Prefix, opts.Name, initChan, pid, args...)
	result := <-initChan

	switch result := result.(type) {
	case *GsInitOk:
	case *GsInitStop:
		return nil, errors.New(result.Reason)
	case error:
		return nil, result
	}

	return pid, nil
}

// Register associates the name with pid
func Register(name interface{}, pid *Pid) error {
	replyChan := make(chan bool, 1)
	r := regNameReq{name: name, pid: pid, replyTo: replyChan}
	env.registry.regNameChan <- r
	reply := <-replyChan

	if reply == true {
		return nil
	}

	return fmt.Errorf("name '%v' already registered", name)
}

func RegisterPrefix(prefix string, name interface{}, pid *Pid) error {
	replyChan := make(chan bool, 1)
	r := regNameReq{prefix: prefix, name: name, pid: pid, replyTo: replyChan}
	env.registry.regNameChan <- r
	reply := <-replyChan

	if reply == true {
		return nil
	}

	return fmt.Errorf("name '%s/%v' already registered", prefix, name)
}

// Unregister removes the registered name
func Unregister(name interface{}) {
	r := unregNameReq{name: name}
	env.registry.unregNameChan <- r
}

func UnregisterPrefix(prefix string, name interface{}) {
	if prefix == "" && name == nil {
		return
	}

	r := unregNameReq{prefix: prefix, name: name}
	env.registry.unregNameChan <- r
}

// Whereis returns pid of registered process
func Whereis(name interface{}) *Pid {
	pid := WhereisPrefix("", name)

	return pid
}

func WhereisPrefix(prefix string, name interface{}) *Pid {
	replyChan := make(chan *Pid, 1)
	r := whereNameReq{prefix: prefix, name: name, replyTo: replyChan}
	env.registry.whereNameChan <- r
	pid := <-replyChan

	return pid
}

// Returns all pids with same prefix
func Whereare(prefix string) regMap {
	replyChan := make(chan regMap, 1)
	r := wherePrefixReq{prefix: prefix, replyTo: replyChan}
	env.registry.wherePrefixChan <- r
	regs := <-replyChan

	return regs
}

// ---------------------------------------------------------------------------
func (n *act) run() {
	go n.registrator()
}

func (n *act) registrator() {
	for {
		select {
		case req := <-n.registry.makePidChan:
			newPidCreated := true

			var newPid Pid
			newPid.id = n.serial + 1

			var resp makePidResp
			resp.pid = &newPid

			// register name with prefix if not empty
			if req.opts.Name != nil {
				if _, ok := n.registered[req.opts.Prefix]; ok {
					// map with prefix exists
					if pid, ok := n.registered[req.opts.Prefix][req.opts.Name]; ok {

						newPidCreated = false

						if req.opts.Return_pid_if_registered == true {
							resp.pid = pid
						} else {
							// name already registered
							resp.pid = nil
							resp.err =
								fmt.Errorf("name '%s/%v' already registered",
									req.opts.Prefix, req.opts.Name)
						}
					} else {
						n.registered[req.opts.Prefix][req.opts.Name] = resp.pid
					}

				} else { // no maps with prefix
					n.registered[req.opts.Prefix] = make(regMap)
					n.registered[req.opts.Prefix][req.opts.Name] = resp.pid
				}
			}

			if newPidCreated {
				n.serial += 1
			}

			req.replyTo <- resp

		case req := <-n.registry.regNameChan:
			if _, ok := n.registered[req.prefix]; !ok {
				n.registered[req.prefix] = make(regMap)
			}
			if _, ok := n.registered[req.prefix][req.name]; ok {
				req.replyTo <- false // name registered
			} else {
				n.registered[req.prefix][req.name] = req.pid
				req.replyTo <- true
			}

		case req := <-n.registry.unregNameChan:
			if _, ok := n.registered[req.prefix]; ok {
				delete(n.registered[req.prefix], req.name)
			}

		case req := <-n.registry.whereNameChan:
			req.replyTo <- n.registered[req.prefix][req.name]

		case req := <-n.registry.wherePrefixChan:
			var rpids regMap
			if pids, ok := n.registered[req.prefix]; ok {
				rpids = make(regMap)
				for k, v := range pids {
					rpids[k] = v
				}
			}
			req.replyTo <- rpids
		}
	}
}

func (n *act) makePid(opts *Opts) (*Pid, error) {
	replyChan := make(chan makePidResp, 1)
	n.registry.makePidChan <- makePidReq{opts: opts, replyTo: replyChan}
	resp := <-replyChan

	return resp.pid, resp.err
}

func (pid *Pid) Id() uint64 {
	if pid == nil {
		return 0
	}

	return pid.id
}
<|endoftext|>


<commit_before>package sirius

import (
	"strings"

	"github.com/kayex/sirius/slack"
	api "github.com/nlopes/slack"
	"golang.org/x/net/context"
)

type Connection interface {
	Listen(context.Context)
	Auth() <-chan slack.UserID
	Send(*Message) error
	Update(*Message) error
	Messages() <-chan Message
	SelfChan() string
}

type RTMConnection struct {
	token    string
	rtm      *api.RTM
	client   *api.Client
	auth     chan slack.UserID
	messages chan Message
	selfChan string
}

func NewRTMConnection(token string) *RTMConnection {
	client := api.New(token)

	rtm := client.NewRTM()
	auth := make(chan slack.UserID, 1)
	msg := make(chan Message)

	return &RTMConnection{
		rtm:      rtm,
		auth:     auth,
		messages: msg,
		client:   client,
		token:    token,
	}
}

func (conn *RTMConnection) Listen(ctx context.Context) {
	go conn.rtm.ManageConnection()

	for {
		select {
		case <-ctx.Done():
			conn.rtm.Disconnect()
			return
		case ev := <-conn.rtm.IncomingEvents:
			conn.handleIncomingEvent(ev)
		}
	}
}

func (conn *RTMConnection) SelfChan() string {
	return conn.selfChan
}

func (conn *RTMConnection) Auth() <-chan slack.UserID {
	return conn.auth
}

func (conn *RTMConnection) Messages() <-chan Message {
	return conn.messages
}

func (conn *RTMConnection) Send(msg *Message) error {
	oMsg := conn.rtm.NewOutgoingMessage(msg.Text, msg.Channel)
	conn.rtm.SendMessage(oMsg)

	return nil
}

func (conn *RTMConnection) Update(msg *Message) error {
	_, _, _, err := conn.rtm.UpdateMessage(msg.Channel, msg.Timestamp, msg.Text)
	return err
}

func (conn *RTMConnection) authenticate(e *api.ConnectedEvent) {
	id := slack.UserID{e.Info.User.ID, e.Info.Team.ID}
	conn.selfChan = conn.getSelfChan(id, e)
	conn.auth <- id
}

func (conn *RTMConnection) getSelfChan(id slack.UserID, e *api.ConnectedEvent) string {
	for _, im := range e.Info.IMs {
		if im.User == id.UserID {
			return im.ID
		}
	}

	panic("")
}

func (conn *RTMConnection) handleIncomingEvent(ev api.RTMEvent) {
	switch msg := ev.Data.(type) {
	case *api.ConnectedEvent:
		conn.authenticate(msg)
	case *api.InvalidAuthEvent:
		panic(msg)
	case *api.MessageEvent:
		conn.handleIncomingMessage(msg)

	case *api.RTMError:
		panic(msg)
	}
}

func (conn *RTMConnection) handleIncomingMessage(ev *api.MessageEvent) {
	// Drop messages with incomplete data
	if ev.User == "" || ev.Team == "" {
		return
	}

	text := removeEscapeCharacters(ev.Text)
	msg := NewMessage(slack.UserID{ev.User, ev.Team}, text, ev.Channel, ev.Timestamp)

	conn.messages <- msg
}

var escapeCharacters map[string]string = map[string]string{
	"<":  "<",
	">":  ">",
	"&": "&",
}

func removeEscapeCharacters(msg string) string {
	for html, unicode := range escapeCharacters {
		msg = strings.Replace(msg, html, unicode, -1)
	}

	return msg
}
<commit_msg>Refactor api.go<commit_after>package sirius

import (
	"strings"

	"github.com/kayex/sirius/slack"
	api "github.com/nlopes/slack"
	"golang.org/x/net/context"
)

type API interface {
	GetUserID(token string) (slack.ID, error)
}

type MessageBroker interface {
	Send(*Message) error
	Update(*Message) error
	Messages() <-chan Message
}

type Connection interface {
	API
	MessageBroker
	Listen(context.Context)
	Auth() <-chan slack.UserID
	Details() ConnectionDetails
}

type ConnectionDetails struct {
	UserID   slack.UserID
	SelfChan string
}

type RTMConnection struct {
	token    string
	rtm      *api.RTM
	client   *api.Client
	auth     chan slack.UserID
	messages chan Message
	details  ConnectionDetails
}

func NewRTMConnection(token string) *RTMConnection {
	client := api.New(token)

	return &RTMConnection{
		token:    token,
		rtm:      client.NewRTM(),
		client:   client,
		auth:     make(chan slack.UserID, 1),
		messages: make(chan Message),
	}
}

func (conn *RTMConnection) Listen(ctx context.Context) {
	go conn.rtm.ManageConnection()

	for {
		select {
		case <-ctx.Done():
			conn.rtm.Disconnect()
			return
		case ev := <-conn.rtm.IncomingEvents:
			conn.handleIncomingEvent(ev)
		}
	}
}

func (conn *RTMConnection) Auth() <-chan slack.UserID {
	return conn.auth
}

func (conn *RTMConnection) Details() ConnectionDetails {
	return conn.details
}

func (conn *RTMConnection) Messages() <-chan Message {
	return conn.messages
}

func (conn *RTMConnection) Send(msg *Message) error {
	oMsg := conn.rtm.NewOutgoingMessage(msg.Text, msg.Channel)
	conn.rtm.SendMessage(oMsg)

	return nil
}

func (conn *RTMConnection) Update(msg *Message) error {
	_, _, _, err := conn.rtm.UpdateMessage(msg.Channel, msg.Timestamp, msg.Text)
	return err
}

func (conn *RTMConnection) GetUserID(token string) (slack.ID, error) {
	res, err := conn.client.AuthTest()

	if err != nil {
		return nil, err
	}

	id := &slack.UserID{
		UserID: res.UserID,
		TeamID: res.TeamID,
	}
	conn.details.UserID = *id

	return id, nil
}

func (conn *RTMConnection) authenticate(e *api.ConnectedEvent) {
	id := slack.UserID{e.Info.User.ID, e.Info.Team.ID}
	conn.details.SelfChan = conn.getSelfChan(id, e)
	conn.details.UserID = id
	conn.auth <- id
}

func (conn *RTMConnection) getSelfChan(id slack.UserID, e *api.ConnectedEvent) string {
	for _, im := range e.Info.IMs {
		if im.User == id.UserID {
			return im.ID
		}
	}

	panic("")
}

func (conn *RTMConnection) handleIncomingEvent(ev api.RTMEvent) {
	switch msg := ev.Data.(type) {
	case *api.ConnectedEvent:
		conn.authenticate(msg)
	case *api.InvalidAuthEvent:
		panic(msg)
	case *api.MessageEvent:
		conn.handleIncomingMessage(msg)

	case *api.RTMError:
		panic(msg)
	}
}

func (conn *RTMConnection) handleIncomingMessage(ev *api.MessageEvent) {
	// Drop messages with incomplete data
	if ev.User == "" || ev.Team == "" {
		return
	}

	text := removeEscapeCharacters(ev.Text)
	msg := NewMessage(slack.UserID{ev.User, ev.Team}, text, ev.Channel, ev.Timestamp)

	conn.messages <- msg
}

var escapeCharacters map[string]string = map[string]string{
	"<":  "<",
	">":  ">",
	"&": "&",
}

func removeEscapeCharacters(msg string) string {
	for html, unicode := range escapeCharacters {
		msg = strings.Replace(msg, html, unicode, -1)
	}

	return msg
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apiGatewayDeploy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"sync/atomic"
	"time"
)

// todo: the full set of states should probably be RECEIVED, READY, FAIL, SUCCESS
const (
	RESPONSE_STATUS_SUCCESS = "SUCCESS"
	RESPONSE_STATUS_FAIL    = "FAIL"
)

const (
	TRACKER_ERR_BUNDLE_DOWNLOAD_TIMEOUT = iota + 1
	TRACKER_ERR_BUNDLE_BAD_CHECKSUM
	TRACKER_ERR_DEPLOYMENT_BAD_JSON
)

const (
	API_ERR_BAD_BLOCK = iota + 1
	API_ERR_BAD_JSON
	API_ERR_BAD_CONTENT
	API_ERR_INTERNAL
)

const (
	sqlTimeFormat    = "2006-01-02 15:04:05.999 -0700 MST"
	iso8601          = "2006-01-02T15:04:05.999Z07:00"
	sqliteTimeFormat = "2006-01-02 15:04:05.999-07:00"
	changeTimeFormat = "2006-01-02 15:04:05.999"
)

type deploymentsResult struct {
	deployments []DataDeployment
	err         error
	eTag        string
}

var (
	deploymentsChanged = make(chan interface{}, 5)
	addSubscriber      = make(chan chan deploymentsResult)
	removeSubscriber   = make(chan chan deploymentsResult)
	eTag               int64
)

type errorResponse struct {
	ErrorCode int    `json:"errorCode"`
	Reason    string `json:"reason"`
}

type ApiDeployment struct {
	ID               string          `json:"id"`
	ScopeId          string          `json:"scopeId"`
	Created          string          `json:"created"`
	CreatedBy        string          `json:"createdBy"`
	Updated          string          `json:"updated"`
	UpdatedBy        string          `json:"updatedBy"`
	ConfigJson       json.RawMessage `json:"configuration"`
	BundleConfigJson json.RawMessage `json:"bundleConfiguration"`
	DisplayName      string          `json:"displayName"`
	URI              string          `json:"uri"`
}

// sent to client
type ApiDeploymentResponse []ApiDeployment

type apiDeploymentResult struct {
	ID        string `json:"id"`
	Status    string `json:"status"`
	ErrorCode int    `json:"errorCode"`
	Message   string `json:"message"`
}

// received from client
type apiDeploymentResults []apiDeploymentResult

const deploymentsEndpoint = "/deployments"

func InitAPI() {
	services.API().HandleFunc(deploymentsEndpoint, apiGetCurrentDeployments).Methods("GET")
	services.API().HandleFunc(deploymentsEndpoint, apiSetDeploymentResults).Methods("PUT")
}

func writeError(w http.ResponseWriter, status int, code int, reason string) {
	w.WriteHeader(status)
	e := errorResponse{
		ErrorCode: code,
		Reason:    reason,
	}
	bytes, err := json.Marshal(e)
	if err != nil {
		log.Errorf("unable to marshal errorResponse: %v", err)
	} else {
		w.Write(bytes)
	}
	log.Debugf("sending %d error to client: %s", status, reason)
}

func writeDatabaseError(w http.ResponseWriter) {
	writeError(w, http.StatusInternalServerError, API_ERR_INTERNAL, "database error")
}

func debounce(in chan interface{}, out chan []interface{}, window time.Duration) {
	send := func(toSend []interface{}) {
		if toSend != nil {
			log.Debugf("debouncer sending: %v", toSend)
			out <- toSend
		}
	}
	var toSend []interface{}
	for {
		select {
		case incoming, ok := <-in:
			if ok {
				log.Debugf("debouncing %v", incoming)
				toSend = append(toSend, incoming)
			} else {
				send(toSend)
				log.Debugf("closing debouncer")
				close(out)
				return
			}
		case <-time.After(window):
			send(toSend)
			toSend = nil
		}
	}
}

func distributeEvents() {
	subscribers := make(map[chan deploymentsResult]struct{})
	deliverDeployments := make(chan []interface{}, 1)

	go debounce(deploymentsChanged, deliverDeployments, debounceDuration)

	for {
		select {
		case _, ok := <-deliverDeployments:
			if !ok {
				return // todo: using this?
			}
			subs := subscribers
			subscribers = make(map[chan deploymentsResult]struct{})
			go func() {
				eTag := incrementETag()
				deployments, err := getReadyDeployments()
				log.Debugf("delivering deployments to %d subscribers", len(subs))
				for subscriber := range subs {
					log.Debugf("delivering to: %v", subscriber)
					subscriber <- deploymentsResult{deployments, err, eTag}
				}
			}()
		case subscriber := <-addSubscriber:
			log.Debugf("Add subscriber: %v", subscriber)
			subscribers[subscriber] = struct{}{}
		case subscriber := <-removeSubscriber:
			log.Debugf("Remove subscriber: %v", subscriber)
			delete(subscribers, subscriber)
		}
	}
}

func apiGetCurrentDeployments(w http.ResponseWriter, r *http.Request) {

	// If returning without a bundle (immediately or after timeout), status = 404
	// If returning If-None-Match value is equal to current deployment, status = 304
	// If returning a new value, status = 200

	// If timeout > 0 AND there is no deployment (or new deployment) available (per If-None-Match), then
	// block for up to the specified number of seconds until a new deployment becomes available.
	b := r.URL.Query().Get("block")
	var timeout int
	if b != "" {
		var err error
		timeout, err = strconv.Atoi(b)
		if err != nil {
			writeError(w, http.StatusBadRequest, API_ERR_BAD_BLOCK, "bad block value, must be number of seconds")
			return
		}
	}
	log.Debugf("api timeout: %d", timeout)

	// If If-None-Match header matches the ETag of current bundle list AND if the request does NOT have a 'block'
	// query param > 0, the server returns a 304 Not Modified response indicating that the client already has the
	// most recent bundle list.
	ifNoneMatch := r.Header.Get("If-None-Match")
	log.Debugf("if-none-match: %s", ifNoneMatch)

	// send unmodified if matches prior eTag and no timeout
	eTag := getETag()
	if eTag == ifNoneMatch && timeout == 0 {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	// send results if different eTag
	if eTag != ifNoneMatch {
		sendReadyDeployments(w)
		return
	}

	// otherwise, subscribe to any new deployment changes
	var newDeploymentsChannel chan deploymentsResult
	if timeout > 0 && ifNoneMatch != "" {
		newDeploymentsChannel = make(chan deploymentsResult, 1)
		addSubscriber <- newDeploymentsChannel
	}

	log.Debug("Blocking request... Waiting for new Deployments.")

	select {
	case result := <-newDeploymentsChannel:
		if result.err != nil {
			writeDatabaseError(w)
		} else {
			sendDeployments(w, result.deployments, result.eTag)
		}

	case <-time.After(time.Duration(timeout) * time.Second):
		removeSubscriber <- newDeploymentsChannel
		log.Debug("Blocking deployment request timed out.")
		if ifNoneMatch != "" {
			w.WriteHeader(http.StatusNotModified)
		} else {
			sendReadyDeployments(w)
		}
	}
}

func sendReadyDeployments(w http.ResponseWriter) {
	eTag := getETag()
	deployments, err := getReadyDeployments()
	if err != nil {
		writeDatabaseError(w)
		return
	}
	sendDeployments(w, deployments, eTag)
}

func sendDeployments(w http.ResponseWriter, dataDeps []DataDeployment, eTag string) {

	apiDeps := ApiDeploymentResponse{}

	for _, d := range dataDeps {
		apiDeps = append(apiDeps, ApiDeployment{
			ID:               d.ID,
			ScopeId:          d.DataScopeID,
			Created:          convertTime(d.Created),
			CreatedBy:        d.CreatedBy,
			Updated:          convertTime(d.Updated),
			UpdatedBy:        d.UpdatedBy,
			BundleConfigJson: []byte(d.BundleConfigJSON),
			ConfigJson:       []byte(d.ConfigJSON),
			DisplayName:      d.BundleName,
			URI:              d.LocalBundleURI,
		})
	}

	b, err := json.Marshal(apiDeps)
	if err != nil {
		log.Errorf("unable to marshal deployments: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Debugf("sending deployments %s: %s", eTag, b)
	w.Header().Set("ETag", eTag)
	w.Write(b)
}

func apiSetDeploymentResults(w http.ResponseWriter, r *http.Request) {

	var results apiDeploymentResults
	buf, _ := ioutil.ReadAll(r.Body)
	err := json.Unmarshal(buf, &results)
	if err != nil {
		log.Errorf("Resp Handler Json Unmarshal err: ", err)
		writeError(w, http.StatusBadRequest, API_ERR_BAD_JSON, "Malformed JSON")
		return
	}

	// validate the results
	// todo: these errors to the client should be standardized
	var errs bytes.Buffer
	var validResults apiDeploymentResults
	for i, result := range results {
		valid := true
		if result.ID == "" {
			errs.WriteString(fmt.Sprintf("Missing id at %d\n", i))
		}

		if result.Status != RESPONSE_STATUS_SUCCESS && result.Status != RESPONSE_STATUS_FAIL {
			errs.WriteString(fmt.Sprintf("status must be '%s' or '%s' at %d\n",
				RESPONSE_STATUS_SUCCESS, RESPONSE_STATUS_FAIL, i))
		}

		if result.Status == RESPONSE_STATUS_FAIL {
			if result.ErrorCode == 0 {
				errs.WriteString(fmt.Sprintf("errorCode is required for status == fail at %d\n", i))
			}
			if result.Message == "" {
				errs.WriteString(fmt.Sprintf("message are required for status == fail at %d\n", i))
			}
		}

		if valid {
			validResults = append(validResults, result)
		}
	}

	if errs.Len() > 0 {
		writeError(w, http.StatusBadRequest, API_ERR_BAD_CONTENT, errs.String())
		return
	}

	if len(validResults) > 0 {
		setDeploymentResults(validResults)
	}

	w.Write([]byte("OK"))
}

func addHeaders(req *http.Request) {
	var token = services.Config().GetString("apigeesync_bearer_token")
	req.Header.Add("Authorization", "Bearer "+token)
}

func transmitDeploymentResultsToServer(validResults apiDeploymentResults) error {

	retryIn := bundleRetryDelay
	maxBackOff := 5 * time.Minute
	backOffFunc := createBackoff(retryIn, maxBackOff)

	_, err := url.Parse(apiServerBaseURI.String())
	if err != nil {
		log.Errorf("unable to parse apiServerBaseURI %s: %v", apiServerBaseURI.String(), err)
		return err
	}
	apiPath := fmt.Sprintf("%s/clusters/%s/apids/%s/deployments", apiServerBaseURI.String(), apidClusterID, apidInstanceID)

	resultJSON, err := json.Marshal(validResults)
	if err != nil {
		log.Errorf("unable to marshal deployment results %v: %v", validResults, err)
		return err
	}

	for {
		log.Debugf("transmitting deployment results to tracker by URL=%s data=%s", apiPath, string(resultJSON))
		req, err := http.NewRequest("PUT", apiPath, bytes.NewReader(resultJSON))
		if err != nil {
			log.Errorf("unable to create PUT request", err)
			return err
		}
		req.Header.Add("Content-Type", "application/json")
		addHeaders(req)

		resp, err := http.DefaultClient.Do(req)
		if err != nil || resp.StatusCode != http.StatusOK {
			if err != nil {
				log.Errorf("failed to communicate with tracking service: %v", err)
			} else {
				b, _ := ioutil.ReadAll(resp.Body)
				log.Errorf("tracking service call failed to %s, code: %d, body: %s", apiPath, resp.StatusCode, string(b))
			}
			resp.Body.Close()
			backOffFunc()
			continue
		}
		resp.Body.Close()
		return nil
	}
}

// call whenever the list of deployments changes
func incrementETag() string {
	e := atomic.AddInt64(&eTag, 1)
	return strconv.FormatInt(e, 10)
}

func getETag() string {
	e := atomic.LoadInt64(&eTag)
	return strconv.FormatInt(e, 10)
}

func convertTime(t string) string {
	if t == "" {
		return ""
	}
	formats := []string{sqliteTimeFormat, sqlTimeFormat, iso8601, time.RFC3339, changeTimeFormat}
	for _, f := range formats {
		timestamp, err := time.Parse(f, t)
		if err == nil {
			return timestamp.Format(iso8601)
		}
	}
	log.Panic("convertTime: Unsupported time format: " + t)
	return ""
}
<commit_msg>change log level<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apiGatewayDeploy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"sync/atomic"
	"time"
)

// todo: the full set of states should probably be RECEIVED, READY, FAIL, SUCCESS
const (
	RESPONSE_STATUS_SUCCESS = "SUCCESS"
	RESPONSE_STATUS_FAIL    = "FAIL"
)

const (
	TRACKER_ERR_BUNDLE_DOWNLOAD_TIMEOUT = iota + 1
	TRACKER_ERR_BUNDLE_BAD_CHECKSUM
	TRACKER_ERR_DEPLOYMENT_BAD_JSON
)

const (
	API_ERR_BAD_BLOCK = iota + 1
	API_ERR_BAD_JSON
	API_ERR_BAD_CONTENT
	API_ERR_INTERNAL
)

const (
	sqlTimeFormat    = "2006-01-02 15:04:05.999 -0700 MST"
	iso8601          = "2006-01-02T15:04:05.999Z07:00"
	sqliteTimeFormat = "2006-01-02 15:04:05.999-07:00"
	changeTimeFormat = "2006-01-02 15:04:05.999"
)

type deploymentsResult struct {
	deployments []DataDeployment
	err         error
	eTag        string
}

var (
	deploymentsChanged = make(chan interface{}, 5)
	addSubscriber      = make(chan chan deploymentsResult)
	removeSubscriber   = make(chan chan deploymentsResult)
	eTag               int64
)

type errorResponse struct {
	ErrorCode int    `json:"errorCode"`
	Reason    string `json:"reason"`
}

type ApiDeployment struct {
	ID               string          `json:"id"`
	ScopeId          string          `json:"scopeId"`
	Created          string          `json:"created"`
	CreatedBy        string          `json:"createdBy"`
	Updated          string          `json:"updated"`
	UpdatedBy        string          `json:"updatedBy"`
	ConfigJson       json.RawMessage `json:"configuration"`
	BundleConfigJson json.RawMessage `json:"bundleConfiguration"`
	DisplayName      string          `json:"displayName"`
	URI              string          `json:"uri"`
}

// sent to client
type ApiDeploymentResponse []ApiDeployment

type apiDeploymentResult struct {
	ID        string `json:"id"`
	Status    string `json:"status"`
	ErrorCode int    `json:"errorCode"`
	Message   string `json:"message"`
}

// received from client
type apiDeploymentResults []apiDeploymentResult

const deploymentsEndpoint = "/deployments"

func InitAPI() {
	services.API().HandleFunc(deploymentsEndpoint, apiGetCurrentDeployments).Methods("GET")
	services.API().HandleFunc(deploymentsEndpoint, apiSetDeploymentResults).Methods("PUT")
}

func writeError(w http.ResponseWriter, status int, code int, reason string) {
	w.WriteHeader(status)
	e := errorResponse{
		ErrorCode: code,
		Reason:    reason,
	}
	bytes, err := json.Marshal(e)
	if err != nil {
		log.Errorf("unable to marshal errorResponse: %v", err)
	} else {
		w.Write(bytes)
	}
	log.Debugf("sending %d error to client: %s", status, reason)
}

func writeDatabaseError(w http.ResponseWriter) {
	writeError(w, http.StatusInternalServerError, API_ERR_INTERNAL, "database error")
}

func debounce(in chan interface{}, out chan []interface{}, window time.Duration) {
	send := func(toSend []interface{}) {
		if toSend != nil {
			log.Debugf("debouncer sending: %v", toSend)
			out <- toSend
		}
	}
	var toSend []interface{}
	for {
		select {
		case incoming, ok := <-in:
			if ok {
				log.Debugf("debouncing %v", incoming)
				toSend = append(toSend, incoming)
			} else {
				send(toSend)
				log.Debugf("closing debouncer")
				close(out)
				return
			}
		case <-time.After(window):
			send(toSend)
			toSend = nil
		}
	}
}

func distributeEvents() {
	subscribers := make(map[chan deploymentsResult]struct{})
	deliverDeployments := make(chan []interface{}, 1)

	go debounce(deploymentsChanged, deliverDeployments, debounceDuration)

	for {
		select {
		case _, ok := <-deliverDeployments:
			if !ok {
				return // todo: using this?
			}
			subs := subscribers
			subscribers = make(map[chan deploymentsResult]struct{})
			go func() {
				eTag := incrementETag()
				deployments, err := getReadyDeployments()
				log.Debugf("delivering deployments to %d subscribers", len(subs))
				for subscriber := range subs {
					log.Debugf("delivering to: %v", subscriber)
					subscriber <- deploymentsResult{deployments, err, eTag}
				}
			}()
		case subscriber := <-addSubscriber:
			log.Debugf("Add subscriber: %v", subscriber)
			subscribers[subscriber] = struct{}{}
		case subscriber := <-removeSubscriber:
			log.Debugf("Remove subscriber: %v", subscriber)
			delete(subscribers, subscriber)
		}
	}
}

func apiGetCurrentDeployments(w http.ResponseWriter, r *http.Request) {

	// If returning without a bundle (immediately or after timeout), status = 404
	// If returning If-None-Match value is equal to current deployment, status = 304
	// If returning a new value, status = 200

	// If timeout > 0 AND there is no deployment (or new deployment) available (per If-None-Match), then
	// block for up to the specified number of seconds until a new deployment becomes available.
	b := r.URL.Query().Get("block")
	var timeout int
	if b != "" {
		var err error
		timeout, err = strconv.Atoi(b)
		if err != nil {
			writeError(w, http.StatusBadRequest, API_ERR_BAD_BLOCK, "bad block value, must be number of seconds")
			return
		}
	}
	log.Debugf("api timeout: %d", timeout)

	// If If-None-Match header matches the ETag of current bundle list AND if the request does NOT have a 'block'
	// query param > 0, the server returns a 304 Not Modified response indicating that the client already has the
	// most recent bundle list.
	ifNoneMatch := r.Header.Get("If-None-Match")
	log.Debugf("if-none-match: %s", ifNoneMatch)

	// send unmodified if matches prior eTag and no timeout
	eTag := getETag()
	if eTag == ifNoneMatch && timeout == 0 {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	// send results if different eTag
	if eTag != ifNoneMatch {
		sendReadyDeployments(w)
		return
	}

	// otherwise, subscribe to any new deployment changes
	var newDeploymentsChannel chan deploymentsResult
	if timeout > 0 && ifNoneMatch != "" {
		newDeploymentsChannel = make(chan deploymentsResult, 1)
		addSubscriber <- newDeploymentsChannel
	}

	log.Debug("Blocking request... Waiting for new Deployments.")

	select {
	case result := <-newDeploymentsChannel:
		if result.err != nil {
			writeDatabaseError(w)
		} else {
			sendDeployments(w, result.deployments, result.eTag)
		}

	case <-time.After(time.Duration(timeout) * time.Second):
		removeSubscriber <- newDeploymentsChannel
		log.Debug("Blocking deployment request timed out.")
		if ifNoneMatch != "" {
			w.WriteHeader(http.StatusNotModified)
		} else {
			sendReadyDeployments(w)
		}
	}
}

func sendReadyDeployments(w http.ResponseWriter) {
	eTag := getETag()
	deployments, err := getReadyDeployments()
	if err != nil {
		writeDatabaseError(w)
		return
	}
	sendDeployments(w, deployments, eTag)
}

func sendDeployments(w http.ResponseWriter, dataDeps []DataDeployment, eTag string) {

	apiDeps := ApiDeploymentResponse{}

	for _, d := range dataDeps {
		apiDeps = append(apiDeps, ApiDeployment{
			ID:               d.ID,
			ScopeId:          d.DataScopeID,
			Created:          convertTime(d.Created),
			CreatedBy:        d.CreatedBy,
			Updated:          convertTime(d.Updated),
			UpdatedBy:        d.UpdatedBy,
			BundleConfigJson: []byte(d.BundleConfigJSON),
			ConfigJson:       []byte(d.ConfigJSON),
			DisplayName:      d.BundleName,
			URI:              d.LocalBundleURI,
		})
	}

	b, err := json.Marshal(apiDeps)
	if err != nil {
		log.Errorf("unable to marshal deployments: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Debugf("sending deployments %s: %s", eTag, b)
	w.Header().Set("ETag", eTag)
	w.Write(b)
}

func apiSetDeploymentResults(w http.ResponseWriter, r *http.Request) {

	var results apiDeploymentResults
	buf, _ := ioutil.ReadAll(r.Body)
	err := json.Unmarshal(buf, &results)
	if err != nil {
		log.Errorf("Resp Handler Json Unmarshal err: ", err)
		writeError(w, http.StatusBadRequest, API_ERR_BAD_JSON, "Malformed JSON")
		return
	}

	// validate the results
	// todo: these errors to the client should be standardized
	var errs bytes.Buffer
	var validResults apiDeploymentResults
	for i, result := range results {
		valid := true
		if result.ID == "" {
			errs.WriteString(fmt.Sprintf("Missing id at %d\n", i))
		}

		if result.Status != RESPONSE_STATUS_SUCCESS && result.Status != RESPONSE_STATUS_FAIL {
			errs.WriteString(fmt.Sprintf("status must be '%s' or '%s' at %d\n",
				RESPONSE_STATUS_SUCCESS, RESPONSE_STATUS_FAIL, i))
		}

		if result.Status == RESPONSE_STATUS_FAIL {
			if result.ErrorCode == 0 {
				errs.WriteString(fmt.Sprintf("errorCode is required for status == fail at %d\n", i))
			}
			if result.Message == "" {
				errs.WriteString(fmt.Sprintf("message are required for status == fail at %d\n", i))
			}
		}

		if valid {
			validResults = append(validResults, result)
		}
	}

	if errs.Len() > 0 {
		writeError(w, http.StatusBadRequest, API_ERR_BAD_CONTENT, errs.String())
		return
	}

	if len(validResults) > 0 {
		setDeploymentResults(validResults)
	}

	w.Write([]byte("OK"))
}

func addHeaders(req *http.Request) {
	var token = services.Config().GetString("apigeesync_bearer_token")
	req.Header.Add("Authorization", "Bearer "+token)
}

func transmitDeploymentResultsToServer(validResults apiDeploymentResults) error {

	retryIn := bundleRetryDelay
	maxBackOff := 5 * time.Minute
	backOffFunc := createBackoff(retryIn, maxBackOff)

	_, err := url.Parse(apiServerBaseURI.String())
	if err != nil {
		log.Errorf("unable to parse apiServerBaseURI %s: %v", apiServerBaseURI.String(), err)
		return err
	}
	apiPath := fmt.Sprintf("%s/clusters/%s/apids/%s/deployments", apiServerBaseURI.String(), apidClusterID, apidInstanceID)

	resultJSON, err := json.Marshal(validResults)
	if err != nil {
		log.Errorf("unable to marshal deployment results %v: %v", validResults, err)
		return err
	}

	for {
		log.Debugf("transmitting deployment results to tracker by URL=%s data=%s", apiPath, string(resultJSON))
		req, err := http.NewRequest("PUT", apiPath, bytes.NewReader(resultJSON))
		if err != nil {
			log.Errorf("unable to create PUT request", err)
			return err
		}
		req.Header.Add("Content-Type", "application/json")
		addHeaders(req)

		resp, err := http.DefaultClient.Do(req)
		if err != nil || resp.StatusCode != http.StatusOK {
			if err != nil {
				log.Errorf("failed to communicate with tracking service: %v", err)
			} else {
				b, _ := ioutil.ReadAll(resp.Body)
				log.Errorf("tracking service call failed to %s, code: %d, body: %s", apiPath, resp.StatusCode, string(b))
			}
			resp.Body.Close()
			backOffFunc()
			continue
		}
		resp.Body.Close()
		return nil
	}
}

// call whenever the list of deployments changes
func incrementETag() string {
	e := atomic.AddInt64(&eTag, 1)
	return strconv.FormatInt(e, 10)
}

func getETag() string {
	e := atomic.LoadInt64(&eTag)
	return strconv.FormatInt(e, 10)
}

func convertTime(t string) string {
	if t == "" {
		return ""
	}
	formats := []string{sqliteTimeFormat, sqlTimeFormat, iso8601, time.RFC3339, changeTimeFormat}
	for _, f := range formats {
		timestamp, err := time.Parse(f, t)
		if err == nil {
			return timestamp.Format(iso8601)
		}
	}
	log.Error("convertTime: Unsupported time format: " + t)
	return t
}
<|endoftext|>


<commit_before>// Clients are expected to attempt a handshake if they receive HTTP 401
//
//
// Any method may return HTTP 500
package main

// vim: set noexpandtab:

import (
	//"bytes"
	"crypto/rand"
	"github.com/emicklei/go-restful"
	"github.com/gokyle/cryptobox/box"
	"github.com/golang/glog"
	//"crypto/x509"
	//	"database/sql"
	"encoding/base64"
	//"fmt"
	//"errors"
	"fmt"
	"io"
	"net/http"
	//"time"
	"regexp"
	"strconv"
)

const (
	challengeSize int = 16 // bytes
	tokenSize     int = 32 // bytes
)

func checkAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	var err error
	var token *http.Cookie
	var id int64
	var valid bool
	token, err = req.Request.Cookie("Token")
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Token' not set in cookie")
		}
		resp.WriteErrorString(400, "'Token' not set in cookie")
		return
	}
	idStr, err := req.Request.Cookie("Id")
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Id' not set in cookie")
		}
		resp.WriteErrorString(400, "'Id' not set in cookie")
		return
	}
	id, err = strconv.ParseInt(idStr.Value, 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Id' not valid int64")
		}
		resp.WriteErrorString(400, "'Id' not valid int64")
		return
	}
	err = q["checkToken"].QueryRow(id, decodeBase64(token.Value)).Scan(&valid)
	if err != nil {
		if glog.V(2) {
			glog.Errorf("Token checking SQL returned error: %v\n", q["checkToken"])
		}
		resp.WriteErrorString(500, "error checking token")
		return
	}
	if !valid {
		if glog.V(1) {
			glog.Infof("Auth BAD for %d\n", id)
		}
		resp.WriteErrorString(401, "Unauthenticated")
		return
	}
	if glog.V(1) {
		glog.Infof("Auth OK for %d\n", id)
	}
	chain.ProcessFilter(req, resp)
}

func checkAuthorization(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	idStr, _ := req.Request.Cookie("Id")
	id, _ := strconv.ParseInt(idStr.Value, 10, 64)
	u, _ := GetUser(id)
	if path, _ := regexp.MatchString("^/api/user(/.*)?$", req.Request.URL.Path); path {
		switch req.Request.Method {
		case "DELETE", "PUT":
			if !u.Admin || req.PathParameter("id") != string(u.Id) {
				resp.WriteErrorString(403, "Unauthorized")
				return
			}
		case "POST":
			if !u.Admin {
				resp.WriteErrorString(403, "Unauthorized")
				return
			}
		default:
			break
		}
	}
	chain.ProcessFilter(req, resp)
	return
}

// GET /api/auth?name=me
//     {"id": int, "challenge": <base64 string>}
func getChallenge(req *restful.Request, resp *restful.Response) {
	var err error
	var name string = req.PathParameter("name")
	var c []byte = make([]byte, challengeSize)

	u, err := GetUserByName(name)
	if err != nil {
		if glog.V(2) {
			glog.Errorln(err)
		}
		resp.WriteErrorString(http.StatusBadRequest, "Cannot find user")
		return
	}

	_, err = io.ReadFull(rand.Reader, c)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error generating challenge")
		return
	}

	//box, ok := box.SignAndSeal(c, boxPriv, boxPub, *u.PubKey)
	box, ok := box.Seal(c, u.PubKey)
	if !ok {
		glog.Errorln("Error boxing challenge")
		resp.WriteErrorString(http.StatusInternalServerError, "Error boxing challenge")
		return
	}
	err = SaveChallenge(u.Id, c)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error recording challenge")
		return
	}

	resp.WriteEntity(&map[string]string{"challenge": base64.StdEncoding.EncodeToString(box), "id": fmt.Sprintf("%d", u.Id)})
	if glog.V(1) {
		glog.Infof("Auth.Login: sent challenge for %s\n", name)
		if glog.V(3) {
			glog.Infof("id:\t%d\n", u.Id)
			glog.Infof("token:\t%x\n", c)
			glog.Infof("encrypted challenge:\t%v\n", base64.StdEncoding.EncodeToString(box))
		}
	}
	return
}

// POST /api/auth {"id": <int>, "challenge": <base64 string>}
//      <Cookies>
func postChallenge(req *restful.Request, resp *restful.Response) {
	var err error
	var tok []byte = make([]byte, tokenSize)
	var c map[string]string

	err = req.ReadEntity(&c)
	if err != nil {
		if glog.V(1) {
			glog.Warningln(err)
		}
		resp.WriteErrorString(http.StatusInternalServerError, "Error deserialzing response")
		return
	}

	if glog.V(3) {
		glog.Infof("recv'd:\t%+v\n", c)
	}
	_, okC := c["challenge"]
	_, okI := c["id"]
	if !(okC && okI) {
		if glog.V(2) {
			glog.Warningln("Malformed response")
		}
		resp.WriteErrorString(http.StatusBadRequest, "Malformed response")
		return
	}

	id, err := strconv.ParseInt(c["id"], 10, 64)
	if err != nil {
		resp.WriteErrorString(http.StatusBadRequest, "Invalid Credentials")
		return
	}

	if !CheckChallenge(id, decodeBase64(c["challenge"])) {
		resp.WriteErrorString(http.StatusBadRequest, "Invalid Credentials")
		return
	}

	_, err = io.ReadFull(rand.Reader, tok)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error generating token")
		return
	}

	err = SaveToken(id, tok)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error saving token")
		return
	}

	for k, v := range map[string]string{
		"Token": base64.StdEncoding.EncodeToString(tok),
		"Id":    fmt.Sprintf("%d", id),
	} {
		cookie := &http.Cookie{Name: k, Value: v}
		http.SetCookie(resp.ResponseWriter, cookie)
		if glog.V(3) {
			glog.Infof("Set cookie:\t%s:%s\n", k, v)
		}
	}
	if glog.V(3) {
		glog.Infof("Send auth token for %d\n", id)
	}

	return
}

func fetchUser(req *restful.Request, resp *restful.Response) {
	id, err := strconv.ParseInt(req.PathParameter("id"), 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("unable to parse id")
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to parse Id")
		return
	}
	u, err := GetUser(id)
	if err != nil {
		if glog.V(2) {
			glog.Warningf("unable to find user with id %d\n", id)
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to find user with Id")
		return
	}
	if glog.V(3) {
		glog.Infof("Sent info for user %d\n", id)
	}
	resp.WriteEntity(u)
}

func createUser(req *restful.Request, resp *restful.Response) {
	var err error
	var body struct {
		Admin  bool
		Name   string
		Groups []int64
	}

	err = req.ReadEntity(&body)
	if err != nil {
		glog.Info("Malformed body")
		resp.WriteErrorString(http.StatusBadRequest, "malformed body")
		return
	}
	if glog.V(3) {
		glog.Info(body)
	}
}

func modifyUser(req *restful.Request, resp *restful.Response) {
}

func removeUser(req *restful.Request, resp *restful.Response) {
}

func searchUser(req *restful.Request, resp *restful.Response) {
	var name string = req.QueryParameter("name")
	var id []int64
	rows, err := db.Query("SELECT id FROM users WHERE name LIKE $1;", name)
	if err != nil {
		glog.Error(err)
		return
	}

	for rows.Next() {
		var t int64
		if err := rows.Scan(&t); err != nil {
			glog.Error(err)
			return
		}
		id = append(id, t)
	}

	if len(id) == 0 {
		if glog.V(2) {
			glog.Infof("bad name: %s\n", name)
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to find any user with name")
		return
	}
	if glog.V(3) {
		glog.Infof("Successful search for user %d\n", id)
	}
	resp.WriteEntity(&map[string][]int64{"id": id})
}
<commit_msg>add user mod/delte functions<commit_after>// Clients are expected to attempt a handshake if they receive HTTP 401
//
//
// Any method may return HTTP 500
package main

// vim: set noexpandtab:

import (
	//"bytes"
	"crypto/rand"
	"github.com/emicklei/go-restful"
	"github.com/gokyle/cryptobox/box"
	"github.com/golang/glog"
	//"crypto/x509"
	//	"database/sql"
	"encoding/base64"
	//"fmt"
	//"errors"
	"fmt"
	"io"
	"net/http"
	//"time"
	"regexp"
	"strconv"
)

const (
	challengeSize int = 16 // bytes
	tokenSize     int = 32 // bytes
)

func checkAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	var err error
	var token *http.Cookie
	var id int64
	var valid bool
	token, err = req.Request.Cookie("Token")
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Token' not set in cookie")
		}
		resp.WriteErrorString(400, "'Token' not set in cookie")
		return
	}
	idStr, err := req.Request.Cookie("Id")
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Id' not set in cookie")
		}
		resp.WriteErrorString(400, "'Id' not set in cookie")
		return
	}
	id, err = strconv.ParseInt(idStr.Value, 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("'Id' not valid int64")
		}
		resp.WriteErrorString(400, "'Id' not valid int64")
		return
	}
	err = q["checkToken"].QueryRow(id, decodeBase64(token.Value)).Scan(&valid)
	if err != nil {
		if glog.V(2) {
			glog.Errorf("Token checking SQL returned error: %v\n", q["checkToken"])
		}
		resp.WriteErrorString(500, "error checking token")
		return
	}
	if !valid {
		if glog.V(1) {
			glog.Infof("Auth BAD for %d\n", id)
		}
		resp.WriteErrorString(401, "Unauthenticated")
		return
	}
	if glog.V(1) {
		glog.Infof("Auth OK for %d\n", id)
	}
	chain.ProcessFilter(req, resp)
}

func checkAuthorization(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	idStr, _ := req.Request.Cookie("Id")
	id, _ := strconv.ParseInt(idStr.Value, 10, 64)
	u, _ := GetUser(id)
	if path, _ := regexp.MatchString("^/api/user(/.*)?$", req.Request.URL.Path); path {
		switch req.Request.Method {
		case "DELETE", "PUT":
			if !u.Admin || req.PathParameter("id") != string(u.Id) {
				resp.WriteErrorString(403, "Unauthorized")
				return
			}
		case "POST":
			if !u.Admin {
				resp.WriteErrorString(403, "Unauthorized")
				return
			}
		default:
			break
		}
	}
	chain.ProcessFilter(req, resp)
	return
}

// GET /api/auth?name=me
//     {"id": int, "challenge": <base64 string>}
func getChallenge(req *restful.Request, resp *restful.Response) {
	var err error
	var name string = req.PathParameter("name")
	var c []byte = make([]byte, challengeSize)

	u, err := GetUserByName(name)
	if err != nil {
		if glog.V(2) {
			glog.Errorln(err)
		}
		resp.WriteErrorString(http.StatusBadRequest, "Cannot find user")
		return
	}

	_, err = io.ReadFull(rand.Reader, c)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error generating challenge")
		return
	}

	//box, ok := box.SignAndSeal(c, boxPriv, boxPub, *u.PubKey)
	box, ok := box.Seal(c, u.PubKey)
	if !ok {
		glog.Errorln("Error boxing challenge")
		resp.WriteErrorString(http.StatusInternalServerError, "Error boxing challenge")
		return
	}
	err = SaveChallenge(u.Id, c)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error recording challenge")
		return
	}

	resp.WriteEntity(&map[string]string{"challenge": base64.StdEncoding.EncodeToString(box), "id": fmt.Sprintf("%d", u.Id)})
	if glog.V(1) {
		glog.Infof("Auth.Login: sent challenge for %s\n", name)
		if glog.V(3) {
			glog.Infof("id:\t%d\n", u.Id)
			glog.Infof("token:\t%x\n", c)
			glog.Infof("encrypted challenge:\t%v\n", base64.StdEncoding.EncodeToString(box))
		}
	}
	return
}

// POST /api/auth {"id": <int>, "challenge": <base64 string>}
//      <Cookies>
func postChallenge(req *restful.Request, resp *restful.Response) {
	var err error
	var tok []byte = make([]byte, tokenSize)
	var c map[string]string

	err = req.ReadEntity(&c)
	if err != nil {
		if glog.V(1) {
			glog.Warningln(err)
		}
		resp.WriteErrorString(http.StatusInternalServerError, "Error deserialzing response")
		return
	}

	if glog.V(3) {
		glog.Infof("recv'd:\t%+v\n", c)
	}
	_, okC := c["challenge"]
	_, okI := c["id"]
	if !(okC && okI) {
		if glog.V(2) {
			glog.Warningln("Malformed response")
		}
		resp.WriteErrorString(http.StatusBadRequest, "Malformed response")
		return
	}

	id, err := strconv.ParseInt(c["id"], 10, 64)
	if err != nil {
		resp.WriteErrorString(http.StatusBadRequest, "Invalid Credentials")
		return
	}

	if !CheckChallenge(id, decodeBase64(c["challenge"])) {
		resp.WriteErrorString(http.StatusBadRequest, "Invalid Credentials")
		return
	}

	_, err = io.ReadFull(rand.Reader, tok)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error generating token")
		return
	}

	err = SaveToken(id, tok)
	if err != nil {
		glog.Errorln(err)
		resp.WriteErrorString(http.StatusInternalServerError, "Error saving token")
		return
	}

	for k, v := range map[string]string{
		"Token": base64.StdEncoding.EncodeToString(tok),
		"Id":    fmt.Sprintf("%d", id),
	} {
		cookie := &http.Cookie{Name: k, Value: v}
		http.SetCookie(resp.ResponseWriter, cookie)
		if glog.V(3) {
			glog.Infof("Set cookie:\t%s:%s\n", k, v)
		}
	}
	if glog.V(3) {
		glog.Infof("Send auth token for %d\n", id)
	}

	return
}

func fetchUser(req *restful.Request, resp *restful.Response) {
	id, err := strconv.ParseInt(req.PathParameter("id"), 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("unable to parse id")
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to parse Id")
		return
	}
	u, err := GetUser(id)
	if err != nil {
		if glog.V(2) {
			glog.Warningf("unable to find user with id %d\n", id)
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to find user with Id")
		return
	}
	if glog.V(3) {
		glog.Infof("Sent info for user %d\n", id)
	}
	resp.WriteEntity(u)
}

func createUser(req *restful.Request, resp *restful.Response) {
	var err error
	var body struct {
		Admin  bool
		Name   string
		Groups []int64
	}

	err = req.ReadEntity(&body)
	if err != nil {
		glog.Info("Malformed body")
		resp.WriteErrorString(http.StatusBadRequest, "malformed body")
		return
	}
	if glog.V(3) {
		glog.Info(body)
	}
}

func modifyUser(req *restful.Request, resp *restful.Response) {
	id, err := strconv.ParseInt(req.PathParameter("id"), 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("unable to parse id")
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to parse Id")
		return
	}
	resp.WriteErrorString(http.StatusNotImplemented, fmt.Sprintf("%d", id))
	return
}

func removeUser(req *restful.Request, resp *restful.Response) {
	id, err := strconv.ParseInt(req.PathParameter("id"), 10, 64)
	if err != nil {
		if glog.V(2) {
			glog.Warningln("unable to parse id")
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to parse Id")
		return
	}
	resp.WriteErrorString(http.StatusNotImplemented, fmt.Sprintf("%d", id))
	return
}

func searchUser(req *restful.Request, resp *restful.Response) {
	var name string = req.QueryParameter("name")
	var id []int64
	rows, err := db.Query("SELECT id FROM users WHERE name LIKE $1;", name)
	if err != nil {
		glog.Error(err)
		return
	}

	for rows.Next() {
		var t int64
		if err := rows.Scan(&t); err != nil {
			glog.Error(err)
			return
		}
		id = append(id, t)
	}

	if len(id) == 0 {
		if glog.V(2) {
			glog.Infof("bad name: %s\n", name)
		}
		resp.WriteErrorString(http.StatusBadRequest, "unable to find any user with name")
		return
	}
	if glog.V(3) {
		glog.Infof("Successful search for user %d\n", id)
	}
	resp.WriteEntity(&map[string][]int64{"id": id})
}
<|endoftext|>


<commit_before>// Package stockfighter provides a simple wrapper for the Stockfighter API:
//
// https://www.stockfighter.io/
//
// https://starfighter.readme.io/
package stockfighter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"

	"github.com/gorilla/websocket"
)

func apiUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/ob/api/"+path, args...)
}

func gmUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/gm/"+path, args...)
}

func wsUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("wss://api.stockfighter.io/ob/ws/"+path, args...)
}

type apiCall interface {
	Err() error
}

type response struct {
	Ok    bool
	Error string
}

func (r response) Err() error {
	if len(r.Error) > 0 {
		return fmt.Errorf(r.Error)
	}
	return nil
}

type venueResponse struct {
	response
	Venue string
}

type stocksResponse struct {
	response
	Symbols []Symbol
}

type orderBookResponse struct {
	response
	OrderBook
}

type quoteResponse struct {
	response
	Quote
}

type orderResponse struct {
	response
	OrderState
}

type bulkOrderResponse struct {
	response
	Venue  string
	Orders []OrderState
}

type quoteMessage struct {
	Ok bool
	Quote
}

type executionMessage struct {
	Ok bool
	Execution
}

type gameResponse struct {
	response
	Game
}

type gameStateResponse struct {
	response
	GameState
}

type Stockfighter struct {
	apiKey string
	debug  bool
}

// Create new Stockfighter API instance.
// If debug is true, log all HTTP requests and responses.
func NewStockfighter(apiKey string, debug bool) *Stockfighter {
	return &Stockfighter{
		apiKey: apiKey,
		debug:  debug,
	}
}

// Check the API Is Up. Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) Heartbeat() error {
	var resp response
	return sf.do("GET", apiUrl("heartbeat"), nil, &resp)
}

// Check a venue is up. Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) VenueHeartbeat(venue string) error {
	var resp venueResponse
	url := apiUrl("venues/%s/heartbeat", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return err
	}
	return nil
}

// Get the stocks available for trading on a venue.
func (sf *Stockfighter) Stocks(venue string) ([]Symbol, error) {
	var resp stocksResponse
	url := apiUrl("venues/%s/stocks", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Symbols, nil
}

// Get the orderbook for a particular stock.
func (sf *Stockfighter) OrderBook(venue, stock string) (*OrderBook, error) {
	var resp orderBookResponse
	url := apiUrl("venues/%s/stocks/%s", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderBook, nil
}

// Get a quick look at the most recent trade information for a stock.
func (sf *Stockfighter) Quote(venue, stock string) (*Quote, error) {
	var resp quoteResponse
	url := apiUrl("venues/%s/stocks/%s/quote", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Quote, nil
}

// Place an order
func (sf *Stockfighter) Place(order *Order) (*OrderState, error) {
	body, err := encodeJson(order)
	if err != nil {
		return nil, err
	}
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders", order.Venue, order.Stock)
	if err := sf.do("POST", url, body, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the status for an existing order.
func (sf *Stockfighter) Status(venue, stock string, id uint64) (*OrderState, error) {
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the statuses for all an account's orders of a stock on a venue. If stock is a non-empty string, only statuses for that stock are returned
func (sf *Stockfighter) StockStatus(account, venue, stock string) ([]OrderState, error) {
	url := apiUrl("venues/%s/accounts/%s/orders", venue, account)
	if len(stock) > 0 {
		url = apiUrl("venues/%s/accounts/%s/stocks/%s/orders", venue, account, stock)
	}
	var resp bulkOrderResponse
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Orders, nil
}

// Cancel an existing order
func (sf *Stockfighter) Cancel(venue, stock string, id uint64) error {
	var resp response
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	return sf.do("DELETE", url, nil, &resp)
}

// Subscribe to a stream of quotes for a venue. If stock is a non-empy string, only quotes for that stock are returned.
func (sf *Stockfighter) Quotes(account, venue, stock string) (chan *Quote, error) {
	url := wsUrl("%s/venues/%s/tickertape", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/tickertape", account, venue, stock)
	}
	c := make(chan *Quote)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var quote quoteMessage
		if err := conn.ReadJSON(&quote); err != nil {
			close(c)
			return err
		}
		if quote.Ok {
			c <- &quote.Quote
		}
		return nil
	})
}

// Subscribe to a stream of executions for a venue. If stock is a non-empy string, only executions for that stock are returned.
func (sf *Stockfighter) Executions(account, venue, stock string) (chan *Execution, error) {
	url := wsUrl("%s/venues/%s/executions", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/executions", account, venue, stock)
	}
	c := make(chan *Execution)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var execution executionMessage
		if err := conn.ReadJSON(&execution); err != nil {
			close(c)
			return err
		}
		if execution.Ok {
			c <- &execution.Execution
		}
		return nil
	})
}

// Start a new level.
func (sf *Stockfighter) Start(level string) (*Game, error) {
	var resp gameResponse
	url := gmUrl("levels/%s", level)
	if err := sf.do("POST", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Game, nil
}

// Restart a level using the instance id from a previously started Game.
func (sf *Stockfighter) Restart(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/restart", id)
	return sf.do("POST", url, nil, &resp)
}

// Resume a level using the instance id from a previously started Game.
func (sf *Stockfighter) Resume(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/resume", id)
	return sf.do("POST", url, nil, &resp)
}

// Stop a level using the instance id from a previously started Game.
func (sf *Stockfighter) Stop(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/resume", id)
	return sf.do("POST", url, nil, &resp)
}

// Get the GameState using the instance id from a previously started Game.
func (sf *Stockfighter) GameStatus(id uint64) (*GameState, error) {
	var resp gameStateResponse
	url := gmUrl("instances/%d", id)
	if err := sf.do("Get", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.GameState, nil
}

func encodeJson(v interface{}) (io.Reader, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(v); err != nil {
		return nil, err
	}
	return &buf, nil
}

func (sf *Stockfighter) do(method, url string, body io.Reader, value apiCall) error {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("X-Starfighter-Authorization", sf.apiKey)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if sf.debug {
		out, _ := httputil.DumpRequest(req, true)
		log.Println(string(out))
		out, _ = httputil.DumpResponse(resp, true)
		log.Println(string(out))
	}
	if err := json.NewDecoder(resp.Body).Decode(value); err != nil {
		return err
	}
	if err := value.Err(); err != nil {
		return err
	}
	return nil
}

func (sf *Stockfighter) pump(url string, f func(*websocket.Conn) error) error {
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return err
	}
	go func() {
		defer conn.Close()
		for err := f(conn); err == nil; err = f(conn) {
		}
	}()
	return nil
}
<commit_msg>Fix game stop url<commit_after>// Package stockfighter provides a simple wrapper for the Stockfighter API:
//
// https://www.stockfighter.io/
//
// https://starfighter.readme.io/
package stockfighter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"

	"github.com/gorilla/websocket"
)

func apiUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/ob/api/"+path, args...)
}

func gmUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/gm/"+path, args...)
}

func wsUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("wss://api.stockfighter.io/ob/ws/"+path, args...)
}

type apiCall interface {
	Err() error
}

type response struct {
	Ok    bool
	Error string
}

func (r response) Err() error {
	if len(r.Error) > 0 {
		return fmt.Errorf(r.Error)
	}
	return nil
}

type venueResponse struct {
	response
	Venue string
}

type stocksResponse struct {
	response
	Symbols []Symbol
}

type orderBookResponse struct {
	response
	OrderBook
}

type quoteResponse struct {
	response
	Quote
}

type orderResponse struct {
	response
	OrderState
}

type bulkOrderResponse struct {
	response
	Venue  string
	Orders []OrderState
}

type quoteMessage struct {
	Ok bool
	Quote
}

type executionMessage struct {
	Ok bool
	Execution
}

type gameResponse struct {
	response
	Game
}

type gameStateResponse struct {
	response
	GameState
}

type Stockfighter struct {
	apiKey string
	debug  bool
}

// Create new Stockfighter API instance.
// If debug is true, log all HTTP requests and responses.
func NewStockfighter(apiKey string, debug bool) *Stockfighter {
	return &Stockfighter{
		apiKey: apiKey,
		debug:  debug,
	}
}

// Check the API Is Up. Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) Heartbeat() error {
	var resp response
	return sf.do("GET", apiUrl("heartbeat"), nil, &resp)
}

// Check a venue is up. Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) VenueHeartbeat(venue string) error {
	var resp venueResponse
	url := apiUrl("venues/%s/heartbeat", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return err
	}
	return nil
}

// Get the stocks available for trading on a venue.
func (sf *Stockfighter) Stocks(venue string) ([]Symbol, error) {
	var resp stocksResponse
	url := apiUrl("venues/%s/stocks", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Symbols, nil
}

// Get the orderbook for a particular stock.
func (sf *Stockfighter) OrderBook(venue, stock string) (*OrderBook, error) {
	var resp orderBookResponse
	url := apiUrl("venues/%s/stocks/%s", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderBook, nil
}

// Get a quick look at the most recent trade information for a stock.
func (sf *Stockfighter) Quote(venue, stock string) (*Quote, error) {
	var resp quoteResponse
	url := apiUrl("venues/%s/stocks/%s/quote", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Quote, nil
}

// Place an order
func (sf *Stockfighter) Place(order *Order) (*OrderState, error) {
	body, err := encodeJson(order)
	if err != nil {
		return nil, err
	}
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders", order.Venue, order.Stock)
	if err := sf.do("POST", url, body, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the status for an existing order.
func (sf *Stockfighter) Status(venue, stock string, id uint64) (*OrderState, error) {
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the statuses for all an account's orders of a stock on a venue. If stock is a non-empty string, only statuses for that stock are returned
func (sf *Stockfighter) StockStatus(account, venue, stock string) ([]OrderState, error) {
	url := apiUrl("venues/%s/accounts/%s/orders", venue, account)
	if len(stock) > 0 {
		url = apiUrl("venues/%s/accounts/%s/stocks/%s/orders", venue, account, stock)
	}
	var resp bulkOrderResponse
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Orders, nil
}

// Cancel an existing order
func (sf *Stockfighter) Cancel(venue, stock string, id uint64) error {
	var resp response
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	return sf.do("DELETE", url, nil, &resp)
}

// Subscribe to a stream of quotes for a venue. If stock is a non-empy string, only quotes for that stock are returned.
func (sf *Stockfighter) Quotes(account, venue, stock string) (chan *Quote, error) {
	url := wsUrl("%s/venues/%s/tickertape", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/tickertape", account, venue, stock)
	}
	c := make(chan *Quote)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var quote quoteMessage
		if err := conn.ReadJSON(&quote); err != nil {
			close(c)
			return err
		}
		if quote.Ok {
			c <- &quote.Quote
		}
		return nil
	})
}

// Subscribe to a stream of executions for a venue. If stock is a non-empy string, only executions for that stock are returned.
func (sf *Stockfighter) Executions(account, venue, stock string) (chan *Execution, error) {
	url := wsUrl("%s/venues/%s/executions", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/executions", account, venue, stock)
	}
	c := make(chan *Execution)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var execution executionMessage
		if err := conn.ReadJSON(&execution); err != nil {
			close(c)
			return err
		}
		if execution.Ok {
			c <- &execution.Execution
		}
		return nil
	})
}

// Start a new level.
func (sf *Stockfighter) Start(level string) (*Game, error) {
	var resp gameResponse
	url := gmUrl("levels/%s", level)
	if err := sf.do("POST", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Game, nil
}

// Restart a level using the instance id from a previously started Game.
func (sf *Stockfighter) Restart(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/restart", id)
	return sf.do("POST", url, nil, &resp)
}

// Resume a level using the instance id from a previously started Game.
func (sf *Stockfighter) Resume(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/resume", id)
	return sf.do("POST", url, nil, &resp)
}

// Stop a level using the instance id from a previously started Game.
func (sf *Stockfighter) Stop(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/stop", id)
	return sf.do("POST", url, nil, &resp)
}

// Get the GameState using the instance id from a previously started Game.
func (sf *Stockfighter) GameStatus(id uint64) (*GameState, error) {
	var resp gameStateResponse
	url := gmUrl("instances/%d", id)
	if err := sf.do("Get", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.GameState, nil
}

func encodeJson(v interface{}) (io.Reader, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(v); err != nil {
		return nil, err
	}
	return &buf, nil
}

func (sf *Stockfighter) do(method, url string, body io.Reader, value apiCall) error {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("X-Starfighter-Authorization", sf.apiKey)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if sf.debug {
		out, _ := httputil.DumpRequest(req, true)
		log.Println(string(out))
		out, _ = httputil.DumpResponse(resp, true)
		log.Println(string(out))
	}
	if err := json.NewDecoder(resp.Body).Decode(value); err != nil {
		return err
	}
	if err := value.Err(); err != nil {
		return err
	}
	return nil
}

func (sf *Stockfighter) pump(url string, f func(*websocket.Conn) error) error {
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return err
	}
	go func() {
		defer conn.Close()
		for err := f(conn); err == nil; err = f(conn) {
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>// Original code from https://github.com/johannesboyne/gofreegeoipclient
// with some tweaks and fixes.
package geoipc

import (
	"encoding/json"
	"net/http"
)

const (
	FREEGEOIP_URL = "https://freegeoip.net/json/"
)

type Location struct {
	Ip          string  `json:"ip"`
	CountryCode string  `json:"country_code"`
	CountryName string  `json:"country_name"`
	RegionCode  string  `json:"region_code"`
	RegionName  string  `json:"region_name"`
	City        string  `json:"city"`
	Zipcode     string  `json:"zipcode"`
	Latitude    float64 `json:"latitude"`
	Longitude   float64 `json:"longitude"`
	MetroCode   int     `json:"metro_code"`
	AreaCode    int     `json:"area_code"`
	Timezone    string  `json:"time_zone"`
}

func GetLocationForIP(ip string) (Location, error) {
	res, err := http.Get(FREEGEOIP_URL + ip)
	if err != nil {
		return Location{}, err
	}
	var loc Location
	decoder := json.NewDecoder(res.Body)
	if err := decoder.Decode(&loc); err != nil {
		return Location{}, err
	}
	return loc, nil
}

func GetLocation() (Location, error) {
	return GetLocationForIP("")
}
<commit_msg>API changes<commit_after>// Original code from https://github.com/johannesboyne/gofreegeoipclient
// with some tweaks and fixes.
package geoipc

import (
	"encoding/json"
	"net/http"
)

const (
	FREEGEOIP_URL = "https://freegeoip.net/json/"
)

type Location struct {
	IP          string  `json:"ip"`
	CountryCode string  `json:"country_code"`
	CountryName string  `json:"country_name"`
	RegionCode  string  `json:"region_code"`
	RegionName  string  `json:"region_name"`
	City        string  `json:"city"`
	ZipCode     string  `json:"zipcode"`
	Latitude    float64 `json:"latitude"`
	Longitude   float64 `json:"longitude"`
	MetroCode   int     `json:"metro_code"`
	AreaCode    int     `json:"area_code"`
	Timezone    string  `json:"time_zone"`
}

func GetLocationForIP(ip string) (Location, error) {
	res, err := http.Get(FREEGEOIP_URL + ip)
	if err != nil {
		return Location{}, err
	}

	var loc Location
	decoder := json.NewDecoder(res.Body)
	if err := decoder.Decode(&loc); err != nil {
		return Location{}, err
	}

	return loc, nil
}

func GetLocation() (Location, error) {
	return GetLocationForIP("")
}
<|endoftext|>


<commit_before>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
pzsvc-pdal provides an endpoint for accepting PDAL requests.

Examples

  $ curl -v -X POST -H "Content-Type: application/json" \
    -d '{"source":{"bucket":"venicegeo-sample-data","key":"pointcloud/samp11-utm.laz"},"function":"info"}' http://hostIP:8080/pdal

We shall see where we land with the input and output message for the job manager, but for now, we are expecting something along these lines.

Input:

	{
		"source": {
			"bucket": "venicegeo-sample-data",
			"key": "pointcloud/samp11-utm.laz"
		},
		"function": "ground",
		"options": {
			"slope": 0.5
		},
		"destination": {
			"bucket": "venicegeo-sample-data",
			"key" "temp/output.laz"
		}
	}

Output:

	{
		"input": <echo the input message>,
		"started_at": "2015-12-23T18:07:36.987565884Z",
		"finished_at": "2015-12-23T18:07:38.111658707Z",
		"code": 200,
		"message": "Success!"
	}

These messages are known to be incomplete at the moment. I'm sure there will be things like job IDs, etc. that have not been included at the moment. This is a good starting point though.
*/
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/julienschmidt/httprouter"
	"github.com/venicegeo/pzsvc-pdal/functions"
	"github.com/venicegeo/pzsvc-pdal/handlers"
)

// var pdalMetadata = job.ResourceMetadata{
// 	Name:         "pdal",
// 	ServiceID:    "",
// 	Description:  "Process point cloud data using PDAL.",
// 	URL:          "https://api.piazzageo.io/v1/pdal",
// 	Networks:     "TBD",
// 	QoS:          "Development",
// 	Availability: "UP",
// 	Tags:         "point cloud, pdal, lidar",
// 	ClassType:    "Unclassified",
// 	// TermDate:            time.Now(),
// 	// ClientCertRequired:  false,
// 	// CredentialsRequired: false,
// 	// PreAuthRequired:     false,
// 	// Contracts:           "",
// 	// Method:              "",
// 	// MimeType:            "",
// 	// Params:              "",
// 	// Reason:              "",
// }

func main() {
	// For standalone demo purposes, we will start two services: our PDAL service, and a mocked up JobManager.

	router := httprouter.New()

	router.GET("/",
		func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
			fmt.Fprintf(w, "Hi!")
		})

	type ListFuncs struct {
		Functions []string `json:"functions"`
	}
	out := ListFuncs{[]string{
		"crop", "dart", "dtm", "ground", "height", "info", "radius", "statistical",
		"translate", "vo",
	}}

	router.GET("/api/v1/functions/:name",
		func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
			w.Header().Set("Content-Type", "application/json; charset=UTF-8")
			var a interface{}
			switch ps.ByName("name") {
			case "crop":
				a = functions.NewCropOptions()
				w.WriteHeader(http.StatusOK)

			case "dart":
				a = functions.NewDartOptions()
				w.WriteHeader(http.StatusOK)

			case "dtm":
				a = functions.NewDtmOptions()
				w.WriteHeader(http.StatusOK)

			case "ground":
				a = functions.NewGroundOptions()
				w.WriteHeader(http.StatusOK)

			case "height":
				w.WriteHeader(http.StatusOK)

			case "info":
				a = functions.NewInfoOptions()
				w.WriteHeader(http.StatusOK)

			case "radius":
				a = functions.NewRadiusOptions()
				w.WriteHeader(http.StatusOK)

			case "statistical":
				a = functions.NewStatisticalOptions()
				w.WriteHeader(http.StatusOK)

			case "translate":
				w.WriteHeader(http.StatusOK)

			case "vo":
				w.WriteHeader(http.StatusOK)

			default:
				type DefaultMsg struct {
					Message string `json:"message"`
					ListFuncs
				}
				msg := "Unrecognized function " + ps.ByName("name") + "."
				a = DefaultMsg{msg, out}
				w.WriteHeader(http.StatusBadRequest)
			}
			if err := json.NewEncoder(w).Encode(a); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		})

	router.GET("/api/v1/functions",
		func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
			w.Header().Set("Content-Type", "application/json; charset=UTF-8")
			w.WriteHeader(http.StatusOK)
			if err := json.NewEncoder(w).Encode(out); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		})

	// // Setup the PDAL service.
	router.POST("/api/v1/pdal", handlers.PdalHandler)

	// Setup the mocked up JobManager.
	// router.POST("/manager", handlers.JobManagerHandler)

	var defaultPort = os.Getenv("PORT")
	if defaultPort == "" {
		defaultPort = "8080"
	}

	log.Println("Starting on port ", defaultPort)
	if err := http.ListenAndServe(":"+defaultPort, router); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Register with pz-servicecontroller<commit_after>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
pzsvc-pdal provides an endpoint for accepting PDAL requests.

Examples

  $ curl -v -X POST -H "Content-Type: application/json" \
    -d '{"source":{"bucket":"venicegeo-sample-data","key":"pointcloud/samp11-utm.laz"},"function":"info"}' http://hostIP:8080/pdal

We shall see where we land with the input and output message for the job manager, but for now, we are expecting something along these lines.

Input:

	{
		"source": {
			"bucket": "venicegeo-sample-data",
			"key": "pointcloud/samp11-utm.laz"
		},
		"function": "ground",
		"options": {
			"slope": 0.5
		},
		"destination": {
			"bucket": "venicegeo-sample-data",
			"key" "temp/output.laz"
		}
	}

Output:

	{
		"input": <echo the input message>,
		"started_at": "2015-12-23T18:07:36.987565884Z",
		"finished_at": "2015-12-23T18:07:38.111658707Z",
		"code": 200,
		"message": "Success!"
	}

These messages are known to be incomplete at the moment. I'm sure there will be things like job IDs, etc. that have not been included at the moment. This is a good starting point though.
*/
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/julienschmidt/httprouter"
	"github.com/venicegeo/pzsvc-pdal/functions"
	"github.com/venicegeo/pzsvc-pdal/handlers"
	"github.com/venicegeo/pzsvc-sdk-go/job"
)

func main() {
	// For standalone demo purposes, we will start two services: our PDAL service, and a mocked up JobManager.

	m := job.ResourceMetadata{
		Name:             "pzsvc-pdal",
		URL:              "http://pzsvc-pdal.cf.piazzageo.io/api/v1/pdal",
		Description:      "Process point cloud data using PDAL",
		Method:           "POST",
		RequestMimeType:  job.ContentTypeJSON,
		ResponseMimeType: job.ContentTypeJSON,
	}
	if err := job.RegisterService(m); err != nil {
		log.Println(err)
	}

	router := httprouter.New()

	router.GET("/",
		func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
			fmt.Fprintf(w, "Hi!")
		})

	type ListFuncs struct {
		Functions []string `json:"functions"`
	}
	out := ListFuncs{[]string{
		"crop", "dart", "dtm", "ground", "height", "info", "radius", "statistical",
		"translate", "vo",
	}}

	router.GET("/api/v1/functions/:name",
		func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
			w.Header().Set("Content-Type", "application/json; charset=UTF-8")
			var a interface{}
			switch ps.ByName("name") {
			case "crop":
				a = functions.NewCropOptions()
				w.WriteHeader(http.StatusOK)

			case "dart":
				a = functions.NewDartOptions()
				w.WriteHeader(http.StatusOK)

			case "dtm":
				a = functions.NewDtmOptions()
				w.WriteHeader(http.StatusOK)

			case "ground":
				a = functions.NewGroundOptions()
				w.WriteHeader(http.StatusOK)

			case "height":
				w.WriteHeader(http.StatusOK)

			case "info":
				a = functions.NewInfoOptions()
				w.WriteHeader(http.StatusOK)

			case "radius":
				a = functions.NewRadiusOptions()
				w.WriteHeader(http.StatusOK)

			case "statistical":
				a = functions.NewStatisticalOptions()
				w.WriteHeader(http.StatusOK)

			case "translate":
				w.WriteHeader(http.StatusOK)

			case "vo":
				w.WriteHeader(http.StatusOK)

			default:
				type DefaultMsg struct {
					Message string `json:"message"`
					ListFuncs
				}
				msg := "Unrecognized function " + ps.ByName("name") + "."
				a = DefaultMsg{msg, out}
				w.WriteHeader(http.StatusBadRequest)
			}
			if err := json.NewEncoder(w).Encode(a); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		})

	router.GET("/api/v1/functions",
		func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
			w.Header().Set("Content-Type", "application/json; charset=UTF-8")
			w.WriteHeader(http.StatusOK)
			if err := json.NewEncoder(w).Encode(out); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		})

	// // Setup the PDAL service.
	router.POST("/api/v1/pdal", handlers.PdalHandler)

	// Setup the mocked up JobManager.
	// router.POST("/manager", handlers.JobManagerHandler)

	var defaultPort = os.Getenv("PORT")
	if defaultPort == "" {
		defaultPort = "8080"
	}

	log.Println("Starting on port ", defaultPort)
	if err := http.ListenAndServe(":"+defaultPort, router); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package networking

const (
	// GroupName is the name for the networking API group.
	GroupName = "networking.internal.knative.dev"

	// IngressClassAnnotationKey is the annotation for the
	// explicit class of Ingress that a particular resource has
	// opted into. For example,
	//
	//    networking.knative.dev/ingress.class: some-network-impl
	//
	// This uses a different domain because unlike the resource, it is
	// user-facing.
	//
	// The parent resource may use its own annotations to choose the
	// annotation value for the Ingress it uses.  Based on such
	// value a different reconciliation logic may be used (for examples,
	// Istio-based Ingress will reconcile into a VirtualService).
	IngressClassAnnotationKey = "networking.knative.dev/ingress.class"

	// IngressLabelKey is the label key attached to underlying network programming
	// resources to indicate which Ingress triggered their creation.
	IngressLabelKey = GroupName + "/ingress"

	// SKSLabelKey is the label key that SKS Controller attaches to the
	// underlying resources it controls.
	SKSLabelKey = GroupName + "/serverlessservice"

	// ServiceTypeKey is the label key attached to a service specifying the type of service.
	// e.g. Public, Private.
	ServiceTypeKey = GroupName + "/serviceType"

	// OriginSecretNameLabelKey is the label key attached to the TLS secret to indicate
	// the name of the origin secret that the TLS secret is copied from.
	OriginSecretNameLabelKey = GroupName + "/originSecretName"

	// OriginSecretNamespaceLabelKey is the label key attached to the TLS secret
	// to indicate the namespace of the origin secret that the TLS secret is copied from.
	OriginSecretNamespaceLabelKey = GroupName + "/originSecretNamespace"

	// CertificateClassAnnotationKey is the annotation for the
	// explicit class of Certificate that a particular resource has
	// opted into. For example,
	//
	//    networking.knative.dev/certificate.class: some-network-impl
	//
	// This uses a different domain because unlike the resource, it is
	// user-facing.
	//
	// The parent resource may use its own annotations to choose the
	// annotation value for the Certificate it uses.  Based on such
	// value a different reconciliation logic may be used (for examples,
	// Cert-Manager-based Certificate will reconcile into a Cert-Manager Certificate).
	CertificateClassAnnotationKey = "networking.knative.dev/certificate.class"

	// ActivatorServiceName is the name of the activator Kubernetes service.
	ActivatorServiceName = "activator-service"

	// DeprecatedDisableWildcardCertLabelKey is the deprecated label key attached to a namespace to indicate that
	// a wildcard certificate should be not created for it.
	DeprecatedDisableWildcardCertLabelKey = GroupName + "/disableWildcardCert"

	// DisableWildcardCertLabelKey is the label key attached to a namespace to indicate that
	// a wildcard certificate should be not created for it.
	DisableWildcardCertLabelKey = "networking.knative.dev/disableWildcardCert"

	// WildcardCertDomainLabelKey is the label key attached to a certificate to indicate the
	// domain for which it was issued.
	WildcardCertDomainLabelKey = "networking.knative.dev/wildcardDomain"

	// KnativeIngressGateway is the name of the ingress gateway
	KnativeIngressGateway = "knative-ingress-gateway"
	// ClusterLocalGateway is the name of the local gateway
	ClusterLocalGateway = "cluster-local-gateway"
)

// ServiceType is the enumeration type for the Kubernetes services
// that we have in our system, classified by usage purpose.
type ServiceType string

const (
	// ServiceTypePrivate is the label value for internal only services
	// for user applications.
	ServiceTypePrivate ServiceType = "Private"
	// ServiceTypePublic is the label value for externally reachable
	// services for user applications.
	ServiceTypePublic ServiceType = "Public"
)

// Pseudo-constants
var (
	// DefaultRetryCount will be set if Attempts not specified.
	DefaultRetryCount = 3
)
<commit_msg>Remove Istio specific constants (to be moved to net-istio). (#105)<commit_after>/*
Copyright 2018 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package networking

const (
	// GroupName is the name for the networking API group.
	GroupName = "networking.internal.knative.dev"

	// IngressClassAnnotationKey is the annotation for the
	// explicit class of Ingress that a particular resource has
	// opted into. For example,
	//
	//    networking.knative.dev/ingress.class: some-network-impl
	//
	// This uses a different domain because unlike the resource, it is
	// user-facing.
	//
	// The parent resource may use its own annotations to choose the
	// annotation value for the Ingress it uses.  Based on such
	// value a different reconciliation logic may be used (for examples,
	// Istio-based Ingress will reconcile into a VirtualService).
	IngressClassAnnotationKey = "networking.knative.dev/ingress.class"

	// IngressLabelKey is the label key attached to underlying network programming
	// resources to indicate which Ingress triggered their creation.
	IngressLabelKey = GroupName + "/ingress"

	// SKSLabelKey is the label key that SKS Controller attaches to the
	// underlying resources it controls.
	SKSLabelKey = GroupName + "/serverlessservice"

	// ServiceTypeKey is the label key attached to a service specifying the type of service.
	// e.g. Public, Private.
	ServiceTypeKey = GroupName + "/serviceType"

	// OriginSecretNameLabelKey is the label key attached to the TLS secret to indicate
	// the name of the origin secret that the TLS secret is copied from.
	OriginSecretNameLabelKey = GroupName + "/originSecretName"

	// OriginSecretNamespaceLabelKey is the label key attached to the TLS secret
	// to indicate the namespace of the origin secret that the TLS secret is copied from.
	OriginSecretNamespaceLabelKey = GroupName + "/originSecretNamespace"

	// CertificateClassAnnotationKey is the annotation for the
	// explicit class of Certificate that a particular resource has
	// opted into. For example,
	//
	//    networking.knative.dev/certificate.class: some-network-impl
	//
	// This uses a different domain because unlike the resource, it is
	// user-facing.
	//
	// The parent resource may use its own annotations to choose the
	// annotation value for the Certificate it uses.  Based on such
	// value a different reconciliation logic may be used (for examples,
	// Cert-Manager-based Certificate will reconcile into a Cert-Manager Certificate).
	CertificateClassAnnotationKey = "networking.knative.dev/certificate.class"

	// ActivatorServiceName is the name of the activator Kubernetes service.
	ActivatorServiceName = "activator-service"

	// DeprecatedDisableWildcardCertLabelKey is the deprecated label key attached to a namespace to indicate that
	// a wildcard certificate should be not created for it.
	DeprecatedDisableWildcardCertLabelKey = GroupName + "/disableWildcardCert"

	// DisableWildcardCertLabelKey is the label key attached to a namespace to indicate that
	// a wildcard certificate should be not created for it.
	DisableWildcardCertLabelKey = "networking.knative.dev/disableWildcardCert"

	// WildcardCertDomainLabelKey is the label key attached to a certificate to indicate the
	// domain for which it was issued.
	WildcardCertDomainLabelKey = "networking.knative.dev/wildcardDomain"
)

// ServiceType is the enumeration type for the Kubernetes services
// that we have in our system, classified by usage purpose.
type ServiceType string

const (
	// ServiceTypePrivate is the label value for internal only services
	// for user applications.
	ServiceTypePrivate ServiceType = "Private"
	// ServiceTypePublic is the label value for externally reachable
	// services for user applications.
	ServiceTypePublic ServiceType = "Public"
)

// Pseudo-constants
var (
	// DefaultRetryCount will be set if Attempts not specified.
	DefaultRetryCount = 3
)
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Reads the pod configuration from the Kubernetes apiserver.
package config

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
)

// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(c *client.Client, hostname string, updates chan<- interface{}) {
	lw := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.OneTermEqualSelector(client.PodHost, hostname))
	newSourceApiserverFromLW(lw, updates)
}

// newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver.
func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}) {
	send := func(objs []interface{}) {
		var pods []*api.Pod
		for _, o := range objs {
			pods = append(pods, o.(*api.Pod))
		}
		updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.ApiserverSource}
	}
	cache.NewReflector(lw, &api.Pod{}, cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc), 0).Run()
}

func getHostFieldLabel(apiVersion string) string {
	switch apiVersion {
	case "v1beta1", "v1beta2":
		return "DesiredState.Host"
	default:
		return "spec.host"
	}
}
<commit_msg>Kubelet: remove unused getHostFieldLabel function<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Reads the pod configuration from the Kubernetes apiserver.
package config

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
)

// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(c *client.Client, hostname string, updates chan<- interface{}) {
	lw := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.OneTermEqualSelector(client.PodHost, hostname))
	newSourceApiserverFromLW(lw, updates)
}

// newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver.
func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}) {
	send := func(objs []interface{}) {
		var pods []*api.Pod
		for _, o := range objs {
			pods = append(pods, o.(*api.Pod))
		}
		updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.ApiserverSource}
	}
	cache.NewReflector(lw, &api.Pod{}, cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc), 0).Run()
}
<|endoftext|>