<commit_before>/*
Copyright 2018 Gravitational, Inc.

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

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

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

package web

import (
	"net/http"

	"github.com/gravitational/teleport/api/defaults"
	"github.com/gravitational/teleport/api/types"
	"github.com/gravitational/teleport/lib/auth"
	"github.com/gravitational/teleport/lib/client"
	"github.com/gravitational/teleport/lib/reversetunnel"
	"github.com/gravitational/teleport/lib/sshutils/scp"

	"github.com/gravitational/trace"
	"github.com/julienschmidt/httprouter"
)

// fileTransferRequest describes HTTP file transfer request
type fileTransferRequest struct {
	// Server describes a server to connect to (serverId|hostname[:port]).
	server string
	// Login is Linux username to connect as.
	login string
	// Namespace is node namespace.
	namespace string
	// Cluster is the name of the remote cluster to connect to.
	cluster string
	// remoteLocation is file remote location
	remoteLocation string
	// filename is a file name
	filename string
}

func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
	query := r.URL.Query()
	req := fileTransferRequest{
		cluster:        p.ByName("site"),
		login:          p.ByName("login"),
		server:         p.ByName("server"),
		remoteLocation: query.Get("location"),
		filename:       query.Get("filename"),
		namespace:      defaults.Namespace,
	}

	clt, err := ctx.GetUserClient(site)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	ft := fileTransfer{
		ctx:           ctx,
		authClient:    clt,
		proxyHostPort: h.ProxyHostPort(),
	}

	isUpload := r.Method == http.MethodPost
	if isUpload {
		err = ft.upload(req, r)
	} else {
		err = ft.download(req, r, w)
	}

	if err != nil {
		return nil, trace.Wrap(err)
	}

	return OK(), nil
}

type fileTransfer struct {
	// ctx is a web session context for the currently logged in user.
	ctx           *SessionContext
	authClient    auth.ClientI
	proxyHostPort string
}

func (f *fileTransfer) download(req fileTransferRequest, httpReq *http.Request, w http.ResponseWriter) error {
	cmd, err := scp.CreateHTTPDownload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		HTTPResponse:   w,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req, httpReq)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(httpReq.Context(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) upload(req fileTransferRequest, httpReq *http.Request) error {
	cmd, err := scp.CreateHTTPUpload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		FileName:       req.filename,
		HTTPRequest:    httpReq,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req, httpReq)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(httpReq.Context(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) createClient(req fileTransferRequest, httpReq *http.Request) (*client.TeleportClient, error) {
	if !types.IsValidNamespace(req.namespace) {
		return nil, trace.BadParameter("invalid namespace %q", req.namespace)
	}

	if req.login == "" {
		return nil, trace.BadParameter("missing login")
	}

	servers, err := f.authClient.GetNodes(httpReq.Context(), req.namespace)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	hostName, hostPort, err := resolveServerHostPort(req.server, servers)
	if err != nil {
		return nil, trace.BadParameter("invalid server name %q: %v", req.server, err)
	}

	cfg, err := makeTeleportClientConfig(httpReq.Context(), f.ctx)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	cfg.HostLogin = req.login
	cfg.SiteName = req.cluster
	cfg.Namespace = req.namespace
	if err := cfg.ParseProxyHost(f.proxyHostPort); err != nil {
		return nil, trace.BadParameter("failed to parse proxy address: %v", err)
	}
	cfg.Host = hostName
	cfg.HostPort = hostPort
	cfg.ClientAddr = httpReq.RemoteAddr

	tc, err := client.NewClient(cfg)
	if err != nil {
		return nil, trace.BadParameter("failed to create client: %v", err)
	}

	return tc, nil
}
<commit_msg>Return nil on success for web UI file tranfers (#15021)<commit_after>/*
Copyright 2018 Gravitational, Inc.

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

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

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

package web

import (
	"net/http"

	"github.com/gravitational/teleport/api/defaults"
	"github.com/gravitational/teleport/api/types"
	"github.com/gravitational/teleport/lib/auth"
	"github.com/gravitational/teleport/lib/client"
	"github.com/gravitational/teleport/lib/reversetunnel"
	"github.com/gravitational/teleport/lib/sshutils/scp"

	"github.com/gravitational/trace"
	"github.com/julienschmidt/httprouter"
)

// fileTransferRequest describes HTTP file transfer request
type fileTransferRequest struct {
	// Server describes a server to connect to (serverId|hostname[:port]).
	server string
	// Login is Linux username to connect as.
	login string
	// Namespace is node namespace.
	namespace string
	// Cluster is the name of the remote cluster to connect to.
	cluster string
	// remoteLocation is file remote location
	remoteLocation string
	// filename is a file name
	filename string
}

func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
	query := r.URL.Query()
	req := fileTransferRequest{
		cluster:        p.ByName("site"),
		login:          p.ByName("login"),
		server:         p.ByName("server"),
		remoteLocation: query.Get("location"),
		filename:       query.Get("filename"),
		namespace:      defaults.Namespace,
	}

	clt, err := ctx.GetUserClient(site)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	ft := fileTransfer{
		ctx:           ctx,
		authClient:    clt,
		proxyHostPort: h.ProxyHostPort(),
	}

	isUpload := r.Method == http.MethodPost
	if isUpload {
		err = ft.upload(req, r)
	} else {
		err = ft.download(req, r, w)
	}

	if err != nil {
		return nil, trace.Wrap(err)
	}

	// We must return nil so that we don't write anything to
	// the response, which would corrupt the downloaded file.
	return nil, nil
}

type fileTransfer struct {
	// ctx is a web session context for the currently logged in user.
	ctx           *SessionContext
	authClient    auth.ClientI
	proxyHostPort string
}

func (f *fileTransfer) download(req fileTransferRequest, httpReq *http.Request, w http.ResponseWriter) error {
	cmd, err := scp.CreateHTTPDownload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		HTTPResponse:   w,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req, httpReq)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(httpReq.Context(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) upload(req fileTransferRequest, httpReq *http.Request) error {
	cmd, err := scp.CreateHTTPUpload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		FileName:       req.filename,
		HTTPRequest:    httpReq,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req, httpReq)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(httpReq.Context(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) createClient(req fileTransferRequest, httpReq *http.Request) (*client.TeleportClient, error) {
	if !types.IsValidNamespace(req.namespace) {
		return nil, trace.BadParameter("invalid namespace %q", req.namespace)
	}

	if req.login == "" {
		return nil, trace.BadParameter("missing login")
	}

	servers, err := f.authClient.GetNodes(httpReq.Context(), req.namespace)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	hostName, hostPort, err := resolveServerHostPort(req.server, servers)
	if err != nil {
		return nil, trace.BadParameter("invalid server name %q: %v", req.server, err)
	}

	cfg, err := makeTeleportClientConfig(httpReq.Context(), f.ctx)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	cfg.HostLogin = req.login
	cfg.SiteName = req.cluster
	cfg.Namespace = req.namespace
	if err := cfg.ParseProxyHost(f.proxyHostPort); err != nil {
		return nil, trace.BadParameter("failed to parse proxy address: %v", err)
	}
	cfg.Host = hostName
	cfg.HostPort = hostPort
	cfg.ClientAddr = httpReq.RemoteAddr

	tc, err := client.NewClient(cfg)
	if err != nil {
		return nil, trace.BadParameter("failed to create client: %v", err)
	}

	return tc, nil
}
<|endoftext|>


<commit_before>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"fmt"

	"github.com/keybase/client/go/protocol/keybase1"
)

// NewInitModeFromType returns an InitMode object corresponding to the
// given type.
func NewInitModeFromType(t InitModeType) InitMode {
	switch t {
	case InitDefault:
		return modeDefault{}
	case InitMinimal:
		return modeMinimal{}
	case InitSingleOp:
		return modeSingleOp{modeDefault{}}
	case InitConstrained:
		return modeConstrained{modeDefault{}}
	default:
		panic(fmt.Sprintf("Unknown mode: %s", t))
	}
}

// Default mode:

type modeDefault struct {
}

func (md modeDefault) Type() InitModeType {
	return InitDefault
}

func (md modeDefault) BlockWorkers() int {
	return defaultBlockRetrievalWorkerQueueSize
}

func (md modeDefault) PrefetchWorkers() int {
	return defaultPrefetchWorkerQueueSize
}

func (md modeDefault) RekeyWorkers() int {
	return 16
}

func (md modeDefault) RekeyQueueSize() int {
	return 2048 // 48 KB
}

func (md modeDefault) IsTestMode() bool {
	return false
}

func (md modeDefault) DirtyBlockCacheEnabled() bool {
	return true
}

func (md modeDefault) BackgroundFlushesEnabled() bool {
	return true
}

func (md modeDefault) MetricsEnabled() bool {
	return true
}

func (md modeDefault) ConflictResolutionEnabled() bool {
	return true
}

func (md modeDefault) BlockManagementEnabled() bool {
	return true
}

func (md modeDefault) QuotaReclamationEnabled() bool {
	return true
}

func (md modeDefault) NodeCacheEnabled() bool {
	return true
}

func (md modeDefault) TLFUpdatesEnabled() bool {
	return true
}

func (md modeDefault) KBFSServiceEnabled() bool {
	return true
}

func (md modeDefault) JournalEnabled() bool {
	return true
}

func (md modeDefault) UnmergedTLFsEnabled() bool {
	return true
}

func (md modeDefault) ServiceKeepaliveEnabled() bool {
	return true
}

func (md modeDefault) TLFEditHistoryEnabled() bool {
	return true
}

func (md modeDefault) SendEditNotificationsEnabled() bool {
	return true
}

func (md modeDefault) ClientType() keybase1.ClientType {
	return keybase1.ClientType_KBFS
}

func (md modeDefault) LocalHTTPServerEnabled() bool {
	return true
}

// Minimal mode:

type modeMinimal struct {
}

func (mm modeMinimal) Type() InitModeType {
	return InitMinimal
}

func (mm modeMinimal) BlockWorkers() int {
	// In minimal mode, block re-embedding is not required, so we
	// don't fetch the unembedded blocks..
	return 0
}

func (mm modeMinimal) PrefetchWorkers() int {
	return 0
}

func (mm modeMinimal) RekeyWorkers() int {
	return 4
}

func (mm modeMinimal) RekeyQueueSize() int {
	return 512 // 12 KB
}

func (mm modeMinimal) IsTestMode() bool {
	return false
}

func (mm modeMinimal) DirtyBlockCacheEnabled() bool {
	// No blocks will be dirtied in minimal mode, so don't bother with
	// the dirty block cache.
	return false
}

func (mm modeMinimal) BackgroundFlushesEnabled() bool {
	// Don't do background flushes when in minimal mode, since there
	// shouldn't be any data writes.
	return false
}

func (mm modeMinimal) MetricsEnabled() bool {
	return false
}

func (mm modeMinimal) ConflictResolutionEnabled() bool {
	// No need to run CR if there won't be any data writes on this
	// device.  (There may still be rekey writes, but we don't allow
	// conflicts to happen in that case.)
	return false
}

func (mm modeMinimal) BlockManagementEnabled() bool {
	// If this device is in minimal mode and won't be doing any data
	// writes, no need deal with block-level cleanup operations.
	// TODO: in the future it might still be useful to have
	// e.g. mobile devices doing QR.
	return false
}

func (mm modeMinimal) QuotaReclamationEnabled() bool {
	return false
}

func (mm modeMinimal) NodeCacheEnabled() bool {
	// If we're in minimal mode, let the node cache remain nil to
	// ensure that the user doesn't try any data reads or writes.
	return false
}

func (mm modeMinimal) TLFUpdatesEnabled() bool {
	return true
}

func (mm modeMinimal) KBFSServiceEnabled() bool {
	return false
}

func (mm modeMinimal) JournalEnabled() bool {
	return false
}

func (mm modeMinimal) UnmergedTLFsEnabled() bool {
	// Writes aren't allowed, so unmerged TLFs on this device
	// shouldn't be possible.
	return false
}

func (mm modeMinimal) ServiceKeepaliveEnabled() bool {
	return false
}

func (mm modeMinimal) TLFEditHistoryEnabled() bool {
	return false
}

func (mm modeMinimal) SendEditNotificationsEnabled() bool {
	// Writes aren't allowed, so we shouldn't need to send any.
	return false
}

func (mm modeMinimal) ClientType() keybase1.ClientType {
	return keybase1.ClientType_KBFS
}

func (mm modeMinimal) LocalHTTPServerEnabled() bool {
	return false
}

// Single op mode:

type modeSingleOp struct {
	InitMode
}

func (mso modeSingleOp) Type() InitModeType {
	return InitSingleOp
}

func (mso modeSingleOp) RekeyWorkers() int {
	// Just block all rekeys and don't bother cleaning up requests
	// since the process is short lived anyway.
	return 0
}

func (mso modeSingleOp) RekeyQueueSize() int {
	return 0
}

func (mso modeSingleOp) QuotaReclamationEnabled() bool {
	return false
}

func (mso modeSingleOp) TLFUpdatesEnabled() bool {
	return false
}

func (mso modeSingleOp) KBFSServiceEnabled() bool {
	return false
}

func (mso modeSingleOp) UnmergedTLFsEnabled() bool {
	// There's basically no way for a TLF to start off as unmerged
	// since single-ops should be using a fresh journal.
	return false
}

func (mso modeSingleOp) TLFEditHistoryEnabled() bool {
	return false
}

func (mso modeSingleOp) SendEditNotificationsEnabled() bool {
	// We don't want git, or other single op writes, showing up in the
	// notification history.
	return false
}

func (mso modeSingleOp) ClientType() keybase1.ClientType {
	return keybase1.ClientType_NONE
}

func (mso modeSingleOp) LocalHTTPServerEnabled() bool {
	return false
}

// Constrained mode:

type modeConstrained struct {
	InitMode
}

func (mc modeConstrained) Type() InitModeType {
	return InitConstrained
}

func (mc modeConstrained) BlockWorkers() int {
	return 1
}

func (mc modeConstrained) PrefetchWorkers() int {
	return 0
}

func (mc modeConstrained) RekeyWorkers() int {
	return 4
}

func (mc modeConstrained) RekeyQueueSize() int {
	return 1024 // 24 KB
}

func (mc modeConstrained) BackgroundFlushesEnabled() bool {
	return true
}

func (mc modeConstrained) ConflictResolutionEnabled() bool {
	return true
}

func (mc modeConstrained) QuotaReclamationEnabled() bool {
	// Disable QR for mobile for now, until we add a new mode mothod to
	// indicate that this device should only self-QR. Also need to verify that
	// the QR timer doesn't cause app wakeups.
	// See https://github.com/keybase/kbfs/pull/1616#discussion_r195269845
	return false
}

func (mc modeConstrained) KBFSServiceEnabled() bool {
	return false
}

func (mc modeConstrained) JournalEnabled() bool {
	return true
}

func (mc modeConstrained) UnmergedTLFsEnabled() bool {
	return true
}

func (mc modeConstrained) ServiceKeepaliveEnabled() bool {
	return false
}

func (mc modeConstrained) TLFEditHistoryEnabled() bool {
	return false
}

func (mc modeConstrained) SendEditNotificationsEnabled() bool {
	// TODO: turn this on once we allow mobile writes.
	return false
}

func (mc modeConstrained) LocalHTTPServerEnabled() bool {
	return true
}

// Wrapper for tests.

type modeTest struct {
	InitMode
}

func (mt modeTest) IsTestMode() bool {
	return true
}
<commit_msg>modes: enable sending edit notifications on mobile<commit_after>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"fmt"

	"github.com/keybase/client/go/protocol/keybase1"
)

// NewInitModeFromType returns an InitMode object corresponding to the
// given type.
func NewInitModeFromType(t InitModeType) InitMode {
	switch t {
	case InitDefault:
		return modeDefault{}
	case InitMinimal:
		return modeMinimal{}
	case InitSingleOp:
		return modeSingleOp{modeDefault{}}
	case InitConstrained:
		return modeConstrained{modeDefault{}}
	default:
		panic(fmt.Sprintf("Unknown mode: %s", t))
	}
}

// Default mode:

type modeDefault struct {
}

func (md modeDefault) Type() InitModeType {
	return InitDefault
}

func (md modeDefault) BlockWorkers() int {
	return defaultBlockRetrievalWorkerQueueSize
}

func (md modeDefault) PrefetchWorkers() int {
	return defaultPrefetchWorkerQueueSize
}

func (md modeDefault) RekeyWorkers() int {
	return 16
}

func (md modeDefault) RekeyQueueSize() int {
	return 2048 // 48 KB
}

func (md modeDefault) IsTestMode() bool {
	return false
}

func (md modeDefault) DirtyBlockCacheEnabled() bool {
	return true
}

func (md modeDefault) BackgroundFlushesEnabled() bool {
	return true
}

func (md modeDefault) MetricsEnabled() bool {
	return true
}

func (md modeDefault) ConflictResolutionEnabled() bool {
	return true
}

func (md modeDefault) BlockManagementEnabled() bool {
	return true
}

func (md modeDefault) QuotaReclamationEnabled() bool {
	return true
}

func (md modeDefault) NodeCacheEnabled() bool {
	return true
}

func (md modeDefault) TLFUpdatesEnabled() bool {
	return true
}

func (md modeDefault) KBFSServiceEnabled() bool {
	return true
}

func (md modeDefault) JournalEnabled() bool {
	return true
}

func (md modeDefault) UnmergedTLFsEnabled() bool {
	return true
}

func (md modeDefault) ServiceKeepaliveEnabled() bool {
	return true
}

func (md modeDefault) TLFEditHistoryEnabled() bool {
	return true
}

func (md modeDefault) SendEditNotificationsEnabled() bool {
	return true
}

func (md modeDefault) ClientType() keybase1.ClientType {
	return keybase1.ClientType_KBFS
}

func (md modeDefault) LocalHTTPServerEnabled() bool {
	return true
}

// Minimal mode:

type modeMinimal struct {
}

func (mm modeMinimal) Type() InitModeType {
	return InitMinimal
}

func (mm modeMinimal) BlockWorkers() int {
	// In minimal mode, block re-embedding is not required, so we
	// don't fetch the unembedded blocks..
	return 0
}

func (mm modeMinimal) PrefetchWorkers() int {
	return 0
}

func (mm modeMinimal) RekeyWorkers() int {
	return 4
}

func (mm modeMinimal) RekeyQueueSize() int {
	return 512 // 12 KB
}

func (mm modeMinimal) IsTestMode() bool {
	return false
}

func (mm modeMinimal) DirtyBlockCacheEnabled() bool {
	// No blocks will be dirtied in minimal mode, so don't bother with
	// the dirty block cache.
	return false
}

func (mm modeMinimal) BackgroundFlushesEnabled() bool {
	// Don't do background flushes when in minimal mode, since there
	// shouldn't be any data writes.
	return false
}

func (mm modeMinimal) MetricsEnabled() bool {
	return false
}

func (mm modeMinimal) ConflictResolutionEnabled() bool {
	// No need to run CR if there won't be any data writes on this
	// device.  (There may still be rekey writes, but we don't allow
	// conflicts to happen in that case.)
	return false
}

func (mm modeMinimal) BlockManagementEnabled() bool {
	// If this device is in minimal mode and won't be doing any data
	// writes, no need deal with block-level cleanup operations.
	// TODO: in the future it might still be useful to have
	// e.g. mobile devices doing QR.
	return false
}

func (mm modeMinimal) QuotaReclamationEnabled() bool {
	return false
}

func (mm modeMinimal) NodeCacheEnabled() bool {
	// If we're in minimal mode, let the node cache remain nil to
	// ensure that the user doesn't try any data reads or writes.
	return false
}

func (mm modeMinimal) TLFUpdatesEnabled() bool {
	return true
}

func (mm modeMinimal) KBFSServiceEnabled() bool {
	return false
}

func (mm modeMinimal) JournalEnabled() bool {
	return false
}

func (mm modeMinimal) UnmergedTLFsEnabled() bool {
	// Writes aren't allowed, so unmerged TLFs on this device
	// shouldn't be possible.
	return false
}

func (mm modeMinimal) ServiceKeepaliveEnabled() bool {
	return false
}

func (mm modeMinimal) TLFEditHistoryEnabled() bool {
	return false
}

func (mm modeMinimal) SendEditNotificationsEnabled() bool {
	// Writes aren't allowed, so we shouldn't need to send any.
	return false
}

func (mm modeMinimal) ClientType() keybase1.ClientType {
	return keybase1.ClientType_KBFS
}

func (mm modeMinimal) LocalHTTPServerEnabled() bool {
	return false
}

// Single op mode:

type modeSingleOp struct {
	InitMode
}

func (mso modeSingleOp) Type() InitModeType {
	return InitSingleOp
}

func (mso modeSingleOp) RekeyWorkers() int {
	// Just block all rekeys and don't bother cleaning up requests
	// since the process is short lived anyway.
	return 0
}

func (mso modeSingleOp) RekeyQueueSize() int {
	return 0
}

func (mso modeSingleOp) QuotaReclamationEnabled() bool {
	return false
}

func (mso modeSingleOp) TLFUpdatesEnabled() bool {
	return false
}

func (mso modeSingleOp) KBFSServiceEnabled() bool {
	return false
}

func (mso modeSingleOp) UnmergedTLFsEnabled() bool {
	// There's basically no way for a TLF to start off as unmerged
	// since single-ops should be using a fresh journal.
	return false
}

func (mso modeSingleOp) TLFEditHistoryEnabled() bool {
	return false
}

func (mso modeSingleOp) SendEditNotificationsEnabled() bool {
	// We don't want git, or other single op writes, showing up in the
	// notification history.
	return false
}

func (mso modeSingleOp) ClientType() keybase1.ClientType {
	return keybase1.ClientType_NONE
}

func (mso modeSingleOp) LocalHTTPServerEnabled() bool {
	return false
}

// Constrained mode:

type modeConstrained struct {
	InitMode
}

func (mc modeConstrained) Type() InitModeType {
	return InitConstrained
}

func (mc modeConstrained) BlockWorkers() int {
	return 1
}

func (mc modeConstrained) PrefetchWorkers() int {
	return 0
}

func (mc modeConstrained) RekeyWorkers() int {
	return 4
}

func (mc modeConstrained) RekeyQueueSize() int {
	return 1024 // 24 KB
}

func (mc modeConstrained) BackgroundFlushesEnabled() bool {
	return true
}

func (mc modeConstrained) ConflictResolutionEnabled() bool {
	return true
}

func (mc modeConstrained) QuotaReclamationEnabled() bool {
	// Disable QR for mobile for now, until we add a new mode mothod to
	// indicate that this device should only self-QR. Also need to verify that
	// the QR timer doesn't cause app wakeups.
	// See https://github.com/keybase/kbfs/pull/1616#discussion_r195269845
	return false
}

func (mc modeConstrained) KBFSServiceEnabled() bool {
	return false
}

func (mc modeConstrained) JournalEnabled() bool {
	return true
}

func (mc modeConstrained) UnmergedTLFsEnabled() bool {
	return true
}

func (mc modeConstrained) ServiceKeepaliveEnabled() bool {
	return false
}

func (mc modeConstrained) TLFEditHistoryEnabled() bool {
	return false
}

func (mc modeConstrained) SendEditNotificationsEnabled() bool {
	return true
}

func (mc modeConstrained) LocalHTTPServerEnabled() bool {
	return true
}

// Wrapper for tests.

type modeTest struct {
	InitMode
}

func (mt modeTest) IsTestMode() bool {
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"database/sql"
	"flag"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"io"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type logEntry struct {
	Node string
	Time int64
	Msg  string
}

var (
	tsFormat = "2006/01/02 15:04:05"
	addr     string
	dbFile   string
	logChan  chan *logEntry
)

var logSplit = regexp.MustCompile("^([\\w-:]+) (\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}) (.+)$")
var responseCheck = regexp.MustCompile("response time: (\\d+)us$")

func init() {
	flLogBuffer := flag.Uint("b", 16, "log entries to buffer")
	flDbFile := flag.String("f", "logs.db", "database file")
	port := flag.Uint("p", 5988, "port to listen on")
	flag.Parse()

	addr = fmt.Sprintf(":%d", *port)
	dbFile = *flDbFile
	logChan = make(chan *logEntry, *flLogBuffer)
}

func main() {
	dbSetup()
	go log()
	go listen()

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Kill, os.Interrupt, syscall.SIGTERM)
	<-sigc
	close(logChan)
	<-time.After(100 * time.Millisecond)

	os.Exit(1)
}

func listen() {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[!] failed to resolve TCP address:", err.Error())
		os.Exit(1)
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[!] failed to set up TCP listener:", err.Error())
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("[!] TCP error:", err.Error())
			continue
		}
		go processMessage(conn)
	}

}

func processMessage(conn net.Conn) {
	fmt.Println("[+] client connected:", conn.RemoteAddr())
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		msg, err := r.ReadString(0x0a)
		if err != nil {
			if err != io.EOF {
				fmt.Println("[!] error reading from client:",
					err.Error())
			}
			return
		}
		msg = strings.Trim(string(msg), "\n \t")
		fmt.Println("-- ", msg)

		nodeID := logSplit.ReplaceAllString(msg, "$1")
		dateString := logSplit.ReplaceAllString(msg, "$2")
		logMsg := logSplit.ReplaceAllString(msg, "$3")
		tm, err := time.Parse(tsFormat, dateString)
		if err != nil {
			fmt.Fprintf(os.Stderr, "[!] error parsing time %s: %s\n",
				dateString, err.Error())
			return
		}
		le := &logEntry{nodeID, tm.UTC().Unix(), logMsg}
		logChan <- le
	}
}

func log() {
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	for {
		le, ok := <-logChan
		if !ok {
			fmt.Println("[+] shutting down database listener")
			return
		}
		_, err := db.Exec("insert into entries values (?, ?, ?)",
			le.Node, le.Time, le.Msg)
		if err != nil {
			fmt.Println("[!] database error:", err.Error())
			continue
		}

		if responseCheck.MatchString(le.Msg) {
			respString := responseCheck.ReplaceAllString(le.Msg, "$1")
			rTime, err := strconv.Atoi(respString)
			if err != nil {
				fmt.Println("[!] error reading response time:", err.Error())
				return
			}
			_, err = db.Exec("insert into response_times values (?, ?, ?)",
				le.Node, le.Time, rTime)
			if err != nil {
				fmt.Println("[!] error writing to database:", err.Error())
			}
		}

	}
}

func logResponseTime(db *sql.DB, le *logEntry) {
}

func dbSetup() {
	entryTable()
	respTable()
}

func entryTable() {
	const createSql = `CREATE TABLE entries (node text, timestamp integer, message string)`
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	rows, err := db.Query(`select sql from sqlite_master
                               where type='table' and name='entries'`)
	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	}

	var tblSql string
	for rows.Next() {
		err = rows.Scan(&tblSql)
		break
	}

	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	} else if tblSql == "" {
		fmt.Println("[+] creating table")
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	} else if tblSql != createSql {
		fmt.Println("[+] schema out of sync")
		_, err = db.Exec(`drop table entries`)
		if err != nil {
			fmt.Println("[!] error dropping table:", err.Error())
			os.Exit(1)
		}
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	}
}

func respTable() {
	const createSql = `CREATE TABLE response_times (node text, timestamp integer, microsec integer)`
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	rows, err := db.Query(`select sql from sqlite_master
                               where type='table' and name='response_times'`)
	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	}

	var tblSql string
	for rows.Next() {
		err = rows.Scan(&tblSql)
		break
	}

	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	} else if tblSql == "" {
		fmt.Println("[+] creating table")
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	} else if tblSql != createSql {
		fmt.Println("[+] schema out of sync")
		_, err = db.Exec(`drop table response_times`)
		if err != nil {
			fmt.Println("[!] error dropping table:", err.Error())
			os.Exit(1)
		}
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	}
}
<commit_msg>ignore empty messages<commit_after>package main

import (
	"bufio"
	"database/sql"
	"flag"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"io"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type logEntry struct {
	Node string
	Time int64
	Msg  string
}

var (
	tsFormat = "2006/01/02 15:04:05"
	addr     string
	dbFile   string
	logChan  chan *logEntry
)

var logSplit = regexp.MustCompile("^([\\w-:]+) (\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}) (.+)$")
var responseCheck = regexp.MustCompile("response time: (\\d+)us$")

func init() {
	flLogBuffer := flag.Uint("b", 16, "log entries to buffer")
	flDbFile := flag.String("f", "logs.db", "database file")
	port := flag.Uint("p", 5988, "port to listen on")
	flag.Parse()

	addr = fmt.Sprintf(":%d", *port)
	dbFile = *flDbFile
	logChan = make(chan *logEntry, *flLogBuffer)
}

func main() {
	dbSetup()
	go log()
	go listen()

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Kill, os.Interrupt, syscall.SIGTERM)
	<-sigc
	close(logChan)
	<-time.After(100 * time.Millisecond)

	os.Exit(1)
}

func listen() {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[!] failed to resolve TCP address:", err.Error())
		os.Exit(1)
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[!] failed to set up TCP listener:", err.Error())
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("[!] TCP error:", err.Error())
			continue
		}
		go processMessage(conn)
	}

}

func processMessage(conn net.Conn) {
	fmt.Println("[+] client connected:", conn.RemoteAddr())
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		msg, err := r.ReadString(0x0a)
		if err != nil {
			if err != io.EOF {
				fmt.Println("[!] error reading from client:",
					err.Error())
			}
			return
		} else if msg == "" {
			return
		}
		msg = strings.Trim(string(msg), "\n \t")
		fmt.Println("-- ", msg)

		nodeID := logSplit.ReplaceAllString(msg, "$1")
		dateString := logSplit.ReplaceAllString(msg, "$2")
		logMsg := logSplit.ReplaceAllString(msg, "$3")
		tm, err := time.Parse(tsFormat, dateString)
		if err != nil {
			fmt.Fprintf(os.Stderr, "[!] error parsing time %s: %s\n",
				dateString, err.Error())
			return
		}
		le := &logEntry{nodeID, tm.UTC().Unix(), logMsg}
		logChan <- le
	}
}

func log() {
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	for {
		le, ok := <-logChan
		if !ok {
			fmt.Println("[+] shutting down database listener")
			return
		}
		_, err := db.Exec("insert into entries values (?, ?, ?)",
			le.Node, le.Time, le.Msg)
		if err != nil {
			fmt.Println("[!] database error:", err.Error())
			continue
		}

		if responseCheck.MatchString(le.Msg) {
			respString := responseCheck.ReplaceAllString(le.Msg, "$1")
			rTime, err := strconv.Atoi(respString)
			if err != nil {
				fmt.Println("[!] error reading response time:", err.Error())
				return
			}
			_, err = db.Exec("insert into response_times values (?, ?, ?)",
				le.Node, le.Time, rTime)
			if err != nil {
				fmt.Println("[!] error writing to database:", err.Error())
			}
		}

	}
}

func logResponseTime(db *sql.DB, le *logEntry) {
}

func dbSetup() {
	entryTable()
	respTable()
}

func entryTable() {
	const createSql = `CREATE TABLE entries (node text, timestamp integer, message string)`
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	rows, err := db.Query(`select sql from sqlite_master
                               where type='table' and name='entries'`)
	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	}

	var tblSql string
	for rows.Next() {
		err = rows.Scan(&tblSql)
		break
	}

	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	} else if tblSql == "" {
		fmt.Println("[+] creating table")
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	} else if tblSql != createSql {
		fmt.Println("[+] schema out of sync")
		_, err = db.Exec(`drop table entries`)
		if err != nil {
			fmt.Println("[!] error dropping table:", err.Error())
			os.Exit(1)
		}
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	}
}

func respTable() {
	const createSql = `CREATE TABLE response_times (node text, timestamp integer, microsec integer)`
	db, err := sql.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Println("[!] failed to open DB file:", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	rows, err := db.Query(`select sql from sqlite_master
                               where type='table' and name='response_times'`)
	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	}

	var tblSql string
	for rows.Next() {
		err = rows.Scan(&tblSql)
		break
	}

	if err != nil {
		fmt.Println("[!] error reading database:", err.Error())
		os.Exit(1)
	} else if tblSql == "" {
		fmt.Println("[+] creating table")
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	} else if tblSql != createSql {
		fmt.Println("[+] schema out of sync")
		_, err = db.Exec(`drop table response_times`)
		if err != nil {
			fmt.Println("[!] error dropping table:", err.Error())
			os.Exit(1)
		}
		_, err = db.Exec(createSql)
		if err != nil {
			fmt.Println("[!] error creating table:", err.Error())
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package util

import (
	"regexp"
	"strings"
)

type Regex struct {
	*regexp.Regexp
}

// NewRegex creates a new Regex struct matching the given pattern.
func NewRegex(pattern string) *Regex {
	// Create a case insensitive regular expression which matches all given
	// arguments.
	return &Regex{regexp.MustCompile(pattern)}
}

// NewWordMatchRegex creates a new Regex struct matching any of the words
// passed as arguments.
func NewRegexFromWords(words ...string) *Regex {
	// Create a case insensitive regular expression which matches all given
	// arguments.
	return NewRegex("(?i)" + strings.Join(words, "|"))
}

// In returns true if a match can be found in text.
func (r *Regex) In(text string) bool {
	return r.FindStringIndex(text) != nil
}
<commit_msg>removed comment<commit_after>package util

import (
	"regexp"
	"strings"
)

type Regex struct {
	*regexp.Regexp
}

// NewRegex creates a new Regex struct matching the given pattern.
func NewRegex(pattern string) *Regex {
	return &Regex{regexp.MustCompile(pattern)}
}

// NewWordMatchRegex creates a new Regex struct matching any of the words
// passed as arguments.
func NewRegexFromWords(words ...string) *Regex {
	// Create a case insensitive regular expression which matches all given
	// arguments.
	return NewRegex("(?i)" + strings.Join(words, "|"))
}

// In returns true if a match can be found in text.
func (r *Regex) In(text string) bool {
	return r.FindStringIndex(text) != nil
}
<|endoftext|>


<commit_before>package utils

import (
	"compress/gzip"
	"io"
	"os"
	"sync"
	"time"

	"github.com/free/concurrent-writer/concurrent"
	"github.com/inconshreveable/log15"
	"go.uber.org/atomic"
)

type OFile struct {
	oFile      *os.File
	closeAt    atomic.Int64
	Name       string
	writer     *concurrent.Writer
	gzipwriter *cGzipWriter
	syncmu     sync.Mutex
	refs       atomic.Int32
	logger     log15.Logger
}

func NewOFile(f *os.File, name string, closeAt time.Time, bufferSize int, doGzip bool, gzipLevel int, logger log15.Logger) *OFile {
	//openedFilesGauge.Inc()
	o := &OFile{
		oFile:  f,
		Name:   name,
		logger: logger,
	}
	o.closeAt.Store(closeAt.UnixNano())
	if gzipLevel == 0 || !doGzip {
		o.writer = concurrent.NewWriterAutoFlush(f, bufferSize, 0.75)
		// the native go file finalizer will close the file when we do not reference it anymore
	} else {
		o.gzipwriter = newGzipWriter(f)
		o.writer = concurrent.NewWriterAutoFlush(o.gzipwriter, bufferSize, 0.75)
	}
	return o
}

func (o *OFile) Release() {
	if o.refs.Add(-1) == 0 {
		o.closeFile()
		o.logger.Debug("Closing file", "filename", o.Name)
	}
}

func (o *OFile) Acquire() {
	o.refs.Add(1)
}

func (o *OFile) Postpone(d time.Duration) {
	o.closeAt.Store(time.Now().Add(d).UnixNano())
}

func (o *OFile) Expired() bool {
	return time.Now().After(time.Unix(0, o.closeAt.Load()))
}

func (o *OFile) Write(p []byte) (int, error) {
	// may be called concurrently
	return o.writer.Write(p)
}

func (o *OFile) Flush() (err error) {
	return o.writer.Flush()
}

func (o *OFile) Sync() (err error) {
	// may be called concurrently
	o.syncmu.Lock()
	defer o.syncmu.Unlock()
	if o.gzipwriter != nil {
		// flush the gzip writer
		err = o.gzipwriter.Flush()
		if err != nil {
			return err
		}
	}
	// fsync the file itself
	return o.oFile.Sync()
}

func (o *OFile) closeFile() {
	o.Flush()
	if o.gzipwriter != nil {
		_ = o.gzipwriter.Close()
	}
	err := o.oFile.Close()
	if err != nil {
		//openedFilesGauge.Dec()
	}
}

// ensure thread safety for the gzip writer
type cGzipWriter struct {
	w  *gzip.Writer
	mu sync.Mutex
}

func newGzipWriter(w io.Writer) *cGzipWriter {
	return &cGzipWriter{w: gzip.NewWriter(w)}
}

func (gw *cGzipWriter) Write(p []byte) (n int, err error) {
	gw.mu.Lock()
	n, err = gw.w.Write(p)
	gw.mu.Unlock()
	return
}

func (gw *cGzipWriter) Flush() (err error) {
	gw.mu.Lock()
	err = gw.w.Flush()
	gw.mu.Unlock()
	return
}

func (gw *cGzipWriter) Close() (err error) {
	gw.mu.Lock()
	err = gw.w.Close()
	gw.mu.Unlock()
	return
}
<commit_msg>deal with gauge fix<commit_after>package utils

import (
	"compress/gzip"
	"io"
	"os"
	"sync"
	"time"

	"github.com/free/concurrent-writer/concurrent"
	"github.com/inconshreveable/log15"
	"go.uber.org/atomic"
)

type OFile struct {
	f          *os.File
	closeAt    atomic.Int64
	Name       string
	writer     *concurrent.Writer
	gzipwriter *cGzipWriter
	syncmu     sync.Mutex
	refs       atomic.Int32
	logger     log15.Logger
}

func NewOFile(f *os.File, name string, closeAt time.Time, bufferSize int, doGzip bool, gzipLevel int, logger log15.Logger) *OFile {
	o := &OFile{
		f:      f,
		Name:   name,
		logger: logger,
	}
	o.closeAt.Store(closeAt.UnixNano())
	if gzipLevel == 0 || !doGzip {
		o.writer = concurrent.NewWriterAutoFlush(f, bufferSize, 0.75)
		// the native go file finalizer will close the file when we do not reference it anymore
	} else {
		o.gzipwriter = newGzipWriter(f)
		o.writer = concurrent.NewWriterAutoFlush(o.gzipwriter, bufferSize, 0.75)
	}
	return o
}

func (o *OFile) Release() bool {
	if o.refs.Add(-1) == 0 {
		o.close()
		o.logger.Debug("Closing file", "filename", o.Name)
		return true
	}
	return false
}

func (o *OFile) Acquire() {
	o.refs.Add(1)
}

func (o *OFile) Postpone(d time.Duration) {
	o.closeAt.Store(time.Now().Add(d).UnixNano())
}

func (o *OFile) Expired() bool {
	return time.Now().After(time.Unix(0, o.closeAt.Load()))
}

func (o *OFile) Write(p []byte) (int, error) {
	// may be called concurrently
	return o.writer.Write(p)
}

func (o *OFile) Flush() (err error) {
	return o.writer.Flush()
}

func (o *OFile) Sync() (err error) {
	// may be called concurrently
	o.syncmu.Lock()
	defer o.syncmu.Unlock()
	if o.gzipwriter != nil {
		// flush the gzip writer
		err = o.gzipwriter.Flush()
		if err != nil {
			return err
		}
	}
	// fsync the file itself
	return o.f.Sync()
}

func (o *OFile) close() {
	o.Flush()
	if o.gzipwriter != nil {
		_ = o.gzipwriter.Close()
	}
	_ = o.f.Close()
}

// ensure thread safety for the gzip writer
type cGzipWriter struct {
	w  *gzip.Writer
	mu sync.Mutex
}

func newGzipWriter(w io.Writer) *cGzipWriter {
	return &cGzipWriter{w: gzip.NewWriter(w)}
}

func (gw *cGzipWriter) Write(p []byte) (n int, err error) {
	gw.mu.Lock()
	n, err = gw.w.Write(p)
	gw.mu.Unlock()
	return
}

func (gw *cGzipWriter) Flush() (err error) {
	gw.mu.Lock()
	err = gw.w.Flush()
	gw.mu.Unlock()
	return
}

func (gw *cGzipWriter) Close() (err error) {
	gw.mu.Lock()
	err = gw.w.Close()
	gw.mu.Unlock()
	return
}
<|endoftext|>


<commit_before>package utils

import (
	"database/sql"
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-get/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	ErrUserNotExist     error = errors.New("User does not exist")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	send chan *User
	done chan bool
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
	err             error  `json:"-"`
}

func UserInit() {

	fmt.Println("Initializing User Info Worker...")

	// make worker channel
	userdataWorker = &userWorker{
		send: make(chan *User, 64),
		done: make(chan bool, 64),
	}

	go func() {

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

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			fmt.Println(err)
			return
		}

		// range through tasks channel
		for u := range userdataWorker.send {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				u.err = err
			}

			// send back data
			userdataWorker.done <- true

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	// get original uid
	uid := u.Id

	// send to worker
	userdataWorker.send <- u

	// block until done
	<-userdataWorker.done

	// check error
	if u.err == sql.ErrNoRows {
		return ErrUserNotExist
	} else if u.err != nil {
		return e.ErrInternalError
	}

	// check that theyre still the same just in case
	if u.Id != uid {
		return e.ErrInternalError
	}

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<commit_msg>add better blocking<commit_after>package utils

import (
	"database/sql"
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-get/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	ErrUserNotExist     error = errors.New("User does not exist")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	send chan *User
	done chan bool
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
	err             error  `json:"-"`
}

func UserInit() {

	fmt.Println("Initializing User Info Worker...")

	// make worker channel
	userdataWorker = &userWorker{
		send: make(chan *User, 64),
		done: make(chan bool, 64),
	}

	go func() {

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

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			fmt.Println(err)
			return
		}

		// range through tasks channel
		for u := range userdataWorker.send {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				u.err = err
			}

			// send back data
			userdataWorker.done <- true

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	// get original uid
	uid := u.Id

	fmt.Printf("%s\n", u)

	// send to worker
	userdataWorker.send <- u

	// block until done
	<-userdataWorker.done

	fmt.Printf("%s\n", u)

	// check error
	if u.err == sql.ErrNoRows {
		return ErrUserNotExist
	} else if u.err != nil {
		return e.ErrInternalError
	}

	// check that theyre still the same just in case
	if u.Id != uid {
		return e.ErrInternalError
	}

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Che Wei, Lin
//
// 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 tinynet

import (
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
)

func TestInc(t *testing.T) {
	ip, _, _ := net.ParseCIDR("140.113.234.123/30")
	expected := []string{"140.113.234.123", "140.113.234.124", "140.113.234.125"}

	for i, _ := range expected {
		assert.Equal(t, ip.String(), expected[i], "Those two address should be same")
		inc(ip)
	}
}

func TestUtils(t *testing.T) {

	data := []struct {
		desc     string
		cidr     string
		expected []string
	}{
		{"ValidCIDR_29", "140.113.234.123/29", []string{"140.113.234.121", "140.113.234.122", "140.113.234.123", "140.113.234.124", "140.113.234.125", "140.113.234.126"}},
		{"ValidCIDR_30", "140.113.234.123/30", []string{"140.113.234.121", "140.113.234.122"}},
		{"ValidCIDR_31", "140.113.234.123/31", []string{}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			data, err := getAllIPsfromCIDR(d.cidr)
			assert.NoError(t, err)
			assert.Equal(t, len(data), len(d.expected))

			for i, _ := range data {
				assert.Equal(t, data[i], d.expected[i])
			}
		})
	}
}
<commit_msg>add testing for invalid condition<commit_after>// Copyright (c) 2017 Che Wei, Lin
//
// 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 tinynet

import (
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
)

func TestUtils_Invalid(t *testing.T) {
	_, err := getAllIPsfromCIDR("1.2.3.4.5./32")
	assert.Error(t, err)
}

func TestInc(t *testing.T) {
	ip, _, _ := net.ParseCIDR("140.113.234.123/30")
	expected := []string{"140.113.234.123", "140.113.234.124", "140.113.234.125"}

	for i, _ := range expected {
		assert.Equal(t, ip.String(), expected[i], "Those two address should be same")
		inc(ip)
	}
}

func TestUtils_Success(t *testing.T) {

	data := []struct {
		desc     string
		cidr     string
		expected []string
	}{
		{"ValidCIDR_29", "140.113.234.123/29", []string{"140.113.234.121", "140.113.234.122", "140.113.234.123", "140.113.234.124", "140.113.234.125", "140.113.234.126"}},
		{"ValidCIDR_30", "140.113.234.123/30", []string{"140.113.234.121", "140.113.234.122"}},
		{"ValidCIDR_31", "140.113.234.123/31", []string{}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			data, err := getAllIPsfromCIDR(d.cidr)
			assert.NoError(t, err)
			assert.Equal(t, len(data), len(d.expected))

			for i, _ := range data {
				assert.Equal(t, data[i], d.expected[i])
			}
		})
	}
}
<|endoftext|>


<commit_before>package jsonschema

import (
	"encoding/json"
	"fmt"
	"strings"
)

type properties map[string]json.RawMessage

func (p properties) Validate(v interface{}) []ValidationError {
	var valErrs []ValidationError
	for schemaKey, schemaValue := range p {
		dataMap, ok := v.(map[string]interface{})
		if !ok {
			continue
		}
		if dataValue, ok := dataMap[schemaKey]; ok {
			var schema Schema
			err := json.Unmarshal(schemaValue, &schema)
			if err != nil {
				break
			}
			valErrs = append(valErrs, schema.Validate(dataValue)...)
		}
	}
	return valErrs
}

type minimum struct {
	json.Number
}

func (m minimum) Validate(unnormalized interface{}) []ValidationError {
	v, err := normalizeNumber(unnormalized)
	if err != nil {
		return []ValidationError{ValidationError{err.Error()}}
	}
	var isLarger bool
	switch n := v.(type) {
	case int64:
		isLarger = m.isLargerThanInt(n)
	case float64:
		isLarger = m.isLargerThanFloat(n)
	}
	if isLarger {
		minErr := ValidationError{fmt.Sprintf("Value must be larger than %s.", m)}
		return []ValidationError{minErr}
	}
	return nil
}

func (m *minimum) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, &m.Number); err != nil {
		return err
	}
	return nil
}

func (m minimum) isLargerThanInt(n int64) bool {
	if strings.Contains(m.String(), ".") {
		flt, err := m.Float64()
		if err != nil {
			return false
		}
		if flt > float64(n) {
			return true
		}
	} else {
		intg, err := m.Int64()
		if err != nil {
			return false
		}
		if intg > n {
			return true
		}
	}
	return false
}

func (m minimum) isLargerThanFloat(n float64) bool {
	flt, err := m.Float64()
	if err != nil {
		return false
	}
	if flt > n {
		return true
	}
	return false
}
<commit_msg>Remove unnecessary lines.<commit_after>package jsonschema

import (
	"encoding/json"
	"fmt"
	"strings"
)

type properties map[string]json.RawMessage

func (p properties) Validate(v interface{}) []ValidationError {
	var valErrs []ValidationError
	for schemaKey, schemaValue := range p {
		dataMap, ok := v.(map[string]interface{})
		if !ok {
			continue
		}
		if dataValue, ok := dataMap[schemaKey]; ok {
			var schema Schema
			err := json.Unmarshal(schemaValue, &schema)
			if err != nil {
				break
			}
			valErrs = append(valErrs, schema.Validate(dataValue)...)
		}
	}
	return valErrs
}

type minimum struct {
	json.Number
}

func (m minimum) Validate(unnormalized interface{}) []ValidationError {
	v, err := normalizeNumber(unnormalized)
	if err != nil {
		return []ValidationError{ValidationError{err.Error()}}
	}
	var isLarger bool
	switch n := v.(type) {
	case int64:
		isLarger = m.isLargerThanInt(n)
	case float64:
		isLarger = m.isLargerThanFloat(n)
	}
	if isLarger {
		minErr := ValidationError{fmt.Sprintf("Value must be larger than %s.", m)}
		return []ValidationError{minErr}
	}
	return nil
}

func (m *minimum) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, &m.Number)
}

func (m minimum) isLargerThanInt(n int64) bool {
	if strings.Contains(m.String(), ".") {
		flt, err := m.Float64()
		if err != nil {
			return false
		}
		if flt > float64(n) {
			return true
		}
	} else {
		intg, err := m.Int64()
		if err != nil {
			return false
		}
		if intg > n {
			return true
		}
	}
	return false
}

func (m minimum) isLargerThanFloat(n float64) bool {
	flt, err := m.Float64()
	if err != nil {
		return false
	}
	if flt > n {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package config

import "github.com/juju/errors"

var current *ChainConfig

type ChainConfig struct {
	Name      string `json:"name"`
	CoreAsset string `json:"core_asset"`
	Prefix    string `json:"prefix"`
	ID        string `json:"id"`
}

const (
	ChainIDUnknown = "0000000000000000000000000000000000000000000000000000000000000000"
	ChainIDBTS     = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8"
	ChainIDMuse    = "45ad2d3f9ef92a49b55c2227eb06123f613bb35dd08bd876f2aea21925a67a67"
	ChainIDTest    = "39f5e2ede1f8bc1a3a54a7914414e3779e33193f1f5693510e73cb7a87617447"
	ChainIDObelisk = "1cfde7c388b9e8ac06462d68aadbd966b58f88797637d9af805b4560b0e9661e"
	ChainIDGPH     = "b8d1603965b3eb1acba27e62ff59f74efa3154d43a4188d381088ac7cdf35539"
	ChainIDKarma   = "c85b4a30545e09c01aaa7943be89e9785481c1e7bd5ee7d176cb2b3d8dd71a70"
)

var (
	knownNetworks = []ChainConfig{
		ChainConfig{
			Name:      "Unknown",
			CoreAsset: "n/a",
			Prefix:    "n/a",
			ID:        ChainIDUnknown,
		},
		ChainConfig{
			Name:      "Graphene",
			CoreAsset: "CORE",
			Prefix:    "GPH",
			ID:        ChainIDGPH,
		},
		ChainConfig{
			Name:      "BitShares",
			CoreAsset: "BTS",
			Prefix:    "BTS",
			ID:        ChainIDBTS,
		},
		ChainConfig{
			Name:      "Muse",
			CoreAsset: "MUSE",
			Prefix:    "MUSE",
			ID:        ChainIDMuse,
		},
		ChainConfig{
			Name:      "Test",
			CoreAsset: "TEST",
			Prefix:    "TEST",
			ID:        ChainIDTest,
		},
		ChainConfig{
			Name:      "Obelisk",
			CoreAsset: "GOV",
			Prefix:    "FEW",
			ID:        ChainIDObelisk,
		},
		ChainConfig{
			"name":           "Karma",
			"core_asset":     "KRM",
			"address_prefix": "KRM",
			"chain_id":       ChainIDKarma,
		},
	}
)

func Current() *ChainConfig {
	return current
}

func Add(cnf ChainConfig) error {
	if FindByID(cnf.ID) != nil {
		return errors.Errorf("ChainConfig for ID %q already available", cnf.ID)
	}

	knownNetworks = append(knownNetworks, cnf)
	return nil
}

func FindByID(chainID string) *ChainConfig {
	for _, cnf := range knownNetworks {
		if cnf.ID == chainID {
			return &cnf
		}
	}

	return nil
}

func SetCurrent(chainID string) error {
	current = FindByID(chainID)
	if current != nil {
		return nil
	}

	return errors.Errorf("ChainConfig for ID %q not found", chainID)
}
<commit_msg>fix chainconfig<commit_after>package config

import "github.com/juju/errors"

var current *ChainConfig

type ChainConfig struct {
	Name      string `json:"name"`
	CoreAsset string `json:"core_asset"`
	Prefix    string `json:"prefix"`
	ID        string `json:"id"`
}

const (
	ChainIDUnknown = "0000000000000000000000000000000000000000000000000000000000000000"
	ChainIDBTS     = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8"
	ChainIDMuse    = "45ad2d3f9ef92a49b55c2227eb06123f613bb35dd08bd876f2aea21925a67a67"
	ChainIDTest    = "39f5e2ede1f8bc1a3a54a7914414e3779e33193f1f5693510e73cb7a87617447"
	ChainIDObelisk = "1cfde7c388b9e8ac06462d68aadbd966b58f88797637d9af805b4560b0e9661e"
	ChainIDGPH     = "b8d1603965b3eb1acba27e62ff59f74efa3154d43a4188d381088ac7cdf35539"
	ChainIDKarma   = "c85b4a30545e09c01aaa7943be89e9785481c1e7bd5ee7d176cb2b3d8dd71a70"
)

var (
	knownNetworks = []ChainConfig{
		ChainConfig{
			Name:      "Unknown",
			CoreAsset: "n/a",
			Prefix:    "n/a",
			ID:        ChainIDUnknown,
		},
		ChainConfig{
			Name:      "Graphene",
			CoreAsset: "CORE",
			Prefix:    "GPH",
			ID:        ChainIDGPH,
		},
		ChainConfig{
			Name:      "BitShares",
			CoreAsset: "BTS",
			Prefix:    "BTS",
			ID:        ChainIDBTS,
		},
		ChainConfig{
			Name:      "Muse",
			CoreAsset: "MUSE",
			Prefix:    "MUSE",
			ID:        ChainIDMuse,
		},
		ChainConfig{
			Name:      "Test",
			CoreAsset: "TEST",
			Prefix:    "TEST",
			ID:        ChainIDTest,
		},
		ChainConfig{
			Name:      "Obelisk",
			CoreAsset: "GOV",
			Prefix:    "FEW",
			ID:        ChainIDObelisk,
		},
		ChainConfig{
			Name:      "Karma",
			CoreAsset: "KRM",
			Prefix:    "KRM",
			ID:        ChainIDKarma,
		},
	}
)

func Current() *ChainConfig {
	return current
}

func Add(cnf ChainConfig) error {
	if FindByID(cnf.ID) != nil {
		return errors.Errorf("ChainConfig for ID %q already available", cnf.ID)
	}

	knownNetworks = append(knownNetworks, cnf)
	return nil
}

func FindByID(chainID string) *ChainConfig {
	for _, cnf := range knownNetworks {
		if cnf.ID == chainID {
			return &cnf
		}
	}

	return nil
}

func SetCurrent(chainID string) error {
	current = FindByID(chainID)
	if current != nil {
		return nil
	}

	return errors.Errorf("ChainConfig for ID %q not found", chainID)
}
<|endoftext|>


<commit_before>package config

import (
	"log"
	"runtime"
	"strings"

	"github.com/wangkuiyi/sh"
)

// LinuxDistro returns known distribution names, including centos,
// coreos, and ubuntu, if the current system is Linux, or panics
// otherwise.
func LinuxDistro() string {
	if runtime.GOOS != "linux" {
		log.Panicf("Not Linux, but %s", runtime.GOOS)
	}

	line := strings.ToLower(<-sh.Head(sh.Cat("/etc/os-release"), 1))

	if strings.Contains(line, "CentOS") {
		return "centos"
	} else if strings.Contains(line, "Ubuntu") {
		return "ubuntu"
	} else if strings.Contains(line, "CoreOS") {
		return "coreos"
	}
	log.Panicf("Unknown OS %s", line)
	return "" // dummpy return
}
<commit_msg>Fix a bug<commit_after>package config

import (
	"log"
	"runtime"
	"strings"

	"github.com/wangkuiyi/sh"
)

// LinuxDistro returns known distribution names, including centos,
// coreos, and ubuntu, if the current system is Linux, or panics
// otherwise.
func LinuxDistro() string {
	if runtime.GOOS != "linux" {
		log.Panicf("Not Linux, but %s", runtime.GOOS)
	}

	line := strings.ToLower(<-sh.Head(sh.Cat("/etc/os-release"), 1))

	if strings.Contains(line, "centos") {
		return "centos"
	} else if strings.Contains(line, "ubuntu") {
		return "ubuntu"
	} else if strings.Contains(line, "coreos") {
		return "coreos"
	}
	log.Panicf("Unknown OS %s", line)
	return "" // dummpy return
}
<|endoftext|>


<commit_before>package xcontext

import (
	"context"
	"net/http"
)

// ContextAware is an optional mixin implemented by anything with can hold a context
type ContextAware interface {
	// Context *never* returns a nil context
	Context() context.Context
	SetContext(context.Context)
}

type contextAwareResponseWriter struct {
	http.ResponseWriter

	// NOTE: Accessing the context is intentionally not concurrency safe
	ctx context.Context
}

func (carw *contextAwareResponseWriter) Context() context.Context {
	if carw.ctx != nil {
		return carw.ctx
	}
	// mimic net/http.Request.Context()
	// this allows contextAwareResponseWriter{response} to be valid
	return context.Background()
}

func (carw *contextAwareResponseWriter) SetContext(ctx context.Context) {
	if ctx == nil {
		// mimic the behavior of the net/http package
		panic("nil context")
	}

	carw.ctx = ctx
}

func Context(response http.ResponseWriter, request *http.Request) context.Context {
	if ca, ok := response.(ContextAware); ok {
		return ca.Context()
	}

	// fallback to the request's context
	return request.Context()
}

// SetContext associates a context with a response.  Useful for decorated code that needs to communicate
// a context back up the call stack.
//
// Note that since ContextAware is an optional interface, it's possible that the supplied ResponseWriter does
// not implement ContextAware.  This is tolerated, so as to be backward compatible.
//
// The returned ResponseWriter will always be ContextAware.  This writer can be used for subsequent handling code.
func SetContext(response http.ResponseWriter, ctx context.Context) http.ResponseWriter {
	if ca, ok := response.(ContextAware); ok {
		ca.SetContext(ctx)
		return response
	}

	if ctx == nil {
		panic("nil context")
	}

	return &contextAwareResponseWriter{response, ctx}
}

// WithContext associates a context with the response/request pair that can later be accessed via the Context function.
// If response is already ContextAware, it is used and returned as is.
//
// Useful for code that is decorating http handling code in order to establish a context.
func WithContext(response http.ResponseWriter, request *http.Request, ctx context.Context) (http.ResponseWriter, *http.Request) {
	if ca, ok := response.(ContextAware); ok {
		ca.SetContext(ctx)
		return response, request.WithContext(ctx)
	}

	if ctx == nil {
		panic("nil context")
	}

	return &contextAwareResponseWriter{response, ctx}, request.WithContext(ctx)
}
<commit_msg>Fixed the ContextAware functionality<commit_after>package xcontext

import (
	"bufio"
	"context"
	"errors"
	"net"
	"net/http"
)

// ContextAware is an optional mixin implemented by anything with can hold a context
type ContextAware interface {
	// Context *never* returns a nil context
	Context() context.Context
	SetContext(context.Context)
}

type contextAwareResponseWriter struct {
	http.ResponseWriter
	ctx context.Context
}

var _ ContextAware = &contextAwareResponseWriter{}
var _ http.Hijacker = &contextAwareResponseWriter{}
var _ http.Flusher = &contextAwareResponseWriter{}
var _ http.Pusher = &contextAwareResponseWriter{}

func (carw contextAwareResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if h, ok := carw.ResponseWriter.(http.Hijacker); ok {
		return h.Hijack()
	}

	return nil, nil, errors.New("Hijacker not supported")
}

func (carw contextAwareResponseWriter) Flush() {
	if f, ok := carw.ResponseWriter.(http.Flusher); ok {
		f.Flush()
	}
}

func (carw contextAwareResponseWriter) Push(target string, opts *http.PushOptions) error {
	if p, ok := carw.ResponseWriter.(http.Pusher); ok {
		return p.Push(target, opts)
	}

	return errors.New("Pusher not supported")
}

func (carw *contextAwareResponseWriter) Context() context.Context {
	if carw.ctx != nil {
		return carw.ctx
	}

	return context.Background()
}

func (carw *contextAwareResponseWriter) SetContext(ctx context.Context) {
	if ctx == nil {
		// mimic the behavior of the net/http package
		panic("nil context")
	}

	carw.ctx = ctx
}

func Context(response http.ResponseWriter, request *http.Request) context.Context {
	if ca, ok := response.(ContextAware); ok {
		return ca.Context()
	}

	// fallback to the request's context
	return request.Context()
}

// SetContext associates a context with a response.  Useful for decorated code that needs to communicate
// a context back up the call stack.
//
// Note that since ContextAware is an optional interface, it's possible that the supplied ResponseWriter does
// not implement ContextAware.  This is tolerated, so as to be backward compatible.
//
// The returned ResponseWriter will always be ContextAware.  This writer can be used for subsequent handling code.
func SetContext(response http.ResponseWriter, ctx context.Context) http.ResponseWriter {
	if ca, ok := response.(ContextAware); ok {
		ca.SetContext(ctx)
		return response
	}

	if ctx == nil {
		panic("nil context")
	}

	return &contextAwareResponseWriter{response, ctx}
}

// WithContext associates a context with the response/request pair that can later be accessed via the Context function.
// If response is already ContextAware, it is used and returned as is.
//
// Useful for code that is decorating http handling code in order to establish a context.
func WithContext(response http.ResponseWriter, request *http.Request, ctx context.Context) (http.ResponseWriter, *http.Request) {
	if ca, ok := response.(ContextAware); ok {
		ca.SetContext(ctx)
		return response, request.WithContext(ctx)
	}

	if ctx == nil {
		ctx = context.Background()
	}

	return &contextAwareResponseWriter{response, ctx}, request.WithContext(ctx)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"github.com/armon/consul-api"
	"io/ioutil"
	"os"
	"testing"
	"time"
)

func TestBuildTemplate(t *testing.T) {
	conf := &Config{
		Template: "test-fixtures/simple.conf",
	}
	servers := map[string][]*consulapi.ServiceEntry{
		"app": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "app", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "app", Port: 8000},
			},
		},
	}

	out, err := buildTemplate(conf, servers)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	expect, err := ioutil.ReadFile("test-fixtures/simple.conf.out")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !bytes.Equal(out, expect) {
		t.Fatalf("bad: %s", out)
	}
}

func TestReload(t *testing.T) {
	os.Remove("test_out")
	conf := &Config{
		ReloadCommand: "echo 'foo' > test_out",
	}
	if err := reload(conf); err != nil {
		t.Fatalf("err: %v", err)
	}
	bytes, err := ioutil.ReadFile("test_out")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if string(bytes) != "foo\n" {
		t.Fatalf("bad: %v", bytes)
	}
	os.Remove("test_out")
}

func TestShouldStop(t *testing.T) {
	ch := make(chan struct{})
	if shouldStop(ch) {
		t.Fatalf("bad")
	}
	close(ch)
	if !shouldStop(ch) {
		t.Fatalf("bad")
	}
}

func TestAsyncNotify(t *testing.T) {
	ch := make(chan struct{}, 1)
	asyncNotify(ch)
	asyncNotify(ch)
	asyncNotify(ch)

	select {
	case <-ch:
	default:
		t.Fatalf("should work")
	}
	select {
	case <-ch:
		t.Fatalf("should not work")
	default:
	}

}

func TestMin(t *testing.T) {
	if min(1, 2) != 1 {
		t.Fatalf("Bad")
	}
	if min(2, 1) != 1 {
		t.Fatalf("Bad")
	}
}

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<commit_msg>Test aggregation<commit_after>package main

import (
	"bytes"
	"github.com/armon/consul-api"
	"io/ioutil"
	"os"
	"testing"
	"time"
)

func TestAggregateServers(t *testing.T) {
	en1 := &consulapi.ServiceEntry{
		Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
		Service: &consulapi.AgentService{ID: "app", Port: 8000},
	}
	en2 := &consulapi.ServiceEntry{
		Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
		Service: &consulapi.AgentService{ID: "app", Port: 8000},
	}
	en3 := &consulapi.ServiceEntry{
		Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
		Service: &consulapi.AgentService{ID: "db", Port: 5000},
	}
	wp1 := &WatchPath{Backend: "app"}
	wp2 := &WatchPath{Backend: "app"}
	wp3 := &WatchPath{Backend: "db"}
	d := &backendData{
		Servers: map[*WatchPath][]*consulapi.ServiceEntry{
			wp1: []*consulapi.ServiceEntry{en1},
			wp2: []*consulapi.ServiceEntry{en2},
			wp3: []*consulapi.ServiceEntry{en3},
		},
		Backends: map[string][]*WatchPath{
			"app": []*WatchPath{wp1, wp2},
			"db":  []*WatchPath{wp3},
		},
	}
	agg := aggregateServers(d)
	if len(agg) != 2 {
		t.Fatalf("Bad: %v", agg)
	}
	app := agg["app"]
	if len(app) != 2 {
		t.Fatalf("Bad: %v", app)
	}
	if app[0] != en1 && app[1] != en2 {
		t.Fatalf("Bad: %v", app)
	}
	db := agg["db"]
	if len(db) != 1 {
		t.Fatalf("Bad: %v", db)
	}
	if db[0] != en3 {
		t.Fatalf("Bad: %v", db)
	}
}

func TestBuildTemplate(t *testing.T) {
	conf := &Config{
		Template: "test-fixtures/simple.conf",
	}
	servers := map[string][]*consulapi.ServiceEntry{
		"app": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "app", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "app", Port: 8000},
			},
		},
	}

	out, err := buildTemplate(conf, servers)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	expect, err := ioutil.ReadFile("test-fixtures/simple.conf.out")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !bytes.Equal(out, expect) {
		t.Fatalf("bad: %s", out)
	}
}

func TestReload(t *testing.T) {
	os.Remove("test_out")
	conf := &Config{
		ReloadCommand: "echo 'foo' > test_out",
	}
	if err := reload(conf); err != nil {
		t.Fatalf("err: %v", err)
	}
	bytes, err := ioutil.ReadFile("test_out")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if string(bytes) != "foo\n" {
		t.Fatalf("bad: %v", bytes)
	}
	os.Remove("test_out")
}

func TestShouldStop(t *testing.T) {
	ch := make(chan struct{})
	if shouldStop(ch) {
		t.Fatalf("bad")
	}
	close(ch)
	if !shouldStop(ch) {
		t.Fatalf("bad")
	}
}

func TestAsyncNotify(t *testing.T) {
	ch := make(chan struct{}, 1)
	asyncNotify(ch)
	asyncNotify(ch)
	asyncNotify(ch)

	select {
	case <-ch:
	default:
		t.Fatalf("should work")
	}
	select {
	case <-ch:
		t.Fatalf("should not work")
	default:
	}

}

func TestMin(t *testing.T) {
	if min(1, 2) != 1 {
		t.Fatalf("Bad")
	}
	if min(2, 1) != 1 {
		t.Fatalf("Bad")
	}
}

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<|endoftext|>


<commit_before>// Library for general purpose functions used by the Yieldbot Infrastructure
// teams in sensu.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package ybsensupluginutil

import (
	"fmt"
	"os"
	"strings"
)

// EHndlr is for generic error handling in all Yieldbot monitoring packages.
func EHndlr(e error) {
	if e != nil {
		fmt.Printf("ERROR: %v", e)
		os.Exit(129)
	}
}

// Exit method for all sensu checks that will print the output and desired
// exit code
func Exit(args ...interface{}) {
	// YELLOW need to make sure that condition exists
	var exitCode int
	output := ""

	if 1 > len(args) {
		panic("Not enough parameters.")
	}

	for i, p := range args {
		switch i {
		case 0: // name
			param, ok := p.(int)
			if !ok {
				panic("1st parameter not type string.")
			}

			for k := range MonitoringErrorCodes {
				if k == strings.ToUpper(param) {
					exitCode = MonitoringErrorCodes[k]
				}
			}

		case 1: // x
			param, ok := p.(string)
			if !ok {
				panic("2nd parameter not type string.")
			}
			output = param

		default:
			panic("Wrong parameter count.")
		}
	}

	fmt.Printf("%v", output)
	os.Exit(exitCode)
}
<commit_msg>debugging functions<commit_after>// Library for general purpose functions used by the Yieldbot Infrastructure
// teams in sensu.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package ybsensupluginutil

import (
	"fmt"
	"os"
	"strings"
)

// EHndlr is for generic error handling in all Yieldbot monitoring packages.
func EHndlr(e error) {
	if e != nil {
		fmt.Printf("ERROR: %v", e)
		os.Exit(129)
	}
}

// Exit method for all sensu checks that will print the output and desired
// exit code
func Exit(args ...string) {
	// YELLOW need to make sure that condition exists
	var exitCode int
	output := ""

	if 1 > len(args) {
		panic("Not enough parameters.")
	}

	for i, p := range args {
		switch i {
		case 0: // name
			param, ok := p.(str)
			if !ok {
				panic("1st parameter not type string.")
			}

			for k := range MonitoringErrorCodes {
				if k == strings.ToUpper(param) {
					exitCode = MonitoringErrorCodes[k]
				}
			}

		case 1: // x
			param, ok := p.(string)
			if !ok {
				panic("2nd parameter not type string.")
			}
			output = param

		default:
			panic("Wrong parameter count.")
		}
	}

	fmt.Printf("%v", output)
	os.Exit(exitCode)
}

func CamelCaseAll(ss ...string) []string {

	camelCasedStrings := make([]string, len(ss))

	for i, s := range ss {
		camelCasedStrings[i] = stringcase.ToCamelCase(s)
	}

	return camelCasedStrings
}

func main() {
	ss1 := CamelCaseAll("hello world", "Apple Banana Cherry")
	// = []string{"helloWorld", "appleBananaCherry"}

	ss2 := CamelCaseAll("More than meets the eye")
	// = []string{"moreThanMeetsTheEye"}

	ss3 := CamelCaseAll()
	// = []string{}

	fmt.Printf("ss1 = %v\n", ss1)
	fmt.Printf("ss2 = %v\n", ss2)
	fmt.Printf("ss3 = %v\n", ss3)

	// Output:
	// ss1 = [helloWorld appleBananaCherry]
	// ss2 = [moreThanMeetsTheEye]
	// ss3 = []
}
<|endoftext|>


<commit_before>package interfaces

import (
	"fmt"
	"math/rand"
	"strings"
	"time"

	"github.com/Tinker-Ware/gh-service/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"

	ghoauth "golang.org/x/oauth2/github"
)

// GithubRepository receives a github client and performs the necessary operations
// within an user account
type GithubRepository struct {
	client      *github.Client
	oauthConfig *oauth2.Config
}

// NewGithubRepository initializes the GithubRepository
func NewGithubRepository(clientID, clientSecret string, scopes []string) (*GithubRepository, error) {

	oauth2client := &oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scopes:       scopes,
		Endpoint:     ghoauth.Endpoint,
	}

	rp := &GithubRepository{
		oauthConfig: oauth2client,
	}

	return rp, nil
}

// README defines a readme to be written in a repository
var README = domain.File{
	Path:    "README.md",
	Content: []byte("# This is a README"),
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// GetOauthURL returns the OATH URL based on the configuration
func (repo GithubRepository) GetOauthURL() (string, string) {
	oauthStateString := randSeq(10)
	url := repo.oauthConfig.AuthCodeURL(oauthStateString, oauth2.AccessTypeOnline)
	return url, oauthStateString
}

// GetToken returns a token from Github with the code received from the GET request
func (repo GithubRepository) GetToken(code, givenState, incomingStates string) (*domain.User, error) {

	token, err := repo.oauthConfig.Exchange(oauth2.NoContext, code)
	if err != nil {
		return nil, fmt.Errorf("oauthConf.Exchange() failed with '%s'", err.Error())
	}

	oauthClient := repo.oauthConfig.Client(oauth2.NoContext, token)
	client := github.NewClient(oauthClient)
	user, _, err := client.Users.Get("")
	if err != nil {
		return nil, fmt.Errorf("Cannot retrieve User data: %s", err.Error())
	}

	usr := domain.User{
		Username:       *user.Login,
		AccessToken:    token.AccessToken,
		ExpirationDate: token.Expiry.Unix(),
	}

	return &usr, nil
}

// GetUser retrieves the github user information
func (repo *GithubRepository) GetUser(username string) (*domain.User, error) {
	user, _, err := repo.client.Users.Get(username)

	if err != nil {
		return nil, err
	}

	usr := domain.User{
		ID:       *user.ID,
		Username: *user.Login,
	}

	return &usr, nil

}

// SetToken sets the token for the client
func (repo *GithubRepository) SetToken(token string) {

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)
	repo.client = client

}

// GetAllRepos returns all the repos from an user account
func (repo GithubRepository) GetAllRepos(username string) ([]domain.Repository, error) {

	opt := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 30},
	}

	var allRepos []domain.Repository
	for {
		repos, resp, err := repo.client.Repositories.List("", opt)
		if err != nil {
			return nil, err
		}
		for _, repo := range repos {

			r := domain.Repository{
				Name:        repo.Name,
				FullName:    repo.FullName,
				Description: repo.Description,
				Private:     repo.Private,
				HTMLURL:     repo.HTMLURL,
				CloneURL:    repo.CloneURL,
				SSHURL:      repo.SSHURL,
			}
			allRepos = append(allRepos, r)
		}
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	return allRepos, nil
}

// GetRepo gets the information from a single repo
func (repo GithubRepository) GetRepo(username, reponame string) (*domain.Repository, error) {

	rp, _, err := repo.client.Repositories.Get(username, reponame)
	if err != nil {
		return nil, err
	}

	r := &domain.Repository{
		Name:        rp.Name,
		FullName:    rp.FullName,
		Description: rp.Description,
		Private:     rp.Private,
		HTMLURL:     rp.HTMLURL,
		CloneURL:    rp.CloneURL,
		SSHURL:      rp.SSHURL,
	}

	return r, nil
}

// CreateRepo creates a repository in the github user account
func (repo GithubRepository) CreateRepo(username, reponame, org string, private bool) (*domain.Repository, error) {
	rp := &github.Repository{
		Name:    github.String(reponame),
		Private: github.Bool(private),
	}
	rp, _, err := repo.client.Repositories.Create(org, rp)

	if err != nil {
		return nil, err
	}

	r := &domain.Repository{
		Name:        rp.Name,
		FullName:    rp.FullName,
		Description: rp.Description,
		Private:     rp.Private,
		HTMLURL:     rp.HTMLURL,
		CloneURL:    rp.CloneURL,
		SSHURL:      rp.SSHURL,
	}

	return r, nil
}

// GetKey returns a Key from the user github account
func (repo GithubRepository) GetKey(username string, id int) (*domain.Key, error) {
	ghkey, _, err := repo.client.Users.GetKey(id)
	if err != nil {
		return nil, err
	}

	key := &domain.Key{
		ID:    ghkey.ID,
		Title: ghkey.Title,
		Key:   ghkey.Key,
		URL:   ghkey.URL,
	}

	return key, nil
}

// ShowKeys returns all the keys in a user github account
func (repo GithubRepository) ShowKeys(username string) ([]domain.Key, error) {
	ghKeys, _, err := repo.client.Users.ListKeys(username, nil)
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}

	keys := []domain.Key{}

	for _, k := range ghKeys {
		key := domain.Key{
			ID:    k.ID,
			Key:   k.Key,
			Title: k.Title,
			URL:   k.URL,
		}
		keys = append(keys, key)
	}

	return keys, nil

}

// CreateKey creates a key in the github repository
func (repo GithubRepository) CreateKey(username string, key *domain.Key) error {

	k := github.Key{
		Title: key.Title,
		Key:   key.Key,
	}

	ghK, _, err := repo.client.Users.CreateKey(&k)
	if err != nil {
		return err
	}

	key.ID = ghK.ID
	key.URL = ghK.URL

	return nil

}

// CreateFile creates file inside an user repository
func (repo GithubRepository) CreateFile(file domain.File, author domain.Author, username, repoName string) error {

	opt := &github.RepositoryContentFileOptions{
		Message: github.String(author.Message),
		Content: file.Content,
		Branch:  github.String(author.Branch),
		Committer: &github.CommitAuthor{
			Name:  github.String(author.Author),
			Email: github.String(author.Email),
		},
	}

	_, _, err := repo.client.Repositories.CreateFile(username, repoName, file.Path, opt)
	if err != nil {
		return err
	}
	return nil
}

// AddFiles inserts multiple files inside a github repository
func (repo GithubRepository) AddFiles(files []domain.File, author domain.Author, username, reponame string) error {
	tree := []github.TreeEntry{}
	emptyRepo := "409 Git Repository is empty"

	// Get the reference sha
	// TODO remove hardcoded branch name
	ghTree, _, err := repo.client.Git.GetRef(username, reponame, "heads/master")
	if err != nil {

		// if the repo is empty create a README, else unexpected error
		if strings.Contains(err.Error(), emptyRepo) {

			// Create a copy of author for the initial commit
			author2 := author
			author2.Message = "Initial Commit"

			err = repo.CreateFile(README, author2, username, reponame)
			if err != nil {
				return err
			}

			// Repository should not be empty, otherwise, unexpected error
			ghTree, _, err = repo.client.Git.GetRef(username, reponame, "heads/master")
			if err != nil {
				return err
			}

		} else {
			return err

		}

	}
	lastCommit := *ghTree.Ref

	// Create a new tree
	// TODO Check for existing files and paths

	for _, file := range files {
		t := github.TreeEntry{
			Path:    github.String(file.Path),
			Mode:    github.String("100644"),
			Type:    github.String("blob"),
			Content: github.String(string(file.Content)),
		}

		tree = append(tree, t)
	}

	// Get the current tree
	currentTree, _, err := repo.client.Git.GetTree(username, reponame, lastCommit, false)
	if err != nil {
		return err
	}

	// Add the existing files to the tree
	for _, file := range currentTree.Entries {
		t := github.TreeEntry{
			Path: file.Path,
			Mode: file.Mode,
			Type: file.Type,
			SHA:  file.SHA,
		}

		tree = append(tree, t)
	}

	newTree, _, err := repo.client.Git.CreateTree(username, reponame, *currentTree.SHA, tree)
	if err != nil {
		return err
	}

	commit := github.Commit{
		Message: github.String(author.Message),
		Parents: []github.Commit{{SHA: currentTree.SHA}},
		Tree:    &github.Tree{SHA: newTree.SHA},
	}

	newCommit, _, err := repo.client.Git.CreateCommit(username, reponame, &commit)
	if err != nil {
		return err
	}

	reference := github.Reference{
		Ref: github.String("refs/heads/master"),
		Object: &github.GitObject{
			SHA: newCommit.SHA,
		},
	}

	_, _, err = repo.client.Git.UpdateRef(username, reponame, &reference, false)
	if err != nil {
		return err
	}

	return nil
}

func randSeq(n int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<commit_msg>Update to the new version of the github client<commit_after>package interfaces

import (
	"context"
	"fmt"
	"math/rand"
	"strings"
	"time"

	"github.com/Tinker-Ware/gh-service/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"

	ghoauth "golang.org/x/oauth2/github"
)

// GithubRepository receives a github client and performs the necessary operations
// within an user account
type GithubRepository struct {
	client      *github.Client
	oauthConfig *oauth2.Config
	context     context.Context
}

// NewGithubRepository initializes the GithubRepository
func NewGithubRepository(clientID, clientSecret string, scopes []string) (*GithubRepository, error) {

	oauth2client := &oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scopes:       scopes,
		Endpoint:     ghoauth.Endpoint,
	}

	rp := &GithubRepository{
		oauthConfig: oauth2client,
		context:     context.Background(),
	}

	return rp, nil
}

// README defines a readme to be written in a repository
var README = domain.File{
	Path:    "README.md",
	Content: []byte("# This is a README"),
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// GetOauthURL returns the OATH URL based on the configuration
func (repo GithubRepository) GetOauthURL() (string, string) {
	oauthStateString := randSeq(10)
	url := repo.oauthConfig.AuthCodeURL(oauthStateString, oauth2.AccessTypeOnline)
	return url, oauthStateString
}

// GetToken returns a token from Github with the code received from the GET request
func (repo GithubRepository) GetToken(code, givenState, incomingStates string) (*domain.User, error) {

	token, err := repo.oauthConfig.Exchange(oauth2.NoContext, code)
	if err != nil {
		return nil, fmt.Errorf("oauthConf.Exchange() failed with '%s'", err.Error())
	}

	oauthClient := repo.oauthConfig.Client(oauth2.NoContext, token)
	client := github.NewClient(oauthClient)
	user, _, err := client.Users.Get(repo.context, "")
	if err != nil {
		return nil, fmt.Errorf("Cannot retrieve User data: %s", err.Error())
	}

	usr := domain.User{
		Username:       *user.Login,
		AccessToken:    token.AccessToken,
		ExpirationDate: token.Expiry.Unix(),
	}

	return &usr, nil
}

// GetUser retrieves the github user information
func (repo *GithubRepository) GetUser(username string) (*domain.User, error) {
	user, _, err := repo.client.Users.Get(repo.context, username)

	if err != nil {
		return nil, err
	}

	usr := domain.User{
		ID:       *user.ID,
		Username: *user.Login,
	}

	return &usr, nil

}

// SetToken sets the token for the client
func (repo *GithubRepository) SetToken(token string) {

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)
	repo.client = client

}

// GetAllRepos returns all the repos from an user account
func (repo GithubRepository) GetAllRepos(username string) ([]domain.Repository, error) {

	opt := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 30},
	}

	var allRepos []domain.Repository
	for {
		repos, resp, err := repo.client.Repositories.List(repo.context, "", opt)
		if err != nil {
			return nil, err
		}
		for _, repo := range repos {

			r := domain.Repository{
				Name:        repo.Name,
				FullName:    repo.FullName,
				Description: repo.Description,
				Private:     repo.Private,
				HTMLURL:     repo.HTMLURL,
				CloneURL:    repo.CloneURL,
				SSHURL:      repo.SSHURL,
			}
			allRepos = append(allRepos, r)
		}
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	return allRepos, nil
}

// GetRepo gets the information from a single repo
func (repo GithubRepository) GetRepo(username, reponame string) (*domain.Repository, error) {

	rp, _, err := repo.client.Repositories.Get(repo.context, username, reponame)
	if err != nil {
		return nil, err
	}

	r := &domain.Repository{
		Name:        rp.Name,
		FullName:    rp.FullName,
		Description: rp.Description,
		Private:     rp.Private,
		HTMLURL:     rp.HTMLURL,
		CloneURL:    rp.CloneURL,
		SSHURL:      rp.SSHURL,
	}

	return r, nil
}

// CreateRepo creates a repository in the github user account
func (repo GithubRepository) CreateRepo(username, reponame, org string, private bool) (*domain.Repository, error) {
	rp := &github.Repository{
		Name:    github.String(reponame),
		Private: github.Bool(private),
	}
	rp, _, err := repo.client.Repositories.Create(repo.context, org, rp)

	if err != nil {
		return nil, err
	}

	r := &domain.Repository{
		Name:        rp.Name,
		FullName:    rp.FullName,
		Description: rp.Description,
		Private:     rp.Private,
		HTMLURL:     rp.HTMLURL,
		CloneURL:    rp.CloneURL,
		SSHURL:      rp.SSHURL,
	}

	return r, nil
}

// GetKey returns a Key from the user github account
func (repo GithubRepository) GetKey(username string, id int) (*domain.Key, error) {
	ghkey, _, err := repo.client.Users.GetKey(repo.context, id)
	if err != nil {
		return nil, err
	}

	key := &domain.Key{
		ID:    ghkey.ID,
		Title: ghkey.Title,
		Key:   ghkey.Key,
		URL:   ghkey.URL,
	}

	return key, nil
}

// ShowKeys returns all the keys in a user github account
func (repo GithubRepository) ShowKeys(username string) ([]domain.Key, error) {
	ghKeys, _, err := repo.client.Users.ListKeys(repo.context, username, nil)
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}

	keys := []domain.Key{}

	for _, k := range ghKeys {
		key := domain.Key{
			ID:    k.ID,
			Key:   k.Key,
			Title: k.Title,
			URL:   k.URL,
		}
		keys = append(keys, key)
	}

	return keys, nil

}

// CreateKey creates a key in the github repository
func (repo GithubRepository) CreateKey(username string, key *domain.Key) error {

	k := github.Key{
		Title: key.Title,
		Key:   key.Key,
	}

	ghK, _, err := repo.client.Users.CreateKey(repo.context, &k)
	if err != nil {
		return err
	}

	key.ID = ghK.ID
	key.URL = ghK.URL

	return nil

}

// CreateFile creates file inside an user repository
func (repo GithubRepository) CreateFile(file domain.File, author domain.Author, username, repoName string) error {

	opt := &github.RepositoryContentFileOptions{
		Message: github.String(author.Message),
		Content: file.Content,
		Branch:  github.String(author.Branch),
		Committer: &github.CommitAuthor{
			Name:  github.String(author.Author),
			Email: github.String(author.Email),
		},
	}

	_, _, err := repo.client.Repositories.CreateFile(repo.context, username, repoName, file.Path, opt)
	if err != nil {
		return err
	}
	return nil
}

// AddFiles inserts multiple files inside a github repository
func (repo GithubRepository) AddFiles(files []domain.File, author domain.Author, username, reponame string) error {
	tree := []github.TreeEntry{}
	emptyRepo := "409 Git Repository is empty"

	// Get the reference sha
	// TODO remove hardcoded branch name
	ghTree, _, err := repo.client.Git.GetRef(repo.context, username, reponame, "heads/master")
	if err != nil {

		// if the repo is empty create a README, else unexpected error
		if strings.Contains(err.Error(), emptyRepo) {

			// Create a copy of author for the initial commit
			author2 := author
			author2.Message = "Initial Commit"

			err = repo.CreateFile(README, author2, username, reponame)
			if err != nil {
				return err
			}

			// Repository should not be empty, otherwise, unexpected error
			ghTree, _, err = repo.client.Git.GetRef(repo.context, username, reponame, "heads/master")
			if err != nil {
				return err
			}

		} else {
			return err

		}

	}
	lastCommit := *ghTree.Ref

	// Create a new tree
	// TODO Check for existing files and paths

	for _, file := range files {
		t := github.TreeEntry{
			Path:    github.String(file.Path),
			Mode:    github.String("100644"),
			Type:    github.String("blob"),
			Content: github.String(string(file.Content)),
		}

		tree = append(tree, t)
	}

	// Get the current tree
	currentTree, _, err := repo.client.Git.GetTree(repo.context, username, reponame, lastCommit, false)
	if err != nil {
		return err
	}

	// Add the existing files to the tree
	for _, file := range currentTree.Entries {
		t := github.TreeEntry{
			Path: file.Path,
			Mode: file.Mode,
			Type: file.Type,
			SHA:  file.SHA,
		}

		tree = append(tree, t)
	}

	newTree, _, err := repo.client.Git.CreateTree(repo.context, username, reponame, *currentTree.SHA, tree)
	if err != nil {
		return err
	}

	commit := github.Commit{
		Message: github.String(author.Message),
		Parents: []github.Commit{{SHA: currentTree.SHA}},
		Tree:    &github.Tree{SHA: newTree.SHA},
	}

	newCommit, _, err := repo.client.Git.CreateCommit(repo.context, username, reponame, &commit)
	if err != nil {
		return err
	}

	reference := github.Reference{
		Ref: github.String("refs/heads/master"),
		Object: &github.GitObject{
			SHA: newCommit.SHA,
		},
	}

	_, _, err = repo.client.Git.UpdateRef(repo.context, username, reponame, &reference, false)
	if err != nil {
		return err
	}

	return nil
}

func randSeq(n int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The CephCSI Authors.

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

    http://www.apache.org/licenses/LICENSE2.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 util

import (
	"os"

	k8s "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	klog "k8s.io/klog/v2"
)

// NewK8sClient create kubernetes client.
func NewK8sClient() *k8s.Clientset {
	var cfg *rest.Config
	var err error
	cPath := os.Getenv("KUBERNETES_CONFIG_PATH")
	if cPath != "" {
		cfg, err = clientcmd.BuildConfigFromFlags("", cPath)
		if err != nil {
			klog.Errorf("Failed to get cluster config with error: %v\n", err)
			os.Exit(1)
		}
	} else {
		cfg, err = rest.InClusterConfig()
		if err != nil {
			klog.Errorf("Failed to get cluster config with error: %v\n", err)
			os.Exit(1)
		}
	}
	client, err := k8s.NewForConfig(cfg)
	if err != nil {
		klog.Errorf("Failed to create client with error: %v\n", err)
		os.Exit(1)
	}
	return client
}
<commit_msg>util: use local FatalLog() for NewK8sClient() instead of klog<commit_after>/*
Copyright 2020 The CephCSI Authors.

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

    http://www.apache.org/licenses/LICENSE2.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 util

import (
	"os"

	k8s "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

// NewK8sClient create kubernetes client.
func NewK8sClient() *k8s.Clientset {
	var cfg *rest.Config
	var err error
	cPath := os.Getenv("KUBERNETES_CONFIG_PATH")
	if cPath != "" {
		cfg, err = clientcmd.BuildConfigFromFlags("", cPath)
		if err != nil {
			FatalLog("Failed to get cluster config with error: %v\n", err)
		}
	} else {
		cfg, err = rest.InClusterConfig()
		if err != nil {
			FatalLog("Failed to get cluster config with error: %v\n", err)
		}
	}
	client, err := k8s.NewForConfig(cfg)
	if err != nil {
		FatalLog("Failed to create client with error: %v\n", err)
	}
	return client
}
<|endoftext|>