<commit_before>package controllers

import (
	"github.com/astaxie/beego"
	"github.com/scmo/apayment-backend/models"
	"encoding/json"
	"github.com/scmo/apayment-backend/services"
	"strconv"
	"github.com/scmo/apayment-backend/ethereum"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
	"time"
)

// Operations about Contributions
type RequestController struct {
	beego.Controller
}

// @Title Create a new Request
// @Description Endpoint to create a new Request
// @Param	body		body 	models.Request	true		"body for request content"
// @Success 200 {Object} models.Request
// @Failure 403 body is empty
// @router / [post]
func (this *RequestController) Post() {
	var request models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}
	request.User = user

	err = services.CreateRequest(&request, ethereum.GetAuth(user.Address))
	if err != nil {
		this.CustomAbort(500, err.Error())
	}
	go func() {
		// wait till contract created
		time.Sleep(time.Minute * 2)
		// Update GVE for the request
		err = services.SetGVE(&request)
		if (err != nil ) {
			this.CustomAbort(500, err.Error())
		}
	}()

	this.ServeJSON()
}

// @Title Get
// @Description find request by requestID
// @Param jwtToken header string true "jwt Token for Authorization"
// @Param	requestId		path 	string	true		"the requestid you want to get"
// @Success 200 {object} models.Request
// @Failure 403 :requestId is empty
// @router /:requestId [get]
func (this *RequestController) Get() {
	input := this.Ctx.Input.Param(":requestId")
	requestId, err := strconv.ParseInt(input, 10, 64)
	if err != nil {
		beego.Error(err)
	}
	this.Data["json"] = services.GetRequestById(requestId)
	this.ServeJSON()
}

// @Title GetAll
// @Description get all request
// @Success 200 {object} models.Request
// @router / [get]
func (this *RequestController) GetAll() {
	requests := []*models.Request{}

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if (user.HasRole("Farmer")) {
		requests = services.GetAllRequestsByUserId(user.Id)
	} else if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		requests = services.GetAllRequests()
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = requests
	this.ServeJSON()
}

// @Title GetAll
// @Description get all request which have an inspector assigned
// @Success 200 {object} models.Request
// @router /inspection [get]
func (this *RequestController) GetAllForInspection() {
	requests := []*models.Request{}
	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if (user.HasRole("Inspector")) {
		requests = services.GetAllRequestsForInspectionByInspectorId(user.Id)
	} else if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		requests = services.GetAllRequestsForInspection()
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = requests
	this.ServeJSON()
}

// @Title Add Inspector
// @Description add Inspector to Requestion
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /inspector [put]
func (this *RequestController) AddInspector() {
	var request models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		//requests = services.GetAllRequests()
		services.AddInspectorToRequest(&request, ethereum.GetAuth(user.Address))
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = request
	this.ServeJSON()
}

// @Title Add Inspection
// @Description Add the report of the inspection
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /inspection [post]
func (this *RequestController) AddInspection() {
	var inspection models.Inspection
	json.Unmarshal(this.Ctx.Input.RequestBody, &inspection)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}
	if ( user.HasRole("Admin") || user.HasRole("Inspector")) {
		//inspection.InspectorId = user.Id
	} else {
		this.CustomAbort(401, "Unauthorized")
	}
	err = services.AddLacksToRequest(&inspection, ethereum.GetAuth(user.Address))
	if err != nil {
		this.CustomAbort(500, err.Error())
	}
	this.Data["json"] = inspection
	this.ServeJSON()
}

// @Title Update GVE
// @Description Update GVE of request
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @Failure 403 :requestId is empty
// @router /gve [put]
func (this *RequestController) UpdateGVE() {
	var request models.Request

	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( ( user.HasRole("Admin") || user.HasRole("Canton") ) || user.Address == request.User.Address) {
		err = services.SetGVE(&request)
		if (err != nil ) {
			this.CustomAbort(500, err.Error())
		}
	}

	this.Data["json"] = request
	this.ServeJSON()
}

// @Title Pay DirectPayment
// @Description Update GVE of request
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /pay [post]
func (this *RequestController) Pay() {

	var r models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &r)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( ( user.HasRole("Admin") || user.HasRole("Canton") ) == false ) {
		this.CustomAbort(401, "Unauthorized")
	}

	request := services.GetRequestById(r.Id)

	if ( len(request.Payments) == 0 ) {
		beego.Debug("make first payment")
		amount, err := services.GetFirstPaymentAmount(request)
		if (err != nil) {
			beego.Error("Error while getting first payment amount. ", err)
			this.CustomAbort(500, err.Error())
		}
		amount.Div(amount, big.NewInt(2)) // 50% of the amount
		err = services.Transfer(common.HexToAddress(user.Address), common.HexToAddress(request.User.Address), amount)
		if err != nil {
			beego.Debug("Error while transfer")
			this.CustomAbort(500, err.Error())
		}
		err = services.AddPayment(request, common.HexToAddress(user.Address), amount)
		if err != nil {
			beego.Debug("Error while adding payment to smartcontract")
			this.CustomAbort(500, err.Error())
		}
	} else if ( len(request.Payments) == 1 ) {
		beego.Debug("make second payment")
		services.AddPayment(request, common.HexToAddress(user.Address), big.NewInt(333))
	} else if ( len(request.Payments) == 2 ) {
		beego.Debug("make third payment")
	}

	request = services.GetRequestById(r.Id)
	this.Data["json"] = request
	this.ServeJSON()
}<commit_msg>sync GVE after 1 minute<commit_after>package controllers

import (
	"github.com/astaxie/beego"
	"github.com/scmo/apayment-backend/models"
	"encoding/json"
	"github.com/scmo/apayment-backend/services"
	"strconv"
	"github.com/scmo/apayment-backend/ethereum"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
	"time"
)

// Operations about Contributions
type RequestController struct {
	beego.Controller
}

// @Title Create a new Request
// @Description Endpoint to create a new Request
// @Param	body		body 	models.Request	true		"body for request content"
// @Success 200 {Object} models.Request
// @Failure 403 body is empty
// @router / [post]
func (this *RequestController) Post() {
	var request models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}
	request.User = user

	err = services.CreateRequest(&request, ethereum.GetAuth(user.Address))
	if err != nil {
		this.CustomAbort(500, err.Error())
	}
	go func() {
		// wait till contract created
		time.Sleep(time.Minute * 1)
		// Update GVE for the request
		err = services.SetGVE(&request)
		if (err != nil ) {
			this.CustomAbort(500, err.Error())
		}
	}()

	this.ServeJSON()
}

// @Title Get
// @Description find request by requestID
// @Param jwtToken header string true "jwt Token for Authorization"
// @Param	requestId		path 	string	true		"the requestid you want to get"
// @Success 200 {object} models.Request
// @Failure 403 :requestId is empty
// @router /:requestId [get]
func (this *RequestController) Get() {
	input := this.Ctx.Input.Param(":requestId")
	requestId, err := strconv.ParseInt(input, 10, 64)
	if err != nil {
		beego.Error(err)
	}
	this.Data["json"] = services.GetRequestById(requestId)
	this.ServeJSON()
}

// @Title GetAll
// @Description get all request
// @Success 200 {object} models.Request
// @router / [get]
func (this *RequestController) GetAll() {
	requests := []*models.Request{}

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if (user.HasRole("Farmer")) {
		requests = services.GetAllRequestsByUserId(user.Id)
	} else if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		requests = services.GetAllRequests()
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = requests
	this.ServeJSON()
}

// @Title GetAll
// @Description get all request which have an inspector assigned
// @Success 200 {object} models.Request
// @router /inspection [get]
func (this *RequestController) GetAllForInspection() {
	requests := []*models.Request{}
	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if (user.HasRole("Inspector")) {
		requests = services.GetAllRequestsForInspectionByInspectorId(user.Id)
	} else if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		requests = services.GetAllRequestsForInspection()
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = requests
	this.ServeJSON()
}

// @Title Add Inspector
// @Description add Inspector to Requestion
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /inspector [put]
func (this *RequestController) AddInspector() {
	var request models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( user.HasRole("Admin") || user.HasRole("Canton")) {
		//requests = services.GetAllRequests()
		services.AddInspectorToRequest(&request, ethereum.GetAuth(user.Address))
	} else {
		this.CustomAbort(401, "Unauthorized")
	}

	this.Data["json"] = request
	this.ServeJSON()
}

// @Title Add Inspection
// @Description Add the report of the inspection
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /inspection [post]
func (this *RequestController) AddInspection() {
	var inspection models.Inspection
	json.Unmarshal(this.Ctx.Input.RequestBody, &inspection)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}
	if ( user.HasRole("Admin") || user.HasRole("Inspector")) {
		//inspection.InspectorId = user.Id
	} else {
		this.CustomAbort(401, "Unauthorized")
	}
	err = services.AddLacksToRequest(&inspection, ethereum.GetAuth(user.Address))
	if err != nil {
		this.CustomAbort(500, err.Error())
	}
	this.Data["json"] = inspection
	this.ServeJSON()
}

// @Title Update GVE
// @Description Update GVE of request
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @Failure 403 :requestId is empty
// @router /gve [put]
func (this *RequestController) UpdateGVE() {
	var request models.Request

	json.Unmarshal(this.Ctx.Input.RequestBody, &request)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( ( user.HasRole("Admin") || user.HasRole("Canton") ) || user.Address == request.User.Address) {
		err = services.SetGVE(&request)
		if (err != nil ) {
			this.CustomAbort(500, err.Error())
		}
	}

	this.Data["json"] = request
	this.ServeJSON()
}

// @Title Pay DirectPayment
// @Description Update GVE of request
// @Param	body		body 	models.Request	true		"body for requestion content"
// @Success 200 {object} models.Request
// @router /pay [post]
func (this *RequestController) Pay() {

	var r models.Request
	json.Unmarshal(this.Ctx.Input.RequestBody, &r)

	claims, _ := services.ParseToken(this.Ctx.Request.Header.Get("Authorization"))
	user, err := services.GetUserByUsername(claims.Subject)
	if err != nil {
		this.CustomAbort(404, err.Error())
	}

	if ( ( user.HasRole("Admin") || user.HasRole("Canton") ) == false ) {
		this.CustomAbort(401, "Unauthorized")
	}

	request := services.GetRequestById(r.Id)

	if ( len(request.Payments) == 0 ) {
		beego.Debug("make first payment")
		amount, err := services.GetFirstPaymentAmount(request)
		if (err != nil) {
			beego.Error("Error while getting first payment amount. ", err)
			this.CustomAbort(500, err.Error())
		}
		amount.Div(amount, big.NewInt(2)) // 50% of the amount
		err = services.Transfer(common.HexToAddress(user.Address), common.HexToAddress(request.User.Address), amount)
		if err != nil {
			beego.Debug("Error while transfer")
			this.CustomAbort(500, err.Error())
		}
		err = services.AddPayment(request, common.HexToAddress(user.Address), amount)
		if err != nil {
			beego.Debug("Error while adding payment to smartcontract")
			this.CustomAbort(500, err.Error())
		}
	} else if ( len(request.Payments) == 1 ) {
		beego.Debug("make second payment")
		services.AddPayment(request, common.HexToAddress(user.Address), big.NewInt(333))
	} else if ( len(request.Payments) == 2 ) {
		beego.Debug("make third payment")
	}

	request = services.GetRequestById(r.Id)
	this.Data["json"] = request
	this.ServeJSON()
}<|endoftext|>


<commit_before>package gogrs

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type memData map[int64][][]string

// DailyData start with stock no, date.
type DailyData struct {
	No      string
	Date    time.Time
	RawData [][]string
	hasData memData
}

// URL return stock csv url path.
func (d DailyData) URL() string {
	path := fmt.Sprintf(TWSECSV, d.Date.Year(), d.Date.Month(), d.Date.Year(), d.Date.Month(), d.No, RandInt())
	return fmt.Sprintf("%s%s", TWSEHOST, path)
}

// Round will do sub one month.
func (d *DailyData) Round() {
	year, month, _ := d.Date.Date()
	d.Date = time.Date(year, month-1, 1, 0, 0, 0, 0, time.UTC)
}

// GetData return csv data in array.
func (d *DailyData) GetData() ([][]string, error) {
	if d.hasData == nil {
		d.hasData = make(memData)
	}
	if len(d.hasData[d.Date.Unix()]) == 0 {
		csvFiles, err := http.Get(d.URL())
		if err != nil {
			return nil, fmt.Errorf("Network fail: %s", err)
		}
		defer csvFiles.Body.Close()
		data, _ := ioutil.ReadAll(csvFiles.Body)
		csvArrayContent := strings.Split(string(data), "\n")
		for i := range csvArrayContent {
			csvArrayContent[i] = strings.TrimSpace(csvArrayContent[i])
		}
		if len(csvArrayContent) > 2 {
			csvReader := csv.NewReader(strings.NewReader(strings.Join(csvArrayContent[2:], "\n")))
			allData, err := csvReader.ReadAll()
			d.RawData = append(allData, d.RawData...)
			d.hasData[d.Date.Unix()] = allData
			return allData, err
		}
		return nil, errors.New("Not enough data.")
	}
	return d.hasData[d.Date.Unix()], nil
}

// GetDataByTimeMap return a map by key of time.Time
func (d DailyData) GetDataByTimeMap() map[time.Time]interface{} {
	data := make(map[time.Time]interface{})
	dailyData, _ := d.GetData()
	for _, v := range dailyData {
		data[ParseDate(v[0])] = v
	}
	return data
}

func (d DailyData) GetColsList(colsNo int) []interface{} {
	var result []interface{}
	result = make([]interface{}, len(d.RawData))
	for i, value := range d.RawData {
		result[i] = value[colsNo]
	}
	return result
}

// FmtDailyData is struct for daily data format.
type FmtDailyData struct {
	Date       time.Time
	Volume     uint64
	TotalPrice uint64
	Open       float64
	High       float64
	Low        float64
	Price      float64
	Range      float64
	Totalsale  uint64
}

// FormatDailyData is format daily data.
func (d DailyData) FormatDailyData() []FmtDailyData {
	result := make([]FmtDailyData, len(d.RawData))
	var loopd FmtDailyData
	for i, v := range d.RawData {
		loopd.Date = ParseDate(v[0])

		volume, _ := strconv.ParseUint(strings.Replace(v[1], ",", "", -1), 10, 32)
		loopd.Volume = volume

		totalprice, _ := strconv.ParseUint(strings.Replace(v[2], ",", "", -1), 10, 32)
		loopd.TotalPrice = totalprice

		open, _ := strconv.ParseFloat(v[3], 64)
		loopd.Open = open

		high, _ := strconv.ParseFloat(v[4], 64)
		loopd.High = high

		low, _ := strconv.ParseFloat(v[5], 64)
		loopd.Low = low

		price, _ := strconv.ParseFloat(v[6], 64)
		loopd.Price = price

		rangeData, _ := strconv.ParseFloat(v[7], 64)
		loopd.Range = rangeData

		totalsale, _ := strconv.ParseUint(strings.Replace(v[8], ",", "", -1), 10, 64)
		loopd.Totalsale = totalsale

		result[i] = loopd
	}
	return result
}
<commit_msg>Add `GetVolumeList`.<commit_after>package gogrs

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type memData map[int64][][]string

// DailyData start with stock no, date.
type DailyData struct {
	No      string
	Date    time.Time
	RawData [][]string
	hasData memData
}

// URL return stock csv url path.
func (d DailyData) URL() string {
	path := fmt.Sprintf(TWSECSV, d.Date.Year(), d.Date.Month(), d.Date.Year(), d.Date.Month(), d.No, RandInt())
	return fmt.Sprintf("%s%s", TWSEHOST, path)
}

// Round will do sub one month.
func (d *DailyData) Round() {
	year, month, _ := d.Date.Date()
	d.Date = time.Date(year, month-1, 1, 0, 0, 0, 0, time.UTC)
}

// GetData return csv data in array.
func (d *DailyData) GetData() ([][]string, error) {
	if d.hasData == nil {
		d.hasData = make(memData)
	}
	if len(d.hasData[d.Date.Unix()]) == 0 {
		csvFiles, err := http.Get(d.URL())
		if err != nil {
			return nil, fmt.Errorf("Network fail: %s", err)
		}
		defer csvFiles.Body.Close()
		data, _ := ioutil.ReadAll(csvFiles.Body)
		csvArrayContent := strings.Split(string(data), "\n")
		for i := range csvArrayContent {
			csvArrayContent[i] = strings.TrimSpace(csvArrayContent[i])
		}
		if len(csvArrayContent) > 2 {
			csvReader := csv.NewReader(strings.NewReader(strings.Join(csvArrayContent[2:], "\n")))
			allData, err := csvReader.ReadAll()
			d.RawData = append(allData, d.RawData...)
			d.hasData[d.Date.Unix()] = allData
			return allData, err
		}
		return nil, errors.New("Not enough data.")
	}
	return d.hasData[d.Date.Unix()], nil
}

// GetDataByTimeMap return a map by key of time.Time
func (d DailyData) GetDataByTimeMap() map[time.Time]interface{} {
	data := make(map[time.Time]interface{})
	dailyData, _ := d.GetData()
	for _, v := range dailyData {
		data[ParseDate(v[0])] = v
	}
	return data
}

func (d DailyData) getColsList(colsNo int) []string {
	var result []string
	result = make([]string, len(d.RawData))
	for i, value := range d.RawData {
		result[i] = value[colsNo]
	}
	return result
}

func (d DailyData) GetVolumeList() []uint64 {
	var result []uint64
	result = make([]uint64, len(d.RawData))
	for i, v := range d.getColsList(1) {
		result[i], _ = strconv.ParseUint(strings.Replace(v, ",", "", -1), 10, 64)
	}
	return result
}

// FmtDailyData is struct for daily data format.
type FmtDailyData struct {
	Date       time.Time
	Volume     uint64
	TotalPrice uint64
	Open       float64
	High       float64
	Low        float64
	Price      float64
	Range      float64
	Totalsale  uint64
}

// FormatDailyData is format daily data.
func (d DailyData) FormatDailyData() []FmtDailyData {
	result := make([]FmtDailyData, len(d.RawData))
	var loopd FmtDailyData
	for i, v := range d.RawData {
		loopd.Date = ParseDate(v[0])

		volume, _ := strconv.ParseUint(strings.Replace(v[1], ",", "", -1), 10, 32)
		loopd.Volume = volume

		totalprice, _ := strconv.ParseUint(strings.Replace(v[2], ",", "", -1), 10, 32)
		loopd.TotalPrice = totalprice

		open, _ := strconv.ParseFloat(v[3], 64)
		loopd.Open = open

		high, _ := strconv.ParseFloat(v[4], 64)
		loopd.High = high

		low, _ := strconv.ParseFloat(v[5], 64)
		loopd.Low = low

		price, _ := strconv.ParseFloat(v[6], 64)
		loopd.Price = price

		rangeData, _ := strconv.ParseFloat(v[7], 64)
		loopd.Range = rangeData

		totalsale, _ := strconv.ParseUint(strings.Replace(v[8], ",", "", -1), 10, 64)
		loopd.Totalsale = totalsale

		result[i] = loopd
	}
	return result
}
<|endoftext|>


<commit_before>package telebot

import (
	"strconv"
	"time"
)

// User object represents a Telegram user, bot.
type User struct {
	ID int64 `json:"id"`

	FirstName    string `json:"first_name"`
	LastName     string `json:"last_name"`
	Username     string `json:"username"`
	LanguageCode string `json:"language_code"`
	IsBot        bool   `json:"is_bot"`

	// Returns only in getMe
	CanJoinGroups   bool `json:"can_join_groups"`
	CanReadMessages bool `json:"can_read_all_group_messages"`
	SupportsInline  bool `json:"supports_inline_queries"`
}

// Recipient returns user ID (see Recipient interface).
func (u *User) Recipient() string {
	return strconv.FormatInt(u.ID, 10)
}

// Chat object represents a Telegram user, bot, group or a channel.
type Chat struct {
	ID int64 `json:"id"`

	// See ChatType and consts.
	Type ChatType `json:"type"`

	// Won't be there for ChatPrivate.
	Title string `json:"title"`

	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Username  string `json:"username"`

	// Still shows whether the user is a member
	// of the chat at the moment of the request.
	Still bool `json:"is_member,omitempty"`

	// Returns only in getChat
	Bio              string        `json:"bio,omitempty"`
	Photo            *ChatPhoto    `json:"photo,omitempty"`
	Description      string        `json:"description,omitempty"`
	InviteLink       string        `json:"invite_link,omitempty"`
	PinnedMessage    *Message      `json:"pinned_message,omitempty"`
	Permissions      *Rights       `json:"permissions,omitempty"`
	SlowMode         int           `json:"slow_mode_delay,omitempty"`
	StickerSet       string        `json:"sticker_set_name,omitempty"`
	CanSetStickerSet bool          `json:"can_set_sticker_set,omitempty"`
	LinkedChatID     int64         `json:"linked_chat_id,omitempty"`
	ChatLocation     *ChatLocation `json:"location,omitempty"`
}

type ChatLocation struct {
	Location Location `json:"location,omitempty"`
	Address  string   `json:"address,omitempty"`
}

// ChatPhoto object represents a chat photo.
type ChatPhoto struct {
	// File identifiers of small (160x160) chat photo
	SmallFileID   string `json:"small_file_id"`
	SmallUniqueID string `json:"small_file_unique_id"`

	// File identifiers of big (640x640) chat photo
	BigFileID   string `json:"big_file_id"`
	BigUniqueID string `json:"big_file_unique_id"`
}

// Recipient returns chat ID (see Recipient interface).
func (c *Chat) Recipient() string {
	return strconv.FormatInt(c.ID, 10)
}

// ChatMember object represents information about a single chat member.
type ChatMember struct {
	Rights

	User      *User        `json:"user"`
	Role      MemberStatus `json:"status"`
	Title     string       `json:"custom_title"`
	Anonymous bool         `json:"is_anonymous"`

	// Date when restrictions will be lifted for the user, unix time.
	//
	// If user is restricted for more than 366 days or less than
	// 30 seconds from the current time, they are considered to be
	// restricted forever.
	//
	// Use tele.Forever().
	//
	RestrictedUntil int64 `json:"until_date,omitempty"`
}

// ChatID represents a chat or an user integer ID, which can be used
// as recipient in bot methods. It is very useful in cases where
// you have special group IDs, for example in your config, and don't
// want to wrap it into *tele.Chat every time you send messages.
//
// Example:
//
//		group := tele.ChatID(-100756389456)
//		b.Send(group, "Hello!")
//
//		type Config struct {
//			AdminGroup tele.ChatID `json:"admin_group"`
//		}
//		b.Send(conf.AdminGroup, "Hello!")
//
type ChatID int64

// Recipient returns chat ID (see Recipient interface).
func (i ChatID) Recipient() string {
	return strconv.FormatInt(int64(i), 10)
}

// ChatJoinRequest represents a join request sent to a chat.
type ChatJoinRequest struct {
	// Chat to which the request was sent.
	Chat *Chat `json:"chat"`

	// Sender is the user that sent the join request.
	Sender *User `json:"user"`

	// Unixtime, use ChatJoinRequest.Time() to get time.Time.
	Unixtime int64 `json:"date"`

	// Bio of the user, optional.
	Bio string `json:"bio"`

	// InviteLink is the chat invite link that was used by
	//the user to send the join request, optional.
	InviteLink *ChatInviteLink `json:"invite_link"`
}

// Time returns the moment of chat join request sending in local time.
func (r ChatJoinRequest) Time() time.Time {
	return time.Unix(r.Unixtime, 0)
}
<commit_msg>chat: fix chat join request Sender field<commit_after>package telebot

import (
	"strconv"
	"time"
)

// User object represents a Telegram user, bot.
type User struct {
	ID int64 `json:"id"`

	FirstName    string `json:"first_name"`
	LastName     string `json:"last_name"`
	Username     string `json:"username"`
	LanguageCode string `json:"language_code"`
	IsBot        bool   `json:"is_bot"`

	// Returns only in getMe
	CanJoinGroups   bool `json:"can_join_groups"`
	CanReadMessages bool `json:"can_read_all_group_messages"`
	SupportsInline  bool `json:"supports_inline_queries"`
}

// Recipient returns user ID (see Recipient interface).
func (u *User) Recipient() string {
	return strconv.FormatInt(u.ID, 10)
}

// Chat object represents a Telegram user, bot, group or a channel.
type Chat struct {
	ID int64 `json:"id"`

	// See ChatType and consts.
	Type ChatType `json:"type"`

	// Won't be there for ChatPrivate.
	Title string `json:"title"`

	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Username  string `json:"username"`

	// Still shows whether the user is a member
	// of the chat at the moment of the request.
	Still bool `json:"is_member,omitempty"`

	// Returns only in getChat
	Bio              string        `json:"bio,omitempty"`
	Photo            *ChatPhoto    `json:"photo,omitempty"`
	Description      string        `json:"description,omitempty"`
	InviteLink       string        `json:"invite_link,omitempty"`
	PinnedMessage    *Message      `json:"pinned_message,omitempty"`
	Permissions      *Rights       `json:"permissions,omitempty"`
	SlowMode         int           `json:"slow_mode_delay,omitempty"`
	StickerSet       string        `json:"sticker_set_name,omitempty"`
	CanSetStickerSet bool          `json:"can_set_sticker_set,omitempty"`
	LinkedChatID     int64         `json:"linked_chat_id,omitempty"`
	ChatLocation     *ChatLocation `json:"location,omitempty"`
}

type ChatLocation struct {
	Location Location `json:"location,omitempty"`
	Address  string   `json:"address,omitempty"`
}

// ChatPhoto object represents a chat photo.
type ChatPhoto struct {
	// File identifiers of small (160x160) chat photo
	SmallFileID   string `json:"small_file_id"`
	SmallUniqueID string `json:"small_file_unique_id"`

	// File identifiers of big (640x640) chat photo
	BigFileID   string `json:"big_file_id"`
	BigUniqueID string `json:"big_file_unique_id"`
}

// Recipient returns chat ID (see Recipient interface).
func (c *Chat) Recipient() string {
	return strconv.FormatInt(c.ID, 10)
}

// ChatMember object represents information about a single chat member.
type ChatMember struct {
	Rights

	User      *User        `json:"user"`
	Role      MemberStatus `json:"status"`
	Title     string       `json:"custom_title"`
	Anonymous bool         `json:"is_anonymous"`

	// Date when restrictions will be lifted for the user, unix time.
	//
	// If user is restricted for more than 366 days or less than
	// 30 seconds from the current time, they are considered to be
	// restricted forever.
	//
	// Use tele.Forever().
	//
	RestrictedUntil int64 `json:"until_date,omitempty"`
}

// ChatID represents a chat or an user integer ID, which can be used
// as recipient in bot methods. It is very useful in cases where
// you have special group IDs, for example in your config, and don't
// want to wrap it into *tele.Chat every time you send messages.
//
// Example:
//
//		group := tele.ChatID(-100756389456)
//		b.Send(group, "Hello!")
//
//		type Config struct {
//			AdminGroup tele.ChatID `json:"admin_group"`
//		}
//		b.Send(conf.AdminGroup, "Hello!")
//
type ChatID int64

// Recipient returns chat ID (see Recipient interface).
func (i ChatID) Recipient() string {
	return strconv.FormatInt(int64(i), 10)
}

// ChatJoinRequest represents a join request sent to a chat.
type ChatJoinRequest struct {
	// Chat to which the request was sent.
	Chat *Chat `json:"chat"`

	// Sender is the user that sent the join request.
	Sender *User `json:"from"`

	// Unixtime, use ChatJoinRequest.Time() to get time.Time.
	Unixtime int64 `json:"date"`

	// Bio of the user, optional.
	Bio string `json:"bio"`

	// InviteLink is the chat invite link that was used by
	//the user to send the join request, optional.
	InviteLink *ChatInviteLink `json:"invite_link"`
}

// Time returns the moment of chat join request sending in local time.
func (r ChatJoinRequest) Time() time.Time {
	return time.Unix(r.Unixtime, 0)
}
<|endoftext|>


<commit_before>package store

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

type mockSnapshotSink struct {
	*os.File
}

func (m *mockSnapshotSink) ID() string {
	return "1"
}

func (m *mockSnapshotSink) Cancel() error {
	return nil
}

func Test_OpenStoreSingleNode(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
}

func Test_OpenStoreCloseSingleNode(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	if err := s.Close(true); err != nil {
		t.Fatalf("failed to close single-node store: %s", err.Error())
	}
}

func Test_SingleNodeInMemExecuteQuery(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeFileExecuteQuery(t *testing.T) {
	s := mustNewStore(false)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeExecuteQueryTx(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, true)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, true, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, true, Weak)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, true, Strong)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	_, err = s.Execute(queries, false, true)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
}

func Test_MultiNodeExecuteQuery(t *testing.T) {
	s0 := mustNewStore(true)
	defer os.RemoveAll(s0.Path())
	if err := s0.Open(true); err != nil {
		t.Fatalf("failed to open node for multi-node test: %s", err.Error())
	}
	defer s0.Close(true)
	s0.WaitForLeader(10 * time.Second)

	s1 := mustNewStore(true)
	defer os.RemoveAll(s1.Path())
	if err := s1.Open(false); err != nil {
		t.Fatalf("failed to open node for multi-node test: %s", err.Error())
	}
	defer s1.Close(true)

	// Join the second node to the first.
	if err := s0.Join(s1.Addr().String()); err != nil {
		t.Fatalf("failed to join to node at %s: %s", s0.Addr().String(), err.Error())
	}

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s0.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s0.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}

	// Wait until the 3 log entries have been applied to the follower,
	// and then query.
	if err := s1.WaitForAppliedIndex(3, 5*time.Second); err != nil {
		t.Fatalf("error waiting for follower to apply index: %s:", err.Error())
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, Weak)
	if err == nil {
		t.Fatalf("successfully queried non-leader node")
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, Strong)
	if err == nil {
		t.Fatalf("successfully queried non-leader node")
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeSnapshot(t *testing.T) {
	s := mustNewStore(false)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	_, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}

	// Snap the node and write to disk.
	f, err := s.Snapshot()
	if err != nil {
		t.Fatalf("failed to snapshot node: %s", err.Error())
	}

	snapDir := mustTempDir()
	defer os.RemoveAll(snapDir)
	snapFile, err := os.Create(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to create snapshot file: %s", err.Error())
	}
	sink := &mockSnapshotSink{snapFile}
	if err := f.Persist(sink); err != nil {
		t.Fatalf("failed to persist snapshot to disk: %s", err.Error())
	}

	// Check restoration.
	snapFile, err = os.Open(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to open snapshot file: %s", err.Error())
	}
	if err := s.Restore(snapFile); err != nil {
		t.Fatalf("failed to restore snapshot from disk: %s", err.Error())
	}

	// Ensure database is back in the correct state.
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func mustNewStore(inmem bool) *Store {
	path := mustTempDir()
	defer os.RemoveAll(path)

	cfg := NewDBConfig("", inmem)
	s := New(cfg, path, "localhost:0")
	if s == nil {
		panic("failed to create new store")
	}
	return s
}

func mustTempDir() string {
	var err error
	path, err := ioutil.TempDir("", "rqlilte-test-")
	if err != nil {
		panic("failed to create temp dir")
	}
	return path
}

func asJSON(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic("failed to JSON marshal value")
	}
	return string(b)
}
<commit_msg>Unit test restoring in-memory databases<commit_after>package store

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
)

type mockSnapshotSink struct {
	*os.File
}

func (m *mockSnapshotSink) ID() string {
	return "1"
}

func (m *mockSnapshotSink) Cancel() error {
	return nil
}

func Test_OpenStoreSingleNode(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
}

func Test_OpenStoreCloseSingleNode(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	if err := s.Close(true); err != nil {
		t.Fatalf("failed to close single-node store: %s", err.Error())
	}
}

func Test_SingleNodeInMemExecuteQuery(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeFileExecuteQuery(t *testing.T) {
	s := mustNewStore(false)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeExecuteQueryTx(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, true)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, true, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, true, Weak)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	r, err = s.Query([]string{`SELECT * FROM foo`}, false, true, Strong)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	_, err = s.Execute(queries, false, true)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
}

func Test_MultiNodeExecuteQuery(t *testing.T) {
	s0 := mustNewStore(true)
	defer os.RemoveAll(s0.Path())
	if err := s0.Open(true); err != nil {
		t.Fatalf("failed to open node for multi-node test: %s", err.Error())
	}
	defer s0.Close(true)
	s0.WaitForLeader(10 * time.Second)

	s1 := mustNewStore(true)
	defer os.RemoveAll(s1.Path())
	if err := s1.Open(false); err != nil {
		t.Fatalf("failed to open node for multi-node test: %s", err.Error())
	}
	defer s1.Close(true)

	// Join the second node to the first.
	if err := s0.Join(s1.Addr().String()); err != nil {
		t.Fatalf("failed to join to node at %s: %s", s0.Addr().String(), err.Error())
	}

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s0.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	r, err := s0.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}

	// Wait until the 3 log entries have been applied to the follower,
	// and then query.
	if err := s1.WaitForAppliedIndex(3, 5*time.Second); err != nil {
		t.Fatalf("error waiting for follower to apply index: %s:", err.Error())
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, Weak)
	if err == nil {
		t.Fatalf("successfully queried non-leader node")
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, Strong)
	if err == nil {
		t.Fatalf("successfully queried non-leader node")
	}
	r, err = s1.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeSnapshotOnDisk(t *testing.T) {
	s := mustNewStore(false)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	_, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}

	// Snap the node and write to disk.
	f, err := s.Snapshot()
	if err != nil {
		t.Fatalf("failed to snapshot node: %s", err.Error())
	}

	snapDir := mustTempDir()
	defer os.RemoveAll(snapDir)
	snapFile, err := os.Create(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to create snapshot file: %s", err.Error())
	}
	sink := &mockSnapshotSink{snapFile}
	if err := f.Persist(sink); err != nil {
		t.Fatalf("failed to persist snapshot to disk: %s", err.Error())
	}

	// Check restoration.
	snapFile, err = os.Open(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to open snapshot file: %s", err.Error())
	}
	if err := s.Restore(snapFile); err != nil {
		t.Fatalf("failed to restore snapshot from disk: %s", err.Error())
	}

	// Ensure database is back in the correct state.
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func Test_SingleNodeSnapshotInMem(t *testing.T) {
	s := mustNewStore(true)
	defer os.RemoveAll(s.Path())

	if err := s.Open(true); err != nil {
		t.Fatalf("failed to open single-node store: %s", err.Error())
	}
	defer s.Close(true)
	s.WaitForLeader(10 * time.Second)

	queries := []string{
		`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
		`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
	}
	_, err := s.Execute(queries, false, false)
	if err != nil {
		t.Fatalf("failed to execute on single node: %s", err.Error())
	}
	_, err = s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}

	// Snap the node and write to disk.
	f, err := s.Snapshot()
	if err != nil {
		t.Fatalf("failed to snapshot node: %s", err.Error())
	}

	snapDir := mustTempDir()
	defer os.RemoveAll(snapDir)
	snapFile, err := os.Create(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to create snapshot file: %s", err.Error())
	}
	sink := &mockSnapshotSink{snapFile}
	if err := f.Persist(sink); err != nil {
		t.Fatalf("failed to persist snapshot to disk: %s", err.Error())
	}

	// Check restoration.
	snapFile, err = os.Open(filepath.Join(snapDir, "snapshot"))
	if err != nil {
		t.Fatalf("failed to open snapshot file: %s", err.Error())
	}
	if err := s.Restore(snapFile); err != nil {
		t.Fatalf("failed to restore snapshot from disk: %s", err.Error())
	}

	// Ensure database is back in the correct state.
	r, err := s.Query([]string{`SELECT * FROM foo`}, false, false, None)
	if err != nil {
		t.Fatalf("failed to query single node: %s", err.Error())
	}
	if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
	if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
		t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
	}
}

func mustNewStore(inmem bool) *Store {
	path := mustTempDir()
	defer os.RemoveAll(path)

	cfg := NewDBConfig("", inmem)
	s := New(cfg, path, "localhost:0")
	if s == nil {
		panic("failed to create new store")
	}
	return s
}

func mustTempDir() string {
	var err error
	path, err := ioutil.TempDir("", "rqlilte-test-")
	if err != nil {
		panic("failed to create temp dir")
	}
	return path
}

func asJSON(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic("failed to JSON marshal value")
	}
	return string(b)
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validators

import (
	"fmt"
	"os"
	"testing"
)

func TestMain(m *testing.M) {
	setup()
	defer teardown()
	m.Run()
}

func setup() {
	writeFile(javaUnitTestFilePath, javaUnitTestCode)
	writeFile(javaCodePath, javaCode)
	writeFile(goUnitTestFilePath, goUnitTestCode)
	writeFile(goCodePath, goCode)
}

func teardown() {
	removeFile(javaUnitTestFilePath)
	removeFile(javaCodePath)
	removeFile(goUnitTestFilePath)
	removeFile(goCodePath)
}

func removeFile(path string) {
	err := os.Remove(path)
	if err != nil {
		panic(fmt.Errorf("error during test teardown: %s", err.Error()))
	}
}

func writeFile(path string, code string) {
	err := os.WriteFile(path, []byte(code), 0600)
	if err != nil {
		panic(fmt.Errorf("error during test setup: %s", err.Error()))
	}
}
<commit_msg>Docs for validators tests<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validators

import (
	"fmt"
	"os"
	"testing"
)

// TestMain setups and teardown all necessary functionality for tests
// in 'validators' package (i.e. for java_validators_test, go_validators_test,
// python_validators_test)
func TestMain(m *testing.M) {
	setup()
	defer teardown()
	m.Run()
}

func setup() {
	writeFile(javaUnitTestFilePath, javaUnitTestCode)
	writeFile(javaCodePath, javaCode)
	writeFile(goUnitTestFilePath, goUnitTestCode)
	writeFile(goCodePath, goCode)
}

func teardown() {
	removeFile(javaUnitTestFilePath)
	removeFile(javaCodePath)
	removeFile(goUnitTestFilePath)
	removeFile(goCodePath)
}

func removeFile(path string) {
	err := os.Remove(path)
	if err != nil {
		panic(fmt.Errorf("error during test teardown: %s", err.Error()))
	}
}

func writeFile(path string, code string) {
	err := os.WriteFile(path, []byte(code), 0600)
	if err != nil {
		panic(fmt.Errorf("error during test setup: %s", err.Error()))
	}
}
<|endoftext|>


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

package kube

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"time"

	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/subnet"

	"github.com/golang/glog"
	"golang.org/x/net/context"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
	clientset "k8s.io/client-go/kubernetes"
	listers "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	ErrUnimplemented = errors.New("unimplemented")
)

const (
	resyncPeriod              = 5 * time.Minute
	nodeControllerSyncTimeout = 10 * time.Minute

	netConfPath = "/etc/kube-flannel/net-conf.json"
)

type kubeSubnetManager struct {
	annotations    annotations
	client         clientset.Interface
	nodeName       string
	nodeStore      listers.NodeLister
	nodeController cache.Controller
	subnetConf     *subnet.Config
	events         chan subnet.Event
}

func NewSubnetManager(apiUrl, kubeconfig, prefix string) (subnet.Manager, error) {

	var cfg *rest.Config
	var err error
	// Use out of cluster config if the URL or kubeconfig have been specified. Otherwise use incluster config.
	if apiUrl != "" || kubeconfig != "" {
		cfg, err = clientcmd.BuildConfigFromFlags(apiUrl, kubeconfig)
		if err != nil {
			return nil, fmt.Errorf("unable to create k8s config: %v", err)
		}
	} else {
		cfg, err = rest.InClusterConfig()
		if err != nil {
			return nil, fmt.Errorf("unable to initialize inclusterconfig: %v", err)
		}
	}

	c, err := clientset.NewForConfig(cfg)
	if err != nil {
		return nil, fmt.Errorf("unable to initialize client: %v", err)
	}

	// The kube subnet mgr needs to know the k8s node name that it's running on so it can annotate it.
	// If we're running as a pod then the POD_NAME and POD_NAMESPACE will be populated and can be used to find the node
	// name. Otherwise, the environment variable NODE_NAME can be passed in.
	nodeName := os.Getenv("NODE_NAME")
	if nodeName == "" {
		podName := os.Getenv("POD_NAME")
		podNamespace := os.Getenv("POD_NAMESPACE")
		if podName == "" || podNamespace == "" {
			return nil, fmt.Errorf("env variables POD_NAME and POD_NAMESPACE must be set")
		}

		pod, err := c.Pods(podNamespace).Get(podName, metav1.GetOptions{})
		if err != nil {
			return nil, fmt.Errorf("error retrieving pod spec for '%s/%s': %v", podNamespace, podName, err)
		}
		nodeName = pod.Spec.NodeName
		if nodeName == "" {
			return nil, fmt.Errorf("node name not present in pod spec '%s/%s'", podNamespace, podName)
		}
	}

	netConf, err := ioutil.ReadFile(netConfPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read net conf: %v", err)
	}

	sc, err := subnet.ParseConfig(string(netConf))
	if err != nil {
		return nil, fmt.Errorf("error parsing subnet config: %s", err)
	}

	sm, err := newKubeSubnetManager(c, sc, nodeName, prefix)
	if err != nil {
		return nil, fmt.Errorf("error creating network manager: %s", err)
	}
	go sm.Run(context.Background())

	glog.Infof("Waiting %s for node controller to sync", nodeControllerSyncTimeout)
	err = wait.Poll(time.Second, nodeControllerSyncTimeout, func() (bool, error) {
		return sm.nodeController.HasSynced(), nil
	})
	if err != nil {
		return nil, fmt.Errorf("error waiting for nodeController to sync state: %v", err)
	}
	glog.Infof("Node controller sync successful")

	return sm, nil
}

func newKubeSubnetManager(c clientset.Interface, sc *subnet.Config, nodeName, prefix string) (*kubeSubnetManager, error) {
	var err error
	var ksm kubeSubnetManager
	ksm.annotations, err = newAnnotations(prefix)
	if err != nil {
		return nil, err
	}
	ksm.client = c
	ksm.nodeName = nodeName
	ksm.subnetConf = sc
	ksm.events = make(chan subnet.Event, 5000)
	indexer, controller := cache.NewIndexerInformer(
		&cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				return ksm.client.CoreV1().Nodes().List(options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				return ksm.client.CoreV1().Nodes().Watch(options)
			},
		},
		&v1.Node{},
		resyncPeriod,
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				ksm.handleAddLeaseEvent(subnet.EventAdded, obj)
			},
			UpdateFunc: ksm.handleUpdateLeaseEvent,
			DeleteFunc: func(obj interface{}) {
				node, isNode := obj.(*v1.Node)
				// We can get DeletedFinalStateUnknown instead of *api.Node here and we need to handle that correctly.
				if !isNode {
					deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
					if !ok {
						glog.Infof("Error received unexpected object: %v", obj)
						return
					}
					node, ok = deletedState.Obj.(*v1.Node)
					if !ok {
						glog.Infof("Error deletedFinalStateUnknown contained non-Node object: %v", deletedState.Obj)
						return
					}
					obj = node
				}
				ksm.handleAddLeaseEvent(subnet.EventRemoved, obj)
			},
		},
		cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
	)
	ksm.nodeController = controller
	ksm.nodeStore = listers.NewNodeLister(indexer)
	return &ksm, nil
}

func (ksm *kubeSubnetManager) handleAddLeaseEvent(et subnet.EventType, obj interface{}) {
	n := obj.(*v1.Node)
	if s, ok := n.Annotations[ksm.annotations.SubnetKubeManaged]; !ok || s != "true" {
		return
	}

	l, err := ksm.nodeToLease(*n)
	if err != nil {
		glog.Infof("Error turning node %q to lease: %v", n.ObjectMeta.Name, err)
		return
	}
	ksm.events <- subnet.Event{et, l}
}

func (ksm *kubeSubnetManager) handleUpdateLeaseEvent(oldObj, newObj interface{}) {
	o := oldObj.(*v1.Node)
	n := newObj.(*v1.Node)
	if s, ok := n.Annotations[ksm.annotations.SubnetKubeManaged]; !ok || s != "true" {
		return
	}
	if o.Annotations[ksm.annotations.BackendData] == n.Annotations[ksm.annotations.BackendData] &&
		o.Annotations[ksm.annotations.BackendType] == n.Annotations[ksm.annotations.BackendType] &&
		o.Annotations[ksm.annotations.BackendPublicIP] == n.Annotations[ksm.annotations.BackendPublicIP] {
		return // No change to lease
	}

	l, err := ksm.nodeToLease(*n)
	if err != nil {
		glog.Infof("Error turning node %q to lease: %v", n.ObjectMeta.Name, err)
		return
	}
	ksm.events <- subnet.Event{subnet.EventAdded, l}
}

func (ksm *kubeSubnetManager) GetNetworkConfig(ctx context.Context) (*subnet.Config, error) {
	return ksm.subnetConf, nil
}

func (ksm *kubeSubnetManager) AcquireLease(ctx context.Context, attrs *subnet.LeaseAttrs) (*subnet.Lease, error) {
	cachedNode, err := ksm.nodeStore.Get(ksm.nodeName)
	if err != nil {
		return nil, err
	}
	nobj, err := api.Scheme.DeepCopy(cachedNode)
	if err != nil {
		return nil, err
	}
	n := nobj.(*v1.Node)

	if n.Spec.PodCIDR == "" {
		return nil, fmt.Errorf("node %q pod cidr not assigned", ksm.nodeName)
	}
	bd, err := attrs.BackendData.MarshalJSON()
	if err != nil {
		return nil, err
	}
	_, cidr, err := net.ParseCIDR(n.Spec.PodCIDR)
	if err != nil {
		return nil, err
	}
	if n.Annotations[ksm.annotations.BackendData] != string(bd) ||
		n.Annotations[ksm.annotations.BackendType] != attrs.BackendType ||
		n.Annotations[ksm.annotations.BackendPublicIP] != attrs.PublicIP.String() ||
		n.Annotations[ksm.annotations.SubnetKubeManaged] != "true" ||
		(n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != "" && n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != attrs.PublicIP.String()) {
		n.Annotations[ksm.annotations.BackendType] = attrs.BackendType
		n.Annotations[ksm.annotations.BackendData] = string(bd)
		if n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != "" {
			if n.Annotations[ksm.annotations.BackendPublicIP] != n.Annotations[ksm.annotations.BackendPublicIPOverwrite] {
				glog.Infof("Overriding public ip with '%s' from node annotation '%s'",
					n.Annotations[ksm.annotations.BackendPublicIPOverwrite],
					ksm.annotations.BackendPublicIPOverwrite)
				n.Annotations[ksm.annotations.BackendPublicIP] = n.Annotations[ksm.annotations.BackendPublicIPOverwrite]
			}
		} else {
			n.Annotations[ksm.annotations.BackendPublicIP] = attrs.PublicIP.String()
		}
		n.Annotations[ksm.annotations.SubnetKubeManaged] = "true"

		oldData, err := json.Marshal(cachedNode)
		if err != nil {
			return nil, err
		}

		newData, err := json.Marshal(n)
		if err != nil {
			return nil, err
		}

		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
		if err != nil {
			return nil, fmt.Errorf("failed to create patch for node %q: %v", ksm.nodeName, err)
		}

		_, err = ksm.client.CoreV1().Nodes().Patch(ksm.nodeName, types.StrategicMergePatchType, patchBytes, "status")
		if err != nil {
			return nil, err
		}
	}
	return &subnet.Lease{
		Subnet:     ip.FromIPNet(cidr),
		Attrs:      *attrs,
		Expiration: time.Now().Add(24 * time.Hour),
	}, nil
}

func (ksm *kubeSubnetManager) WatchLeases(ctx context.Context, cursor interface{}) (subnet.LeaseWatchResult, error) {
	select {
	case event := <-ksm.events:
		return subnet.LeaseWatchResult{
			Events: []subnet.Event{event},
		}, nil
	case <-ctx.Done():
		return subnet.LeaseWatchResult{}, nil
	}
}

func (ksm *kubeSubnetManager) Run(ctx context.Context) {
	glog.Infof("Starting kube subnet manager")
	ksm.nodeController.Run(ctx.Done())
}

func (ksm *kubeSubnetManager) nodeToLease(n v1.Node) (l subnet.Lease, err error) {
	l.Attrs.PublicIP, err = ip.ParseIP4(n.Annotations[ksm.annotations.BackendPublicIP])
	if err != nil {
		return l, err
	}

	l.Attrs.BackendType = n.Annotations[ksm.annotations.BackendType]
	l.Attrs.BackendData = json.RawMessage(n.Annotations[ksm.annotations.BackendData])

	_, cidr, err := net.ParseCIDR(n.Spec.PodCIDR)
	if err != nil {
		return l, err
	}

	l.Subnet = ip.FromIPNet(cidr)
	return l, nil
}

// RenewLease: unimplemented
func (ksm *kubeSubnetManager) RenewLease(ctx context.Context, lease *subnet.Lease) error {
	return ErrUnimplemented
}

func (ksm *kubeSubnetManager) WatchLease(ctx context.Context, sn ip.IP4Net, cursor interface{}) (subnet.LeaseWatchResult, error) {
	return subnet.LeaseWatchResult{}, ErrUnimplemented
}

func (ksm *kubeSubnetManager) Name() string {
	return fmt.Sprintf("Kubernetes Subnet Manager - %s", ksm.nodeName)
}
<commit_msg>clean redundant code in building kubernetes config<commit_after>// Copyright 2016 flannel authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package kube

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"time"

	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/subnet"

	"github.com/golang/glog"
	"golang.org/x/net/context"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
	clientset "k8s.io/client-go/kubernetes"
	listers "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	ErrUnimplemented = errors.New("unimplemented")
)

const (
	resyncPeriod              = 5 * time.Minute
	nodeControllerSyncTimeout = 10 * time.Minute

	netConfPath = "/etc/kube-flannel/net-conf.json"
)

type kubeSubnetManager struct {
	annotations    annotations
	client         clientset.Interface
	nodeName       string
	nodeStore      listers.NodeLister
	nodeController cache.Controller
	subnetConf     *subnet.Config
	events         chan subnet.Event
}

func NewSubnetManager(apiUrl, kubeconfig, prefix string) (subnet.Manager, error) {

	var cfg *rest.Config
	var err error
	// Try to build kubernetes config from a master url or a kubeconfig filepath. If neither masterUrl
	// or kubeconfigPath are passed in we fall back to inClusterConfig. If inClusterConfig fails,
	// we fallback to the default config.
	cfg, err = clientcmd.BuildConfigFromFlags(apiUrl, kubeconfig)
	if err != nil {
		return nil, fmt.Errorf("fail to create kubernetes config: %v", err)
	}

	c, err := clientset.NewForConfig(cfg)
	if err != nil {
		return nil, fmt.Errorf("unable to initialize client: %v", err)
	}

	// The kube subnet mgr needs to know the k8s node name that it's running on so it can annotate it.
	// If we're running as a pod then the POD_NAME and POD_NAMESPACE will be populated and can be used to find the node
	// name. Otherwise, the environment variable NODE_NAME can be passed in.
	nodeName := os.Getenv("NODE_NAME")
	if nodeName == "" {
		podName := os.Getenv("POD_NAME")
		podNamespace := os.Getenv("POD_NAMESPACE")
		if podName == "" || podNamespace == "" {
			return nil, fmt.Errorf("env variables POD_NAME and POD_NAMESPACE must be set")
		}

		pod, err := c.Pods(podNamespace).Get(podName, metav1.GetOptions{})
		if err != nil {
			return nil, fmt.Errorf("error retrieving pod spec for '%s/%s': %v", podNamespace, podName, err)
		}
		nodeName = pod.Spec.NodeName
		if nodeName == "" {
			return nil, fmt.Errorf("node name not present in pod spec '%s/%s'", podNamespace, podName)
		}
	}

	netConf, err := ioutil.ReadFile(netConfPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read net conf: %v", err)
	}

	sc, err := subnet.ParseConfig(string(netConf))
	if err != nil {
		return nil, fmt.Errorf("error parsing subnet config: %s", err)
	}

	sm, err := newKubeSubnetManager(c, sc, nodeName, prefix)
	if err != nil {
		return nil, fmt.Errorf("error creating network manager: %s", err)
	}
	go sm.Run(context.Background())

	glog.Infof("Waiting %s for node controller to sync", nodeControllerSyncTimeout)
	err = wait.Poll(time.Second, nodeControllerSyncTimeout, func() (bool, error) {
		return sm.nodeController.HasSynced(), nil
	})
	if err != nil {
		return nil, fmt.Errorf("error waiting for nodeController to sync state: %v", err)
	}
	glog.Infof("Node controller sync successful")

	return sm, nil
}

func newKubeSubnetManager(c clientset.Interface, sc *subnet.Config, nodeName, prefix string) (*kubeSubnetManager, error) {
	var err error
	var ksm kubeSubnetManager
	ksm.annotations, err = newAnnotations(prefix)
	if err != nil {
		return nil, err
	}
	ksm.client = c
	ksm.nodeName = nodeName
	ksm.subnetConf = sc
	ksm.events = make(chan subnet.Event, 5000)
	indexer, controller := cache.NewIndexerInformer(
		&cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				return ksm.client.CoreV1().Nodes().List(options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				return ksm.client.CoreV1().Nodes().Watch(options)
			},
		},
		&v1.Node{},
		resyncPeriod,
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				ksm.handleAddLeaseEvent(subnet.EventAdded, obj)
			},
			UpdateFunc: ksm.handleUpdateLeaseEvent,
			DeleteFunc: func(obj interface{}) {
				node, isNode := obj.(*v1.Node)
				// We can get DeletedFinalStateUnknown instead of *api.Node here and we need to handle that correctly.
				if !isNode {
					deletedState, ok := obj.(cache.DeletedFinalStateUnknown)
					if !ok {
						glog.Infof("Error received unexpected object: %v", obj)
						return
					}
					node, ok = deletedState.Obj.(*v1.Node)
					if !ok {
						glog.Infof("Error deletedFinalStateUnknown contained non-Node object: %v", deletedState.Obj)
						return
					}
					obj = node
				}
				ksm.handleAddLeaseEvent(subnet.EventRemoved, obj)
			},
		},
		cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
	)
	ksm.nodeController = controller
	ksm.nodeStore = listers.NewNodeLister(indexer)
	return &ksm, nil
}

func (ksm *kubeSubnetManager) handleAddLeaseEvent(et subnet.EventType, obj interface{}) {
	n := obj.(*v1.Node)
	if s, ok := n.Annotations[ksm.annotations.SubnetKubeManaged]; !ok || s != "true" {
		return
	}

	l, err := ksm.nodeToLease(*n)
	if err != nil {
		glog.Infof("Error turning node %q to lease: %v", n.ObjectMeta.Name, err)
		return
	}
	ksm.events <- subnet.Event{et, l}
}

func (ksm *kubeSubnetManager) handleUpdateLeaseEvent(oldObj, newObj interface{}) {
	o := oldObj.(*v1.Node)
	n := newObj.(*v1.Node)
	if s, ok := n.Annotations[ksm.annotations.SubnetKubeManaged]; !ok || s != "true" {
		return
	}
	if o.Annotations[ksm.annotations.BackendData] == n.Annotations[ksm.annotations.BackendData] &&
		o.Annotations[ksm.annotations.BackendType] == n.Annotations[ksm.annotations.BackendType] &&
		o.Annotations[ksm.annotations.BackendPublicIP] == n.Annotations[ksm.annotations.BackendPublicIP] {
		return // No change to lease
	}

	l, err := ksm.nodeToLease(*n)
	if err != nil {
		glog.Infof("Error turning node %q to lease: %v", n.ObjectMeta.Name, err)
		return
	}
	ksm.events <- subnet.Event{subnet.EventAdded, l}
}

func (ksm *kubeSubnetManager) GetNetworkConfig(ctx context.Context) (*subnet.Config, error) {
	return ksm.subnetConf, nil
}

func (ksm *kubeSubnetManager) AcquireLease(ctx context.Context, attrs *subnet.LeaseAttrs) (*subnet.Lease, error) {
	cachedNode, err := ksm.nodeStore.Get(ksm.nodeName)
	if err != nil {
		return nil, err
	}
	nobj, err := api.Scheme.DeepCopy(cachedNode)
	if err != nil {
		return nil, err
	}
	n := nobj.(*v1.Node)

	if n.Spec.PodCIDR == "" {
		return nil, fmt.Errorf("node %q pod cidr not assigned", ksm.nodeName)
	}
	bd, err := attrs.BackendData.MarshalJSON()
	if err != nil {
		return nil, err
	}
	_, cidr, err := net.ParseCIDR(n.Spec.PodCIDR)
	if err != nil {
		return nil, err
	}
	if n.Annotations[ksm.annotations.BackendData] != string(bd) ||
		n.Annotations[ksm.annotations.BackendType] != attrs.BackendType ||
		n.Annotations[ksm.annotations.BackendPublicIP] != attrs.PublicIP.String() ||
		n.Annotations[ksm.annotations.SubnetKubeManaged] != "true" ||
		(n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != "" && n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != attrs.PublicIP.String()) {
		n.Annotations[ksm.annotations.BackendType] = attrs.BackendType
		n.Annotations[ksm.annotations.BackendData] = string(bd)
		if n.Annotations[ksm.annotations.BackendPublicIPOverwrite] != "" {
			if n.Annotations[ksm.annotations.BackendPublicIP] != n.Annotations[ksm.annotations.BackendPublicIPOverwrite] {
				glog.Infof("Overriding public ip with '%s' from node annotation '%s'",
					n.Annotations[ksm.annotations.BackendPublicIPOverwrite],
					ksm.annotations.BackendPublicIPOverwrite)
				n.Annotations[ksm.annotations.BackendPublicIP] = n.Annotations[ksm.annotations.BackendPublicIPOverwrite]
			}
		} else {
			n.Annotations[ksm.annotations.BackendPublicIP] = attrs.PublicIP.String()
		}
		n.Annotations[ksm.annotations.SubnetKubeManaged] = "true"

		oldData, err := json.Marshal(cachedNode)
		if err != nil {
			return nil, err
		}

		newData, err := json.Marshal(n)
		if err != nil {
			return nil, err
		}

		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
		if err != nil {
			return nil, fmt.Errorf("failed to create patch for node %q: %v", ksm.nodeName, err)
		}

		_, err = ksm.client.CoreV1().Nodes().Patch(ksm.nodeName, types.StrategicMergePatchType, patchBytes, "status")
		if err != nil {
			return nil, err
		}
	}
	return &subnet.Lease{
		Subnet:     ip.FromIPNet(cidr),
		Attrs:      *attrs,
		Expiration: time.Now().Add(24 * time.Hour),
	}, nil
}

func (ksm *kubeSubnetManager) WatchLeases(ctx context.Context, cursor interface{}) (subnet.LeaseWatchResult, error) {
	select {
	case event := <-ksm.events:
		return subnet.LeaseWatchResult{
			Events: []subnet.Event{event},
		}, nil
	case <-ctx.Done():
		return subnet.LeaseWatchResult{}, nil
	}
}

func (ksm *kubeSubnetManager) Run(ctx context.Context) {
	glog.Infof("Starting kube subnet manager")
	ksm.nodeController.Run(ctx.Done())
}

func (ksm *kubeSubnetManager) nodeToLease(n v1.Node) (l subnet.Lease, err error) {
	l.Attrs.PublicIP, err = ip.ParseIP4(n.Annotations[ksm.annotations.BackendPublicIP])
	if err != nil {
		return l, err
	}

	l.Attrs.BackendType = n.Annotations[ksm.annotations.BackendType]
	l.Attrs.BackendData = json.RawMessage(n.Annotations[ksm.annotations.BackendData])

	_, cidr, err := net.ParseCIDR(n.Spec.PodCIDR)
	if err != nil {
		return l, err
	}

	l.Subnet = ip.FromIPNet(cidr)
	return l, nil
}

// RenewLease: unimplemented
func (ksm *kubeSubnetManager) RenewLease(ctx context.Context, lease *subnet.Lease) error {
	return ErrUnimplemented
}

func (ksm *kubeSubnetManager) WatchLease(ctx context.Context, sn ip.IP4Net, cursor interface{}) (subnet.LeaseWatchResult, error) {
	return subnet.LeaseWatchResult{}, ErrUnimplemented
}

func (ksm *kubeSubnetManager) Name() string {
	return fmt.Sprintf("Kubernetes Subnet Manager - %s", ksm.nodeName)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

func contains(slice []string, str string) bool {
	for _, elem := range slice {
		if elem == str {
			return true
		}
	}
	return false
}

type cmd interface {
	Action() []byte
	Help() string
	Names() []string
}

type cmdMatcher interface {
	Match(name string) bool
}

type cmdUp struct{}

func (c *cmdUp) Action() []byte {
	return []byte("u")
}

func (c *cmdUp) Help() string {
	return ""
}

func (c *cmdUp) Names() []string {
	return []string{"up", "start"}
}

type cmdDown struct{}

func (c *cmdDown) Action() []byte {
	return []byte("d")
}

func (c *cmdDown) Help() string {
	return ""
}

func (c *cmdDown) Names() []string {
	return []string{"down", "stop"}
}

type cmdSignal struct {
	action []byte
}

func (c *cmdSignal) Action() []byte {
	return c.action
}

func (c *cmdSignal) Help() string {
	return ""
}

func (c *cmdSignal) Names() []string {
	return []string{
		"pause", "cont", "hup", "alarm", "interrupt",
		"quit", "1", "2", "term", "kill",
	}
}

func (c *cmdSignal) Match(name string) bool {
	for _, s := range c.Names() {
		if name == s || name == s[0:1] {
			c.action = []byte(name[0:1])
			return true
		}
	}
	return false
}

func cmdAll() []cmd {
	return []cmd{
		&cmdUp{},
		&cmdDown{},
		&cmdSignal{},
	}
}

func cmdMatch(name string) cmd {
	for _, cmd := range cmdAll() {
		m, ok := cmd.(cmdMatcher)
		if (ok && m.Match(name)) || contains(cmd.Names(), name) || string(cmd.Action()) == name {
			return cmd
		}
	}
	return nil
}

func cmdMatchName(partialName string) []string {
	res := []string{}
	for _, cmd := range cmdAll() {
		for _, name := range cmd.Names() {
			if strings.HasPrefix(name, partialName) {
				res = append(res, fmt.Sprintf("%s ", name))
			}
		}
	}
	return res
}
<commit_msg>restart and reload actions<commit_after>package main

import (
	"fmt"
	"strings"
)

func contains(slice []string, str string) bool {
	for _, elem := range slice {
		if elem == str {
			return true
		}
	}
	return false
}

type cmd interface {
	Action() []byte
	Help() string
	Names() []string
}

type cmdMatcher interface {
	Match(name string) bool
}

type cmdUp struct{}

func (c *cmdUp) Action() []byte {
	return []byte("u")
}

func (c *cmdUp) Help() string {
	return ""
}

func (c *cmdUp) Names() []string {
	return []string{"up", "start"}
}

type cmdDown struct{}

func (c *cmdDown) Action() []byte {
	return []byte("d")
}

func (c *cmdDown) Help() string {
	return ""
}

func (c *cmdDown) Names() []string {
	return []string{"down", "stop"}
}

type cmdRestart struct{}

func (c *cmdRestart) Action() []byte {
	return []byte("tcu")
}

func (c *cmdRestart) Help() string {
	return ""
}

func (c *cmdRestart) Names() []string {
	return []string{"restart"}
}

type cmdSignal struct {
	action []byte
}

func (c *cmdSignal) Action() []byte {
	return c.action
}

func (c *cmdSignal) Help() string {
	return ""
}

func (c *cmdSignal) Names() []string {
	return []string{
		"pause", "cont", "hup", "alarm", "interrupt",
		"quit", "1", "2", "term", "kill",
	}
}

func (c *cmdSignal) Match(name string) bool {
	for _, s := range c.Names() {
		if name == s || name == s[0:1] {
			c.action = []byte(name[0:1])
			return true
		}
		if name == "reload" {
			c.action = []byte("h")
			return true
		}
	}
	return false
}

func cmdAll() []cmd {
	return []cmd{
		&cmdUp{},
		&cmdDown{},
		&cmdRestart{},
		&cmdSignal{},
	}
}

func cmdMatch(name string) cmd {
	for _, cmd := range cmdAll() {
		m, ok := cmd.(cmdMatcher)
		if (ok && m.Match(name)) || contains(cmd.Names(), name) || string(cmd.Action()) == name {
			return cmd
		}
	}
	return nil
}

func cmdMatchName(partialName string) []string {
	res := []string{}
	for _, cmd := range cmdAll() {
		for _, name := range cmd.Names() {
			if strings.HasPrefix(name, partialName) {
				res = append(res, fmt.Sprintf("%s ", name))
			}
		}
	}
	return res
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "os/exec"
    "regexp"
)

var (
    pPath string
    port  string
    addr  string
)

func init() {
    pPath = os.Getenv("PPATH")
    port  = os.Getenv("PORT")
    if pPath == "" {
        fmt.Println("PPATH environment variable not set.")
        os.Exit(1)
    }
    if port == "" {
        port = "12345"
    }
    addr = fmt.Sprintf(":%s", port)
}

func updateCodebase() {
    cmd     := exec.Command("git", "pull")
    cmd.Dir  = pPath
    err     := cmd.Start()
    if err != nil {
        log.Fatal("Error while running git: ", err)
    }
    log.Printf("Updating code base on %s", pPath)
    err = cmd.Wait()
    // TODO: Don't die if updating codebase update fails.
    if err != nil {
        log.Fatal("Error while updating code base: ", err)
    } else {
        out, _ := cmd.Output()
        log.Printf("Code base updated\n%s", out)
    }
}

func handleRequest(res http.ResponseWriter, req *http.Request) {
    if requestComesFromGithub(req) {
        log.Println("Handling deployment request")
        go updateCodebase()
        fmt.Fprint(res, "ok")
    } else {
        log.Printf("Deployment request coming from %s ignored\n", req.Header.Get("X-Remote-IP"))
        http.NotFound(res, req)
    }
}

func requestComesFromGithub(req *http.Request) bool {
    r := regexp.MustCompile(`192\.30\.252\.\d{1,3}`)
    return r.MatchString(req.Header.Get("X-Remote-IP"))
}

func main() {
    http.HandleFunc("/deploy", handleRequest)
    log.Printf("About to listen on %s\n", addr)
    err := http.ListenAndServe(addr, nil)
    if err != nil {
        log.Fatal("Error while starting server: ", err)
    }
}
<commit_msg>Using proper remote ip header.<commit_after>package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "os/exec"
    "regexp"
)

var (
    pPath string
    port  string
    addr  string
)

func init() {
    pPath = os.Getenv("PPATH")
    port  = os.Getenv("PORT")
    if pPath == "" {
        fmt.Println("PPATH environment variable not set.")
        os.Exit(1)
    }
    if port == "" {
        port = "12345"
    }
    addr = fmt.Sprintf(":%s", port)
}

func updateCodebase() {
    cmd     := exec.Command("git", "pull")
    cmd.Dir  = pPath
    err     := cmd.Start()
    if err != nil {
        log.Fatal("Error while running git: ", err)
    }
    log.Printf("Updating code base on %s", pPath)
    err = cmd.Wait()
    // TODO: Don't die if updating codebase update fails.
    if err != nil {
        log.Fatal("Error while updating code base: ", err)
    } else {
        out, _ := cmd.Output()
        log.Printf("Code base updated\n%s", out)
    }
}

func handleRequest(res http.ResponseWriter, req *http.Request) {
    if requestComesFromGithub(req) {
        log.Println("Handling deployment request")
        go updateCodebase()
        fmt.Fprint(res, "ok")
    } else {
        log.Printf("Deployment request coming from %s ignored\n", req.Header.Get("X-Real-Ip"))
        http.NotFound(res, req)
    }
}

func requestComesFromGithub(req *http.Request) bool {
    r := regexp.MustCompile(`192\.30\.252\.\d{1,3}`)
    return r.MatchString(req.Header.Get("X-Real-Ip"))
}

func main() {
    http.HandleFunc("/deploy", handleRequest)
    log.Printf("About to listen on %s\n", addr)
    err := http.ListenAndServe(addr, nil)
    if err != nil {
        log.Fatal("Error while starting server: ", err)
    }
}
<|endoftext|>


<commit_before>package easyftp

import "net"
import "fmt"
import "os"
import "bytes"
import "strconv"
import "errors"

const (
	maxCmdLength      int = 8096
	maxRespLineLength int = 8096
)

var (
	space = []byte{' '}
	crnl  = []byte{'\r', '\n'}
)

type DataConn struct {
	control *ControlConn
	conn    net.Conn
}

func NewDataConn(control *ControlConn, conn net.Conn) *DataConn {
	return &DataConn{
		control: control,
		conn:    conn,
	}
}

func (c *DataConn) Close() error {
	err := c.conn.Close()
	// Since we're DTP, we need read the result from control connection
	code, msg, err2 := c.control.ReadResponse()
	if err2 != nil {
		err = err2
	}
	if code != 226 {
		err = NewUnexpectedCodeError(code, msg)
	}
	return err
}

func (c *DataConn) Read(b []byte) (int, error) {
	return c.conn.Read(b)
}

func (c *DataConn) Write(b []byte) (int, error) {
	return c.conn.Write(b)
}

// We make this class public to make extension easier, so if you are not intrest
// in this, you can ignore the details and use Client only
type ControlConn struct {
	Debug     bool
	conn      net.Conn
	cmdBuf    []byte
	respLine  []byte
	availData []byte
}

func NewControlConn(conn net.Conn, debug bool) *ControlConn {
	c := new(ControlConn)
	c.Debug = debug
	c.conn = conn
	c.cmdBuf = make([]byte, maxCmdLength)
	c.respLine = make([]byte, maxRespLineLength)
	c.availData = c.respLine[:0]
	return c
}

func (c *ControlConn) Close() error {
	err := c.conn.Close()
	return err
}

func (c *ControlConn) SendCommand(cmd string, msg string) error {
	cmdFullLen := len(cmd) + len(msg) + len(space) + len(crnl)
	if cmdFullLen > maxCmdLength {
		return errors.New("command is too long")
	}

	n := copy(c.cmdBuf, cmd)
	if len(msg) > 0 {
		n += copy(c.cmdBuf[n:], space)
		n += copy(c.cmdBuf[n:], msg)
	}
	n += copy(c.cmdBuf[n:], crnl)

	if c.Debug {
		fmt.Fprintf(os.Stderr, "%p send: %s", c, string(c.cmdBuf[:n]))
	}

	_, err := c.conn.Write(c.cmdBuf[:n])
	if err != nil {
		return err
	}

	return err
}

func (c *ControlConn) ReadResponse() (code int, msg string, err error) {
	c.availData = c.respLine[:0]
	received := 0
	crnlPos := 0
	line := c.respLine[:0]
	for {
		n, err := c.conn.Read(c.respLine[received:])
		if err != nil {
			return -1, "", err
		}
		received += n

		crnlPos = bytes.Index(c.respLine[:received], crnl)
		if crnlPos < 0 {
			if received == len(c.respLine) {
				// TODO: read until we get a crnl
				return -1, "", errors.New("response is too long")
			}
		} else {
			line = c.respLine[:crnlPos]
			break
		}
	}

	if c.Debug {
		fmt.Fprintf(os.Stderr, "%p recv: %s\n", c, string(line))
	}

	c.availData = c.respLine[crnlPos+2 : received]

	if len(line) < 3 {
		return -1, "", errors.New("response is too short")
	}

	code, err = strconv.Atoi(string(line[:3]))
	if err != nil {
		return -1, "", err
	}

	if len(line) >= 4 {
		msg = string(line[4:])
	}
	return
}
<commit_msg>code cleanup<commit_after>package easyftp

import "net"
import "fmt"
import "os"
import "bytes"
import "strconv"
import "errors"

const (
	maxCmdLength      int = 8096
	maxRespLineLength int = 8096
)

var (
	space = []byte{' '}
	crnl  = []byte{'\r', '\n'}
)

type DataConn struct {
	control *ControlConn
	conn    net.Conn
}

func NewDataConn(control *ControlConn, conn net.Conn) *DataConn {
	return &DataConn{
		control: control,
		conn:    conn,
	}
}

func (c *DataConn) Close() error {
	err := c.conn.Close()
	// Since we're DTP, we need read the result from control connection
	code, msg, err2 := c.control.ReadResponse()
	if err2 != nil {
		err = err2
	}
	if code != 226 {
		err = NewUnexpectedCodeError(code, msg)
	}
	return err
}

func (c *DataConn) Read(b []byte) (int, error) {
	return c.conn.Read(b)
}

func (c *DataConn) Write(b []byte) (int, error) {
	return c.conn.Write(b)
}

// We make this class public to make extension easier, so if you are not intrest
// in this, you can ignore the details and use Client only
type ControlConn struct {
	Debug     bool
	conn      net.Conn
	cmdBuf    []byte
	respLine  []byte
}

func NewControlConn(conn net.Conn, debug bool) *ControlConn {
	c := new(ControlConn)
	c.Debug = debug
	c.conn = conn
	c.cmdBuf = make([]byte, maxCmdLength)
	c.respLine = make([]byte, maxRespLineLength)
	return c
}

func (c *ControlConn) Close() error {
	err := c.conn.Close()
	return err
}

func (c *ControlConn) SendCommand(cmd string, msg string) error {
	cmdFullLen := len(cmd) + len(msg) + len(space) + len(crnl)
	if cmdFullLen > maxCmdLength {
		return errors.New("command is too long")
	}

	n := copy(c.cmdBuf, cmd)
	if len(msg) > 0 {
		n += copy(c.cmdBuf[n:], space)
		n += copy(c.cmdBuf[n:], msg)
	}
	n += copy(c.cmdBuf[n:], crnl)

	if c.Debug {
		fmt.Fprintf(os.Stderr, "%p send: %s", c, string(c.cmdBuf[:n]))
	}

	_, err := c.conn.Write(c.cmdBuf[:n])
	if err != nil {
		return err
	}

	return err
}

func (c *ControlConn) ReadResponse() (code int, msg string, err error) {
	received := 0
	crnlPos := 0
	line := c.respLine[:0]
	for {
		n, err := c.conn.Read(c.respLine[received:])
		if err != nil {
			return -1, "", err
		}
		received += n

		crnlPos = bytes.Index(c.respLine[:received], crnl)
		if crnlPos < 0 {
			if received == len(c.respLine) {
				// TODO: read until we get a crnl
				return -1, "", errors.New("response is too long")
			}
		} else {
			line = c.respLine[:crnlPos]
			break
		}
	}

	if c.Debug {
		fmt.Fprintf(os.Stderr, "%p recv: %s\n", c, string(line))
	}

	if len(line) < 3 {
		return -1, "", errors.New("response is too short")
	}

	code, err = strconv.Atoi(string(line[:3]))
	if err != nil {
		return -1, "", err
	}

	if len(line) >= 4 {
		msg = string(line[4:])
	}
	return
}
<|endoftext|>