<commit_before>// Package replicat is a server for n way synchronization of content (Replication for the cloud).
// Copyright 2016 Jacob Taylor jacob@replic.at       More Info: http://replic.at
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/goji/httpauth"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

// ReplicatServer is a structure that contains the definition of the servers in a cluster. Each node has a name and this
// node (as determined by globalSettings.name at the moment) also has a StorageTracker interface.
type ReplicatServer struct {
	ClusterKey    string
	Name          string
	Address       string
	Status        string
	CurrentState  DirTreeMap
	PreviousState DirTreeMap
	Lock          sync.Mutex
	storage       StorageTracker
}

// GetStatus - get the current status of the server
func (server *ReplicatServer) GetStatus() string {
	return server.Status
}

// SetStatus - set the current status of the server
func (server *ReplicatServer) SetStatus(status string) {
	// adding an inline check to make sure the server is valid
	// if the server is being shut down or at the end of a unit test)
	// the assignment can crash without this check
	if server != nil {
		server.Status = status
		sendConfigToServer()
	}
}

const (
	// REPLICAT_STATUS_INITIAL_SCAN - The server is scanning its local storage
	REPLICAT_STATUS_INITIAL_SCAN = "Initial Scan"
	// REPLICAT_STATUS_JOINING_CLUSTER - The server has started to join the cluster and get up to date
	REPLICAT_STATUS_JOINING_CLUSTER = "Joining Cluster"
	// REPLICAT_STATUS_ONLINE - The server is up to date and part of the cluster
	REPLICAT_STATUS_ONLINE = "Online"
)

var serverMap = make(map[string]*ReplicatServer)
var serverMapLock sync.RWMutex

var lastConfigPing = time.Now()

// BootstrapAndServe - Start the server
func BootstrapAndServe(address string) {
	//trackerTestDual()
	//trackerTestSmallFileInSubfolder()
	//trackerTestEmptyDirectoryMovesInOutAround()
	//trackerTestFileChangeTrackerAddFolders()
	//trackerTestSmallFileCreationAndRename()
	//trackerTestSmallFileCreationAndUpdate()
	//trackerTestSmallFileMovesInOutAround()
	//trackerTestDirectoryCreation()
	//trackerTestNestedDirectoryCreation()
	//trackerTestDirectoryStorage()
	//trackerTestFileChangeTrackerAutoCreateFolderAndCleanup()
	//trackerTestNestedFastDirectoryCreation()

	// testing code to enable debugger use
	http.Handle("/event/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(eventHandler)))
	http.Handle("/tree/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(folderTreeHandler)))
	http.Handle("/config/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(configHandler)))
	http.Handle("/upload/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(uploadHandler)))

	lsnr, err := net.Listen("tcp4", address)
	if err != nil {
		panic(fmt.Sprintf("Error listening: %v\nAddress: %s\n", err, address))
	}
	fmt.Println("Listening on:", lsnr.Addr().String())

	logOnlyHandler := LogOnlyChangeHandler{}
	tracker := FilesystemTracker{}
	fmt.Printf("Looking up settings for node: %s\n", globalSettings.Name)

	directory := globalSettings.Directory

	fmt.Printf("GlobalSettings directory retrieved for this node: %s\n", directory)
	server := &ReplicatServer{Name: globalSettings.Name, ClusterKey: globalSettings.ClusterKey, Address: lsnr.Addr().String(), storage: &tracker, Status: REPLICAT_STATUS_INITIAL_SCAN}
	serverMap[globalSettings.Name] = server
	tracker.init(directory, server)

	go func(tracker StorageTracker) {
		for true {
			tracker.GetStatistics()
			time.Sleep(30 * time.Second)
		}
	}(&tracker)

	var c ChangeHandler
	c = &logOnlyHandler
	tracker.watchDirectory(&c)

	go func(listener net.Listener) {
		err = http.Serve(listener, nil)
		if err != nil {
			panic(err)
		}
	}(lsnr)

	fmt.Println("Starting config update processor")
	go configUpdateProcessor(configUpdateChannel)

	if globalSettings.ManagerAddress != "" {
		fmt.Printf("about to send config to server (%s)\nOur address is: (%s)\n", globalSettings.ManagerAddress, lsnr.Addr())
	}

	// we need something to keep us running.
	keepConfigCurrent()
}

const (
	managerOverdueSeconds = 30
	managerCheckSleepTime = 45
)

func keepConfigCurrent() {
	for {
		if time.Since(lastConfigPing) > managerOverdueSeconds*time.Second {
			log.Printf("Manager Contact Overdue, attempting to contact: %s\n", globalSettings.ManagerAddress)
			sendConfigToServer()
		} else {
			fmt.Println("No Update Required")
		}
		time.Sleep(time.Duration(rand.Intn(10)-5+managerCheckSleepTime) * time.Second)
	}
}

func sendConfigToServer() {
	// This field will be empty during testing. We have to abort during testing since the manager is not reachable.
	if globalSettings.ManagerAddress == "" {
		return
	}

	url := "http://" + globalSettings.ManagerAddress + "/config/"
	log.Printf("sendConfigToServer: Manager location: %s\n", url)

	server := serverMap[globalSettings.Name]
	jsonStr, _ := json.Marshal(server)
	jsonStr2, _ := json.Marshal(server.storage.GetStatistics())

	// marshal the stats as well
	//statsJSON := json.NewEncoder()

	byteArraysToMarshal := [][]byte{jsonStr, jsonStr2}
	byteData := bytes.Join(byteArraysToMarshal, []byte{})
	log.Printf("jasonstr: %s\n", string(byteData))
	jsonData := bytes.NewBuffer(byteData)

	req, err := http.NewRequest("POST", url, jsonData)
	req.Header.Set("Content-Type", "application/json")

	data := []byte(globalSettings.ManagerCredentials)
	authHash := base64.StdEncoding.EncodeToString(data)
	req.Header.Add("Authorization", "Basic "+authHash)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Unable to reach server. Data could be lost: %s\n", err)
	}

	newServerMap, err := extractServerMapFromConfig(resp.Body)
	if err != nil {
		log.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap

}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		file, handler, err := r.FormFile("uploadfile")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer file.Close()
		fmt.Fprint(w, handler.Header)

		hash := []byte(r.Form.Get("HASH"))

		storage := serverMap[globalSettings.Name].storage
		local, _ := storage.getEntryJSON(handler.Filename)

		if !bytes.Equal(hash, local.Hash) {
			fullPath := globalSettings.Directory + "/" + handler.Filename
			f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0666)

			if err != nil {
				fmt.Println(err)
				return
			}

			bytesWritten, err := io.Copy(f, file)
			if err != nil {
				log.Printf("Error copying file: %s, error(%#v)\n", handler.Filename, err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("500 - Error copying file"))
				f.Close()
				return
			}
			fmt.Printf("Wrote out (%s) bytes (%d)\n", handler.Filename, bytesWritten)
			f.Close()

			// Get the old entry
			entryString := r.Form.Get("entryJSON")
			if entryString != "" {
				var entry EntryJSON
				err := json.Unmarshal([]byte(entryString), &entry)
				if err != nil {
					log.Fatalf("Error copying file (Entry handling): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}

				err = os.Chtimes(fullPath, time.Now(), entry.ModTime)
				if err != nil {
					log.Fatalf("Error copying file (Changing times): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}
			}

		}
	}
}

var configUpdateChannel = make(chan *map[string]*ReplicatServer, 100)

func configHandler(_ http.ResponseWriter, r *http.Request) {
	newServerMap, err := extractServerMapFromConfig(r.Body)
	if err != nil {
		fmt.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap
}

func extractServerMapFromConfig(sourceReader io.Reader) (newServerMap *map[string]*ReplicatServer, err error) {
	decoder := json.NewDecoder(sourceReader)
	err = decoder.Decode(&newServerMap)
	return
}

func configUpdateProcessor(c chan *map[string]*ReplicatServer) {
	for {
		newServerMap := <-c
		serverMapLock.Lock()

		lastConfigPing = time.Now()
		sendData := false

		// find any nodes that have been deleted and update ones that have changed
		for name, serverData := range serverMap {
			newServerData, exists := (*newServerMap)[name]
			if !exists {
				fmt.Printf("No longer found config for: %s deleting\n", name)
				delete(serverMap, name)
				continue
			}

			if serverData.Address != newServerData.Address || serverData.Name != newServerData.Name || serverData.ClusterKey != newServerData.ClusterKey || serverData.Status != serverData.Status {
				fmt.Printf("Server data is changed. Replacing.\nold: %v\nnew: %v\n", &serverData, &newServerData)
				if serverData.Status != REPLICAT_STATUS_JOINING_CLUSTER && newServerData.Status == REPLICAT_STATUS_JOINING_CLUSTER {
					fmt.Printf("Decided to send data to: %s\n", serverData.Name)
					sendData = true
				}
				serverMap[name] = newServerData
				fmt.Println("Server data replaced with new server data")
			}
		}

		// find any new nodes
		for name, newServerData := range *newServerMap {
			_, exists := serverMap[name]
			if !exists {
				fmt.Printf("New server configuration for %s: %v\n", name, newServerData)

				// If this server map is for ourselves, build a list of folder if needed and notify others
				if name == globalSettings.Name {
					listOfFileInfo, err := scanDirectoryContents()
					if err != nil {
						log.Fatal(err)
					}
					newServerData.CurrentState = listOfFileInfo
					// Tell all of our friends that we exist and our current state for them to compare against.
					go func(tree DirTreeMap) {
						sendFolderTree(tree)
					}(listOfFileInfo)
				} else {
					fmt.Printf("New Node Decided to send data to: %s\n", name)
					sendData = true
				}

				fmt.Printf("New server configuration provided. Copying: %s\n", name)
				serverMap[name] = newServerData
			}
		}

		if sendData {
			server := serverMap[globalSettings.Name]
			fmt.Println("about to send existing files")
			server.storage.SendCatalog()
			fmt.Println("done sending existing files")
		}

		serverMapLock.Unlock()
	}
}
<commit_msg>abore parsing response from config post on server if it is empty.<commit_after>// Package replicat is a server for n way synchronization of content (Replication for the cloud).
// Copyright 2016 Jacob Taylor jacob@replic.at       More Info: http://replic.at
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/goji/httpauth"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

// ReplicatServer is a structure that contains the definition of the servers in a cluster. Each node has a name and this
// node (as determined by globalSettings.name at the moment) also has a StorageTracker interface.
type ReplicatServer struct {
	ClusterKey    string
	Name          string
	Address       string
	Status        string
	CurrentState  DirTreeMap
	PreviousState DirTreeMap
	Lock          sync.Mutex
	storage       StorageTracker
}

// GetStatus - get the current status of the server
func (server *ReplicatServer) GetStatus() string {
	return server.Status
}

// SetStatus - set the current status of the server
func (server *ReplicatServer) SetStatus(status string) {
	// adding an inline check to make sure the server is valid
	// if the server is being shut down or at the end of a unit test)
	// the assignment can crash without this check
	if server != nil {
		server.Status = status
		sendConfigToServer()
	}
}

const (
	// REPLICAT_STATUS_INITIAL_SCAN - The server is scanning its local storage
	REPLICAT_STATUS_INITIAL_SCAN = "Initial Scan"
	// REPLICAT_STATUS_JOINING_CLUSTER - The server has started to join the cluster and get up to date
	REPLICAT_STATUS_JOINING_CLUSTER = "Joining Cluster"
	// REPLICAT_STATUS_ONLINE - The server is up to date and part of the cluster
	REPLICAT_STATUS_ONLINE = "Online"
)

var serverMap = make(map[string]*ReplicatServer)
var serverMapLock sync.RWMutex

var lastConfigPing = time.Now()

// BootstrapAndServe - Start the server
func BootstrapAndServe(address string) {
	//trackerTestDual()
	//trackerTestSmallFileInSubfolder()
	//trackerTestEmptyDirectoryMovesInOutAround()
	//trackerTestFileChangeTrackerAddFolders()
	//trackerTestSmallFileCreationAndRename()
	//trackerTestSmallFileCreationAndUpdate()
	//trackerTestSmallFileMovesInOutAround()
	//trackerTestDirectoryCreation()
	//trackerTestNestedDirectoryCreation()
	//trackerTestDirectoryStorage()
	//trackerTestFileChangeTrackerAutoCreateFolderAndCleanup()
	//trackerTestNestedFastDirectoryCreation()

	// testing code to enable debugger use
	http.Handle("/event/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(eventHandler)))
	http.Handle("/tree/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(folderTreeHandler)))
	http.Handle("/config/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(configHandler)))
	http.Handle("/upload/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(uploadHandler)))

	lsnr, err := net.Listen("tcp4", address)
	if err != nil {
		panic(fmt.Sprintf("Error listening: %v\nAddress: %s\n", err, address))
	}
	fmt.Println("Listening on:", lsnr.Addr().String())

	logOnlyHandler := LogOnlyChangeHandler{}
	tracker := FilesystemTracker{}
	fmt.Printf("Looking up settings for node: %s\n", globalSettings.Name)

	directory := globalSettings.Directory

	fmt.Printf("GlobalSettings directory retrieved for this node: %s\n", directory)
	server := &ReplicatServer{Name: globalSettings.Name, ClusterKey: globalSettings.ClusterKey, Address: lsnr.Addr().String(), storage: &tracker, Status: REPLICAT_STATUS_INITIAL_SCAN}
	serverMap[globalSettings.Name] = server
	tracker.init(directory, server)

	go func(tracker StorageTracker) {
		for true {
			tracker.GetStatistics()
			time.Sleep(30 * time.Second)
		}
	}(&tracker)

	var c ChangeHandler
	c = &logOnlyHandler
	tracker.watchDirectory(&c)

	go func(listener net.Listener) {
		err = http.Serve(listener, nil)
		if err != nil {
			panic(err)
		}
	}(lsnr)

	fmt.Println("Starting config update processor")
	go configUpdateProcessor(configUpdateChannel)

	if globalSettings.ManagerAddress != "" {
		fmt.Printf("about to send config to server (%s)\nOur address is: (%s)\n", globalSettings.ManagerAddress, lsnr.Addr())
	}

	// we need something to keep us running.
	keepConfigCurrent()
}

const (
	managerOverdueSeconds = 30
	managerCheckSleepTime = 45
)

func keepConfigCurrent() {
	for {
		if time.Since(lastConfigPing) > managerOverdueSeconds*time.Second {
			log.Printf("Manager Contact Overdue, attempting to contact: %s\n", globalSettings.ManagerAddress)
			sendConfigToServer()
		} else {
			fmt.Println("No Update Required")
		}
		time.Sleep(time.Duration(rand.Intn(10)-5+managerCheckSleepTime) * time.Second)
	}
}

func sendConfigToServer() {
	// This field will be empty during testing. We have to abort during testing since the manager is not reachable.
	if globalSettings.ManagerAddress == "" {
		return
	}

	url := "http://" + globalSettings.ManagerAddress + "/config/"
	log.Printf("sendConfigToServer: Manager location: %s\n", url)

	server := serverMap[globalSettings.Name]
	jsonStr, _ := json.Marshal(server)
	jsonStr2, _ := json.Marshal(server.storage.GetStatistics())

	// marshal the stats as well
	//statsJSON := json.NewEncoder()

	byteArraysToMarshal := [][]byte{jsonStr, jsonStr2}
	byteData := bytes.Join(byteArraysToMarshal, []byte{})
	log.Printf("jasonstr: %s\n", string(byteData))
	jsonData := bytes.NewBuffer(byteData)

	req, err := http.NewRequest("POST", url, jsonData)
	req.Header.Set("Content-Type", "application/json")

	data := []byte(globalSettings.ManagerCredentials)
	authHash := base64.StdEncoding.EncodeToString(data)
	req.Header.Add("Authorization", "Basic "+authHash)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Unable to reach server. Data could be lost: %s\n", err)
		return
	}

	newServerMap, err := extractServerMapFromConfig(resp.Body)
	if err != nil {
		log.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap

}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		file, handler, err := r.FormFile("uploadfile")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer file.Close()
		fmt.Fprint(w, handler.Header)

		hash := []byte(r.Form.Get("HASH"))

		storage := serverMap[globalSettings.Name].storage
		local, _ := storage.getEntryJSON(handler.Filename)

		if !bytes.Equal(hash, local.Hash) {
			fullPath := globalSettings.Directory + "/" + handler.Filename
			f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0666)

			if err != nil {
				fmt.Println(err)
				return
			}

			bytesWritten, err := io.Copy(f, file)
			if err != nil {
				log.Printf("Error copying file: %s, error(%#v)\n", handler.Filename, err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("500 - Error copying file"))
				f.Close()
				return
			}
			fmt.Printf("Wrote out (%s) bytes (%d)\n", handler.Filename, bytesWritten)
			f.Close()

			// Get the old entry
			entryString := r.Form.Get("entryJSON")
			if entryString != "" {
				var entry EntryJSON
				err := json.Unmarshal([]byte(entryString), &entry)
				if err != nil {
					log.Fatalf("Error copying file (Entry handling): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}

				err = os.Chtimes(fullPath, time.Now(), entry.ModTime)
				if err != nil {
					log.Fatalf("Error copying file (Changing times): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}
			}

		}
	}
}

var configUpdateChannel = make(chan *map[string]*ReplicatServer, 100)

func configHandler(_ http.ResponseWriter, r *http.Request) {
	newServerMap, err := extractServerMapFromConfig(r.Body)
	if err != nil {
		fmt.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap
}

func extractServerMapFromConfig(sourceReader io.Reader) (newServerMap *map[string]*ReplicatServer, err error) {
	decoder := json.NewDecoder(sourceReader)
	err = decoder.Decode(&newServerMap)
	return
}

func configUpdateProcessor(c chan *map[string]*ReplicatServer) {
	for {
		newServerMap := <-c
		serverMapLock.Lock()

		lastConfigPing = time.Now()
		sendData := false

		// find any nodes that have been deleted and update ones that have changed
		for name, serverData := range serverMap {
			newServerData, exists := (*newServerMap)[name]
			if !exists {
				fmt.Printf("No longer found config for: %s deleting\n", name)
				delete(serverMap, name)
				continue
			}

			if serverData.Address != newServerData.Address || serverData.Name != newServerData.Name || serverData.ClusterKey != newServerData.ClusterKey || serverData.Status != serverData.Status {
				fmt.Printf("Server data is changed. Replacing.\nold: %v\nnew: %v\n", &serverData, &newServerData)
				if serverData.Status != REPLICAT_STATUS_JOINING_CLUSTER && newServerData.Status == REPLICAT_STATUS_JOINING_CLUSTER {
					fmt.Printf("Decided to send data to: %s\n", serverData.Name)
					sendData = true
				}
				serverMap[name] = newServerData
				fmt.Println("Server data replaced with new server data")
			}
		}

		// find any new nodes
		for name, newServerData := range *newServerMap {
			_, exists := serverMap[name]
			if !exists {
				fmt.Printf("New server configuration for %s: %v\n", name, newServerData)

				// If this server map is for ourselves, build a list of folder if needed and notify others
				if name == globalSettings.Name {
					listOfFileInfo, err := scanDirectoryContents()
					if err != nil {
						log.Fatal(err)
					}
					newServerData.CurrentState = listOfFileInfo
					// Tell all of our friends that we exist and our current state for them to compare against.
					go func(tree DirTreeMap) {
						sendFolderTree(tree)
					}(listOfFileInfo)
				} else {
					fmt.Printf("New Node Decided to send data to: %s\n", name)
					sendData = true
				}

				fmt.Printf("New server configuration provided. Copying: %s\n", name)
				serverMap[name] = newServerData
			}
		}

		if sendData {
			server := serverMap[globalSettings.Name]
			fmt.Println("about to send existing files")
			server.storage.SendCatalog()
			fmt.Println("done sending existing files")
		}

		serverMapLock.Unlock()
	}
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 Hualiang Wu <wizawu@gmail.com>
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to
 *  deal in the Software without restriction, including without limitation the
 *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 *  sell copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 *  IN THE SOFTWARE.
 */

package meepodb

import (
    "os"
    "time"
    "strconv"
    . "syscall"
)

type COLA struct {
    MetaFd    int
    Bitmap    uint64
    blocks    *Blocks
    /* 57 because of log() */
    extents   [57]*Extent
    LoadTime  int64
    Path      string
}

func (cola *COLA) Get(key []byte) []byte {
    var value []byte
    value = cola.blocks.Get(key)
    if value != nil {
        return value
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap > 0 {
            j := cola.extents[log(i)].Find(key)
            if j >= 0 {
                _, value = cola.extents[log(i)].Record(uint64(j))
                return value
            }
        }
    }
    return nil
}

func (cola *COLA) Set(key, value []byte) bool {
    return cola.blocks.Set(key, value)
}

func (cola *COLA) PushDown() bool {
    ok := BlocksToExtent(cola.Path + "/ext_64.1", cola.blocks.records)
    if !ok {
        return false
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap == 0 {
            oldpath := cola.Path + "/ext_" + strconv.Itoa(i) + ".1"
            newpath := cola.Path + "/ext_" + strconv.Itoa(i)
            err := Rename(oldpath, newpath)
            if err != nil {
                return false
            }
            cola.Bitmap |= uint64(i)
            cola.extents[log(i)], ok = OpenExtent(newpath)
            if !ok {
                return false
            }
            break
        }
        oldpath := cola.Path + "/ext_" + strconv.Itoa(i) + ".1"
        newpath := cola.Path + "/ext_" + strconv.Itoa(i << 1) + ".1"
        ext, ok := OpenExtent(oldpath)
        if !ok {
            return false
        }
        ok = MergeExtents(newpath, cola.extents[log(i)], ext)
        if !ok {
            return false
        }
        cola.extents[log(i)].Free()
        ext.Free()
        cola.Bitmap &= ^uint64(i)
    }
    n, err := Write(cola.MetaFd, uint64ToBytes(cola.Bitmap))
    if err != nil || n != 8 {
        return false
    }
    cola.blocks.Close()
    cola.blocks, ok = NewBlocks(cola.Path + "/blx")
    return ok
}

func NewCOLA(path string) (*COLA, bool) {
    err := Mkdir(path, S_IRALL | S_IWALL | S_IXALL)
    if err != nil {
        return nil, false
    }
    var cola = new(COLA)
    var mode int = O_WRONLY | O_CREAT
    cola.MetaFd, err = Open(path + "/meta", mode, S_IRALL | S_IWALL)
    if err != nil {
        return nil, false
    }
    n, err := Write(cola.MetaFd, uint64ToBytes(cola.Bitmap))
    if err != nil || n != 8 {
        return nil, false
    }
    var ok bool
    cola.blocks, ok = NewBlocks(path + "/blx")
    if !ok {
        return nil, false
    }
    cola.LoadTime = time.Now().Unix()
    cola.Path = path
    return cola, true
}

func OpenCOLA(path string) (*COLA, bool) {
    var cola = new(COLA)
    var err error
    cola.MetaFd, err = Open(path + "/meta", O_RDWR, S_IRALL | S_IWALL)
    if err != nil {
        return nil, false
    }
    Seek(cola.MetaFd, -8, os.SEEK_END)
    var buffer = make([]byte, 8)
    n, err := Read(cola.MetaFd, buffer)
    if err != nil || n != 8 {
        return nil, false
    }
    cola.Bitmap = bytesToUint64(buffer)
    var ok bool
    cola.blocks, ok = LoadBlocks(path + "/blx")
    if !ok {
        return nil, false
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap > 0 {
            extpath := path + "/ext_" + strconv.Itoa(i)
            cola.extents[log(i)], ok = OpenExtent(extpath)
            if !ok {
                return nil, false
            }
        }
    }
    cola.LoadTime = time.Now().Unix()
    cola.Path = path
    // cola.PushDown
    return cola, true
}

func log(i int) int {
    var result int = 0
    for i >>= 7; i > 0; i >>= 1 {
        result++
    }
    return result
}
<commit_msg>PushDown added<commit_after>/*
 *  Copyright (c) 2013 Hualiang Wu <wizawu@gmail.com>
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to
 *  deal in the Software without restriction, including without limitation the
 *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 *  sell copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 *  IN THE SOFTWARE.
 */

package meepodb

import (
    "os"
    "time"
    "strconv"
    . "syscall"
)

type COLA struct {
    MetaFd    int
    Bitmap    uint64
    blocks    *Blocks
    /* 57 because of log() */
    extents   [57]*Extent
    LoadTime  int64
    Path      string
}

func (cola *COLA) Get(key []byte) []byte {
    var value []byte
    value = cola.blocks.Get(key)
    if value != nil {
        return value
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap > 0 {
            j := cola.extents[log(i)].Find(key)
            if j >= 0 {
                _, value = cola.extents[log(i)].Record(uint64(j))
                return value
            }
        }
    }
    return nil
}

func (cola *COLA) Set(key, value []byte) bool {
    var ok bool = cola.blocks.Set(key, value)
    if !ok {
        return false
    }
    if cola.blocks.bitmap == ^uint64(0) {
        return cola.PushDown()
    }
    return true
}

func (cola *COLA) PushDown() bool {
    ok := BlocksToExtent(cola.Path + "/ext_64.1", cola.blocks.records)
    if !ok {
        return false
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap == 0 {
            oldpath := cola.Path + "/ext_" + strconv.Itoa(i) + ".1"
            newpath := cola.Path + "/ext_" + strconv.Itoa(i)
            err := Rename(oldpath, newpath)
            if err != nil {
                return false
            }
            cola.Bitmap |= uint64(i)
            cola.extents[log(i)], ok = OpenExtent(newpath)
            if !ok {
                return false
            }
            break
        }
        oldpath := cola.Path + "/ext_" + strconv.Itoa(i) + ".1"
        newpath := cola.Path + "/ext_" + strconv.Itoa(i << 1) + ".1"
        ext, ok := OpenExtent(oldpath)
        if !ok {
            return false
        }
        ok = MergeExtents(newpath, cola.extents[log(i)], ext)
        if !ok {
            return false
        }
        cola.extents[log(i)].Free()
        ext.Free()
        cola.Bitmap &= ^uint64(i)
    }
    n, err := Write(cola.MetaFd, uint64ToBytes(cola.Bitmap))
    if err != nil || n != 8 {
        return false
    }
    cola.blocks.Close()
    cola.blocks, ok = NewBlocks(cola.Path + "/blx")
    return ok
}

func NewCOLA(path string) (*COLA, bool) {
    err := Mkdir(path, S_IRALL | S_IWALL | S_IXALL)
    if err != nil {
        return nil, false
    }
    var cola = new(COLA)
    var mode int = O_WRONLY | O_CREAT
    cola.MetaFd, err = Open(path + "/meta", mode, S_IRALL | S_IWALL)
    if err != nil {
        return nil, false
    }
    n, err := Write(cola.MetaFd, uint64ToBytes(cola.Bitmap))
    if err != nil || n != 8 {
        return nil, false
    }
    var ok bool
    cola.blocks, ok = NewBlocks(path + "/blx")
    if !ok {
        return nil, false
    }
    cola.LoadTime = time.Now().Unix()
    cola.Path = path
    return cola, true
}

func OpenCOLA(path string) (*COLA, bool) {
    var cola = new(COLA)
    var err error
    cola.MetaFd, err = Open(path + "/meta", O_RDWR, S_IRALL | S_IWALL)
    if err != nil {
        return nil, false
    }
    Seek(cola.MetaFd, -8, os.SEEK_END)
    var buffer = make([]byte, 8)
    n, err := Read(cola.MetaFd, buffer)
    if err != nil || n != 8 {
        return nil, false
    }
    cola.Bitmap = bytesToUint64(buffer)
    var ok bool
    cola.blocks, ok = LoadBlocks(path + "/blx")
    if !ok {
        return nil, false
    }
    for i := 64; i > 0; i <<= 1 {
        if uint64(i) & cola.Bitmap > 0 {
            extpath := path + "/ext_" + strconv.Itoa(i)
            cola.extents[log(i)], ok = OpenExtent(extpath)
            if !ok {
                return nil, false
            }
        }
    }
    cola.LoadTime = time.Now().Unix()
    cola.Path = path
    if cola.blocks.bitmap == ^uint64(0) {
        ok = cola.PushDown()
    }
    return cola, ok
}

func log(i int) int {
    var result int = 0
    for i >>= 7; i > 0; i >>= 1 {
        result++
    }
    return result
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"text/template"
	"time"

	"github.com/couchbaselabs/cbfs/config"
	"sync"
)

type StorageNode struct {
	Addr      string
	AddrRaw   string    `json:"addr_raw"`
	Started   time.Time `json:"starttime"`
	HBTime    time.Time `json:"hbtime"`
	BindAddr  string
	FrameBind string
	HBAgeStr  string `json:"hbage_str"`
	Used      int64
	Free      int64
	Size      int64
	UptimeStr string `json:"uptime_str"`
}

type Tasks map[string]map[string]struct {
	State string
	TS    time.Time
}

type Nodes map[string]StorageNode

var infoFlags = flag.NewFlagSet("info", flag.ExitOnError)
var infoTemplate = infoFlags.String("t", "", "Display template")
var infoTemplateFile = infoFlags.String("T", "", "Display template filename")

const defaultInfoTemplate = `nodes:
{{ range $name, $nodeinfo := .Nodes }}  {{$name}} up {{$nodeinfo.HBAgeStr}}
{{ end }}
{{if .Tasks}}tasks:{{end}}{{ range $node, $tasks := .Tasks }}
  {{$node}}
  {{ range $task, $info := $tasks }}    {{$task}} - {{$info.State}} - {{$info.TS}}
  {{end}}{{end}}
config:
{{ range $k, $v := .Conf.ToMap}}  {{$k}}: {{$v}}
{{end}}
`

func getJsonData(u string, into interface{}) error {
	res, err := http.Get(u)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP Error: %v", res.Status)
	}

	d := json.NewDecoder(res.Body)
	return d.Decode(into)
}

func infoCommand(base string, args []string) {
	infoFlags.Parse(args)

	tmplstr := *infoTemplate
	if tmplstr == "" {
		if *infoTemplateFile == "" {
			tmplstr = defaultInfoTemplate
		} else {
			td, err := ioutil.ReadFile(*infoTemplateFile)
			if err != nil {
				log.Fatalf("Error reading template file: %v", err)
			}
			tmplstr = string(td)
		}
	}

	tmpl, err := template.New("").Parse(tmplstr)
	if err != nil {
		log.Fatalf("Error parsing template: %v", err)
	}

	u, err := url.Parse(base)
	if err != nil {
		log.Fatalf("Error parsing URL: %v", err)
	}

	result := struct {
		Nodes Nodes
		Tasks Tasks
		Conf  cbfsconfig.CBFSConfig
	}{}

	todo := map[string]interface{}{
		"/.cbfs/nodes/":  &result.Nodes,
		"/.cbfs/tasks/":  &result.Tasks,
		"/.cbfs/config/": &result.Conf,
	}

	wg := sync.WaitGroup{}

	for k, v := range todo {
		u.Path = k
		wg.Add(1)
		go func(s string, to interface{}) {
			defer wg.Done()
			err = getJsonData(s, to)
			if err != nil {
				log.Fatalf("Error getting node info: %v", err)
			}
		}(u.String(), v)
	}

	wg.Wait()

	err = tmpl.Execute(os.Stdout, result)
	if err != nil {
		log.Fatalf("Error executing template: %v", err)
	}
}
<commit_msg>Added backups to info.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"text/template"
	"time"

	"github.com/couchbaselabs/cbfs/config"
	"sync"
)

type StorageNode struct {
	Addr      string
	AddrRaw   string    `json:"addr_raw"`
	Started   time.Time `json:"starttime"`
	HBTime    time.Time `json:"hbtime"`
	BindAddr  string
	FrameBind string
	HBAgeStr  string `json:"hbage_str"`
	Used      int64
	Free      int64
	Size      int64
	UptimeStr string `json:"uptime_str"`
}

type Tasks map[string]map[string]struct {
	State string
	TS    time.Time
}

type Backup struct {
	Filename string
	OID      string
	When     time.Time
	Conf     cbfsconfig.CBFSConfig
}

type Nodes map[string]StorageNode

var infoFlags = flag.NewFlagSet("info", flag.ExitOnError)
var infoTemplate = infoFlags.String("t", "", "Display template")
var infoTemplateFile = infoFlags.String("T", "", "Display template filename")

const defaultInfoTemplate = `nodes:
{{ range $name, $nodeinfo := .Nodes }}  {{$name}} up {{$nodeinfo.HBAgeStr}}
{{ end }}
{{if .Tasks}}tasks:{{end}}{{ range $node, $tasks := .Tasks }}
  {{$node}}
  {{ range $task, $info := $tasks }}    {{$task}} - {{$info.State}} - {{$info.TS}}
  {{end}}{{end}}
backups:
  Found {{len .Backups.Previous }} backups.
  Current:  {{.Backups.Latest.Filename}} ({{.Backups.Latest.OID}})
            as of {{.Backups.Latest.When}}

config:
{{ range $k, $v := .Conf.ToMap}}  {{$k}}: {{$v}}
{{end}}
`

func getJsonData(u string, into interface{}) error {
	res, err := http.Get(u)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP Error: %v", res.Status)
	}

	d := json.NewDecoder(res.Body)
	return d.Decode(into)
}

func infoCommand(base string, args []string) {
	infoFlags.Parse(args)

	tmplstr := *infoTemplate
	if tmplstr == "" {
		if *infoTemplateFile == "" {
			tmplstr = defaultInfoTemplate
		} else {
			td, err := ioutil.ReadFile(*infoTemplateFile)
			if err != nil {
				log.Fatalf("Error reading template file: %v", err)
			}
			tmplstr = string(td)
		}
	}

	tmpl, err := template.New("").Parse(tmplstr)
	if err != nil {
		log.Fatalf("Error parsing template: %v", err)
	}

	u, err := url.Parse(base)
	if err != nil {
		log.Fatalf("Error parsing URL: %v", err)
	}

	result := struct {
		Nodes   Nodes
		Tasks   Tasks
		Backups struct {
			Previous []Backup `json:"backups"`
			Latest   Backup
		}
		Conf cbfsconfig.CBFSConfig
	}{}

	todo := map[string]interface{}{
		"/.cbfs/nodes/":  &result.Nodes,
		"/.cbfs/tasks/":  &result.Tasks,
		"/.cbfs/backup/": &result.Backups,
		"/.cbfs/config/": &result.Conf,
	}

	wg := sync.WaitGroup{}

	for k, v := range todo {
		u.Path = k
		wg.Add(1)
		go func(s string, to interface{}) {
			defer wg.Done()
			err = getJsonData(s, to)
			if err != nil {
				log.Fatalf("Error getting node info: %v", err)
			}
		}(u.String(), v)
	}

	wg.Wait()

	err = tmpl.Execute(os.Stdout, result)
	if err != nil {
		log.Fatalf("Error executing template: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/google/go-github/github"
)

type Scraper struct {
	Client *github.Client
	Store  *Store
}

func (s *Scraper) Scrape(search *Search) error {
	for !search.Finished {
		opt := &github.SearchOptions{
			Sort:  "stars",
			Order: "asc",
			ListOptions: github.ListOptions{
				Page: search.CompletedPages + 1,
			},
		}

		repos, res, err := s.Client.Search.Repositories(search.Query, opt)
		if err != nil {
			return err
		}

		for _, r := range repos.Repositories {
			fmt.Println(*r.Name)
		}

		// Update
		search.CompletedPages++
		search.Finished = (res.NextPage == 0)
		q := s.Store.DB.Save(search)
		if q.Error != nil {
			return q.Error
		}
	}

	return nil
}

// FindEmail looks for the given user's email address by looking for commit
// events in their public feed.
func FindEmail(c *github.Client, user string) (string, error) {
	u, _, err := c.Users.Get(user)
	if err != nil {
		return "", err
	}
	if u.Email != nil {
		fmt.Println("email from user fetch:", *u.Email)
	}

	events, _, err := c.Activity.ListEventsPerformedByUser(user, true, nil)
	if err != nil {
		return "", err
	}

	for _, ev := range events {
		if *ev.Type != "PushEvent" {
			continue
		}
		push := ev.Payload().(*github.PushEvent)
		for _, commit := range push.Commits {
			author := commit.Author
			if author.Email != nil {
				return *author.Email, nil
			}
		}
	}

	return "", nil
}
<commit_msg>ProspectFromRepository<commit_after>package main

import (
	"fmt"

	"github.com/google/go-github/github"
)

type Scraper struct {
	Client *github.Client
	Store  *Store
}

func (s *Scraper) ProspectFromRepository(repo github.Repository) (*Prospect, error) {
	user := *repo.Owner.Login

	// Initialize Prospect object
	p := &Prospect{
		User: user,
		Repo: *repo.FullName,
	}

	// Try to fetch the owner's information directly
	u, _, err := s.Client.Users.Get(user)
	if err != nil {
		return nil, err
	}
	if u.Email != nil {
		p.Email = *u.Email
		if u.Name != nil {
			p.Name = *u.Name
		}
		if u.Location != nil {
			p.Location = *u.Location
		}
		return p, nil
	}

	// Otherwise try to fetch it from the activity list
	events, _, err := s.Client.Activity.ListEventsPerformedByUser(user, true, nil)
	if err != nil {
		return nil, err
	}

	for _, ev := range events {
		if *ev.Type != "PushEvent" {
			continue
		}
		push := ev.Payload().(*github.PushEvent)
		for _, commit := range push.Commits {
			author := commit.Author
			if author.Email != nil {
				p.Email = *author.Email
				if author.Name != nil {
					p.Name = *author.Name
				}
				return p, nil
			}
		}
	}

	return nil, nil
}

func (s *Scraper) Scrape(search *Search) error {
	for !search.Finished {
		// Fetch page of results
		opt := &github.SearchOptions{
			Sort:  "stars",
			Order: "asc",
			ListOptions: github.ListOptions{
				Page: search.CompletedPages + 1,
			},
		}

		repos, res, err := s.Client.Search.Repositories(search.Query, opt)
		if err != nil {
			return err
		}

		// Iterate through them and find information about the owner, if we can.
		for _, r := range repos.Repositories {
			fmt.Println(*r.Name)
			p, err := s.ProspectFromRepository(r)
			if err != nil {
				return err
			}
			if p != nil {
				s.Store.DB.Create(p)
			}
		}

		// Update
		search.CompletedPages++
		search.Finished = (res.NextPage == 0)
		q := s.Store.DB.Save(search)
		if q.Error != nil {
			return q.Error
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"

	"github.com/valyala/fasthttp"
)

var (
	addr = flag.String("addr", ":8080", "TCP address to listen to")
)

var body = []byte("OK")

func main() {
	flag.Parse()

	if err := fasthttp.ListenAndServe(*addr, requestHandler); err != nil {
		log.Fatalf("Error in ListenAndServe: %s", err)
	}
}

func requestHandler(ctx *fasthttp.RequestCtx) {
	_, err := ctx.Write(body)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Use reuseport listener in void_server.<commit_after>package main

import (
	"flag"
	"log"

	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/reuseport"
)

var (
	addr = flag.String("addr", ":8080", "TCP address to listen to")
)

var body = []byte("OK")

func main() {
	flag.Parse()

	ln, err := reuseport.Listen("tcp4", *addr)
	if err != nil {
		log.Fatal(err)
	}

	if err := fasthttp.Serve(ln, requestHandler); err != nil {
		log.Fatalf("Error in ListenAndServe: %s", err)
	}
}

func requestHandler(ctx *fasthttp.RequestCtx) {
	_, err := ctx.Write(body)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes 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/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 volumeservice

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
	volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
	"github.com/kubernetes-incubator/external-storage/lib/controller"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/uuid"
)

const initiatorName = "iqn.1994-05.com.redhat:a13fc3d1cc22"

// VolumeConnectionDetails represent the type-specific values for a given
// DriverVolumeType.  Depending on the volume type, fields may be absent or
// have a semantically different meaning.
type VolumeConnectionDetails struct {
	VolumeID string `json:"volume_id"`
	Name     string `json:"name"`

	AuthMethod   string `json:"auth_method"`
	AuthUsername string `json:"auth_username"`
	AuthPassword string `json:"auth_password"`
	SecretType   string `json:"secret_type"`

	TargetPortal string `json:"target_portal"`
	TargetIqn    string `json:"target_iqn"`
	TargetLun    int32  `json:"target_lun"`

	ClusterName string   `json:"cluster_name"`
	Hosts       []string `json:"hosts"`
	Ports       []string `json:"ports"`
}

// VolumeConnection represents the connection information returned from the
// cinder os-initialize_connection API call
type VolumeConnection struct {
	DriverVolumeType string                  `json:"driver_volume_type"`
	Data             VolumeConnectionDetails `json:"data"`
}

type rcvVolumeConnection struct {
	ConnectionInfo VolumeConnection `json:"connection_info"`
}

// CreateCinderVolume creates a new volume in cinder according to the PVC specifications
func CreateCinderVolume(vs *gophercloud.ServiceClient, options controller.VolumeOptions) (string, error) {
	name := fmt.Sprintf("cinder-dynamic-pvc-%s", uuid.NewUUID())
	capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
	sizeBytes := capacity.Value()
	// Cinder works with gigabytes, convert to GiB with rounding up
	sizeGB := int((sizeBytes + 1024*1024*1024 - 1) / (1024 * 1024 * 1024))
	volType := ""
	availability := "nova"
	// Apply ProvisionerParameters (case-insensitive). We leave validation of
	// the values to the cloud provider.
	for k, v := range options.Parameters {
		switch strings.ToLower(k) {
		case "type":
			volType = v
		case "availability":
			availability = v
		default:
			return "", fmt.Errorf("invalid option %q", k)
		}
	}

	opts := volumes_v2.CreateOpts{
		Name:             name,
		Size:             sizeGB,
		VolumeType:       volType,
		AvailabilityZone: availability,
	}

	vol, err := volumes_v2.Create(vs, &opts).Extract()

	if err != nil {
		glog.Errorf("Failed to create a %d GiB volume: %v", sizeGB, err)
		return "", err
	}

	glog.V(2).Infof("Created volume %v in Availability Zone: %v", vol.ID, vol.AvailabilityZone)
	return vol.ID, nil
}

// WaitForAvailableCinderVolume waits for a newly created cinder volume to
// become available.  The connection information cannot be retrieved from cinder
// until the volume is available.
func WaitForAvailableCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	// TODO: Implement proper polling instead of brain-dead timers
	c := make(chan error)
	go time.AfterFunc(5*time.Second, func() {
		c <- nil
	})
	return <-c
}

// ReserveCinderVolume marks the volume as 'Attaching' in cinder.  This prevents
// the volume from being used for another purpose.
func ReserveCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	return volumeactions.Reserve(vs, volumeID).ExtractErr()
}

// ConnectCinderVolume retrieves connection information for a cinder volume.
// Depending on the type of volume, cinder may perform setup on a storage server
// such as mapping a LUN to a particular ISCSI initiator.
func ConnectCinderVolume(vs *gophercloud.ServiceClient, volumeID string) (VolumeConnection, error) {
	opt := volumeactions.InitializeConnectionOpts{
		Host:      "localhost",
		IP:        "127.0.0.1",
		Initiator: initiatorName,
	}
	var rcv rcvVolumeConnection
	err := volumeactions.InitializeConnection(vs, volumeID, &opt).ExtractInto(&rcv)
	if err != nil {
		glog.Errorf("failed to initialize connection :%v", err)
		return VolumeConnection{}, err
	}
	glog.V(3).Infof("Received connection info: %v", rcv)
	return rcv.ConnectionInfo, nil
}

// DisconnectCinderVolume removes a connection to a cinder volume.  Depending on
// the volume type, this may cause cinder to clean up the connection at a
// storage server (i.e. remove a LUN mapping).
func DisconnectCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	opt := volumeactions.TerminateConnectionOpts{
		Host:      "localhost",
		IP:        "127.0.0.1",
		Initiator: initiatorName,
	}

	err := volumeactions.TerminateConnection(vs, volumeID, &opt).Result.Err
	if err != nil {
		glog.Errorf("Failed to terminate connection to volume %s: %v",
			volumeID, err)
		return err
	}

	return nil
}

// UnreserveCinderVolume marks a cinder volume in 'Attaching' state as 'Available'.
func UnreserveCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	return volumeactions.Unreserve(vs, volumeID).ExtractErr()
}

// DeleteCinderVolume removes a volume from cinder which will cause it to be
// deleted on the storage server.
func DeleteCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	err := volumes_v2.Delete(vs, volumeID).ExtractErr()
	if err != nil {
		glog.Errorf("Cannot delete volume %s: %v", volumeID, err)
	}

	return err
}
<commit_msg>Change default az to empty when create cinder volume<commit_after>/*
Copyright 2017 The Kubernetes 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/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 volumeservice

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
	volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
	"github.com/kubernetes-incubator/external-storage/lib/controller"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/uuid"
)

const initiatorName = "iqn.1994-05.com.redhat:a13fc3d1cc22"

// VolumeConnectionDetails represent the type-specific values for a given
// DriverVolumeType.  Depending on the volume type, fields may be absent or
// have a semantically different meaning.
type VolumeConnectionDetails struct {
	VolumeID string `json:"volume_id"`
	Name     string `json:"name"`

	AuthMethod   string `json:"auth_method"`
	AuthUsername string `json:"auth_username"`
	AuthPassword string `json:"auth_password"`
	SecretType   string `json:"secret_type"`

	TargetPortal string `json:"target_portal"`
	TargetIqn    string `json:"target_iqn"`
	TargetLun    int32  `json:"target_lun"`

	ClusterName string   `json:"cluster_name"`
	Hosts       []string `json:"hosts"`
	Ports       []string `json:"ports"`
}

// VolumeConnection represents the connection information returned from the
// cinder os-initialize_connection API call
type VolumeConnection struct {
	DriverVolumeType string                  `json:"driver_volume_type"`
	Data             VolumeConnectionDetails `json:"data"`
}

type rcvVolumeConnection struct {
	ConnectionInfo VolumeConnection `json:"connection_info"`
}

// CreateCinderVolume creates a new volume in cinder according to the PVC specifications
func CreateCinderVolume(vs *gophercloud.ServiceClient, options controller.VolumeOptions) (string, error) {
	name := fmt.Sprintf("cinder-dynamic-pvc-%s", uuid.NewUUID())
	capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
	sizeBytes := capacity.Value()
	// Cinder works with gigabytes, convert to GiB with rounding up
	sizeGB := int((sizeBytes + 1024*1024*1024 - 1) / (1024 * 1024 * 1024))
	volType := ""
	availability := ""
	// Apply ProvisionerParameters (case-insensitive). We leave validation of
	// the values to the cloud provider.
	for k, v := range options.Parameters {
		switch strings.ToLower(k) {
		case "type":
			volType = v
		case "availability":
			availability = v
		default:
			return "", fmt.Errorf("invalid option %q", k)
		}
	}

	opts := volumes_v2.CreateOpts{
		Name:             name,
		Size:             sizeGB,
		VolumeType:       volType,
		AvailabilityZone: availability,
	}

	vol, err := volumes_v2.Create(vs, &opts).Extract()

	if err != nil {
		glog.Errorf("Failed to create a %d GiB volume: %v", sizeGB, err)
		return "", err
	}

	glog.V(2).Infof("Created volume %v in Availability Zone: %v", vol.ID, vol.AvailabilityZone)
	return vol.ID, nil
}

// WaitForAvailableCinderVolume waits for a newly created cinder volume to
// become available.  The connection information cannot be retrieved from cinder
// until the volume is available.
func WaitForAvailableCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	// TODO: Implement proper polling instead of brain-dead timers
	c := make(chan error)
	go time.AfterFunc(5*time.Second, func() {
		c <- nil
	})
	return <-c
}

// ReserveCinderVolume marks the volume as 'Attaching' in cinder.  This prevents
// the volume from being used for another purpose.
func ReserveCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	return volumeactions.Reserve(vs, volumeID).ExtractErr()
}

// ConnectCinderVolume retrieves connection information for a cinder volume.
// Depending on the type of volume, cinder may perform setup on a storage server
// such as mapping a LUN to a particular ISCSI initiator.
func ConnectCinderVolume(vs *gophercloud.ServiceClient, volumeID string) (VolumeConnection, error) {
	opt := volumeactions.InitializeConnectionOpts{
		Host:      "localhost",
		IP:        "127.0.0.1",
		Initiator: initiatorName,
	}
	var rcv rcvVolumeConnection
	err := volumeactions.InitializeConnection(vs, volumeID, &opt).ExtractInto(&rcv)
	if err != nil {
		glog.Errorf("failed to initialize connection :%v", err)
		return VolumeConnection{}, err
	}
	glog.V(3).Infof("Received connection info: %v", rcv)
	return rcv.ConnectionInfo, nil
}

// DisconnectCinderVolume removes a connection to a cinder volume.  Depending on
// the volume type, this may cause cinder to clean up the connection at a
// storage server (i.e. remove a LUN mapping).
func DisconnectCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	opt := volumeactions.TerminateConnectionOpts{
		Host:      "localhost",
		IP:        "127.0.0.1",
		Initiator: initiatorName,
	}

	err := volumeactions.TerminateConnection(vs, volumeID, &opt).Result.Err
	if err != nil {
		glog.Errorf("Failed to terminate connection to volume %s: %v",
			volumeID, err)
		return err
	}

	return nil
}

// UnreserveCinderVolume marks a cinder volume in 'Attaching' state as 'Available'.
func UnreserveCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	return volumeactions.Unreserve(vs, volumeID).ExtractErr()
}

// DeleteCinderVolume removes a volume from cinder which will cause it to be
// deleted on the storage server.
func DeleteCinderVolume(vs *gophercloud.ServiceClient, volumeID string) error {
	err := volumes_v2.Delete(vs, volumeID).ExtractErr()
	if err != nil {
		glog.Errorf("Cannot delete volume %s: %v", volumeID, err)
	}

	return err
}
<|endoftext|>


<commit_before>package sync

import (
  "fmt"
  "time"
)

func Sync() {
  fmt.Println("Start sync")
  fmt.Println("Syncing readings down")
  time.Sleep(time.Duration(5)*time.Second)
  fmt.Println("Syncing highlights")
  fmt.Println("Sync done")
}

<commit_msg>Sync down readings<commit_after>package sync

import (
  "ghighlighter/models"
  "ghighlighter/readmill/readmillreadings"
)

func Sync() {
  config := models.Config()

  syncReadings(config.UserId, config.AccessToken)
}

func syncReadings(userId int, accessToken string) {
  readings := models.Readings()
  readmillReadings := readmillreadings.GetReadings(userId, accessToken)

  for _, readmillReading := range readmillReadings {
    title := readmillReading.Book.Title + " - " + readmillReading.Book.Author
    reading := models.GhReading{title, readmillReading.Id}
    readings.Add(reading)
  }
}

<|endoftext|>


<commit_before>package menu

import (
	"fmt"
	"github.com/xackery/eqemuconfig"

	_ "database/sql"
	"github.com/jmoiron/sqlx"
)

func connectDB(config *eqemuconfig.Config) (db *sqlx.DB, err error) {
	//Connect to DB
	db, err = sqlx.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true", config.Database.Username, config.Database.Password, config.Database.Host, config.Database.Port, config.Database.Db))
	if err != nil {
		//fmt.Println("Error connecting to DB:", err.Error())
		return
	}
	return
}

func menuChatLog(config *eqemuconfig.Config) (err error) {
	fmt.Println("ChatLog")
	return
}

func isChatLoggingEnabled(config *eqemuconfig.Config) bool {
	db, err := connectDB(config)
	if err != nil {
		return false
	}
	//QueryServ, PlayerLogChat
	//REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogChat', 'false', '');
	count := 0
	err = db.Get(&count, "SELECT * FROM rule_values WHERE rule_name = 'QueryServ:PlayerLogChat' AND rule_value = 'true' && ruleset_id = 0")
	if err != nil {
		//fmt.Println("Error initial", err.Error())
		return false
	}
	return count > 0
}

func enableChatLogging(config *eqemuconfig.Config) (err error) {
	db, err := connectDB(config)
	if err != nil {
		return
	}
	db.Exec("REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`) VALUES (0, 'QueryServ:PlayerLogChat', 'true')")

	return
}
<commit_msg>Added chatlog detection<commit_after>package menu

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/xackery/eqemuconfig"
	"strings"
)

var theCommand = "REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`) VALUES (0, 'QueryServ:PlayerLogChat', 'true')"

func menuChatLog(config *eqemuconfig.Config) (err error) {
	fmt.Println("To enable chat logging, I will execute this command:")
	fmt.Println(theCommand)
	fmt.Println("Is this OK?")
	fmt.Println("Y) Yes")
	fmt.Println("N) No")
	option := ""
	fmt.Scan(&option)

	fmt.Println("You chose option:", option)
	option = strings.ToLower(option)
	if option == "y" || option == "yes" {
		err = enableChatLogging(config)
		if err != nil {
			fmt.Println("Error enabling chat logging:", err.Error())
			err = nil
			return
		}
		fmt.Println("Successfully enabled chat logging.")
	} else {
		fmt.Println("Cancelling")
	}
	return
}

func isChatLoggingEnabled(config *eqemuconfig.Config) bool {
	db, err := connectDB(config)
	if err != nil {
		return false
	}
	//QueryServ, PlayerLogChat
	//REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogChat', 'false', '');
	count := 0
	err = db.Get(&count, "SELECT count(ruleset_id) FROM rule_values WHERE rule_name = 'QueryServ:PlayerLogChat' AND rule_value = 'true' && ruleset_id = 0 LIMIT 1")
	if err != nil {
		fmt.Println("Error initial", err.Error())
		return false
	}
	return count > 0
}

func connectDB(config *eqemuconfig.Config) (db *sqlx.DB, err error) {
	//Connect to DB
	db, err = sqlx.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true", config.Database.Username, config.Database.Password, config.Database.Host, config.Database.Port, config.Database.Db))
	if err != nil {
		//fmt.Println("Error connecting to DB:", err.Error())
		return
	}
	return
}

func enableChatLogging(config *eqemuconfig.Config) (err error) {
	db, err := connectDB(config)
	if err != nil {
		return
	}
	var result sql.Result
	result, err = db.Exec(theCommand)
	if err != nil {
		return
	}
	var num int64
	num, err = result.RowsAffected()
	if err != nil {
		return
	}
	if num < 1 {
		err = fmt.Errorf("No rows affected")
	}
	return
}
<|endoftext|>


<commit_before>package menu

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/robjporter/GO-TermColors"
	"golang.org/x/crypto/ssh/terminal"
)

type MenuItem struct {
	Text     string
	ID       string
	SubMenu  *Menu
	Selected bool // For checkboxes.
}

const (
	ButtonType = iota
	CheckboxType
)

type Menu struct {
	Type      int
	Heading   string
	Question  string
	CursorPos int
	MenuItems []*MenuItem
}

type CheckboxMenu struct {
	Menu
	Yes string
	No  string
}

type ButtonMenu struct {
	Menu
}

func NewMenu(heading string, question string, menuType int) *Menu {
	return &Menu{
		MenuItems: make([]*MenuItem, 0),
		Heading:   heading,
		Question:  question,
		Type:      menuType,
	}
}

func NewButtonMenu(heading string, question string) *ButtonMenu {
	return &ButtonMenu{
		Menu: *NewMenu(heading, question, ButtonType),
	}
}

func NewCheckboxMenu(heading string, question string, yes string, no string) *CheckboxMenu {
	return &CheckboxMenu{
		Menu: *NewMenu(heading, question, CheckboxType),
		Yes:  yes,
		No:   no,
	}
}

func (m *Menu) AddMenuItem(text string, id string) *MenuItem {
	menuItem := &MenuItem{
		Text: text,
		ID:   id,
	}

	m.MenuItems = append(m.MenuItems, menuItem)

	return menuItem
}

func (m *Menu) CursorDown() {
	m.CursorPos = (m.CursorPos + 1) % len(m.MenuItems)
	m.DrawMenuItems(true)
}

func (m *Menu) CursorUp() {
	m.CursorPos = (m.CursorPos + len(m.MenuItems) - 1) % len(m.MenuItems)
	m.DrawMenuItems(true)
}

func (m *Menu) ToggleSelection() {
	menuItem := m.MenuItems[m.CursorPos]
	if menuItem.Selected {
		menuItem.Selected = false
	} else {
		menuItem.Selected = true
	}
	m.DrawMenuItems(true)
}

func (mi *MenuItem) SetSubMenu(menu *Menu) {
	mi.SubMenu = menu
}

func (m *Menu) Dump() {
	m.DumpIndent(0)
}

func printf(format string, s ...interface{}) {
	s = append(s, "\r\f")
	fmt.Printf(format+"%s", s...)
}

func (m *Menu) DrawMenuItems(redraw bool) {
	if redraw {
		// Move cursor up by number of menu items.  Assumes each menu item is ONE line.
		fmt.Printf("\033[%dA", len(m.MenuItems)-1)
	}

	for index, menuItem := range m.MenuItems {
		var newline = "\n"
		if index == len(m.MenuItems)-1 {
			newline = ""
		}

		prefix := "  "
		if m.Type == ButtonType {
			prefix = fmt.Sprintf("%d: ", index+1)
		} else if m.Type == CheckboxType {
			if menuItem.Selected {
				prefix = "\u25c9 "
			} else {
				prefix = "\u25ef "
			}
		}

		if index == m.CursorPos {
			cursor := termcolors.Color("> ", termcolors.CYAN)
			fmt.Printf("\r%s%s %s%s", cursor, prefix, menuItem.Text, newline)
		} else {
			fmt.Printf("\r%s%s %s%s", "  ", prefix, menuItem.Text, newline)
		}
	}
}

func (m *Menu) Render() {
	if m.Heading != "" {
		fmt.Println(m.Heading)
	}

	fmt.Printf("%s\n", termcolors.Color(termcolors.Bold(m.Question)+":", termcolors.GREEN))

	m.DrawMenuItems(false)

	// Hide cursor.
	fmt.Printf("\033[?25l")
}

func printIndent(indent int) {
	for i := 0; i < indent; i++ {
		fmt.Printf("  ")
	}
}

func (m *Menu) DumpIndent(indent int) {
	printIndent(indent)
	fmt.Println("Menu: ", m.Question)

	for index, menuItem := range m.MenuItems {
		printIndent(indent)
		fmt.Printf("      %d: %s\n", index+1, menuItem.Text)
	}
}

func (m *ButtonMenu) Run() (string, bool) {
	results, escape := m.RunInternal()
	return results[0], escape
}

func (m *CheckboxMenu) Run() ([]string, bool) {
	results, escape := m.RunInternal()
	return results, escape
}

func (m *Menu) RunInternal() (results []string, escape bool) {
	defer func() {
		// Show cursor.
		fmt.Printf("\033[?25h")
	}()

	m.Render()

	for {
		ascii, keyCode, err := GetChar()

		if (ascii == 3 || ascii == 27) || err != nil {
			fmt.Println()
			return []string{""}, true
		}

		if m.Type == ButtonType && ascii == 13 {
			fmt.Println()
			menuItem := m.MenuItems[m.CursorPos]
			return []string{menuItem.ID}, false
		}

		if m.Type == CheckboxType {
			if ascii == ' ' {
				m.ToggleSelection()
			} else if ascii == 13 {
				selections := make([]string, 0)
				for _, menuItem := range m.MenuItems {
					if menuItem.Selected {
						selections = append(selections, menuItem.ID)
					}
				}
				fmt.Println()
				return selections, false
			}
		}

		const one = 49
		const nine = 57

		if ascii >= one && ascii <= nine {
			num := ascii - one
			if num < len(m.MenuItems) {
				// Redraw items with new cursor selection.
				m.CursorPos = num
				m.DrawMenuItems(true)
				fmt.Println()

				menuItem := m.MenuItems[num]
				return []string{menuItem.ID}, false
			}
		}

		if keyCode == 40 {
			m.CursorDown()
		} else if keyCode == 38 {
			m.CursorUp()
		}
	}
}

func GetSecret(message string, defaultText string) string {
	fmt.Printf("%s", termcolors.Color(termcolors.Bold(message), termcolors.GREEN))

	if defaultText != "" {
		fmt.Printf(" %s%s%s",
			termcolors.Color(termcolors.Bold("["), termcolors.GREEN),
			termcolors.Color(defaultText, termcolors.YELLOW),
			termcolors.Color(termcolors.Bold("]"), termcolors.GREEN))
	}

	fmt.Printf("%s ", termcolors.Color(termcolors.Bold(":"), termcolors.GREEN))

	text := ""
	bytePassword, err := terminal.ReadPassword(0)
	if err == nil {
		text = strings.TrimSpace(string(bytePassword))
	}

	if text == "" {
		text = defaultText
	}

	return text
}

func GetText(message string, defaultText string) string {
	fmt.Printf("%s", termcolors.Color(termcolors.Bold(message), termcolors.GREEN))

	if defaultText != "" {
		fmt.Printf(" %s%s%s",
			termcolors.Color(termcolors.Bold("["), termcolors.GREEN),
			termcolors.Color(defaultText, termcolors.YELLOW),
			termcolors.Color(termcolors.Bold("]"), termcolors.GREEN))
	}

	fmt.Printf("%s ", termcolors.Color(termcolors.Bold(":"), termcolors.GREEN))

	reader := bufio.NewReader(os.Stdin)
	text, _ := reader.ReadString('\n')

	if text[len(text)-1] == '\n' {
		text = text[:len(text)-1]
	}

	if text == "" {
		text = defaultText
	}

	return text
}
<commit_msg>Resolved dependency issue<commit_after>package menu

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	termcolors "github.com/robjporter/GO-TermColors"

	"golang.org/x/crypto/ssh/terminal"
)

type MenuItem struct {
	Text     string
	ID       string
	SubMenu  *Menu
	Selected bool // For checkboxes.
}

const (
	ButtonType = iota
	CheckboxType
)

type Menu struct {
	Type      int
	Heading   string
	Question  string
	CursorPos int
	MenuItems []*MenuItem
}

type CheckboxMenu struct {
	Menu
	Yes string
	No  string
}

type ButtonMenu struct {
	Menu
}

func NewMenu(heading string, question string, menuType int) *Menu {
	return &Menu{
		MenuItems: make([]*MenuItem, 0),
		Heading:   heading,
		Question:  question,
		Type:      menuType,
	}
}

func NewButtonMenu(heading string, question string) *ButtonMenu {
	return &ButtonMenu{
		Menu: *NewMenu(heading, question, ButtonType),
	}
}

func NewCheckboxMenu(heading string, question string, yes string, no string) *CheckboxMenu {
	return &CheckboxMenu{
		Menu: *NewMenu(heading, question, CheckboxType),
		Yes:  yes,
		No:   no,
	}
}

func (m *Menu) AddMenuItem(text string, id string) *MenuItem {
	menuItem := &MenuItem{
		Text: text,
		ID:   id,
	}

	m.MenuItems = append(m.MenuItems, menuItem)

	return menuItem
}

func (m *Menu) CursorDown() {
	m.CursorPos = (m.CursorPos + 1) % len(m.MenuItems)
	m.DrawMenuItems(true)
}

func (m *Menu) CursorUp() {
	m.CursorPos = (m.CursorPos + len(m.MenuItems) - 1) % len(m.MenuItems)
	m.DrawMenuItems(true)
}

func (m *Menu) ToggleSelection() {
	menuItem := m.MenuItems[m.CursorPos]
	if menuItem.Selected {
		menuItem.Selected = false
	} else {
		menuItem.Selected = true
	}
	m.DrawMenuItems(true)
}

func (mi *MenuItem) SetSubMenu(menu *Menu) {
	mi.SubMenu = menu
}

func (m *Menu) Dump() {
	m.DumpIndent(0)
}

func printf(format string, s ...interface{}) {
	s = append(s, "\r\f")
	fmt.Printf(format+"%s", s...)
}

func (m *Menu) DrawMenuItems(redraw bool) {
	if redraw {
		// Move cursor up by number of menu items.  Assumes each menu item is ONE line.
		fmt.Printf("\033[%dA", len(m.MenuItems)-1)
	}

	for index, menuItem := range m.MenuItems {
		var newline = "\n"
		if index == len(m.MenuItems)-1 {
			newline = ""
		}

		prefix := "  "
		if m.Type == ButtonType {
			prefix = fmt.Sprintf("%d: ", index+1)
		} else if m.Type == CheckboxType {
			if menuItem.Selected {
				prefix = "\u25c9 "
			} else {
				prefix = "\u25ef "
			}
		}

		if index == m.CursorPos {
			cursor := termcolors.Color("> ", termcolors.CYAN)
			fmt.Printf("\r%s%s %s%s", cursor, prefix, menuItem.Text, newline)
		} else {
			fmt.Printf("\r%s%s %s%s", "  ", prefix, menuItem.Text, newline)
		}
	}
}

func (m *Menu) Render() {
	if m.Heading != "" {
		fmt.Println(m.Heading)
	}

	fmt.Printf("%s\n", termcolors.Color(termcolors.Bold(m.Question)+":", termcolors.GREEN))

	m.DrawMenuItems(false)

	// Hide cursor.
	fmt.Printf("\033[?25l")
}

func printIndent(indent int) {
	for i := 0; i < indent; i++ {
		fmt.Printf("  ")
	}
}

func (m *Menu) DumpIndent(indent int) {
	printIndent(indent)
	fmt.Println("Menu: ", m.Question)

	for index, menuItem := range m.MenuItems {
		printIndent(indent)
		fmt.Printf("      %d: %s\n", index+1, menuItem.Text)
	}
}

func (m *ButtonMenu) Run() (string, bool) {
	results, escape := m.RunInternal()
	return results[0], escape
}

func (m *CheckboxMenu) Run() ([]string, bool) {
	results, escape := m.RunInternal()
	return results, escape
}

func (m *Menu) RunInternal() (results []string, escape bool) {
	defer func() {
		// Show cursor.
		fmt.Printf("\033[?25h")
	}()

	m.Render()

	for {
		ascii, keyCode, err := GetChar()

		if (ascii == 3 || ascii == 27) || err != nil {
			fmt.Println()
			return []string{""}, true
		}

		if m.Type == ButtonType && ascii == 13 {
			fmt.Println()
			menuItem := m.MenuItems[m.CursorPos]
			return []string{menuItem.ID}, false
		}

		if m.Type == CheckboxType {
			if ascii == ' ' {
				m.ToggleSelection()
			} else if ascii == 13 {
				selections := make([]string, 0)
				for _, menuItem := range m.MenuItems {
					if menuItem.Selected {
						selections = append(selections, menuItem.ID)
					}
				}
				fmt.Println()
				return selections, false
			}
		}

		const one = 49
		const nine = 57

		if ascii >= one && ascii <= nine {
			num := ascii - one
			if num < len(m.MenuItems) {
				// Redraw items with new cursor selection.
				m.CursorPos = num
				m.DrawMenuItems(true)
				fmt.Println()

				menuItem := m.MenuItems[num]
				return []string{menuItem.ID}, false
			}
		}

		if keyCode == 40 {
			m.CursorDown()
		} else if keyCode == 38 {
			m.CursorUp()
		}
	}
}

func GetSecret(message string, defaultText string) string {
	fmt.Printf("%s", termcolors.Color(termcolors.Bold(message), termcolors.GREEN))

	if defaultText != "" {
		fmt.Printf(" %s%s%s",
			termcolors.Color(termcolors.Bold("["), termcolors.GREEN),
			termcolors.Color(defaultText, termcolors.YELLOW),
			termcolors.Color(termcolors.Bold("]"), termcolors.GREEN))
	}

	fmt.Printf("%s ", termcolors.Color(termcolors.Bold(":"), termcolors.GREEN))

	text := ""
	bytePassword, err := terminal.ReadPassword(0)
	if err == nil {
		text = strings.TrimSpace(string(bytePassword))
	}

	if text == "" {
		text = defaultText
	}

	return text
}

func GetText(message string, defaultText string) string {
	fmt.Printf("%s", termcolors.Color(termcolors.Bold(message), termcolors.GREEN))

	if defaultText != "" {
		fmt.Printf(" %s%s%s",
			termcolors.Color(termcolors.Bold("["), termcolors.GREEN),
			termcolors.Color(defaultText, termcolors.YELLOW),
			termcolors.Color(termcolors.Bold("]"), termcolors.GREEN))
	}

	fmt.Printf("%s ", termcolors.Color(termcolors.Bold(":"), termcolors.GREEN))

	reader := bufio.NewReader(os.Stdin)
	text, _ := reader.ReadString('\n')

	if text[len(text)-1] == '\n' {
		text = text[:len(text)-1]
	}

	if text == "" {
		text = defaultText
	}

	return text
}
<|endoftext|>


<commit_before>package ccserialize

import (
	"reflect"
	"strconv"
	"strings"
)

func Serialize(input interface{}) string {
	switch reflect.ValueOf(input).Kind() {
	case reflect.Int:
		return strconv.Itoa(input.(int))
	case reflect.Uint8:
		return Serialize(int(input.(uint8)))
	case reflect.Int8:
		return Serialize(int(input.(int8)))
	case reflect.Uint16:
		return Serialize(int(input.(uint16)))
	case reflect.Int16:
		return Serialize(int(input.(int16)))
	case reflect.Uint32:
		return Serialize(int64(input.(uint32)))
	case reflect.Int32:
		return Serialize(int(input.(int32)))
	case reflect.Int64:
		return strconv.FormatInt(input.(int64), 10)
	case reflect.Float64:
		return strconv.FormatFloat(input.(float64), 'f', 6, 64)
	case reflect.String:
		return "\"" + strings.Replace(input.(string), "\"", "\\\"", -1) + "\""
	case reflect.Map:
		t := reflect.TypeOf(input)
		v := reflect.ValueOf(input)
		it := reflect.TypeOf((*interface{})(nil)).Elem()
		m := reflect.MakeMap(reflect.MapOf(t.Key(), it))

		for _, mk := range v.MapKeys() {
			m.SetMapIndex(mk, v.MapIndex(mk))
		}

		return mapSerialize(m.Interface().(map[string]interface{}))
	case reflect.Slice:
		s := reflect.ValueOf(input)
		ret := make([]interface{}, s.Len())

		for i := 0; i < s.Len(); i++ {
			ret[i] = s.Index(i).Interface()
		}

		return arraySerialize(ret)
	case reflect.Struct:
		return structSerialize(input)
	default:
		panic("Attempt to serialize unsupported type.")
	}
}

func structSerialize(input interface{}) string {
	serializedString := "{"

	intStr := reflect.ValueOf(input)
	str := reflect.TypeOf(input)
	for i := 0; i < str.NumField(); i++ {
		f := intStr.Field(i)
		keyName := str.Field(i).Name
		if str.Field(i).Tag.Get("ccserialize") != "" {
			keyName = str.Field(i).Tag.Get("ccserialize")
		}

		serializedString = serializedString + "[\"" + strings.ToLower(keyName) + "\"]="
		serializedString = serializedString + Serialize(f.Interface()) + ","
	}

	return serializedString + "}"
}

func arraySerialize(input []interface{}) string {
	serializedString := "{"
	for k, v := range input {
		serializedString = serializedString + "[" + strconv.Itoa(k+1) + "]=" + Serialize(v) + ","
	}
	return serializedString + "}"
}

func mapSerialize(input map[string]interface{}) string {
	serializedString := "{"
	for k, v := range input {
		serializedString = serializedString + "[\"" + k + "\"]=" + Serialize(v) + ","
	}
	return serializedString + "}"
}
<commit_msg>Add protection from unexported fields<commit_after>package ccserialize

import (
	"reflect"
	"strconv"
	"strings"
)

func Serialize(input interface{}) string {
	switch reflect.ValueOf(input).Kind() {
	case reflect.Int:
		return strconv.Itoa(input.(int))
	case reflect.Uint8:
		return Serialize(int(input.(uint8)))
	case reflect.Int8:
		return Serialize(int(input.(int8)))
	case reflect.Uint16:
		return Serialize(int(input.(uint16)))
	case reflect.Int16:
		return Serialize(int(input.(int16)))
	case reflect.Uint32:
		return Serialize(int64(input.(uint32)))
	case reflect.Int32:
		return Serialize(int(input.(int32)))
	case reflect.Int64:
		return strconv.FormatInt(input.(int64), 10)
	case reflect.Float64:
		return strconv.FormatFloat(input.(float64), 'f', 6, 64)
	case reflect.String:
		return "\"" + strings.Replace(input.(string), "\"", "\\\"", -1) + "\""
	case reflect.Map:
		t := reflect.TypeOf(input)
		v := reflect.ValueOf(input)
		it := reflect.TypeOf((*interface{})(nil)).Elem()
		m := reflect.MakeMap(reflect.MapOf(t.Key(), it))

		for _, mk := range v.MapKeys() {
			m.SetMapIndex(mk, v.MapIndex(mk))
		}

		return mapSerialize(m.Interface().(map[string]interface{}))
	case reflect.Slice:
		s := reflect.ValueOf(input)
		ret := make([]interface{}, s.Len())

		for i := 0; i < s.Len(); i++ {
			ret[i] = s.Index(i).Interface()
		}

		return arraySerialize(ret)
	case reflect.Struct:
		return structSerialize(input)
	default:
		panic("Attempt to serialize unsupported type.")
	}
}

func structSerialize(input interface{}) string {
	serializedString := "{"

	intStr := reflect.ValueOf(input)
	str := reflect.TypeOf(input)
	for i := 0; i < str.NumField(); i++ {
		f := intStr.Field(i)
		keyName := str.Field(i).Name
		if str.Field(i).Tag.Get("ccserialize") != "" {
			keyName = str.Field(i).Tag.Get("ccserialize")
		}

		if keyName == "-" || !f.CanInterface() {
			continue
		}

		serializedString = serializedString + "[\"" + strings.ToLower(keyName) + "\"]="
		serializedString = serializedString + Serialize(f.Interface()) + ","
	}

	return serializedString + "}"
}

func arraySerialize(input []interface{}) string {
	serializedString := "{"
	for k, v := range input {
		serializedString = serializedString + "[" + strconv.Itoa(k+1) + "]=" + Serialize(v) + ","
	}
	return serializedString + "}"
}

func mapSerialize(input map[string]interface{}) string {
	serializedString := "{"
	for k, v := range input {
		serializedString = serializedString + "[\"" + k + "\"]=" + Serialize(v) + ","
	}
	return serializedString + "}"
}
<|endoftext|>


<commit_before>// HTTP server that takes JSON feedback for the Alkomat 3000 app and turns it into a neat
// e-mail forwarded to the maintainer's address.
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"strings"
	"time"
)

func main() {
	if FromAddr == "foo@example.com" {
		log.Fatal("Please set the constants in config.go and recompile")
	}

	if Passwd == "" {
		log.Fatal("Please enter the password in config.go and recompile")
	}

	http.HandleFunc("/", rootHandler)

	log.Println("Starting server on port", Port)
	log.Fatal(http.ListenAndServeTLS(":"+Port, CertificatePath, PrivateKeyPath, nil))
}

type Device struct {
	OSVer    string
	OSAPILvl int
	Device   string
	Model    string
}

func (d Device) String() string {
	return fmt.Sprintf("\tOS version: %s (API %d)\n\tDevice: %s\n\tModel: %s\n",
		d.OSVer, d.OSAPILvl, d.Device, d.Model)
}

type Feedback struct {
	Device     Device
	AppInfo    string
	LogTrace   string
	Sender     string
	SenderMail string
	Message    string
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	body, _ := ioutil.ReadAll(r.Body)
	fbstr := string(body)

	agent := r.Header.Get("user-agent")
	log.Println("Received feedback from", agent, "(", r.RemoteAddr, ")")

	decoder := json.NewDecoder(strings.NewReader(fbstr))
	var feedback Feedback
	err := decoder.Decode(&feedback)
	if err != nil {
		log.Println("JSON decode error:", err)
	}

	// Only show sender if one is mentioned.
	senderstr := ""
	if feedback.Sender != "" {
		senderstr = fmt.Sprintf("Sender: %s <%s>", feedback.Sender, feedback.SenderMail)
	}

	// The message written by the app user is indented by a single tab for clearer separation.
	msg := fmt.Sprintf("Alkomat 3000 Feedback\n%s\nDevice:\n%v\nApp: %s\nMessage:\n\n\t",
		senderstr, feedback.Device, feedback.AppInfo)
	msg += strings.Replace(feedback.Message, "\n", "\n\t", -1) + "\n"
	msg += "\nEnd of message\n"
	msg += "Log trace:\n" + feedback.LogTrace + "\n"

	err = sendMail(Subject, msg)
	if err != nil {
		log.Println("couldn't send mail:", err)
		return
	}
}

// sendMail sends a mail with the given subject and content. The content must have Unix
// newlines (\n) and end in a newline. These newlines will be converted to SMTP's CRLF
// automatically.
func sendMail(subject, content string) error {
	auth := smtp.PlainAuth("", FromAddr, Passwd, SMTPSrv)
	to := []string{ToAddr}
	date := time.Now().Format(time.RFC822Z)

	header := fmt.Sprintf("Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\n", date, FromAddr, ToAddr, subject)
	body := strings.Replace(content, "\n", "\r\n", -1)
	msg := []byte(header + "\r\n" + body)

	return smtp.SendMail(SMTPSrv+":"+SMTPPort, auth, FromAddr, to, msg)
}
<commit_msg>Update main.go<commit_after>// HTTP server that takes JSON feedback for the Alkomat 3000 app and turns it into a neat
// e-mail forwarded to the maintainer's address.
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"strings"
	"time"
)

func main() {
	if FromAddr == "foo@example.com" {
		log.Fatal("Please set the constants in config.go and recompile")
	}

	if Passwd == "" {
		log.Fatal("Please enter the password in config.go and recompile")
	}

	http.HandleFunc("/", rootHandler)

	log.Println("Starting server on port", Port)
	log.Fatal(http.ListenAndServeTLS(":"+Port, CertificatePath, PrivateKeyPath, nil))
}

type Device struct {
	OSVer    string
	OSAPILvl int
	Device   string
	Model    string
}

func (d Device) String() string {
	return fmt.Sprintf("\tOS version: %s (API %d)\n\tDevice: %s\n\tModel: %s\n",
		d.OSVer, d.OSAPILvl, d.Device, d.Model)
}

type Feedback struct {
	Device     Device
	AppInfo    string
	LogTrace   string
	Sender     string
	SenderMail string
	Message    string
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	body, _ := ioutil.ReadAll(r.Body)
	fbstr := string(body)

	agent := r.Header.Get("user-agent")

	f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal(err)
	}

	defer f.Close()
	log.SetOutput(f)

	log.Println("Received feedback from", agent, "(", r.RemoteAddr, ")")

	decoder := json.NewDecoder(strings.NewReader(fbstr))
	var feedback Feedback
	err := decoder.Decode(&feedback)
	if err != nil {
		log.Println("JSON decode error:", err)
	}

	// Only show sender if one is mentioned.
	senderstr := ""
	if feedback.Sender != "" {
		senderstr = fmt.Sprintf("Sender: %s <%s>", feedback.Sender, feedback.SenderMail)
	}

	// The message written by the app user is indented by a single tab for clearer separation.
	msg := fmt.Sprintf("Alkomat 3000 Feedback\n%s\nDevice:\n%v\nApp: %s\nMessage:\n\n\t",
		senderstr, feedback.Device, feedback.AppInfo)
	msg += strings.Replace(feedback.Message, "\n", "\n\t", -1) + "\n"
	msg += "\nEnd of message\n"
	msg += "Log trace:\n" + feedback.LogTrace + "\n"

	err = sendMail(Subject, msg)
	if err != nil {
		log.Println("couldn't send mail:", err)
		return
	}
}

// sendMail sends a mail with the given subject and content. The content must have Unix
// newlines (\n) and end in a newline. These newlines will be converted to SMTP's CRLF
// automatically.
func sendMail(subject, content string) error {
	auth := smtp.PlainAuth("", FromAddr, Passwd, SMTPSrv)
	to := []string{ToAddr}
	date := time.Now().Format(time.RFC822Z)

	header := fmt.Sprintf("Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\n", date, FromAddr, ToAddr, subject)
	body := strings.Replace(content, "\n", "\r\n", -1)
	msg := []byte(header + "\r\n" + body)

	return smtp.SendMail(SMTPSrv+":"+SMTPPort, auth, FromAddr, to, msg)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"net/http"
	"os"
	"strings"
)

func main() {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	l, err := net.Listen("tcp4", ":0")
	if err != nil {
		log.Fatal(err)
	}
	addr := strings.Split(l.Addr().String(), ":")

	log.Printf("Serving %s at http://localhost:%s/. Ctrl+C to exit", cwd, addr[len(addr)-1])
	log.Fatal(http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Served %s to %s", r.URL, r.RemoteAddr)
        http.FileServer(http.Dir(cwd)).ServeHTTP(w, r)
    })))
}
<commit_msg>gofmt magic<commit_after>package main

import (
	"log"
	"net"
	"net/http"
	"os"
)

func main() {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	l, err := net.Listen("tcp4", ":0")
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Serving %s at http://%s/. Ctrl+C to exit", cwd, l.Addr())
	log.Fatal(http.Serve(l, http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			log.Printf("Served %s to %s", r.URL, r.RemoteAddr)
			http.FileServer(http.Dir(cwd)).ServeHTTP(w, r)
		})))
}
<|endoftext|>


<commit_before>package kcp

import (
	"crypto/sha1"
	"fmt"
	"log"
	"sync"
	"testing"
	"time"

	"golang.org/x/crypto/pbkdf2"
)

const port = "127.0.0.1:9999"
const salt = "kcptest"

var key = []byte("testkey")
var fec = 4

func DialTest() (*UDPSession, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return DialWithOptions(port, block, 10, 3)
}

func DialTest2() (*UDPSession, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return DialWithOptions(port, block, 10, 3, OptionWithConvId{1234})
}

// all uncovered codes
func TestCoverage(t *testing.T) {
	x := struct{}{}
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewAESBlockCrypt(pass)
	DialWithOptions("127.0.0.1:100000", block, 0, 0, x)
}

func ListenTest() (*Listener, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return ListenWithOptions(port, block, 10, 3)
}

func server() {
	l, err := ListenTest()
	if err != nil {
		panic(err)
	}

	l.SetReadBuffer(16 * 1024 * 1024)
	l.SetWriteBuffer(16 * 1024 * 1024)
	l.SetDSCP(46)
	log.Println("listening on:", l.Addr())
	for {
		s, err := l.Accept()
		if err != nil {
			panic(err)
		}

		// coverage test
		s.SetReadBuffer(16 * 1024 * 1024)
		s.SetWriteBuffer(16 * 1024 * 1024)
		s.SetKeepAlive(1)
		go handleClient(s)
	}
}

func init() {
	go server()
}

func handleClient(conn *UDPSession) {
	conn.SetStreamMode(true)
	conn.SetWindowSize(1024, 1024)
	conn.SetNoDelay(1, 20, 2, 1)
	conn.SetDSCP(46)
	conn.SetMtu(1450)
	conn.SetACKNoDelay(false)
	conn.SetReadDeadline(time.Now().Add(time.Hour))
	conn.SetWriteDeadline(time.Now().Add(time.Hour))
	fmt.Println("new client", conn.RemoteAddr())
	buf := make([]byte, 65536)
	count := 0
	for {
		n, err := conn.Read(buf)
		if err != nil {
			panic(err)
		}
		count++
		conn.Write(buf[:n])
	}
}

func TestTimeout(t *testing.T) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, 10)

	//timeout
	cli.SetDeadline(time.Now().Add(time.Second))
	<-time.After(2 * time.Second)
	n, err := cli.Read(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
	n, err = cli.Write(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
}

func TestClose(t *testing.T) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, 10)

	cli.Close()
	if cli.Close() == nil {
		t.Fail()
	}
	n, err := cli.Write(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
	n, err = cli.Read(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
}

func TestSendRecv(t *testing.T) {
	var wg sync.WaitGroup
	const par = 1
	wg.Add(par)
	for i := 0; i < par; i++ {
		go client(&wg)
	}
	wg.Wait()
}

func client(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	cli.SetReadBuffer(16 * 1024 * 1024)
	cli.SetWriteBuffer(16 * 1024 * 1024)
	cli.SetStreamMode(true)
	cli.SetNoDelay(1, 20, 2, 1)
	cli.SetACKNoDelay(true)
	cli.SetDeadline(time.Now().Add(time.Minute))
	const N = 100
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		fmt.Println("sent:", msg)
		cli.Write([]byte(msg))
		if n, err := cli.Read(buf); err == nil {
			fmt.Println("recv:", string(buf[:n]))
		} else {
			panic(err)
		}
	}
	cli.Close()
	wg.Done()
}

func TestBigPacket(t *testing.T) {
	var wg sync.WaitGroup
	wg.Add(1)
	go client2(&wg)
	wg.Wait()
}

func client2(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	cli.SetNoDelay(1, 20, 2, 1)
	const N = 10
	buf := make([]byte, 1024*512)
	msg := make([]byte, 1024*512)
	for i := 0; i < N; i++ {
		cli.Write(msg)
	}
	println("total written:", len(msg)*N)

	nrecv := 0
	cli.SetReadDeadline(time.Now().Add(3 * time.Second))
	for {
		n, err := cli.Read(buf)
		if err != nil {
			break
		} else {
			nrecv += n
			if nrecv == len(msg)*N {
				break
			}
		}
	}

	println("total recv:", nrecv)
	cli.Close()
	wg.Done()
}

func TestSpeed(t *testing.T) {
	var wg sync.WaitGroup
	wg.Add(1)
	go client3(&wg)
	wg.Wait()
}

func client3(wg *sync.WaitGroup) {
	cli, err := DialTest2()
	if err != nil {
		panic(err)
	}
	log.Println("remote:", cli.RemoteAddr(), "local:", cli.LocalAddr())
	log.Println("conv:", cli.GetConv())
	cli.SetNoDelay(1, 20, 2, 1)
	start := time.Now()

	go func() {
		buf := make([]byte, 1024*1024)
		nrecv := 0
		for {
			n, err := cli.Read(buf)
			if err != nil {
				fmt.Println(err)
				break
			} else {
				nrecv += n
				if nrecv == 4096*4096 {
					break
				}
			}
		}
		println("total recv:", nrecv)
		cli.Close()
		fmt.Println("time for 16MB rtt with encryption", time.Now().Sub(start))
		fmt.Printf("%+v\n", DefaultSnmp.Copy())
		wg.Done()
	}()
	msg := make([]byte, 4096)
	cli.SetWindowSize(1024, 1024)
	for i := 0; i < 4096; i++ {
		cli.Write(msg)
	}
}

func TestParallel(t *testing.T) {
	par := 200
	var wg sync.WaitGroup
	wg.Add(par)
	fmt.Println("testing parallel", par, "connections")
	for i := 0; i < par; i++ {
		go client4(&wg)
	}
	wg.Wait()
}

func client4(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	const N = 100
	cli.SetNoDelay(1, 20, 2, 1)
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		cli.Write([]byte(msg))
		if _, err := cli.Read(buf); err != nil {
			break
		}
		<-time.After(10 * time.Millisecond)
	}
	cli.Close()
	wg.Done()
}
<commit_msg>upd a test<commit_after>package kcp

import (
	"crypto/sha1"
	"fmt"
	"log"
	"net"
	"sync"
	"testing"
	"time"

	"golang.org/x/crypto/pbkdf2"
)

const port = "127.0.0.1:9999"
const salt = "kcptest"

var key = []byte("testkey")
var fec = 4

func DialTest() (*UDPSession, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return DialWithOptions(port, block, 10, 3)
}

func DialTest2() (*UDPSession, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return DialWithOptions(port, block, 10, 3, OptionWithConvId{1234})
}

// all uncovered codes
func TestCoverage(t *testing.T) {
	x := struct{}{}
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewAESBlockCrypt(pass)
	DialWithOptions("127.0.0.1:100000", block, 0, 0, x)
}

func ListenTest() (net.Listener, error) {
	pass := pbkdf2.Key(key, []byte(salt), 4096, 32, sha1.New)
	block, _ := NewNoneBlockCrypt(pass)
	//block, _ := NewSimpleXORBlockCrypt(pass)
	//block, _ := NewTEABlockCrypt(pass[:16])
	//block, _ := NewAESBlockCrypt(pass)
	return ListenWithOptions(port, block, 10, 3)
}

func server() {
	l, err := ListenTest()
	if err != nil {
		panic(err)
	}

	kcplistener := l.(*Listener)
	kcplistener.SetReadBuffer(16 * 1024 * 1024)
	kcplistener.SetWriteBuffer(16 * 1024 * 1024)
	kcplistener.SetDSCP(46)
	log.Println("listening on:", kcplistener)
	for {
		s, err := l.Accept()
		if err != nil {
			panic(err)
		}

		// coverage test
		s.(*UDPSession).SetReadBuffer(16 * 1024 * 1024)
		s.(*UDPSession).SetWriteBuffer(16 * 1024 * 1024)
		s.(*UDPSession).SetKeepAlive(1)
		go handleClient(s.(*UDPSession))
	}
}

func init() {
	go server()
}

func handleClient(conn *UDPSession) {
	conn.SetStreamMode(true)
	conn.SetWindowSize(1024, 1024)
	conn.SetNoDelay(1, 20, 2, 1)
	conn.SetDSCP(46)
	conn.SetMtu(1450)
	conn.SetACKNoDelay(false)
	conn.SetReadDeadline(time.Now().Add(time.Hour))
	conn.SetWriteDeadline(time.Now().Add(time.Hour))
	fmt.Println("new client", conn.RemoteAddr())
	buf := make([]byte, 65536)
	count := 0
	for {
		n, err := conn.Read(buf)
		if err != nil {
			panic(err)
		}
		count++
		conn.Write(buf[:n])
	}
}

func TestTimeout(t *testing.T) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, 10)

	//timeout
	cli.SetDeadline(time.Now().Add(time.Second))
	<-time.After(2 * time.Second)
	n, err := cli.Read(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
	n, err = cli.Write(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
}

func TestClose(t *testing.T) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, 10)

	cli.Close()
	if cli.Close() == nil {
		t.Fail()
	}
	n, err := cli.Write(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
	n, err = cli.Read(buf)
	if n != 0 || err == nil {
		t.Fail()
	}
}

func TestSendRecv(t *testing.T) {
	var wg sync.WaitGroup
	const par = 1
	wg.Add(par)
	for i := 0; i < par; i++ {
		go client(&wg)
	}
	wg.Wait()
}

func client(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	cli.SetReadBuffer(16 * 1024 * 1024)
	cli.SetWriteBuffer(16 * 1024 * 1024)
	cli.SetStreamMode(true)
	cli.SetNoDelay(1, 20, 2, 1)
	cli.SetACKNoDelay(true)
	cli.SetDeadline(time.Now().Add(time.Minute))
	const N = 100
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		fmt.Println("sent:", msg)
		cli.Write([]byte(msg))
		if n, err := cli.Read(buf); err == nil {
			fmt.Println("recv:", string(buf[:n]))
		} else {
			panic(err)
		}
	}
	cli.Close()
	wg.Done()
}

func TestBigPacket(t *testing.T) {
	var wg sync.WaitGroup
	wg.Add(1)
	go client2(&wg)
	wg.Wait()
}

func client2(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	cli.SetNoDelay(1, 20, 2, 1)
	const N = 10
	buf := make([]byte, 1024*512)
	msg := make([]byte, 1024*512)
	for i := 0; i < N; i++ {
		cli.Write(msg)
	}
	println("total written:", len(msg)*N)

	nrecv := 0
	cli.SetReadDeadline(time.Now().Add(3 * time.Second))
	for {
		n, err := cli.Read(buf)
		if err != nil {
			break
		} else {
			nrecv += n
			if nrecv == len(msg)*N {
				break
			}
		}
	}

	println("total recv:", nrecv)
	cli.Close()
	wg.Done()
}

func TestSpeed(t *testing.T) {
	var wg sync.WaitGroup
	wg.Add(1)
	go client3(&wg)
	wg.Wait()
}

func client3(wg *sync.WaitGroup) {
	cli, err := DialTest2()
	if err != nil {
		panic(err)
	}
	log.Println("remote:", cli.RemoteAddr(), "local:", cli.LocalAddr())
	log.Println("conv:", cli.GetConv())
	cli.SetNoDelay(1, 20, 2, 1)
	start := time.Now()

	go func() {
		buf := make([]byte, 1024*1024)
		nrecv := 0
		for {
			n, err := cli.Read(buf)
			if err != nil {
				fmt.Println(err)
				break
			} else {
				nrecv += n
				if nrecv == 4096*4096 {
					break
				}
			}
		}
		println("total recv:", nrecv)
		cli.Close()
		fmt.Println("time for 16MB rtt with encryption", time.Now().Sub(start))
		fmt.Printf("%+v\n", DefaultSnmp.Copy())
		wg.Done()
	}()
	msg := make([]byte, 4096)
	cli.SetWindowSize(1024, 1024)
	for i := 0; i < 4096; i++ {
		cli.Write(msg)
	}
}

func TestParallel(t *testing.T) {
	par := 200
	var wg sync.WaitGroup
	wg.Add(par)
	fmt.Println("testing parallel", par, "connections")
	for i := 0; i < par; i++ {
		go client4(&wg)
	}
	wg.Wait()
}

func client4(wg *sync.WaitGroup) {
	cli, err := DialTest()
	if err != nil {
		panic(err)
	}
	const N = 100
	cli.SetNoDelay(1, 20, 2, 1)
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		cli.Write([]byte(msg))
		if _, err := cli.Read(buf); err != nil {
			break
		}
		<-time.After(10 * time.Millisecond)
	}
	cli.Close()
	wg.Done()
}
<|endoftext|>