<commit_before>// Copyright 2016 Google Inc. 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.

package main

import (
	_ "expvar" // For HTTP server registration
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"time"

	"github.com/golang/glog"
	"github.com/google/trillian"
	"github.com/google/trillian/examples/ct"
	"google.golang.org/grpc"
)

// Global flags that affect all log instances.
var serverPortFlag = flag.Int("port", 6962, "Port to serve CT log requests on")
var rpcBackendFlag = flag.String("log_rpc_server", "localhost:8090", "Backend Log RPC server to use")
var rpcDeadlineFlag = flag.Duration("rpc_deadline", time.Second*10, "Deadline for backend RPC requests")
var logConfigFlag = flag.String("log_config", "", "File holding log config in JSON")

func awaitSignal() {
	// Arrange notification for the standard set of signals used to terminate a server
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// Now block main and wait for a signal
	sig := <-sigs
	glog.Warningf("Signal received: %v", sig)
	glog.Flush()

	// Terminate the process
	os.Exit(1)
}

func main() {
	flag.Parse()
	// Get log config from file before we start.
	cfg, err := ct.LogConfigFromFile(*logConfigFlag)
	if err != nil {
		glog.Fatalf("Failed to read log config: %v", err)
	}

	glog.CopyStandardLogTo("WARNING")
	glog.Info("**** CT HTTP Server Starting ****")

	// TODO(Martin2112): Support TLS and other stuff for RPC client and http server, this is just to
	// get started. Uses a blocking connection so we don't start serving before we're connected
	// to backend.
	conn, err := grpc.Dial(*rpcBackendFlag, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		glog.Fatalf("Could not connect to rpc server: %v", err)
	}
	defer conn.Close()
	client := trillian.NewTrillianLogClient(conn)

	for _, c := range cfg {
		handlers, err := c.SetUpInstance(client, *rpcDeadlineFlag)
		if err != nil {
			glog.Fatalf("Failed to set up log instance for %+v: %v", cfg, err)
		}
		for path, handler := range *handlers {
			http.Handle(path, handler)
		}
	}

	// Bring up the HTTP server and serve until we get a signal not to.
	go awaitSignal()
	server := http.Server{Addr: fmt.Sprintf("localhost:%d", *serverPortFlag), Handler: nil}
	err = server.ListenAndServe()
	glog.Warningf("Server exited: %v", err)
	glog.Flush()
}
<commit_msg>Prefer glog.Exitf to glog.Fatalf<commit_after>// Copyright 2016 Google Inc. 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.

package main

import (
	_ "expvar" // For HTTP server registration
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"time"

	"github.com/golang/glog"
	"github.com/google/trillian"
	"github.com/google/trillian/examples/ct"
	"google.golang.org/grpc"
)

// Global flags that affect all log instances.
var serverPortFlag = flag.Int("port", 6962, "Port to serve CT log requests on")
var rpcBackendFlag = flag.String("log_rpc_server", "localhost:8090", "Backend Log RPC server to use")
var rpcDeadlineFlag = flag.Duration("rpc_deadline", time.Second*10, "Deadline for backend RPC requests")
var logConfigFlag = flag.String("log_config", "", "File holding log config in JSON")

func awaitSignal() {
	// Arrange notification for the standard set of signals used to terminate a server
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// Now block main and wait for a signal
	sig := <-sigs
	glog.Warningf("Signal received: %v", sig)
	glog.Flush()

	// Terminate the process
	os.Exit(1)
}

func main() {
	flag.Parse()
	// Get log config from file before we start.
	cfg, err := ct.LogConfigFromFile(*logConfigFlag)
	if err != nil {
		glog.Exitf("Failed to read log config: %v", err)
	}

	glog.CopyStandardLogTo("WARNING")
	glog.Info("**** CT HTTP Server Starting ****")

	// TODO(Martin2112): Support TLS and other stuff for RPC client and http server, this is just to
	// get started. Uses a blocking connection so we don't start serving before we're connected
	// to backend.
	conn, err := grpc.Dial(*rpcBackendFlag, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		glog.Exitf("Could not connect to rpc server: %v", err)
	}
	defer conn.Close()
	client := trillian.NewTrillianLogClient(conn)

	for _, c := range cfg {
		handlers, err := c.SetUpInstance(client, *rpcDeadlineFlag)
		if err != nil {
			glog.Exitf("Failed to set up log instance for %+v: %v", cfg, err)
		}
		for path, handler := range *handlers {
			http.Handle(path, handler)
		}
	}

	// Bring up the HTTP server and serve until we get a signal not to.
	go awaitSignal()
	server := http.Server{Addr: fmt.Sprintf("localhost:%d", *serverPortFlag), Handler: nil}
	err = server.ListenAndServe()
	glog.Warningf("Server exited: %v", err)
	glog.Flush()
}
<|endoftext|>


<commit_before>package db

import (
	"io/ioutil"
	"os"
	"testing"
)

func TestIdxCRUD(t *testing.T) {
	os.RemoveAll(TEST_DATA_DIR)
	defer os.RemoveAll(TEST_DATA_DIR)
	if err := os.MkdirAll(TEST_DATA_DIR, 0700); err != nil {
		t.Fatal(err)
	}
	if err := ioutil.WriteFile(TEST_DATA_DIR+"/number_of_partitions", []byte("2"), 0600); err != nil {
		t.Fatal(err)
	}
	db, err := OpenDB(TEST_DATA_DIR)
	if err != nil {
		t.Fatal(err)
	}
	if err = db.Create("col"); err != nil {
		t.Fatal(err)
	}
	col := db.Use("col")
	if len(col.AllIndexes()) != 0 {
		t.Fatal(col.AllIndexes())
	}
	// Create index & verify
	if err = col.Index([]string{"a", "b"}); err != nil {
		t.Fatal(err)
	}
	if col.Index([]string{"a", "b"}) == nil {
		t.Fatal(col.indexPaths, "Did not error")
	}
	if len(col.AllIndexes()) != 1 || col.AllIndexes()[0][0] != "a" || col.AllIndexes()[0][1] != "b" {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Index([]string{"c"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 2 || col.AllIndexes()[0][0] != "a" || col.AllIndexes()[0][1] != "b" || col.AllIndexes()[1][0] != "c" {
		t.Fatal(col.AllIndexes())
	}
	// Unindex & verify
	if col.Unindex([]string{"%&^*"}) == nil {
		t.Fatal("Did not error")
	}
	if err = col.Unindex([]string{"c"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 1 || col.AllIndexes()[0][0] != "a" || col.AllIndexes()[0][1] != "b" {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Unindex([]string{"a", "b"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 0 {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Sync(); err != nil {
		t.Fatal(err)
	}
	if err := db.Close(); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>fix test case<commit_after>package db

import (
	"io/ioutil"
	"os"
	"testing"
)

func TestIdxCRUD(t *testing.T) {
	os.RemoveAll(TEST_DATA_DIR)
	defer os.RemoveAll(TEST_DATA_DIR)
	if err := os.MkdirAll(TEST_DATA_DIR, 0700); err != nil {
		t.Fatal(err)
	}
	if err := ioutil.WriteFile(TEST_DATA_DIR+"/number_of_partitions", []byte("2"), 0600); err != nil {
		t.Fatal(err)
	}
	db, err := OpenDB(TEST_DATA_DIR)
	if err != nil {
		t.Fatal(err)
	}
	if err = db.Create("col"); err != nil {
		t.Fatal(err)
	}
	col := db.Use("col")
	if len(col.AllIndexes()) != 0 {
		t.Fatal(col.AllIndexes())
	}
	// Create index & verify
	if err = col.Index([]string{"a", "b"}); err != nil {
		t.Fatal(err)
	}
	if col.Index([]string{"a", "b"}) == nil {
		t.Fatal(col.indexPaths, "Did not error")
	}
	if len(col.AllIndexes()) != 1 || col.AllIndexes()[0][0] != "a" || col.AllIndexes()[0][1] != "b" {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Index([]string{"c"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 2 || !((col.AllIndexes()[0][0] == "a" && col.AllIndexes()[0][1] == "b" && col.AllIndexes()[1][0] == "c") || (col.AllIndexes()[0][0] == "c" && col.AllIndexes()[1][0] == "a" && col.AllIndexes()[1][1] == "b")) {
		t.Fatal(col.AllIndexes())
	}
	// Unindex & verify
	if col.Unindex([]string{"%&^*"}) == nil {
		t.Fatal("Did not error")
	}
	if err = col.Unindex([]string{"c"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 1 || col.AllIndexes()[0][0] != "a" || col.AllIndexes()[0][1] != "b" {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Unindex([]string{"a", "b"}); err != nil {
		t.Fatal(err)
	}
	if len(col.AllIndexes()) != 0 {
		t.Fatal(col.AllIndexes())
	}
	if err = col.Sync(); err != nil {
		t.Fatal(err)
	}
	if err := db.Close(); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// @author       sigu-399
// @description  An implementation of JSON Schema, draft v4 - Go language
// @created      26-02-2013

package gojsonschema

import (
	"encoding/json"
	"errors"
	"fmt"
	"gojsonreference"
	"io/ioutil"
	"net/http"
	"reflect"
)

func NewJsonSchemaDocument(documentReferenceString string) (*JsonSchemaDocument, error) {

	var err error

	d := JsonSchemaDocument{}
	d.documentReference, err = gojsonreference.NewJsonReference(documentReferenceString)

	resp, err := http.Get(documentReferenceString)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, errors.New("Could not access schema " + resp.Status)
	}

	bodyBuff, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var document interface{}
	err = json.Unmarshal(bodyBuff, &document)
	if err != nil {
		return nil, err
	}

	err = d.parse(document)
	return &d, err
}

type JsonSchemaDocument struct {
	documentReference gojsonreference.JsonReference
	rootSchema        *JsonSchema
}

func (d *JsonSchemaDocument) parse(document interface{}) error {
	d.rootSchema = &JsonSchema{}
	return d.parseSchema(document, d.rootSchema)
}

func (d *JsonSchemaDocument) parseSchema(documentNode interface{}, currentSchema *JsonSchema) error {

	if !isKind(documentNode, reflect.Map) {
		return errors.New("Schema must be an object")
	}

	m := documentNode.(map[string]interface{})

	if currentSchema == d.rootSchema {
		if !existsMapKey(m, "$schema") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "$schema"))
		}
		if !isKind(m["$schema"], reflect.String) {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "$schema", "string"))
		}
		schemaRef := m["$schema"].(string)
		schemaReference, err := gojsonreference.NewJsonReference(schemaRef)
		currentSchema.schema = &schemaReference
		if err != nil {
			return err
		}
	}

	// id
	if existsMapKey(m, "id") && !isKind(m["id"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "id", "string"))
	}
	if k, ok := m["id"].(string); ok {
		currentSchema.id = &k
	}

	// title
	if existsMapKey(m, "title") && !isKind(m["title"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "title", "string"))
	}
	if k, ok := m["title"].(string); ok {
		currentSchema.title = &k
	}

	// description
	if existsMapKey(m, "description") && !isKind(m["description"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "description", "string"))
	}
	if k, ok := m["description"].(string); ok {
		currentSchema.description = &k
	}

	// ref
	if existsMapKey(m, "$ref") && !isKind(m["$ref"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "$ref", "string"))
	}
	if k, ok := m["$ref"].(string); ok {
		currentSchema.ref = &k
	}

	// properties
	/*	if !existsMapKey(m, "properties") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "properties"))
		}
	*/
	for k := range m {
		if k == "properties" {
			err := d.parseProperties(m[k], currentSchema)
			if err != nil {
				return err
			}
		}
	}

	// items
	/*	if !existsMapKey(m, "items") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "items"))
		}
	*/
	for k := range m {
		if k == "items" {
			newSchema := &JsonSchema{}
			currentSchema.AddPropertiesChild(newSchema)
			err := d.parseSchema(m[k], newSchema)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (d *JsonSchemaDocument) parseProperties(documentNode interface{}, currentSchema *JsonSchema) error {

	if !isKind(documentNode, reflect.Map) {
		return errors.New("Properties must be an object")
	}

	m := documentNode.(map[string]interface{})
	for k := range m {
		schemaProperty := k
		newSchema := &JsonSchema{property: &schemaProperty}
		currentSchema.AddPropertiesChild(newSchema)
		err := d.parseSchema(m[k], newSchema)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>moved json loading to jsonutils<commit_after>// @author       sigu-399
// @description  An implementation of JSON Schema, draft v4 - Go language
// @created      26-02-2013

package gojsonschema

import (
	"errors"
	"fmt"
	"gojsonreference"
	"reflect"
)

func NewJsonSchemaDocument(documentReferenceString string) (*JsonSchemaDocument, error) {

	var err error

	d := JsonSchemaDocument{}
	d.documentReference, err = gojsonreference.NewJsonReference(documentReferenceString)

	document, err := GetHttpJson(documentReferenceString)
	if err != nil {
		return nil, err
	}

	err = d.parse(document)
	return &d, err
}

type JsonSchemaDocument struct {
	documentReference gojsonreference.JsonReference
	rootSchema        *JsonSchema
}

func (d *JsonSchemaDocument) parse(document interface{}) error {
	d.rootSchema = &JsonSchema{}
	return d.parseSchema(document, d.rootSchema)
}

func (d *JsonSchemaDocument) parseSchema(documentNode interface{}, currentSchema *JsonSchema) error {

	if !isKind(documentNode, reflect.Map) {
		return errors.New("Schema must be an object")
	}

	m := documentNode.(map[string]interface{})

	if currentSchema == d.rootSchema {
		if !existsMapKey(m, "$schema") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "$schema"))
		}
		if !isKind(m["$schema"], reflect.String) {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "$schema", "string"))
		}
		schemaRef := m["$schema"].(string)
		schemaReference, err := gojsonreference.NewJsonReference(schemaRef)
		currentSchema.schema = &schemaReference
		if err != nil {
			return err
		}
	}

	// id
	if existsMapKey(m, "id") && !isKind(m["id"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "id", "string"))
	}
	if k, ok := m["id"].(string); ok {
		currentSchema.id = &k
	}

	// title
	if existsMapKey(m, "title") && !isKind(m["title"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "title", "string"))
	}
	if k, ok := m["title"].(string); ok {
		currentSchema.title = &k
	}

	// description
	if existsMapKey(m, "description") && !isKind(m["description"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "description", "string"))
	}
	if k, ok := m["description"].(string); ok {
		currentSchema.description = &k
	}

	// ref
	if existsMapKey(m, "$ref") && !isKind(m["$ref"], reflect.String) {
		return errors.New(fmt.Sprintf(ERROR_MESSAGE_MUST_BE_OF_TYPE, "$ref", "string"))
	}
	if k, ok := m["$ref"].(string); ok {
		currentSchema.ref = &k
	}

	// properties
	/*	if !existsMapKey(m, "properties") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "properties"))
		}
	*/
	for k := range m {
		if k == "properties" {
			err := d.parseProperties(m[k], currentSchema)
			if err != nil {
				return err
			}
		}
	}

	// items
	/*	if !existsMapKey(m, "items") {
			return errors.New(fmt.Sprintf(ERROR_MESSAGE_IS_REQUIRED, "items"))
		}
	*/
	for k := range m {
		if k == "items" {
			newSchema := &JsonSchema{}
			currentSchema.AddPropertiesChild(newSchema)
			err := d.parseSchema(m[k], newSchema)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (d *JsonSchemaDocument) parseProperties(documentNode interface{}, currentSchema *JsonSchema) error {

	if !isKind(documentNode, reflect.Map) {
		return errors.New("Properties must be an object")
	}

	m := documentNode.(map[string]interface{})
	for k := range m {
		schemaProperty := k
		newSchema := &JsonSchema{property: &schemaProperty}
		currentSchema.AddPropertiesChild(newSchema)
		err := d.parseSchema(m[k], newSchema)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package uploadthis

import (
	"testing"
)

func TestParseOptsAccessKey(t *testing.T) {
	optsParser = func(interface{}) ([]string, error) {
		opts.AccesssKey = "FAKE KEY"
		opts.SecretKey = ""
		return []string{}, nil
	}
	ParseOpts()
}
<commit_msg>updating tests<commit_after>package uploadthis

import (
	"launchpad.net/gocheck"
	"testing"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { gocheck.TestingT(t) }

type MySuite struct{}

var _ = gocheck.Suite(&MySuite{})

func (s *MySuite) TestHelloWorld(c *gocheck.C) {
	optsParser = func(interface{}) ([]string, error) {
		opts.AccesssKey = "MOCK KEY"
		opts.SecretKey = "MOCK SECRET"
		return []string{}, nil
	}
	ParseOpts()
	c.Check(opts.AccesssKey, gocheck.Equals, "MOCK KEY")
	c.Check(opts.SecretKey, gocheck.Equals, "MOCK SECRET")
}
<|endoftext|>


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

package private

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net"
	"net/http"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/httplib"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
)

func newRequest(url, method string) *httplib.Request {
	return httplib.NewRequest(url, method).Header("Authorization",
		fmt.Sprintf("Bearer %s", setting.InternalToken))
}

// Response internal request response
type Response struct {
	Err string `json:"err"`
}

func decodeJSONError(resp *http.Response) *Response {
	var res Response
	err := json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		res.Err = err.Error()
	}
	return &res
}

func newInternalRequest(url, method string) *httplib.Request {
	req := newRequest(url, method).SetTLSClientConfig(&tls.Config{
		InsecureSkipVerify: true,
	})
	if setting.Protocol == setting.UnixSocket {
		req.SetTransport(&http.Transport{
			Dial: func(_, _ string) (net.Conn, error) {
				return net.Dial("unix", setting.HTTPAddr)
			},
		})
	}
	return req
}

// CheckUnitUser check whether user could visit the unit of this repository
func CheckUnitUser(userID, repoID int64, isAdmin bool, unitType models.UnitType) (*models.AccessMode, error) {
	reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/user/%d/checkunituser?isAdmin=%t&unitType=%d", repoID, userID, isAdmin, unitType)
	log.GitLogger.Trace("CheckUnitUser: %s", reqURL)

	resp, err := newInternalRequest(reqURL, "GET").Response()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to CheckUnitUser: %s", decodeJSONError(resp).Err)
	}

	var a models.AccessMode
	if err := json.NewDecoder(resp.Body).Decode(&a); err != nil {
		return nil, err
	}

	return &a, nil
}

// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame.
func GetRepositoryByOwnerAndName(ownerName, repoName string) (*models.Repository, error) {
	reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repo/%s/%s", ownerName, repoName)
	log.GitLogger.Trace("GetRepositoryByOwnerAndName: %s", reqURL)

	resp, err := newInternalRequest(reqURL, "GET").Response()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err)
	}

	var repo models.Repository
	if err := json.NewDecoder(resp.Body).Decode(&repo); err != nil {
		return nil, err
	}

	return &repo, nil
}
<commit_msg>Fix TLS errors when using acme/autocert for local connections (#5820)<commit_after>// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package private

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net"
	"net/http"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/httplib"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
)

func newRequest(url, method string) *httplib.Request {
	return httplib.NewRequest(url, method).Header("Authorization",
		fmt.Sprintf("Bearer %s", setting.InternalToken))
}

// Response internal request response
type Response struct {
	Err string `json:"err"`
}

func decodeJSONError(resp *http.Response) *Response {
	var res Response
	err := json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		res.Err = err.Error()
	}
	return &res
}

func newInternalRequest(url, method string) *httplib.Request {
	req := newRequest(url, method).SetTLSClientConfig(&tls.Config{
		InsecureSkipVerify: true,
		ServerName:         setting.Domain,
	})
	if setting.Protocol == setting.UnixSocket {
		req.SetTransport(&http.Transport{
			Dial: func(_, _ string) (net.Conn, error) {
				return net.Dial("unix", setting.HTTPAddr)
			},
		})
	}
	return req
}

// CheckUnitUser check whether user could visit the unit of this repository
func CheckUnitUser(userID, repoID int64, isAdmin bool, unitType models.UnitType) (*models.AccessMode, error) {
	reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/user/%d/checkunituser?isAdmin=%t&unitType=%d", repoID, userID, isAdmin, unitType)
	log.GitLogger.Trace("CheckUnitUser: %s", reqURL)

	resp, err := newInternalRequest(reqURL, "GET").Response()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to CheckUnitUser: %s", decodeJSONError(resp).Err)
	}

	var a models.AccessMode
	if err := json.NewDecoder(resp.Body).Decode(&a); err != nil {
		return nil, err
	}

	return &a, nil
}

// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame.
func GetRepositoryByOwnerAndName(ownerName, repoName string) (*models.Repository, error) {
	reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repo/%s/%s", ownerName, repoName)
	log.GitLogger.Trace("GetRepositoryByOwnerAndName: %s", reqURL)

	resp, err := newInternalRequest(reqURL, "GET").Response()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err)
	}

	var repo models.Repository
	if err := json.NewDecoder(resp.Body).Decode(&repo); err != nil {
		return nil, err
	}

	return &repo, nil
}
<|endoftext|>


<commit_before>package crane

import (
	"fmt"
	"github.com/michaelsauter/crane/print"
	"github.com/spf13/cobra"
	"os"
	"strings"
)

type Options struct {
	verbose             bool
	recreate            bool
	nocache             bool
	notrunc             bool
	forceRm             bool
	cascadeDependencies string
	cascadeAffected     string
	config              string
	target              []string
}

var options = Options{
	verbose:             false,
	recreate:            false,
	nocache:             false,
	notrunc:             false,
	forceRm:             false,
	cascadeDependencies: "",
	cascadeAffected:     "",
	config:              "",
	target:              make([]string, 1), //FIXME: remove pre-allocation when -t/--target is removed
}

func isVerbose() bool {
	return options.verbose
}

// returns a function to be set as a cobra command run, wrapping a command meant to be run according to the config
func configCommand(wrapped func(config Config), forceOrder bool) func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		for _, value := range []string{options.cascadeDependencies, options.cascadeAffected} {
			if value != "none" && value != "all" && value != "link" && value != "volumesFrom" && value != "net" {
				cmd.Printf("Error: invalid cascading value: %v", value)
				cmd.Usage()
				panic(StatusError{status: 64})
			}
		}
		if options.target[0] != "" { //FIXME: remove when -t/--target is removed
			print.Noticef("DEPRECATION: -t/--target is now implicit and will be removed in an upcoming release\n")
			if len(args) > 0 {
				options.target = append(args, options.target[0])
			}
		} else {
			options.target = args
		}

		config := NewConfig(options, forceOrder)
		if containers := config.TargetedContainers(); len(containers) == 0 {
			print.Errorf("ERROR: Command cannot be applied to any container.")
		} else {
			if isVerbose() {
				print.Infof("Command will be applied to: %v\n\n", strings.Join(containers.names(), ", "))
			}
			wrapped(config)
		}
	}
}

func handleCmd() {

	var cmdLift = &cobra.Command{
		Use:   "lift",
		Short: "Build or pull images if they don't exist, then run or start the containers",
		Long: `
lift will provision missing images and run all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().lift(options.recreate, options.nocache)
		}, false),
	}

	var cmdProvision = &cobra.Command{
		Use:   "provision",
		Short: "Build or pull images",
		Long: `
provision will use specified Dockerfiles to build all targeted images.
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().provision(options.nocache)
		}, true),
	}

	var cmdRun = &cobra.Command{
		Use:   "run",
		Short: "Run the containers",
		Long:  `run will call docker run for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().run(options.recreate)
		}, false),
	}

	var cmdRm = &cobra.Command{
		Use:   "rm",
		Short: "Remove the containers",
		Long:  `rm will call docker rm for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().rm(options.forceRm)
		}, true),
	}

	var cmdKill = &cobra.Command{
		Use:   "kill",
		Short: "Kill the containers",
		Long:  `kill will call docker kill for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().kill()
		}, true),
	}

	var cmdStart = &cobra.Command{
		Use:   "start",
		Short: "Start the containers",
		Long:  `start will call docker start for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().start()
		}, false),
	}

	var cmdStop = &cobra.Command{
		Use:   "stop",
		Short: "Stop the containers",
		Long:  `stop will call docker stop for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().stop()
		}, true),
	}

	var cmdPause = &cobra.Command{
		Use:   "pause",
		Short: "Pause the containers",
		Long:  `pause will call docker pause for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().pause()
		}, true),
	}

	var cmdUnpause = &cobra.Command{
		Use:   "unpause",
		Short: "Unpause the containers",
		Long:  `unpause will call docker unpause for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().unpause()
		}, false),
	}

	var cmdPush = &cobra.Command{
		Use:   "push",
		Short: "Push the containers",
		Long:  `push will call docker push for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().push()
		}, true),
	}

	var cmdStatus = &cobra.Command{
		Use:   "status",
		Short: "Displays status of containers",
		Long:  `Displays the current status of all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().status(options.notrunc)
		}, true),
	}

	var cmdGraph = &cobra.Command{
		Use:   "graph",
		Short: "Dumps the dependency graph as a DOT file",
		Long:  `Generate a DOT file representing the dependency graph. Bold nodes represent the
containers declared in the config (as opposed to non-bold ones that are referenced
in the config, but not defined). Targeted containers are highlighted with color
borders. Solid edges represent links, dashed edges volumesFrom, and dotted edges
net=container relations.`,
		Run: configCommand(func(config Config) {
				config.DependencyGraph().DOT(os.Stdout, config.TargetedContainers())
		}, true),
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.9.0")
		},
	}

	var craneCmd = &cobra.Command{
		Use:   "crane",
		Short: "crane - Lift containers with ease",
		Long: `
Crane is a little tool to orchestrate Docker containers.
It works by reading in JSON or YAML which describes how to obtain container images and how to run them.
See the corresponding docker commands for more information.`,
	}

	craneCmd.PersistentFlags().BoolVarP(&options.verbose, "verbose", "v", false, "Verbose output")
	craneCmd.PersistentFlags().StringVarP(&options.config, "config", "c", "", "Config file to read from")
	craneCmd.PersistentFlags().StringVarP(&options.target[0], "target", "t", "", "Group or container to execute the command for [DEPRECATED, NOW IMPLICIT]")
	cascadingValuesSuffix := `
					"all": follow any kind of dependency
					"link": follow --link dependencies only
					"volumesFrom": follow --volumesFrom dependencies only
					"net": follow --net dependencies only
	`
	craneCmd.PersistentFlags().StringVarP(&options.cascadeDependencies, "cascade-dependencies", "d", "none", "Also apply the command for the containers that (any of) the explicitly targeted one(s) depend on"+cascadingValuesSuffix)
	craneCmd.PersistentFlags().StringVarP(&options.cascadeAffected, "cascade-affected", "a", "none", "Also apply the command for the existing containers depending on (any of) the explicitly targeted one(s)"+cascadingValuesSuffix)

	cmdLift.Flags().BoolVarP(&options.recreate, "recreate", "r", false, "Recreate containers (force-remove containers if they exist, force-provision images, run containers)")
	cmdLift.Flags().BoolVarP(&options.nocache, "no-cache", "n", false, "Build the image without any cache")

	cmdProvision.Flags().BoolVarP(&options.nocache, "no-cache", "n", false, "Build the image without any cache")

	cmdRun.Flags().BoolVarP(&options.recreate, "recreate", "r", false, "Recreate containers (force-remove containers first)")

	cmdRm.Flags().BoolVarP(&options.forceRm, "force", "f", false, "Kill containers if they are running first")

	cmdStatus.Flags().BoolVarP(&options.notrunc, "no-trunc", "", false, "Don't truncate output")

	// default usage template with target arguments & description
	craneCmd.SetUsageTemplate(`{{ $cmd := . }}
Usage: {{if .Runnable}}
  {{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if .HasSubCommands}}
  {{ .CommandPath}} [command]{{end}} [target1 [target2 [...]]]
{{ if .HasSubCommands}}
Available Commands: {{range .Commands}}{{if .Runnable}}
  {{rpad .Use .UsagePadding }} {{.Short}}{{end}}{{end}}
{{end}}
Explicit targeting:
  By default, the command is applied to all containers declared in the
  config,  or to the containers defined in the group ` + "`" + `default` + "`" + ` if it is
  defined. If one or several container or group reference(s) is/are
  passed as  argument(s), the command will only be applied to containers
  matching these references. Note however that providing cascading flags
  might extend the set of targeted containers.

{{ if .HasFlags}}Available Flags:
{{.Flags.FlagUsages}}{{end}}{{if .HasParent}}{{if and (gt .Commands 0) (gt .Parent.Commands 1) }}
Additional help topics: {{if gt .Commands 0 }}{{range .Commands}}{{if not .Runnable}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if gt .Parent.Commands 1 }}{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }}{{end}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{end}}
{{end}}
Use "{{.Root.Name}} help [command]" for more information about that command.
`)

	craneCmd.AddCommand(cmdLift, cmdProvision, cmdRun, cmdRm, cmdKill, cmdStart, cmdStop, cmdPause, cmdUnpause, cmdPush, cmdStatus, cmdGraph, cmdVersion)
	err := craneCmd.Execute()
	if err != nil {
		panic(StatusError{status: 64})
	}
}
<commit_msg>bump to avoid confusion<commit_after>package crane

import (
	"fmt"
	"github.com/michaelsauter/crane/print"
	"github.com/spf13/cobra"
	"os"
	"strings"
)

type Options struct {
	verbose             bool
	recreate            bool
	nocache             bool
	notrunc             bool
	forceRm             bool
	cascadeDependencies string
	cascadeAffected     string
	config              string
	target              []string
}

var options = Options{
	verbose:             false,
	recreate:            false,
	nocache:             false,
	notrunc:             false,
	forceRm:             false,
	cascadeDependencies: "",
	cascadeAffected:     "",
	config:              "",
	target:              make([]string, 1), //FIXME: remove pre-allocation when -t/--target is removed
}

func isVerbose() bool {
	return options.verbose
}

// returns a function to be set as a cobra command run, wrapping a command meant to be run according to the config
func configCommand(wrapped func(config Config), forceOrder bool) func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		for _, value := range []string{options.cascadeDependencies, options.cascadeAffected} {
			if value != "none" && value != "all" && value != "link" && value != "volumesFrom" && value != "net" {
				cmd.Printf("Error: invalid cascading value: %v", value)
				cmd.Usage()
				panic(StatusError{status: 64})
			}
		}
		if options.target[0] != "" { //FIXME: remove when -t/--target is removed
			print.Noticef("DEPRECATION: -t/--target is now implicit and will be removed in an upcoming release\n")
			if len(args) > 0 {
				options.target = append(args, options.target[0])
			}
		} else {
			options.target = args
		}

		config := NewConfig(options, forceOrder)
		if containers := config.TargetedContainers(); len(containers) == 0 {
			print.Errorf("ERROR: Command cannot be applied to any container.")
		} else {
			if isVerbose() {
				print.Infof("Command will be applied to: %v\n\n", strings.Join(containers.names(), ", "))
			}
			wrapped(config)
		}
	}
}

func handleCmd() {

	var cmdLift = &cobra.Command{
		Use:   "lift",
		Short: "Build or pull images if they don't exist, then run or start the containers",
		Long: `
lift will provision missing images and run all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().lift(options.recreate, options.nocache)
		}, false),
	}

	var cmdProvision = &cobra.Command{
		Use:   "provision",
		Short: "Build or pull images",
		Long: `
provision will use specified Dockerfiles to build all targeted images.
If no Dockerfile is given, it will pull the image(s) from the given registry.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().provision(options.nocache)
		}, true),
	}

	var cmdRun = &cobra.Command{
		Use:   "run",
		Short: "Run the containers",
		Long:  `run will call docker run for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().run(options.recreate)
		}, false),
	}

	var cmdRm = &cobra.Command{
		Use:   "rm",
		Short: "Remove the containers",
		Long:  `rm will call docker rm for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().rm(options.forceRm)
		}, true),
	}

	var cmdKill = &cobra.Command{
		Use:   "kill",
		Short: "Kill the containers",
		Long:  `kill will call docker kill for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().kill()
		}, true),
	}

	var cmdStart = &cobra.Command{
		Use:   "start",
		Short: "Start the containers",
		Long:  `start will call docker start for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().start()
		}, false),
	}

	var cmdStop = &cobra.Command{
		Use:   "stop",
		Short: "Stop the containers",
		Long:  `stop will call docker stop for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().stop()
		}, true),
	}

	var cmdPause = &cobra.Command{
		Use:   "pause",
		Short: "Pause the containers",
		Long:  `pause will call docker pause for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().reversed().pause()
		}, true),
	}

	var cmdUnpause = &cobra.Command{
		Use:   "unpause",
		Short: "Unpause the containers",
		Long:  `unpause will call docker unpause for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().unpause()
		}, false),
	}

	var cmdPush = &cobra.Command{
		Use:   "push",
		Short: "Push the containers",
		Long:  `push will call docker push for all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().push()
		}, true),
	}

	var cmdStatus = &cobra.Command{
		Use:   "status",
		Short: "Displays status of containers",
		Long:  `Displays the current status of all targeted containers.`,
		Run: configCommand(func(config Config) {
			config.TargetedContainers().status(options.notrunc)
		}, true),
	}

	var cmdGraph = &cobra.Command{
		Use:   "graph",
		Short: "Dumps the dependency graph as a DOT file",
		Long:  `Generate a DOT file representing the dependency graph. Bold nodes represent the
containers declared in the config (as opposed to non-bold ones that are referenced
in the config, but not defined). Targeted containers are highlighted with color
borders. Solid edges represent links, dashed edges volumesFrom, and dotted edges
net=container relations.`,
		Run: configCommand(func(config Config) {
				config.DependencyGraph().DOT(os.Stdout, config.TargetedContainers())
		}, true),
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.9.1-SNAPSHOT")
		},
	}

	var craneCmd = &cobra.Command{
		Use:   "crane",
		Short: "crane - Lift containers with ease",
		Long: `
Crane is a little tool to orchestrate Docker containers.
It works by reading in JSON or YAML which describes how to obtain container images and how to run them.
See the corresponding docker commands for more information.`,
	}

	craneCmd.PersistentFlags().BoolVarP(&options.verbose, "verbose", "v", false, "Verbose output")
	craneCmd.PersistentFlags().StringVarP(&options.config, "config", "c", "", "Config file to read from")
	craneCmd.PersistentFlags().StringVarP(&options.target[0], "target", "t", "", "Group or container to execute the command for [DEPRECATED, NOW IMPLICIT]")
	cascadingValuesSuffix := `
					"all": follow any kind of dependency
					"link": follow --link dependencies only
					"volumesFrom": follow --volumesFrom dependencies only
					"net": follow --net dependencies only
	`
	craneCmd.PersistentFlags().StringVarP(&options.cascadeDependencies, "cascade-dependencies", "d", "none", "Also apply the command for the containers that (any of) the explicitly targeted one(s) depend on"+cascadingValuesSuffix)
	craneCmd.PersistentFlags().StringVarP(&options.cascadeAffected, "cascade-affected", "a", "none", "Also apply the command for the existing containers depending on (any of) the explicitly targeted one(s)"+cascadingValuesSuffix)

	cmdLift.Flags().BoolVarP(&options.recreate, "recreate", "r", false, "Recreate containers (force-remove containers if they exist, force-provision images, run containers)")
	cmdLift.Flags().BoolVarP(&options.nocache, "no-cache", "n", false, "Build the image without any cache")

	cmdProvision.Flags().BoolVarP(&options.nocache, "no-cache", "n", false, "Build the image without any cache")

	cmdRun.Flags().BoolVarP(&options.recreate, "recreate", "r", false, "Recreate containers (force-remove containers first)")

	cmdRm.Flags().BoolVarP(&options.forceRm, "force", "f", false, "Kill containers if they are running first")

	cmdStatus.Flags().BoolVarP(&options.notrunc, "no-trunc", "", false, "Don't truncate output")

	// default usage template with target arguments & description
	craneCmd.SetUsageTemplate(`{{ $cmd := . }}
Usage: {{if .Runnable}}
  {{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if .HasSubCommands}}
  {{ .CommandPath}} [command]{{end}} [target1 [target2 [...]]]
{{ if .HasSubCommands}}
Available Commands: {{range .Commands}}{{if .Runnable}}
  {{rpad .Use .UsagePadding }} {{.Short}}{{end}}{{end}}
{{end}}
Explicit targeting:
  By default, the command is applied to all containers declared in the
  config,  or to the containers defined in the group ` + "`" + `default` + "`" + ` if it is
  defined. If one or several container or group reference(s) is/are
  passed as  argument(s), the command will only be applied to containers
  matching these references. Note however that providing cascading flags
  might extend the set of targeted containers.

{{ if .HasFlags}}Available Flags:
{{.Flags.FlagUsages}}{{end}}{{if .HasParent}}{{if and (gt .Commands 0) (gt .Parent.Commands 1) }}
Additional help topics: {{if gt .Commands 0 }}{{range .Commands}}{{if not .Runnable}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if gt .Parent.Commands 1 }}{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }}{{end}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{end}}
{{end}}
Use "{{.Root.Name}} help [command]" for more information about that command.
`)

	craneCmd.AddCommand(cmdLift, cmdProvision, cmdRun, cmdRm, cmdKill, cmdStart, cmdStop, cmdPause, cmdUnpause, cmdPush, cmdStatus, cmdGraph, cmdVersion)
	err := craneCmd.Execute()
	if err != nil {
		panic(StatusError{status: 64})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"
	"strings"

	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var conn dbox.IConnection
var count int
var ratioTableName string

var (
	plcodes = []string{"PL7A", "PL29A*", "Pl31*", "PL28",
		"PL33*", "PL34*", "PL35*"}
	branchids                   = []string{"CD04", "CD11"}
	trxsource                   = "rdsbymksadj"
	sourcetablename             = "salespls-summary"
	calctablename               = "salespls-summary"
	desttablename               = "salespls-summary"
	t0                          time.Time
	fiscalyear, iscount, scount int
	data                        map[string]float64
	masters                     = toolkit.M{}
)

type plalloc struct {
	Key      string
	Ref1     float64
	Current  float64
	Expect   float64
	Absorbed float64
}

type allocmap map[string]*plalloc

var plallocs = allocmap{}
var targets = allocmap{}
var totals = allocmap{}

func adjustAllocs(allocsmap *allocmap, key string, current, expect, absorbed, ref1 float64) {
	allocs := *allocsmap
	alloc := allocs[key]
	if alloc == nil {
		alloc = new(plalloc)
		alloc.Key = key
	}
	alloc.Current += current
	alloc.Expect += expect
	alloc.Ref1 += ref1
	alloc.Absorbed += absorbed
	allocs[key] = alloc
	*allocsmap = allocs
}

func main() {
	t0 = time.Now()

	setinitialconnection()
	defer gdrj.CloseDb()
	prepmastercalc()

	toolkit.Println("Start data query...")
	tablenames := []string{
		"salespls-summary"}

	for _, tn := range tablenames {
		e := buildRatio(calctablename)
		if e != nil {
			toolkit.Printfn("Build ratio error: %s - %s", tn, e.Error())
			return
		}

		e = processTable(tn)
		if e != nil {
			toolkit.Printfn("Process table error: %s - %s", tn, e.Error())
			return
		}
	}
}

func buildRatio(tn string) error {

	cratios, _ := conn.NewQuery().From("rawpromobybrand").Select().Cursor(nil)
	defer cratios.Close()
	for {
		mr := toolkit.M{}
		eratio := cratios.Fetch(&mr, 1, false)
		if eratio != nil {
			break
		}
		keytarget := mr.GetString("_id")
		value := mr.GetFloat64("target")
		adjustAllocs(&targets, keytarget, value, 0, 0, 0)
	}

	cursor, _ := conn.NewQuery().From(calctablename).
		Select().
		Cursor(nil)
	defer cursor.Close()

	i := 0
	count := cursor.Count()
	t0 := time.Now()
	mstone := 0

	for {
		mr := toolkit.M{}
		efetch := cursor.Fetch(&mr, 1, false)
		if efetch != nil {
			break
		}
		i++
		makeProgressLog("Build Ratio", i, count, 5, &mstone, t0)
		//-- keyes
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("date_fiscal")
		keyaccountid := key.GetString("customer_customergroupname")
		brandid := key.GetString("product_brand")

		keytarget := toolkit.Sprintf("%s_%s",
			fiscal, brandid)
		target := targets[keytarget]
		if target == nil {
			continue
		}

		keyalloc := toolkit.Sprintf("%s_%s_%s",
			fiscal, keyaccountid, brandid)
		keyttotal := toolkit.Sprintf("%s_%s",
			fiscal, keyaccountid)

		sales := mr.GetFloat64("PL8A")
		spg := mr.GetFloat64("PL31")
		promo := mr.GetFloat64("PL29A")

		adjustAllocs(&plallocs, keyalloc, spg+promo, 0, 0, sales)
		adjustAllocs(&totals, keyttotal, spg+promo, 0, 0, sales)
	}

	for kalloc, valloc := range plallocs {
		kallocs := strings.Split(kalloc, "_")
		keyttotal := toolkit.Sprintf("%s_%s", kallocs[0], kallocs[1])
		keytarget := toolkit.Sprintf("%s_%s", kallocs[0], kallocs[2])

		total := totals[keyttotal]
		target := targets[keytarget]
		valloc.Expect = target.Current + valloc.Current/total.Current
	}

	toolkit.Printfn("PL Alloc:\n%s", toolkit.JsonStringIndent(plallocs, " "))
	return nil
}

func makeProgressLog(reference string, i, count, step int, current *int, tstart time.Time) int {
	perstep := count * step / 100
	icurrent := *current
	if icurrent == 0 {
		icurrent = perstep
	}
	pct := i * 100 / count
	if i >= icurrent {
		toolkit.Printfn("Processing %s, %d of %d [%d pct] in %s",
			reference, i, count, pct, time.Since(tstart).String())
		icurrent += perstep
	}
	*current = icurrent
	return icurrent
}

func processTable(tn string) error {
	connsave, _ := modules.GetDboxIConnection("db_godrej")
	defer connsave.Close()

	toolkit.Printfn("Start processing allocation")
	cursor, _ := conn.NewQuery().From(calctablename).
		Cursor(nil)
	defer cursor.Close()

	plmodels := masters.Get("plmodel", map[string]*gdrj.PLModel{}).(map[string]*gdrj.PLModel)
	qsave := connsave.NewQuery().SetConfig("multiexec", true).From(desttablename).Save()

	count := cursor.Count()
	i := 0
	mstone := 0
	t0 = time.Now()
	for {
		mr := toolkit.M{}
		ef := cursor.Fetch(&mr, 1, false)
		if ef != nil {
			break
		}

		//-- logging
		i++
		makeProgressLog("Processing", i, count, 5, &mstone, t0)

		//-- keyes
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("date_fiscal")
		keyaccountid := key.GetString("customer_customergroupname")
		brandid := key.GetString("product_brand")

		//--- scaledown
		keyalloc := toolkit.Sprintf("%s_%s_%s",
			fiscal, keyaccountid, brandid)
		alloc := plallocs[keyalloc]
		if alloc != nil {
			continue
		}
		adjustment := alloc.Expect - alloc.Current
		sales := mr.GetFloat64("PL8A")
		salesratio := toolkit.Div(sales, alloc.Ref1)

		spgpromototal := float64(0)
		spgpromoratios := map[string]float64{}
		for plid, plvalue := range mr {
			validpl := validatePLID(plid, plmodels)
			if validpl {
				f64plvalue := plvalue.(float64)
				spgpromototal += f64plvalue
				spgpromoratios[plid] = spgpromoratios[plid] + f64plvalue
			}
		}

		for plid, plvalue := range mr {
			validpl := validatePLID(plid, plmodels)
			if validpl {
				spgpromoratio := spgpromoratios[plid]
				f64plvalue := plvalue.(float64)
				newvalue := toolkit.Div(
					spgpromoratio*salesratio*adjustment,
					spgpromototal) + f64plvalue
				mr.Set(plid, newvalue)
			}
		}

		gdrj.CalcSum(mr, masters)
		esave2 := qsave.Exec(toolkit.M{}.Set("data", mr))
		if esave2 != nil {
			return esave2
		}
		//key := mr.Get("key", toolkit.M{}).(toolkit.M)
		//fiscal := key.GetString("date_fiscal")
	}
	return nil
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, ecrx := gdrj.Find(fnModel(), filter, nil)
	if ecrx != nil {
		toolkit.Printfn("Cursor Error: %s", ecrx.Error())
		os.Exit(100)
	}
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmastercalc() {
	toolkit.Println("--> PL MODEL")
	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))
}

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

func validatePLID(plid string, plmodels map[string]*gdrj.PLModel) bool {
	//-- exit if summary
	if plid == "PL29A" || plid == "31" {
		return false
	}

	//-- gte plmodel and exit if no model
	plmodel := plmodels[plid]
	if plmodel == nil {
		return false
	}

	if strings.HasPrefix(plmodel.PLHeader2, "SPG Exp") {
		return true
	} else if strings.HasPrefix(plmodel.PLHeader2, "Promotions Expense") {
		return true
	}
	return false
}
<commit_msg>ipd promo<commit_after>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"
	"strings"

	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var conn dbox.IConnection
var count int
var ratioTableName string

var (
	plcodes = []string{"PL7A", "PL29A*", "Pl31*", "PL28",
		"PL33*", "PL34*", "PL35*"}
	branchids                   = []string{"CD04", "CD11"}
	trxsource                   = "rdsbymksadj"
	sourcetablename             = "salespls-summary"
	calctablename               = "salespls-summary"
	desttablename               = "salespls-summary"
	t0                          time.Time
	fiscalyear, iscount, scount int
	data                        map[string]float64
	masters                     = toolkit.M{}
)

type plalloc struct {
	Key      string
	Ref1     float64
	Current  float64
	Expect   float64
	Absorbed float64
}

type allocmap map[string]*plalloc

var plallocs = allocmap{}
var targets = allocmap{}
var totals = allocmap{}

func adjustAllocs(allocsmap *allocmap, key string, current, expect, absorbed, ref1 float64) {
	allocs := *allocsmap
	alloc := allocs[key]
	if alloc == nil {
		alloc = new(plalloc)
		alloc.Key = key
	}
	alloc.Current += current
	alloc.Expect += expect
	alloc.Ref1 += ref1
	alloc.Absorbed += absorbed
	allocs[key] = alloc
	*allocsmap = allocs
}

func main() {
	t0 = time.Now()

	setinitialconnection()
	defer gdrj.CloseDb()
	prepmastercalc()

	toolkit.Println("Start data query...")
	tablenames := []string{
		"salespls-summary"}

	for _, tn := range tablenames {
		e := buildRatio(calctablename)
		if e != nil {
			toolkit.Printfn("Build ratio error: %s - %s", tn, e.Error())
			return
		}

		e = processTable(tn)
		if e != nil {
			toolkit.Printfn("Process table error: %s - %s", tn, e.Error())
			return
		}
	}
}

func buildRatio(tn string) error {

	cratios, _ := conn.NewQuery().From("rawpromobybrand").Select().Cursor(nil)
	defer cratios.Close()
	for {
		mr := toolkit.M{}
		eratio := cratios.Fetch(&mr, 1, false)
		if eratio != nil {
			break
		}
		keytarget := mr.GetString("_id")
		value := mr.GetFloat64("target")
		adjustAllocs(&targets, keytarget, value, 0, 0, 0)
	}

	cursor, _ := conn.NewQuery().From(calctablename).
		Select().
		Cursor(nil)
	defer cursor.Close()

	i := 0
	count := cursor.Count()
	t0 := time.Now()
	mstone := 0

	for {
		mr := toolkit.M{}
		efetch := cursor.Fetch(&mr, 1, false)
		if efetch != nil {
			break
		}
		i++
		makeProgressLog("Build Ratio", i, count, 5, &mstone, t0)
		//-- keyes
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("date_fiscal")
		keyaccountid := key.GetString("customer_customergroupname")
		brandid := key.GetString("product_brand")

		keytarget := toolkit.Sprintf("%s_%s",
			fiscal, brandid)
		target := targets[keytarget]
		if target == nil {
			continue
		}

		keyalloc := toolkit.Sprintf("%s_%s_%s",
			fiscal, keyaccountid, brandid)
		keyttotal := toolkit.Sprintf("%s_%s",
			fiscal, keyaccountid)

		sales := mr.GetFloat64("PL8A")
		spg := mr.GetFloat64("PL31")
		promo := mr.GetFloat64("PL29A")

		adjustAllocs(&plallocs, keyalloc, spg+promo, 0, 0, sales)
		adjustAllocs(&totals, keyttotal, spg+promo, 0, 0, sales)
	}

	for kalloc, valloc := range plallocs {
		kallocs := strings.Split(kalloc, "_")
		keyttotal := toolkit.Sprintf("%s_%s", kallocs[0], kallocs[1])
		keytarget := toolkit.Sprintf("%s_%s", kallocs[0], kallocs[2])

		total := totals[keyttotal]
		target := targets[keytarget]
		valloc.Expect = target.Current + valloc.Current/total.Current
	}

	toolkit.Printfn("PL Alloc:\n%s", toolkit.JsonStringIndent(plallocs, " "))
	return nil
}

func makeProgressLog(reference string, i, count, step int, current *int, tstart time.Time) int {
	perstep := count * step / 100
	icurrent := *current
	if icurrent == 0 {
		icurrent = perstep
	}
	pct := i * 100 / count
	if i >= icurrent {
		toolkit.Printfn("Processing %s, %d of %d [%d pct] in %s",
			reference, i, count, pct, time.Since(tstart).String())
		icurrent += perstep
	}
	*current = icurrent
	return icurrent
}

func processTable(tn string) error {
	connsave, _ := modules.GetDboxIConnection("db_godrej")
	defer connsave.Close()

	toolkit.Printfn("Start processing allocation")
	cursor, _ := conn.NewQuery().From(calctablename).
		Cursor(nil)
	defer cursor.Close()

	plmodels := masters.Get("plmodel", map[string]*gdrj.PLModel{}).(map[string]*gdrj.PLModel)
	qsave := connsave.NewQuery().SetConfig("multiexec", true).From(desttablename).Save()

	count := cursor.Count()
	i := 0
	mstone := 0
	t0 = time.Now()
	for {
		mr := toolkit.M{}
		ef := cursor.Fetch(&mr, 1, false)
		if ef != nil {
			break
		}

		//-- logging
		i++
		makeProgressLog("Processing", i, count, 5, &mstone, t0)

		//-- keyes
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("date_fiscal")
		keyaccountid := key.GetString("customer_customergroupname")
		brandid := key.GetString("product_brand")

		//--- scaledown
		keyalloc := toolkit.Sprintf("%s_%s_%s",
			fiscal, keyaccountid, brandid)
		alloc := plallocs[keyalloc]
		if alloc == nil {
			continue
		}
		adjustment := alloc.Expect - alloc.Current
		sales := mr.GetFloat64("PL8A")
		salesratio := toolkit.Div(sales, alloc.Ref1)

		spgpromototal := float64(0)
		spgpromoratios := map[string]float64{}
		for plid, plvalue := range mr {
			validpl := validatePLID(plid, plmodels)
			if validpl {
				f64plvalue := plvalue.(float64)
				spgpromototal += f64plvalue
				spgpromoratios[plid] = spgpromoratios[plid] + f64plvalue
			}
		}

		for plid, plvalue := range mr {
			validpl := validatePLID(plid, plmodels)
			if validpl {
				spgpromoratio := spgpromoratios[plid]
				f64plvalue := plvalue.(float64)
				newvalue := toolkit.Div(
					spgpromoratio*salesratio*adjustment,
					spgpromototal) + f64plvalue
				mr.Set(plid, newvalue)
			}
		}

		gdrj.CalcSum(mr, masters)
		esave2 := qsave.Exec(toolkit.M{}.Set("data", mr))
		if esave2 != nil {
			return esave2
		}
		//key := mr.Get("key", toolkit.M{}).(toolkit.M)
		//fiscal := key.GetString("date_fiscal")
	}
	return nil
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, ecrx := gdrj.Find(fnModel(), filter, nil)
	if ecrx != nil {
		toolkit.Printfn("Cursor Error: %s", ecrx.Error())
		os.Exit(100)
	}
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmastercalc() {
	toolkit.Println("--> PL MODEL")
	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))
}

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

func validatePLID(plid string, plmodels map[string]*gdrj.PLModel) bool {
	//-- exit if summary
	if plid == "PL29A" || plid == "31" {
		return false
	}

	//-- gte plmodel and exit if no model
	plmodel := plmodels[plid]
	if plmodel == nil {
		return false
	}

	if strings.HasPrefix(plmodel.PLHeader2, "SPG Exp") {
		return true
	} else if strings.HasPrefix(plmodel.PLHeader2, "Promotions Expense") {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package registry

type SearchResult struct {
	StarCount   int    `json:"star_count"`
	IsOfficial  bool   `json:"is_official"`
	Name        string `json:"name"`
	IsTrusted   bool   `json:"is_trusted"`
	Description string `json:"description"`
}

type SearchResults struct {
	Query      string         `json:"query"`
	NumResults int            `json:"num_results"`
	Results    []SearchResult `json:"results"`
}

type RepositoryData struct {
	ImgList   map[string]*ImgData
	Endpoints []string
	Tokens    []string
}

type ImgData struct {
	ID              string `json:"id"`
	Checksum        string `json:"checksum,omitempty"`
	ChecksumPayload string `json:"-"`
	Tag             string `json:",omitempty"`
}

type RegistryInfo struct {
	Version    string `json:"version"`
	Standalone bool   `json:"standalone"`
}

type ManifestData struct {
	Name          string   `json:"name"`
	Tag           string   `json:"tag"`
	Architecture  string   `json:"architecture"`
	BlobSums      []string `json:"blobSums"`
	History       []string `json:"history"`
	SchemaVersion int      `json:"schemaVersion"`
}

type APIVersion int

func (av APIVersion) String() string {
	return apiVersions[av]
}

var DefaultAPIVersion APIVersion = APIVersion1
var apiVersions = map[APIVersion]string{
	1: "v1",
	2: "v2",
}

const (
	APIVersion1 = iota + 1
	APIVersion2
)
<commit_msg>Update manifest format to rename blobsums and use arrays of dictionaries<commit_after>package registry

type SearchResult struct {
	StarCount   int    `json:"star_count"`
	IsOfficial  bool   `json:"is_official"`
	Name        string `json:"name"`
	IsTrusted   bool   `json:"is_trusted"`
	Description string `json:"description"`
}

type SearchResults struct {
	Query      string         `json:"query"`
	NumResults int            `json:"num_results"`
	Results    []SearchResult `json:"results"`
}

type RepositoryData struct {
	ImgList   map[string]*ImgData
	Endpoints []string
	Tokens    []string
}

type ImgData struct {
	ID              string `json:"id"`
	Checksum        string `json:"checksum,omitempty"`
	ChecksumPayload string `json:"-"`
	Tag             string `json:",omitempty"`
}

type RegistryInfo struct {
	Version    string `json:"version"`
	Standalone bool   `json:"standalone"`
}

type FSLayer struct {
	BlobSum string `json:"blobSum"`
}

type ManifestHistory struct {
	V1Compatibility string `json:"v1Compatibility"`
}

type ManifestData struct {
	Name          string             `json:"name"`
	Tag           string             `json:"tag"`
	Architecture  string             `json:"architecture"`
	FSLayers      []*FSLayer         `json:"fsLayers"`
	History       []*ManifestHistory `json:"history"`
	SchemaVersion int                `json:"schemaVersion"`
}

type APIVersion int

func (av APIVersion) String() string {
	return apiVersions[av]
}

var DefaultAPIVersion APIVersion = APIVersion1
var apiVersions = map[APIVersion]string{
	1: "v1",
	2: "v2",
}

const (
	APIVersion1 = iota + 1
	APIVersion2
)
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"sort"
	"sync"
	"time"

	"github.com/UniversityRadioYork/baps3-go"
)

type GetResponse struct {
	Status string
	Value  interface{}
}

func GetOk(value interface{}) *GetResponse {
	r := new(GetResponse)
	r.Status = "ok"
	r.Value = value
	return r
}

type bfConnector struct {
	conn   *baps3.Connector
	name   string
	wg     *sync.WaitGroup
	logger *log.Logger

	// Cache of BAPS3 service internal state
	features map[Feature]struct{}
	state    string
	time     time.Duration
	file     string

	reqCh chan httpRequest
	resCh <-chan baps3.Message

	// TODO(CaptainHayashi): move this away from baps3.Message to
	// something generic.
	updateCh chan<- baps3.Message
}

func initBfConnector(name string, updateCh chan baps3.Message, waitGroup *sync.WaitGroup, logger *log.Logger) (c *bfConnector) {
	resCh := make(chan baps3.Message)

	c = new(bfConnector)
	c.resCh = resCh
	c.conn = baps3.InitConnector(name, resCh, waitGroup, logger)
	c.name = name
	c.wg = waitGroup
	c.logger = logger
	c.reqCh = make(chan httpRequest)
	c.updateCh = updateCh

	c.features = make(map[Feature]struct{})
	return
}

func (c *bfConnector) Run() {
	defer c.wg.Done()
	defer close(c.conn.ReqCh)

	go c.conn.Run()

	fmt.Printf("connector %s now listening for requests\n", c.name)

	for {
		select {
		case rq, ok := <-c.reqCh:
			if !ok {
				return
			}

			// TODO(CaptainHayashi): probably make this more robust
			resource := strings.Replace(rq.resource, "/"+c.name, "", 1)
			fmt.Printf("connector %s response %s\n", c.name, resource)

			// TODO(CaptainHayashi): other methods
			rq.resCh <- c.get(resource)
		case res := <-c.resCh:
			var err error
			switch res.Word() {
			case baps3.RsFeatures:
				err = c.updateFeaturesFromMessage(res)
			case baps3.RsFile:
				err = c.updateFileFromMessage(res)
			case baps3.RsState:
				err = c.updateStateFromMessage(res)
			case baps3.RsTime:
				err = c.updateTimeFromMessage(res)
			}
			if err != nil {
				fmt.Println(err)
			}
			c.updateCh <- res
		}
	}

	return
}

// hasFeature returns whether the connected server advertises the given feature.
func (c *bfConnector) hasFeature(f Feature) bool {
	_, ok := c.features[f]
	return ok
}

func splitResource(resource string) []string {
	res := strings.Split(strings.Trim(resource, "/"), "/")

	// The empty resource is returned as {""}: let's fix that
	if len(res) == 1 && res[0] == "" {
		res = []string{}
	}

	return res
}

func (c *bfConnector) get(resource string) interface{} {
	// TODO(CaptainHayashi): HTTP status codes

	resourcePath := splitResource(resource)

	if len(resourcePath) == 0 {
		return GetOk(c.rootGet())
	}

	var r interface{}

	switch resourcePath[0] {
	case "control":
		r = c.control(resourcePath[1:])
	case "player":
		r = c.player(resourcePath[1:])
		//case "playlist":
		//	r = c.playlist(resourcePath[1:])
	}

	if r == nil {
		// TODO(CaptainHayashi): more errors
		return GetResponse{
			Status: "what",
			Value:  "resource not found: " + resource,
		}
	}

	return GetOk(r)
}

// control is the main handler for the /control resource.
func (c *bfConnector) control(resourcePath []string) interface{} {
	if len(resourcePath) == 0 {
		return c.controlGet()
	}

	if len(resourcePath) == 1 {
		switch resourcePath[0] {
		case "features":
			return c.featuresGet()
		case "state":
			return c.stateGet()
		}
	}

	return nil
}

// player is the main handler for the /player resource.
func (c *bfConnector) player(resourcePath []string) interface{} {
	if len(resourcePath) == 0 {
		return c.playerGet()
	}

	if len(resourcePath) == 1 {
		switch resourcePath[0] {
		case "time":
			return c.timeGet()
		case "file":
			return c.fileGet()
		}
	}

	return nil
}

// GET value for /
func (c *bfConnector) rootGet() interface{} {
	return struct {
		Control  interface{} `json:"control,omitempty"`
		Player   interface{} `json:"player,omitempty"`
		Playlist interface{} `json:"playlist,omitempty"`
	}{
		c.controlGet(),
		c.playerGet(),
		[]string{},
	}
}

// GET value for /control
func (c *bfConnector) controlGet() interface{} {
	return struct {
		Features []string `json:"features"`
		State string `json:"state"`
	}{
		c.featuresGet(),
		c.stateGet(),
	}
}

// GET value for /control/features
func (c *bfConnector) featuresGet() []string {
	fstrings := []string{}

	for k := range c.features {
		fstrings = append(fstrings, k.String())
	}

	sort.Strings(fstrings)
	return fstrings
}

// GET value for /control/state
func (c *bfConnector) stateGet() string {
	return c.state
}

// GET value for /player
func (c *bfConnector) playerGet() interface{} {
	// TODO(CaptainHayashi): Probably a spec change, but the fact that this
	// resource is guarded by more than one feature is iffy.  Do we need a
	// Player feature?
	if !(c.hasFeature(FtFileLoad) || c.hasFeature(FtTimeReport)) {
		return nil
	}

	return struct {
		Time interface{} `json:"time"`
		File interface{} `json:"file,omitempty"`
	}{
		c.timeGet(),
		c.fileGet(),
	}
}

// GET value for /player/time
func (c *bfConnector) timeGet() interface{} {
	if !c.hasFeature(FtTimeReport) {
		return nil
	}

	// Time is reported in _micro_seconds
	return c.time.Nanoseconds() / 1000
}

// GET value for /player/file
func (c *bfConnector) fileGet() interface{} {
	if !c.hasFeature(FtFileLoad) {
		return nil
	}

	return c.file
}

func (c *bfConnector) updateFeaturesFromMessage(res baps3.Message) (err error) {
	feats := make(map[Feature]struct{})

	for i := 0; ; i++ {
		if fstring, e := res.Arg(i); e == nil {
			feat := LookupFeature(fstring)
			if feat == FtUnknown {
				err = fmt.Errorf("unknown feature: %q", fstring)
				break
			}
			feats[feat] = struct{}{}
		} else {
			// e != nil means we've run out of arguments.
			break
		}
	}

	c.features = feats
	return
}

func (c *bfConnector) updateFileFromMessage(res baps3.Message) (err error) {
	file, err := res.Arg(0)
	if err != nil {
		c.file = ""
		return
	}

	c.file = file

	return
}

func (c *bfConnector) updateStateFromMessage(res baps3.Message) (err error) {
	state, err := res.Arg(0)
	if err != nil {
		c.state = "???"
		return
	}

	c.state = state

	return
}

func (c *bfConnector) updateTimeFromMessage(res baps3.Message) (err error) {
	usecs, err := res.Arg(0)
	if err != nil {
		return
	}

	usec, err := strconv.Atoi(usecs)
	if err != nil {
		return
	}

	c.time = time.Duration(usec) * time.Microsecond

	return
}
<commit_msg>Use maps for dispatching resource requests.<commit_after>package main

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"sort"
	"sync"
	"time"

	"github.com/UniversityRadioYork/baps3-go"
)

type GetResponse struct {
	Status string
	Value  interface{}
}

func GetOk(value interface{}) *GetResponse {
	r := new(GetResponse)
	r.Status = "ok"
	r.Value = value
	return r
}

type bfConnector struct {
	conn   *baps3.Connector
	name   string
	wg     *sync.WaitGroup
	logger *log.Logger

	// Cache of BAPS3 service internal state
	features map[Feature]struct{}
	state    string
	time     time.Duration
	file     string

	reqCh chan httpRequest
	resCh <-chan baps3.Message

	// TODO(CaptainHayashi): move this away from baps3.Message to
	// something generic.
	updateCh chan<- baps3.Message
}

func initBfConnector(name string, updateCh chan baps3.Message, waitGroup *sync.WaitGroup, logger *log.Logger) (c *bfConnector) {
	resCh := make(chan baps3.Message)

	c = new(bfConnector)
	c.resCh = resCh
	c.conn = baps3.InitConnector(name, resCh, waitGroup, logger)
	c.name = name
	c.wg = waitGroup
	c.logger = logger
	c.reqCh = make(chan httpRequest)
	c.updateCh = updateCh

	c.features = make(map[Feature]struct{})
	return
}

func (c *bfConnector) Run() {
	defer c.wg.Done()
	defer close(c.conn.ReqCh)

	go c.conn.Run()

	fmt.Printf("connector %s now listening for requests\n", c.name)

	for {
		select {
		case rq, ok := <-c.reqCh:
			if !ok {
				return
			}

			// TODO(CaptainHayashi): probably make this more robust
			resource := strings.Replace(rq.resource, "/"+c.name, "", 1)
			fmt.Printf("connector %s response %s\n", c.name, resource)

			// TODO(CaptainHayashi): other methods
			rq.resCh <- c.get(resource)
		case res := <-c.resCh:
			var err error
			switch res.Word() {
			case baps3.RsFeatures:
				err = c.updateFeaturesFromMessage(res)
			case baps3.RsFile:
				err = c.updateFileFromMessage(res)
			case baps3.RsState:
				err = c.updateStateFromMessage(res)
			case baps3.RsTime:
				err = c.updateTimeFromMessage(res)
			}
			if err != nil {
				fmt.Println(err)
			}
			c.updateCh <- res
		}
	}

	return
}

// hasFeature returns whether the connected server advertises the given feature.
func (c *bfConnector) hasFeature(f Feature) bool {
	_, ok := c.features[f]
	return ok
}

func splitResource(resource string) []string {
	res := strings.Split(strings.Trim(resource, "/"), "/")

	// The empty resource is returned as {""}: let's fix that
	if len(res) == 1 && res[0] == "" {
		res = []string{}
	}

	return res
}

func (c *bfConnector) get(resource string) interface{} {
	// TODO(CaptainHayashi): HTTP status codes

	resourcePath := splitResource(resource)

	r := c.rootGet(resourcePath)

	if r == nil {
		// TODO(CaptainHayashi): more errors
		return GetResponse{
			Status: "what",
			Value:  "resource not found: " + resource,
		}
	}

	return GetOk(r)
}

/* These resMaps describe simple composite resources, mapping each child
 * resource to the functions handling them.
 *
 * TODO(CaptainHayashi): add support for things that aren't GET
 *   (have each resource be a jump table of possible methods, or send the method
 *    to the resMap func?)
 * TODO(CaptainHayashi): decouple traversal from GET
 * TODO(CaptainHayashi): maybe make traversal iterative instead of recursive?
 */

type resMap map[string]func(*bfConnector, []string) interface{}

var (
	rootRes = resMap{
		"control": (*bfConnector).controlGet,
		"player": (*bfConnector).playerGet,
		// "playlist": (*bfConnector).playlistGet
	}
	controlRes = resMap{
		"features": (*bfConnector).featuresGet,
		"state": (*bfConnector).stateGet,
	}
	playerRes = resMap{
		"time": (*bfConnector).timeGet,
		"file": (*bfConnector).fileGet,
	}
)

func (c *bfConnector) getResource(rm resMap, resourcePath []string) interface{} {
	if len(resourcePath) == 0 {
		// Pull down all of the available child resources in this
		// resource.
		object := make(map[string] interface{})

		for k := range(rm) {
			child := rm[k](c, []string{})

			// Only add a key if the child definitely exists.
			if child != nil {
				object[k] = child
			}
		}

		return object
	}

	// Does the next step on the resource path exist?
	rfunc, ok := rm[resourcePath[0]]
	if ok {
		// Make it that resource's responsibility to
		// find the resource, then.
		return rfunc(c, resourcePath[1:])
	}
	return nil
}

// controlGet is the GET handler for the /control resource.
func (c *bfConnector) controlGet(resourcePath []string) interface{} {
	return c.getResource(controlRes, resourcePath)
}

// playerGet is the GET handler for the /player resource.
func (c *bfConnector) playerGet(resourcePath []string) interface{} {
	// TODO(CaptainHayashi): Probably a spec change, but the fact that this
	// resource is guarded by more than one feature is iffy.  Do we need a
	// Player feature?
	if !(c.hasFeature(FtFileLoad) || c.hasFeature(FtTimeReport)) {
		return nil
	}

	return c.getResource(playerRes, resourcePath)
}

// rootGet is the GET handler for the / resource.
func (c *bfConnector) rootGet(resourcePath []string) interface{} {
	return c.getResource(rootRes, resourcePath)
}

// GET value for /control/features
func (c *bfConnector) featuresGet(resourcePath []string) interface{} {
	// We only want a resource length of 0 (all features), or 1
	// (some index into the list of resources).
	if 1 < len(resourcePath) {
		return nil
	}

	fstrings := []string{}

	for k := range c.features {
		fstrings = append(fstrings, k.String())
	}

	sort.Strings(fstrings)

	if len(resourcePath) == 0 {
		return fstrings
	} else {
		i, err := strconv.Atoi(resourcePath[0])
		// TODO(CaptainHayashi): handle err properly
		if err == nil && 0 <= i && i <= len(fstrings) {
			return fstrings[i]
		}
	}

	return nil
}

// GET value for /control/state
func (c *bfConnector) stateGet(resourcePath []string) interface{} {
	if 0 < len(resourcePath) {
		return nil
	}

	return c.state
}

// GET value for /player/time
func (c *bfConnector) timeGet(resourcePath []string) interface{} {
	if 0 < len(resourcePath) {
		return nil
	}
	if !c.hasFeature(FtTimeReport) {
		return nil
	}

	// Time is reported in _micro_seconds
	return c.time.Nanoseconds() / 1000
}

// GET value for /player/file
func (c *bfConnector) fileGet(resourcePath []string) interface{} {
	if 0 < len(resourcePath) {
		return nil
	}
	if !c.hasFeature(FtFileLoad) {
		return nil
	}

	return c.file
}

func (c *bfConnector) updateFeaturesFromMessage(res baps3.Message) (err error) {
	feats := make(map[Feature]struct{})

	for i := 0; ; i++ {
		if fstring, e := res.Arg(i); e == nil {
			feat := LookupFeature(fstring)
			if feat == FtUnknown {
				err = fmt.Errorf("unknown feature: %q", fstring)
				break
			}
			feats[feat] = struct{}{}
		} else {
			// e != nil means we've run out of arguments.
			break
		}
	}

	c.features = feats
	return
}

func (c *bfConnector) updateFileFromMessage(res baps3.Message) (err error) {
	file, err := res.Arg(0)
	if err != nil {
		c.file = ""
		return
	}

	c.file = file

	return
}

func (c *bfConnector) updateStateFromMessage(res baps3.Message) (err error) {
	state, err := res.Arg(0)
	if err != nil {
		c.state = "???"
		return
	}

	c.state = state

	return
}

func (c *bfConnector) updateTimeFromMessage(res baps3.Message) (err error) {
	usecs, err := res.Arg(0)
	if err != nil {
		return
	}

	usec, err := strconv.Atoi(usecs)
	if err != nil {
		return
	}

	c.time = time.Duration(usec) * time.Microsecond

	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io/ioutil"
	"sync"
	"time"
)

// @author Robin Verlangen
// This element will controll the requests and let people vote untill the authorization level is met

type Consensus struct {
	pendingMux sync.RWMutex
	Pending    map[string]*ConsensusRequest
	ConfFile   string
}

type ConsensusRequest struct {
	Id             string
	TemplateId     string
	ClientIds      []string
	RequestUserId  string
	Reason         string
	ApproveUserIds map[string]bool
	executeMux     sync.RWMutex
	Executed       bool
	CreateTime     int64                     // Unix TS for creation of consensus request
	StartTime      int64                     // Unix TS for start of command execution
	CompleteTime   int64                     // Unix TS for completion of command exectuion
	Callbacks      []func(*ConsensusRequest) `json:"-"` // Will be called on completions
}

func (c *Consensus) Get(id string) *ConsensusRequest {
	c.pendingMux.RLock()
	defer c.pendingMux.RUnlock()
	return c.Pending[id]
}

// Delete
func (c *ConsensusRequest) Delete() bool {
	// Delete child commands
	server.clientsMux.RLock()
	for _, client := range server.clients {
		client.mux.Lock()
		for k, cmd := range client.DispatchedCmds {
			if cmd.ConsensusRequestId == c.Id {
				delete(client.DispatchedCmds, k)
			}
		}
		client.mux.Unlock()
	}
	server.clientsMux.RUnlock()

	// Delete request itself
	server.consensus.pendingMux.Lock()
	defer server.consensus.pendingMux.Unlock()
	delete(server.consensus.Pending, c.Id)

	return true
}

// Cancel the request
func (c *ConsensusRequest) Cancel(user *User) bool {
	audit.Log(user, "Consensus", fmt.Sprintf("Cancel %s", c.Id))
	return c.Delete()
}
func (c *ConsensusRequest) Template() *Template {
	server.templateStore.templateMux.RLock()
	template := server.templateStore.Templates[c.TemplateId]
	server.templateStore.templateMux.RUnlock()
	return template
}

// Start template execution
func (c *ConsensusRequest) start() bool {
	template := c.Template()
	if template == nil {
		log.Printf("Template %s not found for request %s", c.TemplateId, c.Id)
		return false
	}

	// Lock
	c.executeMux.Lock()
	defer c.executeMux.Unlock()
	if c.Executed {
		// Already executed
		return false
	}
	c.Executed = true

	// Currently we only support one execution strategy
	strategy := c.Template().GetExecutionStrategy()
	if strategy == nil {
		log.Printf("Execution strategy not found for request %s", c.Id)
		return false
	}

	// Start time
	c.StartTime = time.Now().Unix()

	// Execute
	strategy.Execute(c)

	// Completed
	c.CompleteTime = time.Now().Unix()

	return true
}

// Check whether this request is good to dispatch
func (c *ConsensusRequest) check() bool {
	// Can we start?
	template := c.Template()
	if template == nil {
		log.Printf("Template %s not found for request %s", c.TemplateId, c.Id)
		return false
	}

	// Did we meet the auth?
	minAuth := template.Acl.MinAuth
	voteCount := 1 // Initial vote by the requester
	for _ = range c.ApproveUserIds {
		voteCount++
	}
	if uint(voteCount) < minAuth {
		// Did not meet
		log.Printf("Vote count %d does not yet meet required %d for request %s", voteCount, minAuth, c.Id)
		return false
	}

	// Start
	return c.start()
}

func (c *ConsensusRequest) Approve(user *User) bool {
	if c.ApproveUserIds == nil {
		c.ApproveUserIds = make(map[string]bool)
	}
	if c.RequestUserId == user.Id {
		return false
	}
	if c.ApproveUserIds[user.Id] {
		return false
	}
	c.ApproveUserIds[user.Id] = true

	audit.Log(user, "Consensus", fmt.Sprintf("Approve %s", c.Id))

	c.check()

	return true
}

func (c *Consensus) save() {
	c.pendingMux.Lock()
	defer c.pendingMux.Unlock()
	bytes, je := json.Marshal(c.Pending)
	if je != nil {
		log.Printf("Failed to write consensus: %s", je)
		return
	}
	err := ioutil.WriteFile(c.ConfFile, bytes, 0644)
	if err != nil {
		log.Printf("Failed to write consensus: %s", err)
		return
	}
}

func (c *Consensus) load() {
	c.pendingMux.Lock()
	defer c.pendingMux.Unlock()
	// Read file and load into
	bytes, err := ioutil.ReadFile(c.ConfFile)
	if err == nil {
		var v map[string]*ConsensusRequest
		je := json.Unmarshal(bytes, &v)
		if je != nil {
			log.Printf("Invalid users.json: %s", je)
			return
		}
		c.Pending = v
	}
}

func (c *Consensus) AddRequest(templateId string, clientIds []string, user *User, reason string) *ConsensusRequest {
	// Double check permissions
	if !user.HasRole("requester") {
		log.Printf("User %s (%s) does not have requester permissions", user.Username, user.Id)
		return nil
	}

	// Create request
	cr := newConsensusRequest()
	cr.TemplateId = templateId
	cr.ClientIds = clientIds
	cr.RequestUserId = user.Id
	cr.Reason = reason

	audit.Log(user, "Consensus", fmt.Sprintf("Request %s, reason: %s", cr.Id, cr.Reason))

	c.pendingMux.Lock()
	c.Pending[cr.Id] = cr
	c.pendingMux.Unlock()

	return cr
}

func newConsensus() *Consensus {
	c := &Consensus{
		Pending:  make(map[string]*ConsensusRequest),
		ConfFile: "/etc/indispenso/consensus.json",
	}
	c.load()
	return c
}
func newConsensusRequest() *ConsensusRequest {
	id, _ := uuid.NewV4()
	return &ConsensusRequest{
		Id:             id.String(),
		ApproveUserIds: make(map[string]bool),
		CreateTime:     time.Now().Unix(),
		Callbacks:      make([]func(*ConsensusRequest), 0),
	}
}
<commit_msg>Cleanup consensus file, fixes #30<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io/ioutil"
	"sync"
	"time"
)

// @author Robin Verlangen
// This element will controll the requests and let people vote untill the authorization level is met

type Consensus struct {
	pendingMux sync.RWMutex
	Pending    map[string]*ConsensusRequest
	ConfFile   string
}

type ConsensusRequest struct {
	Id             string
	TemplateId     string
	ClientIds      []string
	RequestUserId  string
	Reason         string
	ApproveUserIds map[string]bool
	executeMux     sync.RWMutex
	Executed       bool
	CreateTime     int64                     // Unix TS for creation of consensus request
	StartTime      int64                     // Unix TS for start of command execution
	CompleteTime   int64                     // Unix TS for completion of command exectuion
	Callbacks      []func(*ConsensusRequest) `json:"-"` // Will be called on completions
}

func (c *Consensus) Get(id string) *ConsensusRequest {
	c.pendingMux.RLock()
	defer c.pendingMux.RUnlock()
	return c.Pending[id]
}

// Delete
func (c *ConsensusRequest) Delete() bool {
	// Delete child commands
	server.clientsMux.RLock()
	for _, client := range server.clients {
		client.mux.Lock()
		for k, cmd := range client.DispatchedCmds {
			if cmd.ConsensusRequestId == c.Id {
				delete(client.DispatchedCmds, k)
			}
		}
		client.mux.Unlock()
	}
	server.clientsMux.RUnlock()

	// Delete request itself
	server.consensus.pendingMux.Lock()
	defer server.consensus.pendingMux.Unlock()
	delete(server.consensus.Pending, c.Id)

	return true
}

// Cancel the request
func (c *ConsensusRequest) Cancel(user *User) bool {
	audit.Log(user, "Consensus", fmt.Sprintf("Cancel %s", c.Id))
	return c.Delete()
}
func (c *ConsensusRequest) Template() *Template {
	server.templateStore.templateMux.RLock()
	template := server.templateStore.Templates[c.TemplateId]
	server.templateStore.templateMux.RUnlock()
	return template
}

// Start template execution
func (c *ConsensusRequest) start() bool {
	template := c.Template()
	if template == nil {
		log.Printf("Template %s not found for request %s", c.TemplateId, c.Id)
		return false
	}

	// Lock
	c.executeMux.Lock()
	defer c.executeMux.Unlock()
	if c.Executed {
		// Already executed
		return false
	}
	c.Executed = true

	// Currently we only support one execution strategy
	strategy := c.Template().GetExecutionStrategy()
	if strategy == nil {
		log.Printf("Execution strategy not found for request %s", c.Id)
		return false
	}

	// Start time
	c.StartTime = time.Now().Unix()

	// Execute
	strategy.Execute(c)

	// Completed
	c.CompleteTime = time.Now().Unix()

	return true
}

// Check whether this request is good to dispatch
func (c *ConsensusRequest) check() bool {
	// Can we start?
	template := c.Template()
	if template == nil {
		log.Printf("Template %s not found for request %s", c.TemplateId, c.Id)
		return false
	}

	// Did we meet the auth?
	minAuth := template.Acl.MinAuth
	voteCount := 1 // Initial vote by the requester
	for _ = range c.ApproveUserIds {
		voteCount++
	}
	if uint(voteCount) < minAuth {
		// Did not meet
		log.Printf("Vote count %d does not yet meet required %d for request %s", voteCount, minAuth, c.Id)
		return false
	}

	// Start
	return c.start()
}

func (c *ConsensusRequest) Approve(user *User) bool {
	if c.ApproveUserIds == nil {
		c.ApproveUserIds = make(map[string]bool)
	}
	if c.RequestUserId == user.Id {
		return false
	}
	if c.ApproveUserIds[user.Id] {
		return false
	}
	c.ApproveUserIds[user.Id] = true

	audit.Log(user, "Consensus", fmt.Sprintf("Approve %s", c.Id))

	c.check()

	return true
}

func (c *Consensus) save() {
	// Lock
	c.pendingMux.Lock()
	defer c.pendingMux.Unlock()

	// Cleanup older than 2 weeks
	maxAge := time.Now().Unix() - (14 * 86400)
	newPending := make(map[string]*ConsensusRequest)
	for k, pending := range c.Pending {
		// Skip if too old
		if pending.CreateTime < maxAge {
			continue
		}
		newPending[k] = pending
	}

	// Put in place
	c.Pending = newPending

	// To JSON
	bytes, je := json.Marshal(c.Pending)
	if je != nil {
		log.Printf("Failed to write consensus: %s", je)
		return
	}

	// Write to disk
	err := ioutil.WriteFile(c.ConfFile, bytes, 0644)
	if err != nil {
		log.Printf("Failed to write consensus: %s", err)
		return
	}
}

func (c *Consensus) load() {
	c.pendingMux.Lock()
	defer c.pendingMux.Unlock()
	// Read file and load into
	bytes, err := ioutil.ReadFile(c.ConfFile)
	if err == nil {
		var v map[string]*ConsensusRequest
		je := json.Unmarshal(bytes, &v)
		if je != nil {
			log.Printf("Invalid users.json: %s", je)
			return
		}
		c.Pending = v
	}
}

func (c *Consensus) AddRequest(templateId string, clientIds []string, user *User, reason string) *ConsensusRequest {
	// Double check permissions
	if !user.HasRole("requester") {
		log.Printf("User %s (%s) does not have requester permissions", user.Username, user.Id)
		return nil
	}

	// Create request
	cr := newConsensusRequest()
	cr.TemplateId = templateId
	cr.ClientIds = clientIds
	cr.RequestUserId = user.Id
	cr.Reason = reason

	audit.Log(user, "Consensus", fmt.Sprintf("Request %s, reason: %s", cr.Id, cr.Reason))

	c.pendingMux.Lock()
	c.Pending[cr.Id] = cr
	c.pendingMux.Unlock()

	return cr
}

func newConsensus() *Consensus {
	c := &Consensus{
		Pending:  make(map[string]*ConsensusRequest),
		ConfFile: "/etc/indispenso/consensus.json",
	}
	c.load()
	return c
}
func newConsensusRequest() *ConsensusRequest {
	id, _ := uuid.NewV4()
	return &ConsensusRequest{
		Id:             id.String(),
		ApproveUserIds: make(map[string]bool),
		CreateTime:     time.Now().Unix(),
		Callbacks:      make([]func(*ConsensusRequest), 0),
	}
}
<|endoftext|>