<commit_before>package task

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"time"
)

type CloudTask struct {
	task       string
	token      string
	createtime string
	doingtime  string
	updatetime string
	donetime   string
	status     string
}

type CloudTasks struct {
	filename string
	tasks    []CloudTask
}

func CloudNewList(filename string) *CloudTasks {
	return &CloudTasks{filename, nil}
}

func (l *CloudTasks) CloudUpdateTask(n int, upstr string) error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	if n >= len(tasks) || n < 0 {
		return errors.New("index out of range")
	}
	f, err := os.Create(l.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	for i, t := range tasks {
		if i == n {
			if strings.HasPrefix(t, "1") {
				t = strings.Replace(t, "1", upstr, 1)
			}
			if strings.HasPrefix(t, "2") {
				t = strings.Replace(t, "2", upstr, 1)
			}
			if strings.HasPrefix(t, "0") {
				t = strings.Replace(t, "0", upstr, 1)
			}
			_, err = fmt.Fprintln(f, t)
		} else {
			_, err = fmt.Fprintln(f, t)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func (l *CloudTasks) CloudAddTask(s string) error {
	s = strings.Join([]string{"0", time.Now().Format("[2006-01-02 15:04:05]"), s}, " ")
	var flags = os.O_WRONLY | os.O_CREATE | os.O_APPEND
	f, err := os.OpenFile(l.filename, flags, 0600)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = fmt.Fprintln(f, s)
	if err != nil {
		return err
	}
	return err
}

func (l *CloudTasks) CloudRemoveTask(n int) error {
	tasks, err := l.CloudGet()
	if n >= len(tasks) || n < 0 {
		return errors.New("index out of range")
	}
	if err != nil {
		return err
	}
	f, err := os.Create(l.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	for i, t := range tasks {
		if i == n {
			continue
		}
		_, err = fmt.Fprintln(f, t)
		if err != nil {
			return err
		}
	}
	return nil
}

func (l *CloudTasks) CloudGetTask(n int) (string, error) {
	tasks, err := l.CloudGet()
	if err != nil {
		return "", err
	}
	if n >= len(tasks) || n < 0 {
		return "", errors.New("index out of range")
	}
	return tasks[n], nil
}

func (l *CloudTasks) CloudGet() ([]string, error) {
	f, err := os.Open(l.filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	var tasks []string
	br := bufio.NewReader(f)
	for {
		t, _, err := br.ReadLine()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		tasks = append(tasks, string(t))
	}
	return tasks, nil
}

func (l *CloudTasks) CloudDoneTask(n int) error {
	return l.CloudUpdateTask(n, "2")
}

func (l *CloudTasks) CloudDoingTask(n int) error {
	return l.CloudUpdateTask(n, "1")
}

func (l *CloudTasks) CloudUndoTask(n int) error {
	return l.CloudUpdateTask(n, "0")
}

func (l *CloudTasks) CloudCleanTask() error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	for i, t := range tasks {
		if strings.HasPrefix(t, "2") {
			err = l.CloudRemoveTask(i)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (l *CloudTasks) CloudClearTask() error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	for i, _ := range tasks {
		err = l.CloudRemoveTask(i)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>cloud add task test<commit_after>package task

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/jack-zh/ztodo/utils"
	"io"
	"os"
	"strings"
	"time"
)

type CloudTask struct {
	task       string
	token      string
	createtime string
	doingtime  string
	updatetime string
	donetime   string
	status     string
}

type CloudTasks struct {
	filename string
	tasks    []CloudTask
}

func CloudNewList(filename string) *CloudTasks {
	return &CloudTasks{filename, nil}
}

func (l *CloudTasks) CloudUpdateTask(n int, upstr string) error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	if n >= len(tasks) || n < 0 {
		return errors.New("index out of range")
	}
	f, err := os.Create(l.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	for i, t := range tasks {
		if i == n {
			if strings.HasPrefix(t, "1") {
				t = strings.Replace(t, "1", upstr, 1)
			}
			if strings.HasPrefix(t, "2") {
				t = strings.Replace(t, "2", upstr, 1)
			}
			if strings.HasPrefix(t, "0") {
				t = strings.Replace(t, "0", upstr, 1)
			}
			_, err = fmt.Fprintln(f, t)
		} else {
			_, err = fmt.Fprintln(f, t)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func (l *CloudTasks) CloudAddTask(s string) error {
	create_time_str := time.Now().Format("2006-01-02 15:04:05")
	doing_time_str := "2006-01-02 15:04:05"
	done_time_str := "2006-01-02 15:04:05"
	status := "Future"
	task_str := s
	token, _ := utils.GenUUID()
	task := CloudTask{
		task:       task_str,
		token:      token,
		createtime: create_time_str,
		doingtime:  doing_time_str,
		donetime:   done_time_str,
		status:     status,
		updatetime: create_time_str,
	}
	return utils.Struct2File(task)
}

func (l *CloudTasks) CloudRemoveTask(n int) error {
	tasks, err := l.CloudGet()
	if n >= len(tasks) || n < 0 {
		return errors.New("index out of range")
	}
	if err != nil {
		return err
	}
	f, err := os.Create(l.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	for i, t := range tasks {
		if i == n {
			continue
		}
		_, err = fmt.Fprintln(f, t)
		if err != nil {
			return err
		}
	}
	return nil
}

func (l *CloudTasks) CloudGetTask(n int) (string, error) {
	tasks, err := l.CloudGet()
	if err != nil {
		return "", err
	}
	if n >= len(tasks) || n < 0 {
		return "", errors.New("index out of range")
	}
	return tasks[n], nil
}

func (l *CloudTasks) CloudGet() ([]string, error) {
	f, err := os.Open(l.filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	var tasks []string
	br := bufio.NewReader(f)
	for {
		t, _, err := br.ReadLine()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		tasks = append(tasks, string(t))
	}
	return tasks, nil
}

func (l *CloudTasks) CloudDoneTask(n int) error {
	return l.CloudUpdateTask(n, "2")
}

func (l *CloudTasks) CloudDoingTask(n int) error {
	return l.CloudUpdateTask(n, "1")
}

func (l *CloudTasks) CloudUndoTask(n int) error {
	return l.CloudUpdateTask(n, "0")
}

func (l *CloudTasks) CloudCleanTask() error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	for i, t := range tasks {
		if strings.HasPrefix(t, "2") {
			err = l.CloudRemoveTask(i)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (l *CloudTasks) CloudClearTask() error {
	tasks, err := l.CloudGet()
	if err != nil {
		return err
	}
	for i, _ := range tasks {
		err = l.CloudRemoveTask(i)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Package modbusclient provides modbus Serial Line/RTU and TCP/IP access
// for client (master) applications to communicate with server (slave)
// devices. Logic specifically in this file implements the Serial Line/RTU
// protocol.

package modbusclient

import (
	"fmt"
	"github.com/tarm/goserial"
	"log"
	"time"
)

// crc computes and returns a cyclic redundancy check of the given byte array
func crc(data []byte) uint16 {
	var crc16 uint16 = 0xffff
	l := len(data)
	for i := 0; i < l; i++ {
		crc16 ^= uint16(data[i])
		for j := 0; j < 8; j++ {
			if crc16&0x0001 > 0 {
				crc16 = (crc16 >> 1) ^ 0xA001
			} else {
				crc16 >>= 1
			}
		}
	}
	return crc16
}

// GenerateRTUFrame is a method corresponding to a RTUFrame object which
// returns a byte array representing the associated serial line/RTU
// application data unit (ADU)
func (frame *RTUFrame) GenerateRTUFrame() []byte {

	packetLen := 8
	if len(frame.Data) > 0 {
		packetLen = RTU_FRAME_MAXSIZE
	}

	packet := make([]byte, packetLen)
	packet[0] = frame.SlaveAddress
	packet[1] = frame.FunctionCode
	packet[2] = byte(frame.StartRegister >> 8)       // (High Byte)
	packet[3] = byte(frame.StartRegister & 0xff)     // (Low Byte)
	packet[4] = byte(frame.NumberOfRegisters >> 8)   // (High Byte)
	packet[5] = byte(frame.NumberOfRegisters & 0xff) // (Low Byte)
	bytesUsed := 6

	for i := 0; i < len(frame.Data); i++ {
		packet[(bytesUsed + i)] = frame.Data[i]
	}
	bytesUsed += len(frame.Data)

	// add the crc to the end
	packet_crc := crc(packet[:bytesUsed])
	packet[bytesUsed] = byte(packet_crc & 0xff)
	packet[(bytesUsed + 1)] = byte(packet_crc >> 8)
	bytesUsed += 2

	return packet[:bytesUsed]
}

// viaRTU is a private method which applies the given function validator,
// to make sure the functionCode passed is valid for the operation
// desired. If correct, it creates an RTUFrame given the corresponding
// information, attempts to open the serialDevice, and if successful, transmits
// it to the modbus server (slave device) specified by the given (serial port),
// and returns a byte array of the slave device's reply, and error (if any)
func viaRTU(fnValidator func(byte) bool, serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, data []byte, baudRate, timeOut int, debug bool) ([]byte, error) {
	if fnValidator(functionCode) {
		frame := new(RTUFrame)
		frame.TimeoutInMilliseconds = timeOut
		frame.SlaveAddress = slaveAddress
		frame.FunctionCode = functionCode
		frame.StartRegister = startRegister
		frame.NumberOfRegisters = numRegisters
		if len(data) > 0 {
			frame.Data = data
		}

		// make sure we can access the serial device
		c := &serial.Config{Name: serialDevice, Baud: baudRate}
		s, err := serial.OpenPort(c)
		if err != nil {
			if debug {
				log.Println(fmt.Sprintf("RTU Open Err: %s", err))
			}
			return []byte{}, err
		} else {
			// generate the ADU from the RTU frame
			adu := frame.GenerateRTUFrame()
			if debug {
				log.Println(fmt.Sprintf("Tx: %x", adu))
			}

			// transmit the ADU to the slave device via the
			// serial port represented by the fd pointer
			_, werr := s.Write(adu)
			if werr != nil {
				if debug {
					log.Println(fmt.Sprintf("RTU Write Err: %s", werr))
				}
				return []byte{}, werr
			}

			// allow the slave device adequate time to respond
			time.Sleep(time.Duration(frame.TimeoutInMilliseconds) * time.Millisecond)

			// then attempt to read the reply
			response := make([]byte, RTU_FRAME_MAXSIZE)
			n, rerr := s.Read(response)
			if rerr != nil {
				if debug {
					log.Println(fmt.Sprintf("RTU Read Err: %s", rerr))
				}
				return []byte{}, rerr
			}

			// check the validity of the response
			if response[0] != frame.SlaveAddress || response[1] != frame.FunctionCode {
				if debug {
					log.Println("RTU Response Invalid")
				}
				if response[0] == frame.SlaveAddress && (response[1]&0x7f) == frame.FunctionCode {
					switch response[2] {
					case EXCEPTION_ILLEGAL_FUNCTION:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_ILLEGAL_FUNCTION]
					case EXCEPTION_DATA_ADDRESS:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_DATA_ADDRESS]
					case EXCEPTION_DATA_VALUE:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_DATA_VALUE]
					case EXCEPTION_SLAVE_DEVICE_FAILURE:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_SLAVE_DEVICE_FAILURE]
					}
				}
				return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_UNSPECIFIED]
			}

			// confirm the checksum (crc)
			response_length := response[2]
			response_crc := crc(response[:3+response_length])
			if response[(3+response_length)] != byte((response_crc&0xff)) ||
				response[(3+response_length+1)] != byte((response_crc>>8)) {
				// crc failed (odd that there's no specific code for it)
				if debug {
					log.Println("RTU Response Invalid: Bad Checksum")
				}
				return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_UNSPECIFIED]
			}

			// return only the number of bytes read
			return response[:n], nil
		}

	}
	return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_ILLEGAL_FUNCTION]
}

// RTURead performs the given modbus Read function over RTU to the given
// serialDevice, using the given frame data
func RTURead(serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, baudRate, timeOut int, debug bool) ([]byte, error) {
	return viaRTU(ValidReadFunction, serialDevice, slaveAddress, functionCode, startRegister, numRegisters, []byte{}, baudRate, timeOut, debug)
}

// RTUWrite performs the given modbus Write function over RTU to the given
// serialDevice, using the given frame data
func RTUWrite(serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, data []byte, baudRate, timeOut int, debug bool) ([]byte, error) {
	return viaRTU(ValidWriteFunction, serialDevice, slaveAddress, functionCode, startRegister, numRegisters, data, baudRate, timeOut, debug)
}
<commit_msg>Fixed the crc confirmation check on the RTU reply message<commit_after>// Package modbusclient provides modbus Serial Line/RTU and TCP/IP access
// for client (master) applications to communicate with server (slave)
// devices. Logic specifically in this file implements the Serial Line/RTU
// protocol.

package modbusclient

import (
	"fmt"
	"github.com/tarm/goserial"
	"log"
	"time"
)

// crc computes and returns a cyclic redundancy check of the given byte array
func crc(data []byte) uint16 {
	var crc16 uint16 = 0xffff
	l := len(data)
	for i := 0; i < l; i++ {
		crc16 ^= uint16(data[i])
		for j := 0; j < 8; j++ {
			if crc16&0x0001 > 0 {
				crc16 = (crc16 >> 1) ^ 0xA001
			} else {
				crc16 >>= 1
			}
		}
	}
	return crc16
}

// GenerateRTUFrame is a method corresponding to a RTUFrame object which
// returns a byte array representing the associated serial line/RTU
// application data unit (ADU)
func (frame *RTUFrame) GenerateRTUFrame() []byte {

	packetLen := 8
	if len(frame.Data) > 0 {
		packetLen = RTU_FRAME_MAXSIZE
	}

	packet := make([]byte, packetLen)
	packet[0] = frame.SlaveAddress
	packet[1] = frame.FunctionCode
	packet[2] = byte(frame.StartRegister >> 8)       // (High Byte)
	packet[3] = byte(frame.StartRegister & 0xff)     // (Low Byte)
	packet[4] = byte(frame.NumberOfRegisters >> 8)   // (High Byte)
	packet[5] = byte(frame.NumberOfRegisters & 0xff) // (Low Byte)
	bytesUsed := 6

	for i := 0; i < len(frame.Data); i++ {
		packet[(bytesUsed + i)] = frame.Data[i]
	}
	bytesUsed += len(frame.Data)

	// add the crc to the end
	packet_crc := crc(packet[:bytesUsed])
	packet[bytesUsed] = byte(packet_crc & 0xff)
	packet[(bytesUsed + 1)] = byte(packet_crc >> 8)
	bytesUsed += 2

	return packet[:bytesUsed]
}

// viaRTU is a private method which applies the given function validator,
// to make sure the functionCode passed is valid for the operation
// desired. If correct, it creates an RTUFrame given the corresponding
// information, attempts to open the serialDevice, and if successful, transmits
// it to the modbus server (slave device) specified by the given (serial port),
// and returns a byte array of the slave device's reply, and error (if any)
func viaRTU(fnValidator func(byte) bool, serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, data []byte, baudRate, timeOut int, debug bool) ([]byte, error) {
	if fnValidator(functionCode) {
		frame := new(RTUFrame)
		frame.TimeoutInMilliseconds = timeOut
		frame.SlaveAddress = slaveAddress
		frame.FunctionCode = functionCode
		frame.StartRegister = startRegister
		frame.NumberOfRegisters = numRegisters
		if len(data) > 0 {
			frame.Data = data
		}

		// make sure we can access the serial device
		c := &serial.Config{Name: serialDevice, Baud: baudRate}
		s, err := serial.OpenPort(c)
		if err != nil {
			if debug {
				log.Println(fmt.Sprintf("RTU Open Err: %s", err))
			}
			return []byte{}, err
		} else {
			// generate the ADU from the RTU frame
			adu := frame.GenerateRTUFrame()
			if debug {
				log.Println(fmt.Sprintf("Tx: %x", adu))
			}

			// transmit the ADU to the slave device via the
			// serial port represented by the fd pointer
			_, werr := s.Write(adu)
			if werr != nil {
				if debug {
					log.Println(fmt.Sprintf("RTU Write Err: %s", werr))
				}
				return []byte{}, werr
			}

			// allow the slave device adequate time to respond
			time.Sleep(time.Duration(frame.TimeoutInMilliseconds) * time.Millisecond)

			// then attempt to read the reply
			response := make([]byte, RTU_FRAME_MAXSIZE)
			n, rerr := s.Read(response)
			if rerr != nil {
				if debug {
					log.Println(fmt.Sprintf("RTU Read Err: %s", rerr))
				}
				return []byte{}, rerr
			}

			// check the validity of the response
			if response[0] != frame.SlaveAddress || response[1] != frame.FunctionCode {
				if debug {
					log.Println("RTU Response Invalid")
				}
				if response[0] == frame.SlaveAddress && (response[1]&0x7f) == frame.FunctionCode {
					switch response[2] {
					case EXCEPTION_ILLEGAL_FUNCTION:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_ILLEGAL_FUNCTION]
					case EXCEPTION_DATA_ADDRESS:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_DATA_ADDRESS]
					case EXCEPTION_DATA_VALUE:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_DATA_VALUE]
					case EXCEPTION_SLAVE_DEVICE_FAILURE:
						return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_SLAVE_DEVICE_FAILURE]
					}
				}
				return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_UNSPECIFIED]
			}

			// confirm the checksum (crc)
			response_crc := crc(response[:(n - 2)])
			if response[(n-2)] != byte((response_crc&0xff)) ||
				response[(n-1)] != byte((response_crc>>8)) {
				// crc failed (odd that there's no specific code for it)
				if debug {
					log.Println("RTU Response Invalid: Bad Checksum")
				}
				return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_UNSPECIFIED]
			}

			// return only the number of bytes read
			return response[:n], nil
		}

	}
	return []byte{}, MODBUS_EXCEPTIONS[EXCEPTION_ILLEGAL_FUNCTION]
}

// RTURead performs the given modbus Read function over RTU to the given
// serialDevice, using the given frame data
func RTURead(serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, baudRate, timeOut int, debug bool) ([]byte, error) {
	return viaRTU(ValidReadFunction, serialDevice, slaveAddress, functionCode, startRegister, numRegisters, []byte{}, baudRate, timeOut, debug)
}

// RTUWrite performs the given modbus Write function over RTU to the given
// serialDevice, using the given frame data
func RTUWrite(serialDevice string, slaveAddress, functionCode byte, startRegister, numRegisters uint16, data []byte, baudRate, timeOut int, debug bool) ([]byte, error) {
	return viaRTU(ValidWriteFunction, serialDevice, slaveAddress, functionCode, startRegister, numRegisters, data, baudRate, timeOut, debug)
}
<|endoftext|>


<commit_before>package controllers

// InstallationsController ...
type InstallationsController struct {
	ObjectsController
}

// HandleFind ...
// @router / [get]
func (i *InstallationsController) HandleFind() {
	i.ClassName = "_Installation"
	i.ObjectsController.HandleFind()
}

// HandleGet ...
// @router /:objectId [get]
func (i *InstallationsController) HandleGet() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleGet()
}

// HandleCreate ...
// @router / [post]
func (i *InstallationsController) HandleCreate() {
	i.ClassName = "_Installation"
	i.ObjectsController.HandleCreate()
}

// HandleUpdate ...
// @router /:objectId [put]
func (i *InstallationsController) HandleUpdate() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleUpdate()
}

// HandleDelete ...
// @router /:objectId [delete]
func (i *InstallationsController) HandleDelete() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleDelete()
}

// Delete ...
// @router / [delete]
func (i *InstallationsController) Delete() {
	i.ObjectsController.Delete()
}

// Put ...
// @router / [put]
func (i *InstallationsController) Put() {
	i.ObjectsController.Put()
}
<commit_msg>重构 installations.go<commit_after>package controllers

// InstallationsController 处理 /installations 接口的请求
type InstallationsController struct {
	ObjectsController
}

// HandleFind 处理查找已安装设备请求
// @router / [get]
func (i *InstallationsController) HandleFind() {
	i.ClassName = "_Installation"
	i.ObjectsController.HandleFind()
}

// HandleGet 处理获取指定设备信息请求
// @router /:objectId [get]
func (i *InstallationsController) HandleGet() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleGet()
}

// HandleCreate 处理添加设备请求
// @router / [post]
func (i *InstallationsController) HandleCreate() {
	i.ClassName = "_Installation"
	i.ObjectsController.HandleCreate()
}

// HandleUpdate 处理更新设备信息请求
// @router /:objectId [put]
func (i *InstallationsController) HandleUpdate() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleUpdate()
}

// HandleDelete 处理删除指定设备请求
// @router /:objectId [delete]
func (i *InstallationsController) HandleDelete() {
	i.ClassName = "_Installation"
	i.ObjectID = i.Ctx.Input.Param(":objectId")
	i.ObjectsController.HandleDelete()
}

// Delete ...
// @router / [delete]
func (i *InstallationsController) Delete() {
	i.ObjectsController.Delete()
}

// Put ...
// @router / [put]
func (i *InstallationsController) Put() {
	i.ObjectsController.Put()
}
<|endoftext|>


<commit_before>package controllers

import (
  . "seeme/models"
  . "seeme/helpers"
  "seeme/db"

  "fmt"
  "net/http"
  "html/template"

  "encoding/json"
  "golang.org/x/crypto/bcrypt"
)

func RegisterUserController(w http.ResponseWriter, r *http.Request) {
  templLogin := template.Must(template.ParseFiles("views/register.html"))
  var page Page

  if r.FormValue("register") != "" {
    if err := db.InsertUser(CreateUserFromRequest(r)); err != nil {
      page.Alert = err.Error()
      fmt.Println("Database Insert Failure: " + err.Error())
    } else {
      http.Redirect(w, r, "/seeme/api/login/user?username=" + r.FormValue("username"), http.StatusFound)
      return
    }
  }

  if err := templLogin.ExecuteTemplate(w, "register.html", page); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}

func HandlerLogin(w http.ResponseWriter, r *http.Request) {
  templLogin := template.Must(template.ParseFiles("views/login.html"))
  var page Page

  if r.FormValue("register") != "" {
    http.Redirect(w, r, "/seeme/api/register", http.StatusFound)
    return
  } else if r.FormValue("login") != "" {
    user, err := db.GetUser(r.FormValue("username"));
    if err != nil {
      page.Alert = err.Error()
    }
    if user.Username == "" {
      http.Redirect(w, r, "/seeme/api/login/user?username=", http.StatusFound)
      return
    } else {
      if err := bcrypt.CompareHashAndPassword(user.Secret, []byte(r.FormValue("password"))); err != nil {
        http.Redirect(w, r, "/seeme/api/login/user?username=", http.StatusFound)
        return
      } else {
        http.Redirect(w, r, "/seeme/api/login/user?username=" + user.Username, http.StatusFound)
        return
      }
    }
  }

  if err := templLogin.ExecuteTemplate(w, "login.html", page); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}

func HandlerLoginUser(w http.ResponseWriter, r *http.Request) {
  var userSlice = []User{}
  if r.FormValue("username") != "" {
    user, _ := db.GetUser(r.FormValue("username"))
    userSlice = []User{user}
  }

  js, err := json.Marshal(userSlice)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.Header().Set("Content-Type", "application/json")
  w.Write(js)
}

<commit_msg>removed additional handlers in RegisterUserController<commit_after>package controllers

import (
  . "seeme/models"
  . "seeme/helpers"
  "seeme/db"

  "fmt"
  "net/http"
  "html/template"
)

func RegisterUserController(w http.ResponseWriter, r *http.Request) {
  templLogin := template.Must(template.ParseFiles("views/register.html"))
  var page Page

  if r.FormValue("register") != "" {
    if err := db.InsertUser(CreateUserFromRequest(r)); err != nil {
      fmt.Println("Database Insert Failure: " + err.Error())
    } else {
      http.Redirect(w, r, "/seeme/api/login/user?username=" + r.FormValue("username"), http.StatusFound)
      return
    }
  }

  if err := templLogin.ExecuteTemplate(w, "register.html", page); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}<|endoftext|>


<commit_before>// Copyright 2009 Michael Johnson. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package models

import (
	"appengine"
	"appengine/datastore"
	"encoding/binary"
	"encoding/gob"
	"io"
	"time"
)

const CurrentVersion = 0x00

const (
	GameHL2 = 0x00
)

const DefaultGame = GameHL2

var PrettyGameNames = map[byte]string{
	GameHL2: "Half-Life 2",
}

type Run struct {
	ID      int64          `datastore:"-" json:"-" goon:"id"`
	User    *datastore.Key `datastore:"-" json:"uploader" goon:"parent"`
	Deleted bool           `datastore:",noindex" json:"-"`
	Ranked  bool           `json:"ranked"`

	UploadTime time.Time `json:"uploaded_at"`

	Game         int               `json:"game"` // TODO: We'd like to use a single byte here, but App Engine doesn't support single bytes as a datastore type.
	RunFile      appengine.BlobKey `datastore:",noindex" json:"-"`
	TotalTime    time.Duration     `json:"-"`
	FullAnalysis *datastore.Key    `datastore:",noindex" json:"-"`
}

func init() {
	gob.Register(MapAnalysis{})
}

type MapAnalysis struct {
	Name string
	Time time.Duration
}

type Analysis struct {
	ID  int64          `datastore:"-" goon:"id" json:"-"`
	Run *datastore.Key `datastore:"-" goon:"parent" json:"-"`

	RawHeader []byte     `json:"-"` // TODO: Unhackify.
	Header    *RunHeader `datastore:"-" json:"header"`

	Maps    []MapAnalysis `json:"maps"`
	Players []string      `json:"runners"`

	Fail       bool   `json:"failed"`
	FailReason string `json:"fail_reason"`
}

func (a *Analysis) MakeHeader() {
	if a.RawHeader != nil && len(a.RawHeader) >= 9 {
		a.Header = &RunHeader{
			Game: a.RawHeader[0],

			GhostColorR: a.RawHeader[2],
			GhostColorG: a.RawHeader[3],
			GhostColorB: a.RawHeader[4],

			TrailColorR: a.RawHeader[5],
			TrailColorG: a.RawHeader[6],
			TrailColorB: a.RawHeader[7],
			TrailLength: a.RawHeader[8],
		}
	}
}

type RunReader struct {
	io.Reader
}

type RunHeader struct {
	Game byte

	GhostColorR byte
	GhostColorG byte
	GhostColorB byte

	TrailColorR byte
	TrailColorG byte
	TrailColorB byte
	TrailLength byte
}

func (h *RunHeader) MakeRaw() []byte {
	return []byte{h.Game, h.GhostColorR, h.GhostColorG, h.GhostColorB, h.TrailColorR, h.TrailColorG, h.TrailColorB, h.TrailLength}
}

func (h *RunHeader) TrailDuration() time.Duration {
	return time.Duration(h.TrailLength) * time.Second
}

type RunLine struct {
	MapName    string
	PlayerName string

	Time float32
	X    float32
	Y    float32
	Z    float32
}

func readByte(r io.Reader) (byte, error) {
	arr := make([]byte, 1)
	if _, err := io.ReadFull(r, arr); err != nil {
		return 0, err
	}

	return arr[0], nil
}

// Verifies the beginning of the file.
// It always returns false if an error occurs.
// It will return false if the first byte of the file is not 0xAF or the second byte is not a known verison of the run file format.
func (r *RunReader) VerifyPreamble() (bool, error) {
	if firstByte, err := readByte(r); err != nil {
		return false, err
	} else if firstByte != 0xAF {
		return false, nil
	}

	if versionNumber, err := readByte(r); err != nil {
		return false, err
	} else if versionNumber != CurrentVersion {
		return false, nil
	}

	return true, nil
}

func (r *RunReader) ReadHeader() (header *RunHeader, err error) {
	header = new(RunHeader)
	err = binary.Read(r, binary.LittleEndian, header)
	return
}

func (r *RunReader) ReadLine() (*RunLine, error) {
	mapNameLength, err := readByte(r)
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			err = io.EOF
		}
		return nil, err
	}
	mapNameArray := make([]byte, mapNameLength)
	if _, err := io.ReadFull(r, mapNameArray); err != nil {
		return nil, err
	}
	mapName := string(mapNameArray)

	playerNameLength, err := readByte(r)
	if err != nil {
		return nil, err
	}
	playerNameArray := make([]byte, playerNameLength)
	if _, err := io.ReadFull(r, playerNameArray); err != nil {
		return nil, err
	}
	playerName := string(playerNameArray)

	runLine := &RunLine{
		MapName:    mapName,
		PlayerName: playerName,
	}

	if err := binary.Read(r, binary.LittleEndian, &runLine.Time); err != nil {
		return nil, err
	}

	if err := binary.Read(r, binary.LittleEndian, &runLine.X); err != nil {
		return nil, err
	}
	if err := binary.Read(r, binary.LittleEndian, &runLine.Y); err != nil {
		return nil, err
	}
	if err := binary.Read(r, binary.LittleEndian, &runLine.Z); err != nil {
		return nil, err
	}

	return runLine, nil
}
<commit_msg>Deeerrrpppp<commit_after>// Copyright 2009 Michael Johnson. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package models

import (
	"appengine"
	"appengine/datastore"
	"encoding/binary"
	"encoding/gob"
	"io"
	"time"
)

const CurrentVersion = 0x00

const (
	GameHL2 = 0x00
)

const DefaultGame = GameHL2

var PrettyGameNames = map[byte]string{
	GameHL2: "Half-Life 2",
}

type Run struct {
	ID      int64          `datastore:"-" json:"-" goon:"id"`
	User    *datastore.Key `datastore:"-" json:"uploader" goon:"parent"`
	Deleted bool           `datastore:",noindex" json:"-"`
	Ranked  bool           `json:"ranked"`

	UploadTime time.Time `json:"uploaded_at"`

	Game         int               `json:"game"` // TODO: We'd like to use a single byte here, but App Engine doesn't support single bytes as a datastore type.
	RunFile      appengine.BlobKey `datastore:",noindex" json:"-"`
	TotalTime    time.Duration     `json:"-"`
	FullAnalysis *datastore.Key    `datastore:",noindex" json:"-"`
}

func init() {
	gob.Register(MapAnalysis{})
}

type MapAnalysis struct {
	Name string
	Time time.Duration
}

type Analysis struct {
	ID  int64          `datastore:"-" goon:"id" json:"-"`
	Run *datastore.Key `datastore:"-" goon:"parent" json:"-"`

	RawHeader []byte     `json:"-"` // TODO: Unhackify.
	Header    *RunHeader `datastore:"-" json:"header"`

	Maps    []MapAnalysis `json:"maps"`
	Players []string      `json:"runners"`

	Fail       bool   `json:"failed"`
	FailReason string `json:"fail_reason"`
}

func (a *Analysis) MakeHeader() {
	if a.RawHeader != nil && len(a.RawHeader) >= 8 {
		a.Header = &RunHeader{
			Game: a.RawHeader[0],

			GhostColorR: a.RawHeader[1],
			GhostColorG: a.RawHeader[2],
			GhostColorB: a.RawHeader[3],

			TrailColorR: a.RawHeader[4],
			TrailColorG: a.RawHeader[5],
			TrailColorB: a.RawHeader[6],
			TrailLength: a.RawHeader[7],
		}
	} else {
		panic("Attempted to make a header while no suitable RawHeader existed.")
	}
}

type RunReader struct {
	io.Reader
}

type RunHeader struct {
	Game byte

	GhostColorR byte
	GhostColorG byte
	GhostColorB byte

	TrailColorR byte
	TrailColorG byte
	TrailColorB byte
	TrailLength byte
}

func (h *RunHeader) MakeRaw() []byte {
	return []byte{h.Game, h.GhostColorR, h.GhostColorG, h.GhostColorB, h.TrailColorR, h.TrailColorG, h.TrailColorB, h.TrailLength}
}

func (h *RunHeader) TrailDuration() time.Duration {
	return time.Duration(h.TrailLength) * time.Second
}

type RunLine struct {
	MapName    string
	PlayerName string

	Time float32
	X    float32
	Y    float32
	Z    float32
}

func readByte(r io.Reader) (byte, error) {
	arr := make([]byte, 1)
	if _, err := io.ReadFull(r, arr); err != nil {
		return 0, err
	}

	return arr[0], nil
}

// Verifies the beginning of the file.
// It always returns false if an error occurs.
// It will return false if the first byte of the file is not 0xAF or the second byte is not a known verison of the run file format.
func (r *RunReader) VerifyPreamble() (bool, error) {
	if firstByte, err := readByte(r); err != nil {
		return false, err
	} else if firstByte != 0xAF {
		return false, nil
	}

	if versionNumber, err := readByte(r); err != nil {
		return false, err
	} else if versionNumber != CurrentVersion {
		return false, nil
	}

	return true, nil
}

func (r *RunReader) ReadHeader() (header *RunHeader, err error) {
	header = new(RunHeader)
	err = binary.Read(r, binary.LittleEndian, header)
	return
}

func (r *RunReader) ReadLine() (*RunLine, error) {
	mapNameLength, err := readByte(r)
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			err = io.EOF
		}
		return nil, err
	}
	mapNameArray := make([]byte, mapNameLength)
	if _, err := io.ReadFull(r, mapNameArray); err != nil {
		return nil, err
	}
	mapName := string(mapNameArray)

	playerNameLength, err := readByte(r)
	if err != nil {
		return nil, err
	}
	playerNameArray := make([]byte, playerNameLength)
	if _, err := io.ReadFull(r, playerNameArray); err != nil {
		return nil, err
	}
	playerName := string(playerNameArray)

	runLine := &RunLine{
		MapName:    mapName,
		PlayerName: playerName,
	}

	if err := binary.Read(r, binary.LittleEndian, &runLine.Time); err != nil {
		return nil, err
	}

	if err := binary.Read(r, binary.LittleEndian, &runLine.X); err != nil {
		return nil, err
	}
	if err := binary.Read(r, binary.LittleEndian, &runLine.Y); err != nil {
		return nil, err
	}
	if err := binary.Read(r, binary.LittleEndian, &runLine.Z); err != nil {
		return nil, err
	}

	return runLine, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsElasticacheCluster() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticacheClusterCreate,
		Read:   resourceAwsElasticacheClusterRead,
		Delete: resourceAwsElasticacheClusterDelete,

		Schema: map[string]*schema.Schema{
			"cluster_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"engine": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"node_type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"num_cache_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},
			"parameter_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"port": &schema.Schema{
				Type:     schema.TypeInt,
				Default:  11211,
				Optional: true,
				ForceNew: true,
			},
			"engine_version": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"subnet_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"security_group_names": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			"security_group_ids": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
		},
	}
}

func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	clusterId := d.Get("cluster_id").(string)
	nodeType := d.Get("node_type").(string)           // e.g) cache.m1.small
	numNodes := int64(d.Get("num_cache_nodes").(int)) // 2
	engine := d.Get("engine").(string)                // memcached
	engineVersion := d.Get("engine_version").(string) // 1.4.14
	port := int64(d.Get("port").(int))                // 11211
	subnetGroupName := d.Get("subnet_group_name").(string)
	securityNameSet := d.Get("security_group_names").(*schema.Set)
	securityIdSet := d.Get("security_group_ids").(*schema.Set)
	paramGroupName := d.Get("parameter_group_name").(string) // default.memcached1.4

	securityNames := expandStringList(securityNameSet.List())
	securityIds := expandStringList(securityIdSet.List())

	req := &elasticache.CreateCacheClusterInput{
		CacheClusterID:          aws.String(clusterId),
		CacheNodeType:           aws.String(nodeType),
		NumCacheNodes:           aws.Long(numNodes),
		Engine:                  aws.String(engine),
		EngineVersion:           aws.String(engineVersion),
		Port:                    aws.Long(port),
		CacheSubnetGroupName:    aws.String(subnetGroupName),
		CacheSecurityGroupNames: securityNames,
		SecurityGroupIDs:        securityIds,
		CacheParameterGroupName: aws.String(paramGroupName),
	}

	_, err := conn.CreateCacheCluster(req)
	if err != nil {
		return fmt.Errorf("Error creating Elasticache: %s", err)
	}

	pending := []string{"creating"}
	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     "available",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "available", pending),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id())
	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr)
	}

	d.SetId(clusterId)

	return nil
}

func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn
	req := &elasticache.DescribeCacheClustersInput{
		CacheClusterID: aws.String(d.Id()),
	}

	res, err := conn.DescribeCacheClusters(req)
	if err != nil {
		return err
	}

	if len(res.CacheClusters) == 1 {
		c := res.CacheClusters[0]
		d.Set("cluster_id", c.CacheClusterID)
		d.Set("node_type", c.CacheNodeType)
		d.Set("num_cache_nodes", c.NumCacheNodes)
		d.Set("engine", c.Engine)
		d.Set("engine_version", c.EngineVersion)
		if c.ConfigurationEndpoint != nil {
			d.Set("port", c.ConfigurationEndpoint.Port)
		}
		d.Set("subnet_group_name", c.CacheSubnetGroupName)
		d.Set("security_group_names", c.CacheSecurityGroups)
		d.Set("security_group_ids", c.SecurityGroups)
		d.Set("parameter_group_name", c.CacheParameterGroup)
	}

	return nil
}

func resourceAwsElasticacheClusterDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	req := &elasticache.DeleteCacheClusterInput{
		CacheClusterID: aws.String(d.Id()),
	}
	_, err := conn.DeleteCacheCluster(req)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Waiting for deletion: %v", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"creating", "available", "deleting", "incompatible-parameters", "incompatible-network", "restore-failed"},
		Target:     "",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "", []string{}),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to delete: %s", d.Id(), sterr)
	}

	d.SetId("")

	return nil
}

func CacheClusterStateRefreshFunc(conn *elasticache.ElastiCache, clusterID, givenState string, pending []string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterID: aws.String(clusterID),
		})
		if err != nil {
			apierr := err.(aws.APIError)
			log.Printf("[DEBUG] message: %v, code: %v", apierr.Message, apierr.Code)
			if apierr.Message == fmt.Sprintf("CacheCluster not found: %v", clusterID) {
				log.Printf("[DEBUG] Detect deletion")
				return nil, "", nil
			}

			log.Printf("[ERROR] CacheClusterStateRefreshFunc: %s", err)
			return nil, "", err
		}

		c := resp.CacheClusters[0]
		log.Printf("[DEBUG] status: %v", *c.CacheClusterStatus)

		// return the current state if it's in the pending array
		for _, p := range pending {
			s := *c.CacheClusterStatus
			if p == s {
				log.Printf("[DEBUG] Return with status: %v", *c.CacheClusterStatus)
				return c, p, nil
			}
		}

		// return given state if it's not in pending
		if givenState != "" {
			return c, givenState, nil
		}
		log.Printf("[DEBUG] current status: %v", *c.CacheClusterStatus)
		return c, *c.CacheClusterStatus, nil
	}
}
<commit_msg>provider/aws: Document AWS ElastiCache cluster<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsElasticacheCluster() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticacheClusterCreate,
		Read:   resourceAwsElasticacheClusterRead,
		Delete: resourceAwsElasticacheClusterDelete,

		Schema: map[string]*schema.Schema{
			"cluster_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"engine": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"node_type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"num_cache_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},
			"parameter_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"port": &schema.Schema{
				Type:     schema.TypeInt,
				Default:  11211,
				Optional: true,
				ForceNew: true,
			},
			"engine_version": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"subnet_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"security_group_names": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			"security_group_ids": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
		},
	}
}

func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	clusterId := d.Get("cluster_id").(string)
	nodeType := d.Get("node_type").(string)           // e.g) cache.m1.small
	numNodes := int64(d.Get("num_cache_nodes").(int)) // 2
	engine := d.Get("engine").(string)                // memcached
	engineVersion := d.Get("engine_version").(string) // 1.4.14
	port := int64(d.Get("port").(int))                // 11211
	subnetGroupName := d.Get("subnet_group_name").(string)
	securityNameSet := d.Get("security_group_names").(*schema.Set)
	securityIdSet := d.Get("security_group_ids").(*schema.Set)
	paramGroupName := d.Get("parameter_group_name").(string) // default.memcached1.4

	securityNames := expandStringList(securityNameSet.List())
	securityIds := expandStringList(securityIdSet.List())

	req := &elasticache.CreateCacheClusterInput{
		CacheClusterID:          aws.String(clusterId),
		CacheNodeType:           aws.String(nodeType),
		NumCacheNodes:           aws.Long(numNodes),
		Engine:                  aws.String(engine),
		EngineVersion:           aws.String(engineVersion),
		Port:                    aws.Long(port),
		CacheSubnetGroupName:    aws.String(subnetGroupName),
		CacheSecurityGroupNames: securityNames,
		SecurityGroupIDs:        securityIds,
		CacheParameterGroupName: aws.String(paramGroupName),
	}

	_, err := conn.CreateCacheCluster(req)
	if err != nil {
		return fmt.Errorf("Error creating Elasticache: %s", err)
	}

	pending := []string{"creating"}
	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     "available",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "available", pending),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id())
	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr)
	}

	d.SetId(clusterId)

	return nil
}

func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn
	req := &elasticache.DescribeCacheClustersInput{
		CacheClusterID: aws.String(d.Id()),
	}

	res, err := conn.DescribeCacheClusters(req)
	if err != nil {
		return err
	}

	if len(res.CacheClusters) == 1 {
		c := res.CacheClusters[0]
		d.Set("cluster_id", c.CacheClusterID)
		d.Set("node_type", c.CacheNodeType)
		d.Set("num_cache_nodes", c.NumCacheNodes)
		d.Set("engine", c.Engine)
		d.Set("engine_version", c.EngineVersion)
		if c.ConfigurationEndpoint != nil {
			d.Set("port", c.ConfigurationEndpoint.Port)
		}
		d.Set("subnet_group_name", c.CacheSubnetGroupName)
		d.Set("security_group_names", c.CacheSecurityGroups)
		d.Set("security_group_ids", c.SecurityGroups)
		d.Set("parameter_group_name", c.CacheParameterGroup)
	}

	return nil
}

func resourceAwsElasticacheClusterDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	req := &elasticache.DeleteCacheClusterInput{
		CacheClusterID: aws.String(d.Id()),
	}
	_, err := conn.DeleteCacheCluster(req)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Waiting for deletion: %v", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"creating", "available", "deleting", "incompatible-parameters", "incompatible-network", "restore-failed"},
		Target:     "",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "", []string{}),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to delete: %s", d.Id(), sterr)
	}

	d.SetId("")

	return nil
}

func CacheClusterStateRefreshFunc(conn *elasticache.ElastiCache, clusterID, givenState string, pending []string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterID: aws.String(clusterID),
		})
		if err != nil {
			apierr := err.(aws.APIError)
			log.Printf("[DEBUG] message: %v, code: %v", apierr.Message, apierr.Code)
			if apierr.Message == fmt.Sprintf("CacheCluster not found: %v", clusterID) {
				log.Printf("[DEBUG] Detect deletion")
				return nil, "", nil
			}

			log.Printf("[ERROR] CacheClusterStateRefreshFunc: %s", err)
			return nil, "", err
		}

		c := resp.CacheClusters[0]
		log.Printf("[DEBUG] status: %v", *c.CacheClusterStatus)

		// return the current state if it's in the pending array
		for _, p := range pending {
			s := *c.CacheClusterStatus
			if p == s {
				log.Printf("[DEBUG] Return with status: %v", *c.CacheClusterStatus)
				return c, p, nil
			}
		}

		// return given state if it's not in pending
		if givenState != "" {
			return c, givenState, nil
		}
		log.Printf("[DEBUG] current status: %v", *c.CacheClusterStatus)
		return c, *c.CacheClusterStatus, nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)

/**
 * Predefine
 **/
const (
	ApiURL   = "http://ip-api.com/json/"
	ApiAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
)

/**
 * QueryResponse Json Object
 **/
type QueryReponse struct {
	Country     string `json:"country"`
	CountryCode string `json:"countryCode"`
	Region      string `json:"region"`
	RegionName  string `json:"regionName"`
	City        string `json:"city"`
	Zip         string `json:"zip"`
	Timezone    string `json:"timezone"`
	IP          string `json:"query"`
	AS          string `json:"as"`
	ISP         string `json:"isp"`
	ORG         string `json:"org"`
	Longitude   string `json:"lon"`
	Latitude    string `json:"lat"`
}

/**
 *  Get HTTP Response Header
 **/
func GetHeaders() http.Header {
	headers := http.Header{}
	headers.Set("Content-type", "application/json")
	return headers
}

/**
 * Get Json Object
 **/
func GetQuery(IP string) QueryReponse {

	// create a empty object
	result := QueryReponse{}

	// if empty, return
	if len(IP) == 0 {
		return result
	}

	// create a client object
	client := &http.Client{}

	// create a request object
	req, err := http.NewRequest("GET", ApiURL+IP, nil)
	if err != nil {
		return result
	}

	// apply user-agent
	req.Header.Add("User-Agent", ApiAgent)

	// send request
	resp, err := client.Do(req)
	if err != nil {
		return result
	}

	// prepare buffer
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return result
	}

	// close request
	resp.Body.Close()

	// json decode
	json.Unmarshal([]byte(buf), &result)
	return result
}
<commit_msg>fix empty location issue, set lat and lon as float64<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)

/**
 * Predefine
 **/
const (
	ApiURL   = "http://ip-api.com/json/"
	ApiAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
)

/**
 * QueryResponse Json Object
 **/
type QueryReponse struct {
	AS          string `json:"as"`
	City        string `json:"city"`
	Country     string `json:"country"`
	CountryCode string `json:"countryCode"`
	ISP         string `json:"isp"`
	Latitude    float64 `json:"lat"`
	Longitude   float64 `json:"lon"`
	ORG         string `json:"org"`
	IP          string `json:"query"`
	Region      string `json:"region"`
	RegionName  string `json:"regionName"`
        Status      string `json:"status"`
	Timezone    string `json:"timezone"`
	Zip         string `json:"zip"`
}

/**
 *  Get HTTP Response Header
 **/
func GetHeaders() http.Header {
	headers := http.Header{}
	headers.Set("Content-type", "application/json")
	return headers
}

/**
 * Get Json Object
 **/
func GetQuery(IP string) QueryReponse {

	// create a empty object
	result := QueryReponse{}

	// if empty, return
	if len(IP) == 0 {
		return result
	}

	// create a client object
	client := &http.Client{}

	// create a request object
	req, err := http.NewRequest("GET", ApiURL+IP, nil)
	if err != nil {
		return result
	}

	// apply user-agent
	req.Header.Add("User-Agent", ApiAgent)

	// send request
	resp, err := client.Do(req)
	if err != nil {
		return result
	}

	// prepare buffer
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return result
	}

	// close request
	resp.Body.Close()

	// json decode
	json.Unmarshal([]byte(buf), &result)
	return result
}
<|endoftext|>


<commit_before>package kafka

import (
	"github.com/Shopify/sarama"
	"github.com/luopengift/golibs/channel"
	"github.com/luopengift/golibs/logger"
)

type Producer struct {
	addrs   []string
	topic   string
	message chan []byte      //将数据写入这个管道中
	channel *channel.Channel //并发写topic的协程控制
}

func NewProducer(addrs []string, topic string, maxThreads int) *Producer {
	return &Producer{
		addrs:   addrs,
		topic:   topic,
		message: make(chan []byte, 1000),
		channel: channel.NewChannel(maxThreads),
	}
}

func (self *Producer) ChanInfo() string {
	return self.channel.String()
}

func (self *Producer) Write(msg []byte) (int, error) {
	self.message <- msg
	return len(msg), nil
}

func (self *Producer) WriteToTopic() error {

	config := sarama.NewConfig()
	config.Producer.Return.Successes = true
	if err := config.Validate(); err != nil {
		logger.Error("<config error> %v", err)
		return err
	}

	producer, err := sarama.NewSyncProducer(self.addrs, config)
	if err != nil {
		logger.Error("<Failed to produce message> %v", err)
		return err
	}
	defer producer.Close()

	for {
		select {
		case message := <-self.message:
			self.channel.Add()
			go func(message []byte) {
				msg := &sarama.ProducerMessage{
					Topic:     self.topic,
					Partition: int32(-1),
					Key:       sarama.StringEncoder("key"),
					Value:     sarama.ByteEncoder(message),
				}
				if partition, offset, err := producer.SendMessage(msg); err != nil {
					logger.Error("<write to kafka error,partition=%v,offset=%v> %v", partition, offset, err)
				}
				self.channel.Done()
			}(message)
		}
	}
	return nil
}
<commit_msg>Fix kafka write one partation<commit_after>package kafka

import (
	"github.com/Shopify/sarama"
	"github.com/luopengift/golibs/channel"
	"github.com/luopengift/golibs/logger"
)

type Producer struct {
	addrs   []string
	topic   string
	message chan []byte      //将数据写入这个管道中
	channel *channel.Channel //并发写topic的协程控制
}

func NewProducer(addrs []string, topic string, maxThreads int) *Producer {
	return &Producer{
		addrs:   addrs,
		topic:   topic,
		message: make(chan []byte, 1000),
		channel: channel.NewChannel(maxThreads),
	}
}

func (self *Producer) ChanInfo() string {
	return self.channel.String()
}

func (self *Producer) Write(msg []byte) (int, error) {
	self.message <- msg
	return len(msg), nil
}

func (self *Producer) WriteToTopic() error {

	config := sarama.NewConfig()
	config.Producer.Return.Successes = true
	if err := config.Validate(); err != nil {
		logger.Error("<config error> %v", err)
		return err
	}

	producer, err := sarama.NewSyncProducer(self.addrs, config)
	if err != nil {
		logger.Error("<Failed to produce message> %v", err)
		return err
	}
	defer producer.Close()

	for {
		select {
		case message := <-self.message:
			self.channel.Add()
			go func(message []byte) {
				msg := &sarama.ProducerMessage{
					Topic:     self.topic,
					//Partition: int32(-1),
					//Key:       sarama.StringEncoder("key"),
					Value:     sarama.ByteEncoder(message),
				}
				if partition, offset, err := producer.SendMessage(msg); err != nil {
					logger.Error("<write to kafka error,partition=%v,offset=%v> %v", partition, offset, err)
				}
				self.channel.Done()
			}(message)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"flag"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
)

var (
	keyFile      = flag.String("keys", "", "")
	accountsFile = flag.String("accounts", "", "")
	groupsFile   = flag.String("groups", "", "")
)

type key struct {
	algorithm   string
	key         string
	description string
}

type account struct {
	account  string
	keyNames []string
}

func parseKeys(b []byte) ([]key, error) {
	var keys []key
	re := regexp.MustCompile(`(?m)^([^\s#]+)\s+([^\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		keys = append(keys, key{
			algorithm:   e[1],
			key:         e[2],
			description: e[3],
		})
	}
	return keys, nil
}

func readKeys(fn string) ([]key, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	return parseKeys(b)
}

func readAccounts(fn string) ([]account, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	var accounts []account
	re := regexp.MustCompile(`(?m)^([^#\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		accounts = append(accounts, account{
			account:  e[1],
			keyNames: strings.Split(e[2], " "),
		})
	}
	return accounts, nil
}

func readGroups(fn string) (map[string][]string, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	groups := map[string][]string{}
	re := regexp.MustCompile(`(?m)^([^#\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		groups[e[1]] = strings.Split(e[2], " ")
	}
	return groups, nil
}

func checkAccount(ctx context.Context, kg map[string]*KeyGroup, account account) ([]string, []string, error) {
	cmd := exec.CommandContext(ctx, "ssh", account.account, "cat .ssh/authorized_keys")
	var buf bytes.Buffer
	cmd.Stdout = &buf
	if err := cmd.Run(); err != nil {
		return nil, nil, err
	}
	var err error
	currentKeys, err := parseKeys(buf.Bytes())
	if err != nil {
		return nil, nil, err
	}

	// Check for extra keys.
	var extra []string
	for _, ck := range currentKeys {
		found := false
		for _, kn := range account.keyNames {
			a := kg[kn]
			if a.Has(ck.key) {
				found = true
				break
			}
		}
		if !found {
			extra = append(extra, ck.description)
		}
	}

	// Check for missing keys.
	var missing []string
	for _, kn := range account.keyNames {
		found := false
		for _, ck := range currentKeys {
			a := kg[kn]
			if a.Has(ck.key) {
				found = true
				break
			}
		}
		if !found {
			missing = append(missing, kn)
		}
	}
	return extra, missing, nil
}

func check(ctx context.Context, kg map[string]*KeyGroup, accounts []account) error {
	log.Infof("Checking accounts…")
	for n := range accounts {
		log.Infof("Checking %q", accounts[n].account)
		ctx2, cancel := context.WithTimeout(ctx, 60*time.Second)
		defer cancel()
		extra, missing, err := checkAccount(ctx2, kg, accounts[n])
		if err != nil {
			log.Errorf("Failed to check account %q: %v", accounts[n].account, err)
			continue
		}

		if len(extra) > 0 {
			log.Warningf("Extra keys: %q", extra)
		}
		if len(missing) > 0 {
			log.Warningf("Missing keys: %q", missing)
		}
	}
	return nil
}

type KeyGroup struct {
	keys []key
}

func NewKeyGroup() *KeyGroup {
	return &KeyGroup{}
}

func (k *KeyGroup) Has(key string) bool {
	for _, k2 := range k.keys {
		if key == k2.key {
			return true
		}
	}
	return false
}

func (k *KeyGroup) Add(ky ...key) {
	k.keys = append(k.keys, ky...)
}

func (k *KeyGroup) Keys() []key {
	return k.keys
}

func main() {
	flag.Parse()

	// Read keys.
	keys, err := readKeys(*keyFile)
	if err != nil {
		log.Fatalf("Failed to read keyfile %q: %v", *keyFile, err)
	}
	log.Infof("Read %d keys", len(keys))

	// Make keygroups.
	keyGroups := map[string]*KeyGroup{}
	for _, k := range keys {
		kg := NewKeyGroup()
		kg.Add(k)
		keyGroups[k.description] = kg
	}

	groups, err := readGroups(*groupsFile)
	if err != nil {
		log.Fatalf("Failed to read groups file %q: %v", *groupsFile, err)
	}
	log.Infof("Read %d groups", len(groups))
	for g, ks := range groups {
		kg := NewKeyGroup()
		for _, kn := range ks {
			o, found := keyGroups[kn]
			if !found {
				log.Fatalf("Group %q refers to non-existing key %q", g, kn)
			}
			kg.Add(o.Keys()...)
		}
		keyGroups["@"+g] = kg
	}

	// Read accounts.
	accounts, err := readAccounts(*accountsFile)
	if err != nil {
		log.Fatalf("Failed to read accounts file %q: %v", *accountsFile, err)
	}
	log.Infof("Read %d accounts", len(accounts))

	// Verify that all accounts' keys exist in database.
	for _, a := range accounts {
		for _, kn := range a.keyNames {
			if _, found := keyGroups[kn]; !found {
				log.Fatalf("Unknown key %q for account %q", kn, a.account)
			}
		}
	}

	// Check all accounts.
	ctx := context.Background()
	if err := check(ctx, keyGroups, accounts); err != nil {
		log.Fatalf("blah: %v", err)
	}

}
<commit_msg>Fix 'missing' keys reporting<commit_after>package main

import (
	"bytes"
	"context"
	"flag"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
)

var (
	keyFile      = flag.String("keys", "", "File containing SSH pubkeys.")
	accountsFile = flag.String("accounts", "", "File containing account definitions.")
	groupsFile   = flag.String("groups", "", "File containing group definitions.")
	matching     = flag.String("matching", ".*", "Only check hosts matching this regex.")
)

type key struct {
	algorithm   string
	key         string
	description string
}

type account struct {
	account       string
	keyGroupNames []string
}

func parseKeys(b []byte) ([]key, error) {
	var keys []key
	re := regexp.MustCompile(`(?m)^([^\s#]+)\s+([^\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		keys = append(keys, key{
			algorithm:   e[1],
			key:         e[2],
			description: e[3],
		})
	}
	return keys, nil
}

func readKeys(fn string) ([]key, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	return parseKeys(b)
}

func readAccounts(fn string) ([]account, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	var accounts []account
	re := regexp.MustCompile(`(?m)^([^#\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		accounts = append(accounts, account{
			account:       e[1],
			keyGroupNames: strings.Split(e[2], " "),
		})
	}
	return accounts, nil
}

func readGroups(fn string) (map[string][]string, error) {
	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, err
	}
	groups := map[string][]string{}
	re := regexp.MustCompile(`(?m)^([^#\s]+)\s+(.*)$`)
	for _, e := range re.FindAllStringSubmatch(string(b), -1) {
		groups[e[1]] = strings.Split(e[2], " ")
	}
	return groups, nil
}

func checkAccount(ctx context.Context, kg map[string]*KeyGroup, account account) ([]string, []string, error) {
	cmd := exec.CommandContext(ctx, "ssh", account.account, "cat .ssh/authorized_keys")
	var buf bytes.Buffer
	cmd.Stdout = &buf
	if err := cmd.Run(); err != nil {
		return nil, nil, err
	}
	var err error
	currentKeys, err := parseKeys(buf.Bytes())
	if err != nil {
		return nil, nil, err
	}
	log.Debugf("Found %d current keys", len(currentKeys))

	// Check for extra keys.
	var extra []string
	for _, ck := range currentKeys {
		found := false
		for _, kn := range account.keyGroupNames {
			a := kg[kn]
			if a.Has(ck.key) {
				found = true
				break
			}
		}
		if !found {
			extra = append(extra, ck.description)
		}
	}

	// Check for missing keys.
	var missing []string
	for _, kgn := range account.keyGroupNames {
		for _, k := range kg[kgn].Keys() {
			found := false
			for _, ck := range currentKeys {
				if k.key == ck.key {
					found = true
					break
				}
			}
			if !found {
				missing = append(missing, k.description)
			}
		}
	}
	return extra, missing, nil
}

func check(ctx context.Context, kg map[string]*KeyGroup, accounts []account) error {
	log.Infof("Checking accounts…")
	re, err := regexp.Compile(*matching)
	if err != nil {
		return err
	}
	for n := range accounts {
		if re.FindString(accounts[n].account) == "" {
			continue
		}

		log.Infof("Checking %q", accounts[n].account)
		ctx2, cancel := context.WithTimeout(ctx, 60*time.Second)
		defer cancel()
		extra, missing, err := checkAccount(ctx2, kg, accounts[n])
		if err != nil {
			log.Errorf("Failed to check account %q: %v", accounts[n].account, err)
			continue
		}

		if len(extra) > 0 {
			log.Warningf("Extra keys: %q", extra)
		}
		if len(missing) > 0 {
			log.Warningf("Missing keys: %q", missing)
		}
	}
	return nil
}

type KeyGroup struct {
	keys []key
}

func NewKeyGroup() *KeyGroup {
	return &KeyGroup{}
}

func (k *KeyGroup) Has(key string) bool {
	for _, k2 := range k.keys {
		if key == k2.key {
			return true
		}
	}
	return false
}

func (k *KeyGroup) Add(ky ...key) {
	k.keys = append(k.keys, ky...)
}

func (k *KeyGroup) Keys() []key {
	return k.keys
}

func main() {
	flag.Parse()

	// Read keys.
	keys, err := readKeys(*keyFile)
	if err != nil {
		log.Fatalf("Failed to read keyfile %q: %v", *keyFile, err)
	}
	log.Infof("Read %d keys", len(keys))

	// Make keygroups.
	keyGroups := map[string]*KeyGroup{}
	for _, k := range keys {
		kg := NewKeyGroup()
		kg.Add(k)
		keyGroups[k.description] = kg
	}

	groups, err := readGroups(*groupsFile)
	if err != nil {
		log.Fatalf("Failed to read groups file %q: %v", *groupsFile, err)
	}
	log.Infof("Read %d groups", len(groups))
	for g, ks := range groups {
		kg := NewKeyGroup()
		for _, kn := range ks {
			o, found := keyGroups[kn]
			if !found {
				log.Fatalf("Group %q refers to non-existing key %q", g, kn)
			}
			kg.Add(o.Keys()...)
		}
		keyGroups["@"+g] = kg
	}

	// Read accounts.
	accounts, err := readAccounts(*accountsFile)
	if err != nil {
		log.Fatalf("Failed to read accounts file %q: %v", *accountsFile, err)
	}
	log.Infof("Read %d accounts", len(accounts))

	// Verify that all accounts' keys exist in database.
	for _, a := range accounts {
		for _, kn := range a.keyGroupNames {
			if _, found := keyGroups[kn]; !found {
				log.Fatalf("Unknown key %q for account %q", kn, a.account)
			}
		}
	}

	// Check all accounts.
	ctx := context.Background()
	if err := check(ctx, keyGroups, accounts); err != nil {
		log.Fatalf("blah: %v", err)
	}
	log.Infof("Done")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"crypto"
	"encoding/pem"
	"fmt"
	"os"
	"strings"
	"io/ioutil"
	"time"
	"strconv"
	"path/filepath"
)

const COUNTER_INTERVAL = 1000000

func main() {
    fmt.Printf("\nHello welcome to the Distributed email\n")
    user_name, userKey:= AuthUser()
    //fmt.Println("User_name: ", user_name)
    //fmt.Println("User_key: ", userKey)

    for {
        fmt.Printf("Main Menu\n 1.New email 2.Check your inbox 3. Exit\n")
        Menu(user_name, userKey)
    }

}

/*Creates new Mail struct and fills its fields
with the provided information; ready to be sent*/
func NewMail(userKey *rsa.PrivateKey, toPublicKey *rsa.PublicKey, message string, to string, from string) (mail Mail){
	//create symmetric encryption key for AES encryption of payload
	var h Header
	var pow []byte
	t := time.Now()

	/*Fill header with mail specific info*/
	h.ZeroCount = 20
	h.Date = CreateDate(t)
	rsrc, err := x509.MarshalPKIXPublicKey(toPublicKey)
	checkError(err)
	h.Resource = Encode64(rsrc)//Para ler de volta, usar -- bytes, err, := x509.ParsePKIXPublicKey(Decode64(h.Resource))
	h.RandString = RndStr(12) //random 12 byte string
	h.Counter = RndInt(COUNTER_INTERVAL)

	/*Hashcash to create valid proof_of_work*/
	header := h.HeaderToString() //header in string format
	pow = HashDigest(header)

	for !CheckZeroBits(pow, h.ZeroCount)  {
		h.IncCounter()//increment counter to create new digest
		header = h.HeaderToString()
		pow = HashDigest(header)
	}
	mail.Header = header
	mail.Proof_of_Work = Encode64(pow)

	/*Generate payload string with format "PoW//\\TO//\\FROM//\\MESSAGE//\\SIGNATURE" */
	payloadArray := []string{mail.Proof_of_Work, to, from, message}
	payload := strings.Join(payloadArray, "//\\\\")

	/*Sign payload*/
	payloadSignature := Sign(HashDigest(payload), userKey)

	/*Encrypt (payload + signature) and from field with symKey*/
	symKey := GenSymKey()
	mail.From = SymEncrypt(symKey, from)
	mail.Payload = SymEncrypt(symKey, payload + "//\\\\" + payloadSignature) //Payload encrypted with symKey, encoded in Base64

	/*Encrypt symKey with recipient toPublicKey*/
	encSymKey, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, toPublicKey, symKey, []byte(""))
	checkError(err)
	mail.SymKey = Encode64(encSymKey)

	return mail
}

/*Reads Mail using user PrivateKey and sender PublicKey*/
func ReadMail(userKey *rsa.PrivateKey, senderKey *rsa.PublicKey, mail Mail) {

	/*Integrity check*/
	if mail.Proof_of_Work != Encode64(HashDigest(mail.Header)){
		fmt.Print("Mail may be spam or was illicitly altered!! (pow test fail)\n")
		return
	}
	var header Header
	header.StringToHeader(mail.Header)

	/*Check if user PublicKey is equal to header.Resource(TO) */
	pub, err := x509.MarshalPKIXPublicKey(&userKey.PublicKey)
	checkError(err)
	if header.Resource == Encode64(pub) {
		fmt.Print("Header.Resource == userKey.PublicKey\n")
	}

	/*Retrieve symKey*/
	symKey, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, userKey, Decode64(mail.SymKey), []byte(""))
	checkError(err)
	/*Retrieve payload*/
	payload := SymDecrypt(symKey, mail.Payload)
	from := SymDecrypt(symKey, mail.From)
	plParts := strings.Split(payload, "//\\\\")

	/*Check for valid sender signature*/
	d := HashDigest(strings.Replace(payload, "//\\\\" + plParts[4], "", -1))
	if !CheckSign(d, []byte(Decode64(plParts[4])), senderKey) {
		fmt.Print("Mail illicitly altered or corrupt!! (signature mismatch)")
		return
	}

	fmt.Print("\nMESSAGE\nFROM: ", from, "\nTO: ", plParts[1], "\nCONTENT: ", plParts[3], "\n")

}

/*Signs digest with priv private key
Returns signature in string format, encoded in Base64
 */
func Sign(digest []byte, priv *rsa.PrivateKey) string{
	var opts rsa.PSSOptions
	opts.SaltLength = rsa.PSSSaltLengthAuto //for simplicity
	signature, err := rsa.SignPSS(rand.Reader, priv, crypto.SHA1, digest, &opts)
	checkError(err)
	return Encode64(signature)
}

/*Check signature with senderKey and digest
 *Returns true if signature is valid and false otherwise
 */
func CheckSign(digest []byte, signature []byte, senderKey *rsa.PublicKey) bool{
	var opts rsa.PSSOptions
	opts.SaltLength = rsa.PSSSaltLengthAuto
	if rsa.VerifyPSS(senderKey, crypto.SHA1, digest, signature, &opts) == nil {
		return true
	}else {
		return false
	}
}

/*Create a date string with current date of the form DDMMYYHHmm */
func CreateDate(t time.Time) (date string) {

	DD := t.Day()
	MM := int(t.Month())

	day := strconv.Itoa(DD)
	month := strconv.Itoa(MM)
	if DD < 10 {
		day = "0" + day
	}
	if MM < 10 {
		month = "0" + month
	}

	hh, mm, _ := t.Clock()
	hours := strconv.Itoa(hh)
	minutes := strconv.Itoa(mm)
	if hh < 10 {
		hours = "0" + hours
	}
	if mm < 10 {
		minutes = "0" + minutes
	}
	date = day + month + strconv.Itoa(t.Year()-2000) + hours + minutes
	return date
}

func AuthUser() (string, *rsa.PrivateKey) {

	//check if Users dir exists if not creates one
	rootpath, _ := os.Getwd()
	subpath := filepath.Join(rootpath, "Users")
	err := os.MkdirAll(subpath, os.ModePerm)
	checkError(err)

	//check if Users list file, with the passwords exists if not creates one
	users_list := filepath.Join(subpath,"users_list.txt")
	_, err = os.Stat(users_list)

	if os.IsNotExist(err){
		var users_list, err = os.Create(users_list)
		checkError(err)
		defer users_list.Close()
	}

	user_name := DataInput("Insert Username: ")
	userPriv := filepath.Join(subpath, user_name + "_PrivateKey")
	_, err = os.Stat(userPriv)

	// detect if key file associated to user exists
	if os.IsNotExist(err) {

		//create user key file
		var user_file, err = os.Create(userPriv)
		checkError(err)
		defer user_file.Close()

		// generate user key
		userKey, err := rsa.GenerateKey(rand.Reader, 2048)
		checkError(err)

		//encode key to file
		pemdata := pem.EncodeToMemory(
			&pem.Block{
				Type: "RSA PRIVATE KEY",
				Bytes: x509.MarshalPKCS1PrivateKey(userKey),
			},
		)

		ioutil.WriteFile(userPriv, pemdata, 0644)

		//create user PublicKey contact file
		PublicKey, err := x509.MarshalPKIXPublicKey(&userKey.PublicKey)
		checkError(err)

		pemdata = pem.EncodeToMemory(
			&pem.Block{
				Type: "RSA PUBLIC KEY",
				Bytes: PublicKey,
			},
		)

		userPub := filepath.Join(subpath, user_name + "_PublicKey")
		contact_file, err := os.Create(userPub)
		checkError(err)
		defer contact_file.Close()

		ioutil.WriteFile(userPub, pemdata, 0644)

		fmt.Printf("User keys generated!\n")
		return user_name, userKey

	}else{
		//load user key from file
		fmt.Printf("User login successful!\n")
		file_data, err := ioutil.ReadFile(userPriv)
		checkError(err)
		pemdata, _ := pem.Decode(file_data)
		userKey, err := x509.ParsePKCS1PrivateKey(pemdata.Bytes)
		checkError(err)

		return user_name, userKey
	}
}
/*
func Pass_gen_or_check(user_name string){
	rcv_pass := DataInput("Insert Password: ")
}*/

func Menu(user_name string, userKey *rsa.PrivateKey){

	var input int
	n, err := fmt.Scanln(&input)
	if n < 1 || n > 2 || err != nil {
		fmt.Println("Invalid input\n")
		return
	}
	switch input {
	case 1:
		fmt.Println("New email option chosen:\n")
		dest_name, dest_PublicKey := RcvDest()
		file_name := FileToSend()
		fmt.Println("Sender:", user_name, "\nDest :", dest_name, "\nFile: ", file_name,"\n")
		message := ReadFile(file_name)
		mail := NewMail(userKey, dest_PublicKey, message, dest_name, user_name)

		fmt.Println()

		WriteJSON(mail)

	case 2:
		fmt.Println("Check inbox option chosen\n")
		rcvMail := ReadJSON("mail_ready.json")
		_, pub := RcvDest()
		ReadMail(userKey, pub, rcvMail)
	case 3:
		fmt.Println("Goodbye thank you for choosing us\n")
		os.Exit(0)
	default:
		fmt.Println("Invalid Input\n")
	}
}

func RcvDest() (string, *rsa.PublicKey){

	//check if Contacts dir exists if not creates one
	rootpath, _ := os.Getwd()
	subpath := filepath.Join(rootpath, "Contacts")
	os.MkdirAll(subpath, os.ModePerm)

	//receive name of contact
	var recp_name = DataInput("Insert Recipient: ")

	//Check if contact exists
	subpath = filepath.Join(subpath, recp_name + "_PublicKey")
	_, err := os.Stat(subpath)

	if os.IsNotExist(err) {
		fmt.Printf("No such contact in Contacts list!\n")
		os.Exit(3)
	}

	fmt.Println("Contact found!\n")
	file_data, err := ioutil.ReadFile(subpath)
	checkError(err)
	pemdata, _ := pem.Decode(file_data)
	pub, err := x509.ParsePKIXPublicKey(pemdata.Bytes)
	checkError(err)

	return recp_name, pub.(*rsa.PublicKey)
}

func FileToSend()(string){
	//recieve name of file
	var file_name = DataInput("Insert name of file to send: ")

	//Check if file exists
	_, err := os.Stat(file_name)
	if os.IsNotExist(err) {
		fmt.Println(err.Error())
		os.Exit(3)
	} else{
		fmt.Println("File found!\n")
	}
	return file_name
}

func DataInput(msg string) (string){
	for{
		var data string
		fmt.Println(msg)
		n, err := fmt.Scanln(&data)
		if n < 1 || n > 2 || err != nil {
			fmt.Println("Invalid input\n")
		}else{
			return data
		}
	}
}
<commit_msg>start password mechanism<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"crypto"
	"encoding/pem"
	"fmt"
	"os"
	"strings"
	"io/ioutil"
	"time"
	"strconv"
	"path/filepath"
)

const COUNTER_INTERVAL = 1000000

func main() {

	fmt.Printf("\nHello welcome to the Distributed email\n")
  user_name, userKey:= AuthUser()

  for {
    fmt.Printf("Main Menu\n 1.New email 2.Check your inbox 3. Exit\n")
    Menu(user_name, userKey)
  }
}

/*Creates new Mail struct and fills its fields
with the provided information; ready to be sent*/
func NewMail(userKey *rsa.PrivateKey, toPublicKey *rsa.PublicKey, message string, to string, from string) (mail Mail){
	//create symmetric encryption key for AES encryption of payload
	var h Header
	var pow []byte
	t := time.Now()

	/*Fill header with mail specific info*/
	h.ZeroCount = 20
	h.Date = CreateDate(t)
	rsrc, err := x509.MarshalPKIXPublicKey(toPublicKey)
	checkError(err)
	h.Resource = Encode64(rsrc)//Para ler de volta, usar -- bytes, err, := x509.ParsePKIXPublicKey(Decode64(h.Resource))
	h.RandString = RndStr(12) //random 12 byte string
	h.Counter = RndInt(COUNTER_INTERVAL)

	/*Hashcash to create valid proof_of_work*/
	header := h.HeaderToString() //header in string format
	pow = HashDigest(header)

	for !CheckZeroBits(pow, h.ZeroCount)  {
		h.IncCounter()//increment counter to create new digest
		header = h.HeaderToString()
		pow = HashDigest(header)
	}
	mail.Header = header
	mail.Proof_of_Work = Encode64(pow)

	/*Generate payload string with format "PoW//\\TO//\\FROM//\\MESSAGE//\\SIGNATURE" */
	payloadArray := []string{mail.Proof_of_Work, to, from, message}
	payload := strings.Join(payloadArray, "//\\\\")

	/*Sign payload*/
	payloadSignature := Sign(HashDigest(payload), userKey)

	/*Encrypt (payload + signature) and from field with symKey*/
	symKey := GenSymKey()
	mail.From = SymEncrypt(symKey, from)
	mail.Payload = SymEncrypt(symKey, payload + "//\\\\" + payloadSignature) //Payload encrypted with symKey, encoded in Base64

	/*Encrypt symKey with recipient toPublicKey*/
	encSymKey, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, toPublicKey, symKey, []byte(""))
	checkError(err)
	mail.SymKey = Encode64(encSymKey)

	return mail
}

/*Reads Mail using user PrivateKey and sender PublicKey*/
func ReadMail(userKey *rsa.PrivateKey, senderKey *rsa.PublicKey, mail Mail) {

	/*Integrity check*/
	if mail.Proof_of_Work != Encode64(HashDigest(mail.Header)){
		fmt.Print("Mail may be spam or was illicitly altered!! (pow test fail)\n")
		return
	}
	var header Header
	header.StringToHeader(mail.Header)

	/*Check if user PublicKey is equal to header.Resource(TO) */
	pub, err := x509.MarshalPKIXPublicKey(&userKey.PublicKey)
	checkError(err)
	if header.Resource == Encode64(pub) {
		fmt.Print("Header.Resource == userKey.PublicKey\n")
	}

	/*Retrieve symKey*/
	symKey, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, userKey, Decode64(mail.SymKey), []byte(""))
	checkError(err)
	/*Retrieve payload*/
	payload := SymDecrypt(symKey, mail.Payload)
	from := SymDecrypt(symKey, mail.From)
	plParts := strings.Split(payload, "//\\\\")

	/*Check for valid sender signature*/
	d := HashDigest(strings.Replace(payload, "//\\\\" + plParts[4], "", -1))
	if !CheckSign(d, []byte(Decode64(plParts[4])), senderKey) {
		fmt.Print("Mail illicitly altered or corrupt!! (signature mismatch)")
		return
	}

	fmt.Print("\nMESSAGE\nFROM: ", from, "\nTO: ", plParts[1], "\nCONTENT: ", plParts[3], "\n")

}

/*Signs digest with priv private key
Returns signature in string format, encoded in Base64
 */
func Sign(digest []byte, priv *rsa.PrivateKey) string{
	var opts rsa.PSSOptions
	opts.SaltLength = rsa.PSSSaltLengthAuto //for simplicity
	signature, err := rsa.SignPSS(rand.Reader, priv, crypto.SHA1, digest, &opts)
	checkError(err)
	return Encode64(signature)
}

/*Check signature with senderKey and digest
 *Returns true if signature is valid and false otherwise
 */
func CheckSign(digest []byte, signature []byte, senderKey *rsa.PublicKey) bool{
	var opts rsa.PSSOptions
	opts.SaltLength = rsa.PSSSaltLengthAuto
	if rsa.VerifyPSS(senderKey, crypto.SHA1, digest, signature, &opts) == nil {
		return true
	}else {
		return false
	}
}

/*Create a date string with current date of the form DDMMYYHHmm */
func CreateDate(t time.Time) (date string) {

	DD := t.Day()
	MM := int(t.Month())

	day := strconv.Itoa(DD)
	month := strconv.Itoa(MM)
	if DD < 10 {
		day = "0" + day
	}
	if MM < 10 {
		month = "0" + month
	}

	hh, mm, _ := t.Clock()
	hours := strconv.Itoa(hh)
	minutes := strconv.Itoa(mm)
	if hh < 10 {
		hours = "0" + hours
	}
	if mm < 10 {
		minutes = "0" + minutes
	}
	date = day + month + strconv.Itoa(t.Year()-2000) + hours + minutes
	return date
}

func AuthUser() (string, *rsa.PrivateKey) {

	//check if Users dir exists if not creates one
	rootpath, _ := os.Getwd()
	subpath := filepath.Join(rootpath, "Users")
	err := os.MkdirAll(subpath, os.ModePerm)
	checkError(err)

	user_name := DataInput("Insert Username: ")
	userPriv := filepath.Join(subpath, user_name + "_PrivateKey")
	_, err = os.Stat(userPriv)

	// detect if key file associated to user exists
	if os.IsNotExist(err) {

		//create user key file
		var user_file, err = os.Create(userPriv)
		checkError(err)
		defer user_file.Close()

		// generate user key
		userKey, err := rsa.GenerateKey(rand.Reader, 2048)
		checkError(err)

		//encode key to file
		pemdata := pem.EncodeToMemory(
			&pem.Block{
				Type: "RSA PRIVATE KEY",
				Bytes: x509.MarshalPKCS1PrivateKey(userKey),
			},
		)

		ioutil.WriteFile(userPriv, pemdata, 0644)

		//create user PublicKey contact file
		PublicKey, err := x509.MarshalPKIXPublicKey(&userKey.PublicKey)
		checkError(err)

		pemdata = pem.EncodeToMemory(
			&pem.Block{
				Type: "RSA PUBLIC KEY",
				Bytes: PublicKey,
			},
		)

		userPub := filepath.Join(subpath, user_name + "_PublicKey")
		contact_file, err := os.Create(userPub)
		checkError(err)
		defer contact_file.Close()

		ioutil.WriteFile(userPub, pemdata, 0644)

		fmt.Printf("User keys generated!\n")
		return user_name, userKey

	}else{
		//load user key from file
		fmt.Printf("User login successful!\n")
		file_data, err := ioutil.ReadFile(userPriv)
		checkError(err)
		pemdata, _ := pem.Decode(file_data)
		userKey, err := x509.ParsePKCS1PrivateKey(pemdata.Bytes)
		checkError(err)

		return user_name, userKey
	}
}
/*
func Pass_gen_or_check(user_name string){
	rcv_pass := DataInput("Insert Password: ")
}*/

func Menu(user_name string, userKey *rsa.PrivateKey){

	var input int
	n, err := fmt.Scanln(&input)
	if n < 1 || n > 2 || err != nil {
		fmt.Println("Invalid input\n")
		return
	}
	switch input {
	case 1:
		fmt.Println("New email option chosen:\n")
		dest_name, dest_PublicKey := RcvDest()
		file_name := FileToSend()
		fmt.Println("Sender:", user_name, "\nDest :", dest_name, "\nFile: ", file_name,"\n")
		message := ReadFile(file_name)
		mail := NewMail(userKey, dest_PublicKey, message, dest_name, user_name)

		fmt.Println()

		WriteJSON(mail)

	case 2:
		fmt.Println("Check inbox option chosen\n")
		rcvMail := ReadJSON("mail_ready.json")
		_, pub := RcvDest()
		ReadMail(userKey, pub, rcvMail)
	case 3:
		fmt.Println("Goodbye thank you for choosing us\n")
		os.Exit(0)
	default:
		fmt.Println("Invalid Input\n")
	}
}

func RcvDest() (string, *rsa.PublicKey){

	//check if Contacts dir exists if not creates one
	rootpath, _ := os.Getwd()
	subpath := filepath.Join(rootpath, "Contacts")
	os.MkdirAll(subpath, os.ModePerm)

	//receive name of contact
	var recp_name = DataInput("Insert Recipient: ")

	//Check if contact exists
	subpath = filepath.Join(subpath, recp_name + "_PublicKey")
	_, err := os.Stat(subpath)

	if os.IsNotExist(err) {
		fmt.Printf("No such contact in Contacts list!\n")
		os.Exit(3)
	}

	fmt.Println("Contact found!\n")
	file_data, err := ioutil.ReadFile(subpath)
	checkError(err)
	pemdata, _ := pem.Decode(file_data)
	pub, err := x509.ParsePKIXPublicKey(pemdata.Bytes)
	checkError(err)

	return recp_name, pub.(*rsa.PublicKey)
}

func FileToSend()(string){
	//recieve name of file
	var file_name = DataInput("Insert name of file to send: ")

	//Check if file exists
	_, err := os.Stat(file_name)
	if os.IsNotExist(err) {
		fmt.Println(err.Error())
		os.Exit(3)
	} else{
		fmt.Println("File found!\n")
	}
	return file_name
}

func DataInput(msg string) (string){
	for{
		var data string
		fmt.Println(msg)
		n, err := fmt.Scanln(&data)
		if n < 1 || n > 2 || err != nil {
			fmt.Println("Invalid input\n")
		}else{
			return data
		}
	}
}
/*
func pwd(){
	//check if Users list file, with the passwords exists if not creates one
	_, err = os.Stat("users_list.txt")

	if os.IsNotExist(err){
		var users_list, err = os.Create(users_list)
		checkError(err)
		defer users_list.Close()
	}
	flag := DataInput("Press 1 for: Login Or 2 for: Sign up\n")
	if(flag = 1 || flag =2){
		username := DataInput("Insert Username:\n")
		pwd := DataInput("Insert Password:\n")

		if(flag = 1){
			pow = HashDigest(pwd + salt)

		}
		if(flag = 2){

		}

	}else{

	}
}*/
<|endoftext|>


<commit_before>// package bitswap implements the IPFS Exchange interface with the BitSwap
// bilateral exchange protocol.
package bitswap

import (
	"time"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"

	blocks "github.com/jbenet/go-ipfs/blocks"
	blockstore "github.com/jbenet/go-ipfs/blockstore"
	exchange "github.com/jbenet/go-ipfs/exchange"
	bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
	notifications "github.com/jbenet/go-ipfs/exchange/bitswap/notifications"
	strategy "github.com/jbenet/go-ipfs/exchange/bitswap/strategy"
	inet "github.com/jbenet/go-ipfs/net"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("bitswap")

// NetMessageSession initializes a BitSwap session that communicates over the
// provided NetMessage service.
// Runs until context is cancelled
func NetMessageSession(ctx context.Context, p peer.Peer,
	net inet.Network, srv inet.Service, directory bsnet.Routing,
	d ds.ThreadSafeDatastore, nice bool) exchange.Interface {

	networkAdapter := bsnet.NetMessageAdapter(srv, net, nil)

	notif := notifications.New()

	go func() {
		select {
		case <-ctx.Done():
			notif.Shutdown()
		}
	}()

	bs := &bitswap{
		blockstore:    blockstore.NewBlockstore(d),
		notifications: notif,
		strategy:      strategy.New(nice),
		routing:       directory,
		sender:        networkAdapter,
		wantlist:      u.NewKeySet(),
	}
	networkAdapter.SetDelegate(bs)

	return bs
}

// bitswap instances implement the bitswap protocol.
type bitswap struct {

	// sender delivers messages on behalf of the session
	sender bsnet.Adapter

	// blockstore is the local database
	// NB: ensure threadsafety
	blockstore blockstore.Blockstore

	// routing interface for communication
	routing bsnet.Routing

	notifications notifications.PubSub

	// strategy listens to network traffic and makes decisions about how to
	// interact with partners.
	// TODO(brian): save the strategy's state to the datastore
	strategy strategy.Strategy

	wantlist u.KeySet
}

// GetBlock attempts to retrieve a particular block from peers within the
// deadline enforced by the context
//
// TODO ensure only one active request per key
func (bs *bitswap) Block(parent context.Context, k u.Key) (*blocks.Block, error) {
	log.Debugf("Get Block %v", k)
	now := time.Now()
	defer func() {
		log.Debugf("GetBlock took %f secs", time.Now().Sub(now).Seconds())
	}()

	ctx, cancelFunc := context.WithCancel(parent)
	defer cancelFunc()

	bs.wantlist.Add(k)
	promise := bs.notifications.Subscribe(ctx, k)

	const maxProviders = 20
	peersToQuery := bs.routing.FindProvidersAsync(ctx, k, maxProviders)

	go func() {
		message := bsmsg.New()
		for _, wanted := range bs.wantlist.Keys() {
			message.AddWanted(wanted)
		}
		for peerToQuery := range peersToQuery {
			log.Debugf("bitswap got peersToQuery: %s", peerToQuery)
			go func(p peer.Peer) {

				log.Debugf("bitswap dialing peer: %s", p)
				err := bs.sender.DialPeer(ctx, p)
				if err != nil {
					log.Errorf("Error sender.DialPeer(%s)", p)
					return
				}

				response, err := bs.sender.SendRequest(ctx, p, message)
				if err != nil {
					log.Errorf("Error sender.SendRequest(%s) = %s", p, err)
					return
				}
				// FIXME ensure accounting is handled correctly when
				// communication fails. May require slightly different API to
				// get better guarantees. May need shared sequence numbers.
				bs.strategy.MessageSent(p, message)

				if response == nil {
					return
				}
				bs.ReceiveMessage(ctx, p, response)
			}(peerToQuery)
		}
	}()

	select {
	case block := <-promise:
		bs.wantlist.Remove(k)
		return &block, nil
	case <-parent.Done():
		return nil, parent.Err()
	}
}

// HasBlock announces the existance of a block to this bitswap service. The
// service will potentially notify its peers.
func (bs *bitswap) HasBlock(ctx context.Context, blk blocks.Block) error {
	log.Debugf("Has Block %v", blk.Key())
	bs.wantlist.Remove(blk.Key())
	bs.sendToPeersThatWant(ctx, blk)
	return bs.routing.Provide(ctx, blk.Key())
}

// TODO(brian): handle errors
func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) (
	peer.Peer, bsmsg.BitSwapMessage) {
	log.Debugf("ReceiveMessage from %v", p.Key())
	log.Debugf("Message wantlist: %v", incoming.Wantlist())

	if p == nil {
		log.Error("Received message from nil peer!")
		// TODO propagate the error upward
		return nil, nil
	}
	if incoming == nil {
		log.Error("Got nil bitswap message!")
		// TODO propagate the error upward
		return nil, nil
	}

	// Record message bytes in ledger
	// TODO: this is bad, and could be easily abused.
	// Should only track *useful* messages in ledger
	bs.strategy.MessageReceived(p, incoming) // FIRST

	for _, block := range incoming.Blocks() {
		// TODO verify blocks?
		if err := bs.blockstore.Put(&block); err != nil {
			continue // FIXME(brian): err ignored
		}
		bs.notifications.Publish(block)
		err := bs.HasBlock(ctx, block)
		if err != nil {
			log.Warningf("HasBlock errored: %s", err)
		}
	}

	message := bsmsg.New()
	for _, wanted := range bs.wantlist.Keys() {
		message.AddWanted(wanted)
	}
	for _, key := range incoming.Wantlist() {
		// TODO: might be better to check if we have the block before checking
		//			if we should send it to someone
		if bs.strategy.ShouldSendBlockToPeer(key, p) {
			if block, errBlockNotFound := bs.blockstore.Get(key); errBlockNotFound != nil {
				continue
			} else {
				message.AddBlock(*block)
			}
		}
	}
	defer bs.strategy.MessageSent(p, message)

	log.Debug("Returning message.")
	return p, message
}

func (bs *bitswap) ReceiveError(err error) {
	log.Errorf("Bitswap ReceiveError: %s", err)
	// TODO log the network error
	// TODO bubble the network error up to the parent context/error logger
}

// send strives to ensure that accounting is always performed when a message is
// sent
func (bs *bitswap) send(ctx context.Context, p peer.Peer, m bsmsg.BitSwapMessage) {
	bs.sender.SendMessage(ctx, p, m)
	bs.strategy.MessageSent(p, m)
}

func (bs *bitswap) sendToPeersThatWant(ctx context.Context, block blocks.Block) {
	log.Debugf("Sending %v to peers that want it", block.Key())

	for _, p := range bs.strategy.Peers() {
		if bs.strategy.BlockIsWantedByPeer(block.Key(), p) {
			log.Debugf("%v wants %v", p, block.Key())
			if bs.strategy.ShouldSendBlockToPeer(block.Key(), p) {
				message := bsmsg.New()
				message.AddBlock(block)
				for _, wanted := range bs.wantlist.Keys() {
					message.AddWanted(wanted)
				}
				bs.send(ctx, p, message)
			}
		}
	}
}
<commit_msg>style(bitswap) rename variable to 'routing'<commit_after>// package bitswap implements the IPFS Exchange interface with the BitSwap
// bilateral exchange protocol.
package bitswap

import (
	"time"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"

	blocks "github.com/jbenet/go-ipfs/blocks"
	blockstore "github.com/jbenet/go-ipfs/blockstore"
	exchange "github.com/jbenet/go-ipfs/exchange"
	bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
	notifications "github.com/jbenet/go-ipfs/exchange/bitswap/notifications"
	strategy "github.com/jbenet/go-ipfs/exchange/bitswap/strategy"
	inet "github.com/jbenet/go-ipfs/net"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("bitswap")

// NetMessageSession initializes a BitSwap session that communicates over the
// provided NetMessage service.
// Runs until context is cancelled
func NetMessageSession(ctx context.Context, p peer.Peer,
	net inet.Network, srv inet.Service, routing bsnet.Routing,
	d ds.ThreadSafeDatastore, nice bool) exchange.Interface {

	networkAdapter := bsnet.NetMessageAdapter(srv, net, nil)

	notif := notifications.New()

	go func() {
		select {
		case <-ctx.Done():
			notif.Shutdown()
		}
	}()

	bs := &bitswap{
		blockstore:    blockstore.NewBlockstore(d),
		notifications: notif,
		strategy:      strategy.New(nice),
		routing:       routing,
		sender:        networkAdapter,
		wantlist:      u.NewKeySet(),
	}
	networkAdapter.SetDelegate(bs)

	return bs
}

// bitswap instances implement the bitswap protocol.
type bitswap struct {

	// sender delivers messages on behalf of the session
	sender bsnet.Adapter

	// blockstore is the local database
	// NB: ensure threadsafety
	blockstore blockstore.Blockstore

	// routing interface for communication
	routing bsnet.Routing

	notifications notifications.PubSub

	// strategy listens to network traffic and makes decisions about how to
	// interact with partners.
	// TODO(brian): save the strategy's state to the datastore
	strategy strategy.Strategy

	wantlist u.KeySet
}

// GetBlock attempts to retrieve a particular block from peers within the
// deadline enforced by the context
//
// TODO ensure only one active request per key
func (bs *bitswap) Block(parent context.Context, k u.Key) (*blocks.Block, error) {
	log.Debugf("Get Block %v", k)
	now := time.Now()
	defer func() {
		log.Debugf("GetBlock took %f secs", time.Now().Sub(now).Seconds())
	}()

	ctx, cancelFunc := context.WithCancel(parent)
	defer cancelFunc()

	bs.wantlist.Add(k)
	promise := bs.notifications.Subscribe(ctx, k)

	const maxProviders = 20
	peersToQuery := bs.routing.FindProvidersAsync(ctx, k, maxProviders)

	go func() {
		message := bsmsg.New()
		for _, wanted := range bs.wantlist.Keys() {
			message.AddWanted(wanted)
		}
		for peerToQuery := range peersToQuery {
			log.Debugf("bitswap got peersToQuery: %s", peerToQuery)
			go func(p peer.Peer) {

				log.Debugf("bitswap dialing peer: %s", p)
				err := bs.sender.DialPeer(ctx, p)
				if err != nil {
					log.Errorf("Error sender.DialPeer(%s)", p)
					return
				}

				response, err := bs.sender.SendRequest(ctx, p, message)
				if err != nil {
					log.Errorf("Error sender.SendRequest(%s) = %s", p, err)
					return
				}
				// FIXME ensure accounting is handled correctly when
				// communication fails. May require slightly different API to
				// get better guarantees. May need shared sequence numbers.
				bs.strategy.MessageSent(p, message)

				if response == nil {
					return
				}
				bs.ReceiveMessage(ctx, p, response)
			}(peerToQuery)
		}
	}()

	select {
	case block := <-promise:
		bs.wantlist.Remove(k)
		return &block, nil
	case <-parent.Done():
		return nil, parent.Err()
	}
}

// HasBlock announces the existance of a block to this bitswap service. The
// service will potentially notify its peers.
func (bs *bitswap) HasBlock(ctx context.Context, blk blocks.Block) error {
	log.Debugf("Has Block %v", blk.Key())
	bs.wantlist.Remove(blk.Key())
	bs.sendToPeersThatWant(ctx, blk)
	return bs.routing.Provide(ctx, blk.Key())
}

// TODO(brian): handle errors
func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) (
	peer.Peer, bsmsg.BitSwapMessage) {
	log.Debugf("ReceiveMessage from %v", p.Key())
	log.Debugf("Message wantlist: %v", incoming.Wantlist())

	if p == nil {
		log.Error("Received message from nil peer!")
		// TODO propagate the error upward
		return nil, nil
	}
	if incoming == nil {
		log.Error("Got nil bitswap message!")
		// TODO propagate the error upward
		return nil, nil
	}

	// Record message bytes in ledger
	// TODO: this is bad, and could be easily abused.
	// Should only track *useful* messages in ledger
	bs.strategy.MessageReceived(p, incoming) // FIRST

	for _, block := range incoming.Blocks() {
		// TODO verify blocks?
		if err := bs.blockstore.Put(&block); err != nil {
			continue // FIXME(brian): err ignored
		}
		bs.notifications.Publish(block)
		err := bs.HasBlock(ctx, block)
		if err != nil {
			log.Warningf("HasBlock errored: %s", err)
		}
	}

	message := bsmsg.New()
	for _, wanted := range bs.wantlist.Keys() {
		message.AddWanted(wanted)
	}
	for _, key := range incoming.Wantlist() {
		// TODO: might be better to check if we have the block before checking
		//			if we should send it to someone
		if bs.strategy.ShouldSendBlockToPeer(key, p) {
			if block, errBlockNotFound := bs.blockstore.Get(key); errBlockNotFound != nil {
				continue
			} else {
				message.AddBlock(*block)
			}
		}
	}
	defer bs.strategy.MessageSent(p, message)

	log.Debug("Returning message.")
	return p, message
}

func (bs *bitswap) ReceiveError(err error) {
	log.Errorf("Bitswap ReceiveError: %s", err)
	// TODO log the network error
	// TODO bubble the network error up to the parent context/error logger
}

// send strives to ensure that accounting is always performed when a message is
// sent
func (bs *bitswap) send(ctx context.Context, p peer.Peer, m bsmsg.BitSwapMessage) {
	bs.sender.SendMessage(ctx, p, m)
	bs.strategy.MessageSent(p, m)
}

func (bs *bitswap) sendToPeersThatWant(ctx context.Context, block blocks.Block) {
	log.Debugf("Sending %v to peers that want it", block.Key())

	for _, p := range bs.strategy.Peers() {
		if bs.strategy.BlockIsWantedByPeer(block.Key(), p) {
			log.Debugf("%v wants %v", p, block.Key())
			if bs.strategy.ShouldSendBlockToPeer(block.Key(), p) {
				message := bsmsg.New()
				message.AddBlock(block)
				for _, wanted := range bs.wantlist.Keys() {
					message.AddWanted(wanted)
				}
				bs.send(ctx, p, message)
			}
		}
	}
}
<|endoftext|>