<commit_before>package main

import (
	"net/http"
	"flag"
	"log"
	"errors"
	"sync"
	"net/url"
	"io/ioutil"
	"strings"
)

var (
	listen = flag.String("listen", ":80", "HTTP listen address.")
	path = flag.String("path", "/xhprof.io/import", "Import endpoint.")
	xhProfIoUrl = flag.String("xhProfIoUrl", "http://localhost/xhprof.io", "Url to xhprof.io installation.")
)

type importRequest struct {
	HttpHost string
	RequestMethod string
	RequestUri string
	XHProfData string
}

type importHandler interface {
	// interface to consume requests
	consume(*importRequest, *sync.WaitGroup)
}

type importHandle struct {
	// import queue
	queue chan importRequest
	// channel that receive one close event
	closeSignal chan string

	count int
}

func main() {
	flag.Parse()

	handle := new(importHandle)
	handle.count = 0
	handle.queue = make(chan importRequest)
	var wg *sync.WaitGroup = new(sync.WaitGroup)
	go importHandlerLoop(handle, wg)

	// provide http endpoint
	http.HandleFunc(*path, func(w http.ResponseWriter, r *http.Request) {
		importRequest, err := createImportRequest(r)
		if err == nil {
			handle.queue <- importRequest
			handle.count++
			w.WriteHeader(http.StatusAccepted)
			return
		}

		w.WriteHeader(http.StatusBadRequest)
		log.Printf("Import error: %v", err)
	})

	// startup http server
	err := http.ListenAndServe(*listen, nil)
	if err != nil {
		panic("HTTP server err: " + err.Error())
	}

}

func importHandlerLoop(handle *importHandle, wg *sync.WaitGroup) {
	for {
		select {
		case importRequest := <-handle.queue:
			wg.Add(1)
			handle.consume(importRequest, wg)
		}
	}
}

func (this importHandle) consume(r importRequest, wg *sync.WaitGroup) {
	defer wg.Done()

	log.Printf("Executing import request for '%s %s%s'.", r.RequestMethod, r.HttpHost, r.RequestUri)

	values := make(url.Values)
	values.Set("http_host", r.HttpHost)
	values.Set("request_method", r.RequestMethod)
	values.Set("request_uri", r.RequestUri)
	values.Set("xhprof_data", r.XHProfData)
	url := []string{*xhProfIoUrl, "/import.php"};
	resp, err := http.PostForm(strings.Join(url, ""), values)
	if err != nil {
		log.Printf("ERROR: %s", err)
		return
	}

	body, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	log.Printf("%s", body)
}

func createImportRequest(r *http.Request) (importRequest importRequest, err error) {
	httpHost := r.FormValue("http_host")
	requestMethod := r.FormValue("request_method")
	requestUri := r.FormValue("request_uri")
	xhProfData := r.FormValue("xhprof_data")

	if httpHost != "" && requestMethod != "" && requestUri != "" && xhProfData != "" {
		importRequest.HttpHost = httpHost
		importRequest.RequestMethod = requestMethod
		importRequest.RequestUri = requestUri
		importRequest.XHProfData = xhProfData
	} else {
		err = errors.New("Missing host, method, uri or xhprof data.")
	}

	return importRequest, err
}
<commit_msg>added xhprof data size to log output<commit_after>package main

import (
	"net/http"
	"flag"
	"log"
	"errors"
	"sync"
	"net/url"
	"io/ioutil"
	"strings"
)

var (
	listen = flag.String("listen", ":80", "HTTP listen address.")
	path = flag.String("path", "/xhprof.io/import", "Import endpoint.")
	xhProfIoUrl = flag.String("xhProfIoUrl", "http://localhost/xhprof.io", "Url to xhprof.io installation.")
)

type importRequest struct {
	HttpHost string
	RequestMethod string
	RequestUri string
	XHProfData string
}

type importHandler interface {
	// interface to consume requests
	consume(*importRequest, *sync.WaitGroup)
}

type importHandle struct {
	// import queue
	queue chan importRequest
	// channel that receive one close event
	closeSignal chan string

	count int
}

func main() {
	flag.Parse()

	handle := new(importHandle)
	handle.count = 0
	handle.queue = make(chan importRequest)
	var wg *sync.WaitGroup = new(sync.WaitGroup)
	go importHandlerLoop(handle, wg)

	// provide http endpoint
	http.HandleFunc(*path, func(w http.ResponseWriter, r *http.Request) {
		importRequest, err := createImportRequest(r)
		if err == nil {
			handle.queue <- importRequest
			handle.count++
			w.WriteHeader(http.StatusAccepted)
			return
		}

		w.WriteHeader(http.StatusBadRequest)
		log.Printf("Import error: %v", err)
	})

	// startup http server
	err := http.ListenAndServe(*listen, nil)
	if err != nil {
		panic("HTTP server err: " + err.Error())
	}

}

func importHandlerLoop(handle *importHandle, wg *sync.WaitGroup) {
	for {
		select {
		case importRequest := <-handle.queue:
			wg.Add(1)
			handle.consume(importRequest, wg)
		}
	}
}

func (this importHandle) consume(r importRequest, wg *sync.WaitGroup) {
	defer wg.Done()

	log.Printf("Executing import request for '%s %s%s'.", r.RequestMethod, r.HttpHost, r.RequestUri)

	values := make(url.Values)
	values.Set("http_host", r.HttpHost)
	values.Set("request_method", r.RequestMethod)
	values.Set("request_uri", r.RequestUri)
	values.Set("xhprof_data", r.XHProfData)
	url := []string{*xhProfIoUrl, "/import.php"};
	resp, err := http.PostForm(strings.Join(url, ""), values)
	if err != nil {
		log.Printf("ERROR: %s", err)
		return
	}

	body, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	log.Printf("%s with json data size %v bytes.", body, len(r.XHProfData))
}

func createImportRequest(r *http.Request) (importRequest importRequest, err error) {
	httpHost := r.FormValue("http_host")
	requestMethod := r.FormValue("request_method")
	requestUri := r.FormValue("request_uri")
	xhProfData := r.FormValue("xhprof_data")

	if httpHost != "" && requestMethod != "" && requestUri != "" && xhProfData != "" {
		importRequest.HttpHost = httpHost
		importRequest.RequestMethod = requestMethod
		importRequest.RequestUri = requestUri
		importRequest.XHProfData = xhProfData
	} else {
		err = errors.New("Missing host, method, uri or xhprof data.")
	}

	return importRequest, err
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 trivago GmbH
//
// 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 core

import (
	"errors"
	"github.com/sirupsen/logrus"
	"github.com/trivago/tgo/ttesting"
	"testing"
)

type dummyFormatter struct {
	SimpleFormatter
	ConfigureHasCalled      bool
	ApplyFormatterHasCalled bool
}

func (format *dummyFormatter) Configure(conf PluginConfigReader) {
	format.ConfigureHasCalled = true
}

func (format *dummyFormatter) GetLogger() logrus.FieldLogger {
	return logrus
}

func (format *dummyFormatter) ApplyFormatter(msg *Message) error {
	format.ApplyFormatterHasCalled = true
	return nil
}

type dummyErrorFormatter struct {
	SimpleFormatter
	ConfigureHasCalled      bool
	ApplyFormatterHasCalled bool
}

func (format *dummyErrorFormatter) Configure(conf PluginConfigReader) {
	format.ConfigureHasCalled = true
}

func (format *dummyErrorFormatter) GetLogger() logrus.FieldLogger {
	return logrus
}

func (format *dummyErrorFormatter) ApplyFormatter(msg *Message) error {
	format.ApplyFormatterHasCalled = true
	return errors.New("Dummy error")
}

func TestFormatterModulatorApplyFormatter(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Nil(formatterModulator.ApplyFormatter(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterModulatorModulate(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Equal(ModulateResultContinue, formatterModulator.Modulate(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterModulatorModulateError(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyErrorFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Equal(ModulateResultDiscard, formatterModulator.Modulate(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterArray(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, _ := getDummyFormatter()
	secondFormatter, _ := getDummyFormatter()

	formatterArray := FormatterArray{formatter, secondFormatter}
	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Nil(formatterArray.ApplyFormatter(msg))

	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
	expect.True(secondFormatter.ConfigureHasCalled)
	expect.True(secondFormatter.ApplyFormatterHasCalled)
}

func getDummyFormatter() (*dummyFormatter, error) {
	TypeRegistry.Register(dummyFormatter{ConfigureHasCalled: false, ApplyFormatterHasCalled: false})
	config := NewPluginConfig("", "core.dummyFormatter")

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		return nil, err
	}

	formatter, casted := plugin.(*dummyFormatter)
	if casted != true {
		return nil, errors.New("Could not carst to dummyFormatter")
	}

	return formatter, nil
}

func getDummyErrorFormatter() (*dummyErrorFormatter, error) {
	TypeRegistry.Register(dummyErrorFormatter{ConfigureHasCalled: false, ApplyFormatterHasCalled: false})
	config := NewPluginConfig("", "core.dummyErrorFormatter")

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		return nil, err
	}

	formatter, casted := plugin.(*dummyErrorFormatter)
	if casted != true {
		return nil, errors.New("Could not carst to dummyErrorFormatter")
	}

	return formatter, nil
}
<commit_msg>Instantiate logrus correctly<commit_after>// Copyright 2015-2017 trivago GmbH
//
// 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 core

import (
	"errors"
	"github.com/sirupsen/logrus"
	"github.com/trivago/tgo/ttesting"
	"testing"
)

type dummyFormatter struct {
	SimpleFormatter
	ConfigureHasCalled      bool
	ApplyFormatterHasCalled bool
}

func (format *dummyFormatter) Configure(conf PluginConfigReader) {
	format.ConfigureHasCalled = true
}

func (format *dummyFormatter) GetLogger() logrus.FieldLogger {
	return logrus.WithField("Scope", "dummyFormatter")
}

func (format *dummyFormatter) ApplyFormatter(msg *Message) error {
	format.ApplyFormatterHasCalled = true
	return nil
}

type dummyErrorFormatter struct {
	SimpleFormatter
	ConfigureHasCalled      bool
	ApplyFormatterHasCalled bool
}

func (format *dummyErrorFormatter) Configure(conf PluginConfigReader) {
	format.ConfigureHasCalled = true
}

func (format *dummyErrorFormatter) GetLogger() logrus.FieldLogger {
	return logrus.WithField("Scope", "dummyErrorFormatter")
}

func (format *dummyErrorFormatter) ApplyFormatter(msg *Message) error {
	format.ApplyFormatterHasCalled = true
	return errors.New("Dummy error")
}

func TestFormatterModulatorApplyFormatter(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Nil(formatterModulator.ApplyFormatter(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterModulatorModulate(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Equal(ModulateResultContinue, formatterModulator.Modulate(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterModulatorModulateError(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, err := getDummyErrorFormatter()
	expect.NoError(err)

	formatterModulator := NewFormatterModulator(formatter)

	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Equal(ModulateResultDiscard, formatterModulator.Modulate(msg))
	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
}

func TestFormatterArray(t *testing.T) {
	expect := ttesting.NewExpect(t)

	formatter, _ := getDummyFormatter()
	secondFormatter, _ := getDummyFormatter()

	formatterArray := FormatterArray{formatter, secondFormatter}
	msg := NewMessage(nil, []byte("test"), InvalidStreamID)

	expect.Nil(formatterArray.ApplyFormatter(msg))

	expect.True(formatter.ConfigureHasCalled)
	expect.True(formatter.ApplyFormatterHasCalled)
	expect.True(secondFormatter.ConfigureHasCalled)
	expect.True(secondFormatter.ApplyFormatterHasCalled)
}

func getDummyFormatter() (*dummyFormatter, error) {
	TypeRegistry.Register(dummyFormatter{ConfigureHasCalled: false, ApplyFormatterHasCalled: false})
	config := NewPluginConfig("", "core.dummyFormatter")

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		return nil, err
	}

	formatter, casted := plugin.(*dummyFormatter)
	if casted != true {
		return nil, errors.New("Could not carst to dummyFormatter")
	}

	return formatter, nil
}

func getDummyErrorFormatter() (*dummyErrorFormatter, error) {
	TypeRegistry.Register(dummyErrorFormatter{ConfigureHasCalled: false, ApplyFormatterHasCalled: false})
	config := NewPluginConfig("", "core.dummyErrorFormatter")

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		return nil, err
	}

	formatter, casted := plugin.(*dummyErrorFormatter)
	if casted != true {
		return nil, errors.New("Could not carst to dummyErrorFormatter")
	}

	return formatter, nil
}
<|endoftext|>


<commit_before>// +build windows

package daemon

import (
	"fmt"

	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/debug"
	"golang.org/x/sys/windows/svc/eventlog"
)

var elog debug.Log

type winSvc struct {
	d Daemon
}

func (ws *winSvc) Execute(args []string, cr <-chan svc.ChangeRequest, change chan<- svc.Status) (svcSpecific bool, errCode uint32) {
	change <- svc.Status{State: svc.StartPending}
	status := make(chan Status, 1)
	cb := func() {
		status <- ws.d.Status()
	}
	ws.d.SetCallback(cb)

	if err := ws.d.Start(args); err != nil {
		errCode = 1
		goto exit
	}

	change <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}

	for {
		select {
		case s := <-status:
			switch s {
			case Invalid:
				errCode = 2
				goto exit
			case Stopped:
				goto exit
			}
		case c := <-cr:
			switch c.Cmd {
			case svc.Interrogate:
				change <- c.CurrentStatus
			case svc.Stop, svc.Shutdown:
				goto exit
			default:
				elog.Error(1, fmt.Sprintf("unexpected control request: #%d", c))
			}
		}
	}

exit:
	change <- svc.Status{State: svc.StopPending}
	ws.d.Stop()
	change <- svc.Status{State: svc.Stopped}
	return false, errCode
}

// Run runs the daemon as either a Windows service or as a console application.
func Run(d Daemon) error {
	isIntSess, err := svc.IsAnInteractiveSession()
	if err != nil {
		return fmt.Errorf("unable to determine if started as a service: %v", err)
	}

	if isIntSess {
		return Console(d)
	}

	ws := &winSvc{d: d}

	elog, err = eventlog.Open(d.Name())
	if err != nil {
		return err
	}
	err = svc.Run(d.Name(), ws)
	if err != nil {
		elog.Error(1, fmt.Sprintf("%s service failed: %v", d.Name(), err))
		return err
	}

	elog.Info(1, fmt.Sprintf("%s service stopped", d.Name()))
	return nil
}
<commit_msg>Add more logging<commit_after>// +build windows

package daemon

import (
	"fmt"

	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/debug"
	"golang.org/x/sys/windows/svc/eventlog"
)

var elog debug.Log

type winSvc struct {
	d Daemon
}

func (ws *winSvc) Execute(args []string, cr <-chan svc.ChangeRequest, change chan<- svc.Status) (svcSpecific bool, errCode uint32) {
	change <- svc.Status{State: svc.StartPending}
	status := make(chan Status, 1)
	cb := func() {
		status <- ws.d.Status()
	}
	ws.d.SetCallback(cb)

	if err := ws.d.Start(args); err != nil {
		errCode = 1
		elog.Error(3, fmt.Sprintf("%s: start failed: %v", ws.d.Name(), err))
		goto exit
	}

	change <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}

	for {
		select {
		case s := <-status:
			switch s {
			case Invalid:
				errCode = 2
				goto exit
			case Stopped:
				goto exit
			}
		case c := <-cr:
			switch c.Cmd {
			case svc.Interrogate:
				change <- c.CurrentStatus
			case svc.Stop, svc.Shutdown:
				goto exit
			default:
				elog.Error(4, fmt.Sprintf("%s: unexpected control request: #%d", ws.d.Name(), c))
			}
		}
	}

exit:
	elog.Info(5, fmt.Sprintf("%s: stopping", d.Name()))
	change <- svc.Status{State: svc.StopPending}
	ws.d.Stop()
	change <- svc.Status{State: svc.Stopped}
	return false, errCode
}

// Run runs the daemon as either a Windows service or as a console application.
func Run(d Daemon) error {
	interactive, err := svc.IsAnInteractiveSession()
	if err != nil {
		interactive = true
	}

	if interactive {
		return Console(d)
	}

	elog, err = eventlog.Open(d.Name())
	if err != nil {
		return err
	}

	elog.Info(1, fmt.Sprintf("%s: starting", d.Name()))
	err = svc.Run(d.Name(), &winSvc{d: d})
	if err != nil {
		elog.Info(2, fmt.Sprintf("%s: service start failed: %v", d.Name(), err))
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package fnlog_test

import (
	"github.com/northbright/fnlog"
	"log"
)

var (
	noTagLog *log.Logger
)

func Example() {
	iLog := fnlog.New("i")
	wLog := fnlog.New("w")
	eLog := fnlog.New("e")

	// Global *log.Logger
	noTagLog = fnlog.New("")

	iLog.Printf("print infos")
	wLog.Printf("print warnnings")
	eLog.Printf("print errors")
	noTagLog.Printf("print messages without tag")

	// Output:
	// 2015/06/09 14:32:59 unit_test.go:14 fnlog_test.Example(): i: print infos
	// 2015/06/09 14:32:59 unit_test.go:15 fnlog_test.Example(): w: print warnnings
	// 2015/06/09 14:32:59 unit_test.go:16 fnlog_test.Example(): e: print errors
	// 2015/06/09 14:32:59 unit_test.go:17 fnlog_test.Example(): print messages without tag
}
<commit_msg>Remove comment to see outputs works in godoc<commit_after>package fnlog_test

import (
	"github.com/northbright/fnlog"
	"log"
)

var (
	noTagLog *log.Logger
)

func Example() {
	iLog := fnlog.New("i")
	wLog := fnlog.New("w")
	eLog := fnlog.New("e")

	noTagLog = fnlog.New("")

	iLog.Printf("print infos")
	wLog.Printf("print warnnings")
	eLog.Printf("print errors")
	noTagLog.Printf("print messages without tag")

	// Output:
	// 2015/06/09 14:32:59 unit_test.go:14 fnlog_test.Example(): i: print infos
	// 2015/06/09 14:32:59 unit_test.go:15 fnlog_test.Example(): w: print warnnings
	// 2015/06/09 14:32:59 unit_test.go:16 fnlog_test.Example(): e: print errors
	// 2015/06/09 14:32:59 unit_test.go:17 fnlog_test.Example(): print messages without tag
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"text/template"
)

var (
	baseUrl string
	sshKey  string
)

const ipxeBootScript = `#!ipxe
set coreos-version {{.Version}}
set base-url http://{{.BaseUrl}}/coreos/amd64-generic/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz root=squashfs: state=tmpfs: sshkey="{{.SSHKey}}"
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`

func ipxeBootScriptServer(w http.ResponseWriter, r *http.Request) {
	v := r.URL.Query()
	version := v.Get("version")
	if version == "" {
		version = "latest"
	}

	t, err := template.New("ipxebootscript").Parse(ipxeBootScript)
	if err != nil {
		http.Error(w, "cannot generate ipxe boot script", 500)
		return
	}

	data := map[string]string{
		"BaseUrl": baseUrl,
		"SSHKey":  sshKey,
		"Version": version,
	}

	err = t.Execute(w, data)
	if err != nil {
		http.Error(w, "cannot generate ipxe boot script", 500)
		return
	}
	return
}

func sshKeyFromFile(filename string) (string, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", err
	}
	return string(bytes.TrimSpace(b)), nil
}

func main() {
	var err error

	// Set the base directory where the coreos directory containing
	// the ssh public key, kernal and boot images.
	baseDir := os.Getenv("COREOS_IPXE_SERVER_BASE_DIR")
	if baseDir == "" {
		log.Fatal("COREOS_IPXE_SERVER_BASE_DIR must be set and non-empty")
	}

	// Set the base URL used by the iPXE boot script.
	baseUrl = os.Getenv("COREOS_IPXE_SERVER_BASE_URL")
	if baseUrl == "" {
		log.Fatal("COREOS_IPXE_SERVER_BASE_URL must be set and non-empty")
	}

	// Set the host:port to listen for HTTP requests.
	listenHost := os.Getenv("COREOS_IPXE_SERVER_LISTEN_HOST")
	listenPort := os.Getenv("COREOS_IPXE_SERVER_LISTEN_PORT")
	if listenPort == "" {
		log.Fatal("COREOS_IPXE_SERVER_LISTEN_PORT must be set and non-empty")
	}
	hostPort := net.JoinHostPort(listenHost, listenPort)

	// The ssh public must exist as $baseDir/coreos/coreos.pub
	sshKeyPath := filepath.Join(baseDir, "coreos/coreos.pub")
	sshKey, err = sshKeyFromFile(sshKeyPath)
	if err != nil {
		log.Fatal("error reading ssh public key from " + sshKeyPath)
	}

	http.HandleFunc("/", ipxeBootScriptServer)

	// Serve kernel and pxe boot images
	staticFilePath := filepath.Join(baseDir, "coreos")
	http.Handle("/coreos/", http.StripPrefix("/coreos/", http.FileServer(http.Dir(staticFilePath))))
	log.Fatal(http.ListenAndServe(hostPort, nil))
}
<commit_msg>Add state query parameter<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"text/template"
)

var (
	baseUrl string
	sshKey  string
)

const ipxeBootScript = `#!ipxe
set coreos-version {{.Version}}
set base-url http://{{.BaseUrl}}/coreos/amd64-generic/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz root=squashfs: {{if not .State}}state=tmpfs: {{end}}sshkey="{{.SSHKey}}"
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`

func ipxeBootScriptServer(w http.ResponseWriter, r *http.Request) {
	v := r.URL.Query()
	version := v.Get("version")
	if version == "" {
		version = "latest"
	}
	state := v.Get("state")

	t, err := template.New("ipxebootscript").Parse(ipxeBootScript)
	if err != nil {
		http.Error(w, "cannot generate ipxe boot script", 500)
		return
	}

	data := map[string]string{
		"BaseUrl": baseUrl,
		"SSHKey":  sshKey,
		"State":   state,
		"Version": version,
	}

	err = t.Execute(w, data)
	if err != nil {
		http.Error(w, "cannot generate ipxe boot script", 500)
		return
	}
	return
}

func sshKeyFromFile(filename string) (string, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", err
	}
	return string(bytes.TrimSpace(b)), nil
}

func main() {
	var err error

	// Set the base directory where the coreos directory containing
	// the ssh public key, kernal and boot images.
	baseDir := os.Getenv("COREOS_IPXE_SERVER_BASE_DIR")
	if baseDir == "" {
		log.Fatal("COREOS_IPXE_SERVER_BASE_DIR must be set and non-empty")
	}

	// Set the base URL used by the iPXE boot script.
	baseUrl = os.Getenv("COREOS_IPXE_SERVER_BASE_URL")
	if baseUrl == "" {
		log.Fatal("COREOS_IPXE_SERVER_BASE_URL must be set and non-empty")
	}

	// Set the host:port to listen for HTTP requests.
	listenHost := os.Getenv("COREOS_IPXE_SERVER_LISTEN_HOST")
	listenPort := os.Getenv("COREOS_IPXE_SERVER_LISTEN_PORT")
	if listenPort == "" {
		log.Fatal("COREOS_IPXE_SERVER_LISTEN_PORT must be set and non-empty")
	}
	hostPort := net.JoinHostPort(listenHost, listenPort)

	// The ssh public must exist as $baseDir/coreos/coreos.pub
	sshKeyPath := filepath.Join(baseDir, "coreos/coreos.pub")
	sshKey, err = sshKeyFromFile(sshKeyPath)
	if err != nil {
		log.Fatal("error reading ssh public key from " + sshKeyPath)
	}

	http.HandleFunc("/", ipxeBootScriptServer)

	// Serve kernel and pxe boot images
	staticFilePath := filepath.Join(baseDir, "coreos")
	http.Handle("/coreos/", http.StripPrefix("/coreos/", http.FileServer(http.Dir(staticFilePath))))
	log.Fatal(http.ListenAndServe(hostPort, nil))
}
<|endoftext|>


<commit_before>package controllers

import (
	m "devices-server/app/models"
	"github.com/revel/revel"
)

type Devices struct {
	GormController
}

/*
	Deviceを作成
 	@param name:機種名
 	@param manufacturer:メーカー
 	@param carrier:キャリア
 	@param os:OS
 	@param size:サイズ
 	@param resolution:解像度
 	@param memory:メモリ
 	@param dateOfRelease:発売日
 	@param other:その他
 	return data{sucess, device}
*/
func (c Devices) Create(name string,
	manufacturer string,
	carrier string,
	os string,
	size string,
	resolution string,
	memory string,
	dateOfRelease int64,
	other string) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices, "name = ?", name)
	if len(devices) == 0 {
		device := m.Device{
			Name:          name,
			Manufacturer:  manufacturer,
			Carrier:       carrier,
			Os:            os,
			Size:          size,
			Resolution:    resolution,
			Memory:        memory,
			DateOfRelease: dateOfRelease,
			Other:         other,
		}
		c.Txn.NewRecord(device)
		c.Txn.Create(&device)
		data.Device = device
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceを更新
 	@param device_id:ID
 	@param name:機種名
 	@param manufacturer:メーカー
 	@param carrier:キャリア
 	@param os:OS
 	@param size:サイズ
 	@param resolution:解像度
 	@param memory:メモリ
 	@param dateOfRelease:発売日
 	@param other:その他
 	return data{sucess, device}
*/
func (c Devices) Update(device_id int64,
	name string,
	manufacturer string,
	carrier string,
	os string,
	size string,
	resolution string,
	memory string,
	dateOfRelease int64,
	other string) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices, "id = ?", device_id)
	if len(devices) != 0 {
		device := devices[0]
		device.Name = name
		device.Manufacturer = manufacturer
		device.Carrier = carrier
		device.Os = os
		device.Size = size
		device.Resolution = resolution
		device.Memory = memory
		device.DateOfRelease = dateOfRelease
		device.Other = other
		c.Txn.Save(&device)
		data.Device = device
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceのリストを取得
 	return data{sucess, devices}
*/
func (c Devices) List() revel.Result {
	data := struct {
		Success bool       `json:"success"`
		Devices []m.Device `json:"devices"`
	}{
		Success: false,
		Devices: []m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices)
	if len(devices) != 0 {
		for i := 0; i < len(devices); i++ {
			device := devices[i]
			device = m.FindUser(c.Txn, device)
			device = m.FindDeviceStates(c.Txn, device)
			devices[i] = device
		}
		data.Devices = devices
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceを特定のユーザーに貸し出す
	@param userId:ユーザ-ID
 	@param deviceId:端末ID
 	return data{sucess, device}
*/
func (c Devices) Borrow(user_id int64, device_id int64) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var users []m.User
	c.Txn.Find(&users, "id = ?", user_id)
	if len(users) != 0 {
		var devices []m.Device
		c.Txn.Find(&devices, "id = ?", device_id)
		if len(devices) != 0 {
			device := devices[0]
			user := users[0]
			device.UserId = user.Id
			device.User = user
			device.DeviceStates = c.FindAfterCreateDeviceState(user, device, true)
			c.Txn.Save(&device)

			data.Device = device
			data.Success = true
		}
	}
	return c.RenderJson(data)
}

/*
	ユーザーがDeviceを返却する
	@param userId:ユーザ-ID
 	@param deviceId:端末ID
 	return data{sucess, device}
*/
func (c Devices) Return(user_id int64, device_id int64) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var users []m.User
	c.Txn.Find(&users, "id = ?", user_id)
	if len(users) != 0 {
		var devices []m.Device
		c.Txn.Find(&devices, "id = ?", device_id)
		if len(devices) != 0 {
			device := devices[0]
			user := users[0]
			device.UserId = user.Id
			device.User = user
			device.DeviceStates = c.FindAfterCreateDeviceState(user, device, false)
			c.Txn.Save(&device)

			data.Device = device
			data.Success = true
		}
	}
	return c.RenderJson(data)
}

/*
	履歴を追加する
	@param deviceStates:端末の貸し出し履歴
 	@param user:ユーザ-
 	@param device_id:端末ID
 	return deviceStates
*/
func (c Devices) FindAfterCreateDeviceState(user m.User, device m.Device, action bool) []m.DeviceState {
	deviceState := m.DeviceState{
		Action:   action,
		DeviceId: device.Id,
		UserId:   user.Id,
	}
	c.Txn.NewRecord(deviceState)
	c.Txn.Create(&deviceState)

	var device_states []m.DeviceState
	c.Txn.Model(&device).Related(&device_states)

	for i := 0; i < len(device_states); i++ {
		device_state := device_states[i]
		var user m.User
		c.Txt.Model(&device_state).Related(&user)
		device_state.User = user
		device_states[i] = device_state
	}

	return device_states
}
<commit_msg>Modify name<commit_after>package controllers

import (
	m "devices-server/app/models"
	"github.com/revel/revel"
)

type Devices struct {
	GormController
}

/*
	Deviceを作成
 	@param name:機種名
 	@param manufacturer:メーカー
 	@param carrier:キャリア
 	@param os:OS
 	@param size:サイズ
 	@param resolution:解像度
 	@param memory:メモリ
 	@param dateOfRelease:発売日
 	@param other:その他
 	return data{sucess, device}
*/
func (c Devices) Create(name string,
	manufacturer string,
	carrier string,
	os string,
	size string,
	resolution string,
	memory string,
	dateOfRelease int64,
	other string) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices, "name = ?", name)
	if len(devices) == 0 {
		device := m.Device{
			Name:          name,
			Manufacturer:  manufacturer,
			Carrier:       carrier,
			Os:            os,
			Size:          size,
			Resolution:    resolution,
			Memory:        memory,
			DateOfRelease: dateOfRelease,
			Other:         other,
		}
		c.Txn.NewRecord(device)
		c.Txn.Create(&device)
		data.Device = device
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceを更新
 	@param device_id:ID
 	@param name:機種名
 	@param manufacturer:メーカー
 	@param carrier:キャリア
 	@param os:OS
 	@param size:サイズ
 	@param resolution:解像度
 	@param memory:メモリ
 	@param dateOfRelease:発売日
 	@param other:その他
 	return data{sucess, device}
*/
func (c Devices) Update(device_id int64,
	name string,
	manufacturer string,
	carrier string,
	os string,
	size string,
	resolution string,
	memory string,
	dateOfRelease int64,
	other string) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices, "id = ?", device_id)
	if len(devices) != 0 {
		device := devices[0]
		device.Name = name
		device.Manufacturer = manufacturer
		device.Carrier = carrier
		device.Os = os
		device.Size = size
		device.Resolution = resolution
		device.Memory = memory
		device.DateOfRelease = dateOfRelease
		device.Other = other
		c.Txn.Save(&device)
		data.Device = device
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceのリストを取得
 	return data{sucess, devices}
*/
func (c Devices) List() revel.Result {
	data := struct {
		Success bool       `json:"success"`
		Devices []m.Device `json:"devices"`
	}{
		Success: false,
		Devices: []m.Device{},
	}

	var devices []m.Device
	c.Txn.Find(&devices)
	if len(devices) != 0 {
		for i := 0; i < len(devices); i++ {
			device := devices[i]
			device = m.FindUser(c.Txn, device)
			device = m.FindDeviceStates(c.Txn, device)
			devices[i] = device
		}
		data.Devices = devices
		data.Success = true
	}
	return c.RenderJson(data)
}

/*
	Deviceを特定のユーザーに貸し出す
	@param userId:ユーザ-ID
 	@param deviceId:端末ID
 	return data{sucess, device}
*/
func (c Devices) Borrow(user_id int64, device_id int64) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var users []m.User
	c.Txn.Find(&users, "id = ?", user_id)
	if len(users) != 0 {
		var devices []m.Device
		c.Txn.Find(&devices, "id = ?", device_id)
		if len(devices) != 0 {
			device := devices[0]
			user := users[0]
			device.UserId = user.Id
			device.User = user
			device.DeviceStates = c.FindAfterCreateDeviceState(user, device, true)
			c.Txn.Save(&device)

			data.Device = device
			data.Success = true
		}
	}
	return c.RenderJson(data)
}

/*
	ユーザーがDeviceを返却する
	@param userId:ユーザ-ID
 	@param deviceId:端末ID
 	return data{sucess, device}
*/
func (c Devices) Return(user_id int64, device_id int64) revel.Result {
	data := struct {
		Success bool     `json:"success"`
		Device  m.Device `json:"device"`
	}{
		Success: false,
		Device:  m.Device{},
	}

	var users []m.User
	c.Txn.Find(&users, "id = ?", user_id)
	if len(users) != 0 {
		var devices []m.Device
		c.Txn.Find(&devices, "id = ?", device_id)
		if len(devices) != 0 {
			device := devices[0]
			user := users[0]
			device.UserId = user.Id
			device.User = user
			device.DeviceStates = c.FindAfterCreateDeviceState(user, device, false)
			c.Txn.Save(&device)

			data.Device = device
			data.Success = true
		}
	}
	return c.RenderJson(data)
}

/*
	履歴を追加する
	@param deviceStates:端末の貸し出し履歴
 	@param user:ユーザ-
 	@param device_id:端末ID
 	return deviceStates
*/
func (c Devices) FindAfterCreateDeviceState(user m.User, device m.Device, action bool) []m.DeviceState {
	deviceState := m.DeviceState{
		Action:   action,
		DeviceId: device.Id,
		UserId:   user.Id,
	}
	c.Txn.NewRecord(deviceState)
	c.Txn.Create(&deviceState)

	var device_states []m.DeviceState
	c.Txn.Model(&device).Related(&device_states)

	for i := 0; i < len(device_states); i++ {
		device_state := device_states[i]
		var user m.User
		c.Txn.Model(&device_state).Related(&user)
		device_state.User = user
		device_states[i] = device_state
	}

	return device_states
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 The SurgeMQ 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.

package service

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"
	"sync/atomic"
	"time"
)

var (
	bufcnt            int64
	DefaultBufferSize int64

	DeviceInBufferSize  int64
	DeviceOutBufferSize int64

	MasterInBufferSize  int64
	MasterOutBufferSize int64
)

type sequence struct {
	// The current position of the producer or consumer
	cursor,

	// The previous known position of the consumer (if producer) or producer (if consumer)
	gate,

	// These are fillers to pad the cache line, which is generally 64 bytes
	p2, p3, p4, p5, p6, p7 int64
}

func newSequence() *sequence {
	return &sequence{}
}

func (this *sequence) get() int64 {
	return atomic.LoadInt64(&this.cursor)
}

func (this *sequence) set(seq int64) {
	atomic.StoreInt64(&this.cursor, seq)
}

type buffer struct {
	id int64

	readIndex  int64 //读序号
	writeIndex int64 //写序号
	buf        []*[]byte

	size int64
	mask int64

	done int64

	pcond *sync.Cond
	ccond *sync.Cond

	b []byte //readfrom中的临时数组，为反复使用不必创建新数组
}

func newBuffer(size int64) (*buffer, error) {
	if size < 0 {
		return nil, bufio.ErrNegativeCount
	}

	if size == 0 {
		size = DefaultBufferSize
	}

	if !powerOfTwo64(size) {
		fmt.Printf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
		return nil, fmt.Errorf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
	}

	return &buffer{
		id:         atomic.AddInt64(&bufcnt, 1),
		readIndex:  int64(0),
		writeIndex: int64(0),
		buf:        make([]*[]byte, size),
		size:       size,
		mask:       size - 1,
		pcond:      sync.NewCond(new(sync.Mutex)),
		ccond:      sync.NewCond(new(sync.Mutex)),
		b:          make([]byte, 5),
	}, nil
}

/**
获取当前读序号
*/
func (this *buffer) GetCurrentReadIndex() int64 {
	return atomic.LoadInt64(&this.readIndex)
}

/**
获取当前写序号
*/
func (this *buffer) GetCurrentWriteIndex() int64 {
	return atomic.LoadInt64(&this.writeIndex)
}

func (this *buffer) ID() int64 {
	return this.id
}

func (this *buffer) Close() error {
	atomic.StoreInt64(&this.done, 1)

	this.pcond.L.Lock()
	//this.ccond.Signal()
	//this.ccond.Broadcast()
	this.pcond.L.Unlock()

	this.ccond.L.Lock()
	//this.pcond.Signal()
	//this.pcond.Broadcast()
	this.ccond.L.Unlock()

	return nil
}

/**
读取ringbuffer指定的buffer指针，返回该指针并清空ringbuffer该位置存在的指针内容，以及将读序号加1
*/
func (this *buffer) ReadBuffer() (p *[]byte, ok bool) {
	/*this.ccond.L.Lock()
	defer func() {
		//this.pcond.Signal()
		//this.pcond.Broadcast()
		this.ccond.L.Unlock()
		//time.Sleep(3 * time.Millisecond)
	}()*/
	ok = false
	p = nil
	readIndex := this.GetCurrentReadIndex()
	writeIndex := this.GetCurrentWriteIndex()
	for {
		if this.isDone() {
			return nil, false
		}
		writeIndex = this.GetCurrentWriteIndex()
		if readIndex >= writeIndex {
			//this.pcond.Signal()
			//this.pcond.Broadcast()
			//this.ccond.Wait()
			//runtime.Gosched()
			time.Sleep(5 * time.Millisecond)
		} else {
			break
		}
		//time.Sleep(500 * time.Microsecond)
		//time.Sleep(1 * time.Millisecond)
	}
	index := readIndex & this.mask //替代求模
	this.ccond.L.Lock()
	p = this.buf[index]
	this.buf[index] = nil
	this.ccond.L.Unlock()
	atomic.AddInt64(&this.readIndex, int64(1))
	if p != nil {
		ok = true
	}
	return p, ok
}

/**
写入ringbuffer指针，以及将写序号加1
*/
func (this *buffer) WriteBuffer(in *[]byte) (ok bool) {
	/*this.pcond.L.Lock()
	defer func() {
		//this.ccond.Signal()
		//this.ccond.Broadcast()
		this.pcond.L.Unlock()
		//time.Sleep(3 * time.Millisecond)
	}()*/
	ok = false
	readIndex := this.GetCurrentReadIndex()
	writeIndex := this.GetCurrentWriteIndex()
	for {
		if this.isDone() {
			return false
		}
		readIndex = this.GetCurrentReadIndex()
		if writeIndex >= readIndex && writeIndex-readIndex >= this.size {
			//this.ccond.Signal()
			//this.ccond.Broadcast()
			//this.pcond.Wait()
			//time.Sleep(1 * time.Millisecond)
			//runtime.Gosched()
			time.Sleep(5 * time.Millisecond)
		} else {
			break
		}
		//time.Sleep(500 * time.Microsecond)
		//time.Sleep(1 * time.Millisecond)
	}
	index := writeIndex & this.mask //替代求模
	this.pcond.L.Lock()
	this.buf[index] = in
	this.pcond.L.Unlock()
	atomic.AddInt64(&this.writeIndex, int64(1))
	ok = true
	return ok
}

/**
修改 尽量减少数据的创建
*/
func (this *buffer) ReadFrom(r io.Reader) (int64, error) {
	defer this.Close()

	total := int64(0)

	for {
		time.Sleep(5 * time.Millisecond)
		if this.isDone() {
			return total, io.EOF
		}

		var write_bytes []byte

		//b := make([]byte, 5)
		n, err := r.Read(this.b[0:1])
		if err != nil {
			return total, io.EOF
		}
		total += int64(n)
		max_cnt := 1
		for {
			if this.isDone() {
				return total, io.EOF
			}
			// If we have read 5 bytes and still not done, then there's a problem.
			if max_cnt > 4 {
				return 0, fmt.Errorf("sendrecv/peekMessageSize: 4th byte of remaining length has continuation bit set")
			}
			_, err := r.Read(this.b[max_cnt:(max_cnt + 1)])

			//fmt.Println(b)
			if err != nil {
				return total, err
			}
			if this.b[max_cnt] >= 0x80 {
				max_cnt++
			} else {
				break
			}
		}
		remlen, m := binary.Uvarint(this.b[1 : max_cnt+1])
		remlen_tmp := int64(remlen)
		start_ := int64(1) + int64(m)
		total_tmp := remlen_tmp + start_

		write_bytes = make([]byte, total_tmp)
		copy(write_bytes[0:m+1], this.b[0:m+1])
		nlen := int64(0)
		times := 0
		cnt_ := int64(32)
		for nlen < remlen_tmp {
			if this.isDone() {
				return total, io.EOF
			}
			if times > 100 {
				return total, io.EOF
			} else {
				times = 0
			}
			times++
			tmpm := remlen_tmp - nlen

			b_ := write_bytes[(start_ + nlen):]
			if tmpm > cnt_ {
				b_ = write_bytes[(start_ + nlen):(start_ + nlen + cnt_)]
			}

			//b_ := make([]byte, remlen)
			n, err = r.Read(b_[0:])

			if err != nil {
				/*Log.Errorc(func() string {
					return fmt.Sprintf("从conn读取数据失败(%s)(0)", err)
				})
				time.Sleep(5 * time.Millisecond)
				continue*/
				return total, err
			}
			//write_bytes = append(write_bytes, b_[0:]...)
			nlen += int64(n)
			total += int64(n)
		}

		ok := this.WriteBuffer(&write_bytes)

		if !ok {
			return total, errors.New("write ringbuffer failed")
		}
	}
}

func (this *buffer) WriteTo(w io.Writer) (int64, error) {
	defer this.Close()

	total := int64(0)

	for {
		if this.isDone() {
			return total, io.EOF
		}

		p, ok := this.ReadBuffer()
		if !ok {
			return total, errors.New("read buffer failed")
		}
		// There's some data, let's process it first
		if len(*p) > 0 {
			n, err := w.Write(*p)
			total += int64(n)
			//Log.Debugc(func() string{ return fmt.Sprintf("Wrote %d bytes, totaling %d bytes", n, total)})

			if err != nil {
				return total, err
			}
		}

	}
}

func (this *buffer) isDone() bool {
	if atomic.LoadInt64(&this.done) == 1 {
		return true
	}

	return false
}

func ringCopy(dst, src []byte, start int64) int {
	n := len(src)

	i, l := 0, 0

	for n > 0 {
		l = copy(dst[start:], src[i:])
		i += l
		n -= l

		if n > 0 {
			start = 0
		}
	}

	return i
}

func powerOfTwo64(n int64) bool {
	return n != 0 && (n&(n-1)) == 0
}

func roundUpPowerOfTwo64(n int64) int64 {
	n--
	n |= n >> 1
	n |= n >> 2
	n |= n >> 4
	n |= n >> 8
	n |= n >> 16
	n |= n >> 32
	n++

	return n
}
<commit_msg>修改 buffer.go process.go sendrecv.go xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 读写时修改锁定方式;readfrom休眠增加到10毫秒<commit_after>// Copyright (c) 2014 The SurgeMQ 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.

package service

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"
	"sync/atomic"
	"time"
)

var (
	bufcnt            int64
	DefaultBufferSize int64

	DeviceInBufferSize  int64
	DeviceOutBufferSize int64

	MasterInBufferSize  int64
	MasterOutBufferSize int64
)

type sequence struct {
	// The current position of the producer or consumer
	cursor,

	// The previous known position of the consumer (if producer) or producer (if consumer)
	gate,

	// These are fillers to pad the cache line, which is generally 64 bytes
	p2, p3, p4, p5, p6, p7 int64
}

func newSequence() *sequence {
	return &sequence{}
}

func (this *sequence) get() int64 {
	return atomic.LoadInt64(&this.cursor)
}

func (this *sequence) set(seq int64) {
	atomic.StoreInt64(&this.cursor, seq)
}

type buffer struct {
	id int64

	readIndex  int64 //读序号
	writeIndex int64 //写序号
	buf        []*[]byte

	size int64
	mask int64

	done int64

	pcond *sync.Cond
	ccond *sync.Cond

	b []byte //readfrom中的临时数组，为反复使用不必创建新数组
}

func newBuffer(size int64) (*buffer, error) {
	if size < 0 {
		return nil, bufio.ErrNegativeCount
	}

	if size == 0 {
		size = DefaultBufferSize
	}

	if !powerOfTwo64(size) {
		fmt.Printf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
		return nil, fmt.Errorf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
	}

	return &buffer{
		id:         atomic.AddInt64(&bufcnt, 1),
		readIndex:  int64(0),
		writeIndex: int64(0),
		buf:        make([]*[]byte, size),
		size:       size,
		mask:       size - 1,
		pcond:      sync.NewCond(new(sync.Mutex)),
		ccond:      sync.NewCond(new(sync.Mutex)),
		b:          make([]byte, 5),
	}, nil
}

/**
获取当前读序号
*/
func (this *buffer) GetCurrentReadIndex() int64 {
	return atomic.LoadInt64(&this.readIndex)
}

/**
获取当前写序号
*/
func (this *buffer) GetCurrentWriteIndex() int64 {
	return atomic.LoadInt64(&this.writeIndex)
}

func (this *buffer) ID() int64 {
	return this.id
}

func (this *buffer) Close() error {
	atomic.StoreInt64(&this.done, 1)

	this.pcond.L.Lock()
	this.ccond.Signal()
	//this.ccond.Broadcast()
	this.pcond.L.Unlock()

	this.ccond.L.Lock()
	this.pcond.Signal()
	//this.pcond.Broadcast()
	this.ccond.L.Unlock()

	return nil
}

/**
读取ringbuffer指定的buffer指针，返回该指针并清空ringbuffer该位置存在的指针内容，以及将读序号加1
*/
func (this *buffer) ReadBuffer() (p *[]byte, ok bool) {
	/*this.ccond.L.Lock()
	defer func() {
		//this.pcond.Signal()
		//this.pcond.Broadcast()
		this.ccond.L.Unlock()
		//time.Sleep(3 * time.Millisecond)
	}()*/
	ok = false
	p = nil
	readIndex := this.GetCurrentReadIndex()
	writeIndex := this.GetCurrentWriteIndex()
	for {
		if this.isDone() {
			return nil, false
		}
		writeIndex = this.GetCurrentWriteIndex()
		if readIndex >= writeIndex {
			this.ccond.L.Lock()
			this.pcond.Signal()
			//this.pcond.Broadcast()
			this.ccond.Wait()
			this.ccond.L.Unlock()
			//runtime.Gosched()
			//time.Sleep(5 * time.Millisecond)
		} else {
			break
		}
		//time.Sleep(500 * time.Microsecond)
		//time.Sleep(1 * time.Millisecond)
	}
	index := readIndex & this.mask //替代求模

	p = this.buf[index]
	this.buf[index] = nil

	atomic.AddInt64(&this.readIndex, int64(1))
	if p != nil {
		ok = true
	}
	return p, ok
}

/**
写入ringbuffer指针，以及将写序号加1
*/
func (this *buffer) WriteBuffer(in *[]byte) (ok bool) {
	/*this.pcond.L.Lock()
	defer func() {
		//this.ccond.Signal()
		//this.ccond.Broadcast()
		this.pcond.L.Unlock()
		//time.Sleep(3 * time.Millisecond)
	}()*/
	ok = false
	readIndex := this.GetCurrentReadIndex()
	writeIndex := this.GetCurrentWriteIndex()
	for {
		if this.isDone() {
			return false
		}
		readIndex = this.GetCurrentReadIndex()
		if writeIndex >= readIndex && writeIndex-readIndex >= this.size {
			this.pcond.L.Lock()
			this.ccond.Signal()
			//this.ccond.Broadcast()
			this.pcond.Wait()
			this.pcond.L.Unlock()
			//time.Sleep(1 * time.Millisecond)
			//runtime.Gosched()
			//time.Sleep(5 * time.Millisecond)
		} else {
			break
		}
		//time.Sleep(500 * time.Microsecond)
		//time.Sleep(1 * time.Millisecond)
	}
	index := writeIndex & this.mask //替代求模

	this.buf[index] = in

	atomic.AddInt64(&this.writeIndex, int64(1))
	ok = true
	return ok
}

/**
修改 尽量减少数据的创建
*/
func (this *buffer) ReadFrom(r io.Reader) (int64, error) {
	defer this.Close()

	total := int64(0)

	for {
		time.Sleep(10 * time.Millisecond)
		if this.isDone() {
			return total, io.EOF
		}

		var write_bytes []byte

		//b := make([]byte, 5)
		n, err := r.Read(this.b[0:1])
		if err != nil {
			return total, io.EOF
		}
		total += int64(n)
		max_cnt := 1
		for {
			if this.isDone() {
				return total, io.EOF
			}
			// If we have read 5 bytes and still not done, then there's a problem.
			if max_cnt > 4 {
				return 0, fmt.Errorf("sendrecv/peekMessageSize: 4th byte of remaining length has continuation bit set")
			}
			_, err := r.Read(this.b[max_cnt:(max_cnt + 1)])

			//fmt.Println(b)
			if err != nil {
				return total, err
			}
			if this.b[max_cnt] >= 0x80 {
				max_cnt++
			} else {
				break
			}
		}
		remlen, m := binary.Uvarint(this.b[1 : max_cnt+1])
		remlen_tmp := int64(remlen)
		start_ := int64(1) + int64(m)
		total_tmp := remlen_tmp + start_

		write_bytes = make([]byte, total_tmp)
		copy(write_bytes[0:m+1], this.b[0:m+1])
		nlen := int64(0)
		times := 0
		cnt_ := int64(32)
		for nlen < remlen_tmp {
			if this.isDone() {
				return total, io.EOF
			}
			if times > 100 {
				return total, io.EOF
			} else {
				times = 0
			}
			times++
			tmpm := remlen_tmp - nlen

			b_ := write_bytes[(start_ + nlen):]
			if tmpm > cnt_ {
				b_ = write_bytes[(start_ + nlen):(start_ + nlen + cnt_)]
			}

			//b_ := make([]byte, remlen)
			n, err = r.Read(b_[0:])

			if err != nil {
				/*Log.Errorc(func() string {
					return fmt.Sprintf("从conn读取数据失败(%s)(0)", err)
				})
				time.Sleep(5 * time.Millisecond)
				continue*/
				return total, err
			}
			//write_bytes = append(write_bytes, b_[0:]...)
			nlen += int64(n)
			total += int64(n)
		}

		ok := this.WriteBuffer(&write_bytes)

		if !ok {
			return total, errors.New("write ringbuffer failed")
		}
	}
}

func (this *buffer) WriteTo(w io.Writer) (int64, error) {
	defer this.Close()

	total := int64(0)

	for {
		if this.isDone() {
			return total, io.EOF
		}

		p, ok := this.ReadBuffer()
		if !ok {
			return total, errors.New("read buffer failed")
		}
		// There's some data, let's process it first
		if len(*p) > 0 {
			n, err := w.Write(*p)
			total += int64(n)
			//Log.Debugc(func() string{ return fmt.Sprintf("Wrote %d bytes, totaling %d bytes", n, total)})

			if err != nil {
				return total, err
			}
		}

	}
}

func (this *buffer) isDone() bool {
	if atomic.LoadInt64(&this.done) == 1 {
		return true
	}

	return false
}

func ringCopy(dst, src []byte, start int64) int {
	n := len(src)

	i, l := 0, 0

	for n > 0 {
		l = copy(dst[start:], src[i:])
		i += l
		n -= l

		if n > 0 {
			start = 0
		}
	}

	return i
}

func powerOfTwo64(n int64) bool {
	return n != 0 && (n&(n-1)) == 0
}

func roundUpPowerOfTwo64(n int64) int64 {
	n--
	n |= n >> 1
	n |= n >> 2
	n |= n >> 4
	n |= n >> 8
	n |= n >> 16
	n |= n >> 32
	n++

	return n
}
<|endoftext|>


<commit_before>package user

import (
	jwt "github.com/dgrijalva/jwt-go"
	"golang.org/x/crypto/bcrypt"
	"regexp"
	"strings"
	"time"

	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

const (
	// jwt claim keys
	jwt_claim_issuer    = "iss"
	jwt_claim_issued    = "iat"
	jwt_claim_notbefore = "nbf"
	jwt_claim_expire    = "exp"
	jwt_claim_user_id   = "user_id"
	// jwt issuer
	jwt_issuer = "pram"
	// jwt expire days
	jwt_expire_days = 90

	// the username validation regex
	username = `^([a-zA-Z0-9]+[\s_-]?)+$`
)

var regexUsername = regexp.MustCompile(username)

// reserved name list
var reservedNameList = map[string]bool{
	"admin":          true,
	"administrator":  true,
	"administration": true,
	"support":        true,
	"mod":            true,
	"moderator":      true,
	"anon":           true,
	"anonymous":      true,
	"root":           true,
	"webmaster":      true,
	"username":       true,
	"user":           true,
}

type Authenticator interface {
	IsValid() bool
	IsAuthorized(ib uint) bool
	SetId(uid uint)
	SetAuthenticated()
	Password() (err error)
	ComparePassword(password string) bool
	FromName(name string) (err error)
	CreateToken() (newtoken string, err error)
}

// user struct
type User struct {
	Id              uint
	Name            string
	IsAuthenticated bool
	hash            []byte
	isPasswordValid bool
}

var _ = Authenticator(&User{})

// create a user struct
func DefaultUser() User {
	return User{
		Id:              1,
		IsAuthenticated: false,
	}
}

// sets the user id
func (u *User) SetId(uid uint) {
	u.Id = uid
	return
}

// sets authenticated
func (u *User) SetAuthenticated() {
	// do not set auth for the wrong users
	if u.Id == 0 || u.Id == 1 {
		return
	}

	u.IsAuthenticated = true
	return
}

// check user struct validity
func (u *User) IsValid() bool {

	// this isnt a real user id
	if u.Id == 0 {
		return false
	}

	// the anon account can never be authenticated
	if u.Id == 1 && u.IsAuthenticated {
		return false
	}

	// a user can never be unauthenticated
	if u.Id != 1 && !u.IsAuthenticated {
		return false
	}

	return true
}

// checks if the name is valid
func IsValidName(name string) bool {

	if reservedNameList[strings.ToLower(strings.TrimSpace(name))] {
		return false
	}

	return regexUsername.MatchString(name)
}

// will get the password and name from the database for an instantiated user
func (u *User) Password() (err error) {

	// check user struct validity
	if !u.IsValid() {
		return e.ErrUserNotValid
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get hashed password from database
	err = dbase.QueryRow("select user_name, user_password from users where user_id = ?", u.Id).Scan(&u.Name, &u.hash)
	if err != nil {
		return
	}

	return
}

// will get the password and user id from the database for a user name
func (u *User) FromName(name string) (err error) {

	// password length cant be 0
	if len(name) == 0 {
		return e.ErrUserNotValid
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get hashed password from database
	err = dbase.QueryRow("select user_id, user_password from users where user_name = ?", name).Scan(&u.Id, &u.hash)
	if err != nil {
		return
	}

	u.SetAuthenticated()

	if !u.IsValid() {
		return e.ErrUserNotValid
	}

	return

}

// check for duplicate name before registering
func CheckDuplicate(name string) (check bool) {

	// password length cant be 0
	if len(name) == 0 {
		return true
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return true
	}

	// this will return true if there is a user
	err = dbase.QueryRow("select count(*) from users where user_name = ?", name).Scan(&check)
	if err != nil {
		return true
	}

	return

}

// Creates a JWT token with our claims
func (u *User) CreateToken() (newtoken string, err error) {

	// error if theres no secret set
	if Secret == "" {
		err = e.ErrNoSecret
		return
	}

	// check user struct validity
	if !u.IsValid() {
		err = e.ErrUserNotValid
		return
	}

	// a token should never be created
	if u.Id == 0 || u.Id == 1 {
		err = e.ErrUserNotValid
		return
	}

	// a token should never be created
	if !u.IsAuthenticated {
		err = e.ErrUserNotValid
		return
	}

	// check if password was valid
	if !u.isPasswordValid {
		err = e.ErrInvalidPassword
		return
	}

	// Create the token
	token := jwt.New(jwt.SigningMethodHS256)
	// the current time
	now := time.Now()

	// Set our claims
	token.Claims[jwt_claim_issuer] = jwt_issuer
	token.Claims[jwt_claim_issued] = now.Unix()
	token.Claims[jwt_claim_notbefore] = now.Unix()
	token.Claims[jwt_claim_expire] = now.Add(time.Hour * 24 * jwt_expire_days).Unix()
	token.Claims[jwt_claim_user_id] = u.Id

	// Sign and get the complete encoded token as a string
	newtoken, err = token.SignedString([]byte(Secret))
	if err != nil {
		return
	}

	return

}

// get the user info from id
func (u *User) IsAuthorized(ib uint) bool {

	var err error

	if !u.IsValid() {
		return false
	}

	// check for invalid stuff
	if ib == 0 {
		return false
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return false
	}

	// holds our role
	var role uint

	// get data from users table
	err = dbase.QueryRow(`SELECT COALESCE((SELECT MAX(role_id) FROM user_ib_role_map WHERE user_ib_role_map.user_id = users.user_id AND ib_id = ?),user_role_map.role_id) as role
    FROM users
    INNER JOIN user_role_map ON (user_role_map.user_id = users.user_id)
    WHERE users.user_id = ?`, ib, u.Id).Scan(&role)
	if err != nil {
		return false
	}

	switch role {
	case 3:
		return true
	case 4:
		return true
	default:
		return false
	}

	return false

}

// compare password to
func (u *User) ComparePassword(password string) bool {

	// password length cant be 0
	if len(password) == 0 {
		return false
	}

	// if the hash wasnt populated
	if len(u.hash) == 0 {
		return false
	}

	// compare the stored hash with the provided password
	err := bcrypt.CompareHashAndPassword(u.hash, []byte(password))

	// we only want jwt tokens to be created after a valid password has been given
	u.isPasswordValid = err == nil

	return u.isPasswordValid

}

// hash a given password
func HashPassword(password string) (hash []byte, err error) {

	// password length cant be 0
	if len(password) == 0 {
		err = e.ErrInvalidPassword
		return
	}

	return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
}
<commit_msg>add more lengths checking<commit_after>package user

import (
	jwt "github.com/dgrijalva/jwt-go"
	"golang.org/x/crypto/bcrypt"
	"regexp"
	"strings"
	"time"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

const (
	// jwt claim keys
	jwt_claim_issuer    = "iss"
	jwt_claim_issued    = "iat"
	jwt_claim_notbefore = "nbf"
	jwt_claim_expire    = "exp"
	jwt_claim_user_id   = "user_id"
	// jwt issuer
	jwt_issuer = "pram"
	// jwt expire days
	jwt_expire_days = 90

	// the username validation regex
	username = `^([a-zA-Z0-9]+[\s_-]?)+$`
)

var regexUsername = regexp.MustCompile(username)

// reserved name list
var reservedNameList = map[string]bool{
	"admin":          true,
	"administrator":  true,
	"administration": true,
	"support":        true,
	"mod":            true,
	"moderator":      true,
	"anon":           true,
	"anonymous":      true,
	"root":           true,
	"webmaster":      true,
	"username":       true,
	"user":           true,
}

type Authenticator interface {
	IsValid() bool
	IsAuthorized(ib uint) bool
	SetId(uid uint)
	SetAuthenticated()
	Password() (err error)
	ComparePassword(password string) bool
	FromName(name string) (err error)
	CreateToken() (newtoken string, err error)
}

// user struct
type User struct {
	Id              uint
	Name            string
	IsAuthenticated bool
	hash            []byte
	isPasswordValid bool
}

var _ = Authenticator(&User{})

// create a user struct
func DefaultUser() User {
	return User{
		Id:              1,
		IsAuthenticated: false,
	}
}

// sets the user id
func (u *User) SetId(uid uint) {
	u.Id = uid
	return
}

// sets authenticated
func (u *User) SetAuthenticated() {
	// do not set auth for the wrong users
	if u.Id == 0 || u.Id == 1 {
		return
	}

	u.IsAuthenticated = true
	return
}

// check user struct validity
func (u *User) IsValid() bool {

	// this isnt a real user id
	if u.Id == 0 {
		return false
	}

	// the anon account can never be authenticated
	if u.Id == 1 && u.IsAuthenticated {
		return false
	}

	// a user can never be unauthenticated
	if u.Id != 1 && !u.IsAuthenticated {
		return false
	}

	return true
}

// checks if the name is valid
func IsValidName(name string) bool {

	if reservedNameList[strings.ToLower(strings.TrimSpace(name))] {
		return false
	}

	return regexUsername.MatchString(name)
}

// will get the password and name from the database for an instantiated user
func (u *User) Password() (err error) {

	// check user struct validity
	if !u.IsValid() {
		return e.ErrUserNotValid
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get hashed password from database
	err = dbase.QueryRow("select user_name, user_password from users where user_id = ?", u.Id).Scan(&u.Name, &u.hash)
	if err != nil {
		return
	}

	return
}

// will get the password and user id from the database for a user name
func (u *User) FromName(name string) (err error) {

	// password length cant be 0
	if len(name) == 0 {
		return e.ErrUserNotValid
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get hashed password from database
	err = dbase.QueryRow("select user_id, user_password from users where user_name = ?", name).Scan(&u.Id, &u.hash)
	if err != nil {
		return
	}

	u.SetAuthenticated()

	if !u.IsValid() {
		return e.ErrUserNotValid
	}

	return

}

// check for duplicate name before registering
func CheckDuplicate(name string) (check bool) {

	// password length cant be 0
	if len(name) == 0 {
		return true
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return true
	}

	// this will return true if there is a user
	err = dbase.QueryRow("select count(*) from users where user_name = ?", name).Scan(&check)
	if err != nil {
		return true
	}

	return

}

// Creates a JWT token with our claims
func (u *User) CreateToken() (newtoken string, err error) {

	// error if theres no secret set
	if Secret == "" {
		err = e.ErrNoSecret
		return
	}

	// check user struct validity
	if !u.IsValid() {
		err = e.ErrUserNotValid
		return
	}

	// a token should never be created
	if u.Id == 0 || u.Id == 1 {
		err = e.ErrUserNotValid
		return
	}

	// a token should never be created
	if !u.IsAuthenticated {
		err = e.ErrUserNotValid
		return
	}

	// check if password was valid
	if !u.isPasswordValid {
		err = e.ErrInvalidPassword
		return
	}

	// Create the token
	token := jwt.New(jwt.SigningMethodHS256)
	// the current time
	now := time.Now()

	// Set our claims
	token.Claims[jwt_claim_issuer] = jwt_issuer
	token.Claims[jwt_claim_issued] = now.Unix()
	token.Claims[jwt_claim_notbefore] = now.Unix()
	token.Claims[jwt_claim_expire] = now.Add(time.Hour * 24 * jwt_expire_days).Unix()
	token.Claims[jwt_claim_user_id] = u.Id

	// Sign and get the complete encoded token as a string
	newtoken, err = token.SignedString([]byte(Secret))
	if err != nil {
		return
	}

	return

}

// get the user info from id
func (u *User) IsAuthorized(ib uint) bool {

	var err error

	if !u.IsValid() {
		return false
	}

	// check for invalid stuff
	if ib == 0 {
		return false
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return false
	}

	// holds our role
	var role uint

	// get data from users table
	err = dbase.QueryRow(`SELECT COALESCE((SELECT MAX(role_id) FROM user_ib_role_map WHERE user_ib_role_map.user_id = users.user_id AND ib_id = ?),user_role_map.role_id) as role
    FROM users
    INNER JOIN user_role_map ON (user_role_map.user_id = users.user_id)
    WHERE users.user_id = ?`, ib, u.Id).Scan(&role)
	if err != nil {
		return false
	}

	switch role {
	case 3:
		return true
	case 4:
		return true
	default:
		return false
	}

	return false

}

// compare password to
func (u *User) ComparePassword(password string) bool {

	// password length cant be 0
	if len(password) == 0 {
		return false
	}

	// if the hash wasnt populated
	if len(u.hash) == 0 {
		return false
	}

	// compare the stored hash with the provided password
	err := bcrypt.CompareHashAndPassword(u.hash, []byte(password))

	// we only want jwt tokens to be created after a valid password has been given
	u.isPasswordValid = err == nil

	return u.isPasswordValid

}

// hash a given password
func HashPassword(password string) (hash []byte, err error) {

	// check that password has correct lengths
	if len(password) == 0 {
		err = e.ErrPasswordEmpty
		return
	} else if len(password) < config.Settings.Limits.PasswordMinLength {
		err = e.ErrPasswordShort
		return
	} else if len(password) > config.Settings.Limits.PasswordMaxLength {
		err = e.ErrPasswordLong
		return
	}

	return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
}
<|endoftext|>


<commit_before>package GoSDK

import (
	"errors"
	"fmt"
)

const (
	_USER_HEADER_KEY = "ClearBlade-UserToken"
	_USER_PREAMBLE   = "/api/v/1/user"
	_USER_V2         = "/api/v/2/user"
	_USER_ADMIN      = "/admin/user"
)

func (u *UserClient) credentials() ([][]string, error) {
	ret := make([][]string, 0)
	if u.UserToken != "" {
		ret = append(ret, []string{
			_USER_HEADER_KEY,
			u.UserToken,
		})
	}
	if u.SystemSecret != "" && u.SystemKey != "" {
		ret = append(ret, []string{
			_HEADER_SECRET_KEY,
			u.SystemSecret,
		})
		ret = append(ret, []string{
			_HEADER_KEY_KEY,
			u.SystemKey,
		})

	}

	if len(ret) == 0 {
		return [][]string{}, errors.New("No SystemSecret/SystemKey combo, or UserToken found")
	} else {
		return ret, nil
	}
}

func (u *UserClient) preamble() string {
	return _USER_PREAMBLE
}

func (u *UserClient) getSystemInfo() (string, string) {
	return u.SystemKey, u.SystemSecret
}

func (u *UserClient) setToken(t string) {
	u.UserToken = t
}
func (u *UserClient) getToken() string {
	return u.UserToken
}

func (u *UserClient) getMessageId() uint16 {
	return uint16(u.mrand.Int())
}

//GetUserColumns returns the description of the columns in the user table
//Returns a structure shaped []map[string]interface{}{map[string]interface{}{"ColumnName":"blah","ColumnType":"int"}}
func (d *DevClient) GetUserColumns(systemKey string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}

	resp, err := get(d, _USER_ADMIN+"/"+systemKey+"/columns", nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting user columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting user columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//CreateUserColumn creates a new column in the user table
func (d *DevClient) CreateUserColumn(systemKey, columnName, columnType string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"column_name": columnName,
		"type":        columnType,
	}

	resp, err := post(d, _USER_ADMIN+"/"+systemKey+"/columns", data, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating user column: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating user column: %v", resp.Body)
	}

	return nil
}

func (d *DevClient) DeleteUserColumn(systemKey, columnName string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	data := map[string]string{"column": columnName}

	resp, err := delete(d, _USER_ADMIN+"/"+systemKey+"/columns", data, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting user column: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting user column: %v", resp.Body)
	}

	return nil
}

func (u *UserClient) UpdateUser(userQuery *Query, changes map[string]interface{}) error {
	return updateUser(u, userQuery, changes)
}

func updateUser(c cbClient, userQuery *Query, changes map[string]interface{}) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	query := userQuery.serialize()
	body := map[string]interface{}{
		"query":   query,
		"changes": changes,
	}

	resp, err := put(c, _USER_V2+"/info", body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %s", err.Error())
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}

	return nil
}
<commit_msg>added method to fetch user count<commit_after>package GoSDK

import (
	"errors"
	"fmt"
)

const (
	_USER_HEADER_KEY = "ClearBlade-UserToken"
	_USER_PREAMBLE   = "/api/v/1/user"
	_USER_V2         = "/api/v/2/user"
	_USER_ADMIN      = "/admin/user"
)

func (u *UserClient) credentials() ([][]string, error) {
	ret := make([][]string, 0)
	if u.UserToken != "" {
		ret = append(ret, []string{
			_USER_HEADER_KEY,
			u.UserToken,
		})
	}
	if u.SystemSecret != "" && u.SystemKey != "" {
		ret = append(ret, []string{
			_HEADER_SECRET_KEY,
			u.SystemSecret,
		})
		ret = append(ret, []string{
			_HEADER_KEY_KEY,
			u.SystemKey,
		})

	}

	if len(ret) == 0 {
		return [][]string{}, errors.New("No SystemSecret/SystemKey combo, or UserToken found")
	} else {
		return ret, nil
	}
}

func (u *UserClient) preamble() string {
	return _USER_PREAMBLE
}

func (u *UserClient) getSystemInfo() (string, string) {
	return u.SystemKey, u.SystemSecret
}

func (u *UserClient) setToken(t string) {
	u.UserToken = t
}
func (u *UserClient) getToken() string {
	return u.UserToken
}

func (u *UserClient) getMessageId() uint16 {
	return uint16(u.mrand.Int())
}

func (u *UserClient) GetUserCount(systemKey string) (int, error) {
	creds, err := u.credentials()
	if err != nil {
		return -1, err
	}
	resp, err := get(u, u.preamble()+"/count", nil, creds, nil)
	if err != nil {
		return -1, fmt.Errorf("Error getting count: %v", err)
	}
	if resp.StatusCode != 200 {
		return -1, fmt.Errorf("Error getting count: %v", resp.Body)
	}
	bod := resp.Body.(map[string]interface{})
	theCount := int(bod["count"].(float64))
	return theCount, nil
}

//GetUserColumns returns the description of the columns in the user table
//Returns a structure shaped []map[string]interface{}{map[string]interface{}{"ColumnName":"blah","ColumnType":"int"}}
func (d *DevClient) GetUserColumns(systemKey string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}

	resp, err := get(d, _USER_ADMIN+"/"+systemKey+"/columns", nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting user columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting user columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//CreateUserColumn creates a new column in the user table
func (d *DevClient) CreateUserColumn(systemKey, columnName, columnType string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"column_name": columnName,
		"type":        columnType,
	}

	resp, err := post(d, _USER_ADMIN+"/"+systemKey+"/columns", data, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating user column: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating user column: %v", resp.Body)
	}

	return nil
}

func (d *DevClient) DeleteUserColumn(systemKey, columnName string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	data := map[string]string{"column": columnName}

	resp, err := delete(d, _USER_ADMIN+"/"+systemKey+"/columns", data, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting user column: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting user column: %v", resp.Body)
	}

	return nil
}

func (u *UserClient) UpdateUser(userQuery *Query, changes map[string]interface{}) error {
	return updateUser(u, userQuery, changes)
}

func updateUser(c cbClient, userQuery *Query, changes map[string]interface{}) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	query := userQuery.serialize()
	body := map[string]interface{}{
		"query":   query,
		"changes": changes,
	}

	resp, err := put(c, _USER_V2+"/info", body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %s", err.Error())
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}

	return nil
}
<|endoftext|>


<commit_before>// Modified UTF-7 encoding defined in RFC 3501 section 5.1.3
package utf7

import (
	"encoding/base64"

	"golang.org/x/text/encoding"
)

const (
	min = 0x20 // Minimum self-representing UTF-7 value
	max = 0x7E // Maximum self-representing UTF-7 value

	repl = '\uFFFD' // Unicode replacement code point
)

var b64Enc = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,")

type enc struct{}

func (e enc) NewDecoder() *encoding.Decoder {
	return &encoding.Decoder{
		Transformer: &decoder{true},
	}
}

func (e enc) NewEncoder() *encoding.Encoder {
	return &encoding.Encoder{
		Transformer: &encoder{},
	}
}

// Encoding is the modified UTF-7 encoding.
var Encoding encoding.Encoding = enc{}
<commit_msg>utf7: fix package doc comment<commit_after>// Package utf7 implements modified UTF-7 encoding defined in RFC 3501 section 5.1.3
package utf7

import (
	"encoding/base64"

	"golang.org/x/text/encoding"
)

const (
	min = 0x20 // Minimum self-representing UTF-7 value
	max = 0x7E // Maximum self-representing UTF-7 value

	repl = '\uFFFD' // Unicode replacement code point
)

var b64Enc = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,")

type enc struct{}

func (e enc) NewDecoder() *encoding.Decoder {
	return &encoding.Decoder{
		Transformer: &decoder{true},
	}
}

func (e enc) NewEncoder() *encoding.Encoder {
	return &encoding.Encoder{
		Transformer: &encoder{},
	}
}

// Encoding is the modified UTF-7 encoding.
var Encoding encoding.Encoding = enc{}
<|endoftext|>


<commit_before>package machinery

import (
	"errors"
	"fmt"
	"sync"

	"github.com/RichardKnop/machinery/v1/backends"
	"github.com/RichardKnop/machinery/v1/brokers"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/satori/go.uuid"
)

// Server is the main Machinery object and stores all configuration
// All the tasks workers process are registered against the server
type Server struct {
	config          *config.Config
	registeredTasks map[string]interface{}
	broker          brokers.Interface
	backend         backends.Interface
}

// NewServer creates Server instance
func NewServer(cnf *config.Config) (*Server, error) {
	broker, err := BrokerFactory(cnf)
	if err != nil {
		return nil, err
	}

	// Backend is optional so we ignore the error
	backend, _ := BackendFactory(cnf)

	srv := &Server{
		config:          cnf,
		registeredTasks: make(map[string]interface{}),
		broker:          broker,
		backend:         backend,
	}

	// init for eager-mode
	eager, ok := broker.(brokers.EagerMode)
	if ok {
		// we don't have to call worker.Lauch
		// in eager mode
		eager.AssignWorker(srv.NewWorker("eager", 0))
	}

	return srv, nil
}

// NewWorker creates Worker instance
func (server *Server) NewWorker(consumerTag string, concurrency int) *Worker {
	return &Worker{
		server:      server,
		ConsumerTag: consumerTag,
		Concurrency: concurrency,
	}
}

// GetBroker returns broker
func (server *Server) GetBroker() brokers.Interface {
	return server.broker
}

// SetBroker sets broker
func (server *Server) SetBroker(broker brokers.Interface) {
	server.broker = broker
}

// GetBackend returns backend
func (server *Server) GetBackend() backends.Interface {
	return server.backend
}

// SetBackend sets backend
func (server *Server) SetBackend(backend backends.Interface) {
	server.backend = backend
}

// GetConfig returns connection object
func (server *Server) GetConfig() *config.Config {
	return server.config
}

// SetConfig sets config
func (server *Server) SetConfig(cnf *config.Config) {
	server.config = cnf
}

// RegisterTasks registers all tasks at once
func (server *Server) RegisterTasks(namedTaskFuncs map[string]interface{}) error {
	for _, task := range namedTaskFuncs {
		if err := tasks.ValidateTask(task); err != nil {
			return err
		}
	}
	server.registeredTasks = namedTaskFuncs
	server.broker.SetRegisteredTaskNames(server.GetRegisteredTaskNames())
	return nil
}

// RegisterTask registers a single task
func (server *Server) RegisterTask(name string, taskFunc interface{}) error {
	if err := tasks.ValidateTask(taskFunc); err != nil {
		return err
	}
	server.registeredTasks[name] = taskFunc
	server.broker.SetRegisteredTaskNames(server.GetRegisteredTaskNames())
	return nil
}

// IsTaskRegistered returns true if the task name is registered with this broker
func (server *Server) IsTaskRegistered(name string) bool {
	_, ok := server.registeredTasks[name]
	return ok
}

// GetRegisteredTask returns registered task by name
func (server *Server) GetRegisteredTask(name string) (interface{}, error) {
	taskFunc, ok := server.registeredTasks[name]
	if !ok {
		return nil, fmt.Errorf("Task not registered error: %s", name)
	}
	return taskFunc, nil
}

// SendTask publishes a task to the default queue
func (server *Server) SendTask(signature *tasks.Signature) (*backends.AsyncResult, error) {
	// Make sure result backend is defined
	if server.backend == nil {
		return nil, errors.New("Result backend required")
	}

	// Auto generate a UUID if not set already
	if signature.UUID == "" {
		signature.UUID = fmt.Sprintf("task_%v", uuid.NewV4())
	}

	// Set initial task state to PENDING
	if err := server.backend.SetStatePending(signature); err != nil {
		return nil, fmt.Errorf("Set state pending error: %s", err)
	}

	if err := server.broker.Publish(signature); err != nil {
		return nil, fmt.Errorf("Publish message error: %s", err)
	}

	return backends.NewAsyncResult(signature, server.backend), nil
}

// SendChain triggers a chain of tasks
func (server *Server) SendChain(chain *tasks.Chain) (*backends.ChainAsyncResult, error) {
	_, err := server.SendTask(chain.Tasks[0])
	if err != nil {
		return nil, err
	}

	return backends.NewChainAsyncResult(chain.Tasks, server.backend), nil
}

// SendGroup triggers a group of parallel tasks
func (server *Server) SendGroup(group *tasks.Group, sendConcurrency int) ([]*backends.AsyncResult, error) {
	// Make sure result backend is defined
	if server.backend == nil {
		return nil, errors.New("Result backend required")
	}

	asyncResults := make([]*backends.AsyncResult, len(group.Tasks))

	var wg sync.WaitGroup
	wg.Add(len(group.Tasks))
	errorsChan := make(chan error, len(group.Tasks)*2)

	// Init group
	server.backend.InitGroup(group.GroupUUID, group.GetUUIDs())

	// Init the tasks Pending state first
	for _, signature := range group.Tasks {
		if err := server.backend.SetStatePending(signature); err != nil {
			errorsChan <- err
			continue
		}
	}

	pool := make(chan struct{}, sendConcurrency)
	go func() {
		for i := 0; i < sendConcurrency; i++ {
			pool <- struct{}{}
		}
	}()

	for i, signature := range group.Tasks {

		if sendConcurrency > 0 {
			<-pool
		}

		go func(s *tasks.Signature, index int) {
			defer wg.Done()

			// Publish task

			err := server.broker.Publish(s)

			if sendConcurrency > 0 {
				pool <- struct{}{}
			}

			if err != nil {
				errorsChan <- fmt.Errorf("Publish message error: %s", err)
				return
			}

			asyncResults[index] = backends.NewAsyncResult(s, server.backend)
		}(signature, i)
	}

	done := make(chan int)
	go func() {
		wg.Wait()
		done <- 1
	}()

	select {
	case err := <-errorsChan:
		return asyncResults, err
	case <-done:
		return asyncResults, nil
	}
}

// SendChord triggers a group of parallel tasks with a callback
func (server *Server) SendChord(chord *tasks.Chord, sendConcurrency int) (*backends.ChordAsyncResult, error) {
	_, err := server.SendGroup(chord.Group, sendConcurrency)
	if err != nil {
		return nil, err
	}

	return backends.NewChordAsyncResult(
		chord.Group.Tasks,
		chord.Callback,
		server.backend,
	), nil
}

// GetRegisteredTaskNames returns slice of registered task names
func (server *Server) GetRegisteredTaskNames() []string {
	taskNames := make([]string, len(server.registeredTasks))
	var i = 0
	for name := range server.registeredTasks {
		taskNames[i] = name
		i++
	}
	return taskNames
}
<commit_msg>feat(tracing): implement *WithContext variants of SendTask and the like<commit_after>package machinery

import (
	"context"
	"errors"
	"fmt"
	"sync"

	opentracing "github.com/opentracing/opentracing-go"

	"github.com/satori/go.uuid"

	"github.com/RichardKnop/machinery/v1/backends"
	"github.com/RichardKnop/machinery/v1/brokers"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/RichardKnop/machinery/v1/tracing"
)

// Server is the main Machinery object and stores all configuration
// All the tasks workers process are registered against the server
type Server struct {
	config          *config.Config
	registeredTasks map[string]interface{}
	broker          brokers.Interface
	backend         backends.Interface
}

// NewServer creates Server instance
func NewServer(cnf *config.Config) (*Server, error) {
	broker, err := BrokerFactory(cnf)
	if err != nil {
		return nil, err
	}

	// Backend is optional so we ignore the error
	backend, _ := BackendFactory(cnf)

	srv := &Server{
		config:          cnf,
		registeredTasks: make(map[string]interface{}),
		broker:          broker,
		backend:         backend,
	}

	// init for eager-mode
	eager, ok := broker.(brokers.EagerMode)
	if ok {
		// we don't have to call worker.Lauch
		// in eager mode
		eager.AssignWorker(srv.NewWorker("eager", 0))
	}

	return srv, nil
}

// NewWorker creates Worker instance
func (server *Server) NewWorker(consumerTag string, concurrency int) *Worker {
	return &Worker{
		server:      server,
		ConsumerTag: consumerTag,
		Concurrency: concurrency,
	}
}

// GetBroker returns broker
func (server *Server) GetBroker() brokers.Interface {
	return server.broker
}

// SetBroker sets broker
func (server *Server) SetBroker(broker brokers.Interface) {
	server.broker = broker
}

// GetBackend returns backend
func (server *Server) GetBackend() backends.Interface {
	return server.backend
}

// SetBackend sets backend
func (server *Server) SetBackend(backend backends.Interface) {
	server.backend = backend
}

// GetConfig returns connection object
func (server *Server) GetConfig() *config.Config {
	return server.config
}

// SetConfig sets config
func (server *Server) SetConfig(cnf *config.Config) {
	server.config = cnf
}

// RegisterTasks registers all tasks at once
func (server *Server) RegisterTasks(namedTaskFuncs map[string]interface{}) error {
	for _, task := range namedTaskFuncs {
		if err := tasks.ValidateTask(task); err != nil {
			return err
		}
	}
	server.registeredTasks = namedTaskFuncs
	server.broker.SetRegisteredTaskNames(server.GetRegisteredTaskNames())
	return nil
}

// RegisterTask registers a single task
func (server *Server) RegisterTask(name string, taskFunc interface{}) error {
	if err := tasks.ValidateTask(taskFunc); err != nil {
		return err
	}
	server.registeredTasks[name] = taskFunc
	server.broker.SetRegisteredTaskNames(server.GetRegisteredTaskNames())
	return nil
}

// IsTaskRegistered returns true if the task name is registered with this broker
func (server *Server) IsTaskRegistered(name string) bool {
	_, ok := server.registeredTasks[name]
	return ok
}

// GetRegisteredTask returns registered task by name
func (server *Server) GetRegisteredTask(name string) (interface{}, error) {
	taskFunc, ok := server.registeredTasks[name]
	if !ok {
		return nil, fmt.Errorf("Task not registered error: %s", name)
	}
	return taskFunc, nil
}

// SendTaskWithContext will inject the trace context in the signature headers before publishing it
func (server *Server) SendTaskWithContext(ctx context.Context, signature *tasks.Signature) (*backends.AsyncResult, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "SendTask", tracing.ProducerOption(), tracing.MachineryTag)
	defer span.Finish()

	// tag the span with some info about the signature
	signature.Headers = tracing.HeadersWithSpan(signature.Headers, span)

	// Send it on to SendTask as normal
	return server.SendTask(signature)
}

// SendTask publishes a task to the default queue
func (server *Server) SendTask(signature *tasks.Signature) (*backends.AsyncResult, error) {
	// Make sure result backend is defined
	if server.backend == nil {
		return nil, errors.New("Result backend required")
	}

	// Auto generate a UUID if not set already
	if signature.UUID == "" {
		signature.UUID = fmt.Sprintf("task_%v", uuid.NewV4())
	}

	// Set initial task state to PENDING
	if err := server.backend.SetStatePending(signature); err != nil {
		return nil, fmt.Errorf("Set state pending error: %s", err)
	}

	if err := server.broker.Publish(signature); err != nil {
		return nil, fmt.Errorf("Publish message error: %s", err)
	}

	return backends.NewAsyncResult(signature, server.backend), nil
}

// SendChainWithContext will inject the trace context in all the signature headers before publishing it
func (server *Server) SendChainWithContext(ctx context.Context, chain *tasks.Chain) (*backends.ChainAsyncResult, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "SendChain", tracing.ProducerOption(), tracing.MachineryTag, tracing.WorkflowChainTag)
	defer span.Finish()

	tracing.AnnotateSpanWithChainInfo(span, chain)

	return server.SendChain(chain)
}

// SendChain triggers a chain of tasks
func (server *Server) SendChain(chain *tasks.Chain) (*backends.ChainAsyncResult, error) {
	_, err := server.SendTask(chain.Tasks[0])
	if err != nil {
		return nil, err
	}

	return backends.NewChainAsyncResult(chain.Tasks, server.backend), nil
}

// SendGroupWithContext will inject the trace context in all the signature headers before publishing it
func (server *Server) SendGroupWithContext(ctx context.Context, group *tasks.Group, sendConcurrency int) ([]*backends.AsyncResult, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "SendGroup", tracing.ProducerOption(), tracing.MachineryTag, tracing.WorkflowGroupTag)
	defer span.Finish()

	tracing.AnnotateSpanWithGroupInfo(span, group, sendConcurrency)

	return server.SendGroup(group, sendConcurrency)
}

// SendGroup triggers a group of parallel tasks
func (server *Server) SendGroup(group *tasks.Group, sendConcurrency int) ([]*backends.AsyncResult, error) {
	// Make sure result backend is defined
	if server.backend == nil {
		return nil, errors.New("Result backend required")
	}

	asyncResults := make([]*backends.AsyncResult, len(group.Tasks))

	var wg sync.WaitGroup
	wg.Add(len(group.Tasks))
	errorsChan := make(chan error, len(group.Tasks)*2)

	// Init group
	server.backend.InitGroup(group.GroupUUID, group.GetUUIDs())

	// Init the tasks Pending state first
	for _, signature := range group.Tasks {
		if err := server.backend.SetStatePending(signature); err != nil {
			errorsChan <- err
			continue
		}
	}

	pool := make(chan struct{}, sendConcurrency)
	go func() {
		for i := 0; i < sendConcurrency; i++ {
			pool <- struct{}{}
		}
	}()

	for i, signature := range group.Tasks {

		if sendConcurrency > 0 {
			<-pool
		}

		go func(s *tasks.Signature, index int) {
			defer wg.Done()

			// Publish task

			err := server.broker.Publish(s)

			if sendConcurrency > 0 {
				pool <- struct{}{}
			}

			if err != nil {
				errorsChan <- fmt.Errorf("Publish message error: %s", err)
				return
			}

			asyncResults[index] = backends.NewAsyncResult(s, server.backend)
		}(signature, i)
	}

	done := make(chan int)
	go func() {
		wg.Wait()
		done <- 1
	}()

	select {
	case err := <-errorsChan:
		return asyncResults, err
	case <-done:
		return asyncResults, nil
	}
}

// SendChordWithContext will inject the trace context in all the signature headers before publishing it
func (server *Server) SendChordWithContext(ctx context.Context, chord *tasks.Chord, sendConcurrency int) (*backends.ChordAsyncResult, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "SendChord", tracing.ProducerOption(), tracing.MachineryTag, tracing.WorkflowChordTag)
	defer span.Finish()

	tracing.AnnotateSpanWithChordInfo(span, chord, sendConcurrency)

	return server.SendChord(chord, sendConcurrency)
}

// SendChord triggers a group of parallel tasks with a callback
func (server *Server) SendChord(chord *tasks.Chord, sendConcurrency int) (*backends.ChordAsyncResult, error) {
	_, err := server.SendGroup(chord.Group, sendConcurrency)
	if err != nil {
		return nil, err
	}

	return backends.NewChordAsyncResult(
		chord.Group.Tasks,
		chord.Callback,
		server.backend,
	), nil
}

// GetRegisteredTaskNames returns slice of registered task names
func (server *Server) GetRegisteredTaskNames() []string {
	taskNames := make([]string, len(server.registeredTasks))
	var i = 0
	for name := range server.registeredTasks {
		taskNames[i] = name
		i++
	}
	return taskNames
}
<|endoftext|>