<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

// HTTP status codes as registered with IANA.
// See: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
	StatusContinue           = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1

	StatusOK                   = 200 // RFC 7231, 6.3.1
	StatusCreated              = 201 // RFC 7231, 6.3.2
	StatusAccepted             = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
	StatusNoContent            = 204 // RFC 7231, 6.3.5
	StatusResetContent         = 205 // RFC 7231, 6.3.6
	StatusPartialContent       = 206 // RFC 7233, 4.1
	StatusMultiStatus          = 207 // RFC 4918, 11.1
	StatusAlreadyReported      = 208 // RFC 5842, 7.1
	StatusIMUsed               = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
	StatusFound             = 302 // RFC 7231, 6.4.3
	StatusSeeOther          = 303 // RFC 7231, 6.4.4
	StatusNotModified       = 304 // RFC 7232, 4.1
	StatusUseProxy          = 305 // RFC 7231, 6.4.5
	_                       = 306 // RFC 7231, 6.4.6 (Unused)
	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect = 308 // RFC 7538, 3

	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 = 401 // RFC 7235, 3.1
	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
	StatusForbidden                    = 403 // RFC 7231, 6.5.3
	StatusNotFound                     = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
	StatusConflict                     = 409 // RFC 7231, 6.5.8
	StatusGone                         = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
	StatusTeapot                       = 418 // RFC 7168, 2.3.3
	StatusMisdirectedRequest           = 421 // RFC 7540, 9.1.2
	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

var statusText = map[int]string{
	StatusContinue:           "Continue",
	StatusSwitchingProtocols: "Switching Protocols",
	StatusProcessing:         "Processing",

	StatusOK:                   "OK",
	StatusCreated:              "Created",
	StatusAccepted:             "Accepted",
	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
	StatusNoContent:            "No Content",
	StatusResetContent:         "Reset Content",
	StatusPartialContent:       "Partial Content",
	StatusMultiStatus:          "Multi-Status",
	StatusAlreadyReported:      "Already Reported",
	StatusIMUsed:               "IM Used",

	StatusMultipleChoices:   "Multiple Choices",
	StatusMovedPermanently:  "Moved Permanently",
	StatusFound:             "Found",
	StatusSeeOther:          "See Other",
	StatusNotModified:       "Not Modified",
	StatusUseProxy:          "Use Proxy",
	StatusTemporaryRedirect: "Temporary Redirect",
	StatusPermanentRedirect: "Permanent Redirect",

	StatusBadRequest:                   "Bad Request",
	StatusUnauthorized:                 "Unauthorized",
	StatusPaymentRequired:              "Payment Required",
	StatusForbidden:                    "Forbidden",
	StatusNotFound:                     "Not Found",
	StatusMethodNotAllowed:             "Method Not Allowed",
	StatusNotAcceptable:                "Not Acceptable",
	StatusProxyAuthRequired:            "Proxy Authentication Required",
	StatusRequestTimeout:               "Request Timeout",
	StatusConflict:                     "Conflict",
	StatusGone:                         "Gone",
	StatusLengthRequired:               "Length Required",
	StatusPreconditionFailed:           "Precondition Failed",
	StatusRequestEntityTooLarge:        "Request Entity Too Large",
	StatusRequestURITooLong:            "Request URI Too Long",
	StatusUnsupportedMediaType:         "Unsupported Media Type",
	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
	StatusExpectationFailed:            "Expectation Failed",
	StatusTeapot:                       "I'm a teapot",
	StatusMisdirectedRequest:           "Misdirected Request",
	StatusUnprocessableEntity:          "Unprocessable Entity",
	StatusLocked:                       "Locked",
	StatusFailedDependency:             "Failed Dependency",
	StatusUpgradeRequired:              "Upgrade Required",
	StatusPreconditionRequired:         "Precondition Required",
	StatusTooManyRequests:              "Too Many Requests",
	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

	StatusInternalServerError:           "Internal Server Error",
	StatusNotImplemented:                "Not Implemented",
	StatusBadGateway:                    "Bad Gateway",
	StatusServiceUnavailable:            "Service Unavailable",
	StatusGatewayTimeout:                "Gateway Timeout",
	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
	StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
	StatusInsufficientStorage:           "Insufficient Storage",
	StatusLoopDetected:                  "Loop Detected",
	StatusNotExtended:                   "Not Extended",
	StatusNetworkAuthenticationRequired: "Network Authentication Required",
}

// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func StatusText(code int) string {
	return statusText[code]
}
<commit_msg>net/http: add StatusTooEarly (425)<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

// HTTP status codes as registered with IANA.
// See: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
	StatusContinue           = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1

	StatusOK                   = 200 // RFC 7231, 6.3.1
	StatusCreated              = 201 // RFC 7231, 6.3.2
	StatusAccepted             = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
	StatusNoContent            = 204 // RFC 7231, 6.3.5
	StatusResetContent         = 205 // RFC 7231, 6.3.6
	StatusPartialContent       = 206 // RFC 7233, 4.1
	StatusMultiStatus          = 207 // RFC 4918, 11.1
	StatusAlreadyReported      = 208 // RFC 5842, 7.1
	StatusIMUsed               = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
	StatusFound             = 302 // RFC 7231, 6.4.3
	StatusSeeOther          = 303 // RFC 7231, 6.4.4
	StatusNotModified       = 304 // RFC 7232, 4.1
	StatusUseProxy          = 305 // RFC 7231, 6.4.5
	_                       = 306 // RFC 7231, 6.4.6 (Unused)
	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect = 308 // RFC 7538, 3

	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 = 401 // RFC 7235, 3.1
	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
	StatusForbidden                    = 403 // RFC 7231, 6.5.3
	StatusNotFound                     = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
	StatusConflict                     = 409 // RFC 7231, 6.5.8
	StatusGone                         = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
	StatusTeapot                       = 418 // RFC 7168, 2.3.3
	StatusMisdirectedRequest           = 421 // RFC 7540, 9.1.2
	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusTooEarly                     = 425 // RFC 8470, 5.2.
	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

var statusText = map[int]string{
	StatusContinue:           "Continue",
	StatusSwitchingProtocols: "Switching Protocols",
	StatusProcessing:         "Processing",

	StatusOK:                   "OK",
	StatusCreated:              "Created",
	StatusAccepted:             "Accepted",
	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
	StatusNoContent:            "No Content",
	StatusResetContent:         "Reset Content",
	StatusPartialContent:       "Partial Content",
	StatusMultiStatus:          "Multi-Status",
	StatusAlreadyReported:      "Already Reported",
	StatusIMUsed:               "IM Used",

	StatusMultipleChoices:   "Multiple Choices",
	StatusMovedPermanently:  "Moved Permanently",
	StatusFound:             "Found",
	StatusSeeOther:          "See Other",
	StatusNotModified:       "Not Modified",
	StatusUseProxy:          "Use Proxy",
	StatusTemporaryRedirect: "Temporary Redirect",
	StatusPermanentRedirect: "Permanent Redirect",

	StatusBadRequest:                   "Bad Request",
	StatusUnauthorized:                 "Unauthorized",
	StatusPaymentRequired:              "Payment Required",
	StatusForbidden:                    "Forbidden",
	StatusNotFound:                     "Not Found",
	StatusMethodNotAllowed:             "Method Not Allowed",
	StatusNotAcceptable:                "Not Acceptable",
	StatusProxyAuthRequired:            "Proxy Authentication Required",
	StatusRequestTimeout:               "Request Timeout",
	StatusConflict:                     "Conflict",
	StatusGone:                         "Gone",
	StatusLengthRequired:               "Length Required",
	StatusPreconditionFailed:           "Precondition Failed",
	StatusRequestEntityTooLarge:        "Request Entity Too Large",
	StatusRequestURITooLong:            "Request URI Too Long",
	StatusUnsupportedMediaType:         "Unsupported Media Type",
	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
	StatusExpectationFailed:            "Expectation Failed",
	StatusTeapot:                       "I'm a teapot",
	StatusMisdirectedRequest:           "Misdirected Request",
	StatusUnprocessableEntity:          "Unprocessable Entity",
	StatusLocked:                       "Locked",
	StatusFailedDependency:             "Failed Dependency",
	StatusTooEarly:                     "Too Early",
	StatusUpgradeRequired:              "Upgrade Required",
	StatusPreconditionRequired:         "Precondition Required",
	StatusTooManyRequests:              "Too Many Requests",
	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

	StatusInternalServerError:           "Internal Server Error",
	StatusNotImplemented:                "Not Implemented",
	StatusBadGateway:                    "Bad Gateway",
	StatusServiceUnavailable:            "Service Unavailable",
	StatusGatewayTimeout:                "Gateway Timeout",
	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
	StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
	StatusInsufficientStorage:           "Insufficient Storage",
	StatusLoopDetected:                  "Loop Detected",
	StatusNotExtended:                   "Not Extended",
	StatusNetworkAuthenticationRequired: "Network Authentication Required",
}

// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func StatusText(code int) string {
	return statusText[code]
}
<|endoftext|>


<commit_before>package crud

import (
	"fmt"
	"strconv"
	"strings"
)

type joincon struct {
	tablename string
	condition string
}

type joincons []joincon

func (jc joincons) haveTable(tbName string) bool {
	for _, v := range jc {
		if v.tablename == tbName {
			return true
		}
	}
	return false
}

type wherecon struct {
	query string
	args  []interface{}
}

type search struct {
	db              *CRUD
	fields          []string
	tableName       string
	joinConditions  joincons
	whereConditions []wherecon
	group           string
	with            string
	having          string
	limit           interface{}
	offset          interface{}

	query string
	args  []interface{}

	raw bool
}

func (s *search) clone() *search {
	clone := *s
	return &clone
}

func (s *search) Fields(args ...string) *search {
	//err `xxx.xxx`
	//err `xxx.xx AS xxx`
	//err `DISTINCT cid`
	//	for i := 0; i < len(args); i++ {
	//		switch args[i] {
	//		case "id":
	//			args[i] = s.tableName + ".id"
	//			continue
	//		case "*":
	//			continue
	//		}
	//		if strings.Contains(args[i], ".") || strings.Contains(args[i], "AS") || strings.Contains(args[i], "as") || strings.Contains(args[i], "DISTINCT") {

	//		} else {
	//			args[i] = "`" + args[i] + "`"
	//		}

	//	}
	s.fields = append(s.fields, args...)
	return s
}

func (s *search) Where(query string, values ...interface{}) *search {
	id, err := strconv.Atoi(query)
	if err != nil {
		s.whereConditions = append(s.whereConditions, wherecon{query: query, args: values})
	} else {
		s.whereConditions = append(s.whereConditions, wherecon{query: s.tableName + ".id = ?", args: []interface{}{id}})
	}
	return s
}

func (s *search) In(field string, args ...interface{}) *search {
	//In没有参数的话SQL就会报错
	if len(args) == 0 {
		return s
	}
	s.whereConditions = append(s.whereConditions, wherecon{query: fmt.Sprintf("%s IN (%s)", field, placeholder(len(args))), args: args})
	return s
}

func placeholder(n int) string {
	holder := []string{}
	for i := 0; i < n; i++ {
		holder = append(holder, "?")
	}
	return strings.Join(holder, ",")
}

func (s *search) Joins(tablename string, condition ...string) *search {
	if len(condition) == 1 {
		s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: condition[0]})
	} else {
		if s.db.tableColumns[tablename].HaveColumn(s.tableName + "id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", tablename, s.tableName+"id", s.tableName)})
		} else if s.db.tableColumns[tablename].HaveColumn(s.tableName + "_id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", tablename, s.tableName+"_id", s.tableName)})
		} else if s.db.tableColumns[s.tableName].HaveColumn(tablename + "id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", s.tableName, tablename+"id", tablename)})
		} else if s.db.tableColumns[s.tableName].HaveColumn(tablename + "_id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", s.tableName, tablename+"_id", tablename)})
		}
	}
	return s
}

func (s *search) TableName(name string) *search {
	s.tableName = name
	return s
}

func (s *search) Limit(limit interface{}) *search {
	s.limit = limit
	return s
}

func (s *search) Offset(offset interface{}) *search {
	s.offset = offset
	return s
}

func (s *search) Group(query string) *search {
	s.group = query
	return s
}

func (s *search) Parse() (string, []interface{}) {
	if s.raw == true {
		return s.query, s.args
	}
	var (
		fields       string
		joins        string
		paddingwhere string
		wheres       []string
		limit        string
		offset       string
	)
	s.query = ""
	s.args = []interface{}{}
	if len(s.fields) == 0 {
		fields = "*"
	} else {
		for i := 0; i < len(s.fields); i++ {
			var tablename string
			s.fields[i], tablename, _ = s.warpField(s.fields[i])
			if tablename != s.tableName {
				if !s.joinConditions.haveTable(tablename) {
					s.Joins(tablename)
				}
			}
		}
		fields = strings.Join(s.fields, ",")
	}
	for _, joincon := range s.joinConditions {
		joins += fmt.Sprintf(" LEFT JOIN %s ON %s", joincon.tablename, joincon.condition)
	}
	for _, wherecon := range s.whereConditions {
		paddingwhere = " WHERE "
		wheres = append(wheres, wherecon.query)
		s.args = append(s.args, wherecon.args...)
	}
	if s.limit != nil {
		limit = " LIMIT ?"
		s.args = append(s.args, s.limit)
	}
	if s.offset != nil {
		offset = " OFFSET ?"
		s.args = append(s.args, s.offset)
	}
	s.query = fmt.Sprintf("SELECT %s FROM %s%s%s%s%s%s", fields, s.tableName, joins, paddingwhere, strings.Join(wheres, " AND "), limit, offset)
	s.raw = true
	return s.query, s.args
}

//DISTINCT XX
//DISTICT XXX.XXX AS aaa
//XXX.XXX AS aaa
func (s *search) warpField(field string) (warpStr string, tablename string, fieldname string) {
	if strings.Contains(field, " ") {
		if strings.Contains(field, "AS") {
			sp := strings.Split(field, " ")
			for i := 0; i < len(sp); i++ {
				if sp[i] == "AS" {
					sp[i-1], tablename, fieldname = s.warpFieldSingel(sp[i-1])
					warpStr = strings.Join(sp, " ")
					break
				}
			}
		} else {
			sp := strings.Split(field, " ")
			sp[len(sp)-1], tablename, fieldname = s.warpFieldSingel(sp[len(sp)-1])
			warpStr = strings.Join(sp, " ")
		}
	} else {
		return s.warpFieldSingel(field)
	}
	return
}

func (s *search) warpFieldSingel(field string) (warpStr string, tablename string, fieldname string) {
	if strings.Contains(field, ".") {
		sp := strings.Split(field, ".")
		tablename = sp[0]
		fieldname = sp[1]
		warpStr = strings.Replace(field, ".", ".`", 1) + "`"
	} else {
		tablename = s.tableName
		fieldname = field
		switch field {
		case "*", "COUNT(*)":
			warpStr = field
		default:
			warpStr = "`" + field + "`"
		}
	}
	return
}

//结果展示

func (s *search) RowMap() RowMap {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowMap()
}
func (s *search) RowsMap() RowsMap {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowsMap()
}
func (s *search) RowsMapInterface() RowsMapInterface {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowsMapInterface()
}
func (s *search) DoubleSlice() (map[string]int, [][]string) {
	query, args := s.Parse()
	return s.db.Query(query, args...).DoubleSlice()
}

//Int 如果指定字段，则返回指定字段的int值，否则返回第一个字段作为int值返回。
func (s *search) Int(args ...string) int {
	row := s.RowMap()
	if len(args) == 0 {
		for _, v := range row {
			i, _ := strconv.Atoi(v)
			return i
		}
	} else {
		i, _ := strconv.Atoi(row[args[0]])
		return i
	}
	return 0
}

//String like int
func (s *search) String(args ...string) string {
	row := s.RowMap()
	if len(args) == 0 {
		for _, v := range row {
			return v
		}
	} else {
		return row[args[0]]
	}
	return ""
}

func (s *search) Struct(v interface{}) {
	query, args := s.Parse()
	s.db.FindAll(v, append([]interface{}{query}, args...)...)
}

func (s *search) Count() int {
	var count int
	s.fields = []string{"COUNT(*)"}
	query, args := s.Parse()
	s.db.Query(query, args...).Find(&count)
	return count
}
<commit_msg>兼容原来的raw/raws<commit_after>package crud

import (
	"fmt"
	"strconv"
	"strings"
)

type joincon struct {
	tablename string
	condition string
}

type joincons []joincon

func (jc joincons) haveTable(tbName string) bool {
	for _, v := range jc {
		if v.tablename == tbName {
			return true
		}
	}
	return false
}

type wherecon struct {
	query string
	args  []interface{}
}

type search struct {
	db              *CRUD
	fields          []string
	tableName       string
	joinConditions  joincons
	whereConditions []wherecon
	group           string
	with            string
	having          string
	limit           interface{}
	offset          interface{}

	query string
	args  []interface{}

	raw bool
}

func (s *search) clone() *search {
	clone := *s
	return &clone
}

func (s *search) Fields(args ...string) *search {
	//err `xxx.xxx`
	//err `xxx.xx AS xxx`
	//err `DISTINCT cid`
	//	for i := 0; i < len(args); i++ {
	//		switch args[i] {
	//		case "id":
	//			args[i] = s.tableName + ".id"
	//			continue
	//		case "*":
	//			continue
	//		}
	//		if strings.Contains(args[i], ".") || strings.Contains(args[i], "AS") || strings.Contains(args[i], "as") || strings.Contains(args[i], "DISTINCT") {

	//		} else {
	//			args[i] = "`" + args[i] + "`"
	//		}

	//	}
	s.fields = append(s.fields, args...)
	return s
}

func (s *search) Where(query string, values ...interface{}) *search {
	id, err := strconv.Atoi(query)
	if err != nil {
		s.whereConditions = append(s.whereConditions, wherecon{query: query, args: values})
	} else {
		s.whereConditions = append(s.whereConditions, wherecon{query: s.tableName + ".id = ?", args: []interface{}{id}})
	}
	return s
}

func (s *search) In(field string, args ...interface{}) *search {
	//In没有参数的话SQL就会报错
	if len(args) == 0 {
		return s
	}
	s.whereConditions = append(s.whereConditions, wherecon{query: fmt.Sprintf("%s IN (%s)", field, placeholder(len(args))), args: args})
	return s
}

func placeholder(n int) string {
	holder := []string{}
	for i := 0; i < n; i++ {
		holder = append(holder, "?")
	}
	return strings.Join(holder, ",")
}

func (s *search) Joins(tablename string, condition ...string) *search {
	if len(condition) == 1 {
		s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: condition[0]})
	} else {
		if s.db.tableColumns[tablename].HaveColumn(s.tableName + "id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", tablename, s.tableName+"id", s.tableName)})
		} else if s.db.tableColumns[tablename].HaveColumn(s.tableName + "_id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", tablename, s.tableName+"_id", s.tableName)})
		} else if s.db.tableColumns[s.tableName].HaveColumn(tablename + "id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", s.tableName, tablename+"id", tablename)})
		} else if s.db.tableColumns[s.tableName].HaveColumn(tablename + "_id") {
			s.joinConditions = append(s.joinConditions, joincon{tablename: tablename, condition: fmt.Sprintf("%s.%s = %s.id", s.tableName, tablename+"_id", tablename)})
		}
	}
	return s
}

func (s *search) TableName(name string) *search {
	s.tableName = name
	return s
}

func (s *search) Limit(limit interface{}) *search {
	s.limit = limit
	return s
}

func (s *search) Offset(offset interface{}) *search {
	s.offset = offset
	return s
}

func (s *search) Group(query string) *search {
	s.group = query
	return s
}

func (s *search) Parse() (string, []interface{}) {
	if s.raw == true {
		return s.query, s.args
	}
	var (
		fields       string
		joins        string
		paddingwhere string
		wheres       []string
		limit        string
		offset       string
	)
	s.query = ""
	s.args = []interface{}{}
	if len(s.fields) == 0 {
		fields = "*"
	} else {
		for i := 0; i < len(s.fields); i++ {
			var tablename string
			s.fields[i], tablename, _ = s.warpField(s.fields[i])
			if tablename != s.tableName {
				if !s.joinConditions.haveTable(tablename) {
					s.Joins(tablename)
				}
			}
		}
		fields = strings.Join(s.fields, ",")
	}
	for _, joincon := range s.joinConditions {
		joins += fmt.Sprintf(" LEFT JOIN %s ON %s", joincon.tablename, joincon.condition)
	}
	for _, wherecon := range s.whereConditions {
		paddingwhere = " WHERE "
		wheres = append(wheres, wherecon.query)
		s.args = append(s.args, wherecon.args...)
	}
	if s.limit != nil {
		limit = " LIMIT ?"
		s.args = append(s.args, s.limit)
	}
	if s.offset != nil {
		offset = " OFFSET ?"
		s.args = append(s.args, s.offset)
	}
	s.query = fmt.Sprintf("SELECT %s FROM %s%s%s%s%s%s", fields, s.tableName, joins, paddingwhere, strings.Join(wheres, " AND "), limit, offset)
	s.raw = true
	return s.query, s.args
}

//DISTINCT XX
//DISTICT XXX.XXX AS aaa
//XXX.XXX AS aaa
func (s *search) warpField(field string) (warpStr string, tablename string, fieldname string) {
	if strings.Contains(field, " ") {
		if strings.Contains(field, "AS") {
			sp := strings.Split(field, " ")
			for i := 0; i < len(sp); i++ {
				if sp[i] == "AS" {
					sp[i-1], tablename, fieldname = s.warpFieldSingel(sp[i-1])
					warpStr = strings.Join(sp, " ")
					break
				}
			}
		} else {
			sp := strings.Split(field, " ")
			sp[len(sp)-1], tablename, fieldname = s.warpFieldSingel(sp[len(sp)-1])
			warpStr = strings.Join(sp, " ")
		}
	} else {
		return s.warpFieldSingel(field)
	}
	return
}

func (s *search) warpFieldSingel(field string) (warpStr string, tablename string, fieldname string) {
	if strings.Contains(field, ".") {
		sp := strings.Split(field, ".")
		tablename = sp[0]
		fieldname = sp[1]
		warpStr = strings.Replace(field, ".", ".`", 1) + "`"
	} else {
		tablename = s.tableName
		fieldname = field
		switch field {
		case "*", "COUNT(*)":
			warpStr = field
		default:
			warpStr = "`" + field + "`"
		}
	}
	return
}

//结果展示

func (s *search) RawMap() RowMap {
	return s.RowMap()
}
func (s *search) RawsMap() RowsMap {
	return s.RowsMap()
}
func (s *search) RawsMapInterface() RowsMapInterface {
	return s.RowsMapInterface()
}

func (s *search) RowMap() RowMap {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowMap()
}
func (s *search) RowsMap() RowsMap {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowsMap()
}
func (s *search) RowsMapInterface() RowsMapInterface {
	query, args := s.Parse()
	return s.db.Query(query, args...).RowsMapInterface()
}
func (s *search) DoubleSlice() (map[string]int, [][]string) {
	query, args := s.Parse()
	return s.db.Query(query, args...).DoubleSlice()
}

//Int 如果指定字段，则返回指定字段的int值，否则返回第一个字段作为int值返回。
func (s *search) Int(args ...string) int {
	row := s.RowMap()
	if len(args) == 0 {
		for _, v := range row {
			i, _ := strconv.Atoi(v)
			return i
		}
	} else {
		i, _ := strconv.Atoi(row[args[0]])
		return i
	}
	return 0
}

//String like int
func (s *search) String(args ...string) string {
	row := s.RowMap()
	if len(args) == 0 {
		for _, v := range row {
			return v
		}
	} else {
		return row[args[0]]
	}
	return ""
}

func (s *search) Struct(v interface{}) {
	query, args := s.Parse()
	s.db.FindAll(v, append([]interface{}{query}, args...)...)
}

func (s *search) Count() int {
	var count int
	s.fields = []string{"COUNT(*)"}
	query, args := s.Parse()
	s.db.Query(query, args...).Find(&count)
	return count
}
<|endoftext|>


<commit_before>
package main

/* The HTTP server waiting for requests */

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"
)

const (
	ParameterWaypoints = "waypoints"
	ParameterTravelmode = "travelmode"
	ParameterMetric = "metric"
	ParameterAvoid = "avoid"

	SeparatorWaypoints = "|"
	SeparatorLatLng = ","

	Port = ":23401"
)

var (
	featureResponse []byte
)

func main() {
	setupErr := setup()
	if setupErr != nil {
		log.Fatal("Setup failed:", setupErr)
		return
	}

	// map URLs to functions
	http.HandleFunc("/", root)
    http.HandleFunc("/routes", routes)
    http.HandleFunc("/features", features)

	// start the HTTP server
	err := http.ListenAndServe(Port, nil)
	if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}

// Do some stuff when the server is started
func setup() error {
	// create the feature response only once (no change at runtime)
	features := &Features{}
    var err error
	featureResponse, err = json.Marshal(features)
	if err != nil {
        log.Fatal("Creating feature response:", err)
        return err
    }
    return nil
}

// Just tell that the server is alive
func root(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Server is up and running")
}

// Computes routes (at the moment only one route is returned statically)
func routes(w http.ResponseWriter, r *http.Request) {
	// parse URL and extract parameters
	urlParameter := r.URL.Query()

	// handle waypoints parameter
	if urlParameter[ParameterWaypoints] == nil || len(urlParameter[ParameterWaypoints]) < 1 {
		http.Error(w, "no waypoints", http.StatusBadRequest)
		return
	}
	_, err := getWaypoints(urlParameter["waypoints"][0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// there is no need to handle the other parameters at the moment as
	// the implementation should not fail for unknown parameters/values

	// hard coded values for the route response
	var polyline1 = [][]float64{{49.25708,7.045980000000001},{49.257070000000006,7.045960000000001},{49.25652,7.044390000000001}}
	distance1 := Distance{"0.1 km", 131}
	duration1 := Duration{"2 min", 124}
	startLocation1 := Point{49.257080, 7.045980000000001}
	endLocation1 := Point{49.256520, 7.044390000000001}
	step1 := Step{distance1, duration1, startLocation1, endLocation1, polyline1, ""}

	var polyline2 = [][]float64{{49.25652,7.044390000000001},{49.25661,7.0444},{49.25668,7.044390000000001},{49.25674,7.044320000000001},{49.25677,7.044300000000001},{49.256800000000005,7.044270000000001},{49.256820000000005,7.044230000000001},{49.256840000000004,7.0442100000000005},{49.256870000000006,7.04419},{49.25688,7.04415},{49.256910000000005,7.0441400000000005},{49.25694000000001,7.044110000000001},{49.256980000000006,7.044060000000001},{49.25703000000001,7.0440000000000005},{49.25706,7.043950000000001},{49.257090000000005,7.043940000000001},{49.25704,7.043310000000001}}
	distance2 := Distance{"0.1 km", 122}
	duration2 := Duration{"2 min", 136}
	startLocation2 := Point{49.256520, 7.044390000000001}
	endLocation2 := Point{49.257040, 7.043310000000001}
	step2 := Step{distance2, duration2, startLocation2, endLocation2, polyline2, ""}

	distanceL := Distance{"0.3 km", 253}
	durationL := Duration{"4 min", 260}
	startLocationL := Point{49.257080, 7.045980000000001}
	endLocationL := Point{49.257040, 7.043310000000001}
	steps := []Step{step1, step2}
	leg := Leg{distanceL, durationL, startLocationL, endLocationL, steps}

	legs := []Leg{leg}
	route := Route{distanceL, durationL, startLocationL, endLocationL, legs}
	routes := []Route{route}

	northwest := Point{49.25709000000001, 7.043310000000001}
	southeast := Point{49.256520, 7.045980000000001}
	boundingBox := BoundingBox{northwest, southeast}
	result := &Result{boundingBox, routes}
	jsonResult, err := json.Marshal(result)
	if err != nil {
		http.Error(w, "unable to create a proper JSON object", http.StatusInternalServerError)
		return
	}
	w.Write(jsonResult)
}

// Parses the given waypoints
func getWaypoints(waypointString string) ([]Point, error) {
	waypointStrings := strings.Split(waypointString, SeparatorWaypoints)
	if len(waypointStrings) < 2 {
		return nil, errors.New("too few waypoints. at least 2 waypoints are needed")
	}

	points := make([]Point, len(waypointStrings))
	for i, v := range waypointStrings {
		coordinateStrings := strings.Split(v, SeparatorLatLng)
		if len(coordinateStrings) != 2 {
			return nil, errors.New("wrong formatted coordinate in waypoint list: " + v)
		}
		lat, err := strconv.ParseFloat(coordinateStrings[0], 64 /* bitSize */)
		if err != nil {
			return nil, errors.New("wrong formatted number in waypoint list: " + coordinateStrings[0])
		}
		lng, err := strconv.ParseFloat(coordinateStrings[1], 64 /* bitSize */)
		if err != nil {
			return nil, errors.New("wrong formatted number in waypoint list: " + coordinateStrings[1])
		}
		points[i] = Point{lat, lng}
	}
	return points, nil
}

// Handles feature requests
func features(w http.ResponseWriter, r *http.Request) {
	w.Write(featureResponse)
}

<commit_msg>Implemented simple parser for cmd args<commit_after>
package main

/* The HTTP server waiting for requests */

import (
	"encoding/json"
	"errors"
	"flag"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"
)

const (
	ParameterWaypoints = "waypoints"
	ParameterTravelmode = "travelmode"
	ParameterMetric = "metric"
	ParameterAvoid = "avoid"

	SeparatorWaypoints = "|"
	SeparatorLatLng = ","

	DefaultPort = 23401 // The default port number
)

var (
	featureResponse []byte
	// Command line flags
	Port int //The flag for the port
)

func init(){
	flag.IntVar(&Port,"port",DefaultPort,"the port where the server is running")
}

func main() {
	// Call the command line parser
	flag.Parse()
	setupErr := setup()
	if setupErr != nil {
		log.Fatal("Setup failed:", setupErr)
		return
	}

	// map URLs to functions
	http.HandleFunc("/", root)
	http.HandleFunc("/routes", routes)
	http.HandleFunc("/features", features)

	// start the HTTP server
	err := http.ListenAndServe(":"+strconv.Itoa(Port), nil)
	if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}

// Do some stuff when the server is started
func setup() error {
	// create the feature response only once (no change at runtime)
	features := &Features{}
	var err error
	featureResponse, err = json.Marshal(features)
	if err != nil {
		log.Fatal("Creating feature response:", err)
		return err
	}
	return nil
}

// Just tell that the server is alive
func root(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Server is up and running")
}

// Computes routes (at the moment only one route is returned statically)
func routes(w http.ResponseWriter, r *http.Request) {
	// parse URL and extract parameters
	urlParameter := r.URL.Query()

	// handle waypoints parameter
	if urlParameter[ParameterWaypoints] == nil || len(urlParameter[ParameterWaypoints]) < 1 {
		http.Error(w, "no waypoints", http.StatusBadRequest)
		return
	}
	_, err := getWaypoints(urlParameter["waypoints"][0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// there is no need to handle the other parameters at the moment as
	// the implementation should not fail for unknown parameters/values

	// hard coded values for the route response
	var polyline1 = [][]float64{{49.25708,7.045980000000001},{49.257070000000006,7.045960000000001},{49.25652,7.044390000000001}}
	distance1 := Distance{"0.1 km", 131}
	duration1 := Duration{"2 min", 124}
	startLocation1 := Point{49.257080, 7.045980000000001}
	endLocation1 := Point{49.256520, 7.044390000000001}
	step1 := Step{distance1, duration1, startLocation1, endLocation1, polyline1, ""}

	var polyline2 = [][]float64{{49.25652,7.044390000000001},{49.25661,7.0444},{49.25668,7.044390000000001},{49.25674,7.044320000000001},{49.25677,7.044300000000001},{49.256800000000005,7.044270000000001},{49.256820000000005,7.044230000000001},{49.256840000000004,7.0442100000000005},{49.256870000000006,7.04419},{49.25688,7.04415},{49.256910000000005,7.0441400000000005},{49.25694000000001,7.044110000000001},{49.256980000000006,7.044060000000001},{49.25703000000001,7.0440000000000005},{49.25706,7.043950000000001},{49.257090000000005,7.043940000000001},{49.25704,7.043310000000001}}
	distance2 := Distance{"0.1 km", 122}
	duration2 := Duration{"2 min", 136}
	startLocation2 := Point{49.256520, 7.044390000000001}
	endLocation2 := Point{49.257040, 7.043310000000001}
	step2 := Step{distance2, duration2, startLocation2, endLocation2, polyline2, ""}

	distanceL := Distance{"0.3 km", 253}
	durationL := Duration{"4 min", 260}
	startLocationL := Point{49.257080, 7.045980000000001}
	endLocationL := Point{49.257040, 7.043310000000001}
	steps := []Step{step1, step2}
	leg := Leg{distanceL, durationL, startLocationL, endLocationL, steps}

	legs := []Leg{leg}
	route := Route{distanceL, durationL, startLocationL, endLocationL, legs}
	routes := []Route{route}

	northwest := Point{49.25709000000001, 7.043310000000001}
	southeast := Point{49.256520, 7.045980000000001}
	boundingBox := BoundingBox{northwest, southeast}
	result := &Result{boundingBox, routes}
	jsonResult, err := json.Marshal(result)
	if err != nil {
		http.Error(w, "unable to create a proper JSON object", http.StatusInternalServerError)
		return
	}
	w.Write(jsonResult)
}

// Parses the given waypoints
func getWaypoints(waypointString string) ([]Point, error) {
	waypointStrings := strings.Split(waypointString, SeparatorWaypoints)
	if len(waypointStrings) < 2 {
		return nil, errors.New("too few waypoints. at least 2 waypoints are needed")
	}

	points := make([]Point, len(waypointStrings))
	for i, v := range waypointStrings {
		coordinateStrings := strings.Split(v, SeparatorLatLng)
		if len(coordinateStrings) != 2 {
			return nil, errors.New("wrong formatted coordinate in waypoint list: " + v)
		}
		lat, err := strconv.ParseFloat(coordinateStrings[0], 64 /* bitSize */)
		if err != nil {
			return nil, errors.New("wrong formatted number in waypoint list: " + coordinateStrings[0])
		}
		lng, err := strconv.ParseFloat(coordinateStrings[1], 64 /* bitSize */)
		if err != nil {
			return nil, errors.New("wrong formatted number in waypoint list: " + coordinateStrings[1])
		}
		points[i] = Point{lat, lng}
	}
	return points, nil
}

// Handles feature requests
func features(w http.ResponseWriter, r *http.Request) {
	w.Write(featureResponse)
}

<|endoftext|>


<commit_before>package main

import (
    "net/http"
    "html/template"
    "math/rand"
    "reflect"
)

type Recipe struct {
    Name string
}

var (
    recipes []Recipe
    database []Recipe
)

func getField(r *Recipe, field string) string {
    ref := reflect.ValueOf(r)
    f := reflect.Indirect(ref).FieldByName(field)
    return string(f.String())
}

func contains(s []string, e string) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

/*
 * `excludes` maps a Recipe attribute name to the attribute value
 * e.g. {"Name": "Chicken Parm"} indicates that meals named "Chicken Parm"
 * should be excluded
 */
func getRecipe(excludes map[string][]string) Recipe {

    var recipe Recipe

    // Apply filters
    var subDb []Recipe
    var doAdd bool
    for _, r := range database {
        doAdd = true
        for k, val := range excludes {
            if contains(val, getField(&r, k)) {
                doAdd = false
                break
            }
        }

        if doAdd == true {
            subDb = append(subDb, r)
        }
    }

    // TODO: get recipe here
    recipe = subDb[rand.Intn(len(subDb))]
    // END TODO

    return recipe
}

func handler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("home.html")
    t.Execute(w, "foo")
}

func recipesHandler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("recipes.html")

    for i, r := range recipes {
        t.Execute(w, map[string]interface{}{"Recipe":r, "Index":i})
    }
}

func main() {
    database = append(database, Recipe{Name:"Chicken Marsala"})
    database = append(database, Recipe{Name:"Chicken Parm"})
    database = append(database, Recipe{Name:"Chicken Vindaloo"})
    database = append(database, Recipe{Name:"Chicken Wings"})
    database = append(database, Recipe{Name:"Chicken Salad Sandwich"})
    database = append(database, Recipe{Name:"Chicken Fingers"})

    excludes := make(map[string][]string)
    for i:= 0; i < 5; i++ {
        recipe := getRecipe(excludes)
        excludes["Name"] = append(excludes["Name"], recipe.Name)
        recipes = append(recipes, recipe)
    }

    http.HandleFunc("/", handler)
    http.HandleFunc("/recipes", recipesHandler)
    http.ListenAndServe(":8080", nil)
}
<commit_msg>No more reflection<commit_after>package main

import (
    "net/http"
    "html/template"
    "math/rand"
)

type Recipe struct {
    Name string
}

var (
    recipes []Recipe
    database []Recipe
)

func contains(s []string, e string) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

func getRecipe(filters []func(Recipe)bool) Recipe {

    var recipe Recipe

    // Apply filters
    var subDb []Recipe
    var doAdd bool
    for _, r := range database {
        doAdd = true
        for _, f := range filters {
            if !f(r) {
                doAdd = false
                break
            }
        }

        if doAdd == true {
            subDb = append(subDb, r)
        }
    }

    // TODO: get recipe here
    recipe = subDb[rand.Intn(len(subDb))]
    // END TODO

    return recipe
}

func handler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("home.html")
    t.Execute(w, "foo")
}

func recipesHandler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("recipes.html")

    for i, r := range recipes {
        t.Execute(w, map[string]interface{}{"Recipe":r, "Index":i})
    }
}

func main() {
    database = append(database, Recipe{Name:"Chicken Marsala"})
    database = append(database, Recipe{Name:"Chicken Parm"})
    database = append(database, Recipe{Name:"Chicken Vindaloo"})
    database = append(database, Recipe{Name:"Chicken Wings"})
    database = append(database, Recipe{Name:"Chicken Salad Sandwich"})
    database = append(database, Recipe{Name:"Chicken Fingers"})

    var filters []func(Recipe)bool
    var names []string
    for i:= 0; i < 5; i++ {
        recipe := getRecipe(filters)
        names = append(names, recipe.Name)
        filters = append(filters, func(r Recipe) bool {
            return !contains(names, r.Name)
        })
        recipes = append(recipes, recipe)
    }

    http.HandleFunc("/", handler)
    http.HandleFunc("/recipes", recipesHandler)
    http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/gophergala/ImgurGo/imageprocessor"
	"github.com/gophergala/ImgurGo/uploadedfile"
	"io"
	"io/ioutil"
	"net/http"
	"os"
)

type Server struct {
	Config     *Configuration
	HTTPClient *http.Client
}

func CreateServer(c *Configuration) *Server {
	httpclient := &http.Client{}
	return &Server{c, httpclient}
}

func (s *Server) _uploadFile(uploadFile io.ReadCloser, w http.ResponseWriter) {
	defer uploadFile.Close()

	tmpFile, err := ioutil.TempFile(os.TempDir(), "image")
	if err != nil {
		fmt.Println(err)
		ErrorResponse(w, "Unable to write to /tmp", http.StatusInternalServerError)
		return
	}

	defer tmpFile.Close()

	_, err = io.Copy(tmpFile, uploadFile)

	if err != nil {
		fmt.Println(err)
		ErrorResponse(w, "Unable to copy image to disk!", http.StatusInternalServerError)
		return
	}

	upload := uploadedfile.NewUploadedFile("testfile.jpg", tmpFile.Name(), "image/jpeg")
	processor, err := imageprocessor.Factory(s.Config.MaxFileSize, upload)
	if err != nil {
		ErrorResponse(w, "Unable to process image!", http.StatusInternalServerError)
		return
	}

	err = processor.Run(upload)
	if err != nil {
		ErrorResponse(w, "Unable to process image!", http.StatusInternalServerError)
		return
	}

	resp := make(map[string]interface{})

	// TODO: Build JSON respons

	Response(w, resp)
}

func (s *Server) initServer() {
	fileHandler := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		uploadFile, _, err := r.FormFile("image")

		if err != nil {
			fmt.Println(err)
			ErrorResponse(w, "Error processing file!", http.StatusInternalServerError)
			return
		}

		s._uploadFile(uploadFile, w)
	}

	urlHandler := func(w http.ResponseWriter, r *http.Request) {
		uploadFile, err := s.download(r.FormValue("image"))

		if err != nil {
			ErrorResponse(w, "Error dowloading URL!", http.StatusInternalServerError)
			return
		}

		s._uploadFile(uploadFile, w)
	}

	http.HandleFunc("/file", fileHandler)
	http.HandleFunc("/url", urlHandler)

	http.ListenAndServe(":8080", nil)
}

func (s *Server) download(url string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", s.Config.UserAgent)

	resp, err := s.HTTPClient.Do(req)

	if err != nil {
		// "HTTP protocol error" - maybe the server sent an invalid response or timed out
		return nil, err
	}

	if 200 != resp.StatusCode {
		return nil, errors.New("Non-200 status code received")
	}

	contentLength := resp.ContentLength

	if contentLength == 0 {
		return nil, errors.New("Empty file received")
	}

	return resp.Body, nil
}
<commit_msg>Adding filename for file uploads<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/gophergala/ImgurGo/imageprocessor"
	"github.com/gophergala/ImgurGo/uploadedfile"
)

type Server struct {
	Config     *Configuration
	HTTPClient *http.Client
}

func CreateServer(c *Configuration) *Server {
	httpclient := &http.Client{}
	return &Server{c, httpclient}
}

func (s *Server) _uploadFile(uploadFile io.ReadCloser, w http.ResponseWriter, name ...string) {
	defer uploadFile.Close()

	tmpFile, err := ioutil.TempFile(os.TempDir(), "image")
	if err != nil {
		fmt.Println(err)
		ErrorResponse(w, "Unable to write to /tmp", http.StatusInternalServerError)
		return
	}

	defer tmpFile.Close()

	_, err = io.Copy(tmpFile, uploadFile)

	if err != nil {
		fmt.Println(err)
		ErrorResponse(w, "Unable to copy image to disk!", http.StatusInternalServerError)
		return
	}

	var fileName string
	if len(name) > 0 {
		fileName = name[0]
	} else {
		fileName = ""
	}

	upload := uploadedfile.NewUploadedFile(fileName, os.TempDir()+tmpFile.Name(), "image/jpeg")
	processor, err := imageprocessor.Factory(s.Config.MaxFileSize, upload)
	if err != nil {
		ErrorResponse(w, "Unable to process image!", http.StatusInternalServerError)
		return
	}

	err = processor.Run(upload)
	if err != nil {
		ErrorResponse(w, "Unable to process image!", http.StatusInternalServerError)
		return
	}

	resp := make(map[string]interface{})

	// TODO: Build JSON respons

	Response(w, resp)
}

func (s *Server) initServer() {
	fileHandler := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		uploadFile, header, err := r.FormFile("image")

		if err != nil {
			fmt.Println(err)
			ErrorResponse(w, "Error processing file!", http.StatusInternalServerError)
			return
		}

		s._uploadFile(uploadFile, w, header.Filename)
	}

	urlHandler := func(w http.ResponseWriter, r *http.Request) {
		uploadFile, err := s.download(r.FormValue("image"))

		if err != nil {
			ErrorResponse(w, "Error dowloading URL!", http.StatusInternalServerError)
			return
		}

		s._uploadFile(uploadFile, w)
	}

	http.HandleFunc("/file", fileHandler)
	http.HandleFunc("/url", urlHandler)

	http.ListenAndServe(":8080", nil)
}

func (s *Server) download(url string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", s.Config.UserAgent)

	resp, err := s.HTTPClient.Do(req)

	if err != nil {
		// "HTTP protocol error" - maybe the server sent an invalid response or timed out
		return nil, err
	}

	if 200 != resp.StatusCode {
		return nil, errors.New("Non-200 status code received")
	}

	contentLength := resp.ContentLength

	if contentLength == 0 {
		return nil, errors.New("Empty file received")
	}

	return resp.Body, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"github.com/byuoitav/authmiddleware"
	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/handlers"
	"github.com/byuoitav/av-api/health"
	avapi "github.com/byuoitav/av-api/init"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
	"github.com/byuoitav/hateoas"
	jh "github.com/jessemillar/health"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
	base.Pub = eventinfrastructure.NewPublisher("7001")

	var req eventinfrastructure.ConnectionRequest
	req.PublisherAddr = "localhost:7001"
	go eventinfrastructure.SendConnectionRequest("http://localhost:6999/subscribe", req)

	err := avapi.CheckRoomInitialization()
	if err != nil {
		base.PublishError("Fail to run init script. Terminating. ERROR:"+err.Error(), eventinfrastructure.INTERNAL)

		log.Fatalf("Could not initialize room. Error: %v\n", err.Error())
	}

	port := ":8000"
	router := echo.New()
	router.Pre(middleware.RemoveTrailingSlash())
	router.Use(middleware.CORS())

	// Use the `secure` routing group to require authentication
	secure := router.Group("", echo.WrapMiddleware(authmiddleware.Authenticate))

	// GET requests
	router.GET("/", echo.WrapHandler(http.HandlerFunc(hateoas.RootResponse)))

	router.GET("/health", echo.WrapHandler(http.HandlerFunc(jh.Check)))
	secure.GET("/status", health.Status)

	// PUT requests
	secure.PUT("/buildings/:building/rooms/:room", handlers.SetRoomState)

	// room status
	secure.GET("/buildings/:building/rooms/:room", handlers.GetRoomStatus)
	secure.GET("/buildings/:building/rooms/:room/configuration", handlers.GetRoomByNameAndBuilding)

	server := http.Server{
		Addr:           port,
		MaxHeaderBytes: 1024 * 10,
	}

	go health.StartupCheckAndReport()

	router.StartServer(&server)
}
<commit_msg>small change<commit_after>package main

import (
	"log"
	"net/http"

	"github.com/byuoitav/authmiddleware"
	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/handlers"
	"github.com/byuoitav/av-api/health"
	avapi "github.com/byuoitav/av-api/init"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
	"github.com/byuoitav/hateoas"
	jh "github.com/jessemillar/health"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
	base.Pub = eventinfrastructure.NewPublisher("7001")

	var req eventinfrastructure.ConnectionRequest
	req.PublisherAddr = "localhost:7001"
	go eventinfrastructure.SendConnectionRequest("http://localhost:6999/subscribe", req, true)

	err := avapi.CheckRoomInitialization()
	if err != nil {
		base.PublishError("Fail to run init script. Terminating. ERROR:"+err.Error(), eventinfrastructure.INTERNAL)

		log.Fatalf("Could not initialize room. Error: %v\n", err.Error())
	}

	port := ":8000"
	router := echo.New()
	router.Pre(middleware.RemoveTrailingSlash())
	router.Use(middleware.CORS())

	// Use the `secure` routing group to require authentication
	secure := router.Group("", echo.WrapMiddleware(authmiddleware.Authenticate))

	// GET requests
	router.GET("/", echo.WrapHandler(http.HandlerFunc(hateoas.RootResponse)))

	router.GET("/health", echo.WrapHandler(http.HandlerFunc(jh.Check)))
	secure.GET("/status", health.Status)

	// PUT requests
	secure.PUT("/buildings/:building/rooms/:room", handlers.SetRoomState)

	// room status
	secure.GET("/buildings/:building/rooms/:room", handlers.GetRoomStatus)
	secure.GET("/buildings/:building/rooms/:room/configuration", handlers.GetRoomByNameAndBuilding)

	server := http.Server{
		Addr:           port,
		MaxHeaderBytes: 1024 * 10,
	}

	go health.StartupCheckAndReport()

	router.StartServer(&server)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cespare/gostc"
	"github.com/dustin/go-humanize"
)

type Server struct {
	addr            string
	db              *DB
	statsd          *gostc.Client
	quitStatUpdates chan struct{}
}

func NewServer(dir, addr string, chunkSize uint64, expiry time.Duration, statsdAddr string) (*Server, error) {
	db, err := OpenDB(chunkSize, expiry, dir)
	if err != nil {
		return nil, err
	}
	statsd, err := gostc.NewClient(statsdAddr)
	if err != nil {
		return nil, err
	}
	return &Server{
		addr:            addr,
		db:              db,
		statsd:          statsd,
		quitStatUpdates: make(chan struct{}),
	}, nil
}

type Request struct {
	Type RequestType
	Key  []byte
	Val  []byte
	Resp chan *Response
	Err  error // If there was an error reading the request, only this field is set.
}

type RequestType uint8

const (
	RequestSet RequestType = iota + 1
	RequestGet
	RequestPing
	RequestInfo
)

type RedisType uint8

const (
	RedisErr RedisType = iota + 1
	RedisString
	RedisBulk
)

type Response struct {
	Type RedisType
	Msg  []byte
}

func (s *Server) Stop() error {
	close(s.quitStatUpdates)
	s.statsd.Close()
	return s.db.Close()
}

func (s *Server) Start() error {
	l, err := net.Listen("tcp", s.addr)
	if err != nil {
		return err
	}
	s.statsd.Inc("kvcache.server-start")
	go s.statUpdates()
	return s.loop(l)
}

func (s *Server) statUpdates() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			stats := s.db.Info()
			s.statsd.Gauge("kvcache.db.rchunks", float64(stats.RChunks))
			s.statsd.Gauge("kvcache.db.total-rlog-size", float64(stats.TotalRLogSize))
			s.statsd.Gauge("kvcache.db.wlog-keys", float64(stats.WLogKeys))
			s.statsd.Gauge("kvcache.db.rlog-keys", float64(stats.RLogKeys))
			s.statsd.Gauge("kvcache.db.total-keys", float64(stats.TotalKeys))
		case <-s.quitStatUpdates:
			return
		}
	}
}

func (s *Server) loop(l net.Listener) error {
	for {
		c, err := l.Accept()
		if err != nil {
			if e, ok := err.(net.Error); ok && e.Temporary() {
				delay := 10 * time.Millisecond
				log.Printf("Accept error: %s; retrying in %s", e, delay)
				s.statsd.Inc("kvcache.errors.accept")
				time.Sleep(delay)
				continue
			}
			return err
		}
		go s.HandleConn(c)
	}
}

func when(ch chan *Response, pred bool) chan *Response {
	if pred {
		return ch
	}
	return nil
}

func head(q []*Response) *Response {
	if len(q) == 0 {
		return nil
	}
	return q[0]
}

func (s *Server) HandleConn(c net.Conn) {
	log.Printf("Client connected from %s", c.RemoteAddr())
	s.statsd.Inc("kvcache.client-connect")

	// readErr and writeErr are how the request reader and response writer goroutines can notify the other that
	// the client (or connection) broke/disconnected.
	// These signal chans are only closed.
	readErr := make(chan struct{})
	writeErr := make(chan struct{})

	// This request goroutine reads requests and sends them into this goroutine to be handled and buffered;
	// Responses are sent off to the response goroutine.
	// This is necessary for Redis pipelining to work.
	requests := make(chan *Request)
	responses := make(chan *Response)

	go s.readRequests(c, requests, readErr, writeErr)
	go s.writeResponses(c, responses, readErr, writeErr)

	var responseQueue []*Response

reqLoop:
	for {
		resp := &Response{Type: RedisString}
		select {
		case r := <-requests:
			if r.Err != nil {
				s.statsd.Inc("kvcache.errors.request")
				resp.Msg = []byte(r.Err.Error())
				resp.Type = RedisErr
			} else {
				s.statsd.Inc("kvcache.requests")
				switch r.Type {
				case RequestSet:
					s.statsd.Inc("kvcache.requests.set")
					start := time.Now()
					_, err := s.db.Put(r.Key, r.Val)
					switch err {
					case nil:
						resp.Msg = []byte("OK")
					case ErrKeyExist:
						resp.Type = RedisBulk // null
					default:
						if e, ok := err.(FatalDBError); ok {
							log.Println("Fatal DB error:", e)
							if err := s.Stop(); err != nil {
								log.Println("Error while shutting down:", err)
							}
							os.Exit(1)
						}
						resp = ResponseFromError(err)
					}
					s.statsd.Time("kvcache.requests.set", time.Since(start))
				case RequestGet:
					s.statsd.Inc("kvcache.requests.get")
					start := time.Now()
					v, _, err := s.db.Get(r.Key)
					switch err {
					case nil:
						resp.Type = RedisBulk
						resp.Msg = v
					case ErrKeyNotExist:
						resp.Type = RedisBulk // null
					default:
						resp = ResponseFromError(err)
					}
					s.statsd.Time("kvcache.requests.get", time.Since(start))
				case RequestPing:
					s.statsd.Inc("kvcache.requests.ping")
					resp.Msg = []byte("PONG")
				case RequestInfo:
					s.statsd.Inc("kvcache.requests.info")
					resp.Msg = []byte(s.db.Info().String())
				default:
					s.statsd.Inc("kvcache.errors.unexpected-request-type")
					panic("unexpected request type")
				}
			}
			responseQueue = append(responseQueue, resp)
		case when(responses, len(responseQueue) > 0) <- head(responseQueue):
			responseQueue = responseQueue[1:]
		case <-readErr:
			break reqLoop
		case <-writeErr:
			break reqLoop
		}
	}

	log.Printf("Client disconnected from %s", c.RemoteAddr())
	c.Close()
}

func (s *Server) readRequests(c net.Conn, requests chan<- *Request, readErr, writeErr chan struct{}) {
	br := bufio.NewReader(c)
	for {
		var r Request
		if err := r.Parse(br); err != nil {
			if _, ok := err.(net.Error); ok {
				close(readErr)
				return
			}
			r.Err = err
		}
		requests <- &r
		select {
		case <-writeErr:
			return
		default:
		}
	}
}

func (s *Server) writeResponses(c net.Conn, responses <-chan *Response, readErr, writeErr chan struct{}) {
	for {
		select {
		case resp := <-responses:
			if err := resp.Write(c); err != nil {
				close(writeErr)
				return
			}
		case <-readErr:
			return
		}
	}
}

func ResponseFromError(err error) *Response {
	return &Response{
		Type: RedisErr,
		Msg:  []byte(err.Error()),
	}
}

var (
	ErrMalformedRequest    = errors.New("malformed request")
	ErrUnrecognizedCommand = errors.New("unrecognized command")
	ErrWrongNumArgs        = errors.New("wrong number of arguments for command")
	ErrSetXXUnupported     = errors.New("the XX option to SET is not supported")
	ErrSetNXRequired       = errors.New("the NX option to SET is required")
)

func (r *Request) Parse(br *bufio.Reader) error {
	array, err := parseRedisArrayBulkString(br)
	if err != nil {
		return err
	}
	if len(array) == 0 {
		return ErrMalformedRequest
	}
	switch strings.ToUpper(array[0]) {
	case "SET":
		if len(array) < 3 {
			return ErrWrongNumArgs
		}
		r.Type = RequestSet
		r.Key = []byte(array[1])
		r.Val = []byte(array[2])
		var nx bool
		// Note permissive redis behavior:
		// https://github.com/antirez/redis/issues/2157
		for i := 3; i < len(array); i++ {
			param := strings.ToUpper(array[i])
			switch param {
			case "EX", "PX":
				if i+1 >= len(array) {
					return fmt.Errorf("expiry parameter %s provided without a value", param)
				}
				i++ // Skip the expiry value
			case "XX":
				return ErrSetXXUnupported
			case "NX":
				nx = true
			}
		}
		if !nx {
			return ErrSetNXRequired
		}
	case "GET":
		if len(array) != 2 {
			return ErrWrongNumArgs
		}
		r.Type = RequestGet
		r.Key = []byte(array[1])
	case "PING":
		if len(array) != 1 {
			return ErrWrongNumArgs
		}
		r.Type = RequestPing
	case "INFO":
		if len(array) != 1 {
			return ErrWrongNumArgs
		}
		r.Type = RequestInfo
	default:
		return ErrUnrecognizedCommand
	}
	return nil
}

func (r *Response) Write(w io.Writer) error {
	var msg []byte
	switch r.Type {
	case RedisErr:
		msg = append([]byte("-"), r.Msg...)
		msg = append(msg, "\r\n"...)
	case RedisString:
		msg = append([]byte("+"), r.Msg...)
		msg = append(msg, "\r\n"...)
	case RedisBulk:
		if r.Msg == nil {
			msg = []byte("$-1\r\n")
			break
		}
		msg = append([]byte{'$'}, strconv.Itoa(len(r.Msg))...)
		msg = append(msg, "\r\n"...)
		msg = append(msg, r.Msg...)
		msg = append(msg, "\r\n"...)
	default:
		panic("unexpected response type")
	}
	_, err := w.Write(msg)
	return err
}

func main() {
	var (
		addr       = flag.String("addr", "localhost:5533", "Listen addr")
		dir        = flag.String("dir", "db", "DB directory")
		chunkSize  = flag.String("chunksize", "100MB", "Max size for chunks")
		expiry     = flag.Duration("expiry", time.Hour, "How long data persists before expiring")
		statsdAddr = flag.String("statsdaddr", "localhost:8125", "Address to send UDP StatsD metrics")
	)
	flag.Parse()

	chunkSizeBytes, err := humanize.ParseBytes(*chunkSize)
	if err != nil {
		log.Fatalf("Bad -chunksize %q: %s", *chunkSize, err)
	}

	log.Printf("Now listening on %s (dir=%s; chunksize=%d; expiry=%s)", *addr, *dir, chunkSizeBytes, *expiry)
	server, err := NewServer(*dir, *addr, chunkSizeBytes, *expiry, *statsdAddr)
	if err != nil {
		log.Fatal(err)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		log.Printf("Caught signal (%v); shutting down...", <-c)
		if err := server.Stop(); err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()

	if err := server.Start(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Don't leak goroutines when connections go away<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cespare/gostc"
	"github.com/dustin/go-humanize"
)

type Server struct {
	addr            string
	db              *DB
	statsd          *gostc.Client
	quitStatUpdates chan struct{}
}

func NewServer(dir, addr string, chunkSize uint64, expiry time.Duration, statsdAddr string) (*Server, error) {
	db, err := OpenDB(chunkSize, expiry, dir)
	if err != nil {
		return nil, err
	}
	statsd, err := gostc.NewClient(statsdAddr)
	if err != nil {
		return nil, err
	}
	return &Server{
		addr:            addr,
		db:              db,
		statsd:          statsd,
		quitStatUpdates: make(chan struct{}),
	}, nil
}

type Request struct {
	Type RequestType
	Key  []byte
	Val  []byte
	Resp chan *Response
	Err  error // If there was an error reading the request, only this field is set.
}

type RequestType uint8

const (
	RequestSet RequestType = iota + 1
	RequestGet
	RequestPing
	RequestInfo
)

type RedisType uint8

const (
	RedisErr RedisType = iota + 1
	RedisString
	RedisBulk
)

type Response struct {
	Type RedisType
	Msg  []byte
}

func (s *Server) Stop() error {
	close(s.quitStatUpdates)
	s.statsd.Close()
	return s.db.Close()
}

func (s *Server) Start() error {
	l, err := net.Listen("tcp", s.addr)
	if err != nil {
		return err
	}
	s.statsd.Inc("kvcache.server-start")
	go s.statUpdates()
	return s.loop(l)
}

func (s *Server) statUpdates() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			stats := s.db.Info()
			s.statsd.Gauge("kvcache.db.rchunks", float64(stats.RChunks))
			s.statsd.Gauge("kvcache.db.total-rlog-size", float64(stats.TotalRLogSize))
			s.statsd.Gauge("kvcache.db.wlog-keys", float64(stats.WLogKeys))
			s.statsd.Gauge("kvcache.db.rlog-keys", float64(stats.RLogKeys))
			s.statsd.Gauge("kvcache.db.total-keys", float64(stats.TotalKeys))
		case <-s.quitStatUpdates:
			return
		}
	}
}

func (s *Server) loop(l net.Listener) error {
	for {
		c, err := l.Accept()
		if err != nil {
			if e, ok := err.(net.Error); ok && e.Temporary() {
				delay := 10 * time.Millisecond
				log.Printf("Accept error: %s; retrying in %s", e, delay)
				s.statsd.Inc("kvcache.errors.accept")
				time.Sleep(delay)
				continue
			}
			return err
		}
		go s.HandleConn(c)
	}
}

func when(ch chan *Response, pred bool) chan *Response {
	if pred {
		return ch
	}
	return nil
}

func head(q []*Response) *Response {
	if len(q) == 0 {
		return nil
	}
	return q[0]
}

func (s *Server) HandleConn(c net.Conn) {
	log.Printf("Client connected from %s", c.RemoteAddr())
	s.statsd.Inc("kvcache.client-connect")

	// readErr and writeErr are how the request reader and response writer goroutines can notify the other that
	// the client (or connection) broke/disconnected.
	// These signal chans are only closed.
	readErr := make(chan struct{})
	writeErr := make(chan struct{})

	// This request goroutine reads requests and sends them into this goroutine to be handled and buffered;
	// Responses are sent off to the response goroutine.
	// This is necessary for Redis pipelining to work.
	requests := make(chan *Request)
	responses := make(chan *Response)

	go s.readRequests(c, requests, readErr, writeErr)
	go s.writeResponses(c, responses, readErr, writeErr)

	var responseQueue []*Response

reqLoop:
	for {
		resp := &Response{Type: RedisString}
		select {
		case r := <-requests:
			if r.Err != nil {
				s.statsd.Inc("kvcache.errors.request")
				resp.Msg = []byte(r.Err.Error())
				resp.Type = RedisErr
			} else {
				s.statsd.Inc("kvcache.requests")
				switch r.Type {
				case RequestSet:
					s.statsd.Inc("kvcache.requests.set")
					start := time.Now()
					_, err := s.db.Put(r.Key, r.Val)
					switch err {
					case nil:
						resp.Msg = []byte("OK")
					case ErrKeyExist:
						resp.Type = RedisBulk // null
					default:
						if e, ok := err.(FatalDBError); ok {
							log.Println("Fatal DB error:", e)
							if err := s.Stop(); err != nil {
								log.Println("Error while shutting down:", err)
							}
							os.Exit(1)
						}
						resp = ResponseFromError(err)
					}
					s.statsd.Time("kvcache.requests.set", time.Since(start))
				case RequestGet:
					s.statsd.Inc("kvcache.requests.get")
					start := time.Now()
					v, _, err := s.db.Get(r.Key)
					switch err {
					case nil:
						resp.Type = RedisBulk
						resp.Msg = v
					case ErrKeyNotExist:
						resp.Type = RedisBulk // null
					default:
						resp = ResponseFromError(err)
					}
					s.statsd.Time("kvcache.requests.get", time.Since(start))
				case RequestPing:
					s.statsd.Inc("kvcache.requests.ping")
					resp.Msg = []byte("PONG")
				case RequestInfo:
					s.statsd.Inc("kvcache.requests.info")
					resp.Msg = []byte(s.db.Info().String())
				default:
					s.statsd.Inc("kvcache.errors.unexpected-request-type")
					panic("unexpected request type")
				}
			}
			responseQueue = append(responseQueue, resp)
		case when(responses, len(responseQueue) > 0) <- head(responseQueue):
			responseQueue = responseQueue[1:]
		case <-readErr:
			break reqLoop
		case <-writeErr:
			break reqLoop
		}
	}

	log.Printf("Client disconnected from %s", c.RemoteAddr())
	c.Close()
}

func (s *Server) readRequests(c net.Conn, requests chan<- *Request, readErr, writeErr chan struct{}) {
	br := bufio.NewReader(c)
	for {
		var r Request
		if err := r.Parse(br); err != nil {
			if _, ok := err.(net.Error); ok {
				close(readErr)
				return
			}
			r.Err = err
		}
		select {
		case requests <- &r:
		case <-writeErr:
			return
		}
	}
}

func (s *Server) writeResponses(c net.Conn, responses <-chan *Response, readErr, writeErr chan struct{}) {
	for {
		select {
		case resp := <-responses:
			if err := resp.Write(c); err != nil {
				close(writeErr)
				return
			}
		case <-readErr:
			return
		}
	}
}

func ResponseFromError(err error) *Response {
	return &Response{
		Type: RedisErr,
		Msg:  []byte(err.Error()),
	}
}

var (
	ErrMalformedRequest    = errors.New("malformed request")
	ErrUnrecognizedCommand = errors.New("unrecognized command")
	ErrWrongNumArgs        = errors.New("wrong number of arguments for command")
	ErrSetXXUnupported     = errors.New("the XX option to SET is not supported")
	ErrSetNXRequired       = errors.New("the NX option to SET is required")
)

func (r *Request) Parse(br *bufio.Reader) error {
	array, err := parseRedisArrayBulkString(br)
	if err != nil {
		return err
	}
	if len(array) == 0 {
		return ErrMalformedRequest
	}
	switch strings.ToUpper(array[0]) {
	case "SET":
		if len(array) < 3 {
			return ErrWrongNumArgs
		}
		r.Type = RequestSet
		r.Key = []byte(array[1])
		r.Val = []byte(array[2])
		var nx bool
		// Note permissive redis behavior:
		// https://github.com/antirez/redis/issues/2157
		for i := 3; i < len(array); i++ {
			param := strings.ToUpper(array[i])
			switch param {
			case "EX", "PX":
				if i+1 >= len(array) {
					return fmt.Errorf("expiry parameter %s provided without a value", param)
				}
				i++ // Skip the expiry value
			case "XX":
				return ErrSetXXUnupported
			case "NX":
				nx = true
			}
		}
		if !nx {
			return ErrSetNXRequired
		}
	case "GET":
		if len(array) != 2 {
			return ErrWrongNumArgs
		}
		r.Type = RequestGet
		r.Key = []byte(array[1])
	case "PING":
		if len(array) != 1 {
			return ErrWrongNumArgs
		}
		r.Type = RequestPing
	case "INFO":
		if len(array) != 1 {
			return ErrWrongNumArgs
		}
		r.Type = RequestInfo
	default:
		return ErrUnrecognizedCommand
	}
	return nil
}

func (r *Response) Write(w io.Writer) error {
	var msg []byte
	switch r.Type {
	case RedisErr:
		msg = append([]byte("-"), r.Msg...)
		msg = append(msg, "\r\n"...)
	case RedisString:
		msg = append([]byte("+"), r.Msg...)
		msg = append(msg, "\r\n"...)
	case RedisBulk:
		if r.Msg == nil {
			msg = []byte("$-1\r\n")
			break
		}
		msg = append([]byte{'$'}, strconv.Itoa(len(r.Msg))...)
		msg = append(msg, "\r\n"...)
		msg = append(msg, r.Msg...)
		msg = append(msg, "\r\n"...)
	default:
		panic("unexpected response type")
	}
	_, err := w.Write(msg)
	return err
}

func main() {
	var (
		addr       = flag.String("addr", "localhost:5533", "Listen addr")
		dir        = flag.String("dir", "db", "DB directory")
		chunkSize  = flag.String("chunksize", "100MB", "Max size for chunks")
		expiry     = flag.Duration("expiry", time.Hour, "How long data persists before expiring")
		statsdAddr = flag.String("statsdaddr", "localhost:8125", "Address to send UDP StatsD metrics")
	)
	flag.Parse()

	chunkSizeBytes, err := humanize.ParseBytes(*chunkSize)
	if err != nil {
		log.Fatalf("Bad -chunksize %q: %s", *chunkSize, err)
	}

	log.Printf("Now listening on %s (dir=%s; chunksize=%d; expiry=%s)", *addr, *dir, chunkSizeBytes, *expiry)
	server, err := NewServer(*dir, *addr, chunkSizeBytes, *expiry, *statsdAddr)
	if err != nil {
		log.Fatal(err)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		log.Printf("Caught signal (%v); shutting down...", <-c)
		if err := server.Stop(); err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()

	if err := server.Start(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package rex

import (
	"flag"
	"fmt"
	"net/http"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/goanywhere/env"
	"github.com/gorilla/mux"
)

var (
	debug    bool
	port     int
	maxprocs int

	once sync.Once
)

type server struct {
	middleware *middleware
	mux        *mux.Router
	ready      bool
	subservers []*server
}

func New() *server {
	self := &server{
		middleware: new(middleware),
		mux:        mux.NewRouter().StrictSlash(true),
	}
	self.configure()
	return self
}

func (self *server) configure() {
	once.Do(func() {
		flag.BoolVar(&debug, "debug", env.Bool("DEBUG", true), "flag to toggle debug mode")
		flag.IntVar(&port, "port", env.Int("PORT", 5000), "port to run the application server")
		flag.IntVar(&maxprocs, "maxprocs", env.Int("MAXPROCS", runtime.NumCPU()), "maximum cpu processes to run the server")
		flag.Parse()
	})
}

// build constructs all server/subservers along with their middleware modules chain.
func (self *server) build() http.Handler {
	if !self.ready {
		// * add server mux into middlware stack to serve as final http.Handler.
		self.Use(func(http.Handler) http.Handler {
			return self.mux
		})
		// * add subservers into middlware stack to serve as final http.Handler.
		for index := 0; index < len(self.subservers); index++ {
			server := self.subservers[index]
			server.Use(func(http.Handler) http.Handler {
				return server.mux
			})
		}
		self.ready = true
	}
	return self.middleware
}

// register adds the http.Handler/http.HandleFunc into Gorilla mux.
func (self *server) register(pattern string, handler interface{}, methods ...string) {
	var name = strings.Join(methods, "|") + ":" + pattern
	// finds the full function name (with package) as its mappings.
	//var name = runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()

	switch H := handler.(type) {
	case http.Handler:
		self.mux.Handle(pattern, H).Methods(methods...).Name(name)

	case func(http.ResponseWriter, *http.Request):
		self.mux.HandleFunc(pattern, H).Methods(methods...).Name(name)

	default:
		panic("Unsupported handler: " + name)
	}
}

// Any maps most common HTTP methods request to the given `http.Handler`.
// Supports: GET | POST | PUT | DELETE | OPTIONS | HEAD
func (self *server) Any(pattern string, handler interface{}) {
	self.register(pattern, handler, "GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD")
}

// Group creates a new application group under the given path prefix.
func (self *server) Group(prefix string) *server {
	var middleware = new(middleware)
	self.mux.PathPrefix(prefix).Handler(middleware)
	var mux = self.mux.PathPrefix(prefix).Subrouter()

	server := &server{middleware: middleware, mux: mux}
	self.subservers = append(self.subservers, server)
	return server
}

// Name returns route name for the given request, if any.
func (self *server) Name(r *http.Request) (name string) {
	var match mux.RouteMatch
	if self.mux.Match(r, &match) {
		name = match.Route.GetName()
	}
	return name
}

// FileServer registers a handler to serve HTTP (GET|HEAD) requests
// with the contents of file system under the given directory.
func (self *server) FileServer(prefix, dir string) {
	if abs, err := filepath.Abs(dir); err == nil {
		fs := http.StripPrefix(prefix, http.FileServer(http.Dir(abs)))
		self.mux.PathPrefix(prefix).Handler(fs)
	} else {
		panic("Failed to setup file server: " + err.Error())
	}
}

// Use add the middleware module into the stack chain.
func (self *server) Use(modules ...func(http.Handler) http.Handler) {
	self.middleware.stack = append(self.middleware.stack, modules...)
}

// Get is a shortcut for mux.HandleFunc(pattern, handler).Methods("GET"),
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Get(pattern string, handler interface{}) {
	self.register(pattern, handler, "GET")
}

// Head is a shortcut for mux.HandleFunc(pattern, handler).Methods("HEAD")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Head(pattern string, handler interface{}) {
	self.register(pattern, handler, "HEAD")
}

// Options is a shortcut for mux.HandleFunc(pattern, handler).Methods("OPTIONS")
// it also fetch the full function name of the handler (with package) to name the route.
// NOTE method OPTIONS is **NOT** cachable, beware of what you are going to do.
func (self *server) Options(pattern string, handler interface{}) {
	self.register(pattern, handler, "OPTIONS")
}

// POST is a shortcut for mux.HandleFunc(pattern, handler).Methods("POST")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Post(pattern string, handler interface{}) {
	self.register(pattern, handler, "POST")
}

// Put is a shortcut for mux.HandleFunc(pattern, handler).Methods("PUT")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Put(pattern string, handler interface{}) {
	self.register(pattern, handler, "PUT")
}

// Delete is a shortcut for mux.HandleFunc(pattern, handler).Methods("DELETE")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Delete(pattern string, handler interface{}) {
	self.register(pattern, handler, "DELETE")
}

// Trace is a shortcut for mux.HandleFunc(pattern, handler).Methods("TRACE")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Trace(pattern string, handler interface{}) {
	self.register(pattern, handler, "TRACE")
}

// Connect is a shortcut for mux.HandleFunc(pattern, handler).Methods("CONNECT")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Connect(pattern string, handler interface{}) {
	self.register(pattern, handler, "CONNECT")
}

// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (self *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	self.build().ServeHTTP(w, r)
}

// Run starts the application server to serve incoming requests at the given address.
func (self *server) Run() {
	runtime.GOMAXPROCS(maxprocs)

	go func() {
		time.Sleep(500 * time.Millisecond)
		log.Infof("Application server is listening at %d", port)
	}()

	if err := http.ListenAndServe(fmt.Sprintf(":%d", port), self); err != nil {
		log.Fatalf("Failed to start the server: %v", err)
	}
}

// Vars returns the route variables for the current request, if any.
func (self *server) Vars(r *http.Request) map[string]string {
	return mux.Vars(r)
}
<commit_msg>add JSON supports<commit_after>package rex

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/goanywhere/env"
	"github.com/gorilla/mux"
)

var (
	debug    bool
	port     int
	maxprocs int

	once sync.Once
)

type server struct {
	middleware *middleware
	mux        *mux.Router
	ready      bool
	subservers []*server
}

func New() *server {
	self := &server{
		middleware: new(middleware),
		mux:        mux.NewRouter().StrictSlash(true),
	}
	self.configure()
	return self
}

func (self *server) configure() {
	once.Do(func() {
		flag.BoolVar(&debug, "debug", env.Bool("DEBUG", true), "flag to toggle debug mode")
		flag.IntVar(&port, "port", env.Int("PORT", 5000), "port to run the application server")
		flag.IntVar(&maxprocs, "maxprocs", env.Int("MAXPROCS", runtime.NumCPU()), "maximum cpu processes to run the server")
		flag.Parse()
	})
}

// build constructs all server/subservers along with their middleware modules chain.
func (self *server) build() http.Handler {
	if !self.ready {
		// * add server mux into middlware stack to serve as final http.Handler.
		self.Use(func(http.Handler) http.Handler {
			return self.mux
		})
		// * add subservers into middlware stack to serve as final http.Handler.
		for index := 0; index < len(self.subservers); index++ {
			server := self.subservers[index]
			server.Use(func(http.Handler) http.Handler {
				return server.mux
			})
		}
		self.ready = true
	}
	return self.middleware
}

// register adds the http.Handler/http.HandleFunc into Gorilla mux.
func (self *server) register(pattern string, handler interface{}, methods ...string) {
	var name = strings.Join(methods, "|") + ":" + pattern
	// finds the full function name (with package) as its mappings.
	//var name = runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()

	switch H := handler.(type) {
	case http.Handler:
		self.mux.Handle(pattern, H).Methods(methods...).Name(name)

	case func(http.ResponseWriter, *http.Request):
		self.mux.HandleFunc(pattern, H).Methods(methods...).Name(name)

	default:
		panic("Unsupported handler: " + name)
	}
}

// Any maps most common HTTP methods request to the given `http.Handler`.
// Supports: GET | POST | PUT | DELETE | OPTIONS | HEAD
func (self *server) Any(pattern string, handler interface{}) {
	self.register(pattern, handler, "GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD")
}

// Group creates a new application group under the given path prefix.
func (self *server) Group(prefix string) *server {
	var middleware = new(middleware)
	self.mux.PathPrefix(prefix).Handler(middleware)
	var mux = self.mux.PathPrefix(prefix).Subrouter()

	server := &server{middleware: middleware, mux: mux}
	self.subservers = append(self.subservers, server)
	return server
}

// Name returns route name for the given request, if any.
func (self *server) Name(r *http.Request) (name string) {
	var match mux.RouteMatch
	if self.mux.Match(r, &match) {
		name = match.Route.GetName()
	}
	return name
}

// FileServer registers a handler to serve HTTP (GET|HEAD) requests
// with the contents of file system under the given directory.
func (self *server) FileServer(prefix, dir string) {
	if abs, err := filepath.Abs(dir); err == nil {
		fs := http.StripPrefix(prefix, http.FileServer(http.Dir(abs)))
		self.mux.PathPrefix(prefix).Handler(fs)
	} else {
		panic("Failed to setup file server: " + err.Error())
	}
}

// Use add the middleware module into the stack chain.
func (self *server) Use(modules ...func(http.Handler) http.Handler) {
	self.middleware.stack = append(self.middleware.stack, modules...)
}

// Get is a shortcut for mux.HandleFunc(pattern, handler).Methods("GET"),
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Get(pattern string, handler interface{}) {
	self.register(pattern, handler, "GET")
}

// Head is a shortcut for mux.HandleFunc(pattern, handler).Methods("HEAD")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Head(pattern string, handler interface{}) {
	self.register(pattern, handler, "HEAD")
}

// Options is a shortcut for mux.HandleFunc(pattern, handler).Methods("OPTIONS")
// it also fetch the full function name of the handler (with package) to name the route.
// NOTE method OPTIONS is **NOT** cachable, beware of what you are going to do.
func (self *server) Options(pattern string, handler interface{}) {
	self.register(pattern, handler, "OPTIONS")
}

// POST is a shortcut for mux.HandleFunc(pattern, handler).Methods("POST")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Post(pattern string, handler interface{}) {
	self.register(pattern, handler, "POST")
}

// Put is a shortcut for mux.HandleFunc(pattern, handler).Methods("PUT")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Put(pattern string, handler interface{}) {
	self.register(pattern, handler, "PUT")
}

// Delete is a shortcut for mux.HandleFunc(pattern, handler).Methods("DELETE")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Delete(pattern string, handler interface{}) {
	self.register(pattern, handler, "DELETE")
}

// Trace is a shortcut for mux.HandleFunc(pattern, handler).Methods("TRACE")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Trace(pattern string, handler interface{}) {
	self.register(pattern, handler, "TRACE")
}

// Connect is a shortcut for mux.HandleFunc(pattern, handler).Methods("CONNECT")
// it also fetch the full function name of the handler (with package) to name the route.
func (self *server) Connect(pattern string, handler interface{}) {
	self.register(pattern, handler, "CONNECT")
}

// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (self *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	self.build().ServeHTTP(w, r)
}

// Sends the HTTP response in JSON.
func (self *server) Send(w http.ResponseWriter, v interface{}) {
	var buffer = new(bytes.Buffer)

	w.Header().Set("Content-type", "application/json; charset=utf-8")
	if err := json.NewEncoder(buffer).Encode(v); err == nil {
		w.Write(buffer.Bytes())
	} else {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Renders a view (Pongo) and sends the rendered HTML string to the client.
// Optional parameters: value, local variables for the view.
// func (self *server) Render(filename string, v ...interface{}) {}

// Run starts the application server to serve incoming requests at the given address.
func (self *server) Run() {
	runtime.GOMAXPROCS(maxprocs)

	go func() {
		time.Sleep(500 * time.Millisecond)
		log.Infof("Application server is listening at %d", port)
	}()

	if err := http.ListenAndServe(fmt.Sprintf(":%d", port), self); err != nil {
		log.Fatalf("Failed to start the server: %v", err)
	}
}

// Vars returns the route variables for the current request, if any.
func (self *server) Vars(r *http.Request) map[string]string {
	return mux.Vars(r)
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "database/sql"
    "github.com/orc/db"
    "github.com/orc/resources"
    "github.com/orc/router"
    "github.com/orc/mvc/controllers"
    "log"
    "net/http"
    "os"
)

var err error

func main() {
    log.Println("Server started.")

    db.DB, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))

    if err != nil {
        log.Println("Error db connection: ", err.Error())
        os.Exit(1)
    }

    log.Println("DB CONNECTED")

    testData := flag.Bool("test-data", false, "to load test data")
    flag.Parse()

    // db.Init()
    controllers.CreateRegistrationEvent()
    resources.LoadAdmin()

    if *testData == true {
        resources.Load()
    }

    // base := new(controllers.BaseController)
    // base.Index().LoadContestsFromCats()

    http.Handle("/", new(router.FastCGIServer))
    http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./static/js"))))
    http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./static/css"))))
    http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./static/img"))))

    port := os.Getenv("PORT")
    if port == "" {
        port = "5000"
    }

    if err := http.ListenAndServe(":" + port, nil); err != nil {
        log.Println("Error listening: ", err.Error())
        os.Exit(1)
    }
}
<commit_msg>add defer close db connection<commit_after>package main

import (
    "flag"
    "database/sql"
    "github.com/orc/db"
    "github.com/orc/resources"
    "github.com/orc/router"
    "github.com/orc/mvc/controllers"
    "log"
    "net/http"
    "os"
)

var err error

func main() {
    log.Println("Server started.")

    db.DB, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
    defer db.DB.Close()

    if err != nil {
        log.Println("Error db connection: ", err.Error())
        os.Exit(1)
    }

    log.Println("DB CONNECTED")

    testData := flag.Bool("test-data", false, "to load test data")
    flag.Parse()

    // db.Init()
    controllers.CreateRegistrationEvent()
    resources.LoadAdmin()

    if *testData == true {
        resources.Load()
    }

    // base := new(controllers.BaseController)
    // base.Index().LoadContestsFromCats()

    http.Handle("/", new(router.FastCGIServer))
    http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./static/js"))))
    http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./static/css"))))
    http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./static/img"))))

    port := os.Getenv("PORT")
    if port == "" {
        port = "5000"
    }

    if err := http.ListenAndServe(":" + port, nil); err != nil {
        log.Println("Error listening: ", err.Error())
        os.Exit(1)
    }
}
<|endoftext|>


<commit_before>package main

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

type movement struct {
	X_dif int
	Y_dif int
}

func main() {

	//movements := make(chan movement, 500) //makes a channel for movements, with a depth of 500

	http.HandleFunc("/control/", control)

	http.HandleFunc("/move/", func(w http.ResponseWriter, req *http.Request) {
		log.Println("Recieved post request.")
		axis := req.FormValue("axis")
		step := req.FormValue("step")

		if axis != "x" || axis != "y" {
			w.WriteHeader(500)
		}

		log.Printf("Moving %d units on %s", step, axis)
		w.Write([]byte("Success!  "))
	})

	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		panic(err.Error())
	}
}

func control(w http.ResponseWriter, req *http.Request) {
	fmt.Fprint(w, "Oh hi there!")
}

func move_x(movements chan movement, toMove int) {

}

func move_y(movements chan movement, toMove int) {

}
<commit_msg>fixed some wrong stuff<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"strconv"
)

type movement struct {
	X_dif int
	Y_dif int
}

func main() {

	//movements := make(chan movement, 500) //makes a channel for movements, with a depth of 500

	http.HandleFunc("/control/", control)

	http.HandleFunc("/move/", func(w http.ResponseWriter, req *http.Request) {
		log.Println("Recieved post request.")
		axis := req.FormValue("axis")
		step := req.FormValue("step")
		w.Header().Set("Access-Control-Allow-Origin", "*")

		message := []byte("Don't know yet")

		toMove, err := strconv.Atoi(step)
		if err != nil {
			w.WriteHeader(500)
			message = []byte("Step needs to be an integer")
		} else if axis != "x" || axis != "y" {
			w.WriteHeader(500)
			message = []byte("Axis needs to be x or y")
		} else {
			log.Printf("Moving %d units on %s", toMove, axis)
			message = []byte("Success! ")
		}
		w.Write(message)
	})

	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		panic(err.Error())
	}
}

func control(w http.ResponseWriter, req *http.Request) {
	fmt.Fprint(w, "Oh hi there!")
}

func move_x(movements chan movement, toMove int) {

}

func move_y(movements chan movement, toMove int) {

}
<|endoftext|>