<commit_before>//the icws_golib package wraps CIC ICWS fuctionality in a GO library.
//To get started, call icws_golib.NewIcws() to instansiate a new Icws
//struct.  Then call icws.Login(...) and continue on from there.
package icws_golib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

type Icws struct {
	CurrentToken, CurrentCookie, CurrentSession, CurrentServer, UserId, HttpScheme string
	Port                                                                           int
}

//Version information for the server
type ServerVersion struct {
	//The product's two-digit release year. For the release "CIC 2015 R1" this value will be "15"
	MajorVersion string
	//The product's release number. For the release "CIC 2015 R1" this value will be "1".
	MinorVersion string
	//The patch number of the release. The value "0" indicates the release without any patches. For the release "CIC 2015 R1" this value will be "0", and for the release "CIC 2015 R1 Patch2" this value will be "2".
	Su string
	//The product line identifier.
	ProductId string
	//The codebase identifier.
	CodeBaseId string
	//The build number.
	Build string
	//The display string for the release. This does not include patch information.
	ProductReleaseDisplayString string
	//The display string for the release including patch information. This string is recommended for use on application "About" screens.
	ProductPatchDisplayString string
}

//Definition of a server feature
type ServerFeature struct {
	//Id of the features
	FeatureId string
	//version of the feature
	Version int
}

//Creates a new ICWS struct
func NewIcws() (icws *Icws) {
	icws = &Icws{}
	icws.HttpScheme = "https"
	icws.Port = 8019
	return
}

func (i *Icws) loginWithData(applicationName, server, username, password string, loginData map[string]string) (err error) {

	urlFormat := "%s://%s:%d"
	server = fmt.Sprintf(urlFormat, i.HttpScheme, server, i.Port)

	log.Printf("Logging into %s with user %s", server, username)

	i.CurrentSession = ""
	i.CurrentServer = server
	body, statusCode, err, cookie := i.httpPostAdvanced("connection", loginData)

	nextServerIndex := 0
	for statusCode == 503 {

		var returnData map[string]interface{}
		json.Unmarshal(body, &returnData)

		nextServer := returnData["alternateHostList"].([]interface{})[0]

		server = fmt.Sprintf(urlFormat, nextServer)

		log.Printf("Redirected to server %s", server)

		i.CurrentServer = server
		body, statusCode, err, cookie = i.httpPostAdvanced("connection", loginData)

		nextServerIndex++
	}

	if err == nil {

		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		i.CurrentToken = returnData["csrfToken"]
		i.CurrentSession = returnData["sessionId"]
		i.CurrentServer = server
		i.CurrentCookie = cookie
		i.UserId = username

	} else {
		log.Printf("ERROR: %s\n", err.Error())
	}
	return
}

//logs into CIC through a reverse proxy
func (i *Icws) ProxyLoginWithData(applicationName, proxyUrl, serverName, username, password string, loginData map[string]string) (err error) {

	urlFormat := "%s/%s"
	server := fmt.Sprintf(urlFormat, proxyUrl, serverName)

	log.Printf("Logging into %s with user %s", server, username)

	i.CurrentSession = ""
	i.CurrentServer = server
	body, statusCode, err, cookie := i.httpPostAdvanced("connection", loginData)

	nextServerIndex := 0
	for statusCode == 503 {

		var returnData map[string]interface{}
		json.Unmarshal(body, &returnData)

		if returnData["alternateHostList"] == nil {
			err = errors.New("Unable to connect to server, unknown error")
		}

		nextServer := returnData["alternateHostList"].([]interface{})[0]

		server = fmt.Sprintf(urlFormat, proxyUrl, nextServer)

		log.Printf("Redirected to server %s", server)

		i.CurrentServer = server
		body, statusCode, err, cookie = i.httpPostAdvanced("connection", loginData)

		nextServerIndex++
	}

	if err == nil {

		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		i.CurrentToken = returnData["csrfToken"]
		i.CurrentSession = returnData["sessionId"]
		i.CurrentServer = server
		i.CurrentCookie = cookie
		i.UserId = username

	} else {
		log.Printf("ERROR: %s\n", err.Error())
	}
	return
}

//logs into a CIC server through a reverse proxy where the url to reach the server would be proxyUrl/serverName
func (i *Icws) ProxyLogin(applicationName, proxyUrl, serverName, username, password string) (err error) {

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": applicationName,
		"userID":          username,
		"password":        password,
	}

	return i.ProxyLoginWithData(applicationName, proxyUrl, serverName, username, password, loginData)
}

//Logs into a CIC server for a MarketPlace application using the app's custom license.  Server should be a url e.g. https://MyServer:8019
func (i *Icws) ProxyLoginMarketPlaceApp(applicationName, proxyUrl, serverName, username, password, marketplaceLicense, marketplaceAppKey string) (err error) {

	var loginData = map[string]string{
		"__type":                            "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName":                   applicationName,
		"userID":                            username,
		"password":                          password,
		"marketPlaceApplicationLicenseName": marketplaceLicense,
		"marketPlaceApplicationCode":        marketplaceAppKey,
	}

	return i.ProxyLoginWithData(applicationName, proxyUrl, serverName, username, password, loginData)
}

//Logs into a CIC server.  Server should be a server name e.g. MyServer.domain.com
func (i *Icws) Login(applicationName, server, username, password string) (err error) {

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": applicationName,
		"userID":          username,
		"password":        password,
	}

	return i.loginWithData(applicationName, server, username, password, loginData)
}

//Logs into a CIC server for a MarketPlace application using the app's custom license.  Server should be a url e.g. https://MyServer:8019
func (i *Icws) LoginMarketPlaceApp(applicationName, server, username, password, marketplaceLicense, marketplaceAppKey string) (err error) {

	var loginData = map[string]string{
		"__type":                            "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName":                   applicationName,
		"userID":                            username,
		"password":                          password,
		"marketPlaceApplicationLicenseName": marketplaceLicense,
		"marketPlaceApplicationCode":        marketplaceAppKey,
	}

	return i.loginWithData(applicationName, server, username, password, loginData)
}

//gets server version details.  Does not need to be connected to the server
func (i *Icws) GetVersion() (version ServerVersion, err error) {

	body, err := i.httpNoConnectionGet("/connection/version")

	err = json.Unmarshal(body, &version)

	return
}

//Gets a list of features and their version from the server
func (i *Icws) GetFeatures() (features []ServerFeature, err error) {

	body, err := i.httpNoConnectionGet("/connection/features")

	if err != nil {
		return nil, err
	}

	var featureMap map[string][]ServerFeature
	err = json.Unmarshal(body, &featureMap)

	features = featureMap["featureInfoList"]
	return

}

func (i *Icws) httpDelete(url string) (err error) {

	req, err := i.httpRequest("DELETE", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, _ := ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpGet(url string) (body []byte, err error) {

	req, err := i.httpRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpNoConnectionGet(url string) (body []byte, err error) {

	req, err := i.httpNoConnectionRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpPost(url string, attrs map[string]string) (body []byte, err error) {
	body, _, err, _ = i.httpPostAdvanced(url, attrs)
	return
}

func (i *Icws) httpPostAdvanced(url string, attrs map[string]string) (body []byte, statusCode int, err error, cookie string) {

	rbody, _ := json.Marshal(attrs)
	req, err := i.httpRequest("POST", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()

	statusCode = response.StatusCode

	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	if response.Header["Set-Cookie"] != nil {
		cookie = response.Header["Set-Cookie"][0]
	}
	return
}

func (i *Icws) httpPut(url string, attrs map[string]string) (body []byte, err error) {

	rbody, _ := json.Marshal(attrs)
	req, err := i.httpRequest("PUT", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpClient() (client *http.Client) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client = &http.Client{Transport: tr}
	return
}

func (i *Icws) httpNoConnectionRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, i.CurrentServer+"/icws"+url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	return
}

func (i *Icws) httpRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, i.CurrentServer+"/icws/"+i.CurrentSession+url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	if len(i.CurrentCookie) > 0 {
		request.Header.Add("Cookie", i.CurrentCookie)
	} else {
		return
	}

	if len(i.CurrentToken) > 0 {
		request.Header.Add("ININ-ICWS-CSRF-Token", i.CurrentToken)
	} else {
		return
	}

	// request.Header.Add("User-Agent", fmt.Sprintf("cic cli (%s-%s)", runtime.GOOS, runtime.GOARCH))
	return
}

func createErrorMessage(statusCode int, body []byte) string {

	var errorDescription string

	switch statusCode {
	case 400:
		errorDescription = "Bad Request (400)"
	case 401:
		errorDescription = "Unauthorized (401)"
	case 403:
		errorDescription = "Forbidden (403)"
	case 404:
		errorDescription = "Not Found (404)"
	case 410:
		errorDescription = "Gone (410)"
	case 500:
		errorDescription = "Internal Server Error (500)"
	}

	var message map[string]interface{}
	json.Unmarshal(body, &message)

	if message["errorId"] != nil {
		errorDescription += ": " + message["errorId"].(string)
	}

	if message["message"] != nil {
		errorDescription += " " + message["message"].(string)
	}
	return errorDescription
}
<commit_msg>changing proxy login params<commit_after>//the icws_golib package wraps CIC ICWS fuctionality in a GO library.
//To get started, call icws_golib.NewIcws() to instansiate a new Icws
//struct.  Then call icws.Login(...) and continue on from there.
package icws_golib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

type Icws struct {
	CurrentToken, CurrentCookie, CurrentSession, CurrentServer, UserId, HttpScheme string
	Port                                                                           int
}

//Version information for the server
type ServerVersion struct {
	//The product's two-digit release year. For the release "CIC 2015 R1" this value will be "15"
	MajorVersion string
	//The product's release number. For the release "CIC 2015 R1" this value will be "1".
	MinorVersion string
	//The patch number of the release. The value "0" indicates the release without any patches. For the release "CIC 2015 R1" this value will be "0", and for the release "CIC 2015 R1 Patch2" this value will be "2".
	Su string
	//The product line identifier.
	ProductId string
	//The codebase identifier.
	CodeBaseId string
	//The build number.
	Build string
	//The display string for the release. This does not include patch information.
	ProductReleaseDisplayString string
	//The display string for the release including patch information. This string is recommended for use on application "About" screens.
	ProductPatchDisplayString string
}

//Definition of a server feature
type ServerFeature struct {
	//Id of the features
	FeatureId string
	//version of the feature
	Version int
}

//Creates a new ICWS struct
func NewIcws() (icws *Icws) {
	icws = &Icws{}
	icws.HttpScheme = "https"
	icws.Port = 8019
	return
}

func (i *Icws) loginWithData(applicationName, server, username, password string, loginData map[string]string) (err error) {

	urlFormat := "%s://%s:%d"
	server = fmt.Sprintf(urlFormat, i.HttpScheme, server, i.Port)

	log.Printf("Logging into %s with user %s", server, username)

	i.CurrentSession = ""
	i.CurrentServer = server
	body, statusCode, err, cookie := i.httpPostAdvanced("connection", loginData)

	nextServerIndex := 0
	for statusCode == 503 {

		var returnData map[string]interface{}
		json.Unmarshal(body, &returnData)

		nextServer := returnData["alternateHostList"].([]interface{})[0]

		server = fmt.Sprintf(urlFormat, nextServer)

		log.Printf("Redirected to server %s", server)

		i.CurrentServer = server
		body, statusCode, err, cookie = i.httpPostAdvanced("connection", loginData)

		nextServerIndex++
	}

	if err == nil {

		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		i.CurrentToken = returnData["csrfToken"]
		i.CurrentSession = returnData["sessionId"]
		i.CurrentServer = server
		i.CurrentCookie = cookie
		i.UserId = username

	} else {
		log.Printf("ERROR: %s\n", err.Error())
	}
	return
}

//logs into CIC through a reverse proxy
func (i *Icws) ProxyLoginWithData(proxyUrl, serverName, username string, loginData map[string]string) (err error) {

	urlFormat := "%s/%s"
	server := fmt.Sprintf(urlFormat, proxyUrl, serverName)

	i.CurrentSession = ""
	i.CurrentServer = server
	body, statusCode, err, cookie := i.httpPostAdvanced("connection", loginData)

	nextServerIndex := 0
	for statusCode == 503 {

		var returnData map[string]interface{}
		json.Unmarshal(body, &returnData)

		if returnData["alternateHostList"] == nil {
			err = errors.New("Unable to connect to server, unknown error")
		}

		nextServer := returnData["alternateHostList"].([]interface{})[0]

		server = fmt.Sprintf(urlFormat, proxyUrl, nextServer)

		log.Printf("Redirected to server %s", server)

		i.CurrentServer = server
		body, statusCode, err, cookie = i.httpPostAdvanced("connection", loginData)

		nextServerIndex++
	}

	if err == nil {

		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		i.CurrentToken = returnData["csrfToken"]
		i.CurrentSession = returnData["sessionId"]
		i.CurrentServer = serverName
		i.CurrentCookie = cookie
		i.UserId = username

	} else {
		log.Printf("ERROR: %s\n", err.Error())
	}
	return
}

//logs into a CIC server through a reverse proxy where the url to reach the server would be proxyUrl/serverName
func (i *Icws) ProxyLogin(applicationName, proxyUrl, serverName, username, password string) (err error) {

	log.Printf("Logging into %s with user %s", serverName, username)

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": applicationName,
		"userID":          username,
		"password":        password,
	}

	return i.ProxyLoginWithData(proxyUrl, serverName, username, loginData)
}

//Logs into a CIC server for a MarketPlace application using the app's custom license.  Server should be a url e.g. https://MyServer:8019
func (i *Icws) ProxyLoginMarketPlaceApp(applicationName, proxyUrl, serverName, username, password, marketplaceLicense, marketplaceAppKey string) (err error) {

	var loginData = map[string]string{
		"__type":                            "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName":                   applicationName,
		"userID":                            username,
		"password":                          password,
		"marketPlaceApplicationLicenseName": marketplaceLicense,
		"marketPlaceApplicationCode":        marketplaceAppKey,
	}

	return i.ProxyLoginWithData(proxyUrl, serverName, username, loginData)
}

//Logs into a CIC server.  Server should be a server name e.g. MyServer.domain.com
func (i *Icws) Login(applicationName, server, username, password string) (err error) {

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": applicationName,
		"userID":          username,
		"password":        password,
	}

	return i.loginWithData(applicationName, server, username, password, loginData)
}

//Logs into a CIC server for a MarketPlace application using the app's custom license.  Server should be a url e.g. https://MyServer:8019
func (i *Icws) LoginMarketPlaceApp(applicationName, server, username, password, marketplaceLicense, marketplaceAppKey string) (err error) {

	var loginData = map[string]string{
		"__type":                            "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName":                   applicationName,
		"userID":                            username,
		"password":                          password,
		"marketPlaceApplicationLicenseName": marketplaceLicense,
		"marketPlaceApplicationCode":        marketplaceAppKey,
	}

	return i.loginWithData(applicationName, server, username, password, loginData)
}

//gets server version details.  Does not need to be connected to the server
func (i *Icws) GetVersion() (version ServerVersion, err error) {

	body, err := i.httpNoConnectionGet("/connection/version")

	err = json.Unmarshal(body, &version)

	return
}

//Gets a list of features and their version from the server
func (i *Icws) GetFeatures() (features []ServerFeature, err error) {

	body, err := i.httpNoConnectionGet("/connection/features")

	if err != nil {
		return nil, err
	}

	var featureMap map[string][]ServerFeature
	err = json.Unmarshal(body, &featureMap)

	features = featureMap["featureInfoList"]
	return

}

func (i *Icws) httpDelete(url string) (err error) {

	req, err := i.httpRequest("DELETE", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, _ := ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpGet(url string) (body []byte, err error) {

	req, err := i.httpRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpNoConnectionGet(url string) (body []byte, err error) {

	req, err := i.httpNoConnectionRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpPost(url string, attrs map[string]string) (body []byte, err error) {
	body, _, err, _ = i.httpPostAdvanced(url, attrs)
	return
}

func (i *Icws) httpPostAdvanced(url string, attrs map[string]string) (body []byte, statusCode int, err error, cookie string) {

	rbody, _ := json.Marshal(attrs)
	req, err := i.httpRequest("POST", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()

	statusCode = response.StatusCode

	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	if response.Header["Set-Cookie"] != nil {
		cookie = response.Header["Set-Cookie"][0]
	}
	return
}

func (i *Icws) httpPut(url string, attrs map[string]string) (body []byte, err error) {

	rbody, _ := json.Marshal(attrs)
	req, err := i.httpRequest("PUT", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := i.httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func (i *Icws) httpClient() (client *http.Client) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client = &http.Client{Transport: tr}
	return
}

func (i *Icws) httpNoConnectionRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, i.CurrentServer+"/icws"+url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	return
}

func (i *Icws) httpRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, i.CurrentServer+"/icws/"+i.CurrentSession+url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	if len(i.CurrentCookie) > 0 {
		request.Header.Add("Cookie", i.CurrentCookie)
	} else {
		return
	}

	if len(i.CurrentToken) > 0 {
		request.Header.Add("ININ-ICWS-CSRF-Token", i.CurrentToken)
	} else {
		return
	}

	// request.Header.Add("User-Agent", fmt.Sprintf("cic cli (%s-%s)", runtime.GOOS, runtime.GOARCH))
	return
}

func createErrorMessage(statusCode int, body []byte) string {

	var errorDescription string

	switch statusCode {
	case 400:
		errorDescription = "Bad Request (400)"
	case 401:
		errorDescription = "Unauthorized (401)"
	case 403:
		errorDescription = "Forbidden (403)"
	case 404:
		errorDescription = "Not Found (404)"
	case 410:
		errorDescription = "Gone (410)"
	case 500:
		errorDescription = "Internal Server Error (500)"
	}

	var message map[string]interface{}
	json.Unmarshal(body, &message)

	if message["errorId"] != nil {
		errorDescription += ": " + message["errorId"].(string)
	}

	if message["message"] != nil {
		errorDescription += " " + message["message"].(string)
	}
	return errorDescription
}
<|endoftext|>


<commit_before>// Package imap partially implements the Internet Message Access Protocol as
// defined in RFC 3501.
//
// Untagged IMAP responses are parsed into a Mailbox struct, which tracks all
// currently known information concerning the state of the remote mailbox.
// Because no significant information is returned through tagged responses,
// interaction with Mailbox is necessary for all queries.

package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	tp "net/textproto"
	"strings"
	"sync"
)

// The IMAP client.
type Client struct {
	// The underlying textproto connection may be used to extend the
	// functionality of this package; however, using Client.Cmd instead is
	// recommended, as doing so better preserves thread-safety.
	Text *tp.Conn

	Box  *Mailbox

	tags map[string]chan string
	tMut *sync.Mutex
}

// Represents the current known state of the remote mailbox.
type Mailbox struct {
	capabilities []string
	mut          *sync.RWMutex
}

func (m *Mailbox) Capable(c string) bool {
	m.mut.RLock()
	for _, ca := range m.capabilities {
		if c == ca {
			return true
		}
	}
	m.mut.RUnlock()
	return false
}

// Dial creates an unsecured connection to the IMAP server at the given address
// and returns the corresponding Client.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// DialTLS creates a TLS_secured connection to the IMAP server at the given
// address and returns the corresponding Client.
func DialTLS(addr string) (*Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// NewClient returns a new Client using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	text := tp.NewConn(conn)
	client := &Client{
		Text: text,
		Box:  &Mailbox{
			capabilities: []string{},
			mut: new(sync.RWMutex),
		},
		tags: map[string]chan string{},
		tMut: new(sync.Mutex),
	}

	input := make(chan string)

	// Read all input from conn
	go func() {
		l, err := text.ReadLine()
		for err == nil {
			input <- l
			l, err = text.ReadLine()
		}
		if err == io.EOF {
			close(input)
		} else {
			panic(err)
		}
	}()

	// Start the serving goroutine
	go func() {
		for {
			select {
			case l := <-input:
				if isUntagged(l) {
					client.handleUntagged(l[2:])
					continue
				}
				// handle tagged response
				ps := strings.SplitN(l, " ", 2)
				tag := ps[0]
				l = ps[1]
				client.tMut.Lock()
				client.tags[tag] <- l
				client.tMut.Unlock()
			}
		}
	}()
	return client, nil
}

func (c *Client) handleUntagged(l string) {
	c.Box.mut.Lock()
	switch l[0:strings.Index(l, " ")] {
	case "CAPABILITY":
		c.Box.capabilities = strings.Split(l, " ")[1:]
	default:
		println(l)
	}
	c.Box.mut.Unlock()
}

func (c *Client) Cmd(format string, args ...interface{}) error {
	t := c.Text
	id := t.Next()
	tag := fmt.Sprintf("x%d", id)
	t.StartRequest(id)
	err := t.PrintfLine("%s %s", tag, fmt.Sprintf(format, args...))
	if err != nil {
		return err
	}
	t.EndRequest(id)

	t.StartResponse(id)
	defer t.EndResponse(id)

	ch := make(chan string)
	c.tMut.Lock()
	c.tags[tag] = ch
	c.tMut.Unlock()

	l := <-ch
	if l[0:2] == "OK" {
		return nil
	}
	return errors.New(l)
}

func isUntagged(l string) bool {
	return l[0:2] == "* "
}

// Noop sends a NOOP command to the server, which may be abused to test that
// the connection is still working, or keep it active.
func (c *Client) Noop() error {
	return c.Cmd("NOOP")
}

// Capability determines the server's capabilities.
func (c *Client) Capability() error {
	return c.Cmd("CAPABILITY")
}

// Login authenticates a client using the provided username and password. This
// method is only secure if TLS is being used. AUTHENTICATE and STARTTLS are
// not supported.
func (c *Client) Login(username, password string) error {
	return c.Cmd("LOGIN %s %s", username, password)
}

// Logout closes the connection, after instructing the server to do the same.
func (c *Client) Logout() error {
	return c.Cmd("LOGOUT")
}

// Select selects the specified IMAP mailbox, updating its information in the
// Mailbox object.
func (c *Client) Select(mb string) error {
	return c.Cmd(`SELECT %s`, mb)
}

// Examine is identical to select, but marks the mailbox read-only.
func (c *Client) Examine(mb string) error {
	return c.Cmd(`EXAMINE %s`, mb)
}

// CREATE

// DELETE

// RENAME

// SUBSCRIBE

// UNSUBSCRIBE

// List lists all folder within basename that match the wildcard expression mb.
// The result is put into the Client's Mailbox struct.
func (c *Client) List(basename, mb string) error {
	return c.Cmd(`LIST "%s" "%s"`, basename, mb)
}

// LSUB

// STATUS

// APPEND

// CHECK

// CLOSE

// EXPUNGE

// SEARCH

// FETCH

// STORE

// COPY

// UID

<commit_msg>CREATE and DELETE<commit_after>// Package imap partially implements the Internet Message Access Protocol as
// defined in RFC 3501.
//
// Untagged IMAP responses are parsed into a Mailbox struct, which tracks all
// currently known information concerning the state of the remote mailbox.
// Because no significant information is returned through tagged responses,
// interaction with Mailbox is necessary for all queries.

package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	tp "net/textproto"
	"strings"
	"sync"
)

// The IMAP client.
type Client struct {
	// The underlying textproto connection may be used to extend the
	// functionality of this package; however, using Client.Cmd instead is
	// recommended, as doing so better preserves thread-safety.
	Text *tp.Conn

	Box  *Mailbox

	tags map[string]chan string
	tMut *sync.Mutex
}

// Represents the current known state of the remote server.
type Mailbox struct {
	capabilities []string
	mut          *sync.RWMutex
}

func (m *Mailbox) Capable(c string) bool {
	m.mut.RLock()
	for _, ca := range m.capabilities {
		if c == ca {
			return true
		}
	}
	m.mut.RUnlock()
	return false
}

// Dial creates an unsecured connection to the IMAP server at the given address
// and returns the corresponding Client.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// DialTLS creates a TLS_secured connection to the IMAP server at the given
// address and returns the corresponding Client.
func DialTLS(addr string) (*Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// NewClient returns a new Client using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	text := tp.NewConn(conn)
	client := &Client{
		Text: text,
		Box:  &Mailbox{
			capabilities: []string{},
			mut: new(sync.RWMutex),
		},
		tags: map[string]chan string{},
		tMut: new(sync.Mutex),
	}

	input := make(chan string)

	// Read all input from conn
	go func() {
		l, err := text.ReadLine()
		for err == nil {
			input <- l
			l, err = text.ReadLine()
		}
		if err == io.EOF {
			close(input)
		} else {
			panic(err)
		}
	}()

	// Start the serving goroutine
	go func() {
		for {
			select {
			case l := <-input:
				if isUntagged(l) {
					client.handleUntagged(l[2:])
					continue
				}
				// handle tagged response
				ps := strings.SplitN(l, " ", 2)
				tag := ps[0]
				l = ps[1]
				client.tMut.Lock()
				client.tags[tag] <- l
				client.tMut.Unlock()
			}
		}
	}()
	return client, nil
}

func (c *Client) handleUntagged(l string) {
	c.Box.mut.Lock()
	switch l[0:strings.Index(l, " ")] {
	case "CAPABILITY":
		c.Box.capabilities = strings.Split(l, " ")[1:]
	default:
		println(l)
	}
	c.Box.mut.Unlock()
}

func (c *Client) Cmd(format string, args ...interface{}) error {
	t := c.Text
	id := t.Next()
	tag := fmt.Sprintf("x%d", id)
	t.StartRequest(id)
	err := t.PrintfLine("%s %s", tag, fmt.Sprintf(format, args...))
	if err != nil {
		return err
	}
	t.EndRequest(id)

	t.StartResponse(id)
	defer t.EndResponse(id)

	ch := make(chan string)
	c.tMut.Lock()
	c.tags[tag] = ch
	c.tMut.Unlock()

	l := <-ch
	if l[0:2] == "OK" {
		return nil
	}
	return errors.New(l)
}

func isUntagged(l string) bool {
	return l[0:2] == "* "
}

// Noop sends a NOOP command to the server, which may be abused to test that
// the connection is still working, or keep it active.
func (c *Client) Noop() error {
	return c.Cmd("NOOP")
}

// Capability determines the server's capabilities.
func (c *Client) Capability() error {
	return c.Cmd("CAPABILITY")
}

// Login authenticates a client using the provided username and password. This
// method is only secure if TLS is being used. AUTHENTICATE and STARTTLS are
// not supported.
func (c *Client) Login(username, password string) error {
	return c.Cmd("LOGIN %s %s", username, password)
}

// Logout closes the connection, after instructing the server to do the same.
func (c *Client) Logout() error {
	return c.Cmd("LOGOUT")
}

// Select selects the specified IMAP mailbox, updating its information in the
// Mailbox object.
func (c *Client) Select(mb string) error {
	return c.Cmd(`SELECT %s`, mb)
}

// Examine is identical to select, but marks the mailbox read-only.
func (c *Client) Examine(mb string) error {
	return c.Cmd(`EXAMINE %s`, mb)
}

// Create creates the named mailbox.
func (c *Client) Create(mb string) error {
	return c.Cmd(`CREATE %s`, mb)
}

// Delete deletes the named mailbox.
func (c *Client) Delete(mb string) error {
	return c.Cmd(`DELETE %s`, mb)
}

// RENAME

// SUBSCRIBE

// UNSUBSCRIBE

// List lists all folder within basename that match the wildcard expression mb.
// The result is put into the Client's Mailbox struct.
func (c *Client) List(basename, mb string) error {
	return c.Cmd(`LIST "%s" "%s"`, basename, mb)
}

// LSUB

// STATUS

// APPEND

// CHECK

// CLOSE

// EXPUNGE

// SEARCH

// FETCH

// STORE

// COPY

// UID

<|endoftext|>


<commit_before>package imup

import (
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"
)

// ImageTypes defines the allowed types for an uploaded image.
type ImageTypes []string

// Image types according to the MIME specification.
const (
	GIF  = "image/gif"
	PNG  = "image/png"
	JPEG = "image/jpeg"
	BMP  = "image/bmp"
	WEBP = "image/webp"
	ICO  = "image/vnd.microsoft.icon"
)

var (
	// Convenience type for popular image types.
	PopularTypes = ImageTypes{GIF, PNG, JPEG}

	// Convenience type for all image types.
	AllTypes = ImageTypes{GIF, PNG, JPEG, BMP, WEBP, ICO}
)

// UploadedImage defines an uploaded image.
type UploadedImage struct {
	Type   string
	file   multipart.File
	header *multipart.FileHeader
}

// Options defines the available options for an image upload.
type Options struct {
	MaxFileSize  int64
	AllowedTypes ImageTypes
}

// New returns a new UploadedImage object if the uploaded file could be parsed
// and validated as an image, otherwise it returns an error.
//
// The key parameter should refer to the name of the file input from the
// multipart form.
func New(key string, r *http.Request, opts *Options) (*UploadedImage, error) {
	var err error
	ui := &UploadedImage{}

	// Handle max file size.
	if opts.MaxFileSize > 0 {
		// Check Content-Length header.
		cl, _ := strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)
		if cl > opts.MaxFileSize {
			return nil, ErrFileSize
		}

		// Wrap r.Body with our limitReader.
		r.Body = newLimitReader(r.Body, opts.MaxFileSize)
	}

	// Try to parse the multipart file from the request.
	if ui.file, ui.header, err = r.FormFile(key); err != nil {
		return nil, err
	}

	// Check if type is allowed.
	if len(opts.AllowedTypes) > 0 {
		if err = isTypeAllowed(ui, opts.AllowedTypes); err != nil {
			return nil, err
		}
	}

	return ui, nil
}

// Save saves the uploaded image to the given location and returns the location
// with the correct image extension added on.
//
// The underlying multipart image file is automatically closed.
func (ui *UploadedImage) Save(filename string) (string, error) {
	// Handle the file extension.
	var ext string
	switch ui.Type {
	case GIF:
		ext = ".gif"
	case PNG:
		ext = ".png"
	case JPEG:
		ext = ".jpg"
	case BMP:
		ext = ".bmp"
	case WEBP:
		ext = ".webp"
	case ICO:
		ext = ".ico"
	}
	filename += ext

	// Create output file.
	out, err := os.Create(filename)
	if err != nil {
		return "", err
	}
	defer out.Close()

	// Store the uploaded image to output file.
	_, err = io.Copy(out, ui.file)
	if err != nil {
		return "", err
	}
	if err = ui.Close(); err != nil {
		return "", err
	}

	return filename, nil
}

// Close closes an uploaded image.
func (ui *UploadedImage) Close() error {
	return ui.file.Close()
}

// isTypeAllowed checks if the given file type is allowed.
func isTypeAllowed(ui *UploadedImage, types ImageTypes) error {
	// Get up to the first 512 bytes of data.
	b := make([]byte, 512)
	_, err := ui.file.Read(b)
	if err != nil {
		return err
	}

	// Reset file pointer.
	if _, err = ui.file.Seek(0, 0); err != nil {
		return err
	}

	// Try to detect the file type.
	ui.Type = http.DetectContentType(b)

	// Validate type.
	for _, t := range types {
		if ui.Type == t {
			return nil
		}
	}

	return ErrDisallowedType
}

// limitReader defines our custom request body ReaderCloser type, which wraps
// the standard io.LimitedReader.
type limitReader struct {
	r *io.LimitedReader
	io.Closer
}

// newLimitReader creates a new limitReader.
func newLimitReader(r io.ReadCloser, maxSize int64) io.ReadCloser {
	return &limitReader{
		r:      &io.LimitedReader{r, maxSize + 1},
		Closer: r,
	}
}

// Read satisfies the io.Reader interface.
//
// ErrFileSize is returned when the limit is exceeded rather than io.EOF like
// the standard io.LimitedReader.
func (l *limitReader) Read(p []byte) (int, error) {
	n, err := l.r.Read(p)
	if l.r.N < 1 {
		return n, ErrFileSize
	}
	return n, err
}
<commit_msg>- golint: Fixed comment for convenience types<commit_after>package imup

import (
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"
)

// ImageTypes defines the allowed types for an uploaded image.
type ImageTypes []string

// Image types according to the MIME specification.
const (
	GIF  = "image/gif"
	PNG  = "image/png"
	JPEG = "image/jpeg"
	BMP  = "image/bmp"
	WEBP = "image/webp"
	ICO  = "image/vnd.microsoft.icon"
)

// Convenience set of image types.
var (
	PopularTypes = ImageTypes{GIF, PNG, JPEG}
	AllTypes     = ImageTypes{GIF, PNG, JPEG, BMP, WEBP, ICO}
)

// UploadedImage defines an uploaded image.
type UploadedImage struct {
	Type   string
	file   multipart.File
	header *multipart.FileHeader
}

// Options defines the available options for an image upload.
type Options struct {
	MaxFileSize  int64
	AllowedTypes ImageTypes
}

// New returns a new UploadedImage object if the uploaded file could be parsed
// and validated as an image, otherwise it returns an error.
//
// The key parameter should refer to the name of the file input from the
// multipart form.
func New(key string, r *http.Request, opts *Options) (*UploadedImage, error) {
	var err error
	ui := &UploadedImage{}

	// Handle max file size.
	if opts.MaxFileSize > 0 {
		// Check Content-Length header.
		cl, _ := strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)
		if cl > opts.MaxFileSize {
			return nil, ErrFileSize
		}

		// Wrap r.Body with our limitReader.
		r.Body = newLimitReader(r.Body, opts.MaxFileSize)
	}

	// Try to parse the multipart file from the request.
	if ui.file, ui.header, err = r.FormFile(key); err != nil {
		return nil, err
	}

	// Check if type is allowed.
	if len(opts.AllowedTypes) > 0 {
		if err = isTypeAllowed(ui, opts.AllowedTypes); err != nil {
			return nil, err
		}
	}

	return ui, nil
}

// Save saves the uploaded image to the given location and returns the location
// with the correct image extension added on.
//
// The underlying multipart image file is automatically closed.
func (ui *UploadedImage) Save(filename string) (string, error) {
	// Handle the file extension.
	var ext string
	switch ui.Type {
	case GIF:
		ext = ".gif"
	case PNG:
		ext = ".png"
	case JPEG:
		ext = ".jpg"
	case BMP:
		ext = ".bmp"
	case WEBP:
		ext = ".webp"
	case ICO:
		ext = ".ico"
	}
	filename += ext

	// Create output file.
	out, err := os.Create(filename)
	if err != nil {
		return "", err
	}
	defer out.Close()

	// Store the uploaded image to output file.
	_, err = io.Copy(out, ui.file)
	if err != nil {
		return "", err
	}
	if err = ui.Close(); err != nil {
		return "", err
	}

	return filename, nil
}

// Close closes an uploaded image.
func (ui *UploadedImage) Close() error {
	return ui.file.Close()
}

// isTypeAllowed checks if the given file type is allowed.
func isTypeAllowed(ui *UploadedImage, types ImageTypes) error {
	// Get up to the first 512 bytes of data.
	b := make([]byte, 512)
	_, err := ui.file.Read(b)
	if err != nil {
		return err
	}

	// Reset file pointer.
	if _, err = ui.file.Seek(0, 0); err != nil {
		return err
	}

	// Try to detect the file type.
	ui.Type = http.DetectContentType(b)

	// Validate type.
	for _, t := range types {
		if ui.Type == t {
			return nil
		}
	}

	return ErrDisallowedType
}

// limitReader defines our custom request body ReaderCloser type, which wraps
// the standard io.LimitedReader.
type limitReader struct {
	r *io.LimitedReader
	io.Closer
}

// newLimitReader creates a new limitReader.
func newLimitReader(r io.ReadCloser, maxSize int64) io.ReadCloser {
	return &limitReader{
		r:      &io.LimitedReader{r, maxSize + 1},
		Closer: r,
	}
}

// Read satisfies the io.Reader interface.
//
// ErrFileSize is returned when the limit is exceeded rather than io.EOF like
// the standard io.LimitedReader.
func (l *limitReader) Read(p []byte) (int, error) {
	n, err := l.r.Read(p)
	if l.r.N < 1 {
		return n, ErrFileSize
	}
	return n, err
}
<|endoftext|>


<commit_before><commit_msg>Implement run command.<commit_after><|endoftext|>


<commit_before><commit_msg>pprof_mac_fix: more docs<commit_after><|endoftext|>


<commit_before><commit_msg>Add a "new-image" label for new "library" files<commit_after><|endoftext|>


<commit_before><commit_msg>Fix wrong code<commit_after><|endoftext|>


<commit_before><commit_msg>Updated example main code<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed and incosistency with a blocking signal channel.<commit_after><|endoftext|>


<commit_before><commit_msg>Do not forget branches of commits present on multiple sides.<commit_after><|endoftext|>


<commit_before><commit_msg>clean<commit_after><|endoftext|>


<commit_before><commit_msg>Using runtime.NumCPU()<commit_after><|endoftext|>


<commit_before>package picoweb

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"time"

	"strconv"

	"github.com/julienschmidt/httprouter"
	"github.com/tylerb/graceful"

	"github.com/googollee/go-socket.io"
)

var (
	RequestCount int
	isDev        bool
	flash        Flash
)

type Pico struct {
	mux    *httprouter.Router
	server *graceful.Server
	c      chan os.Signal
	sio    *socketio.Server
}

type PicoHandler func(c *Context)

func (p *Pico) Get(pattern string, fn PicoHandler) {
	p.mux.GET(pattern, middle(fn))
}

func (p *Pico) Post(pattern string, fn PicoHandler) {
	p.mux.POST(pattern, middle(fn))
}

func (p *Pico) Put(pattern string, fn PicoHandler) {
	p.mux.PUT(pattern, middle(fn))
}

func (p *Pico) Delete(pattern string, fn PicoHandler) {
	p.mux.DELETE(pattern, middle(fn))
}

func (p *Pico) Static(urlPath, diskPath string) {
	if urlPath[len(urlPath)-1] == '/'{
		urlPath = urlPath[:len(urlPath)-1]
	}

	if urlPath[0:1] != "/"{
		urlPath = "/"+urlPath
	}

	p.mux.ServeFiles(urlPath+"/*filepath", http.Dir(diskPath))
}

func (p *Pico) EnableSocketIoOn(url string) {
	var err error
	p.sio, err = socketio.NewServer(nil)
	p.mux.GET(url, middlehttp(p.sio))
	fmt.Println(err)
}

func (p *Pico) OnConnection(fn func(s socketio.Socket)) {
	p.sio.On("connection", fn)
}

func (p *Pico) OnError(fn func(s socketio.Socket, e error)) {
	p.sio.On("error", fn)
}

func (p *Pico) On(event string, fn func(msg string)) {
	p.sio.On(event, fn)
}

func (p *Pico) GetFlash(sessionId string) interface{} {
	return flash.Get(sessionId)
}

func (p *Pico) SetFlash(sessionId string, value interface{}) {
	flash.Set(sessionId, value)
}

func (p *Pico) Listen(port int) error {
	envPort := os.Getenv("PORT")
	if len(envPort) > 0 {
		pi, err := strconv.Atoi(envPort)
		if err == nil && pi < 65000 {
			port = pi
		}
	}

	p.server = &graceful.Server{
		Timeout: 2 * time.Second,
		Server: &http.Server{
			Addr:    ":" + strconv.Itoa(port),
			Handler: p.mux,
		},
	}
	flash = make(Flash)
	return p.server.ListenAndServe()
}

func (p *Pico) Production() {
	isDev = false
}

func (p *Pico) StopOnInt() {
	p.c = make(chan os.Signal, 1)
	signal.Notify(p.c, os.Interrupt)
	signal.Notify(p.c, os.Kill)

	go func() {
		<-p.c
		if isDev {
			fmt.Println("Shutting Down!")
		}

		p.Stop()

		if isDev {
			fmt.Println("Done!")
		}

		close(p.c)

		os.Exit(0)

	}()
}

func (p *Pico) Stop() {
	p.server.Stop(time.Second * 2)
	fmt.Println("Waiting on Stop Channel")
	flash.Clear()
	<-p.server.StopChan()
	fmt.Println("Channel Returned")
}

func New() *Pico {
	isDev = true
	return &Pico{mux: httprouter.New()}
}
<commit_msg>Options<commit_after>package picoweb

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"time"

	"strconv"

	"github.com/julienschmidt/httprouter"
	"github.com/tylerb/graceful"

	"github.com/googollee/go-socket.io"
)

var (
	RequestCount int
	isDev        bool
	flash        Flash
)

type Pico struct {
	mux    *httprouter.Router
	server *graceful.Server
	c      chan os.Signal
	sio    *socketio.Server
}

type PicoHandler func(c *Context)

func (p *Pico) Get(pattern string, fn PicoHandler) {
	p.mux.GET(pattern, middle(fn))
}

func (p *Pico) Post(pattern string, fn PicoHandler) {
	p.mux.POST(pattern, middle(fn))
}

func (p *Pico) Options(pattern string, fn PicoHandler) {
	p.mux.OPTIONS(pattern, middle(fn))
}

func (p *Pico) Put(pattern string, fn PicoHandler) {
	p.mux.PUT(pattern, middle(fn))
}

func (p *Pico) Delete(pattern string, fn PicoHandler) {
	p.mux.DELETE(pattern, middle(fn))
}

func (p *Pico) Static(urlPath, diskPath string) {
	if urlPath[len(urlPath)-1] == '/' {
		urlPath = urlPath[:len(urlPath)-1]
	}

	if urlPath[0:1] != "/" {
		urlPath = "/" + urlPath
	}

	p.mux.ServeFiles(urlPath+"/*filepath", http.Dir(diskPath))
}

func (p *Pico) EnableSocketIoOn(url string) {
	var err error
	p.sio, err = socketio.NewServer(nil)
	p.mux.GET(url, middlehttp(p.sio))
	fmt.Println(err)
}

func (p *Pico) OnConnection(fn func(s socketio.Socket)) {
	p.sio.On("connection", fn)
}

func (p *Pico) OnError(fn func(s socketio.Socket, e error)) {
	p.sio.On("error", fn)
}

func (p *Pico) On(event string, fn func(msg string)) {
	p.sio.On(event, fn)
}

func (p *Pico) GetFlash(sessionId string) interface{} {
	return flash.Get(sessionId)
}

func (p *Pico) SetFlash(sessionId string, value interface{}) {
	flash.Set(sessionId, value)
}

func (p *Pico) Listen(port int) error {
	envPort := os.Getenv("PORT")
	if len(envPort) > 0 {
		pi, err := strconv.Atoi(envPort)
		if err == nil && pi < 65000 {
			port = pi
		}
	}

	p.server = &graceful.Server{
		Timeout: 2 * time.Second,
		Server: &http.Server{
			Addr:    ":" + strconv.Itoa(port),
			Handler: p.mux,
		},
	}
	flash = make(Flash)
	return p.server.ListenAndServe()
}

func (p *Pico) Production() {
	isDev = false
}

func (p *Pico) StopOnInt() {
	p.c = make(chan os.Signal, 1)
	signal.Notify(p.c, os.Interrupt)
	signal.Notify(p.c, os.Kill)

	go func() {
		<-p.c
		if isDev {
			fmt.Println("Shutting Down!")
		}

		p.Stop()

		if isDev {
			fmt.Println("Done!")
		}

		close(p.c)

		os.Exit(0)

	}()
}

func (p *Pico) Stop() {
	p.server.Stop(time.Second * 2)
	fmt.Println("Waiting on Stop Channel")
	flash.Clear()
	<-p.server.StopChan()
	fmt.Println("Channel Returned")
}

func New() *Pico {
	isDev = true
	return &Pico{mux: httprouter.New()}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
)

// The two arguments that .build executables will be called with, in the "plan"
// or "build" phases.
const (
	ArgDeps  = "deps"
	ArgBuild = "build"
)

// Target represents an individual node in the dependency graph.
type Target struct {
	// Name is the name of the target.
	Name string
}

// Plan is used to build a graph of all the targets and their dependencies.
type Plan struct {
	BuildFunc        func(*Target) error
	DependenciesFunc func(*Target) ([]string, error)

	graph *Graph
}

func newPlan() *Plan {
	return &Plan{
		graph: newGraph(),
	}
}

// Plan builds the graph, starting with the given target.
func (p *Plan) Plan(target string) (*Target, error) {
	t := &Target{
		Name: target,
	}

	if t := p.graph.Add(t); t != nil {
		// If this target already exists in the graph, nothing to do.
		return t, nil
	}

	deps, err := p.DependenciesFunc(t)
	if err != nil {
		return t, fmt.Errorf("error getting dependencies for %s: %v", target, err)
	}

	for _, d := range deps {
		dep, err := p.Plan(d)
		if err != nil {
			return t, err
		}
		p.graph.Connect(t, dep)
	}

	return t, nil
}

// Build executes the plan.
func (p *Plan) Build() error {
	err := p.graph.Walk(func(t *Target) error {
		return p.BuildFunc(t)
	})
	return err
}

func Dependencies(target *Target) ([]string, error) {
	t, err := newFileTarget(target)
	if err != nil {
		return nil, err
	}

	// No .build file, meaning it's a static dependency.
	if t.buildfile == "" {
		return nil, nil
	}

	cmd := t.buildCommand(ArgDeps)
	out, err := cmd.Output()
	if err != nil {
		return nil, err
	}

	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	var deps []string
	scanner := bufio.NewScanner(bytes.NewReader(out))
	for scanner.Scan() {
		path := scanner.Text()
		// Make all paths relative to the working directory.
		path, err := filepath.Rel(wd, filepath.Join(t.buildir, scanner.Text()))
		if err != nil {
			return deps, err
		}
		deps = append(deps, path)
	}

	return deps, scanner.Err()
}

func VerboseBuild(target *Target) error {
	t, err := newFileTarget(target)
	if err != nil {
		return err
	}

	err = BuildFile(t)
	if err == nil && t.buildfile != "" {
		fmt.Printf("build  %s\n", t.Name)
	}
	return err
}

// BuildFile builds the fileTarget.
func BuildFile(t *fileTarget) error {
	if t.buildfile == "" {
		// It's possible for a target to simply be a static file, in which case
		// we don't need to perform a build. We do however want to ensure that
		// it exists in this case.
		_, err := os.Stat(t.path)
		return err
	}

	cmd := t.buildCommand(ArgBuild)
	return cmd.Run()
}

// fileTarget extends a Target that's represented by a file.
type fileTarget struct {
	*Target

	// The absolute path to the file.
	path string

	// path to the buildfile to use.
	buildfile string

	// the directory to use as the working directory when executing the
	// build file.
	buildir string
}

// newFileTarget initializes and returns a new fileTarget instance.
func newFileTarget(t *Target) (*fileTarget, error) {
	path, err := filepath.Abs(t.Name)
	if err != nil {
		return nil, err
	}

	buildfile, err := buildFile(path)
	if err != nil {
		return nil, err
	}

	var buildir string
	if buildfile != "" {
		buildir = filepath.Dir(path)
	}

	return &fileTarget{
		Target:    t,
		path:      path,
		buildfile: buildfile,
		buildir:   buildir,
	}, nil
}

func (t *fileTarget) buildCommand(subcommand string) *exec.Cmd {
	ext := filepath.Ext(t.path)
	name := filepath.Base(t.path)
	nameWithoutExt := name[0 : len(name)-len(ext)]
	cmd := exec.Command(t.buildfile, subcommand, name, nameWithoutExt)
	cmd.Stderr = os.Stderr
	cmd.Dir = t.buildir
	return cmd
}

// buildFile returns the path to the .build file that should be used to build
// this target. If the target has no approriate .build file, then "" is
// returned.
func buildFile(path string) (string, error) {
	dir := filepath.Dir(path)
	name := filepath.Base(path)
	ext := filepath.Ext(name)
	try := []string{
		filepath.Join(".build", name),           // .build/hello.o
		fmt.Sprintf("%s.build", name),           // hello.o.build
		filepath.Join(".build/default%s", name), // .build/default.o
		fmt.Sprintf("default%s.build", ext),     // default.o.build
	}

	for _, n := range try {
		path := filepath.Join(dir, n)
		_, err := os.Stat(path)
		if err == nil {
			return path, nil
		}
	}

	return "", nil
}
<commit_msg>Fix .build/default<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
)

// The two arguments that .build executables will be called with, in the "plan"
// or "build" phases.
const (
	ArgDeps  = "deps"
	ArgBuild = "build"
)

// Target represents an individual node in the dependency graph.
type Target struct {
	// Name is the name of the target.
	Name string
}

// Plan is used to build a graph of all the targets and their dependencies.
type Plan struct {
	BuildFunc        func(*Target) error
	DependenciesFunc func(*Target) ([]string, error)

	graph *Graph
}

func newPlan() *Plan {
	return &Plan{
		graph: newGraph(),
	}
}

// Plan builds the graph, starting with the given target.
func (p *Plan) Plan(target string) (*Target, error) {
	t := &Target{
		Name: target,
	}

	if t := p.graph.Add(t); t != nil {
		// If this target already exists in the graph, nothing to do.
		return t, nil
	}

	deps, err := p.DependenciesFunc(t)
	if err != nil {
		return t, fmt.Errorf("error getting dependencies for %s: %v", target, err)
	}

	for _, d := range deps {
		dep, err := p.Plan(d)
		if err != nil {
			return t, err
		}
		p.graph.Connect(t, dep)
	}

	return t, nil
}

// Build executes the plan.
func (p *Plan) Build() error {
	err := p.graph.Walk(func(t *Target) error {
		return p.BuildFunc(t)
	})
	return err
}

func Dependencies(target *Target) ([]string, error) {
	t, err := newFileTarget(target)
	if err != nil {
		return nil, err
	}

	// No .build file, meaning it's a static dependency.
	if t.buildfile == "" {
		return nil, nil
	}

	cmd := t.buildCommand(ArgDeps)
	out, err := cmd.Output()
	if err != nil {
		return nil, err
	}

	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	var deps []string
	scanner := bufio.NewScanner(bytes.NewReader(out))
	for scanner.Scan() {
		path := scanner.Text()
		// Make all paths relative to the working directory.
		path, err := filepath.Rel(wd, filepath.Join(t.buildir, scanner.Text()))
		if err != nil {
			return deps, err
		}
		deps = append(deps, path)
	}

	return deps, scanner.Err()
}

func VerboseBuild(target *Target) error {
	t, err := newFileTarget(target)
	if err != nil {
		return err
	}

	err = BuildFile(t)
	if err == nil && t.buildfile != "" {
		fmt.Printf("%s\n", t.Name)
	}
	return err
}

// BuildFile builds the fileTarget.
func BuildFile(t *fileTarget) error {
	if t.buildfile == "" {
		// It's possible for a target to simply be a static file, in which case
		// we don't need to perform a build. We do however want to ensure that
		// it exists in this case.
		_, err := os.Stat(t.path)
		return err
	}

	cmd := t.buildCommand(ArgBuild)
	return cmd.Run()
}

// fileTarget extends a Target that's represented by a file.
type fileTarget struct {
	*Target

	// The absolute path to the file.
	path string

	// path to the buildfile to use.
	buildfile string

	// the directory to use as the working directory when executing the
	// build file.
	buildir string
}

// newFileTarget initializes and returns a new fileTarget instance.
func newFileTarget(t *Target) (*fileTarget, error) {
	path, err := filepath.Abs(t.Name)
	if err != nil {
		return nil, err
	}

	buildfile, err := buildFile(path)
	if err != nil {
		return nil, err
	}

	var buildir string
	if buildfile != "" {
		buildir = filepath.Dir(path)
	}

	return &fileTarget{
		Target:    t,
		path:      path,
		buildfile: buildfile,
		buildir:   buildir,
	}, nil
}

func (t *fileTarget) buildCommand(subcommand string) *exec.Cmd {
	ext := filepath.Ext(t.path)
	name := filepath.Base(t.path)
	nameWithoutExt := name[0 : len(name)-len(ext)]
	cmd := exec.Command(t.buildfile, subcommand, name, nameWithoutExt)
	cmd.Stderr = os.Stderr
	cmd.Dir = t.buildir
	return cmd
}

// buildFile returns the path to the .build file that should be used to build
// this target. If the target has no appropriate .build file, then "" is
// returned.
func buildFile(path string) (string, error) {
	dir := filepath.Dir(path)
	name := filepath.Base(path)
	ext := filepath.Ext(name)
	try := []string{
		filepath.Join(".build", name),                          // .build/hello.o
		fmt.Sprintf("%s.build", name),                          // hello.o.build
		filepath.Join(".build", fmt.Sprintf("default%s", ext)), // .build/default.o
		fmt.Sprintf("default%s.build", ext),                    // default.o.build
	}

	for _, n := range try {
		path := filepath.Join(dir, n)
		_, err := os.Stat(path)
		if err == nil {
			return path, nil
		}
	}

	return "", nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
)

// Goのflagパッケージで同名の引数を複数受け取る - Qiita
// http://qiita.com/hironobu_s/items/96e8397ec453dfb976d4
type strslice []string

func (s *strslice) String() string {
    return fmt.Sprintf("%v", *s)
}

func (s *strslice) Set(v string) error {
    *s = append(*s, v)
    return nil
}

func main() {
	var ignore_dirs strslice
	var empty_dirs strslice
	input_dir := flag.String( "top", ".", "tree TOP directory" )
	flag.Var( &ignore_dirs,  "xd", "eXclude Directory" )
	file_display := flag.Bool( "f", false, "Dispaly files" )
	flag.Var( &empty_dirs, "emd", "Behavior as empty directory" )
	flag.Parse()

	fmt.Println(*input_dir)
	tree(*input_dir, *input_dir, 0, "", *file_display, ignore_dirs, empty_dirs)
}

func tree(rootPath, searchPath string, depth int, parent string, file_display bool, ignore_dirs []string, empty_dirs []string) {
	fis, err := ioutil.ReadDir(searchPath)

	if err != nil {
		//fmt.Println( searchPath, " is error" )
		//panic(err)
		return
	}

	searchName := filepath.Base(searchPath)
	for _, emd := range empty_dirs {
		if searchName == emd {
			return
		}
	}

	dirlist  := make([]string, 0)
	filelist := make([]string, 0)
	for _, fi := range fis {
		fullPath := filepath.Join(searchPath, fi.Name())

		if fi.IsDir() {
			ignore := false
			for _, ignore_dir := range ignore_dirs {
				if ignore_dir == fi.Name() {
					ignore = true
					break
				}
			}
			if !ignore {
				dirlist = append(dirlist, fullPath)
			}
		} else if file_display {
			filelist = append(filelist, fullPath)
		}
	}

	has_dir := ( 0 < len(dirlist) )
	for _, file := range filelist {
		rel, err := filepath.Rel(rootPath, file)

		if err != nil {
			//panic(err)
			return
		}

		base := filepath.Base(rel)

		if has_dir {
			fmt.Println(parent + "│  ", base )
		} else {
			fmt.Println(parent + "    ", base )
		}
	}
	if 0 < len(filelist) {
		if has_dir {
			fmt.Println(parent + "│" )
		} else {
			fmt.Println(parent)
		}
	}

	for idx, dir := range dirlist {
		rel, err := filepath.Rel(rootPath, dir)
		has_young_brother := ( 0 < len(dirlist[idx+1:]) )
		next := ""

		if err != nil {
			//panic(err)
			return
		}

		base := filepath.Base(rel)

		if has_young_brother {
			fmt.Println(parent + "├─", base )
			next += "│  "
		} else {
			fmt.Println(parent + "└─", base )
			next += "    "
		}
		tree(rootPath, dir, depth + 1, parent + next, file_display, ignore_dirs, empty_dirs)
	}

}
<commit_msg>Empty dir check is First<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
)

// Goのflagパッケージで同名の引数を複数受け取る - Qiita
// http://qiita.com/hironobu_s/items/96e8397ec453dfb976d4
type strslice []string

func (s *strslice) String() string {
    return fmt.Sprintf("%v", *s)
}

func (s *strslice) Set(v string) error {
    *s = append(*s, v)
    return nil
}

func main() {
	var ignore_dirs strslice
	var empty_dirs strslice
	input_dir := flag.String( "top", ".", "tree TOP directory" )
	flag.Var( &ignore_dirs,  "xd", "eXclude Directory" )
	file_display := flag.Bool( "f", false, "Dispaly files" )
	flag.Var( &empty_dirs, "emd", "Behavior as empty directory" )
	flag.Parse()

	fmt.Println(*input_dir)
	tree(*input_dir, *input_dir, 0, "", *file_display, ignore_dirs, empty_dirs)
}

func tree(rootPath, searchPath string, depth int, parent string, file_display bool, ignore_dirs []string, empty_dirs []string) {

	searchName := filepath.Base(searchPath)
	for _, emd := range empty_dirs {
		if searchName == emd {
			// 空ディレクトリ扱いの場合、以降の処理は不要
			return
		}
	}

	fis, err := ioutil.ReadDir(searchPath)

	if err != nil {
		//fmt.Println( searchPath, " is error" )
		//panic(err)
		return
	}

	dirlist  := make([]string, 0)
	filelist := make([]string, 0)
	for _, fi := range fis {
		fullPath := filepath.Join(searchPath, fi.Name())

		if fi.IsDir() {
			ignore := false
			for _, ignore_dir := range ignore_dirs {
				if ignore_dir == fi.Name() {
					ignore = true
					break
				}
			}
			if !ignore {
				dirlist = append(dirlist, fullPath)
			}
		} else if file_display {
			filelist = append(filelist, fullPath)
		}
	}

	has_dir := ( 0 < len(dirlist) )
	for _, file := range filelist {
		rel, err := filepath.Rel(rootPath, file)

		if err != nil {
			//panic(err)
			return
		}

		base := filepath.Base(rel)

		if has_dir {
			fmt.Println(parent + "│  ", base )
		} else {
			fmt.Println(parent + "    ", base )
		}
	}
	if 0 < len(filelist) {
		if has_dir {
			fmt.Println(parent + "│" )
		} else {
			fmt.Println(parent)
		}
	}

	for idx, dir := range dirlist {
		rel, err := filepath.Rel(rootPath, dir)
		has_young_brother := ( 0 < len(dirlist[idx+1:]) )
		next := ""

		if err != nil {
			//panic(err)
			return
		}

		base := filepath.Base(rel)

		if has_young_brother {
			fmt.Println(parent + "├─", base )
			next += "│  "
		} else {
			fmt.Println(parent + "└─", base )
			next += "    "
		}
		tree(rootPath, dir, depth + 1, parent + next, file_display, ignore_dirs, empty_dirs)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"time"
)

const MSG_MAX_LEN = 256

const (
	EXPECT_START = iota
	EXPECT_DONE
	IN_MESSAGE
)

type handleable interface {
	Handle()
}

type Action struct {
	MatchSequence []byte
	decodeInto    handleable
}

type trimbleCmd interface {
	PacketID() []byte
}

type GetSoftwareVersionCmd struct {
	// NODATA - this command is empty
}

// Note:  The Thunderbolt E appears to send year - 2000 for the App/GPS info, not
// Year - 1900.  (But the packet struct here is written per the spec).
// Also, Trimble refers to the software version as 2.10, but it gets
// reported here - again, per the spec, as 10.2.  Beats me.
type SoftwareVersionPacket struct {
	AppMajor uint8
	AppMinor uint8
	AppMonth uint8
	AppDay uint8
	AppYearFrom1900 uint8
	GPSMajor uint8
	GPSMinor uint8
	GPSMonth uint8
	GPSDay uint8
	GPSYearFrom1900 uint8
}
func (c *GetSoftwareVersionCmd) PacketID() []byte { return []byte{0x1f} }

type PrimaryTimingPacket struct {
	Subcode    uint8
	TimeOfWeek uint32
	WeekNumber uint16
	UTCOffset  int16
	TimingFlag byte
	Seconds    uint8
	Minutes    uint8
	Hours      uint8
	DayOfMonth uint8
	Month      uint8
	Year       uint16
}

type SecondaryTimingPacket struct {
	Subcode              uint8
	ReceiverMode         uint8
	DiscipliningMode     uint8
	SelfSurveyProgress   uint8
	HoldoverDuration     uint32
	CriticalAlarms       uint16
	MinorAlarms          uint16
	GPSDecodeStatus      uint8
	DiscipliningActivity uint8
	SpareStatus1         uint8
	SpareStatus2         uint8
	PPSOffset            float32
	TenMhzOffset         float32
	DACValue             uint32
	DACVoltage           float32
	Temperature          float32
	Latitude             float64
	Longitude            float64
	Altitude             float64
	Spare                int64
}

func (p *SecondaryTimingPacket) Handle() {
	fmt.Printf("Secondary packet:  RCV %d, DIS %d, SUR %d PPS-OFFSET: %f CriticalAlarm: %x MinorAlarm: %x  Temp: %f\n", p.ReceiverMode, p.DiscipliningMode, p.SelfSurveyProgress, p.PPSOffset, p.CriticalAlarms, p.MinorAlarms, p.Temperature)
}

func (p *PrimaryTimingPacket) Handle() {
	fmt.Printf("Primary Timing Packet:  %d/%d/%d %d:%d:%d  (GPS offset %d)\n", p.Year, p.Month, p.DayOfMonth, p.Hours, p.Minutes, p.Seconds, p.UTCOffset)

}

func (p *SoftwareVersionPacket) Handle() {
	fmt.Printf("Software Version Response.  App: %d.%d %d/%d/%d  GPS: %d.%d %d/%d/%d\n",
		p.AppMajor, p.AppMinor, int(p.AppYearFrom1900)+1900, p.AppMonth, p.AppDay,
		p.GPSMajor, p.GPSMinor, int(p.GPSYearFrom1900)+1900, p.GPSMonth, p.GPSDay)
}

var actions []Action

func init() {
	// HUMAN:  The parser requires that you list these in descending
	// order of MatchSequence length.
	actions = []Action{
		Action{[]byte{0x8f, 0xab}, &PrimaryTimingPacket{}},
		Action{[]byte{0x8f, 0xac}, &SecondaryTimingPacket{}},
		Action{[]byte{0x45}, &SoftwareVersionPacket{}},
	}
}

func sendCmd(c trimbleCmd) {
	buf := new(bytes.Buffer)
	// DLE.id.{cmd bytes}.DLE.ETX
	_ = binary.Write(buf, binary.BigEndian, c)
	bufBytes := buf.Bytes()
	bufNew := bytes.Replace(bufBytes, []byte{0x10}, []byte{0x10,0x10}, -1)
	buf.Reset()
	buf.WriteByte(0x10)
	buf.Write(c.PacketID())
	buf.Write(bufNew)
	buf.Write([]byte{0x10,0x03})

	buf.WriteTo(theConn)
}

func handleMsg(msg []byte) {
	var p handleable
	handled := false

	for _, a := range actions {
		alen := len(a.MatchSequence)
		if bytes.Equal(msg[0:alen], a.MatchSequence) {
			p = a.decodeInto
			handled = true
			break
		}
	}

	if handled {
		r := bytes.NewReader(msg[1:])
		binary.Read(r, binary.BigEndian, p)
		p.Handle()
	} else {
		fmt.Printf("Unknown packet type: %x (%x)\n", msg[0], msg[1])
	}
}

var theConn net.Conn // xxx, fix me...

func main() {
	fmt.Println("connecting to serial server")
	conn, err := net.Dial("tcp", "192.168.2.111:6001")
	if err != nil {
		fmt.Println("could not connect:", err)
		return
	}
	theConn = conn
	br := bufio.NewReader(conn)
	// Find a start of message
	for {
		c, _ := br.ReadByte()
		if c == 0x10 {
			c, _ := br.ReadByte()
			if c == 0x3 {
				break
			}
		}
	}
	state := 0
	// XXX - demo:  Grab the software version command after running for a second.
	go func() {
		time.Sleep(time.Second)
		fmt.Println("Sending GetSoftwareVersionCmd")
		sendCmd(&GetSoftwareVersionCmd{})
	}()

	var msg [MSG_MAX_LEN]byte
	msgptr := 0
	for {
		c, _ := br.ReadByte()
		if c == 0x10 {
			// Attempt to de-stuff DLEs if they're in message data
			nextbytes, _ := br.Peek(1)
			if nextbytes[0] == 0x10 {
				c, _ = br.ReadByte()
			} else {
				if state == EXPECT_START {
					msgptr = 0
					state = IN_MESSAGE
					continue
				} else {
					state = EXPECT_DONE
					continue
				}
			}
		}

		if state == EXPECT_DONE {
			if c != 0x03 {
				fmt.Println("Error:  Expected to be done, got", c)
				return
			} else {
				handleMsg(msg[0:msgptr])
				state = EXPECT_START
			}
		}
		if msgptr < MSG_MAX_LEN {
			msg[msgptr] = c
			msgptr++
		} // Else silently discard the rest of the message.  *shrug*
		// This should not happen.
	}
}
<commit_msg>gofmt<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"time"
)

const MSG_MAX_LEN = 256

const (
	EXPECT_START = iota
	EXPECT_DONE
	IN_MESSAGE
)

type handleable interface {
	Handle()
}

type Action struct {
	MatchSequence []byte
	decodeInto    handleable
}

type trimbleCmd interface {
	PacketID() []byte
}

type GetSoftwareVersionCmd struct {
	// NODATA - this command is empty
}

// Note:  The Thunderbolt E appears to send year - 2000 for the App/GPS info, not
// Year - 1900.  (But the packet struct here is written per the spec).
// Also, Trimble refers to the software version as 2.10, but it gets
// reported here - again, per the spec, as 10.2.  Beats me.
type SoftwareVersionPacket struct {
	AppMajor        uint8
	AppMinor        uint8
	AppMonth        uint8
	AppDay          uint8
	AppYearFrom1900 uint8
	GPSMajor        uint8
	GPSMinor        uint8
	GPSMonth        uint8
	GPSDay          uint8
	GPSYearFrom1900 uint8
}

func (c *GetSoftwareVersionCmd) PacketID() []byte { return []byte{0x1f} }

type PrimaryTimingPacket struct {
	Subcode    uint8
	TimeOfWeek uint32
	WeekNumber uint16
	UTCOffset  int16
	TimingFlag byte
	Seconds    uint8
	Minutes    uint8
	Hours      uint8
	DayOfMonth uint8
	Month      uint8
	Year       uint16
}

type SecondaryTimingPacket struct {
	Subcode              uint8
	ReceiverMode         uint8
	DiscipliningMode     uint8
	SelfSurveyProgress   uint8
	HoldoverDuration     uint32
	CriticalAlarms       uint16
	MinorAlarms          uint16
	GPSDecodeStatus      uint8
	DiscipliningActivity uint8
	SpareStatus1         uint8
	SpareStatus2         uint8
	PPSOffset            float32
	TenMhzOffset         float32
	DACValue             uint32
	DACVoltage           float32
	Temperature          float32
	Latitude             float64
	Longitude            float64
	Altitude             float64
	Spare                int64
}

func (p *SecondaryTimingPacket) Handle() {
	fmt.Printf("Secondary packet:  RCV %d, DIS %d, SUR %d PPS-OFFSET: %f CriticalAlarm: %x MinorAlarm: %x  Temp: %f\n", p.ReceiverMode, p.DiscipliningMode, p.SelfSurveyProgress, p.PPSOffset, p.CriticalAlarms, p.MinorAlarms, p.Temperature)
}

func (p *PrimaryTimingPacket) Handle() {
	fmt.Printf("Primary Timing Packet:  %d/%d/%d %d:%d:%d  (GPS offset %d)\n", p.Year, p.Month, p.DayOfMonth, p.Hours, p.Minutes, p.Seconds, p.UTCOffset)

}

func (p *SoftwareVersionPacket) Handle() {
	fmt.Printf("Software Version Response.  App: %d.%d %d/%d/%d  GPS: %d.%d %d/%d/%d\n",
		p.AppMajor, p.AppMinor, int(p.AppYearFrom1900)+1900, p.AppMonth, p.AppDay,
		p.GPSMajor, p.GPSMinor, int(p.GPSYearFrom1900)+1900, p.GPSMonth, p.GPSDay)
}

var actions []Action

func init() {
	// HUMAN:  The parser requires that you list these in descending
	// order of MatchSequence length.
	actions = []Action{
		Action{[]byte{0x8f, 0xab}, &PrimaryTimingPacket{}},
		Action{[]byte{0x8f, 0xac}, &SecondaryTimingPacket{}},
		Action{[]byte{0x45}, &SoftwareVersionPacket{}},
	}
}

func sendCmd(c trimbleCmd) {
	buf := new(bytes.Buffer)
	// DLE.id.{cmd bytes}.DLE.ETX
	_ = binary.Write(buf, binary.BigEndian, c)
	bufBytes := buf.Bytes()
	bufNew := bytes.Replace(bufBytes, []byte{0x10}, []byte{0x10, 0x10}, -1)
	buf.Reset()
	buf.WriteByte(0x10)
	buf.Write(c.PacketID())
	buf.Write(bufNew)
	buf.Write([]byte{0x10, 0x03})

	buf.WriteTo(theConn)
}

func handleMsg(msg []byte) {
	var p handleable
	handled := false

	for _, a := range actions {
		alen := len(a.MatchSequence)
		if bytes.Equal(msg[0:alen], a.MatchSequence) {
			p = a.decodeInto
			handled = true
			break
		}
	}

	if handled {
		r := bytes.NewReader(msg[1:])
		binary.Read(r, binary.BigEndian, p)
		p.Handle()
	} else {
		fmt.Printf("Unknown packet type: %x (%x)\n", msg[0], msg[1])
	}
}

var theConn net.Conn // xxx, fix me...

func main() {
	fmt.Println("connecting to serial server")
	conn, err := net.Dial("tcp", "192.168.2.111:6001")
	if err != nil {
		fmt.Println("could not connect:", err)
		return
	}
	theConn = conn
	br := bufio.NewReader(conn)
	// Find a start of message
	for {
		c, _ := br.ReadByte()
		if c == 0x10 {
			c, _ := br.ReadByte()
			if c == 0x3 {
				break
			}
		}
	}
	state := 0
	// XXX - demo:  Grab the software version command after running for a second.
	go func() {
		time.Sleep(time.Second)
		fmt.Println("Sending GetSoftwareVersionCmd")
		sendCmd(&GetSoftwareVersionCmd{})
	}()

	var msg [MSG_MAX_LEN]byte
	msgptr := 0
	for {
		c, _ := br.ReadByte()
		if c == 0x10 {
			// Attempt to de-stuff DLEs if they're in message data
			nextbytes, _ := br.Peek(1)
			if nextbytes[0] == 0x10 {
				c, _ = br.ReadByte()
			} else {
				if state == EXPECT_START {
					msgptr = 0
					state = IN_MESSAGE
					continue
				} else {
					state = EXPECT_DONE
					continue
				}
			}
		}

		if state == EXPECT_DONE {
			if c != 0x03 {
				fmt.Println("Error:  Expected to be done, got", c)
				return
			} else {
				handleMsg(msg[0:msgptr])
				state = EXPECT_START
			}
		}
		if msgptr < MSG_MAX_LEN {
			msg[msgptr] = c
			msgptr++
		} // Else silently discard the rest of the message.  *shrug*
		// This should not happen.
	}
}
<|endoftext|>


<commit_before>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum: TEXT_TYPE,
		Set:  TEXT_TYPE,
		//Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<commit_msg>fix compitable<commit_after>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<|endoftext|>


<commit_before>// Bindings for glib
package glib

/*
#include <stdlib.h>
#include <glib-object.h>

#define _GINT_SIZE sizeof(gint)
#define _GLONG_SIZE sizeof(glong)

#cgo pkg-config: glib-2.0 gobject-2.0 gthread-2.0
*/
import "C"

import (
	"reflect"
	"strconv"
	"unsafe"
)

type TypeGetter interface {
	Type() Type
}

type PointerSetter interface {
	SetPtr(p Pointer)
}

// A numerical value which represents the unique identifier of a registered type
type Type C.GType

const (
	TYPE_INVALID   = Type(C.G_TYPE_INVALID)
	TYPE_NONE      = Type(C.G_TYPE_NONE)
	TYPE_INTERFACE = Type(C.G_TYPE_INTERFACE)
	TYPE_CHAR      = Type(C.G_TYPE_CHAR)
	TYPE_UCHAR     = Type(C.G_TYPE_UCHAR)
	TYPE_BOOLEAN   = Type(C.G_TYPE_BOOLEAN)
	TYPE_INT       = Type(C.G_TYPE_INT)
	TYPE_UINT      = Type(C.G_TYPE_UINT)
	TYPE_LONG      = Type(C.G_TYPE_LONG)
	TYPE_ULONG     = Type(C.G_TYPE_ULONG)
	TYPE_INT64     = Type(C.G_TYPE_INT64)
	TYPE_UINT64    = Type(C.G_TYPE_UINT64)
	TYPE_ENUM      = Type(C.G_TYPE_ENUM)
	TYPE_FLAGS     = Type(C.G_TYPE_FLAGS)
	TYPE_FLOAT     = Type(C.G_TYPE_FLOAT)
	TYPE_DOUBLE    = Type(C.G_TYPE_DOUBLE)
	TYPE_STRING    = Type(C.G_TYPE_STRING)
	TYPE_POINTER   = Type(C.G_TYPE_POINTER)
	TYPE_BOXED     = Type(C.G_TYPE_BOXED)
	TYPE_PARAM     = Type(C.G_TYPE_PARAM)
	TYPE_OBJECT    = Type(C.G_TYPE_OBJECT)
	TYPE_VARIANT   = Type(C.G_TYPE_VARIANT)
)

var (
	TYPE_GTYPE     Type
	TYPE_GO_INT    Type
	TYPE_GO_UINT   Type
	TYPE_GO_INT32  Type
	TYPE_GO_UINT32 Type
)

func (t Type) g() C.GType {
	return C.GType(t)
}

func (t Type) String() string {
	return C.GoString((*C.char)(C.g_type_name(t.g())))
}

func (t Type) QName() Quark {
	return Quark(C.g_type_qname(t.g()))
}

func (t Type) Type() Type {
	return TYPE_GTYPE
}

func (t Type) Value() *Value {
	v := NewValue(t.Type())
	C.g_value_set_gtype(v.g(), t.g())
	return v
}

func (t Type) Parent() Type {
	return Type(C.g_type_parent(t.g()))
}

func (t Type) Depth() uint {
	return uint(C.g_type_depth(t.g()))
}

// Returns the type that is derived directly from root type which is also
// a base class of t
func (t Type) NextBase(root Type) Type {
	return Type(C.g_type_next_base(t.g(), root.g()))
}

// If t type is a derivable type, check whether type is a descendant of
// it type. If t type is an glib interface, check whether type conforms
// to it.
func (t Type) IsA(it Type) bool {
	return C.g_type_is_a(t.g(), it.g()) != 0
}

var type_getter = reflect.TypeOf((*TypeGetter)(nil)).Elem()
var object_caster = reflect.TypeOf((*ObjectCaster)(nil)).Elem()

func (t Type) Match(rt reflect.Type) bool {
	if rt.Implements(object_caster) {
		return t.IsA(TYPE_OBJECT)
	}
	if rt.Implements(type_getter) {
		if rt.Kind() == reflect.Ptr {
			rt = rt.Elem()
		}
		r := reflect.New(rt).Interface().(TypeGetter).Type()
		return t.QName() == r.QName()
	}
	switch rt.Kind() {
	case reflect.Invalid:
		return t == TYPE_INVALID

	case reflect.String:
		return t == TYPE_STRING

	case reflect.Int:
		return t == TYPE_GO_INT

	case reflect.Uint:
		return t == TYPE_GO_UINT

	case reflect.Int8:
		return t == TYPE_CHAR

	case reflect.Uint8:
		return t == TYPE_UCHAR

	case reflect.Int32:
		return t == TYPE_GO_INT32

	case reflect.Uint32:
		return t == TYPE_GO_UINT32

	case reflect.Int64:
		return t == TYPE_INT64

	case reflect.Uint64:
		return t == TYPE_UINT64

	case reflect.Bool:
		return t == TYPE_BOOLEAN

	case reflect.Float32:
		return t == TYPE_FLOAT

	case reflect.Float64:
		return t == TYPE_DOUBLE

	case reflect.Ptr:
		return t == TYPE_POINTER
	}
	return false
}

// Returns the Type of the value in the interface{}.
func TypeOf(i interface{}) Type {
	// Types ov values that implements TypeGetter
	if o, ok := i.(TypeGetter); ok {
		return o.Type()
	}
	// Other types
	switch reflect.TypeOf(i).Kind() {
	case reflect.Invalid:
		return TYPE_INVALID

	case reflect.Bool:
		return TYPE_BOOLEAN

	case reflect.Int:
		return TYPE_GO_INT

	case reflect.Int8:
		return TYPE_CHAR

	case reflect.Int32:
		return TYPE_GO_INT32

	case reflect.Int64:
		return TYPE_INT64

	case reflect.Uint:
		return TYPE_GO_UINT

	case reflect.Uint8:
		return TYPE_UCHAR

	case reflect.Uint32:
		return TYPE_GO_UINT32

	case reflect.Uint64:
		return TYPE_UINT64

	case reflect.Float32:
		return TYPE_FLOAT

	case reflect.Float64:
		return TYPE_DOUBLE

	case reflect.Ptr:
		return TYPE_POINTER

	case reflect.String:
		return TYPE_STRING
	}
	panic("Can't map Go type to Glib type")
}

func TypeFromName(name string) Type {
	tn := C.CString(name)
	defer C.free(unsafe.Pointer(tn))
	return Type(C.g_type_from_name((*C.gchar)(tn)))
}

func init() {
	C.g_type_init()
	TYPE_GTYPE = Type(C.g_gtype_get_type())
	int_bytes := strconv.IntSize / 8
	if int_bytes == int(C._GINT_SIZE) {
		TYPE_GO_INT = TYPE_INT
		TYPE_GO_UINT = TYPE_UINT
	} else if int_bytes == C._GLONG_SIZE {
		TYPE_GO_INT = TYPE_LONG
		TYPE_GO_UINT = TYPE_ULONG
	} else if int_bytes == 64 {
		TYPE_GO_INT = TYPE_INT64
		TYPE_GO_UINT = TYPE_UINT64
	} else {
		panic("Unexpectd size of 'int'")
	}
	int32_bytes := C.uint(4)
	if int32_bytes == C._GINT_SIZE {
		TYPE_GO_INT32 = TYPE_INT
		TYPE_GO_UINT32 = TYPE_UINT
	} else if int32_bytes == C._GLONG_SIZE {
		TYPE_GO_INT32 = TYPE_LONG
		TYPE_GO_UINT32 = TYPE_ULONG
	} else {
		panic("Neither gint nor glong are 32 bit numbers")
	}
}

type Pointer C.gpointer

func gBoolean(b bool) C.gboolean {
	if b {
		return C.TRUE
	}
	return C.FALSE
}

type Quark C.GQuark

func (q Quark) GQuark() C.GQuark {
	return C.GQuark(q)
}

func (q Quark) String() string {
	return C.GoString((*C.char)(C.g_quark_to_string(q.GQuark())))
}

func QuarkFromString(s string) Quark {
	return Quark(C.g_quark_from_static_string((*C.gchar)(C.CString(s))))
}

type Error C.GError

func (e *Error) String() string {
	return C.GoString((*C.char)(e.message))
}

func (e *Error) GetDomain() Quark {
	return Quark(e.domain)
}

func (e *Error) GetCode() int {
	return int(e.code)
}
<commit_msg>Fix Error to implement error interface<commit_after>// Bindings for glib
package glib

/*
#include <stdlib.h>
#include <glib-object.h>

#define _GINT_SIZE sizeof(gint)
#define _GLONG_SIZE sizeof(glong)

#cgo pkg-config: glib-2.0 gobject-2.0 gthread-2.0
*/
import "C"

import (
	"reflect"
	"strconv"
	"unsafe"
)

type TypeGetter interface {
	Type() Type
}

type PointerSetter interface {
	SetPtr(p Pointer)
}

// A numerical value which represents the unique identifier of a registered type
type Type C.GType

const (
	TYPE_INVALID   = Type(C.G_TYPE_INVALID)
	TYPE_NONE      = Type(C.G_TYPE_NONE)
	TYPE_INTERFACE = Type(C.G_TYPE_INTERFACE)
	TYPE_CHAR      = Type(C.G_TYPE_CHAR)
	TYPE_UCHAR     = Type(C.G_TYPE_UCHAR)
	TYPE_BOOLEAN   = Type(C.G_TYPE_BOOLEAN)
	TYPE_INT       = Type(C.G_TYPE_INT)
	TYPE_UINT      = Type(C.G_TYPE_UINT)
	TYPE_LONG      = Type(C.G_TYPE_LONG)
	TYPE_ULONG     = Type(C.G_TYPE_ULONG)
	TYPE_INT64     = Type(C.G_TYPE_INT64)
	TYPE_UINT64    = Type(C.G_TYPE_UINT64)
	TYPE_ENUM      = Type(C.G_TYPE_ENUM)
	TYPE_FLAGS     = Type(C.G_TYPE_FLAGS)
	TYPE_FLOAT     = Type(C.G_TYPE_FLOAT)
	TYPE_DOUBLE    = Type(C.G_TYPE_DOUBLE)
	TYPE_STRING    = Type(C.G_TYPE_STRING)
	TYPE_POINTER   = Type(C.G_TYPE_POINTER)
	TYPE_BOXED     = Type(C.G_TYPE_BOXED)
	TYPE_PARAM     = Type(C.G_TYPE_PARAM)
	TYPE_OBJECT    = Type(C.G_TYPE_OBJECT)
	TYPE_VARIANT   = Type(C.G_TYPE_VARIANT)
)

var (
	TYPE_GTYPE     Type
	TYPE_GO_INT    Type
	TYPE_GO_UINT   Type
	TYPE_GO_INT32  Type
	TYPE_GO_UINT32 Type
)

func (t Type) g() C.GType {
	return C.GType(t)
}

func (t Type) String() string {
	return C.GoString((*C.char)(C.g_type_name(t.g())))
}

func (t Type) QName() Quark {
	return Quark(C.g_type_qname(t.g()))
}

func (t Type) Type() Type {
	return TYPE_GTYPE
}

func (t Type) Value() *Value {
	v := NewValue(t.Type())
	C.g_value_set_gtype(v.g(), t.g())
	return v
}

func (t Type) Parent() Type {
	return Type(C.g_type_parent(t.g()))
}

func (t Type) Depth() uint {
	return uint(C.g_type_depth(t.g()))
}

// Returns the type that is derived directly from root type which is also
// a base class of t
func (t Type) NextBase(root Type) Type {
	return Type(C.g_type_next_base(t.g(), root.g()))
}

// If t type is a derivable type, check whether type is a descendant of
// it type. If t type is an glib interface, check whether type conforms
// to it.
func (t Type) IsA(it Type) bool {
	return C.g_type_is_a(t.g(), it.g()) != 0
}

var type_getter = reflect.TypeOf((*TypeGetter)(nil)).Elem()
var object_caster = reflect.TypeOf((*ObjectCaster)(nil)).Elem()

func (t Type) Match(rt reflect.Type) bool {
	if rt.Implements(object_caster) {
		return t.IsA(TYPE_OBJECT)
	}
	if rt.Implements(type_getter) {
		if rt.Kind() == reflect.Ptr {
			rt = rt.Elem()
		}
		r := reflect.New(rt).Interface().(TypeGetter).Type()
		return t.QName() == r.QName()
	}
	switch rt.Kind() {
	case reflect.Invalid:
		return t == TYPE_INVALID

	case reflect.String:
		return t == TYPE_STRING

	case reflect.Int:
		return t == TYPE_GO_INT

	case reflect.Uint:
		return t == TYPE_GO_UINT

	case reflect.Int8:
		return t == TYPE_CHAR

	case reflect.Uint8:
		return t == TYPE_UCHAR

	case reflect.Int32:
		return t == TYPE_GO_INT32

	case reflect.Uint32:
		return t == TYPE_GO_UINT32

	case reflect.Int64:
		return t == TYPE_INT64

	case reflect.Uint64:
		return t == TYPE_UINT64

	case reflect.Bool:
		return t == TYPE_BOOLEAN

	case reflect.Float32:
		return t == TYPE_FLOAT

	case reflect.Float64:
		return t == TYPE_DOUBLE

	case reflect.Ptr:
		return t == TYPE_POINTER
	}
	return false
}

// Returns the Type of the value in the interface{}.
func TypeOf(i interface{}) Type {
	// Types ov values that implements TypeGetter
	if o, ok := i.(TypeGetter); ok {
		return o.Type()
	}
	// Other types
	switch reflect.TypeOf(i).Kind() {
	case reflect.Invalid:
		return TYPE_INVALID

	case reflect.Bool:
		return TYPE_BOOLEAN

	case reflect.Int:
		return TYPE_GO_INT

	case reflect.Int8:
		return TYPE_CHAR

	case reflect.Int32:
		return TYPE_GO_INT32

	case reflect.Int64:
		return TYPE_INT64

	case reflect.Uint:
		return TYPE_GO_UINT

	case reflect.Uint8:
		return TYPE_UCHAR

	case reflect.Uint32:
		return TYPE_GO_UINT32

	case reflect.Uint64:
		return TYPE_UINT64

	case reflect.Float32:
		return TYPE_FLOAT

	case reflect.Float64:
		return TYPE_DOUBLE

	case reflect.Ptr:
		return TYPE_POINTER

	case reflect.String:
		return TYPE_STRING
	}
	panic("Can't map Go type to Glib type")
}

func TypeFromName(name string) Type {
	tn := C.CString(name)
	defer C.free(unsafe.Pointer(tn))
	return Type(C.g_type_from_name((*C.gchar)(tn)))
}

func init() {
	C.g_type_init()
	TYPE_GTYPE = Type(C.g_gtype_get_type())
	int_bytes := strconv.IntSize / 8
	if int_bytes == int(C._GINT_SIZE) {
		TYPE_GO_INT = TYPE_INT
		TYPE_GO_UINT = TYPE_UINT
	} else if int_bytes == C._GLONG_SIZE {
		TYPE_GO_INT = TYPE_LONG
		TYPE_GO_UINT = TYPE_ULONG
	} else if int_bytes == 64 {
		TYPE_GO_INT = TYPE_INT64
		TYPE_GO_UINT = TYPE_UINT64
	} else {
		panic("Unexpectd size of 'int'")
	}
	int32_bytes := C.uint(4)
	if int32_bytes == C._GINT_SIZE {
		TYPE_GO_INT32 = TYPE_INT
		TYPE_GO_UINT32 = TYPE_UINT
	} else if int32_bytes == C._GLONG_SIZE {
		TYPE_GO_INT32 = TYPE_LONG
		TYPE_GO_UINT32 = TYPE_ULONG
	} else {
		panic("Neither gint nor glong are 32 bit numbers")
	}
}

type Pointer C.gpointer

func gBoolean(b bool) C.gboolean {
	if b {
		return C.TRUE
	}
	return C.FALSE
}

type Quark C.GQuark

func (q Quark) GQuark() C.GQuark {
	return C.GQuark(q)
}

func (q Quark) String() string {
	return C.GoString((*C.char)(C.g_quark_to_string(q.GQuark())))
}

func QuarkFromString(s string) Quark {
	return Quark(C.g_quark_from_static_string((*C.gchar)(C.CString(s))))
}

type Error C.GError

func (e *Error) Error() string {
	return C.GoString((*C.char)(e.message))
}

func (e *Error) GetDomain() Quark {
	return Quark(e.domain)
}

func (e *Error) GetCode() int {
	return int(e.code)
}
<|endoftext|>