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

// Romana CNI plugin configures kubernetes pods on Romana network.
package main

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"runtime"
	"syscall"

	"github.com/romana/core/pkg/cni/kubernetes"

	"github.com/containernetworking/cni/pkg/ip"
	"github.com/containernetworking/cni/pkg/ns"
	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"
	util "github.com/romana/core/pkg/cni"
	log "github.com/romana/rlog"
	"github.com/vishvananda/netlink"
)

func init() {
	// This ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

// cmdAdd is a callback functions that gets called by skel.PluginMain
// in response to ADD method.
func cmdAdd(args *skel.CmdArgs) error {
	var err error
	// netConf stores Romana related config
	// that comes form stdin.
	netConf, _, _ := loadConf(args.StdinData)
	cniVersion := netConf.CNIVersion
	log.Debugf("Loaded netConf %v", netConf)

	// LoadArgs parses kubernetes related parameters from CNI
	// environment variables.
	k8sargs := kubernetes.K8sArgs{}
	err = types.LoadArgs(args.Args, &k8sargs)
	if err != nil {
		return fmt.Errorf("Failed to types.LoadArgs, err=%(err)", err)
	}
	log.Debugf("Loaded Kubernetes args %v", k8sargs)

	// Retrieves additional information about the pod
	pod, err := kubernetes.GetPodDescription(k8sargs, netConf.KubernetesConfig)
	if err != nil {
		return err
	}

	// Deferring deallocation before allocating ip address,
	// deallocation will be called on any return unless
	// flag set to false.
	var deallocateOnExit bool = true
	defer func() {
		if deallocateOnExit {
			deallocator, err := util.NewRomanaAddressManager(util.DefaultProvider)

			// don't want to panic here
			if netConf != nil && err == nil {
				log.Errorf("Deallocating IP on exist, something went wrong")
				_ = deallocator.Deallocate(*netConf, pod.Name)
			}
		}
	}()

	// Allocating ip address.
	allocator, err := util.NewRomanaAddressManager(util.DefaultProvider)
	if err != nil {
		return err
	}
	podAddress, err := allocator.Allocate(*netConf, util.RomanaAllocatorPodDescription{
		Name:        pod.Name,
		Hostname:    netConf.RomanaHostName,
		Namespace:   pod.Namespace,
		Labels:      pod.Labels,
		Annotations: pod.Annotations,
	})
	if err != nil {
		return err
	}

	// Networking setup
	_, gwAddr, err := GetRomanaGwAddr()
	if err != nil {
		return fmt.Errorf("Failed to detect ipv4 address on romana-gw interface, err=(%s)", err)
	}

	netns, err := ns.GetNS(args.Netns)
	if err != nil {
		return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
	}
	defer netns.Close()

	// Magic variables for callback.
	contIface := &current.Interface{}
	hostIface := &current.Interface{}
	ifName := "eth0"
	mtu := 1500 //TODO for stas, make configurable
	_, defaultNet, _ := net.ParseCIDR("0.0.0.0/0")

	// And this is a callback inside the callback, it sets up networking
	// withing a pod namespace, nice thing it save us from shellouts
	// but still, callback within a callback.
	err = netns.Do(func(hostNS ns.NetNS) error {
		// Creates veth interfacces.
		hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return err
		}

		// transportNet is a romana-gw cidr turned into romana-gw.IP/32
		transportNet := net.IPNet{IP: gwAddr.IP, Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff})}
		transportRoute := netlink.Route{
			LinkIndex: containerVeth.Index,
			Dst:       &transportNet,
		}

		// sets up transport route to allow installing default route
		err = netlink.RouteAdd(&transportRoute)
		if err != nil {
			return fmt.Errorf("route add error=(%s)", err)
		}

		// default route for the pod
		defaultRoute := netlink.Route{
			Dst:       defaultNet,
			LinkIndex: containerVeth.Index,
		}
		err = netlink.RouteAdd(&defaultRoute)
		if err != nil {
			return fmt.Errorf("route add default error=(%s)", err)
		}

		containerVethLink, err := netlink.LinkByIndex(containerVeth.Index)
		if err != nil {
			return fmt.Errorf("failed to discover container veth, err=(%s)", err)
		}

		podIP, err := netlink.ParseAddr(podAddress.String())
		if err != nil {
			return fmt.Errorf("netlink failed to parse address %s, err=(%s)", podAddress, err)
		}

		err = netlink.AddrAdd(containerVethLink, podIP)
		if err != nil {
			return fmt.Errorf("failed to add ip address %s to the interface %s, err=(%s)", podIP, containerVeth, err)
		}

		contIface.Name = containerVeth.Name
		contIface.Mac = containerVeth.HardwareAddr.String()
		contIface.Sandbox = netns.Path()
		hostIface.Name = hostVeth.Name
		return nil
	})
	if err != nil {
		return fmt.Errorf("Failed to create veth interfaces in namespace %v, err=(%s)", netns, err)
	}

	// Rename host part of veth to something convinient.
	vethExternalName := k8sargs.MakeVethName()
	err = RenameLink(hostIface.Name, vethExternalName)
	if err != nil {
		return fmt.Errorf("Failed to rename host part of veth interface from %s to %s, err=(%s)", hostIface.Name, vethExternalName, err)
	}

	// Return route.
	err = AddEndpointRoute(vethExternalName, podAddress)
	if err != nil {
		return fmt.Errorf("Failed to setup return route to %s via interface %s, err=(%s)", podAddress, hostIface.Name, err)
	}

	result := &current.Result{
		IPs: []*current.IPConfig{
			&current.IPConfig{
				Version:   "4",
				Address:   *podAddress,
				Interface: 0,
			},
		},
	}

	result.Interfaces = []*current.Interface{hostIface}

	deallocateOnExit = false
	return types.PrintResult(result, cniVersion)
}

// cmdDel is a callback functions that gets called by skel.PluginMain
// in response to DEL method.
func cmdDel(args *skel.CmdArgs) error {
	var err error
	// netConf stores Romana related config
	// that comes form stdin.
	netConf, _, _ := loadConf(args.StdinData)

	// LoadArgs parses kubernetes related parameters from CNI
	// environment variables.
	k8sargs := kubernetes.K8sArgs{}
	err = types.LoadArgs(args.Args, &k8sargs)
	if err != nil {
		return err
	}

	deallocator, err := util.NewRomanaAddressManager(util.DefaultProvider)
	if err != nil {
		return err
	}
	err = deallocator.Deallocate(*netConf, k8sargs.MakePodName())
	if err != nil {
		return fmt.Errorf("Failed to tear down pod network for %s, err=(%s)", k8sargs.MakePodName(), err)
	}

	return nil
}

// GetRomanaGwAddr detects ip address assigned to romana-gw interface.
func GetRomanaGwAddr() (netlink.Link, *net.IPNet, error) {
	const gwIface = "romana-gw"
	romanaGw, err := netlink.LinkByName(gwIface)
	if err != nil {
		return nil, nil, err
	}

	addr, err := netlink.AddrList(romanaGw, syscall.AF_INET)
	if err != nil {
		return nil, nil, err
	}

	if len(addr) != 1 {
		return nil, nil, fmt.Errorf("Expected exactly 1 ipv4 address on romana-gw interface, found %d", len(addr))
	}

	return romanaGw, addr[0].IPNet, nil
}

// RenameLink renames interface.
func RenameLink(curName, newName string) error {
	curVeth, err := netlink.LinkByName(curName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", curName, err)
	}

	if err = netlink.LinkSetDown(curVeth); err != nil {
		return fmt.Errorf("failed to set %q up: %v", curName, err)
	}

	err = netlink.LinkSetName(curVeth, newName)
	if err != nil {
		return fmt.Errorf("failed to rename %q: %v", curVeth, newName)
	}

	newVeth, err := netlink.LinkByName(newName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", newName, err)
	}

	err = netlink.LinkSetUp(newVeth)
	if err != nil {
		return fmt.Errorf("failed to set %q up: %v", newVeth, err)
	}

	return nil
}

// AddEndpointRoute adds return /32 route from host to pod.
func AddEndpointRoute(ifaceName string, ip *net.IPNet) error {
	veth, err := netlink.LinkByName(ifaceName)
	if err != nil {
		return err
	}

	returnRoute := netlink.Route{
		Dst:       ip,
		LinkIndex: veth.Attrs().Index,
	}

	err = netlink.RouteAdd(&returnRoute)

	return nil
}

// loadConf initializes romana config from stdin.
func loadConf(bytes []byte) (*util.NetConf, string, error) {
	n := &util.NetConf{}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, "", fmt.Errorf("failed to load netconf: %s", err)
	}

	// TODO for stas
	// verify config here
	if n.RomanaHostName == "" {
		hostname, err := os.Hostname()
		if err != nil {
			return nil, "", fmt.Errorf("failed to load netconf: %s", err)
		}

		n.RomanaHostName = hostname
	}

	return n, n.CNIVersion, nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel, version.All)
}
<commit_msg>GoLint proposal<commit_after>// Copyright (c) 2017 Pani Networks
// All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Romana CNI plugin configures kubernetes pods on Romana network.
package main

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"runtime"
	"syscall"

	"github.com/romana/core/pkg/cni/kubernetes"

	"github.com/containernetworking/cni/pkg/ip"
	"github.com/containernetworking/cni/pkg/ns"
	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"
	util "github.com/romana/core/pkg/cni"
	log "github.com/romana/rlog"
	"github.com/vishvananda/netlink"
)

func init() {
	// This ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

// cmdAdd is a callback functions that gets called by skel.PluginMain
// in response to ADD method.
func cmdAdd(args *skel.CmdArgs) error {
	var err error
	// netConf stores Romana related config
	// that comes form stdin.
	netConf, _, _ := loadConf(args.StdinData)
	cniVersion := netConf.CNIVersion
	log.Debugf("Loaded netConf %v", netConf)

	// LoadArgs parses kubernetes related parameters from CNI
	// environment variables.
	k8sargs := kubernetes.K8sArgs{}
	err = types.LoadArgs(args.Args, &k8sargs)
	if err != nil {
		return fmt.Errorf("Failed to types.LoadArgs, err=%(err)", err)
	}
	log.Debugf("Loaded Kubernetes args %v", k8sargs)

	// Retrieves additional information about the pod
	pod, err := kubernetes.GetPodDescription(k8sargs, netConf.KubernetesConfig)
	if err != nil {
		return err
	}

	// Deferring deallocation before allocating ip address,
	// deallocation will be called on any return unless
	// flag set to false.
	var deallocateOnExit = true
	defer func() {
		if deallocateOnExit {
			deallocator, err := util.NewRomanaAddressManager(util.DefaultProvider)

			// don't want to panic here
			if netConf != nil && err == nil {
				log.Errorf("Deallocating IP on exist, something went wrong")
				_ = deallocator.Deallocate(*netConf, pod.Name)
			}
		}
	}()

	// Allocating ip address.
	allocator, err := util.NewRomanaAddressManager(util.DefaultProvider)
	if err != nil {
		return err
	}
	podAddress, err := allocator.Allocate(*netConf, util.RomanaAllocatorPodDescription{
		Name:        pod.Name,
		Hostname:    netConf.RomanaHostName,
		Namespace:   pod.Namespace,
		Labels:      pod.Labels,
		Annotations: pod.Annotations,
	})
	if err != nil {
		return err
	}

	// Networking setup
	_, gwAddr, err := GetRomanaGwAddr()
	if err != nil {
		return fmt.Errorf("Failed to detect ipv4 address on romana-gw interface, err=(%s)", err)
	}

	netns, err := ns.GetNS(args.Netns)
	if err != nil {
		return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
	}
	defer netns.Close()

	// Magic variables for callback.
	contIface := &current.Interface{}
	hostIface := &current.Interface{}
	ifName := "eth0"
	mtu := 1500 //TODO for stas, make configurable
	_, defaultNet, _ := net.ParseCIDR("0.0.0.0/0")

	// And this is a callback inside the callback, it sets up networking
	// withing a pod namespace, nice thing it save us from shellouts
	// but still, callback within a callback.
	err = netns.Do(func(hostNS ns.NetNS) error {
		// Creates veth interfacces.
		hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return err
		}

		// transportNet is a romana-gw cidr turned into romana-gw.IP/32
		transportNet := net.IPNet{IP: gwAddr.IP, Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff})}
		transportRoute := netlink.Route{
			LinkIndex: containerVeth.Index,
			Dst:       &transportNet,
		}

		// sets up transport route to allow installing default route
		err = netlink.RouteAdd(&transportRoute)
		if err != nil {
			return fmt.Errorf("route add error=(%s)", err)
		}

		// default route for the pod
		defaultRoute := netlink.Route{
			Dst:       defaultNet,
			LinkIndex: containerVeth.Index,
		}
		err = netlink.RouteAdd(&defaultRoute)
		if err != nil {
			return fmt.Errorf("route add default error=(%s)", err)
		}

		containerVethLink, err := netlink.LinkByIndex(containerVeth.Index)
		if err != nil {
			return fmt.Errorf("failed to discover container veth, err=(%s)", err)
		}

		podIP, err := netlink.ParseAddr(podAddress.String())
		if err != nil {
			return fmt.Errorf("netlink failed to parse address %s, err=(%s)", podAddress, err)
		}

		err = netlink.AddrAdd(containerVethLink, podIP)
		if err != nil {
			return fmt.Errorf("failed to add ip address %s to the interface %s, err=(%s)", podIP, containerVeth, err)
		}

		contIface.Name = containerVeth.Name
		contIface.Mac = containerVeth.HardwareAddr.String()
		contIface.Sandbox = netns.Path()
		hostIface.Name = hostVeth.Name
		return nil
	})
	if err != nil {
		return fmt.Errorf("Failed to create veth interfaces in namespace %v, err=(%s)", netns, err)
	}

	// Rename host part of veth to something convinient.
	vethExternalName := k8sargs.MakeVethName()
	err = RenameLink(hostIface.Name, vethExternalName)
	if err != nil {
		return fmt.Errorf("Failed to rename host part of veth interface from %s to %s, err=(%s)", hostIface.Name, vethExternalName, err)
	}

	// Return route.
	err = AddEndpointRoute(vethExternalName, podAddress)
	if err != nil {
		return fmt.Errorf("Failed to setup return route to %s via interface %s, err=(%s)", podAddress, hostIface.Name, err)
	}

	result := &current.Result{
		IPs: []*current.IPConfig{
			&current.IPConfig{
				Version:   "4",
				Address:   *podAddress,
				Interface: 0,
			},
		},
	}

	result.Interfaces = []*current.Interface{hostIface}

	deallocateOnExit = false
	return types.PrintResult(result, cniVersion)
}

// cmdDel is a callback functions that gets called by skel.PluginMain
// in response to DEL method.
func cmdDel(args *skel.CmdArgs) error {
	var err error
	// netConf stores Romana related config
	// that comes form stdin.
	netConf, _, _ := loadConf(args.StdinData)

	// LoadArgs parses kubernetes related parameters from CNI
	// environment variables.
	k8sargs := kubernetes.K8sArgs{}
	err = types.LoadArgs(args.Args, &k8sargs)
	if err != nil {
		return err
	}

	deallocator, err := util.NewRomanaAddressManager(util.DefaultProvider)
	if err != nil {
		return err
	}
	err = deallocator.Deallocate(*netConf, k8sargs.MakePodName())
	if err != nil {
		return fmt.Errorf("Failed to tear down pod network for %s, err=(%s)", k8sargs.MakePodName(), err)
	}

	return nil
}

// GetRomanaGwAddr detects ip address assigned to romana-gw interface.
func GetRomanaGwAddr() (netlink.Link, *net.IPNet, error) {
	const gwIface = "romana-gw"
	romanaGw, err := netlink.LinkByName(gwIface)
	if err != nil {
		return nil, nil, err
	}

	addr, err := netlink.AddrList(romanaGw, syscall.AF_INET)
	if err != nil {
		return nil, nil, err
	}

	if len(addr) != 1 {
		return nil, nil, fmt.Errorf("Expected exactly 1 ipv4 address on romana-gw interface, found %d", len(addr))
	}

	return romanaGw, addr[0].IPNet, nil
}

// RenameLink renames interface.
func RenameLink(curName, newName string) error {
	curVeth, err := netlink.LinkByName(curName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", curName, err)
	}

	if err = netlink.LinkSetDown(curVeth); err != nil {
		return fmt.Errorf("failed to set %q up: %v", curName, err)
	}

	err = netlink.LinkSetName(curVeth, newName)
	if err != nil {
		return fmt.Errorf("failed to rename %q: %v", curVeth, newName)
	}

	newVeth, err := netlink.LinkByName(newName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", newName, err)
	}

	err = netlink.LinkSetUp(newVeth)
	if err != nil {
		return fmt.Errorf("failed to set %q up: %v", newVeth, err)
	}

	return nil
}

// AddEndpointRoute adds return /32 route from host to pod.
func AddEndpointRoute(ifaceName string, ip *net.IPNet) error {
	veth, err := netlink.LinkByName(ifaceName)
	if err != nil {
		return err
	}

	returnRoute := netlink.Route{
		Dst:       ip,
		LinkIndex: veth.Attrs().Index,
	}

	err = netlink.RouteAdd(&returnRoute)

	return nil
}

// loadConf initializes romana config from stdin.
func loadConf(bytes []byte) (*util.NetConf, string, error) {
	n := &util.NetConf{}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, "", fmt.Errorf("failed to load netconf: %s", err)
	}

	// TODO for stas
	// verify config here
	if n.RomanaHostName == "" {
		hostname, err := os.Hostname()
		if err != nil {
			return nil, "", fmt.Errorf("failed to load netconf: %s", err)
		}

		n.RomanaHostName = hostname
	}

	return n, n.CNIVersion, nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel, version.All)
}
<|endoftext|>


<commit_before>package apiGatewayDeploy

import (
	"encoding/json"
	"os"
	"time"

	"fmt"

	"github.com/30x/apid-core"
	"github.com/apigee-labs/transicator/common"
)

const (
	APIGEE_SYNC_EVENT = "ApigeeSync"
	DEPLOYMENT_TABLE  = "edgex.deployment"
)

func initListener(services apid.Services) {
	services.Events().Listen(APIGEE_SYNC_EVENT, &apigeeSyncHandler{})
}

type bundleConfigJson struct {
	Name         string `json:"name"`
	URI          string `json:"uri"`
	ChecksumType string `json:"checksumType"`
	Checksum     string `json:"checksum"`
}

type apigeeSyncHandler struct {
}

func (h *apigeeSyncHandler) String() string {
	return "gatewayDeploy"
}

func (h *apigeeSyncHandler) Handle(e apid.Event) {

	if changeSet, ok := e.(*common.ChangeList); ok {
		processChangeList(changeSet)
	} else if snapData, ok := e.(*common.Snapshot); ok {
		processSnapshot(snapData)
	} else {
		log.Errorf("Received invalid event. Ignoring. %v", e)
	}
}

func processSnapshot(snapshot *common.Snapshot) {

	log.Debugf("Snapshot received. Switching to DB version: %s", snapshot.SnapshotInfo)

	db, err := data.DBVersion(snapshot.SnapshotInfo)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}

	err = InitDB(db)
	if err != nil {
		log.Panicf("Unable to initialize database: %v", err)
	}

	var deploymentsToInsert []DataDeployment
	var errResults apiDeploymentResults
	for _, table := range snapshot.Tables {
		switch table.Name {
		case DEPLOYMENT_TABLE:
			for _, row := range table.Rows {
				dep, err := dataDeploymentFromRow(row)
				if err == nil {
					deploymentsToInsert = append(deploymentsToInsert, dep)
				} else {
					result := apiDeploymentResult{
						ID:        dep.ID,
						Status:    RESPONSE_STATUS_FAIL,
						ErrorCode: ERROR_CODE_TODO,
						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
					}
					errResults = append(errResults, result)
				}
			}
		}
	}

	// ensure that no new database updates are made on old database
	dbMux.Lock()
	defer dbMux.Unlock()

	tx, err := db.Begin()
	if err != nil {
		log.Panicf("Error starting transaction: %v", err)
	}
	defer tx.Rollback()

	err = insertDeployments(tx, deploymentsToInsert)
	if err != nil {
		log.Panicf("Error processing Snapshot: %v", err)
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error committing Snapshot change: %v", err)
	}

	SetDB(db)

	for _, dep := range deploymentsToInsert {
		queueDownloadRequest(dep)
	}

	// transmit parsing errors back immediately
	if len(errResults) > 0 {
		go transmitDeploymentResultsToServer(errResults)
	}

	// if no tables, this a startup event for an existing DB, start bundle downloads that didn't finish
	if len(snapshot.Tables) == 0 {
		go func() {
			deployments, err := getUnreadyDeployments()
			if err != nil {
				log.Panicf("unable to query database for unready deployments: %v", err)
			}
			for _, dep := range deployments {
				queueDownloadRequest(dep)
			}
		}()
	}

	log.Debug("Snapshot processed")
}

func processChangeList(changes *common.ChangeList) {

	// gather deleted bundle info
	var deploymentsToInsert, deploymentsToDelete []DataDeployment
	var errResults apiDeploymentResults
	for _, change := range changes.Changes {
		switch change.Table {
		case DEPLOYMENT_TABLE:
			switch change.Operation {
			case common.Insert:
				dep, err := dataDeploymentFromRow(change.NewRow)
				if err == nil {
					deploymentsToInsert = append(deploymentsToInsert, dep)
				} else {
					result := apiDeploymentResult{
						ID:        dep.ID,
						Status:    RESPONSE_STATUS_FAIL,
						ErrorCode: ERROR_CODE_TODO,
						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
					}
					errResults = append(errResults, result)
				}
			case common.Delete:
				var id, dataScopeID string
				change.OldRow.Get("id", &id)
				change.OldRow.Get("data_scope_id", &dataScopeID)
				// only need these two fields to delete and determine bundle file
				dep := DataDeployment{
					ID:          id,
					DataScopeID: dataScopeID,
				}
				deploymentsToDelete = append(deploymentsToDelete, dep)
			}
		}
	}

	// transmit parsing errors back immediately
	if len(errResults) > 0 {
		go transmitDeploymentResultsToServer(errResults)
	}

	tx, err := getDB().Begin()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}
	defer tx.Rollback()

	for _, dep := range deploymentsToDelete {
		err = deleteDeployment(tx, dep.ID)
		if err != nil {
			log.Panicf("Error processing ChangeList: %v", err)
		}
	}
	err = insertDeployments(tx, deploymentsToInsert)
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}

	if len(deploymentsToDelete) > 0 {
		deploymentsChanged <- deploymentsToDelete[0].ID // arbitrary, the ID doesn't matter
	}

	log.Debug("ChangeList processed")

	for _, dep := range deploymentsToInsert {
		queueDownloadRequest(dep)
	}

	// clean up old bundles
	if len(deploymentsToDelete) > 0 {
		log.Debugf("will delete %d old bundles", len(deploymentsToDelete))
		go func() {
			// give clients a minute to avoid conflicts
			time.Sleep(bundleCleanupDelay)
			for _, dep := range deploymentsToDelete {
				bundleFile := getBundleFile(dep)
				log.Debugf("removing old bundle: %v", bundleFile)
				safeDelete(bundleFile)
			}
		}()
	}
}

func dataDeploymentFromRow(row common.Row) (d DataDeployment, err error) {

	row.Get("id", &d.ID)
	row.Get("bundle_config_id", &d.BundleConfigID)
	row.Get("apid_cluster_id", &d.ApidClusterID)
	row.Get("data_scope_id", &d.DataScopeID)
	row.Get("bundle_config_json", &d.BundleConfigJSON)
	row.Get("config_json", &d.ConfigJSON)
	row.Get("created", &d.Created)
	row.Get("created_by", &d.CreatedBy)
	row.Get("updated", &d.Updated)
	row.Get("updated_by", &d.UpdatedBy)

	var bc bundleConfigJson
	json.Unmarshal([]byte(d.BundleConfigJSON), &bc)
	if err != nil {
		log.Errorf("JSON decoding Manifest failed: %v", err)
		return
	}

	d.BundleName = bc.Name
	d.BundleURI = bc.URI
	d.BundleChecksumType = bc.ChecksumType
	d.BundleChecksum = bc.Checksum

	return
}

func safeDelete(file string) {
	if e := os.Remove(file); e != nil && !os.IsNotExist(e) {
		log.Warnf("unable to delete file %s: %v", file, e)
	}
}
<commit_msg>Add log of incorrect operation<commit_after>package apiGatewayDeploy

import (
	"encoding/json"
	"os"
	"time"

	"fmt"

	"github.com/30x/apid-core"
	"github.com/apigee-labs/transicator/common"
)

const (
	APIGEE_SYNC_EVENT = "ApigeeSync"
	DEPLOYMENT_TABLE  = "edgex.deployment"
)

func initListener(services apid.Services) {
	services.Events().Listen(APIGEE_SYNC_EVENT, &apigeeSyncHandler{})
}

type bundleConfigJson struct {
	Name         string `json:"name"`
	URI          string `json:"uri"`
	ChecksumType string `json:"checksumType"`
	Checksum     string `json:"checksum"`
}

type apigeeSyncHandler struct {
}

func (h *apigeeSyncHandler) String() string {
	return "gatewayDeploy"
}

func (h *apigeeSyncHandler) Handle(e apid.Event) {

	if changeSet, ok := e.(*common.ChangeList); ok {
		processChangeList(changeSet)
	} else if snapData, ok := e.(*common.Snapshot); ok {
		processSnapshot(snapData)
	} else {
		log.Errorf("Received invalid event. Ignoring. %v", e)
	}
}

func processSnapshot(snapshot *common.Snapshot) {

	log.Debugf("Snapshot received. Switching to DB version: %s", snapshot.SnapshotInfo)

	db, err := data.DBVersion(snapshot.SnapshotInfo)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}

	err = InitDB(db)
	if err != nil {
		log.Panicf("Unable to initialize database: %v", err)
	}

	var deploymentsToInsert []DataDeployment
	var errResults apiDeploymentResults
	for _, table := range snapshot.Tables {
		switch table.Name {
		case DEPLOYMENT_TABLE:
			for _, row := range table.Rows {
				dep, err := dataDeploymentFromRow(row)
				if err == nil {
					deploymentsToInsert = append(deploymentsToInsert, dep)
				} else {
					result := apiDeploymentResult{
						ID:        dep.ID,
						Status:    RESPONSE_STATUS_FAIL,
						ErrorCode: ERROR_CODE_TODO,
						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
					}
					errResults = append(errResults, result)
				}
			}
		}
	}

	// ensure that no new database updates are made on old database
	dbMux.Lock()
	defer dbMux.Unlock()

	tx, err := db.Begin()
	if err != nil {
		log.Panicf("Error starting transaction: %v", err)
	}
	defer tx.Rollback()

	err = insertDeployments(tx, deploymentsToInsert)
	if err != nil {
		log.Panicf("Error processing Snapshot: %v", err)
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error committing Snapshot change: %v", err)
	}

	SetDB(db)

	for _, dep := range deploymentsToInsert {
		queueDownloadRequest(dep)
	}

	// transmit parsing errors back immediately
	if len(errResults) > 0 {
		go transmitDeploymentResultsToServer(errResults)
	}

	// if no tables, this a startup event for an existing DB, start bundle downloads that didn't finish
	if len(snapshot.Tables) == 0 {
		go func() {
			deployments, err := getUnreadyDeployments()
			if err != nil {
				log.Panicf("unable to query database for unready deployments: %v", err)
			}
			for _, dep := range deployments {
				queueDownloadRequest(dep)
			}
		}()
	}

	log.Debug("Snapshot processed")
}

func processChangeList(changes *common.ChangeList) {

	// gather deleted bundle info
	var deploymentsToInsert, deploymentsToDelete []DataDeployment
	var errResults apiDeploymentResults
	for _, change := range changes.Changes {
		switch change.Table {
		case DEPLOYMENT_TABLE:
			switch change.Operation {
			case common.Insert:
				dep, err := dataDeploymentFromRow(change.NewRow)
				if err == nil {
					deploymentsToInsert = append(deploymentsToInsert, dep)
				} else {
					result := apiDeploymentResult{
						ID:        dep.ID,
						Status:    RESPONSE_STATUS_FAIL,
						ErrorCode: ERROR_CODE_TODO,
						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
					}
					errResults = append(errResults, result)
				}
			case common.Delete:
				var id, dataScopeID string
				change.OldRow.Get("id", &id)
				change.OldRow.Get("data_scope_id", &dataScopeID)
				// only need these two fields to delete and determine bundle file
				dep := DataDeployment{
					ID:          id,
					DataScopeID: dataScopeID,
				}
				deploymentsToDelete = append(deploymentsToDelete, dep)
			default:
				log.Errorf("unexpected operation: %s", change.Operation)
			}
		}
	}

	// transmit parsing errors back immediately
	if len(errResults) > 0 {
		go transmitDeploymentResultsToServer(errResults)
	}

	tx, err := getDB().Begin()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}
	defer tx.Rollback()

	for _, dep := range deploymentsToDelete {
		err = deleteDeployment(tx, dep.ID)
		if err != nil {
			log.Panicf("Error processing ChangeList: %v", err)
		}
	}
	err = insertDeployments(tx, deploymentsToInsert)
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
	}

	if len(deploymentsToDelete) > 0 {
		deploymentsChanged <- deploymentsToDelete[0].ID // arbitrary, the ID doesn't matter
	}

	log.Debug("ChangeList processed")

	for _, dep := range deploymentsToInsert {
		queueDownloadRequest(dep)
	}

	// clean up old bundles
	if len(deploymentsToDelete) > 0 {
		log.Debugf("will delete %d old bundles", len(deploymentsToDelete))
		go func() {
			// give clients a minute to avoid conflicts
			time.Sleep(bundleCleanupDelay)
			for _, dep := range deploymentsToDelete {
				bundleFile := getBundleFile(dep)
				log.Debugf("removing old bundle: %v", bundleFile)
				safeDelete(bundleFile)
			}
		}()
	}
}

func dataDeploymentFromRow(row common.Row) (d DataDeployment, err error) {

	row.Get("id", &d.ID)
	row.Get("bundle_config_id", &d.BundleConfigID)
	row.Get("apid_cluster_id", &d.ApidClusterID)
	row.Get("data_scope_id", &d.DataScopeID)
	row.Get("bundle_config_json", &d.BundleConfigJSON)
	row.Get("config_json", &d.ConfigJSON)
	row.Get("created", &d.Created)
	row.Get("created_by", &d.CreatedBy)
	row.Get("updated", &d.Updated)
	row.Get("updated_by", &d.UpdatedBy)

	var bc bundleConfigJson
	json.Unmarshal([]byte(d.BundleConfigJSON), &bc)
	if err != nil {
		log.Errorf("JSON decoding Manifest failed: %v", err)
		return
	}

	d.BundleName = bc.Name
	d.BundleURI = bc.URI
	d.BundleChecksumType = bc.ChecksumType
	d.BundleChecksum = bc.Checksum

	return
}

func safeDelete(file string) {
	if e := os.Remove(file); e != nil && !os.IsNotExist(e) {
		log.Warnf("unable to delete file %s: %v", file, e)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
)

func main() {
	fmt.Println("vim-go")
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
		}
		go handleConnection(conn)
	}
}
<commit_msg>listener binds to 8080 and prints message<commit_after>package main

import (
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			panic("Oh dear, I couldn't Accept()")
		}
		// go handleConnection(conn)
		_, err = conn.Write([]byte("vim-go\n"))
		err = conn.Close()
		if err != nil {
			panic("Oh dear, I couldn't Close()")
		}

	}
}
<|endoftext|>


<commit_before>package jc

import (
	"reflect"
	"unicode"
	"fmt"
	"errors"
	"strings"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2"
	"github.com/kalcok/jc/tools"
)

type document interface {
	setCollection(string)
	CollectionName() string
	SetDatabase(string)
	Database() string
	Init(reflect.Value, reflect.Type)
	InitDB() error
	Info()
	Save(bool) (*mgo.ChangeInfo, error)
}

type Collection struct {
	_collectionName string                `bson:"-"json:"-"`
	_collectionDB   string                `bson:"-"json:"-"`
	_parent         reflect.Value         `bson:"-"json:"-"`
	_parentType     reflect.Type          `bson:"-"json:"-"`
	_explicitID     string                `bson:"-"json:"-"`
	_implicitID     bson.ObjectId         `bson:"-"json:"-"`
	_skeleton       []reflect.StructField `bson:"-"json:"-"`
}

func (c *Collection) setCollection(name string) {
	c._collectionName = name
}

func (c *Collection) CollectionName() string {
	return c._collectionName
}

func (c *Collection) SetDatabase(name string) {
	c._collectionDB = name

}

func (c *Collection) Database() string {
	return c._collectionDB
}

func (c *Collection) Info() {
	fmt.Printf("Database %s\n", c._collectionDB)
	fmt.Printf("Collection %s\n", c._collectionName)
	fmt.Printf("Parent__ %s\n", c._parent)
}

func (c *Collection) Save(reuseSocket bool) (info *mgo.ChangeInfo, err error) {
	var session *mgo.Session
	master_session, err := tools.GetSession()
	var documentID interface{}

	if err != nil {
		return info, err
	}

	if reuseSocket {
		session = master_session.Clone()
	} else {
		session = master_session.Copy()
	}

	if len(c._explicitID) > 0 {
		documentID = c._parent.Elem().FieldByName(c._explicitID).Interface()
	} else if len(c._implicitID) > 0 {
		documentID = c._implicitID
	} else {
		c._implicitID = bson.NewObjectId()
		documentID = c._implicitID
	}

	collection := session.DB(c._collectionDB).C(c._collectionName)
	info, err = collection.UpsertId(documentID, c._parent.Interface())

	return info, err
}

func (c *Collection) Init(parent reflect.Value, parentType reflect.Type) {

	c._parent = parent
	c._parentType = parentType
	documentIdFound := false
	for i := 0; i < reflect.Indirect(c._parent).NumField(); i++ {
		field := c._parentType.Field(i)

		// Find explicit Collection name
		if field.Type == reflect.TypeOf(Collection{}) {
			explicitName := false
			odm_tag, tag_present := field.Tag.Lookup("odm")
			if tag_present {
				odm_fields := strings.Split(odm_tag, ",")
				if len(odm_fields) > 0 && odm_fields[0] != "" {
					c.setCollection(odm_fields[0])
					explicitName = true
				}
			}
			if !explicitName {
				c.setCollection(camelToSnake(parentType.Name()))
			}
		}

		// Find explicit index field
		bson_tag, tag_present := field.Tag.Lookup("bson")
		if tag_present {
			field_id := strings.Split(bson_tag, ",")
			switch field_id[0] {
			case "_id":
				c._explicitID = field.Name
				documentIdFound = true
				break
			case "-":
				continue
			default:
				break
			}
		}
		c._skeleton = append(c._skeleton, field)
	}
	if !documentIdFound {
		c._explicitID = "_id"
	}

}

func (c *Collection) InitDB() error {
	session, err := tools.GetSession()
	if err == nil {
		c.SetDatabase(session.DB("").Name)
	} else {
		err = errors.New("database not initialized")
	}
	return err
}

func NewDocument(c document) error {
	var err error
	objectType := reflect.TypeOf(c).Elem()
	objectValue := reflect.ValueOf(c)
	c.Init(objectValue, objectType)
	err = c.InitDB()

	return err
}

func camelToSnake(camel string) string {
	var (
		snake_name []rune
		next       rune
	)
	for i, c := range camel {
		if unicode.IsUpper(c) && i != 0 {
			snake_name = append(snake_name, '_')
		}
		next = unicode.ToLower(c)
		snake_name = append(snake_name, next)
	}
	return string(snake_name)
}

func initPrototype(prototype reflect.Value, internalType reflect.Type) reflect.Value {
	var inputs []reflect.Value
	inputs = append(inputs, reflect.ValueOf(prototype))
	inputs = append(inputs, reflect.ValueOf(internalType))
	prototype.MethodByName("Init").Call(inputs)
	prototype.MethodByName("InitDB").Call(nil)

	return reflect.Indirect(prototype)

}
<commit_msg>Fix error when inserting docs with implicit if field (_id)<commit_after>package jc

import (
	"reflect"
	"unicode"
	"fmt"
	"errors"
	"strings"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2"
	"github.com/kalcok/jc/tools"
)

type document interface {
	setCollection(string)
	CollectionName() string
	SetDatabase(string)
	Database() string
	Init(reflect.Value, reflect.Type)
	InitDB() error
	Info()
	Save(bool) (*mgo.ChangeInfo, error)
}

type Collection struct {
	_collectionName string                `bson:"-"json:"-"`
	_collectionDB   string                `bson:"-"json:"-"`
	_parent         reflect.Value         `bson:"-"json:"-"`
	_parentType     reflect.Type          `bson:"-"json:"-"`
	_explicitID     string                `bson:"-"json:"-"`
	_implicitID     bson.ObjectId         `bson:"-"json:"-"`
	_skeleton       []reflect.StructField `bson:"-"json:"-"`
}

func (c *Collection) setCollection(name string) {
	c._collectionName = name
}

func (c *Collection) CollectionName() string {
	return c._collectionName
}

func (c *Collection) SetDatabase(name string) {
	c._collectionDB = name

}

func (c *Collection) Database() string {
	return c._collectionDB
}

func (c *Collection) Info() {
	fmt.Printf("Database %s\n", c._collectionDB)
	fmt.Printf("Collection %s\n", c._collectionName)
	fmt.Printf("Parent__ %s\n", c._parent)
}

func (c *Collection) Save(reuseSocket bool) (info *mgo.ChangeInfo, err error) {
	var session *mgo.Session
	master_session, err := tools.GetSession()
	var documentID interface{}
	idField := "_id"

	if err != nil {
		return info, err
	}

	if reuseSocket {
		session = master_session.Clone()
	} else {
		session = master_session.Copy()
	}

	if len(c._explicitID) > 0 {
		idField = c._explicitID
		documentID = c._parent.Elem().FieldByName(c._explicitID).Interface()
	} else if len(c._implicitID) > 0 {
		documentID = c._implicitID
	} else {
		c._implicitID = bson.NewObjectId()
		documentID = c._implicitID
	}

	collection := session.DB(c._collectionDB).C(c._collectionName)
	info, err = collection.Upsert(bson.M{idField: documentID}, c._parent.Interface())

	return info, err
}

func (c *Collection) Init(parent reflect.Value, parentType reflect.Type) {

	c._parent = parent
	c._parentType = parentType
	for i := 0; i < reflect.Indirect(c._parent).NumField(); i++ {
		field := c._parentType.Field(i)

		// Find explicit Collection name
		if field.Type == reflect.TypeOf(Collection{}) {
			explicitName := false
			odm_tag, tag_present := field.Tag.Lookup("odm")
			if tag_present {
				odm_fields := strings.Split(odm_tag, ",")
				if len(odm_fields) > 0 && odm_fields[0] != "" {
					c.setCollection(odm_fields[0])
					explicitName = true
				}
			}
			if !explicitName {
				c.setCollection(camelToSnake(parentType.Name()))
			}
		}

		// Find explicit index field
		bson_tag, tag_present := field.Tag.Lookup("bson")
		if tag_present {
			field_id := strings.Split(bson_tag, ",")
			switch field_id[0] {
			case "_id":
				c._explicitID = field.Name
				break
			case "-":
				continue
			default:
				break
			}
		}
		c._skeleton = append(c._skeleton, field)
	}

}

func (c *Collection) InitDB() error {
	session, err := tools.GetSession()
	if err == nil {
		c.SetDatabase(session.DB("").Name)
	} else {
		err = errors.New("database not initialized")
	}
	return err
}

func NewDocument(c document) error {
	var err error
	objectType := reflect.TypeOf(c).Elem()
	objectValue := reflect.ValueOf(c)
	c.Init(objectValue, objectType)
	err = c.InitDB()

	return err
}

func camelToSnake(camel string) string {
	var (
		snake_name []rune
		next       rune
	)
	for i, c := range camel {
		if unicode.IsUpper(c) && i != 0 {
			snake_name = append(snake_name, '_')
		}
		next = unicode.ToLower(c)
		snake_name = append(snake_name, next)
	}
	return string(snake_name)
}

func initPrototype(prototype reflect.Value, internalType reflect.Type) reflect.Value {
	var inputs []reflect.Value
	inputs = append(inputs, reflect.ValueOf(prototype))
	inputs = append(inputs, reflect.ValueOf(internalType))
	prototype.MethodByName("Init").Call(inputs)
	prototype.MethodByName("InitDB").Call(nil)

	return reflect.Indirect(prototype)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
)

type App struct {
	Store     *sessions.CookieStore
	Mongo     *mgo.Session
	DB        *mgo.Database
	Templates map[string]*template.Template
}

func (app *App) Init() {
	var err error

	app.Store = sessions.NewCookieStore([]byte("07FdEM5Obo7BM2Kn4e1m-tZCC3IMfWLan0ealKM31"))
	app.Mongo, err = mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	app.Mongo.SetMode(mgo.Monotonic, true)
	app.DB = app.Mongo.DB("logo-spy")

	app.Templates = make(map[string]*template.Template)

	layout_path := "templates/layout.html"
	tmpl_paths, err := filepath.Glob("templates/*.html")
	if err != nil {
		panic(err)
	}
	for _, tmpl_path := range tmpl_paths {
		tmpl_name := filepath.Base(tmpl_path)
		if tmpl_name != "layout.html" {
			files := []string{tmpl_path, layout_path}
			app.Templates[tmpl_name] = template.Must(template.ParseFiles(files...))
		}
	}
}

func (app *App) Close() {
	app.Mongo.Close()
}

var app App

type Employee struct {
	Id    bson.ObjectId `bson:"_id"`
	Name  string        `bson:"name"`
	Code  string        `bson:"code"`
	Admin bool          `bson:"admin"`
}

type ViewData struct {
	Content string
}

func main() {
	app.Init()
	defer app.Close()

	rtr := mux.NewRouter()
	rtr.HandleFunc("/login", showLogin).Methods("GET")
	rtr.HandleFunc("/login", processLogin).Methods("POST")
	rtr.HandleFunc("/", showRecord).Methods("GET")

	fs := http.FileServer(http.Dir("static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))

	http.Handle("/", rtr)

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "3000"
	}
	log.Printf("Listening on port %s...", port)
	http.ListenAndServe(":"+port, nil)
}

func showLogin(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "login")
}

func processLogin(w http.ResponseWriter, r *http.Request) {
	fmt.Println(r.FormValue("code"))
	code, _ := strconv.Atoi(r.FormValue("code"))

	employee := Employee{}
	fmt.Println(bson.M{"code": code})
	err := app.DB.C("employees").Find(bson.M{"code": code}).One(&employee)
	if err != nil {
		session, err := app.Store.Get(r, "logo-spy")
		if err == nil {
			session.Values["user-id"] = employee.Id
			session.Save(r, w)
			http.Redirect(w, r, "/", http.StatusFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	} else {
		http.Redirect(w, r, "/login", http.StatusFound)
	}
}

func showRecord(w http.ResponseWriter, r *http.Request) {
	session, err := app.Store.Get(r, "logo-spy")
	if err == nil {
		fmt.Println(session.Values)
		employeeId := session.Values["user-id"]
		if employeeId != nil {
			renderTemplate(w, "index")
		} else {
			http.Redirect(w, r, "/login", http.StatusFound)
		}
	} else {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderTemplate(w http.ResponseWriter, tmpl_name string) {
	tmpl := app.Templates[tmpl_name+".html"]
	if tmpl != nil {
		tmpl.ExecuteTemplate(w, "layout", nil)
	} else {
		message := fmt.Sprintf("Template '%s' not found", tmpl_name)
		log.Printf(message)
		http.Error(w, message, http.StatusInternalServerError)
	}
}
<commit_msg>Set GOMAXPROCS to NumCPU<commit_after>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"runtime"
)

type App struct {
	Store     *sessions.CookieStore
	Mongo     *mgo.Session
	DB        *mgo.Database
	Templates map[string]*template.Template
}

func (app *App) Init() {
	var err error

	app.Store = sessions.NewCookieStore([]byte("07FdEM5Obo7BM2Kn4e1m-tZCC3IMfWLan0ealKM31"))
	app.Mongo, err = mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	app.Mongo.SetMode(mgo.Monotonic, true)
	app.DB = app.Mongo.DB("logo-spy")

	app.Templates = make(map[string]*template.Template)

	layout_path := "templates/layout.html"
	tmpl_paths, err := filepath.Glob("templates/*.html")
	if err != nil {
		panic(err)
	}
	for _, tmpl_path := range tmpl_paths {
		tmpl_name := filepath.Base(tmpl_path)
		if tmpl_name != "layout.html" {
			files := []string{tmpl_path, layout_path}
			app.Templates[tmpl_name] = template.Must(template.ParseFiles(files...))
		}
	}
}

func (app *App) Close() {
	app.Mongo.Close()
}

var app App

type Employee struct {
	Id    bson.ObjectId `bson:"_id"`
	Name  string        `bson:"name"`
	Code  string        `bson:"code"`
	Admin bool          `bson:"admin"`
}

type ViewData struct {
	Content string
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	app.Init()
	defer app.Close()

	rtr := mux.NewRouter()
	rtr.HandleFunc("/login", showLogin).Methods("GET")
	rtr.HandleFunc("/login", processLogin).Methods("POST")
	rtr.HandleFunc("/", showRecord).Methods("GET")

	fs := http.FileServer(http.Dir("static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))

	http.Handle("/", rtr)

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "3000"
	}
	log.Printf("Listening on port %s...", port)
	http.ListenAndServe(":"+port, nil)
}

func showLogin(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "login")
}

func processLogin(w http.ResponseWriter, r *http.Request) {
	fmt.Println(r.FormValue("code"))
	code, _ := strconv.Atoi(r.FormValue("code"))

	employee := Employee{}
	fmt.Println(bson.M{"code": code})
	err := app.DB.C("employees").Find(bson.M{"code": code}).One(&employee)
	if err != nil {
		session, err := app.Store.Get(r, "logo-spy")
		if err == nil {
			session.Values["user-id"] = employee.Id
			session.Save(r, w)
			http.Redirect(w, r, "/", http.StatusFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	} else {
		http.Redirect(w, r, "/login", http.StatusFound)
	}
}

func showRecord(w http.ResponseWriter, r *http.Request) {
	session, err := app.Store.Get(r, "logo-spy")
	if err == nil {
		fmt.Println(session.Values)
		employeeId := session.Values["user-id"]
		if employeeId != nil {
			renderTemplate(w, "index")
		} else {
			http.Redirect(w, r, "/login", http.StatusFound)
		}
	} else {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderTemplate(w http.ResponseWriter, tmpl_name string) {
	tmpl := app.Templates[tmpl_name+".html"]
	if tmpl != nil {
		tmpl.ExecuteTemplate(w, "layout", nil)
	} else {
		message := fmt.Sprintf("Template '%s' not found", tmpl_name)
		log.Printf(message)
		http.Error(w, message, http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package resource

type Provider interface {
	NewInstance(string) (Instance, error)
}

// TranslatedProvider manipulates resource locations, so as to allow
// sandboxing, or relative paths for example.
type TranslatedProvider struct {
	// The underlying Provider.
	BaseProvider Provider
	// Some location used in calculating final locations.
	BaseLocation string
	// Function that takes BaseLocation, and the caller location and returns
	// the location to be used with the BaseProvider.
	JoinLocations func(base, rel string) string
}

func (me *TranslatedProvider) NewInstance(rel string) (Instance, error) {
	return me.BaseProvider.NewInstance(me.JoinLocations(me.BaseLocation, rel))
}
<commit_msg>resource.TranslatedProvider doesn't require pointer receiver<commit_after>package resource

type Provider interface {
	NewInstance(string) (Instance, error)
}

// TranslatedProvider manipulates resource locations, so as to allow
// sandboxing, or relative paths for example.
type TranslatedProvider struct {
	// The underlying Provider.
	BaseProvider Provider
	// Some location used in calculating final locations.
	BaseLocation string
	// Function that takes BaseLocation, and the caller location and returns
	// the location to be used with the BaseProvider.
	JoinLocations func(base, rel string) string
}

func (me TranslatedProvider) NewInstance(rel string) (Instance, error) {
	return me.BaseProvider.NewInstance(me.JoinLocations(me.BaseLocation, rel))
}
<|endoftext|>


<commit_before>package logstore

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"hash/fnv"
	"os"
	"sync"
)

// ErrNoPartition is returned when the requested partition doesn't exist
var ErrNoPartition = errors.New("Partition doesn't exist")

// ErrShortPayload returned when UnMarshal is given a too small buffer of messages
var ErrShortPayload = errors.New("Too short payload of messages")

// LogStore is an immutable append-only storage engine for logs.
type LogStore struct {
	dataDir    string
	numParts   int
	Partitions []*Partition
}

// Partition bla bla
type Partition struct {
	*sync.Mutex
	Fd  *os.File
	Idx int
}

// Message is a representation of what gets stored on disk
type Message struct {
	Length   uint64
	Checksum uint32
	Payload  []byte
}

// New returns a new LogStore instance
func New(dataDir string, partitions int) *LogStore {
	l := &LogStore{dataDir, partitions, []*Partition{}}
	l.Setup()
	return l
}

func (l *LogStore) newPartition(idx int, fd *os.File) *Partition {
	return &Partition{&sync.Mutex{}, fd, idx}
}

// Setup makes sure that all the files are in place
func (l *LogStore) Setup() {
	os.Mkdir(l.dataDir, 0764)
	for i := 0; i < l.numParts; i++ {
		fname := fmt.Sprintf("%s%d.bilog", l.dataDir, i)
		if fd, error := os.OpenFile(fname, os.O_APPEND|os.O_RDWR, os.ModeAppend); error == nil {
			l.Partitions = append(l.Partitions, l.newPartition(i, fd))
			continue
		}
		_, err := os.Create(fname)
		if err != nil {
			panic(err)
		}
		fd, err := os.OpenFile(fname, os.O_APPEND|os.O_RDWR, os.ModeAppend)
		if err != nil {
			panic(err)
		}
		l.Partitions = append(l.Partitions, l.newPartition(i, fd))
	}
}

// Append appends the given message to the log file
func (l *LogStore) Append(pkey string, payload []byte) (n int64, err error) {
	fn := fnv.New32a()
	fn.Write([]byte(pkey))
	hash := fn.Sum32()
	idx := hash % uint32(l.numParts-1)
	prtn := l.Partitions[idx]
	msg := l.msgify(payload)
	prtn.Lock()
	defer prtn.Unlock()
	n, err = msg.WriteTo(prtn.Fd)
	return n, err
}

// Partition returns a refernce for the requested partition
func (l *LogStore) Partition(idx int) (*Partition, error) {
	if idx > l.numParts {
		return nil, ErrNoPartition
	}
	prtn := l.Partitions[idx]
	return prtn, nil
}

// UnMarshal deserializes the given byte slice into Messages
func (l *LogStore) UnMarshal(b []byte) ([]*Message, error) {
	msgs := []*Message{}
	blen := len(b)
	if blen < 13 {
		return nil, ErrShortPayload
	}
	s := 0
	for {
		msg := &Message{}
		n, err := l.parse(b[s:], msg)
		if err != nil {
			return nil, err
		}
		msgs = append(msgs, msg)
		s += n
		if s == blen {
			break
		}

	}
	return msgs, nil
}

func (l *LogStore) parse(payload []byte, msg *Message) (n int, err error) {
	ln := binary.BigEndian.Uint64(payload[:8])
	crc := binary.BigEndian.Uint32(payload[8:12])
	// TODO(KL): verify message against checksum
	m := payload[12:ln]
	msg.Length = ln
	msg.Payload = m
	msg.Checksum = crc
	return int(ln), nil
}

func (l *LogStore) Read(partition int, offset int64, buf []byte) (n int, err error) {
	if partition > l.numParts {
		return 0, ErrNoPartition
	}
	prtn := l.Partitions[partition]
	prtn.Lock()
	defer prtn.Unlock()
	prtn.Fd.Seek(offset, 0)
	rdr := bufio.NewReader(prtn.Fd)
	n, err = rdr.Read(buf)
	return
}

func (l *LogStore) msgify(payload []byte) *bytes.Buffer {
	buff := new(bytes.Buffer)
	// length/checksum+payload (8) + checksum (4) + N payload
	binary.Write(buff, binary.BigEndian, uint64(8+4+len(payload)))
	binary.Write(buff, binary.BigEndian, checksum(payload))
	binary.Write(buff, binary.BigEndian, payload)
	return buff
}

func checksum(data []byte) uint32 {
	tbl := crc32.MakeTable(0x04C11DB7)
	return crc32.Checksum(data, tbl)
}
<commit_msg>Replace Mutex with RWMutex<commit_after>package logstore

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"hash/fnv"
	"os"
	"sync"
)

// ErrNoPartition is returned when the requested partition doesn't exist
var ErrNoPartition = errors.New("Partition doesn't exist")

// ErrShortPayload returned when UnMarshal is given a too small buffer of messages
var ErrShortPayload = errors.New("Too short payload of messages")

// LogStore is an immutable append-only storage engine for logs.
type LogStore struct {
	dataDir    string
	numParts   int
	Partitions []*Partition
}

// Partition bla bla
type Partition struct {
	*sync.RWMutex
	Fd  *os.File
	Idx int
}

// Message is a representation of what gets stored on disk
type Message struct {
	Length   uint64
	Checksum uint32
	Payload  []byte
}

// New returns a new LogStore instance
func New(dataDir string, partitions int) *LogStore {
	l := &LogStore{dataDir, partitions, []*Partition{}}
	l.Setup()
	return l
}

func (l *LogStore) newPartition(idx int, fd *os.File) *Partition {
	return &Partition{&sync.RWMutex{}, fd, idx}
}

// Setup makes sure that all the files are in place
func (l *LogStore) Setup() {
	os.Mkdir(l.dataDir, 0764)
	for i := 0; i < l.numParts; i++ {
		fname := fmt.Sprintf("%s%d.bilog", l.dataDir, i)
		if fd, error := os.OpenFile(fname, os.O_APPEND|os.O_RDWR, os.ModeAppend); error == nil {
			l.Partitions = append(l.Partitions, l.newPartition(i, fd))
			continue
		}
		_, err := os.Create(fname)
		if err != nil {
			panic(err)
		}
		fd, err := os.OpenFile(fname, os.O_APPEND|os.O_RDWR, os.ModeAppend)
		if err != nil {
			panic(err)
		}
		l.Partitions = append(l.Partitions, l.newPartition(i, fd))
	}
}

// Append appends the given message to the log file
func (l *LogStore) Append(pkey string, payload []byte) (n int64, err error) {
	fn := fnv.New32a()
	fn.Write([]byte(pkey))
	hash := fn.Sum32()
	idx := hash % uint32(l.numParts-1)
	prtn := l.Partitions[idx]
	msg := l.msgify(payload)
	prtn.Lock()
	defer prtn.Unlock()
	n, err = msg.WriteTo(prtn.Fd)
	return n, err
}

// Partition returns a refernce for the requested partition
func (l *LogStore) Partition(idx int) (*Partition, error) {
	if idx > l.numParts {
		return nil, ErrNoPartition
	}
	prtn := l.Partitions[idx]
	return prtn, nil
}

// UnMarshal deserializes the given byte slice into Messages
func (l *LogStore) UnMarshal(b []byte) ([]*Message, error) {
	msgs := []*Message{}
	blen := len(b)
	if blen < 13 {
		return nil, ErrShortPayload
	}
	s := 0
	for {
		msg := &Message{}
		n, err := l.parse(b[s:], msg)
		if err != nil {
			return nil, err
		}
		msgs = append(msgs, msg)
		s += n
		if s == blen {
			break
		}

	}
	return msgs, nil
}

func (l *LogStore) parse(payload []byte, msg *Message) (n int, err error) {
	ln := binary.BigEndian.Uint64(payload[:8])
	crc := binary.BigEndian.Uint32(payload[8:12])
	// TODO(KL): verify message against checksum
	m := payload[12:ln]
	msg.Length = ln
	msg.Payload = m
	msg.Checksum = crc
	return int(ln), nil
}

func (l *LogStore) Read(partition int, offset int64, buf []byte) (n int, err error) {
	if partition > l.numParts {
		return 0, ErrNoPartition
	}
	prtn := l.Partitions[partition]
	prtn.RLock()
	defer prtn.RUnlock()
	prtn.Fd.Seek(offset, 0)
	rdr := bufio.NewReader(prtn.Fd)
	n, err = rdr.Read(buf)
	return
}

func (l *LogStore) msgify(payload []byte) *bytes.Buffer {
	buff := new(bytes.Buffer)
	// length/checksum+payload (8) + checksum (4) + N payload
	binary.Write(buff, binary.BigEndian, uint64(8+4+len(payload)))
	binary.Write(buff, binary.BigEndian, checksum(payload))
	binary.Write(buff, binary.BigEndian, payload)
	return buff
}

func checksum(data []byte) uint32 {
	tbl := crc32.MakeTable(0x04C11DB7)
	return crc32.Checksum(data, tbl)
}
<|endoftext|>


<commit_before>package autoupdate

import (
	"fmt"
	"github.com/materials-commons/materials"
	"time"
)

var updater = NewUpdater()

// StartUpdateMonitor starts a back ground task that periodically
// checks for update to the materials command and website, downloads
// and deploys them. If the materials command is updated then the
// materials server is restarted.
func StartUpdateMonitor() {
	go updateMonitor()
}

// updateMonitor is the back ground monitor that checks for
// updates to the materials command and website. It checks
// for updates every materials.Config.UpdateCheckInterval().
func updateMonitor() {

	for {
		materials.Config.Server.LastUpdateCheck = timeStrNow()
		materials.Config.Server.NextUpdateCheck = timeStrAfterUpdateInterval()
		if updater.UpdatesAvailable() {
			updater.ApplyUpdates()
		}
		time.Sleep(materials.Config.Server.UpdateCheckInterval)
	}
}

func timeStrNow() string {
	n := time.Now()
	return formatTime(n)
}

func timeStrAfterUpdateInterval() string {
	n := time.Now()
	n = n.Add(materials.Config.Server.UpdateCheckInterval)
	return formatTime(n)
}

func formatTime(t time.Time) string {
	return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
		t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
}
<commit_msg>Remove extra line.<commit_after>package autoupdate

import (
	"fmt"
	"github.com/materials-commons/materials"
	"time"
)

var updater = NewUpdater()

// StartUpdateMonitor starts a back ground task that periodically
// checks for update to the materials command and website, downloads
// and deploys them. If the materials command is updated then the
// materials server is restarted.
func StartUpdateMonitor() {
	go updateMonitor()
}

// updateMonitor is the back ground monitor that checks for
// updates to the materials command and website. It checks
// for updates every materials.Config.UpdateCheckInterval().
func updateMonitor() {
	for {
		materials.Config.Server.LastUpdateCheck = timeStrNow()
		materials.Config.Server.NextUpdateCheck = timeStrAfterUpdateInterval()
		if updater.UpdatesAvailable() {
			updater.ApplyUpdates()
		}
		time.Sleep(materials.Config.Server.UpdateCheckInterval)
	}
}

func timeStrNow() string {
	n := time.Now()
	return formatTime(n)
}

func timeStrAfterUpdateInterval() string {
	n := time.Now()
	n = n.Add(materials.Config.Server.UpdateCheckInterval)
	return formatTime(n)
}

func formatTime(t time.Time) string {
	return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
		t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
}
<|endoftext|>


<commit_before>package aws

import (
	"bytes"
	"fmt"
	"github.com/awslabs/aws-sdk-go/aws/awserr"
	"github.com/awslabs/aws-sdk-go/internal/apierr"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"time"
)

var sleepDelay = func(delay time.Duration) {
	time.Sleep(delay)
}

// Interface for matching types which also have a Len method.
type lener interface {
	Len() int
}

// BuildContentLength builds the content length of a request based on the body,
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
// to determine request body length and no "Content-Length" was specified it will panic.
func BuildContentLength(r *Request) {
	if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
		length, _ := strconv.ParseInt(slength, 10, 64)
		r.HTTPRequest.ContentLength = length
		return
	}

	var length int64
	switch body := r.Body.(type) {
	case nil:
		length = 0
	case lener:
		length = int64(body.Len())
	case io.Seeker:
		r.bodyStart, _ = body.Seek(0, 1)
		end, _ := body.Seek(0, 2)
		body.Seek(r.bodyStart, 0) // make sure to seek back to original location
		length = end - r.bodyStart
	default:
		panic("Cannot get length of body, must provide `ContentLength`")
	}

	r.HTTPRequest.ContentLength = length
	r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
}

// UserAgentHandler is a request handler for injecting User agent into requests.
func UserAgentHandler(r *Request) {
	r.HTTPRequest.Header.Set("User-Agent", SDKName+"/"+SDKVersion)
}

var reStatusCode = regexp.MustCompile(`^(\d+)`)

// SendHandler is a request handler to send service request using HTTP client.
func SendHandler(r *Request) {
	var err error
	r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
	if err != nil {
		// Capture the case where url.Error is returned for error processing
		// response. e.g. 301 without location header comes back as string
		// error and r.HTTPResponse is nil. Other url redirect errors will
		// comeback in a similar method.
		if e, ok := err.(*url.Error); ok {
			if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil {
				code, _ := strconv.ParseInt(s[1], 10, 64)
				r.HTTPResponse = &http.Response{
					StatusCode: int(code),
					Status:     http.StatusText(int(code)),
					Body:       ioutil.NopCloser(bytes.NewReader([]byte{})),
				}
				return
			}
		}
		// Catch all other request errors.
		r.Error = apierr.New("RequestError", "send request failed", err)
	}
}

// ValidateResponseHandler is a request handler to validate service response.
func ValidateResponseHandler(r *Request) {
	if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
		// this may be replaced by an UnmarshalError handler
		r.Error = apierr.New("UnknownError", "unknown error", nil)
	}
}

// AfterRetryHandler performs final checks to determine if the request should
// be retried and how long to delay.
func AfterRetryHandler(r *Request) {
	// If one of the other handlers already set the retry state
	// we don't want to override it based on the service's state
	if !r.Retryable.IsSet() {
		r.Retryable.Set(r.Service.ShouldRetry(r))
	}

	if r.WillRetry() {
		r.RetryDelay = r.Service.RetryRules(r)
		sleepDelay(r.RetryDelay)

		// when the expired token exception occurs the credentials
		// need to be expired locally so that the next request to
		// get credentials will trigger a credentials refresh.
		if r.Error != nil {
			if err, ok := r.Error.(awserr.Error); ok && err.Code() == "ExpiredTokenException" {
				r.Config.Credentials.Expire()
				// The credentials will need to be resigned with new credentials
				r.signed = false
			}
		}

		r.RetryCount++
		r.Error = nil
	}
}

var (
	// ErrMissingRegion is an error that is returned if region configuration is
	// not found.
	ErrMissingRegion error = apierr.New("MissingRegion", "could not find region configuration", nil)

	// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
	// resolved for a service.
	ErrMissingEndpoint error = apierr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
)

// ValidateEndpointHandler is a request handler to validate a request had the
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
// region is not valid.
func ValidateEndpointHandler(r *Request) {
	if r.Service.SigningRegion == "" && r.Service.Config.Region == "" {
		r.Error = ErrMissingRegion
	} else if r.Service.Endpoint == "" {
		r.Error = ErrMissingEndpoint
	}
}
<commit_msg>Make network errors retryable<commit_after>package aws

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"time"

	"github.com/awslabs/aws-sdk-go/aws/awserr"
	"github.com/awslabs/aws-sdk-go/internal/apierr"
)

var sleepDelay = func(delay time.Duration) {
	time.Sleep(delay)
}

// Interface for matching types which also have a Len method.
type lener interface {
	Len() int
}

// BuildContentLength builds the content length of a request based on the body,
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
// to determine request body length and no "Content-Length" was specified it will panic.
func BuildContentLength(r *Request) {
	if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
		length, _ := strconv.ParseInt(slength, 10, 64)
		r.HTTPRequest.ContentLength = length
		return
	}

	var length int64
	switch body := r.Body.(type) {
	case nil:
		length = 0
	case lener:
		length = int64(body.Len())
	case io.Seeker:
		r.bodyStart, _ = body.Seek(0, 1)
		end, _ := body.Seek(0, 2)
		body.Seek(r.bodyStart, 0) // make sure to seek back to original location
		length = end - r.bodyStart
	default:
		panic("Cannot get length of body, must provide `ContentLength`")
	}

	r.HTTPRequest.ContentLength = length
	r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
}

// UserAgentHandler is a request handler for injecting User agent into requests.
func UserAgentHandler(r *Request) {
	r.HTTPRequest.Header.Set("User-Agent", SDKName+"/"+SDKVersion)
}

var reStatusCode = regexp.MustCompile(`^(\d+)`)

// SendHandler is a request handler to send service request using HTTP client.
func SendHandler(r *Request) {
	var err error
	r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
	if err != nil {
		// Capture the case where url.Error is returned for error processing
		// response. e.g. 301 without location header comes back as string
		// error and r.HTTPResponse is nil. Other url redirect errors will
		// comeback in a similar method.
		if e, ok := err.(*url.Error); ok {
			if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil {
				code, _ := strconv.ParseInt(s[1], 10, 64)
				r.HTTPResponse = &http.Response{
					StatusCode: int(code),
					Status:     http.StatusText(int(code)),
					Body:       ioutil.NopCloser(bytes.NewReader([]byte{})),
				}
				return
			}
		}
		// Catch all other request errors.
		r.Error = apierr.New("RequestError", "send request failed", err)
		r.Retryable.Set(true) // network errors are retryable
	}
}

// ValidateResponseHandler is a request handler to validate service response.
func ValidateResponseHandler(r *Request) {
	if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
		// this may be replaced by an UnmarshalError handler
		r.Error = apierr.New("UnknownError", "unknown error", nil)
	}
}

// AfterRetryHandler performs final checks to determine if the request should
// be retried and how long to delay.
func AfterRetryHandler(r *Request) {
	// If one of the other handlers already set the retry state
	// we don't want to override it based on the service's state
	if !r.Retryable.IsSet() {
		r.Retryable.Set(r.Service.ShouldRetry(r))
	}

	if r.WillRetry() {
		r.RetryDelay = r.Service.RetryRules(r)
		sleepDelay(r.RetryDelay)

		// when the expired token exception occurs the credentials
		// need to be expired locally so that the next request to
		// get credentials will trigger a credentials refresh.
		if r.Error != nil {
			if err, ok := r.Error.(awserr.Error); ok && err.Code() == "ExpiredTokenException" {
				r.Config.Credentials.Expire()
				// The credentials will need to be resigned with new credentials
				r.signed = false
			}
		}

		r.RetryCount++
		r.Error = nil
	}
}

var (
	// ErrMissingRegion is an error that is returned if region configuration is
	// not found.
	ErrMissingRegion error = apierr.New("MissingRegion", "could not find region configuration", nil)

	// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
	// resolved for a service.
	ErrMissingEndpoint error = apierr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
)

// ValidateEndpointHandler is a request handler to validate a request had the
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
// region is not valid.
func ValidateEndpointHandler(r *Request) {
	if r.Service.SigningRegion == "" && r.Service.Config.Region == "" {
		r.Error = ErrMissingRegion
	} else if r.Service.Endpoint == "" {
		r.Error = ErrMissingEndpoint
	}
}
<|endoftext|>


<commit_before>package accessor

import (
	"fmt"
	"strings"

	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/db"
)

//go:generate counterfeiter . Access

type Access interface {
	HasToken() bool
	IsAuthenticated() bool
	IsAuthorized(string) bool
	IsAdmin() bool
	IsSystem() bool
	TeamNames() []string
	TeamRoles() map[string][]string
	Claims() Claims
}

type Claims struct {
	Sub       string
	Name      string
	UserID    string
	UserName  string
	Email     string
	Connector string
}

type Verification struct {
	HasToken     bool
	IsTokenValid bool
	RawClaims    map[string]interface{}
}

type access struct {
	verification      Verification
	requiredRole      string
	systemClaimKey    string
	systemClaimValues []string
	teams             []db.Team
}

func NewAccessor(
	verification Verification,
	requiredRole string,
	systemClaimKey string,
	systemClaimValues []string,
	teams []db.Team,
) *access {
	return &access{
		verification:      verification,
		requiredRole:      requiredRole,
		systemClaimKey:    systemClaimKey,
		systemClaimValues: systemClaimValues,
		teams:             teams,
	}
}

func (a *access) HasToken() bool {
	return a.verification.HasToken
}

func (a *access) IsAuthenticated() bool {
	return a.verification.IsTokenValid
}

func (a *access) IsAuthorized(teamName string) bool {

	if a.IsAdmin() {
		return true
	}

	for _, team := range a.TeamNames() {
		if team == teamName {
			return true
		}
	}

	return false
}

func (a *access) TeamNames() []string {

	teamNames := []string{}

	isAdmin := a.IsAdmin()

	for _, team := range a.teams {
		if isAdmin || a.hasRequiredRole(team.Auth()) {
			teamNames = append(teamNames, team.Name())
		}
	}

	return teamNames
}

func (a *access) hasRequiredRole(auth atc.TeamAuth) bool {
	for _, teamRole := range a.rolesForTeam(auth) {
		if a.hasPermission(teamRole) {
			return true
		}
	}
	return false
}

func (a *access) teamRoles() map[string][]string {

	teamRoles := map[string][]string{}

	for _, team := range a.teams {
		if roles := a.rolesForTeam(team.Auth()); len(roles) > 0 {
			teamRoles[team.Name()] = roles
		}
	}

	return teamRoles
}

func (a *access) rolesForTeam(auth atc.TeamAuth) []string {

	roleSet := map[string]bool{}

	groups := a.groups()
	connectorID := a.connectorID()
	userID := a.userID()
	userName := a.UserName()

	for role, auth := range auth {
		userAuth := auth["users"]
		groupAuth := auth["groups"]

		// backwards compatibility for allow-all-users
		if len(userAuth) == 0 && len(groupAuth) == 0 {
			roleSet[role] = true
		}

		for _, user := range userAuth {
			if userID != "" {
				if strings.EqualFold(user, fmt.Sprintf("%v:%v", connectorID, userID)) {
					roleSet[role] = true
				}
			}
			if userName != "" {
				if strings.EqualFold(user, fmt.Sprintf("%v:%v", connectorID, userName)) {
					roleSet[role] = true
				}
			}
		}

		for _, group := range groupAuth {
			for _, claimGroup := range groups {
				if claimGroup != "" {
					if strings.EqualFold(group, fmt.Sprintf("%v:%v", connectorID, claimGroup)) {
						roleSet[role] = true
					}
				}
			}
		}
	}

	var roles []string
	for role := range roleSet {
		roles = append(roles, role)
	}
	return roles
}

func (a *access) hasPermission(role string) bool {
	switch a.requiredRole {
	case OwnerRole:
		return role == OwnerRole
	case MemberRole:
		return role == OwnerRole || role == MemberRole
	case OperatorRole:
		return role == OwnerRole || role == MemberRole || role == OperatorRole
	case ViewerRole:
		return role == OwnerRole || role == MemberRole || role == OperatorRole || role == ViewerRole
	default:
		return false
	}
}

func (a *access) claims() map[string]interface{} {
	if a.IsAuthenticated() {
		return a.verification.RawClaims
	}
	return map[string]interface{}{}
}

func (a *access) federatedClaims() map[string]interface{} {
	if raw, ok := a.claims()["federated_claims"]; ok {
		if claim, ok := raw.(map[string]interface{}); ok {
			return claim
		}
	}
	return map[string]interface{}{}
}

func (a *access) federatedClaim(name string) string {
	if raw, ok := a.federatedClaims()[name]; ok {
		if claim, ok := raw.(string); ok {
			return claim
		}
	}
	return ""
}

func (a *access) claim(name string) string {
	if raw, ok := a.claims()[name]; ok {
		if claim, ok := raw.(string); ok {
			return claim
		}
	}
	return ""
}

func (a *access) UserName() string {
	return a.federatedClaim("user_name")
}

func (a *access) userID() string {
	return a.federatedClaim("user_id")
}

func (a *access) connectorID() string {
	return a.federatedClaim("connector_id")
}

func (a *access) groups() []string {
	groups := []string{}
	if raw, ok := a.claims()["groups"]; ok {
		if rawGroups, ok := raw.([]interface{}); ok {
			for _, rawGroup := range rawGroups {
				if group, ok := rawGroup.(string); ok {
					groups = append(groups, group)
				}
			}
		}
	}
	return groups
}

func (a *access) adminTeams() []string {
	var adminTeams []string

	for _, team := range a.teams {
		if team.Admin() {
			adminTeams = append(adminTeams, team.Name())
		}
	}
	return adminTeams
}

func (a *access) IsAdmin() bool {

	teamRoles := a.teamRoles()

	for _, adminTeam := range a.adminTeams() {
		for _, role := range teamRoles[adminTeam] {
			if role == "owner" {
				return true
			}
		}
	}

	return false
}

func (a *access) IsSystem() bool {
	if claim := a.claim(a.systemClaimKey); claim != "" {
		for _, value := range a.systemClaimValues {
			if value == claim {
				return true
			}
		}
	}
	return false
}

func (a *access) TeamRoles() map[string][]string {
	return a.teamRoles()
}

func (a *access) Claims() Claims {
	return Claims{
		Sub:       a.claim("sub"),
		Name:      a.claim("name"),
		Email:     a.claim("email"),
		UserID:    a.userID(),
		UserName:  a.UserName(),
		Connector: a.connectorID(),
	}
}
<commit_msg>api: optimize accessor<commit_after>package accessor

import (
	"fmt"
	"strings"

	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/db"
)

//go:generate counterfeiter . Access

type Access interface {
	HasToken() bool
	IsAuthenticated() bool
	IsAuthorized(string) bool
	IsAdmin() bool
	IsSystem() bool
	TeamNames() []string
	TeamRoles() map[string][]string
	Claims() Claims
}

type Claims struct {
	Sub       string
	Name      string
	UserID    string
	UserName  string
	Email     string
	Connector string
}

type Verification struct {
	HasToken     bool
	IsTokenValid bool
	RawClaims    map[string]interface{}
}

type access struct {
	verification      Verification
	requiredRole      string
	systemClaimKey    string
	systemClaimValues []string
	teams             []db.Team
	teamRoles         map[string][]string
	isAdmin           bool
}

func NewAccessor(
	verification Verification,
	requiredRole string,
	systemClaimKey string,
	systemClaimValues []string,
	teams []db.Team,
) *access {
	a := &access{
		verification:      verification,
		requiredRole:      requiredRole,
		systemClaimKey:    systemClaimKey,
		systemClaimValues: systemClaimValues,
		teams:             teams,
	}
	a.computeTeamRoles()
	return a
}

func (a *access) computeTeamRoles() {
	a.teamRoles = map[string][]string{}

	for _, team := range a.teams {
		roles := a.rolesForTeam(team.Auth())
		if len(roles) > 0 {
			a.teamRoles[team.Name()] = roles
		}
		if team.Admin() && contains(roles, "owner") {
			a.isAdmin = true
		}
	}
}

func contains(arr []string, val string) bool {
	for _, v := range arr {
		if v == val {
			return true
		}
	}
	return false
}

func (a *access) rolesForTeam(auth atc.TeamAuth) []string {
	roleSet := map[string]bool{}

	groups := a.groups()
	connectorID := a.connectorID()
	userID := a.userID()
	userName := a.UserName()

	for role, auth := range auth {
		userAuth := auth["users"]
		groupAuth := auth["groups"]

		// backwards compatibility for allow-all-users
		if len(userAuth) == 0 && len(groupAuth) == 0 {
			roleSet[role] = true
		}

		for _, user := range userAuth {
			if userID != "" {
				if strings.EqualFold(user, fmt.Sprintf("%v:%v", connectorID, userID)) {
					roleSet[role] = true
				}
			}
			if userName != "" {
				if strings.EqualFold(user, fmt.Sprintf("%v:%v", connectorID, userName)) {
					roleSet[role] = true
				}
			}
		}

		for _, group := range groupAuth {
			for _, claimGroup := range groups {
				if claimGroup != "" {
					if strings.EqualFold(group, fmt.Sprintf("%v:%v", connectorID, claimGroup)) {
						roleSet[role] = true
					}
				}
			}
		}
	}

	var roles []string
	for role := range roleSet {
		roles = append(roles, role)
	}
	return roles
}

func (a *access) HasToken() bool {
	return a.verification.HasToken
}

func (a *access) IsAuthenticated() bool {
	return a.verification.IsTokenValid
}

func (a *access) IsAuthorized(teamName string) bool {
	return a.isAdmin || a.hasPermission(a.teamRoles[teamName])
}

func (a *access) TeamNames() []string {
	teamNames := []string{}
	for _, team := range a.teams {
		if a.isAdmin || a.hasPermission(a.teamRoles[team.Name()]) {
			teamNames = append(teamNames, team.Name())
		}
	}

	return teamNames
}

func (a *access) hasPermission(roles []string) bool {
	for _, role := range roles {
		switch a.requiredRole {
		case OwnerRole:
			return role == OwnerRole
		case MemberRole:
			return role == OwnerRole || role == MemberRole
		case OperatorRole:
			return role == OwnerRole || role == MemberRole || role == OperatorRole
		case ViewerRole:
			return role == OwnerRole || role == MemberRole || role == OperatorRole || role == ViewerRole
		default:
			return false
		}
	}
	return false
}

func (a *access) claims() map[string]interface{} {
	if a.IsAuthenticated() {
		return a.verification.RawClaims
	}
	return map[string]interface{}{}
}

func (a *access) federatedClaims() map[string]interface{} {
	if raw, ok := a.claims()["federated_claims"]; ok {
		if claim, ok := raw.(map[string]interface{}); ok {
			return claim
		}
	}
	return map[string]interface{}{}
}

func (a *access) federatedClaim(name string) string {
	if raw, ok := a.federatedClaims()[name]; ok {
		if claim, ok := raw.(string); ok {
			return claim
		}
	}
	return ""
}

func (a *access) claim(name string) string {
	if raw, ok := a.claims()[name]; ok {
		if claim, ok := raw.(string); ok {
			return claim
		}
	}
	return ""
}

func (a *access) UserName() string {
	return a.federatedClaim("user_name")
}

func (a *access) userID() string {
	return a.federatedClaim("user_id")
}

func (a *access) connectorID() string {
	return a.federatedClaim("connector_id")
}

func (a *access) groups() []string {
	groups := []string{}
	if raw, ok := a.claims()["groups"]; ok {
		if rawGroups, ok := raw.([]interface{}); ok {
			for _, rawGroup := range rawGroups {
				if group, ok := rawGroup.(string); ok {
					groups = append(groups, group)
				}
			}
		}
	}
	return groups
}

func (a *access) IsAdmin() bool {
	return a.isAdmin
}

func (a *access) IsSystem() bool {
	if claim := a.claim(a.systemClaimKey); claim != "" {
		for _, value := range a.systemClaimValues {
			if value == claim {
				return true
			}
		}
	}
	return false
}

func (a *access) TeamRoles() map[string][]string {
	return a.teamRoles
}

func (a *access) Claims() Claims {
	return Claims{
		Sub:       a.claim("sub"),
		Name:      a.claim("name"),
		Email:     a.claim("email"),
		UserID:    a.userID(),
		UserName:  a.UserName(),
		Connector: a.connectorID(),
	}
}
<|endoftext|>


<commit_before>package handlers

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

	"github.com/gilcrest/go-API-template/pkg/domain/appUser"
	"github.com/gilcrest/go-API-template/pkg/env"
)

// CreateUserHandler creates a user in the database
func CreateUserHandler(env *env.Env, w http.ResponseWriter, req *http.Request) error {

	// retrieve the context from the http.Request
	ctx := req.Context()

	// Get a new logger instance
	logger := env.Logger
	defer env.Logger.Sync()

	logger.Debug("CreateUserHandler started")
	defer logger.Debug("CreateUserHandler ended")

	var err error

	// Declare usr as an instance of appUser.User
	// Decode JSON HTTP request body into a Decoder type
	//  and unmarshal that into usr
	var usr *appUser.User
	err = json.NewDecoder(req.Body).Decode(&usr)
	if err != nil {
		return HTTPStatusError{http.StatusInternalServerError, err}
	}
	defer req.Body.Close()

	// Call the create method of the appUser object to validate data and write to db
	rows, tx, err := usr.Create(ctx, env)

	// If we have successfully written rows to the db, we commit the transaction
	if rows == 1 {
		err = tx.Commit()
		if err != nil {
			// We return a status error here, which conveniently wraps the error
			// returned from our DB queries. We can clearly define which errors
			// are worth raising a HTTP 500 over vs. which might just be a HTTP
			// 404, 403 or 401 (as appropriate). It's also clear where our
			// handler should stop processing by returning early.
			return HTTPStatusError{http.StatusInternalServerError, err}
		}
	} else if rows <= 0 {
		return HTTPStatusError{http.StatusInternalServerError, err}
	}

	// TODO - Get a unique Request ID and add it to the header and logs via
	// a middleware
	w.Header().Set("Request-Id", "123456789")

	// Encode usr struct to JSON for the response body
	json.NewEncoder(w).Encode(*usr)

	return nil

}
<commit_msg>Changed db approach to send back updated default fields<commit_after>package handlers

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

	"github.com/gilcrest/go-API-template/pkg/domain/appUser"
	"github.com/gilcrest/go-API-template/pkg/env"
)

// CreateUserHandler creates a user in the database
func CreateUserHandler(env *env.Env, w http.ResponseWriter, req *http.Request) error {

	// retrieve the context from the http.Request
	ctx := req.Context()

	// Get a new logger instance
	logger := env.Logger
	defer env.Logger.Sync()

	logger.Debug("CreateUserHandler started")
	defer logger.Debug("CreateUserHandler ended")

	var err error

	// Declare usr as an instance of appUser.User
	// Decode JSON HTTP request body into a Decoder type
	//  and unmarshal that into usr
	var usr *appUser.User
	err = json.NewDecoder(req.Body).Decode(&usr)
	if err != nil {
		return HTTPStatusError{http.StatusInternalServerError, err}
	}
	defer req.Body.Close()

	// Call the create method of the appUser object to validate data and write to db
	tx, err := usr.Create(ctx, env)

	// If we have successfully written rows to the db, we commit the transaction
	if !usr.CreateDate.IsZero() {
		err = tx.Commit()
		if err != nil {
			// We return a status error here, which conveniently wraps the error
			// returned from our DB queries. We can clearly define which errors
			// are worth raising a HTTP 500 over vs. which might just be a HTTP
			// 404, 403 or 401 (as appropriate). It's also clear where our
			// handler should stop processing by returning early.
			return HTTPStatusError{http.StatusInternalServerError, err}
		}
	} else {
		return HTTPStatusError{http.StatusInternalServerError, err}
	}

	// TODO - Get a unique Request ID and add it to the header and logs via
	// a middleware
	w.Header().Set("Request-Id", "123456789")

	// Encode usr struct to JSON for the response body
	json.NewEncoder(w).Encode(*usr)

	return nil

}
<|endoftext|>


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

package common

// Xor computes `a XOR b`, as defined by RFC 4493.
func Xor(a []byte, b []byte) []byte {
	if len(a) != len(b) {
		panic("Xor requires buffers to have identical lengths.")
	}

	output := make([]byte, len(a))
	for i, _ := range a {
		output[i] = a[i] ^ b[i]
	}

	return output
}
<commit_msg>Updated Xor.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

// Xor computes `a XOR b`, as defined by RFC 4493. dst, a, and b must all have
// the same length.
func Xor(dst []byte, a []byte, b []byte) {
	if len(dst) != len(a) || len(a) != len(b) {
		panic("Xor requires buffers to have identical lengths.")
	}

	for i, _ := range a {
		dst[i] = a[i] ^ b[i]
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jyggen/pingu/pingu"
	"github.com/nlopes/slack"
	"github.com/spf13/viper"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

type plugin struct {
	channel      string
	client       *client
	global       *leaderboard
	leaderboards leaderboardList
}

var leaderboardRegex *regexp.Regexp
var version string

func init() {
	leaderboardRegex = regexp.MustCompile("^!leaderboard(?: ([\\d]{4}))?$")
}

func New(c *viper.Viper) pingu.Plugin {
	return pingu.Plugin(&plugin{
		channel: c.GetString("aoc.channel"),
		client: &client{
			httpClient: &http.Client{
				Timeout: c.GetDuration("aoc.timeout") * time.Second,
			},
			ownerId: c.GetInt("aoc.owner"),
			session: c.GetString("aoc.session"),
		},
		global: &leaderboard{},
	})
}

func (pl *plugin) Author() pingu.Author {
	return pingu.Author{
		Email: "jonas@stendahl.me",
		Name:  "Jonas Stendahl",
	}
}

func (pl *plugin) Commands() pingu.Commands {
	return pingu.Commands{
		&pingu.Command{
			Description: "Prints either the global leaderboard, or the leaderboard for a specific year.",
			Func:        pl.postLeaderboard,
			Trigger:     leaderboardRegex,
		},
		&pingu.Command{
			Description: "Forces a refresh of all leaderboards.",
			Func: func(pi *pingu.Pingu, ev *slack.MessageEvent) {
				if ev.Channel != pl.channel {
					pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
					return
				}

				pl.refreshLeaderboards(pi)
			},
			Trigger: regexp.MustCompile("^!refresh$"),
		},
	}
}

func (pl *plugin) Name() string {
	return "Advent of Code"
}

func (pl *plugin) Tasks() pingu.Tasks {
	return pingu.Tasks{
		&pingu.Task{
			Func:     pl.refreshLeaderboards,
			Interval: time.Hour,
		},
	}
}

func (pl *plugin) Version() string {
	return version
}

func (pl *plugin) announceChanges(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

OurLoop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				if our.TotalStars != their.TotalStars {
					diff := calculateDifference(our.Stars, their.Stars)
					diffLen := len(diff)

					if diffLen != 0 {
						starsMessage := pl.buildChangeMessage(diff)

						var starsLabel string

						if diffLen != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						message := fmt.Sprintf("_%s_ earned *%d %s* by completing _%s_", our.Name, diffLen, starsLabel, starsMessage)

						if their.Position > our.Position {
							message += fmt.Sprintf(", moving up to *position %d*", our.Position)
						} else if their.Position < our.Position {
							message += fmt.Sprintf(", moving down to *position %d*", our.Position)
						} else {
							message += fmt.Sprintf(", staying at *position %d*", our.Position)
						}

						if our.TotalStars != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						pi.Say(message+fmt.Sprintf(
							" with *%d %s* (%.2f%%)!",
							our.TotalStars,
							starsLabel,
							float64(our.TotalStars)/float64(availableStars)*100,
						), pl.channel)
					}
				}

				continue OurLoop
			}
		}

		var starsLabel string

		if our.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! _%s_ has joined our ranks, starting at position *%d* with *%d %s* (%.2f%%) collected.",
			our.Name,
			our.Position,
			our.TotalStars,
			starsLabel,
			float64(our.TotalStars)/float64(availableStars)*100,
		), pl.channel)
	}

TheirLoop:
	for _, their := range a.Members {
		for _, our := range b.Members {
			if their.Id == our.Id {
				continue TheirLoop
			}
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! It seems like _%s_ has left our ranks. The leaderboards have been recalculated.",
			their.Name,
		), pl.channel)
	}
}

func (pl *plugin) buildChangeMessage(l starList) string {
	numOfStars := len(l)

	if numOfStars == 0 {
		return ""
	}

	stars := make([]string, numOfStars)

	for i, s := range l {
		stars[i] = fmt.Sprintf("Day %d Part %d (%d)", s.Day, s.Part, s.Year)
	}

	starsString := strings.Join([]string{
		strings.Join(stars[:numOfStars-1], "_, _"),
		stars[numOfStars-1],
	}, "_ and _")

	if starsString[0:7] == "_ and _" {
		starsString = starsString[7:]
	}

	return starsString
}

func (pl *plugin) buildLeaderboard(l *leaderboard) string {
	availableStars := calculateAvailableStars(time.Now(), l.Year)
	message := ""

	for _, m := range l.Members {
		var starsLabel string

		if m.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		message += fmt.Sprintf(
			"*%d.* _%s_ with *%d %s* (%.2f%%) collected.\n",
			m.Position,
			m.Name,
			m.TotalStars,
			starsLabel,
			float64(m.TotalStars)/float64(availableStars)*100,
		)
	}

	return message
}

func (pl *plugin) postLeaderboard(pi *pingu.Pingu, ev *slack.MessageEvent) {
	if ev.Channel != pl.channel {
		pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
		return
	}

	var board *leaderboard

	match := leaderboardRegex.FindStringSubmatch(ev.Text)

	if len(match) == 2 {
		year, _ := strconv.Atoi(match[1])

		for _, l := range pl.leaderboards {
			if l.Year == year {
				board = l
			}
		}

		if board == nil {
			pi.Reply(ev, fmt.Sprintf("Noot! Noot! %d does not have a leaderboard!", year))
		}
	} else {
		board = pl.global
	}

	pi.Say(pl.buildLeaderboard(board), ev.Channel)
}

func (pl *plugin) refreshGlobalLeaderboard() {
	members := make(map[int]*member)

	for _, l := range pl.leaderboards {
		for _, m := range l.Members {
			if _, ok := members[m.Id]; !ok {
				members[m.Id] = &member{
					Id:   m.Id,
					Name: m.Name,
				}
			}

			members[m.Id].GlobalScore += m.GlobalScore
			members[m.Id].LocalScore += m.LocalScore
			members[m.Id].Stars = append(members[m.Id].Stars, m.Stars...)
			members[m.Id].TotalStars += m.TotalStars

			if members[m.Id].LastStarAt.Before(m.LastStarAt) {
				members[m.Id].LastStarAt = m.LastStarAt
			}
		}
	}

	pl.global.Members = make(memberList, len(members))
	i := 0

	for _, m := range members {
		pl.global.Members[i] = m
		i++
	}

	pl.global.Sort()
}

func (pl *plugin) refreshLeaderboards(pi *pingu.Pingu) {
Loop:
	for _, year := range getValidYears(time.Now()) {
		for _, l := range pl.leaderboards {
			if l.Year == year {
				continue Loop
			}
		}

		pl.leaderboards = append(pl.leaderboards, &leaderboard{
			Year: year,
		})
	}

	var wg sync.WaitGroup

	wg.Add(len(pl.leaderboards))

	for _, l := range pl.leaderboards {
		go func(l *leaderboard) {
			err := l.Refresh(pl.client)

			if err != nil {
				pi.Logger().Error(err)
			}

			wg.Done()
		}(l)
	}

	wg.Wait()

	before := *pl.global
	pl.refreshGlobalLeaderboard()
	after := *pl.global

	if len(before.Members) != 0 {
		pl.announceChanges(pi, before, after)
	}
}
<commit_msg>Announce changes on yearly leaderboards instead of global<commit_after>package main

import (
	"fmt"
	"github.com/jyggen/pingu/pingu"
	"github.com/nlopes/slack"
	"github.com/spf13/viper"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

type plugin struct {
	channel      string
	client       *client
	global       *leaderboard
	leaderboards leaderboardList
}

var leaderboardRegex *regexp.Regexp
var version string

func init() {
	leaderboardRegex = regexp.MustCompile("^!leaderboard(?: ([\\d]{4}))?$")
}

func New(c *viper.Viper) pingu.Plugin {
	return pingu.Plugin(&plugin{
		channel: c.GetString("aoc.channel"),
		client: &client{
			httpClient: &http.Client{
				Timeout: c.GetDuration("aoc.timeout") * time.Second,
			},
			ownerId: c.GetInt("aoc.owner"),
			session: c.GetString("aoc.session"),
		},
		global: &leaderboard{},
	})
}

func (pl *plugin) Author() pingu.Author {
	return pingu.Author{
		Email: "jonas@stendahl.me",
		Name:  "Jonas Stendahl",
	}
}

func (pl *plugin) Commands() pingu.Commands {
	return pingu.Commands{
		&pingu.Command{
			Description: "Prints either the global leaderboard, or the leaderboard for a specific year.",
			Func:        pl.postLeaderboard,
			Trigger:     leaderboardRegex,
		},
		&pingu.Command{
			Description: "Forces a refresh of all leaderboards.",
			Func: func(pi *pingu.Pingu, ev *slack.MessageEvent) {
				if ev.Channel != pl.channel {
					pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
					return
				}

				pl.refreshLeaderboards(pi)
			},
			Trigger: regexp.MustCompile("^!refresh$"),
		},
	}
}

func (pl *plugin) Name() string {
	return "Advent of Code"
}

func (pl *plugin) Tasks() pingu.Tasks {
	return pingu.Tasks{
		&pingu.Task{
			Func:     pl.refreshLeaderboards,
			Interval: time.Hour,
		},
	}
}

func (pl *plugin) Version() string {
	return version
}

func (pl *plugin) announceChanges(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

OurLoop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				if our.TotalStars != their.TotalStars {
					diff := calculateDifference(our.Stars, their.Stars)
					diffLen := len(diff)

					if diffLen != 0 {
						starsMessage := pl.buildChangeMessage(diff)

						var starsLabel string

						if diffLen != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						message := fmt.Sprintf("_%s_ earned *%d %s* by completing _%s_", our.Name, diffLen, starsLabel, starsMessage)

						if their.Position > our.Position {
							message += fmt.Sprintf(", moving up to *position %d*", our.Position)
						} else if their.Position < our.Position {
							message += fmt.Sprintf(", moving down to *position %d*", our.Position)
						} else {
							message += fmt.Sprintf(", staying at *position %d*", our.Position)
						}

						if our.TotalStars != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						pi.Say(message+fmt.Sprintf(
							" with *%d %s* (%.2f%%)!",
							our.TotalStars,
							starsLabel,
							float64(our.TotalStars)/float64(availableStars)*100,
						), pl.channel)
					}
				}

				continue OurLoop
			}
		}

		var starsLabel string

		if our.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! _%s_ has joined our ranks, starting at position *%d* with *%d %s* (%.2f%%) collected.",
			our.Name,
			our.Position,
			our.TotalStars,
			starsLabel,
			float64(our.TotalStars)/float64(availableStars)*100,
		), pl.channel)
	}

TheirLoop:
	for _, their := range a.Members {
		for _, our := range b.Members {
			if their.Id == our.Id {
				continue TheirLoop
			}
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! It seems like _%s_ has left our ranks. The leaderboards have been recalculated.",
			their.Name,
		), pl.channel)
	}
}

func (pl *plugin) buildChangeMessage(l starList) string {
	numOfStars := len(l)

	if numOfStars == 0 {
		return ""
	}

	stars := make([]string, numOfStars)

	for i, s := range l {
		stars[i] = fmt.Sprintf("Day %d Part %d (%d)", s.Day, s.Part, s.Year)
	}

	starsString := strings.Join([]string{
		strings.Join(stars[:numOfStars-1], "_, _"),
		stars[numOfStars-1],
	}, "_ and _")

	if starsString[0:7] == "_ and _" {
		starsString = starsString[7:]
	}

	return starsString
}

func (pl *plugin) buildLeaderboard(l *leaderboard) string {
	availableStars := calculateAvailableStars(time.Now(), l.Year)
	message := ""

	for _, m := range l.Members {
		var starsLabel string

		if m.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		message += fmt.Sprintf(
			"*%d.* _%s_ with *%d %s* (%.2f%%) collected.\n",
			m.Position,
			m.Name,
			m.TotalStars,
			starsLabel,
			float64(m.TotalStars)/float64(availableStars)*100,
		)
	}

	return message
}

func (pl *plugin) postLeaderboard(pi *pingu.Pingu, ev *slack.MessageEvent) {
	if ev.Channel != pl.channel {
		pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
		return
	}

	var board *leaderboard

	match := leaderboardRegex.FindStringSubmatch(ev.Text)

	if len(match) == 2 {
		year, _ := strconv.Atoi(match[1])

		for _, l := range pl.leaderboards {
			if l.Year == year {
				board = l
			}
		}

		if board == nil {
			pi.Reply(ev, fmt.Sprintf("Noot! Noot! %d does not have a leaderboard!", year))
		}
	} else {
		board = pl.global
	}

	pi.Say(pl.buildLeaderboard(board), ev.Channel)
}

func (pl *plugin) refreshGlobalLeaderboard() {
	members := make(map[int]*member)

	for _, l := range pl.leaderboards {
		for _, m := range l.Members {
			if _, ok := members[m.Id]; !ok {
				members[m.Id] = &member{
					Id:   m.Id,
					Name: m.Name,
				}
			}

			members[m.Id].GlobalScore += m.GlobalScore
			members[m.Id].LocalScore += m.LocalScore
			members[m.Id].Stars = append(members[m.Id].Stars, m.Stars...)
			members[m.Id].TotalStars += m.TotalStars

			if members[m.Id].LastStarAt.Before(m.LastStarAt) {
				members[m.Id].LastStarAt = m.LastStarAt
			}
		}
	}

	pl.global.Members = make(memberList, len(members))
	i := 0

	for _, m := range members {
		pl.global.Members[i] = m
		i++
	}

	pl.global.Sort()
}

func (pl *plugin) refreshLeaderboards(pi *pingu.Pingu) {
Loop:
	for _, year := range getValidYears(time.Now()) {
		for _, l := range pl.leaderboards {
			if l.Year == year {
				continue Loop
			}
		}

		pl.leaderboards = append(pl.leaderboards, &leaderboard{
			Year: year,
		})
	}

	var wg sync.WaitGroup

	wg.Add(len(pl.leaderboards))

	for _, l := range pl.leaderboards {
		go func(l *leaderboard) {
			before := *l
			err := l.Refresh(pl.client)
			after := *l

			if err != nil {
				pi.Logger().Error(err)
			} else if len(before.Members) != 0 {
				pl.announceChanges(pi, before, after)
			}

			wg.Done()
		}(l)
	}

	wg.Wait()
	pl.refreshGlobalLeaderboard()
}
<|endoftext|>


<commit_before>/*

LICENSE:  MIT
Author:   sine
Email:    sinerwr@gmail.com

*/

package log

import (
	"log"
	"os"

	"github.com/SiCo-DevOps/H/cfg"
)

var (
	filename    string
	warningFile = cfg.Config.Log.WARNING
	errorFile   = cfg.Config.Log.ERROR
	fatalFile   = cfg.Config.Log.FATAL
	logFileDir  = cfg.Config.Log.Logpath
)

func WriteLog(level string, msg string) {
	defer func() {
		if err := recover(); err != nil {
			log.Println("File cannot Write in " + filename)
		}
	}()
	switch level {
	case "warning":
		filename = warningFile
	case "error":
		filename = errorFile
	case "fatal":
		filename = fatalFile
	default:
		filename = "unknown.log"
	}
	fd, err := os.OpenFile(logFileDir+filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0660)
	defer fd.Close()
	if err != nil {
		log.Panicln(filename + " :Open log file Failed")
	}

	logger := log.New(fd, "[SiCo]", log.Lshortfile)
	logger.Println(msg)
}
<commit_msg>make_cfg&log&connection(dao)_as_public_element<commit_after><|endoftext|>