<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2022 Red Hat, Inc.
 *
 */

package testsuite

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/api/equality"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"

	virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
	"kubevirt.io/kubevirt/tests/flags"
	"kubevirt.io/kubevirt/tests/framework/checks"
	"kubevirt.io/kubevirt/tests/util"
)

var (
	KubeVirtDefaultConfig v1.KubeVirtConfiguration
	originalKV            *v1.KubeVirt
)

func AdjustKubeVirtResource() {
	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	originalKV = kv.DeepCopy()

	KubeVirtDefaultConfig = originalKV.Spec.Configuration

	if !flags.ApplyDefaulte2eConfiguration {
		return
	}

	// Rotate very often during the tests to ensure that things are working
	kv.Spec.CertificateRotationStrategy = v1.KubeVirtCertificateRotateStrategy{SelfSigned: &v1.KubeVirtSelfSignConfiguration{
		CA: &v1.CertConfig{
			Duration:    &metav1.Duration{Duration: 20 * time.Minute},
			RenewBefore: &metav1.Duration{Duration: 12 * time.Minute},
		},
		Server: &v1.CertConfig{
			Duration:    &metav1.Duration{Duration: 14 * time.Minute},
			RenewBefore: &metav1.Duration{Duration: 10 * time.Minute},
		},
	}}

	// match default kubevirt-config testing resource
	if kv.Spec.Configuration.DeveloperConfiguration == nil {
		kv.Spec.Configuration.DeveloperConfiguration = &v1.DeveloperConfiguration{}
	}

	if kv.Spec.Configuration.DeveloperConfiguration.FeatureGates == nil {
		kv.Spec.Configuration.DeveloperConfiguration.FeatureGates = []string{}
	}
	kv.Spec.Configuration.DeveloperConfiguration.FeatureGates = append(kv.Spec.Configuration.DeveloperConfiguration.FeatureGates,
		virtconfig.CPUManager,
		virtconfig.LiveMigrationGate,
		virtconfig.IgnitionGate,
		virtconfig.SidecarGate,
		virtconfig.SnapshotGate,
		virtconfig.HostDiskGate,
		virtconfig.VirtIOFSGate,
		virtconfig.HotplugVolumesGate,
		virtconfig.DownwardMetricsFeatureGate,
		virtconfig.NUMAFeatureGate,
		virtconfig.MacvtapGate,
		virtconfig.PasstGate,
		virtconfig.ExpandDisksGate,
		virtconfig.WorkloadEncryptionSEV,
		virtconfig.VMExportGate,
	)
	kv.Spec.Configuration.SELinuxLauncherType = "virt_launcher.process"

	if kv.Spec.Configuration.NetworkConfiguration == nil {
		testDefaultPermitSlirpInterface := true

		kv.Spec.Configuration.NetworkConfiguration = &v1.NetworkConfiguration{
			PermitSlirpInterface: &testDefaultPermitSlirpInterface,
		}
	}

	data, err := json.Marshal(kv.Spec)
	Expect(err).ToNot(HaveOccurred())
	patchData := fmt.Sprintf(`[{ "op": "replace", "path": "/spec", "value": %s }]`, string(data))
	adjustedKV, err := virtClient.KubeVirt(kv.Namespace).Patch(kv.Name, types.JSONPatchType, []byte(patchData), &metav1.PatchOptions{})
	util.PanicOnError(err)
	KubeVirtDefaultConfig = adjustedKV.Spec.Configuration
	nodes, err := virtClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
	Expect(err).NotTo(HaveOccurred())
	if checks.HasFeature(virtconfig.CPUManager) && len(nodes.Items) > 1 {
		// CPUManager is not enabled in the control-plane node
		waitForSchedulableNodeWithCPUManager()
	}
}

func waitForSchedulableNodeWithCPUManager() {

	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)
	Eventually(func() bool {
		nodes, err := virtClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{LabelSelector: v1.NodeSchedulable + "=" + "true," + v1.CPUManager + "=true"})
		Expect(err).ToNot(HaveOccurred(), "Should list compute nodes")
		return len(nodes.Items) != 0
	}, 360, 1*time.Second).Should(BeTrue())
}

func RestoreKubeVirtResource() {
	if originalKV != nil {
		virtClient, err := kubecli.GetKubevirtClient()
		util.PanicOnError(err)
		data, err := json.Marshal(originalKV.Spec)
		Expect(err).ToNot(HaveOccurred())
		patchData := fmt.Sprintf(`[{ "op": "replace", "path": "/spec", "value": %s }]`, string(data))
		_, err = virtClient.KubeVirt(originalKV.Namespace).Patch(originalKV.Name, types.JSONPatchType, []byte(patchData), &metav1.PatchOptions{})
		util.PanicOnError(err)
	}
}

func ShouldAllowEmulation(virtClient kubecli.KubevirtClient) bool {
	allowEmulation := false
	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	if kv.Spec.Configuration.DeveloperConfiguration != nil {
		allowEmulation = kv.Spec.Configuration.DeveloperConfiguration.UseEmulation
	}

	return allowEmulation
}

// UpdateKubeVirtConfigValue updates the given configuration in the kubevirt custom resource
func UpdateKubeVirtConfigValue(kvConfig v1.KubeVirtConfiguration) *v1.KubeVirt {

	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	old, err := json.Marshal(kv)
	Expect(err).ToNot(HaveOccurred())

	if equality.Semantic.DeepEqual(kv.Spec.Configuration, kvConfig) {
		return kv
	}

	suiteConfig, _ := GinkgoConfiguration()
	if suiteConfig.ParallelTotal > 1 {
		Fail("Tests which alter the global kubevirt configuration must not be executed in parallel")
	}

	updatedKV := kv.DeepCopy()
	updatedKV.Spec.Configuration = kvConfig
	newJson, err := json.Marshal(updatedKV)
	Expect(err).ToNot(HaveOccurred())

	patch, err := strategicpatch.CreateTwoWayMergePatch(old, newJson, kv)
	Expect(err).ToNot(HaveOccurred())

	kv, err = virtClient.KubeVirt(kv.Namespace).Patch(kv.GetName(), types.MergePatchType, patch, &metav1.PatchOptions{})
	Expect(err).ToNot(HaveOccurred())

	return kv
}
<commit_msg>Remove live migration feature gate from tests initialization<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2022 Red Hat, Inc.
 *
 */

package testsuite

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/api/equality"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"

	virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
	"kubevirt.io/kubevirt/tests/flags"
	"kubevirt.io/kubevirt/tests/framework/checks"
	"kubevirt.io/kubevirt/tests/util"
)

var (
	KubeVirtDefaultConfig v1.KubeVirtConfiguration
	originalKV            *v1.KubeVirt
)

func AdjustKubeVirtResource() {
	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	originalKV = kv.DeepCopy()

	KubeVirtDefaultConfig = originalKV.Spec.Configuration

	if !flags.ApplyDefaulte2eConfiguration {
		return
	}

	// Rotate very often during the tests to ensure that things are working
	kv.Spec.CertificateRotationStrategy = v1.KubeVirtCertificateRotateStrategy{SelfSigned: &v1.KubeVirtSelfSignConfiguration{
		CA: &v1.CertConfig{
			Duration:    &metav1.Duration{Duration: 20 * time.Minute},
			RenewBefore: &metav1.Duration{Duration: 12 * time.Minute},
		},
		Server: &v1.CertConfig{
			Duration:    &metav1.Duration{Duration: 14 * time.Minute},
			RenewBefore: &metav1.Duration{Duration: 10 * time.Minute},
		},
	}}

	// match default kubevirt-config testing resource
	if kv.Spec.Configuration.DeveloperConfiguration == nil {
		kv.Spec.Configuration.DeveloperConfiguration = &v1.DeveloperConfiguration{}
	}

	if kv.Spec.Configuration.DeveloperConfiguration.FeatureGates == nil {
		kv.Spec.Configuration.DeveloperConfiguration.FeatureGates = []string{}
	}
	kv.Spec.Configuration.DeveloperConfiguration.FeatureGates = append(kv.Spec.Configuration.DeveloperConfiguration.FeatureGates,
		virtconfig.CPUManager,
		virtconfig.IgnitionGate,
		virtconfig.SidecarGate,
		virtconfig.SnapshotGate,
		virtconfig.HostDiskGate,
		virtconfig.VirtIOFSGate,
		virtconfig.HotplugVolumesGate,
		virtconfig.DownwardMetricsFeatureGate,
		virtconfig.NUMAFeatureGate,
		virtconfig.MacvtapGate,
		virtconfig.PasstGate,
		virtconfig.ExpandDisksGate,
		virtconfig.WorkloadEncryptionSEV,
		virtconfig.VMExportGate,
	)
	kv.Spec.Configuration.SELinuxLauncherType = "virt_launcher.process"

	if kv.Spec.Configuration.NetworkConfiguration == nil {
		testDefaultPermitSlirpInterface := true

		kv.Spec.Configuration.NetworkConfiguration = &v1.NetworkConfiguration{
			PermitSlirpInterface: &testDefaultPermitSlirpInterface,
		}
	}

	data, err := json.Marshal(kv.Spec)
	Expect(err).ToNot(HaveOccurred())
	patchData := fmt.Sprintf(`[{ "op": "replace", "path": "/spec", "value": %s }]`, string(data))
	adjustedKV, err := virtClient.KubeVirt(kv.Namespace).Patch(kv.Name, types.JSONPatchType, []byte(patchData), &metav1.PatchOptions{})
	util.PanicOnError(err)
	KubeVirtDefaultConfig = adjustedKV.Spec.Configuration
	nodes, err := virtClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
	Expect(err).NotTo(HaveOccurred())
	if checks.HasFeature(virtconfig.CPUManager) && len(nodes.Items) > 1 {
		// CPUManager is not enabled in the control-plane node
		waitForSchedulableNodeWithCPUManager()
	}
}

func waitForSchedulableNodeWithCPUManager() {

	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)
	Eventually(func() bool {
		nodes, err := virtClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{LabelSelector: v1.NodeSchedulable + "=" + "true," + v1.CPUManager + "=true"})
		Expect(err).ToNot(HaveOccurred(), "Should list compute nodes")
		return len(nodes.Items) != 0
	}, 360, 1*time.Second).Should(BeTrue())
}

func RestoreKubeVirtResource() {
	if originalKV != nil {
		virtClient, err := kubecli.GetKubevirtClient()
		util.PanicOnError(err)
		data, err := json.Marshal(originalKV.Spec)
		Expect(err).ToNot(HaveOccurred())
		patchData := fmt.Sprintf(`[{ "op": "replace", "path": "/spec", "value": %s }]`, string(data))
		_, err = virtClient.KubeVirt(originalKV.Namespace).Patch(originalKV.Name, types.JSONPatchType, []byte(patchData), &metav1.PatchOptions{})
		util.PanicOnError(err)
	}
}

func ShouldAllowEmulation(virtClient kubecli.KubevirtClient) bool {
	allowEmulation := false
	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	if kv.Spec.Configuration.DeveloperConfiguration != nil {
		allowEmulation = kv.Spec.Configuration.DeveloperConfiguration.UseEmulation
	}

	return allowEmulation
}

// UpdateKubeVirtConfigValue updates the given configuration in the kubevirt custom resource
func UpdateKubeVirtConfigValue(kvConfig v1.KubeVirtConfiguration) *v1.KubeVirt {

	virtClient, err := kubecli.GetKubevirtClient()
	util.PanicOnError(err)

	kv := util.GetCurrentKv(virtClient)
	old, err := json.Marshal(kv)
	Expect(err).ToNot(HaveOccurred())

	if equality.Semantic.DeepEqual(kv.Spec.Configuration, kvConfig) {
		return kv
	}

	suiteConfig, _ := GinkgoConfiguration()
	if suiteConfig.ParallelTotal > 1 {
		Fail("Tests which alter the global kubevirt configuration must not be executed in parallel")
	}

	updatedKV := kv.DeepCopy()
	updatedKV.Spec.Configuration = kvConfig
	newJson, err := json.Marshal(updatedKV)
	Expect(err).ToNot(HaveOccurred())

	patch, err := strategicpatch.CreateTwoWayMergePatch(old, newJson, kv)
	Expect(err).ToNot(HaveOccurred())

	kv, err = virtClient.KubeVirt(kv.Namespace).Patch(kv.GetName(), types.MergePatchType, patch, &metav1.PatchOptions{})
	Expect(err).ToNot(HaveOccurred())

	return kv
}
<|endoftext|>


<commit_before>package dorothea

import "math/rand"

type Player struct {
	Color   Color
	OutArea int
}

func createPlayers(playerColors []Color) []Player {
	players := make([]Player, len(playerColors))
	for i, _ := range players {
		players[i] = Player{OutArea: 4, Color: playerColors[i]}
	}
	return players
}

func (p Player) ThrowDice() int {
	return rand.Intn(6) + 1
}
<commit_msg>add Position and HomeArea to Player<commit_after>package dorothea

import "math/rand"

type Player struct {
	Color    Color
	OutArea  int
	Position []int  // of pieces on board
	HomeArea []bool // piece in home[0,1,2,3] ?
}

func createPlayers(playerColors []Color) []Player {
	players := make([]Player, len(playerColors))
	for i, _ := range players {
		players[i] = Player{OutArea: 4, Color: playerColors[i], Position: make([]int, 0), HomeArea: make([]bool, 4)}
	}
	return players
}

func (p Player) ThrowDice() int {
	return rand.Intn(6) + 1
}
<|endoftext|>


<commit_before>package server

import "sync"

type NodeType uint

const (
	HeadNode NodeType = iota + 1
	ArmNode
)

type Player struct {
	ID       uint   `json:"id"`
	Username string `json:"username"`

	Conn *ComConn `json:"-"`

	// TODO: Neaten up this whole system
	Nodes     []*Node        `json:"nodes"`
	nodesMap  map[uint]*Node // Map for quick access
	nodesLock sync.RWMutex
	nodeCount uint
}

func (p *Player) Valid() bool {
	return p.Username != ""
}

func (p *Player) RegisterNode(n Node) (uint, error) {
	id := p.nodeCount + 1

	p.nodesLock.Lock()
	_, ok := p.nodesMap[id]
	if ok {
		return 0, ErrNodeAlreadyExists
	}

	p.Nodes = append(p.Nodes, &n)

	p.nodesMap[id] = &n
	p.nodeCount += 1

	p.nodesLock.Unlock()

	return id, nil
}

type Node struct {
	ID       uint     `json:"id"`
	Type     NodeType `json:"type"`
	PID      uint     `json:"pid"`
	Position Point    `json:"position"`
	Rotation Point    `json:"rotation"`
	Asset    string   `json:"asset"`
	Label    string   `json:"label"`
}

type Point struct {
	X float64
	Y float64
	Z float64
}
<commit_msg>Fix player ID and node ID not persisting<commit_after>package server

import "sync"

type NodeType uint

const (
	HeadNode NodeType = iota + 1
	ArmNode
)

type Player struct {
	ID       uint   `json:"id"`
	Username string `json:"username"`

	Conn *ComConn `json:"-"`

	// TODO: Neaten up this whole system
	Nodes     []*Node        `json:"nodes"`
	nodesMap  map[uint]*Node // Map for quick access
	nodesLock sync.RWMutex
	nodeCount uint
}

func (p *Player) Valid() bool {
	return p.Username != ""
}

func (p *Player) RegisterNode(n Node) (uint, error) {
	id := p.nodeCount + 1

	p.nodesLock.Lock()
	_, ok := p.nodesMap[id]
	if ok {
		return 0, ErrNodeAlreadyExists
	}

	p.Nodes = append(p.Nodes, &n)

	p.nodesMap[id] = &n
	p.nodeCount += 1

	n.PID = p.ID
	p.ID = id

	p.nodesLock.Unlock()

	return id, nil
}

type Node struct {
	ID       uint     `json:"id"`
	Type     NodeType `json:"type"`
	PID      uint     `json:"pid"`
	Position Point    `json:"position"`
	Rotation Point    `json:"rotation"`
	Asset    string   `json:"asset"`
	Label    string   `json:"label"`
}

type Point struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
	Z float64 `json:"z"`
}
<|endoftext|>


<commit_before>// Copyright 2015 Dominique Feyer <dfeyer@ttree.ch>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flowpathmapper

import (
	"github.com/dfeyer/flow-debugproxy/config"
	"github.com/dfeyer/flow-debugproxy/errorhandler"
	"github.com/dfeyer/flow-debugproxy/logger"
	"github.com/dfeyer/flow-debugproxy/pathmapperfactory"
	"github.com/dfeyer/flow-debugproxy/pathmapping"

	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
)

const (
	h                = "%s"
	framework        = "flow"
	cachePathPattern = "@base@/Data/Temporary/@context@/Cache/Code/Flow_Object_Classes/@filename@.php"
)

var (
	regexpPhpFile         = regexp.MustCompile(`(?://)?(/[^ ]*\.php)`)
	regexpFilename        = regexp.MustCompile(`filename=["]?file://(\S+)/Data/Temporary/[^/]*/Cache/Code/Flow_Object_Classes/([^"]*)\.php`)
	regexpPathAndFilename = regexp.MustCompile(`(?m)^# PathAndFilename: (.*)$`)
	regexpPackageClass    = regexp.MustCompile(`(.*?)/Packages/(.*?)/Classes/(.*).php`)
	regexpDot             = regexp.MustCompile(`[\./]`)
)

func init() {
	p := &PathMapper{}
	pathmapperfactory.Register(framework, p)
}

// PathMapper handle the mapping between real code and proxy
type PathMapper struct {
	config      *config.Config
	logger      *logger.Logger
	pathMapping *pathmapping.PathMapping
}

// Initialize the path mapper dependencies
func (p *PathMapper) Initialize(c *config.Config, l *logger.Logger, m *pathmapping.PathMapping) {
	p.config = c
	p.logger = l
	p.pathMapping = m
}

// ApplyMappingToTextProtocol change file path in xDebug text protocol
func (p *PathMapper) ApplyMappingToTextProtocol(message []byte) []byte {
	return p.doTextPathMapping(message)
}

// ApplyMappingToXML change file path in xDebug XML protocol
func (p *PathMapper) ApplyMappingToXML(message []byte) []byte {
	message = p.doXMLPathMapping(message)

	// update xml length count
	s := strings.Split(string(message), "\x00")
	i, err := strconv.Atoi(s[0])
	errorhandler.PanicHandling(err, p.logger)
	l := len(s[1])
	if i != l {
		message = bytes.Replace(message, []byte(strconv.Itoa(i)), []byte(strconv.Itoa(l)), 1)
	}

	return message
}

func (p *PathMapper) doTextPathMapping(message []byte) []byte {
	var processedMapping = map[string]string{}
	for _, match := range regexpPhpFile.FindAllStringSubmatch(string(message), -1) {
		originalPath := match[1]
		path := p.mapPath(originalPath)
		p.logger.Debug("doTextPathMapping %s >>> %s", path, originalPath)
		processedMapping[path] = originalPath
	}

	for path, originalPath := range processedMapping {
		message = bytes.Replace(message, []byte(p.getRealFilename(originalPath)), []byte(p.getRealFilename(path)), -1)
	}

	return message
}

func (p *PathMapper) getCachePath(base, filename string) string {
	cachePath := strings.Replace(cachePathPattern, "@base@", base, 1)
	cachePath = strings.Replace(cachePath, "@context@", p.config.Context, 1)
	return strings.Replace(cachePath, "@filename@", filename, 1)
}

func (p *PathMapper) doXMLPathMapping(b []byte) []byte {
	var processedMapping = map[string]string{}
	for _, match := range regexpFilename.FindAllStringSubmatch(string(b), -1) {
		path := p.getCachePath(match[1], match[2])
		if _, ok := processedMapping[path]; ok == false {
			if originalPath, exist := p.pathMapping.Get(path); exist {
				if p.config.VeryVerbose {
					p.logger.Info("Umpa Lumpa can help you, he know the mapping\n%s\n%s\n", p.logger.Colorize(">>> "+fmt.Sprintf(h, path), "yellow"), p.logger.Colorize(">>> "+fmt.Sprintf(h, p.getRealFilename(originalPath)), "green"))
				}
				processedMapping[path] = originalPath
				p.logger.Debug("doXMLPathMapping mapping exist %s >>> %s", path, originalPath)
			} else {
				originalPath = p.readOriginalPathFromCache(path)
				processedMapping[path] = originalPath
				p.logger.Debug("doXMLPathMapping missing mapping %s >>> %s", path, originalPath)
			}
		}
	}

	for path, originalPath := range processedMapping {
		path = p.getRealFilename(path)
		originalPath = p.getRealFilename(originalPath)
		b = bytes.Replace(b, []byte(path), []byte(originalPath), -1)
	}

	return b
}

// getRealFilename removes file:// protocol from the given path
func (p *PathMapper) getRealFilename(path string) string {
	return strings.TrimPrefix(path, "file://")
}

func (p *PathMapper) mapPath(originalPath string) string {
	if strings.Contains(originalPath, "/Packages/") {
		p.logger.Debug("Path %s is a Flow Package file", originalPath)
		cachePath := p.getCachePath(p.buildClassNameFromPath(originalPath))
		realPath := p.getRealFilename(cachePath)
		if _, err := os.Stat(realPath); err == nil {
			return p.setPathMapping(realPath, originalPath)
		}
	}

	return originalPath
}

func (p *PathMapper) setPathMapping(path string, originalPath string) string {
	if p.config.Verbose {
		p.logger.Info("%s", "Our Umpa Lumpa take care of your mapping and they did a great job, they found a proxy for you:")
		p.logger.Info(">>> %s\n", path)
	}

	if p.pathMapping.Has(path) == false {
		p.pathMapping.Set(path, originalPath)
	}
	return path
}

func (p *PathMapper) readOriginalPathFromCache(path string) string {
	dat, err := ioutil.ReadFile(path)
	errorhandler.PanicHandling(err, p.logger)
	match := regexpPathAndFilename.FindStringSubmatch(string(dat))
	p.logger.Debug("readOriginalPathFromCache %s", path)
	if len(match) == 2 {
		originalPath := match[1]
		if p.config.VeryVerbose {
			p.logger.Info("Umpa Lumpa need to work harder, need to reverse this one\n>>> %s\n>>> %s\n", p.logger.Colorize(fmt.Sprintf(h, path), "yellow"), p.logger.Colorize(fmt.Sprintf(h, originalPath), "green"))
		}
		p.logger.Debug("readOriginalPathFromCache %s >>> %s", path, originalPath)
		p.setPathMapping(path, originalPath)
		return originalPath
	}
	return path
}

func (p *PathMapper) buildClassNameFromPath(path string) (string, string) {
	var (
		basePath  string
		className string
	)
	match := regexpPackageClass.FindStringSubmatch(path)
	if len(match) == 4 {
		// Flow standard packages
		basePath = match[1]
		className = regexpDot.ReplaceAllString(match[3], "_")
	} else {
		// Other (vendor) packages, todo add support for vendor package with Flow proxy class
		p.logger.Warn(h, "Vendor package detected")
		p.logger.Warn("Class mapping not supported currently for path: %s, \n", path)
		basePath = path
		className = ""
	}
	return basePath, className
}
<commit_msg>TASK: Use "h" const in Logger<commit_after>// Copyright 2015 Dominique Feyer <dfeyer@ttree.ch>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flowpathmapper

import (
	"github.com/dfeyer/flow-debugproxy/config"
	"github.com/dfeyer/flow-debugproxy/errorhandler"
	"github.com/dfeyer/flow-debugproxy/logger"
	"github.com/dfeyer/flow-debugproxy/pathmapperfactory"
	"github.com/dfeyer/flow-debugproxy/pathmapping"

	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
)

const (
	h                = "%s"
	framework        = "flow"
	cachePathPattern = "@base@/Data/Temporary/@context@/Cache/Code/Flow_Object_Classes/@filename@.php"
)

var (
	regexpPhpFile         = regexp.MustCompile(`(?://)?(/[^ ]*\.php)`)
	regexpFilename        = regexp.MustCompile(`filename=["]?file://(\S+)/Data/Temporary/[^/]*/Cache/Code/Flow_Object_Classes/([^"]*)\.php`)
	regexpPathAndFilename = regexp.MustCompile(`(?m)^# PathAndFilename: (.*)$`)
	regexpPackageClass    = regexp.MustCompile(`(.*?)/Packages/(.*?)/Classes/(.*).php`)
	regexpDot             = regexp.MustCompile(`[\./]`)
)

func init() {
	p := &PathMapper{}
	pathmapperfactory.Register(framework, p)
}

// PathMapper handle the mapping between real code and proxy
type PathMapper struct {
	config      *config.Config
	logger      *logger.Logger
	pathMapping *pathmapping.PathMapping
}

// Initialize the path mapper dependencies
func (p *PathMapper) Initialize(c *config.Config, l *logger.Logger, m *pathmapping.PathMapping) {
	p.config = c
	p.logger = l
	p.pathMapping = m
}

// ApplyMappingToTextProtocol change file path in xDebug text protocol
func (p *PathMapper) ApplyMappingToTextProtocol(message []byte) []byte {
	return p.doTextPathMapping(message)
}

// ApplyMappingToXML change file path in xDebug XML protocol
func (p *PathMapper) ApplyMappingToXML(message []byte) []byte {
	message = p.doXMLPathMapping(message)

	// update xml length count
	s := strings.Split(string(message), "\x00")
	i, err := strconv.Atoi(s[0])
	errorhandler.PanicHandling(err, p.logger)
	l := len(s[1])
	if i != l {
		message = bytes.Replace(message, []byte(strconv.Itoa(i)), []byte(strconv.Itoa(l)), 1)
	}

	return message
}

func (p *PathMapper) doTextPathMapping(message []byte) []byte {
	var processedMapping = map[string]string{}
	for _, match := range regexpPhpFile.FindAllStringSubmatch(string(message), -1) {
		originalPath := match[1]
		path := p.mapPath(originalPath)
		p.logger.Debug("doTextPathMapping %s >>> %s", path, originalPath)
		processedMapping[path] = originalPath
	}

	for path, originalPath := range processedMapping {
		message = bytes.Replace(message, []byte(p.getRealFilename(originalPath)), []byte(p.getRealFilename(path)), -1)
	}

	return message
}

func (p *PathMapper) getCachePath(base, filename string) string {
	cachePath := strings.Replace(cachePathPattern, "@base@", base, 1)
	cachePath = strings.Replace(cachePath, "@context@", p.config.Context, 1)
	return strings.Replace(cachePath, "@filename@", filename, 1)
}

func (p *PathMapper) doXMLPathMapping(b []byte) []byte {
	var processedMapping = map[string]string{}
	for _, match := range regexpFilename.FindAllStringSubmatch(string(b), -1) {
		path := p.getCachePath(match[1], match[2])
		if _, ok := processedMapping[path]; ok == false {
			if originalPath, exist := p.pathMapping.Get(path); exist {
				if p.config.VeryVerbose {
					p.logger.Info("Umpa Lumpa can help you, he know the mapping\n%s\n%s\n", p.logger.Colorize(">>> "+fmt.Sprintf(h, path), "yellow"), p.logger.Colorize(">>> "+fmt.Sprintf(h, p.getRealFilename(originalPath)), "green"))
				}
				processedMapping[path] = originalPath
				p.logger.Debug("doXMLPathMapping mapping exist %s >>> %s", path, originalPath)
			} else {
				originalPath = p.readOriginalPathFromCache(path)
				processedMapping[path] = originalPath
				p.logger.Debug("doXMLPathMapping missing mapping %s >>> %s", path, originalPath)
			}
		}
	}

	for path, originalPath := range processedMapping {
		path = p.getRealFilename(path)
		originalPath = p.getRealFilename(originalPath)
		b = bytes.Replace(b, []byte(path), []byte(originalPath), -1)
	}

	return b
}

// getRealFilename removes file:// protocol from the given path
func (p *PathMapper) getRealFilename(path string) string {
	return strings.TrimPrefix(path, "file://")
}

func (p *PathMapper) mapPath(originalPath string) string {
	if strings.Contains(originalPath, "/Packages/") {
		p.logger.Debug("Path %s is a Flow Package file", originalPath)
		cachePath := p.getCachePath(p.buildClassNameFromPath(originalPath))
		realPath := p.getRealFilename(cachePath)
		if _, err := os.Stat(realPath); err == nil {
			return p.setPathMapping(realPath, originalPath)
		}
	}

	return originalPath
}

func (p *PathMapper) setPathMapping(path string, originalPath string) string {
	if p.config.Verbose {
		p.logger.Info(h, "Our Umpa Lumpa take care of your mapping and they did a great job, they found a proxy for you:")
		p.logger.Info(">>> %s\n", path)
	}

	if p.pathMapping.Has(path) == false {
		p.pathMapping.Set(path, originalPath)
	}
	return path
}

func (p *PathMapper) readOriginalPathFromCache(path string) string {
	dat, err := ioutil.ReadFile(path)
	errorhandler.PanicHandling(err, p.logger)
	match := regexpPathAndFilename.FindStringSubmatch(string(dat))
	p.logger.Debug("readOriginalPathFromCache %s", path)
	if len(match) == 2 {
		originalPath := match[1]
		if p.config.VeryVerbose {
			p.logger.Info("Umpa Lumpa need to work harder, need to reverse this one\n>>> %s\n>>> %s\n", p.logger.Colorize(fmt.Sprintf(h, path), "yellow"), p.logger.Colorize(fmt.Sprintf(h, originalPath), "green"))
		}
		p.logger.Debug("readOriginalPathFromCache %s >>> %s", path, originalPath)
		p.setPathMapping(path, originalPath)
		return originalPath
	}
	return path
}

func (p *PathMapper) buildClassNameFromPath(path string) (string, string) {
	var (
		basePath  string
		className string
	)
	match := regexpPackageClass.FindStringSubmatch(path)
	if len(match) == 4 {
		// Flow standard packages
		basePath = match[1]
		className = regexpDot.ReplaceAllString(match[3], "_")
	} else {
		// Other (vendor) packages, todo add support for vendor package with Flow proxy class
		p.logger.Warn(h, "Vendor package detected")
		p.logger.Warn("Class mapping not supported currently for path: %s, \n", path)
		basePath = path
		className = ""
	}
	return basePath, className
}
<|endoftext|>


<commit_before>package consumer

import (
	"flume-bridge/config"
	"flume-bridge/consumer/pool"
	"github.com/garyburd/redigo/redis"
	"github.com/momotech/GoRedis/libs/stdlog"
	"log"
	"math/rand"
	"os"
	"strconv"
	"sync"
	"time"
)

type poolwrapper struct {
	hostport config.HostPort

	rpool *redis.Pool

	lastValue int64

	currValue int64
}

type SourceManager struct {
	zkmanager *config.ZKManager

	sourceServers map[string]*SourceServer //业务名称和sourceserver对应

	hp2flumeClientPool map[config.HostPort]*pool.FlumePoolLink //对应的Pool

	redispool map[string][]*poolwrapper // 对应的redispool

	watcherPool map[string]*config.Watcher //watcherPool

	mutex sync.Mutex

	isRunning bool

	instancename string

	flumeLog         stdlog.Logger
	redisLog         stdlog.Logger
	watcherLog       stdlog.Logger
	flumePoolLog     stdlog.Logger
	flumeSourceLog   stdlog.Logger
	sourceManagerLog stdlog.Logger
	option           *config.Option
}

func NewSourceManager(instancename string, option *config.Option) *SourceManager {

	sourcemanager := &SourceManager{}
	sourcemanager.option = option
	sourcemanager.sourceServers = make(map[string]*SourceServer)
	sourcemanager.hp2flumeClientPool = make(map[config.HostPort]*pool.FlumePoolLink)
	sourcemanager.watcherPool = make(map[string]*config.Watcher)

	//创建使用的Logger
	basepath := option.LogPath + "/" + instancename
	sourcemanager.sourceManagerLog = buildLog(basepath, "source_manager", "source_manager.log")
	sourcemanager.flumeLog = buildLog(basepath, "flume_tps", "flume_tps.log")
	sourcemanager.flumePoolLog = buildLog(basepath, "flume_pool", "flume_pool.log")
	sourcemanager.redisLog = buildLog(basepath, "redis_tps", "redis_tps.log")
	sourcemanager.watcherLog = buildLog(basepath, "zk_watcher", "zk_watcher.log")
	sourcemanager.flumeSourceLog = buildLog(basepath, "flume_source", "flume_source.log")

	sourcemanager.redispool = initRedisQueue(option)
	//从zk中拉取flumenode的配置
	zkmanager := config.NewZKManager(option.Zkhost)
	sourcemanager.zkmanager = zkmanager
	sourcemanager.instancename = instancename

	sourcemanager.initSourceServers(option.Businesses, zkmanager)
	sourcemanager.sourceManagerLog.Println("SOURCE_MANGER|Init SourceManager|Succ...")
	return sourcemanager

}

func buildLog(basepath, logname, filename string) stdlog.Logger {

	_, err := os.Stat(basepath)
	if nil != err {
		err := os.MkdirAll(basepath, os.ModePerm)
		if nil != err {
			panic(err)
		}
	}

	//创建redis的log
	f, err := os.OpenFile(basepath+"/"+filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
	if nil != err {
		panic(err)
	}
	logger := stdlog.Log(logname)
	logger.SetOutput(f)
	logger.SetPrefix(func() string {
		now := time.Now()
		nt := now.Format("2006-01-02 15:04:05")
		return nt + "\t"
	})
	return logger
}

func initRedisQueue(option *config.Option) map[string][]*poolwrapper {
	redispool := make(map[string][]*poolwrapper, 0)

	//创建redis的消费连接
	for _, v := range option.QueueHostPorts {

		hp := v
		pool := redis.NewPool(func() (conn redis.Conn, err error) {
			conn, err = redis.DialTimeout("tcp", hp.Host+":"+strconv.Itoa(hp.Port),
				time.Duration(hp.Timeout)*time.Second,
				time.Duration(hp.Timeout)*time.Second,
				time.Duration(hp.Timeout)*time.Second)

			return
		}, hp.Maxconn/2)

		pools, ok := redispool[v.QueueName]
		if !ok {
			pools = make([]*poolwrapper, 0)
			redispool[v.QueueName] = pools
		}

		poolw := &poolwrapper{}
		poolw.hostport = v.HostPort
		poolw.rpool = pool
		redispool[v.QueueName] = append(pools, poolw)
	}

	return redispool
}

func (self *SourceManager) initSourceServers(businesses []string, zkmanager *config.ZKManager) {

	for _, business := range businesses {
		nodewatcher := newFlumeWatcher(business, self)
		flumeNode := zkmanager.GetAndWatch(business, nodewatcher)
		self.watcherPool[business] = nodewatcher
		sserver := self.initSourceServer(business, flumeNode)
		self.sourceServers[business] = sserver
	}

	//-------------------注册当前进程ID到zk
	currpid := os.Getpid()
	hostname, _ := os.Hostname()
	self.zkmanager.RegistePath(businesses, hostname+"_"+self.instancename+":"+strconv.Itoa(currpid))

}

func (self *SourceManager) initSourceServer(business string, flumenodes []config.HostPort) *SourceServer {

	//首先判断当前是否该sink支持该种business
	_, ok := self.watcherPool[business]
	if !ok {
		self.sourceManagerLog.Printf("unsupport business[%s],HostPorts:[%s]\n", business, flumenodes)
		return nil
	}

	if len(flumenodes) == 0 {
		self.sourceManagerLog.Println("no valid flume agent node for [" + business + "]")
		return nil
	}

	//新增的消费类型
	//使用的pool
	pools := self.initFlumeClientPool(business, flumenodes)

	//创建一个sourceserver
	sourceserver := newSourceServer(business, pools, self.flumeSourceLog)

	return sourceserver
}

func (self *SourceManager) initFlumeClientPool(business string, flumenodes []config.HostPort) []*pool.FlumePoolLink {

	pools := make([]*pool.FlumePoolLink, 0, 10)
	for _, hp := range flumenodes {
		poollink, ok := self.hp2flumeClientPool[hp]
		if !ok {
			err, tmppool := pool.NewFlumePoolLink(hp)
			if nil != err {
				self.sourceManagerLog.Println("SOURCE_MANGER|INIT FLUMEPOOLLINE|FAIL|%s", err)
				continue
			}
			poollink = tmppool
			self.hp2flumeClientPool[hp] = poollink
		}

		defer func() {
			if nil == poollink {
				return
			}
			if err := recover(); nil != err {
				self.sourceManagerLog.Printf("SOURCE_MANGER|CREATE FLUMECLIENT|FAIL|[%s]\n", hp)
				poollink = nil
			}
		}()

		if nil == poollink {
			continue
		}

		poollink.AttachBusiness(business)
		pools = append(pools, poollink)
	}
	self.sourceManagerLog.Printf("SOURCE_MANGER|CREATE FLUMECLIENT|SUCCESS|[%s,%d]\n", business, len(flumenodes))

	return pools
}

func (self *SourceManager) Start() {

	self.sourceManagerLog.Println("SourceManager|Start|Begin...")
	for _, v := range self.sourceServers {
		go v.start()
	}
	self.isRunning = true
	go self.monitor()
	self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|[%s]|STARTED\n", self.instancename)
	self.startWorker()
	self.sourceManagerLog.Println("SourceManager|Start|End...")

}

func (self *SourceManager) startWorker() {
	//k：queuename v:redis hostport
	for k, v := range self.redispool {
		self.sourceManagerLog.Println("LOG_SOURCE_MANGER|REDIS|[" + k + "]|START")
		for _, pool := range v {

			go func(queuename string, pool *poolwrapper) {
				//批量收集数据
				conn := pool.rpool.Get()
				defer conn.Close()
				self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|BEGIN|%s|%s\n", queuename, pool.hostport)
				latch := make(chan byte, 100)
				for self.isRunning {
					reply, err := conn.Do("LPOP", queuename)
					if nil != err || nil == reply {
						if nil != err {
							self.sourceManagerLog.Printf("LPOP|FAIL|%T", err)
							conn.Close()
							conn = pool.rpool.Get()
						} else {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|Sleep|%s|%s\n", queuename, pool.hostport)
							time.Sleep(100 * time.Millisecond)
						}
						continue
					}

					//计数器++
					pool.currValue++
					latch <- 1
					go func(resp []byte) {

						start := time.Now().UnixNano()
						defer func() {
							<-latch
						}()
						if self.option.IsCompress {
							resp = decompress(resp)
						}
						if resp == nil {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|decompress|%s\n", resp)
							return
						}
						businessName, logType, event := decodeCommand(resp)
						if nil == event {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|decodeCommand|%s\n", event)
							return
						}

						//提交到对应business的channel中
						routeKey := businessName + logType
						defaultRoutKey := "default" + logType
						sourceServer, ok := self.sourceServers[routeKey]
						if !ok {
							//use the default channel
							sourceServer, ok := self.sourceServers[defaultRoutKey]
							if ok && nil != sourceServer && !sourceServer.isStop {
								sourceServer.buffChannel <- event
							} else {
								self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|DEFAULT SOURCE_SERVER NOT EXSIT OR STOPPED\n")
							}
						} else {
							if !sourceServer.isStop {
								sourceServer.buffChannel <- event
							} else {
								self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|SOURCE_SERVER STOPPED|%s\n", routeKey)
							}
						}

						end := time.Now().UnixNano()
						if rand.Intn(1000) == 0 {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|Process|Cost:%d\n", end-start)
						}

					}(reply.([]byte))
				}
				self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|EXIT|%s|%s\n", queuename, pool.hostport)
			}(k, pool)

		}
	}

}

func (self *SourceManager) Close() {
	self.isRunning = false

	for _, sourceserver := range self.sourceServers {
		sourceserver.stop()
	}

	for _, redispool := range self.redispool {
		for _, pool := range redispool {
			pool.rpool.Close()
		}
	}

	//关闭flumepool
	for _, flumepool := range self.hp2flumeClientPool {
		flumepool.FlumePool.Destroy()
	}

	log.Printf("LOG_SOURCE_MANGER|[%s]|STOP\n", self.instancename)
}
<commit_msg>	modified:   consumer/log_source_manager.go<commit_after>package consumer

import (
	"flume-bridge/config"
	"flume-bridge/consumer/pool"
	"github.com/garyburd/redigo/redis"
	"github.com/momotech/GoRedis/libs/stdlog"
	"log"
	"math/rand"
	"os"
	"strconv"
	"sync"
	"time"
)

type poolwrapper struct {
	hostport config.HostPort

	rpool *redis.Pool

	lastValue int64

	currValue int64
}

type SourceManager struct {
	zkmanager *config.ZKManager

	sourceServers map[string]*SourceServer //业务名称和sourceserver对应

	hp2flumeClientPool map[config.HostPort]*pool.FlumePoolLink //对应的Pool

	redispool map[string][]*poolwrapper // 对应的redispool

	watcherPool map[string]*config.Watcher //watcherPool

	mutex sync.Mutex

	isRunning bool

	instancename string

	flumeLog         stdlog.Logger
	redisLog         stdlog.Logger
	watcherLog       stdlog.Logger
	flumePoolLog     stdlog.Logger
	flumeSourceLog   stdlog.Logger
	sourceManagerLog stdlog.Logger
	option           *config.Option
}

func NewSourceManager(instancename string, option *config.Option) *SourceManager {

	sourcemanager := &SourceManager{}
	sourcemanager.option = option
	sourcemanager.sourceServers = make(map[string]*SourceServer)
	sourcemanager.hp2flumeClientPool = make(map[config.HostPort]*pool.FlumePoolLink)
	sourcemanager.watcherPool = make(map[string]*config.Watcher)

	//创建使用的Logger
	basepath := option.LogPath + "/" + instancename
	sourcemanager.sourceManagerLog = buildLog(basepath, "source_manager", "source_manager.log")
	sourcemanager.flumeLog = buildLog(basepath, "flume_tps", "flume_tps.log")
	sourcemanager.flumePoolLog = buildLog(basepath, "flume_pool", "flume_pool.log")
	sourcemanager.redisLog = buildLog(basepath, "redis_tps", "redis_tps.log")
	sourcemanager.watcherLog = buildLog(basepath, "zk_watcher", "zk_watcher.log")
	sourcemanager.flumeSourceLog = buildLog(basepath, "flume_source", "flume_source.log")

	sourcemanager.redispool = initRedisQueue(option)
	//从zk中拉取flumenode的配置
	zkmanager := config.NewZKManager(option.Zkhost)
	sourcemanager.zkmanager = zkmanager
	sourcemanager.instancename = instancename

	sourcemanager.initSourceServers(option.Businesses, zkmanager)
	sourcemanager.sourceManagerLog.Println("SOURCE_MANGER|Init SourceManager|Succ...")
	return sourcemanager

}

func buildLog(basepath, logname, filename string) stdlog.Logger {

	_, err := os.Stat(basepath)
	if nil != err {
		err := os.MkdirAll(basepath, os.ModePerm)
		if nil != err {
			panic(err)
		}
	}

	//创建redis的log
	f, err := os.OpenFile(basepath+"/"+filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
	if nil != err {
		panic(err)
	}
	logger := stdlog.Log(logname)
	logger.SetOutput(f)
	logger.SetPrefix(func() string {
		now := time.Now()
		nt := now.Format("2006-01-02 15:04:05")
		return nt + "\t"
	})
	return logger
}

func initRedisQueue(option *config.Option) map[string][]*poolwrapper {
	redispool := make(map[string][]*poolwrapper, 0)

	//创建redis的消费连接
	for _, v := range option.QueueHostPorts {

		hp := v
		pool := redis.NewPool(func() (conn redis.Conn, err error) {
			conn, err = redis.DialTimeout("tcp", hp.Host+":"+strconv.Itoa(hp.Port),
				time.Duration(hp.Timeout)*time.Second,
				time.Duration(hp.Timeout)*time.Second,
				time.Duration(hp.Timeout)*time.Second)

			return
		}, hp.Maxconn/2)

		pools, ok := redispool[v.QueueName]
		if !ok {
			pools = make([]*poolwrapper, 0)
			redispool[v.QueueName] = pools
		}

		poolw := &poolwrapper{}
		poolw.hostport = v.HostPort
		poolw.rpool = pool
		redispool[v.QueueName] = append(pools, poolw)
	}

	return redispool
}

func (self *SourceManager) initSourceServers(businesses []string, zkmanager *config.ZKManager) {

	for _, business := range businesses {
		nodewatcher := newFlumeWatcher(business, self)
		flumeNode := zkmanager.GetAndWatch(business, nodewatcher)
		self.watcherPool[business] = nodewatcher
		sserver := self.initSourceServer(business, flumeNode)
		self.sourceServers[business] = sserver
	}

	//-------------------注册当前进程ID到zk
	currpid := os.Getpid()
	hostname, _ := os.Hostname()
	self.zkmanager.RegistePath(businesses, hostname+"_"+self.instancename+":"+strconv.Itoa(currpid))

}

func (self *SourceManager) initSourceServer(business string, flumenodes []config.HostPort) *SourceServer {

	//首先判断当前是否该sink支持该种business
	_, ok := self.watcherPool[business]
	if !ok {
		self.sourceManagerLog.Printf("unsupport business[%s],HostPorts:[%s]\n", business, flumenodes)
		return nil
	}

	if len(flumenodes) == 0 {
		self.sourceManagerLog.Println("no valid flume agent node for [" + business + "]")
		return nil
	}

	//新增的消费类型
	//使用的pool
	pools := self.initFlumeClientPool(business, flumenodes)

	//创建一个sourceserver
	sourceserver := newSourceServer(business, pools, self.flumeSourceLog)

	return sourceserver
}

func (self *SourceManager) initFlumeClientPool(business string, flumenodes []config.HostPort) []*pool.FlumePoolLink {

	pools := make([]*pool.FlumePoolLink, 0, 10)
	for _, hp := range flumenodes {
		poollink, ok := self.hp2flumeClientPool[hp]
		if !ok {
			err, tmppool := pool.NewFlumePoolLink(hp)
			if nil != err {
				self.sourceManagerLog.Println("SOURCE_MANGER|INIT FLUMEPOOLLINE|FAIL|%s", err)
				continue
			}
			poollink = tmppool
			self.hp2flumeClientPool[hp] = poollink
		}

		defer func() {
			if nil == poollink {
				return
			}
			if err := recover(); nil != err {
				self.sourceManagerLog.Printf("SOURCE_MANGER|CREATE FLUMECLIENT|FAIL|[%s]\n", hp)
				poollink = nil
			}
		}()

		if nil == poollink {
			continue
		}

		poollink.AttachBusiness(business)
		pools = append(pools, poollink)
	}
	self.sourceManagerLog.Printf("SOURCE_MANGER|CREATE FLUMECLIENT|SUCCESS|[%s,%d]\n", business, len(flumenodes))

	return pools
}

func (self *SourceManager) Start() {

	self.sourceManagerLog.Println("SourceManager|Start|Begin...")
	for _, v := range self.sourceServers {
		go v.start()
	}
	self.isRunning = true
	go self.monitor()
	self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|[%s]|STARTED\n", self.instancename)
	self.startWorker()
	self.sourceManagerLog.Println("SourceManager|Start|End...")

}

func (self *SourceManager) startWorker() {
	//k：queuename v:redis hostport
	for k, v := range self.redispool {
		self.sourceManagerLog.Println("LOG_SOURCE_MANGER|REDIS|[" + k + "]|START")
		for _, pool := range v {

			go func(queuename string, pool *poolwrapper) {
				//批量收集数据
				conn := pool.rpool.Get()
				defer conn.Close()
				self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|BEGIN|%s|%s\n", queuename, pool.hostport)
				latch := make(chan byte, 100)
				for self.isRunning {
					reply, err := conn.Do("LPOP", queuename)
					if nil != err || nil == reply {
						if nil != err {
							self.sourceManagerLog.Printf("LPOP|FAIL|%T", err)
							conn.Close()
							conn = pool.rpool.Get()
						} else {
							// self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|Sleep|%s|%s\n", queuename, pool.hostport)
							time.Sleep(10 * time.Millisecond)
						}
						continue
					}

					//计数器++
					pool.currValue++
					latch <- 1
					go func(resp []byte) {

						start := time.Now().UnixNano()
						defer func() {
							<-latch
						}()
						if self.option.IsCompress {
							resp = decompress(resp)
						}
						if resp == nil {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|decompress|%s\n", resp)
							return
						}
						businessName, logType, event := decodeCommand(resp)
						if nil == event {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|decodeCommand|%s\n", event)
							return
						}

						//提交到对应business的channel中
						routeKey := businessName + logType
						defaultRoutKey := "default" + logType
						sourceServer, ok := self.sourceServers[routeKey]
						if !ok {
							//use the default channel
							sourceServer, ok := self.sourceServers[defaultRoutKey]
							if ok && nil != sourceServer && !sourceServer.isStop {
								sourceServer.buffChannel <- event
							} else {
								self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|DEFAULT SOURCE_SERVER NOT EXSIT OR STOPPED\n")
							}
						} else {
							if !sourceServer.isStop {
								sourceServer.buffChannel <- event
							} else {
								self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|SOURCE_SERVER STOPPED|%s\n", routeKey)
							}
						}

						end := time.Now().UnixNano()
						if rand.Intn(1000) == 0 {
							self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|Process|Cost:%d\n", end-start)
						}

					}(reply.([]byte))
				}
				self.sourceManagerLog.Printf("LOG_SOURCE_MANGER|REDIS-POP|EXIT|%s|%s\n", queuename, pool.hostport)
			}(k, pool)

		}
	}

}

func (self *SourceManager) Close() {
	self.isRunning = false

	for _, sourceserver := range self.sourceServers {
		sourceserver.stop()
	}

	for _, redispool := range self.redispool {
		for _, pool := range redispool {
			pool.rpool.Close()
		}
	}

	//关闭flumepool
	for _, flumepool := range self.hp2flumeClientPool {
		flumepool.FlumePool.Destroy()
	}

	log.Printf("LOG_SOURCE_MANGER|[%s]|STOP\n", self.instancename)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/appleboy/drone-facebook/template"
	"github.com/line/line-bot-sdk-go/linebot"
)

const defaultPreviewImageURL = "https://cdn4.iconfinder.com/data/icons/miu/24/device-camera-recorder-video-glyph-256.png"

type (
	// Repo information.
	Repo struct {
		Owner string
		Name  string
	}

	// Build information.
	Build struct {
		Event    string
		Number   int
		Commit   string
		Branch   string
		Author   string
		Email    string
		Message  string
		Status   string
		Link     string
		Started  float64
		Finished float64
	}

	// Config for the plugin.
	Config struct {
		ChannelToken  string
		ChannelSecret string
		To            []string
		Delimiter     string
		Message       []string
		Image         []string
		Video         []string
		Audio         []string
		Sticker       []string
		Location      []string
		MatchEmail    bool
	}

	// Plugin values.
	Plugin struct {
		Repo   Repo
		Build  Build
		Config Config
	}

	// Audio format
	Audio struct {
		URL      string
		Duration int
	}

	// Location format
	Location struct {
		Title     string
		Address   string
		Latitude  float64
		Longitude float64
	}
)

func trimElement(keys []string) []string {
	var newKeys []string

	for _, value := range keys {
		value = strings.Trim(value, " ")
		if len(value) == 0 {
			continue
		}
		newKeys = append(newKeys, value)
	}

	return newKeys
}

func convertImage(value, delimiter string) []string {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		values = append(values, values[0])
	}

	return values
}

func convertVideo(value, delimiter string) []string {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		values = append(values, defaultPreviewImageURL)
	}

	return values
}

func convertAudio(value, delimiter string) (Audio, bool) {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		return Audio{}, true
	}

	duration, err := strconv.Atoi(values[1])

	if err != nil {
		log.Println(err.Error())
		return Audio{}, true
	}

	return Audio{
		URL:      values[0],
		Duration: duration,
	}, false
}

func convertSticker(value, delimiter string) ([]string, bool) {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		return []string{}, true
	}

	return values, false
}

func convertLocation(value, delimiter string) (Location, bool) {
	var latitude, longitude float64
	var err error
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 4 {
		return Location{}, true
	}

	latitude, err = strconv.ParseFloat(values[2], 64)

	if err != nil {
		log.Println(err.Error())
		return Location{}, true
	}

	longitude, err = strconv.ParseFloat(values[3], 64)

	if err != nil {
		log.Println(err.Error())
		return Location{}, true
	}

	return Location{
		Title:     values[0],
		Address:   values[1],
		Latitude:  latitude,
		Longitude: longitude,
	}, false
}

func parseTo(to []string, authorEmail string, matchEmail bool, delimiter string) []string {
	var emails []string
	var ids []string
	attachEmail := true

	for _, value := range to {
		idArray := trimElement(strings.Split(value, delimiter))

		// check match author email
		if len(idArray) > 1 {
			if email := idArray[1]; email != authorEmail {
				continue
			}

			emails = append(emails, idArray[0])
			attachEmail = false
			continue
		}

		ids = append(ids, idArray[0])
	}

	if matchEmail == true && attachEmail == false {
		return emails
	}

	for _, value := range emails {
		ids = append(ids, value)
	}

	return ids
}

// Exec executes the plugin.
func (p Plugin) Exec() error {

	if len(p.Config.ChannelToken) == 0 || len(p.Config.ChannelSecret) == 0 {
		log.Println("missing line bot config")

		return errors.New("missing line bot config")
	}

	bot, _ := linebot.New(p.Config.ChannelSecret, p.Config.ChannelToken)

	if len(p.Config.To) == 0 {
		log.Println("missing line user config")

		return errors.New("missing line user config")
	}

	var message []string
	if len(p.Config.Message) > 0 {
		message = p.Config.Message
	} else {
		message = p.Message(p.Repo, p.Build)
	}

	// Initial messages array.
	var messages []linebot.Message

	for _, value := range trimElement(message) {
		txt, err := template.RenderTrim(value, p)
		if err != nil {
			return err
		}

		messages = append(messages, linebot.NewTextMessage(txt))
	}

	// Add image message
	for _, value := range trimElement(p.Config.Image) {
		values := convertImage(value, p.Config.Delimiter)

		messages = append(messages, linebot.NewImageMessage(values[0], values[1]))
	}

	// Add image message.
	for _, value := range trimElement(p.Config.Video) {
		values := convertVideo(value, p.Config.Delimiter)

		messages = append(messages, linebot.NewVideoMessage(values[0], values[1]))
	}

	// Add Audio message.
	for _, value := range trimElement(p.Config.Audio) {
		audio, empty := convertAudio(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewAudioMessage(audio.URL, audio.Duration))
	}

	// Add Sticker message.
	for _, value := range trimElement(p.Config.Sticker) {
		sticker, empty := convertSticker(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewStickerMessage(sticker[0], sticker[1]))
	}

	// check Location array.
	for _, value := range trimElement(p.Config.Location) {
		location, empty := convertLocation(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewLocationMessage(location.Title, location.Address, location.Latitude, location.Longitude))
	}

	ids := parseTo(p.Config.To, p.Build.Email, p.Config.MatchEmail, p.Config.Delimiter)

	// send message to user
	for _, id := range ids {
		if _, err := bot.PushMessage(id, messages...).Do(); err != nil {
			log.Println(err.Error())
		}
	}

	return nil
}

// Message is line default message.
func (p Plugin) Message(repo Repo, build Build) []string {
	return []string{fmt.Sprintf("[%s] <%s> (%s)『%s』by %s",
		build.Status,
		build.Link,
		build.Branch,
		build.Message,
		build.Author,
	)}
}
<commit_msg>test<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/appleboy/drone-facebook/template"
	"github.com/line/line-bot-sdk-go/linebot"
)

const defaultPreviewImageURL = "https://cdn4.iconfinder.com/data/icons/miu/24/device-camera-recorder-video-glyph-256.png"

type (
	// Repo information.
	Repo struct {
		Owner string
		Name  string
	}

	// Build information.
	Build struct {
		Event    string
		Number   int
		Commit   string
		Branch   string
		Author   string
		Email    string
		Message  string
		Status   string
		Link     string
		Started  float64
		Finished float64
	}

	// Config for the plugin.
	Config struct {
		ChannelToken  string
		ChannelSecret string
		To            []string
		Delimiter     string
		Message       []string
		Image         []string
		Video         []string
		Audio         []string
		Sticker       []string
		Location      []string
		MatchEmail    bool
	}

	// Plugin values.
	Plugin struct {
		Repo   Repo
		Build  Build
		Config Config
	}

	// Audio format
	Audio struct {
		URL      string
		Duration int
	}

	// Location format
	Location struct {
		Title     string
		Address   string
		Latitude  float64
		Longitude float64
	}
)

func trimElement(keys []string) []string {
	var newKeys []string

	for _, value := range keys {
		value = strings.Trim(value, " ")
		if len(value) == 0 {
			continue
		}
		newKeys = append(newKeys, value)
	}

	return newKeys
}

func convertImage(value, delimiter string) []string {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		values = append(values, values[0])
	}

	return values
}

func convertVideo(value, delimiter string) []string {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		values = append(values, defaultPreviewImageURL)
	}

	return values
}

func convertAudio(value, delimiter string) (Audio, bool) {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		return Audio{}, true
	}

	duration, err := strconv.Atoi(values[1])

	if err != nil {
		log.Println(err.Error())
		return Audio{}, true
	}

	return Audio{
		URL:      values[0],
		Duration: duration,
	}, false
}

func convertSticker(value, delimiter string) ([]string, bool) {
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 2 {
		return []string{}, true
	}

	return values, false
}

func convertLocation(value, delimiter string) (Location, bool) {
	var latitude, longitude float64
	var err error
	values := trimElement(strings.Split(value, delimiter))

	if len(values) < 4 {
		return Location{}, true
	}

	latitude, err = strconv.ParseFloat(values[2], 64)

	if err != nil {
		log.Println(err.Error())
		return Location{}, true
	}

	longitude, err = strconv.ParseFloat(values[3], 64)

	if err != nil {
		log.Println(err.Error())
		return Location{}, true
	}

	return Location{
		Title:     values[0],
		Address:   values[1],
		Latitude:  latitude,
		Longitude: longitude,
	}, false
}

func parseTo(to []string, authorEmail string, matchEmail bool, delimiter string) []string {
	var emails []string
	var ids []string
	attachEmail := true

	for _, value := range to {
		idArray := trimElement(strings.Split(value, delimiter))

		// check match author email
		if len(idArray) > 1 {
			if email := idArray[1]; email != authorEmail {
				continue
			}

			emails = append(emails, idArray[0])
			attachEmail = false
			continue
		}

		log.Println(idArray[0])
		ids = append(ids, idArray[0])
	}

	if matchEmail == true && attachEmail == false {
		return emails
	}

	for _, value := range emails {
		ids = append(ids, value)
	}

	return ids
}

// Exec executes the plugin.
func (p Plugin) Exec() error {

	if len(p.Config.ChannelToken) == 0 || len(p.Config.ChannelSecret) == 0 {
		log.Println("missing line bot config")

		return errors.New("missing line bot config")
	}

	bot, _ := linebot.New(p.Config.ChannelSecret, p.Config.ChannelToken)

	if len(p.Config.To) == 0 {
		log.Println("missing line user config")

		return errors.New("missing line user config")
	}

	var message []string
	if len(p.Config.Message) > 0 {
		message = p.Config.Message
	} else {
		message = p.Message(p.Repo, p.Build)
	}

	// Initial messages array.
	var messages []linebot.Message

	for _, value := range trimElement(message) {
		txt, err := template.RenderTrim(value, p)
		if err != nil {
			return err
		}

		messages = append(messages, linebot.NewTextMessage(txt))
	}

	// Add image message
	for _, value := range trimElement(p.Config.Image) {
		values := convertImage(value, p.Config.Delimiter)

		messages = append(messages, linebot.NewImageMessage(values[0], values[1]))
	}

	// Add image message.
	for _, value := range trimElement(p.Config.Video) {
		values := convertVideo(value, p.Config.Delimiter)

		messages = append(messages, linebot.NewVideoMessage(values[0], values[1]))
	}

	// Add Audio message.
	for _, value := range trimElement(p.Config.Audio) {
		audio, empty := convertAudio(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewAudioMessage(audio.URL, audio.Duration))
	}

	// Add Sticker message.
	for _, value := range trimElement(p.Config.Sticker) {
		sticker, empty := convertSticker(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewStickerMessage(sticker[0], sticker[1]))
	}

	// check Location array.
	for _, value := range trimElement(p.Config.Location) {
		location, empty := convertLocation(value, p.Config.Delimiter)

		if empty == true {
			continue
		}

		messages = append(messages, linebot.NewLocationMessage(location.Title, location.Address, location.Latitude, location.Longitude))
	}

	ids := parseTo(p.Config.To, p.Build.Email, p.Config.MatchEmail, p.Config.Delimiter)

	// send message to user
	for _, id := range ids {
		if _, err := bot.PushMessage(id, messages...).Do(); err != nil {
			log.Println(err.Error())
		}
	}

	return nil
}

// Message is line default message.
func (p Plugin) Message(repo Repo, build Build) []string {
	return []string{fmt.Sprintf("[%s] <%s> (%s)『%s』by %s",
		build.Status,
		build.Link,
		build.Branch,
		build.Message,
		build.Author,
	)}
}
<|endoftext|>


<commit_before>package handler

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

	"github.com/drone/drone/plugin/remote"
	"github.com/drone/drone/server/datastore"
	"github.com/drone/drone/shared/httputil"
	"github.com/drone/drone/shared/model"
	"github.com/drone/drone/shared/sshutil"
	"github.com/goji/context"
	"github.com/zenazn/goji/web"
)

// GetRepo accepts a request to retrieve a commit
// from the datastore for the given repository, branch and
// commit hash.
//
//     GET /api/repos/:host/:owner/:name
//
func GetRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var (
		role = ToRole(c)
		repo = ToRepo(c)
	)

	// if the user is not requesting (or cannot access)
	// admin data then we just return the repo as-is
	if role.Admin == false {
		json.NewEncoder(w).Encode(struct {
			*model.Repo
			Perm      *model.Perm `json:"role"`
		}{repo, role})
		return
	}

	// else we should return restricted fields
	json.NewEncoder(w).Encode(struct {
		*model.Repo
		PublicKey string      `json:"public_key"`
		Params    string      `json:"params"`
		Perm      *model.Perm `json:"role"`
	}{repo, repo.PublicKey, repo.Params, role})
}

// DelRepo accepts a request to delete the named
// repository.
//
//     DEL /api/repos/:host/:owner/:name
//
func DelRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)

	// completely remove the repository from the database
	var user = ToUser(c)
	var remote = remote.Lookup(repo.Host)
	if remote == nil {
		log.Printf("[ERROR] no remote for host '%s' found", repo.Host)
	} else {
		// Request a new token and update
		user_token, err := remote.GetToken(user)
		if err != nil {
			log.Printf("[ERROR] no token for user '%s' on remote '%s' ", user.Email, repo.Host)
		} else {
			if user_token != nil {
				user.Access = user_token.AccessToken
				user.Secret = user_token.RefreshToken
				user.TokenExpiry = user_token.Expiry
				datastore.PutUser(ctx, user)
			}
			// setup the post-commit hook with the remote system and
			// and deactiveate this hook/user on the remote system
			var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token)
			if err := remote.Deactivate(user, repo, hook); err != nil {
				log.Printf("[ERROR] deactivate on remote '%s' failed: %s", repo.Host, err)
			}
		}
	}
	// fail through: if any of the actions on the remote failed
	// we try to delete the repo in our datastore anyway
	if err := datastore.DelRepo(ctx, repo); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNoContent)
	}
}

// DeactivateRepo accepts a request to deactivate the named
// repository. This will disable all builds in the system
// for this repository.
//
//     POST /api/repos/:host/:owner/:name/deactivate
//
func DeactivateRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)

	// disable everything
	repo.Active = false
	repo.PullRequest = false
	repo.PostCommit = false
	repo.UserID = 0

	if err := datastore.PutRepo(ctx, repo); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	json.NewEncoder(w).Encode(repo)
}

// PostRepo accapets a request to activate the named repository
// in the datastore. It returns a 201 status created if successful
//
//     POST /api/repos/:host/:owner/:name
//
func PostRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)
	var user = ToUser(c)

	// update the repo active flag and fields
	repo.Active = true
	repo.PullRequest = true
	repo.PostCommit = true
	repo.UserID = user.ID
	repo.Timeout = 3600 // default to 1 hour

	// generate a secret key for post-commit hooks
	if len(repo.Token) == 0 {
		repo.Token = model.GenerateToken()
	}

	// generates the rsa key
	if len(repo.PublicKey) == 0 || len(repo.PrivateKey) == 0 {
		key, err := sshutil.GeneratePrivateKey()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		repo.PublicKey = sshutil.MarshalPublicKey(&key.PublicKey)
		repo.PrivateKey = sshutil.MarshalPrivateKey(key)
	}

	var remote = remote.Lookup(repo.Host)
	if remote == nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	// Request a new token and update
	user_token, err := remote.GetToken(user)
	if user_token != nil {
		user.Access = user_token.AccessToken
		user.Secret = user_token.RefreshToken
		user.TokenExpiry = user_token.Expiry
		datastore.PutUser(ctx, user)
	} else if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// setup the post-commit hook with the remote system and
	// if necessary, register the public key
	var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token)
	if err := remote.Activate(user, repo, hook); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if err := datastore.PutRepo(ctx, repo); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(repo)
}

// PutRepo accapets a request to update the named repository
// in the datastore. It expects a JSON input and returns the
// updated repository in JSON format if successful.
//
//     PUT /api/repos/:host/:owner/:name
//
func PutRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)
	var user = ToUser(c)

	// unmarshal the repository from the payload
	defer r.Body.Close()
	in := struct {
		PostCommit  *bool   `json:"post_commits"`
		PullRequest *bool   `json:"pull_requests"`
		Privileged  *bool   `json:"privileged"`
		Params      *string `json:"params"`
		Timeout     *int64  `json:"timeout"`
		PublicKey   *string `json:"public_key"`
		PrivateKey  *string `json:"private_key"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if in.Params != nil {
		repo.Params = *in.Params
		if _, err := repo.ParamMap(); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}
	if in.PostCommit != nil {
		repo.PostCommit = *in.PostCommit
	}
	if in.PullRequest != nil {
		repo.PullRequest = *in.PullRequest
	}
	if in.Privileged != nil && user.Admin {
		repo.Privileged = *in.Privileged
	}
	if in.Timeout != nil && user.Admin {
		repo.Timeout = *in.Timeout
	}
	if in.PrivateKey != nil && in.PublicKey != nil {
		repo.PublicKey = *in.PublicKey
		repo.PrivateKey = *in.PrivateKey
	}
	if err := datastore.PutRepo(ctx, repo); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	json.NewEncoder(w).Encode(repo)
}
<commit_msg>Fixing formatting with gofmt<commit_after>package handler

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

	"github.com/drone/drone/plugin/remote"
	"github.com/drone/drone/server/datastore"
	"github.com/drone/drone/shared/httputil"
	"github.com/drone/drone/shared/model"
	"github.com/drone/drone/shared/sshutil"
	"github.com/goji/context"
	"github.com/zenazn/goji/web"
)

// GetRepo accepts a request to retrieve a commit
// from the datastore for the given repository, branch and
// commit hash.
//
//     GET /api/repos/:host/:owner/:name
//
func GetRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var (
		role = ToRole(c)
		repo = ToRepo(c)
	)

	// if the user is not requesting (or cannot access)
	// admin data then we just return the repo as-is
	if role.Admin == false {
		json.NewEncoder(w).Encode(struct {
			*model.Repo
			Perm *model.Perm `json:"role"`
		}{repo, role})
		return
	}

	// else we should return restricted fields
	json.NewEncoder(w).Encode(struct {
		*model.Repo
		PublicKey string      `json:"public_key"`
		Params    string      `json:"params"`
		Perm      *model.Perm `json:"role"`
	}{repo, repo.PublicKey, repo.Params, role})
}

// DelRepo accepts a request to delete the named
// repository.
//
//     DEL /api/repos/:host/:owner/:name
//
func DelRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)

	// completely remove the repository from the database
	var user = ToUser(c)
	var remote = remote.Lookup(repo.Host)
	if remote == nil {
		log.Printf("[ERROR] no remote for host '%s' found", repo.Host)
	} else {
		// Request a new token and update
		user_token, err := remote.GetToken(user)
		if err != nil {
			log.Printf("[ERROR] no token for user '%s' on remote '%s' ", user.Email, repo.Host)
		} else {
			if user_token != nil {
				user.Access = user_token.AccessToken
				user.Secret = user_token.RefreshToken
				user.TokenExpiry = user_token.Expiry
				datastore.PutUser(ctx, user)
			}
			// setup the post-commit hook with the remote system and
			// and deactiveate this hook/user on the remote system
			var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token)
			if err := remote.Deactivate(user, repo, hook); err != nil {
				log.Printf("[ERROR] deactivate on remote '%s' failed: %s", repo.Host, err)
			}
		}
	}
	// fail through: if any of the actions on the remote failed
	// we try to delete the repo in our datastore anyway
	if err := datastore.DelRepo(ctx, repo); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNoContent)
	}
}

// DeactivateRepo accepts a request to deactivate the named
// repository. This will disable all builds in the system
// for this repository.
//
//     POST /api/repos/:host/:owner/:name/deactivate
//
func DeactivateRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)

	// disable everything
	repo.Active = false
	repo.PullRequest = false
	repo.PostCommit = false
	repo.UserID = 0

	if err := datastore.PutRepo(ctx, repo); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	json.NewEncoder(w).Encode(repo)
}

// PostRepo accapets a request to activate the named repository
// in the datastore. It returns a 201 status created if successful
//
//     POST /api/repos/:host/:owner/:name
//
func PostRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)
	var user = ToUser(c)

	// update the repo active flag and fields
	repo.Active = true
	repo.PullRequest = true
	repo.PostCommit = true
	repo.UserID = user.ID
	repo.Timeout = 3600 // default to 1 hour

	// generate a secret key for post-commit hooks
	if len(repo.Token) == 0 {
		repo.Token = model.GenerateToken()
	}

	// generates the rsa key
	if len(repo.PublicKey) == 0 || len(repo.PrivateKey) == 0 {
		key, err := sshutil.GeneratePrivateKey()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		repo.PublicKey = sshutil.MarshalPublicKey(&key.PublicKey)
		repo.PrivateKey = sshutil.MarshalPrivateKey(key)
	}

	var remote = remote.Lookup(repo.Host)
	if remote == nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	// Request a new token and update
	user_token, err := remote.GetToken(user)
	if user_token != nil {
		user.Access = user_token.AccessToken
		user.Secret = user_token.RefreshToken
		user.TokenExpiry = user_token.Expiry
		datastore.PutUser(ctx, user)
	} else if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// setup the post-commit hook with the remote system and
	// if necessary, register the public key
	var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token)
	if err := remote.Activate(user, repo, hook); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if err := datastore.PutRepo(ctx, repo); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(repo)
}

// PutRepo accapets a request to update the named repository
// in the datastore. It expects a JSON input and returns the
// updated repository in JSON format if successful.
//
//     PUT /api/repos/:host/:owner/:name
//
func PutRepo(c web.C, w http.ResponseWriter, r *http.Request) {
	var ctx = context.FromC(c)
	var repo = ToRepo(c)
	var user = ToUser(c)

	// unmarshal the repository from the payload
	defer r.Body.Close()
	in := struct {
		PostCommit  *bool   `json:"post_commits"`
		PullRequest *bool   `json:"pull_requests"`
		Privileged  *bool   `json:"privileged"`
		Params      *string `json:"params"`
		Timeout     *int64  `json:"timeout"`
		PublicKey   *string `json:"public_key"`
		PrivateKey  *string `json:"private_key"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if in.Params != nil {
		repo.Params = *in.Params
		if _, err := repo.ParamMap(); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}
	if in.PostCommit != nil {
		repo.PostCommit = *in.PostCommit
	}
	if in.PullRequest != nil {
		repo.PullRequest = *in.PullRequest
	}
	if in.Privileged != nil && user.Admin {
		repo.Privileged = *in.Privileged
	}
	if in.Timeout != nil && user.Admin {
		repo.Timeout = *in.Timeout
	}
	if in.PrivateKey != nil && in.PublicKey != nil {
		repo.PublicKey = *in.PublicKey
		repo.PrivateKey = *in.PrivateKey
	}
	if err := datastore.PutRepo(ctx, repo); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	json.NewEncoder(w).Encode(repo)
}
<|endoftext|>


<commit_before>package service

import (
	"github.com/golang/glog"
	"github.com/yangsf5/claw/center"

	"github.com/yangsf5/moba/server/proto"
	"github.com/yangsf5/moba/server/service/room"
)

type Room struct {
	name      string
	logicRoom *room.Room
}

func (s *Room) ClawCallback(session int, source string, msgType int, msg interface{}) {
	glog.Infof("Service.%s recv session=%d type=%v msg=%v", s.name, session, msgType, msg)
	switch msgType {
	case center.MsgTypeSystem:
		if user, ok := msg.(room.User); ok {
			if ret := s.logicRoom.Enter(session, user); !ret {
				glog.Infof("Service.%s enter room failed", s.name)
				return
			}
			center.Send(s.name, "MobaHall", session, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), s.logicRoom.GetCurrentPlayerCount()})
			glog.Infof("Service.%s enter room userName=%s", s.name, user.Name())
		} else {
			glog.Infof("Service.%s msg is not a net.Peer", s.name)
		}
	case center.MsgTypeText:
		if msg, ok := msg.(string); ok {
			if msg == "LEAVE" {
				s.logicRoom.Leave(session)
				center.Send(s.name, "MobaHall", 0, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), s.logicRoom.GetCurrentPlayerCount()})
			}
		}
	case center.MsgTypeClient:
		if pack, ok := msg.(*proto.Pack); ok {
			s.logicRoom.HandleClientMessage(session, pack.Type, pack.Data)
		} else {
			glog.Errorf("Service.%s MsgTypeClient msg is not a *proto.Pack", s.name)
		}
	}
}

func (s *Room) ClawStart() {
	glog.Infof("%s service start", s.name)
	// 向Hall汇报自己的初始信息
	center.Send(s.name, "MobaHall", 0, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), 0})
}

func NewRoomService(roomID int, roomServiceName string) *Room {
	roomService := &Room{}
	r := room.NewRoom(roomID, roomServiceName)
	roomService.logicRoom = r
	roomService.name = roomServiceName
	return roomService
}
<commit_msg>有玩家离开时服务器也通知下客户端新人员清单；当前客户端没有好的方式来去除离开的人的控件<commit_after>package service

import (
	"github.com/golang/glog"
	"github.com/yangsf5/claw/center"

	"github.com/yangsf5/moba/server/proto"
	"github.com/yangsf5/moba/server/service/room"
)

type Room struct {
	name      string
	logicRoom *room.Room
}

func (s *Room) ClawCallback(session int, source string, msgType int, msg interface{}) {
	glog.Infof("Service.%s recv session=%d type=%v msg=%v", s.name, session, msgType, msg)
	switch msgType {
	case center.MsgTypeSystem:
		if user, ok := msg.(room.User); ok {
			if ret := s.logicRoom.Enter(session, user); !ret {
				glog.Infof("Service.%s enter room failed", s.name)
				return
			}
			center.Send(s.name, "MobaHall", session, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), s.logicRoom.GetCurrentPlayerCount()})
			glog.Infof("Service.%s enter room userName=%s", s.name, user.Name())
		} else {
			glog.Infof("Service.%s msg is not a net.Peer", s.name)
		}
	case center.MsgTypeText:
		if msg, ok := msg.(string); ok {
			if msg == "LEAVE" {
				s.logicRoom.Leave(session)
				s.logicRoom.NotifyHCPlayerInfos()
				center.Send(s.name, "MobaHall", 0, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), s.logicRoom.GetCurrentPlayerCount()})
			}
		}
	case center.MsgTypeClient:
		if pack, ok := msg.(*proto.Pack); ok {
			s.logicRoom.HandleClientMessage(session, pack.Type, pack.Data)
		} else {
			glog.Errorf("Service.%s MsgTypeClient msg is not a *proto.Pack", s.name)
		}
	}
}

func (s *Room) ClawStart() {
	glog.Infof("%s service start", s.name)
	// 向Hall汇报自己的初始信息
	center.Send(s.name, "MobaHall", 0, center.MsgTypeSystem, &proto.RoomInfo{s.logicRoom.GetMaxPlayerCount(), 0})
}

func NewRoomService(roomID int, roomServiceName string) *Room {
	roomService := &Room{}
	r := room.NewRoom(roomID, roomServiceName)
	roomService.logicRoom = r
	roomService.name = roomServiceName
	return roomService
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package table

import (
	"encoding/binary"

	"code.google.com/p/snappy-go/snappy"

	"github.com/syndtr/goleveldb/leveldb/block"
	"github.com/syndtr/goleveldb/leveldb/comparer"
	"github.com/syndtr/goleveldb/leveldb/filter"
	"github.com/syndtr/goleveldb/leveldb/hash"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

const (
	// Written to disk; don't modify.
	kNoCompression     = 0
	kSnappyCompression = 1
)

// Writer represent a table writer.
type Writer struct {
	w      storage.Writer
	o      opt.OptionsGetter
	cmp    comparer.Comparer
	filter filter.Filter

	dataBlock   *block.Writer
	indexBlock  *block.Writer
	filterBlock *block.FilterWriter

	n, off int
	lkey   []byte // last key
	lblock *bInfo // last block
	pindex bool   // pending index

	closed bool
}

// NewWriter create new initialized table writer.
func NewWriter(w storage.Writer, o opt.OptionsGetter) *Writer {
	t := &Writer{w: w, o: o, cmp: o.GetComparer()}
	// Creating blocks
	t.dataBlock = block.NewWriter(o.GetBlockRestartInterval())
	t.indexBlock = block.NewWriter(1)
	t.filter = o.GetFilter()
	if t.filter != nil {
		t.filterBlock = block.NewFilterWriter(t.filter)
		t.filterBlock.Generate(0)
	}
	t.lblock = new(bInfo)
	return t
}

// Add append key/value to the table.
func (t *Writer) Add(key, value []byte) (err error) {
	if t.closed {
		panic("operation on closed table writer")
	}

	if t.pindex {
		// write the pending index
		sep := t.cmp.Separator(t.lkey, key)
		t.indexBlock.Add(sep, t.lblock.encode())
		t.pindex = false
	}

	if t.filterBlock != nil {
		t.filterBlock.Add(key)
	}

	t.lkey = key
	t.n++

	t.dataBlock.Add(key, value)
	if t.dataBlock.Size() >= t.o.GetBlockSize() {
		err = t.Flush()
	}
	return
}

// Flush finalize and write the data block.
func (t *Writer) Flush() (err error) {
	if t.closed {
		panic("operation on closed table writer")
	}

	if t.pindex {
		return
	}

	err = t.write(t.dataBlock.Finish(), t.lblock, false)
	if err != nil {
		return
	}
	t.dataBlock.Reset()

	t.pindex = true

	if t.filterBlock != nil {
		t.filterBlock.Generate(t.off)
	}
	return
}

// Finish finalize the table. No Add(), Flush() or Finish() is possible
// beyond this, doing so will raise panic.
func (t *Writer) Finish() (err error) {
	if t.closed {
		panic("operation on closed table writer")
	}

	err = t.Flush()
	if err != nil {
		return
	}

	t.closed = true

	// Write filter block
	fi := new(bInfo)
	if t.filterBlock != nil {
		err = t.write(t.filterBlock.Finish(), fi, true)
		if err != nil {
			return
		}
	}

	// Write meta block
	meta := block.NewWriter(t.o.GetBlockRestartInterval())
	if t.filter != nil {
		key := []byte("filter." + t.filter.Name())
		meta.Add(key, fi.encode())
	}
	mb := new(bInfo)
	err = t.write(meta.Finish(), mb, false)
	if err != nil {
		return
	}

	// Write index block
	if t.pindex {
		suc := t.cmp.Successor(t.lkey)
		t.indexBlock.Add(suc, t.lblock.encode())
		t.pindex = false
	}
	ib := new(bInfo)
	err = t.write(t.indexBlock.Finish(), ib, false)
	if err != nil {
		return
	}

	// Write footer
	var n int
	n, err = writeFooter(t.w, mb, ib)
	if err != nil {
		return
	}
	t.off += n

	return
}

// Len return the number of records added so far.
func (t *Writer) Len() int {
	return t.n
}

// Size return the number of bytes written so far.
func (t *Writer) Size() int {
	return t.off
}

// CountBlock return the number of data block written so far.
func (t *Writer) CountBlock() int {
	n := t.indexBlock.Len()
	if !t.closed {
		n++
	}
	return n
}

func (t *Writer) write(buf []byte, bi *bInfo, raw bool) (err error) {
	compression := kNoCompression
	if !raw {
		switch t.o.GetCompressionType() {
		case opt.DefaultCompression, opt.SnappyCompression:
			compression = kSnappyCompression
			buf, err = snappy.Encode(nil, buf)
			if err != nil {
				return
			}
		}
	}

	if bi != nil {
		bi.offset = uint64(t.off)
		bi.size = uint64(len(buf))
	}

	_, err = t.w.Write(buf)
	if err != nil {
		return
	}

	compbit := []byte{byte(compression)}
	_, err = t.w.Write(compbit)
	if err != nil {
		return
	}

	crc := hash.NewCRC32C()
	crc.Write(buf)
	crc.Write(compbit)
	err = binary.Write(t.w, binary.LittleEndian, hash.MaskCRC32(crc.Sum32()))
	if err != nil {
		return
	}

	t.off += len(buf) + 5
	return
}
<commit_msg>Remove naked returns from leveldb/table/writer.go.<commit_after>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package table

import (
	"encoding/binary"

	"code.google.com/p/snappy-go/snappy"

	"github.com/syndtr/goleveldb/leveldb/block"
	"github.com/syndtr/goleveldb/leveldb/comparer"
	"github.com/syndtr/goleveldb/leveldb/filter"
	"github.com/syndtr/goleveldb/leveldb/hash"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

const (
	// Written to disk; don't modify.
	kNoCompression     = 0
	kSnappyCompression = 1
)

// Writer represent a table writer.
type Writer struct {
	w      storage.Writer
	o      opt.OptionsGetter
	cmp    comparer.Comparer
	filter filter.Filter

	dataBlock   *block.Writer
	indexBlock  *block.Writer
	filterBlock *block.FilterWriter

	n, off int
	lkey   []byte // last key
	lblock *bInfo // last block
	pindex bool   // pending index

	closed bool
}

// NewWriter create new initialized table writer.
func NewWriter(w storage.Writer, o opt.OptionsGetter) *Writer {
	t := &Writer{w: w, o: o, cmp: o.GetComparer()}
	// Creating blocks
	t.dataBlock = block.NewWriter(o.GetBlockRestartInterval())
	t.indexBlock = block.NewWriter(1)
	t.filter = o.GetFilter()
	if t.filter != nil {
		t.filterBlock = block.NewFilterWriter(t.filter)
		t.filterBlock.Generate(0)
	}
	t.lblock = new(bInfo)
	return t
}

// Add append key/value to the table.
func (t *Writer) Add(key, value []byte) error {
	if t.closed {
		panic("operation on closed table writer")
	}

	if t.pindex {
		// write the pending index
		sep := t.cmp.Separator(t.lkey, key)
		t.indexBlock.Add(sep, t.lblock.encode())
		t.pindex = false
	}

	if t.filterBlock != nil {
		t.filterBlock.Add(key)
	}

	t.lkey = key
	t.n++

	t.dataBlock.Add(key, value)
	if t.dataBlock.Size() >= t.o.GetBlockSize() {
		return t.Flush()
	}
	return nil
}

// Flush finalize and write the data block.
func (t *Writer) Flush() error {
	if t.closed {
		panic("operation on closed table writer")
	}

	if t.pindex {
		return nil
	}

	if err := t.write(t.dataBlock.Finish(), t.lblock, false); err != nil {
		return err
	}
	t.dataBlock.Reset()

	t.pindex = true

	if t.filterBlock != nil {
		t.filterBlock.Generate(t.off)
	}
	return nil
}

// Finish finalize the table. No Add(), Flush() or Finish() is possible
// beyond this, doing so will raise panic.
func (t *Writer) Finish() error {
	if t.closed {
		panic("operation on closed table writer")
	}

	if err := t.Flush(); err != nil {
		return err
	}

	t.closed = true

	// Write filter block
	fi := new(bInfo)
	if t.filterBlock != nil {
		if err := t.write(t.filterBlock.Finish(), fi, true); err != nil {
			return err
		}
	}

	// Write meta block
	meta := block.NewWriter(t.o.GetBlockRestartInterval())
	if t.filter != nil {
		key := []byte("filter." + t.filter.Name())
		meta.Add(key, fi.encode())
	}
	mb := new(bInfo)
	if err := t.write(meta.Finish(), mb, false); err != nil {
		return err
	}

	// Write index block
	if t.pindex {
		suc := t.cmp.Successor(t.lkey)
		t.indexBlock.Add(suc, t.lblock.encode())
		t.pindex = false
	}
	ib := new(bInfo)
	if err := t.write(t.indexBlock.Finish(), ib, false); err != nil {
		return err
	}

	// Write footer
	n, err := writeFooter(t.w, mb, ib)
	if err != nil {
		return err
	}
	t.off += n

	return nil
}

// Len return the number of records added so far.
func (t *Writer) Len() int {
	return t.n
}

// Size return the number of bytes written so far.
func (t *Writer) Size() int {
	return t.off
}

// CountBlock return the number of data block written so far.
func (t *Writer) CountBlock() int {
	n := t.indexBlock.Len()
	if !t.closed {
		n++
	}
	return n
}

func (t *Writer) write(buf []byte, bi *bInfo, raw bool) (err error) {
	compression := kNoCompression
	if !raw {
		switch t.o.GetCompressionType() {
		case opt.DefaultCompression, opt.SnappyCompression:
			compression = kSnappyCompression
			buf, err = snappy.Encode(nil, buf)
			if err != nil {
				return err
			}
		}
	}

	if bi != nil {
		bi.offset = uint64(t.off)
		bi.size = uint64(len(buf))
	}

	if _, err = t.w.Write(buf); err != nil {
		return err
	}

	compbit := []byte{byte(compression)}
	if _, err = t.w.Write(compbit); err != nil {
		return err
	}

	crc := hash.NewCRC32C()
	crc.Write(buf)
	crc.Write(compbit)
	if err = binary.Write(t.w, binary.LittleEndian, hash.MaskCRC32(crc.Sum32())); err != nil {
		return err
	}

	t.off += len(buf) + 5
	return nil
}
<|endoftext|>


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

package sqlite

import (
	"fmt"
	"io"
)

// IntegrityCheck checks database integrity.
// Database name is optional (default is 'main').
// (See http://www.sqlite.org/pragma.html#pragma_integrity_check
// and http://www.sqlite.org/pragma.html#pragma_quick_check)
func (c *Conn) IntegrityCheck(dbName string, max int, quick bool) error {
	var prefix string
	if quick {
		prefix = "quick"
	} else {
		prefix = "integrity"
	}
	pragmaName := fmt.Sprintf("%s_check(%d)", prefix, max)
	var msg string
	err := c.oneValue(pragma(dbName, pragmaName), &msg)
	if err != nil {
		return err
	}
	if msg != "ok" {
		return c.specificError("Integrity check failed (%s)", msg)
	}
	return nil
}

// Encoding returns the text encoding used by the specified database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_encoding)
func (c *Conn) Encoding(dbName string) (string, error) {
	var encoding string
	err := c.oneValue(pragma(dbName, "encoding"), &encoding)
	if err != nil {
		return "", err
	}
	return encoding, nil
}

// SchemaVersion gets the value of the schema-version.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_schema_version)
func (c *Conn) SchemaVersion(dbName string) (int, error) {
	var version int
	err := c.oneValue(pragma(dbName, "schema_version"), &version)
	if err != nil {
		return -1, err
	}
	return version, nil
}

// SetRecursiveTriggers sets or clears the recursive trigger capability.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_recursive_triggers)
func (c *Conn) SetRecursiveTriggers(dbName string, on bool) error {
	return c.exec(pragma(dbName, fmt.Sprintf("recursive_triggers=%t", on)))
}

// JournalMode queries the current journaling mode for database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_journal_mode)
func (c *Conn) JournalMode(dbName string) (string, error) {
	var mode string
	err := c.oneValue(pragma(dbName, "journal_mode"), &mode)
	if err != nil {
		return "", err
	}
	return mode, nil
}

// SetJournalMode changes the journaling mode for database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_journal_mode)
func (c *Conn) SetJournalMode(dbName, mode string) (string, error) {
	var newMode string
	err := c.oneValue(pragma(dbName, Mprintf("journal_mode=%Q", mode)), &newMode)
	if err != nil {
		return "", err
	}
	return newMode, nil
}

// LockingMode queries the database connection locking-mode.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_locking_mode)
func (c *Conn) LockingMode(dbName string) (string, error) {
	var mode string
	err := c.oneValue(pragma(dbName, "locking_mode"), &mode)
	if err != nil {
		return "", err
	}
	return mode, nil
}

// SetLockingMode changes the database connection locking-mode.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_locking_mode)
func (c *Conn) SetLockingMode(dbName, mode string) (string, error) {
	var newMode string
	err := c.oneValue(pragma(dbName, Mprintf("locking_mode=%Q", mode)), &newMode)
	if err != nil {
		return "", err
	}
	return newMode, nil
}

// Synchronous queries the synchronous flag.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_synchronous)
func (c *Conn) Synchronous(dbName string) (int, error) {
	var mode int
	err := c.oneValue(pragma(dbName, "synchronous"), &mode)
	if err != nil {
		return -1, err
	}
	return mode, nil
}

// SetSynchronous changes the synchronous flag.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_synchronous)
func (c *Conn) SetSynchronous(dbName string, mode int) error {
	return c.exec(pragma(dbName, fmt.Sprintf("synchronous=%d", mode)))
}

func pragma(dbName, pragmaName string) string {
	if len(dbName) == 0 {
		return "PRAGMA " + pragmaName
	}
	return Mprintf("PRAGMA %Q."+pragmaName, dbName)
}

func (c *Conn) oneValue(query string, value interface{}, args ...interface{}) error { // no cache
	s, err := c.prepare(query, args...)
	if err != nil {
		return err
	}
	defer func() {
		s.Reset()
		s.finalize()
	}()
	b, err := s.Next()
	if err != nil {
		return err
	} else if !b {
		return io.EOF
	}
	return s.Scan(value)
}
<commit_msg>Misc.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sqlite

/*
#include <sqlite3.h>
*/
import "C"

import (
	"fmt"
	"io"
)

// IntegrityCheck checks database integrity.
// Database name is optional (default is 'main').
// (See http://www.sqlite.org/pragma.html#pragma_integrity_check
// and http://www.sqlite.org/pragma.html#pragma_quick_check)
func (c *Conn) IntegrityCheck(dbName string, max int, quick bool) error {
	var prefix string
	if quick {
		prefix = "quick"
	} else {
		prefix = "integrity"
	}
	pragmaName := fmt.Sprintf("%s_check(%d)", prefix, max)
	var msg string
	err := c.oneValue(pragma(dbName, pragmaName), &msg)
	if err != nil {
		return err
	}
	if msg != "ok" {
		return c.specificError("Integrity check failed (%s)", msg)
	}
	return nil
}

// Encoding returns the text encoding used by the specified database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_encoding)
func (c *Conn) Encoding(dbName string) (string, error) {
	var encoding string
	err := c.oneValue(pragma(dbName, "encoding"), &encoding)
	if err != nil {
		return "", err
	}
	return encoding, nil
}

// SchemaVersion gets the value of the schema-version.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_schema_version)
func (c *Conn) SchemaVersion(dbName string) (int, error) {
	var version int
	err := c.oneValue(pragma(dbName, "schema_version"), &version)
	if err != nil {
		return -1, err
	}
	return version, nil
}

// SetRecursiveTriggers sets or clears the recursive trigger capability.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_recursive_triggers)
func (c *Conn) SetRecursiveTriggers(dbName string, on bool) error {
	return c.exec(pragma(dbName, fmt.Sprintf("recursive_triggers=%t", on)))
}

// JournalMode queries the current journaling mode for database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_journal_mode)
func (c *Conn) JournalMode(dbName string) (string, error) {
	var mode string
	err := c.oneValue(pragma(dbName, "journal_mode"), &mode)
	if err != nil {
		return "", err
	}
	return mode, nil
}

// SetJournalMode changes the journaling mode for database.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_journal_mode)
func (c *Conn) SetJournalMode(dbName, mode string) (string, error) {
	var newMode string
	err := c.oneValue(pragma(dbName, Mprintf("journal_mode=%Q", mode)), &newMode)
	if err != nil {
		return "", err
	}
	return newMode, nil
}

// LockingMode queries the database connection locking-mode.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_locking_mode)
func (c *Conn) LockingMode(dbName string) (string, error) {
	var mode string
	err := c.oneValue(pragma(dbName, "locking_mode"), &mode)
	if err != nil {
		return "", err
	}
	return mode, nil
}

// SetLockingMode changes the database connection locking-mode.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_locking_mode)
func (c *Conn) SetLockingMode(dbName, mode string) (string, error) {
	var newMode string
	err := c.oneValue(pragma(dbName, Mprintf("locking_mode=%Q", mode)), &newMode)
	if err != nil {
		return "", err
	}
	return newMode, nil
}

// Synchronous queries the synchronous flag.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_synchronous)
func (c *Conn) Synchronous(dbName string) (int, error) {
	var mode int
	err := c.oneValue(pragma(dbName, "synchronous"), &mode)
	if err != nil {
		return -1, err
	}
	return mode, nil
}

// SetSynchronous changes the synchronous flag.
// Database name is optional (default is 'main').
// (See http://sqlite.org/pragma.html#pragma_synchronous)
func (c *Conn) SetSynchronous(dbName string, mode int) error {
	return c.exec(pragma(dbName, fmt.Sprintf("synchronous=%d", mode)))
}

func pragma(dbName, pragmaName string) string {
	if len(dbName) == 0 {
		return "PRAGMA " + pragmaName
	}
	return Mprintf("PRAGMA %Q."+pragmaName, dbName)
}

func (c *Conn) oneValue(query string, value interface{}) error { // no cache
	s, err := c.prepare(query)
	if err != nil {
		return err
	}
	defer s.finalize()
	rv := C.sqlite3_step(s.stmt)
	err = Errno(rv)
	if err == Row {
		return s.Scan(value)
	} else if err == Done {
		return io.EOF
	}
	return s.error(rv)
}
<|endoftext|>