<commit_before>package factom

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/FactomProject/FactomCode/wallet"
)

var server string = "http://localhost:8083"

func sha(b []byte) []byte {
	s := sha256.New()
	s.Write(b)
	return s.Sum(nil)
}

// PrintEntry is a helper function for debugging entry transport and encoding
func PrintEntry(e *Entry) {
	fmt.Println("ChainID:", hex.EncodeToString(e.ChainID))
	fmt.Println("ExtIDs:")
	for i := range e.ExtIDs {
		fmt.Println("	", string(e.ExtIDs[i]))
	}
	fmt.Println("Data:", string(e.Data))
}

// SetServer specifies the address of the server recieving the factom messages.
// It should be depricated by the final release once the p2p network has been
// implimented
func SetServer(s string) {
	server = s
}

// NewEntry creates a factom entry. It is supplied a string chain id, a []byte
// of data, and a series of string external ids for entry lookup
func NewEntry(cid string, eids []string, data []byte) (e *Entry, err error) {
	e = new(Entry)
	e.ChainID, err = hex.DecodeString(cid)
	if err != nil {
		return nil, err
	}
	e.Data = data
	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, []byte(v))
	}
	return
}

// NewChain creates a factom chain from a []string chain name and a new entry
// to be the first entry of the new chain from []byte data, and a series of
// string external ids
func NewChain(name []string, eids []string, data []byte) (c *Chain, err error) {
	c = new(Chain)
	for _, v := range name {
		c.Name = append(c.Name, []byte(v))
	}
	c.GenerateID()
	e := c.FirstEntry
	e.ChainID = c.ChainID
	e.Data = data
	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, []byte(v))
	}
	return
}

// CommitEntry sends a message to the factom network containing a hash of the
// entry to be used to verify the later RevealEntry.
func CommitEntry(e *Entry) error {
	var msg bytes.Buffer

	msg.Write([]byte{byte(time.Now().Unix())})
	msg.Write(e.MarshalBinary())
	sig := wallet.SignData(msg.Bytes())

	// msg.Bytes should be a int64 timestamp followed by a binary entry

	data := url.Values{
		"datatype":  {"commitentry"},
		"format":    {"binary"},
		"signature": {hex.EncodeToString((*sig.Sig)[:])},
		"data":      {hex.EncodeToString(msg.Bytes())},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// RevealEntry sends a message to the factom network containing the binary
// encoded entry for the server to add it to the factom blockchain. The entry
// will be rejected if a CommitEntry was not done.
func RevealEntry(e *Entry) error {
	data := url.Values{
		"datatype": {"entry"},
		"format":   {"binary"},
		"entry":    {e.Hex()},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// CommitChain sends a message to the factom network containing a series of
// hashes to be used to verify the later RevealChain.
func CommitChain(c *Chain) error {
	data := url.Values{
		"datatype": {"chainhash"},
		"format":   {"binary"},
		"data":     {c.Hash()},
	}

	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// RevealChain sends a message to the factom network containing the binary
// encoded first entry for a chain to be used by the server to add a new factom
// chain. It will be rejected if a CommitChain was not done.
func RevealChain(c *Chain) error {
	data := url.Values{
		"datatype": {"entry"},
		"format":   {"binary"},
		"data":     {c.FirstEntry.Hex()},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// Submit wraps CommitEntry and RevealEntry. Submit takes a FactomWriter (an
// entry is a FactomWriter) and does a commit and reveal for the entry adding
// it to the factom blockchain.
func Submit(f FactomWriter) (err error) {
	e := f.CreateFactomEntry()
//	err = CommitEntry(e)
//	if err != nil {
//		return err
//	}
	err = RevealEntry(e)
	if err != nil {
		return err
	}
	return nil
}

// CreateChain takes a FactomChainer (a Chain is a FactomChainer) and calls
// commit and reveal to create the factom chain on the network.
func CreateChain(f FactomChainer) error {
	c := f.CreateFactomChain()
	err := CommitChain(c)
	if err != nil {
		return err
	}
	time.Sleep(1 * time.Minute)
	err = RevealChain(c)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>more work on CommitEntry()<commit_after>package factom

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/FactomProject/FactomCode/wallet"
)

var server string = "http://localhost:8083"

func sha(b []byte) []byte {
	s := sha256.New()
	s.Write(b)
	return s.Sum(nil)
}

// PrintEntry is a helper function for debugging entry transport and encoding
func PrintEntry(e *Entry) {
	fmt.Println("ChainID:", hex.EncodeToString(e.ChainID))
	fmt.Println("ExtIDs:")
	for i := range e.ExtIDs {
		fmt.Println("	", string(e.ExtIDs[i]))
	}
	fmt.Println("Data:", string(e.Data))
}

// SetServer specifies the address of the server recieving the factom messages.
// It should be depricated by the final release once the p2p network has been
// implimented
func SetServer(s string) {
	server = s
}

// NewEntry creates a factom entry. It is supplied a string chain id, a []byte
// of data, and a series of string external ids for entry lookup
func NewEntry(cid string, eids []string, data []byte) (e *Entry, err error) {
	e = new(Entry)
	e.ChainID, err = hex.DecodeString(cid)
	if err != nil {
		return nil, err
	}
	e.Data = data
	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, []byte(v))
	}
	return
}

// NewChain creates a factom chain from a []string chain name and a new entry
// to be the first entry of the new chain from []byte data, and a series of
// string external ids
func NewChain(name []string, eids []string, data []byte) (c *Chain, err error) {
	c = new(Chain)
	for _, v := range name {
		c.Name = append(c.Name, []byte(v))
	}
	c.GenerateID()
	e := c.FirstEntry
	e.ChainID = c.ChainID
	e.Data = data
	for _, v := range eids {
		e.ExtIDs = append(e.ExtIDs, []byte(v))
	}
	return
}

// CommitEntry sends a message to the factom network containing a hash of the
// entry to be used to verify the later RevealEntry.
func CommitEntry(e *Entry) error {
	var msg bytes.Buffer

	msg.Write([]byte{byte(time.Now().Unix())})
	msg.Write(sha(e.MarshalBinary()))
	sig := wallet.SignData(msg.Bytes())

	// msg.Bytes should be a int64 timestamp followed by a binary entry

	data := url.Values{
		"datatype":  {"commitentry"},
		"format":    {"binary"},
		"signature": {hex.EncodeToString((*sig.Sig)[:])},
		"data":      {hex.EncodeToString(msg.Bytes())},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// RevealEntry sends a message to the factom network containing the binary
// encoded entry for the server to add it to the factom blockchain. The entry
// will be rejected if a CommitEntry was not done.
func RevealEntry(e *Entry) error {
	data := url.Values{
		"datatype": {"entry"},
		"format":   {"binary"},
		"entry":    {e.Hex()},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// CommitChain sends a message to the factom network containing a series of
// hashes to be used to verify the later RevealChain.
func CommitChain(c *Chain) error {
	data := url.Values{
		"datatype": {"chainhash"},
		"format":   {"binary"},
		"data":     {c.Hash()},
	}

	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// RevealChain sends a message to the factom network containing the binary
// encoded first entry for a chain to be used by the server to add a new factom
// chain. It will be rejected if a CommitChain was not done.
func RevealChain(c *Chain) error {
	data := url.Values{
		"datatype": {"entry"},
		"format":   {"binary"},
		"data":     {c.FirstEntry.Hex()},
	}
	_, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	return nil
}

// Submit wraps CommitEntry and RevealEntry. Submit takes a FactomWriter (an
// entry is a FactomWriter) and does a commit and reveal for the entry adding
// it to the factom blockchain.
func Submit(f FactomWriter) (err error) {
	e := f.CreateFactomEntry()
//	err = CommitEntry(e)
//	if err != nil {
//		return err
//	}
	err = RevealEntry(e)
	if err != nil {
		return err
	}
	return nil
}

// CreateChain takes a FactomChainer (a Chain is a FactomChainer) and calls
// commit and reveal to create the factom chain on the network.
func CreateChain(f FactomChainer) error {
	c := f.CreateFactomChain()
	err := CommitChain(c)
	if err != nil {
		return err
	}
	time.Sleep(1 * time.Minute)
	err = RevealChain(c)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

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

const apiEndpoint = "http://dbios.herokuapp.com/"

type Program struct {
    Title    string `json:"title"`
    Id       int    `json:"id"`
    ImageUrl string `json:"image_url"`
}

type ProgramCollection []Program

type Workout struct {
    ImageUrl           string `json:"image_url"`
    WorkoutDescription string `json:"workout_description"`
    Title              string `json:"title"`
    ProgramIDs         []int  `json:"program_ids"`
    TrainerName        string `json:"trainer_name"`
}

type WorkoutCollection []Workout

func getJawn(thingType string) []byte {
    apiURL := apiEndpoint + thingType
    res, err := http.Get(apiURL)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    return body
}

func parsePrograms() ProgramCollection {
    response := getJawn("programs")
    var result ProgramCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func parseWorkouts() WorkoutCollection {
    response := getJawn("workouts")
    var result WorkoutCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func main() {
}
<commit_msg>print Programs<commit_after>package main

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

const apiEndpoint = "http://dbios.herokuapp.com/"

type Program struct {
    Title    string `json:"title"`
    Id       int    `json:"id"`
    ImageUrl string `json:"image_url"`
}

type ProgramCollection []Program

type Workout struct {
    ImageUrl           string `json:"image_url"`
    WorkoutDescription string `json:"workout_description"`
    Title              string `json:"title"`
    ProgramIDs         []int  `json:"program_ids"`
    TrainerName        string `json:"trainer_name"`
}

type WorkoutCollection []Workout

func getJawn(thingType string) []byte {
    apiURL := apiEndpoint + thingType
    res, err := http.Get(apiURL)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    return body
}

func parsePrograms() ProgramCollection {
    response := getJawn("programs")
    var result ProgramCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func parseWorkouts() WorkoutCollection {
    response := getJawn("workouts")
    var result WorkoutCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func listPrograms() {
    programs := parsePrograms()
    for i := range programs {
        fmt.Println(programs[i].Title, programs[i].Id, programs[i].ImageUrl)
    }
}

func main() {
    listPrograms()
}
<|endoftext|>


<commit_before>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}
<commit_msg>adding WalkDevices<commit_after>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}

func (vm VirtualMachine) WalkDevices(f func(Device) bool, types ...string) bool {
	var sata, ide, scsi bool
	for _, t := range types {
		switch t {
		case "sata":
			sata = true
		case "ide":
			ide = true
		case "scsi":
			scsi = true
		}
	}
	if len(types) == 0 {
		sata, ide, scsi = true, true, true
	}
	if ide {
		for _, d := range vm.IDEDevices {
			if f(d.Device) {
				return true
			}
		}
	}
	if scsi {
		for _, d := range vm.SCSIDevices {
			if f(d.Device) {
				return true
			}
		}
	}
	if sata {
		for _, d := range vm.SATADevices {
			if f(d.Device) {
				return true
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hash"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

func init() {
	http.HandleFunc("/", home)
	http.HandleFunc("/_github", githubWebhook)
}

func home(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome Home")
}

func githubWebhook(w http.ResponseWriter, r *http.Request) {
	event := r.Header.Get("X-GitHub-Event")
	signature := r.Header.Get("X-Hub-Signature")
	if event == "" || signature == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Missing Event or Signature")
		return
	}
	if event != "push" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid event")
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error reading body: %s\n", err)
		return
	}

	var hashMethod string
	p := strings.SplitN(signature, "=", 2)
	hashMethod, signature = p[0], p[1]

	var hasher func() hash.Hash
	switch hashMethod {
	case "sha1":
		hasher = sha1.New
	default:
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid Hash Method")
		return
	}

	hmacer := hmac.New(hasher, GITHUB_SECRET)
	hmacer.Write(body)
	computed := hex.EncodeToString(hmacer.Sum(nil))
	if computed != signature {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid signature")
		return
	}

	var data *struct {
		RefName string `json:"ref_name"`
		Ref     string `json:"ref"`
	}
	err = json.Unmarshal(body, &data)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Unparsable body")
		return
	}

	if data.RefName == "" {
		data.RefName = strings.Replace(strings.Replace(data.Ref, "refs/tags/", "", -1), "refs/heads/", "", -1)
	}
	if data.RefName != "master" {
		fmt.Fprintln(w, "Ignoring as branch isn't master")
		return
	}

	go func() {
		time.Sleep(1 * time.Second)
		os.Exit(420)
	}()

	fmt.Fprintln(w, "Updating in 1 second...")
}
<commit_msg>Convert to byte array<commit_after>package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hash"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

func init() {
	http.HandleFunc("/", home)
	http.HandleFunc("/_github", githubWebhook)
}

func home(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome Home")
}

func githubWebhook(w http.ResponseWriter, r *http.Request) {
	event := r.Header.Get("X-GitHub-Event")
	signature := r.Header.Get("X-Hub-Signature")
	if event == "" || signature == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Missing Event or Signature")
		return
	}
	if event != "push" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid event")
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error reading body: %s\n", err)
		return
	}

	var hashMethod string
	p := strings.SplitN(signature, "=", 2)
	hashMethod, signature = p[0], p[1]

	var hasher func() hash.Hash
	switch hashMethod {
	case "sha1":
		hasher = sha1.New
	default:
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid Hash Method")
		return
	}

	hmacer := hmac.New(hasher, []byte(GITHUB_SECRET))
	hmacer.Write(body)
	computed := hex.EncodeToString(hmacer.Sum(nil))
	if computed != signature {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Invalid signature")
		return
	}

	var data *struct {
		RefName string `json:"ref_name"`
		Ref     string `json:"ref"`
	}
	err = json.Unmarshal(body, &data)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Unparsable body")
		return
	}

	if data.RefName == "" {
		data.RefName = strings.Replace(strings.Replace(data.Ref, "refs/tags/", "", -1), "refs/heads/", "", -1)
	}
	if data.RefName != "master" {
		fmt.Fprintln(w, "Ignoring as branch isn't master")
		return
	}

	go func() {
		time.Sleep(1 * time.Second)
		os.Exit(420)
	}()

	fmt.Fprintln(w, "Updating in 1 second...")
}
<|endoftext|>


<commit_before>package itembase

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/facebookgo/httpcontrol"
	"net/http"
	"net/url"
	"time"
)

// httpClient is the HTTP client used to make calls to Itembase with the default API
var httpClient = newTimeoutClient(connectTimeout, readWriteTimeout)

// itembaseAPI is the internal implementation of the Itembase API client.
type itembaseAPI struct{}

var (
	connectTimeout   = time.Duration(30 * time.Second) // timeout for http connection
	readWriteTimeout = time.Duration(30 * time.Second) // timeout for http read/write
)

func doItembaseRequest(client *http.Client, method, path, auth, accept string, body interface{}, params map[string]string) (*http.Response, error) {

	qs := url.Values{}

	for k, v := range params {
		qs.Set(k, v)
	}

	if len(qs) > 0 {
		path += "?" + qs.Encode()
	}

	encodedBody, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	fmt.Println(path)
	req, err := http.NewRequest(method, path, bytes.NewReader(encodedBody))
	if err != nil {
		return nil, err
	}

	// if the client has an auth, set it as a header
	if len(auth) > 0 {
		req.Header.Add("Authorization", "Bearer "+auth)
	}

	if accept != "" {
		req.Header.Add("Accept", accept)
	}

	req.Close = true

	return client.Do(req)
}

// Call invokes the appropriate HTTP method on a given Itembase URL.
func (f *itembaseAPI) Call(method, path, auth string, body interface{}, params map[string]string, dest interface{}) error {
	response, err := doItembaseRequest(httpClient, method, path, auth, "", body, params)
	if err != nil {
		fmt.Println("error")
		fmt.Println(err)
		return err
	}

	defer response.Body.Close()

	decoder := json.NewDecoder(response.Body)
	if response.StatusCode >= 400 {
		err := &Error{Code: response.StatusCode, Message: response.Status}
		decoder.Decode(err)
		return err
	}

	if dest != nil && response.ContentLength != 0 {
		err = decoder.Decode(dest)
		if err != nil {
			fmt.Println("error 3")
			fmt.Println(err)
			return err
		}
	}

	return nil
}

func newTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {
	return &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout:      readWriteTimeout,
			DialTimeout:         connectTimeout,
			MaxTries:            30,
			MaxIdleConnsPerHost: 5,
		},
	}
}
<commit_msg>increase timeouts to 120 seconds, retry after timeout<commit_after>package itembase

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/facebookgo/httpcontrol"
	"net/http"
	"net/url"
	"time"
)

// httpClient is the HTTP client used to make calls to Itembase with the default API
var httpClient = newTimeoutClient(connectTimeout, readWriteTimeout)

// itembaseAPI is the internal implementation of the Itembase API client.
type itembaseAPI struct{}

var (
	connectTimeout   = time.Duration(120 * time.Second) // timeout for http connection
	readWriteTimeout = time.Duration(120 * time.Second) // timeout for http read/write
)

func doItembaseRequest(client *http.Client, method, path, auth, accept string, body interface{}, params map[string]string) (*http.Response, error) {

	qs := url.Values{}

	for k, v := range params {
		qs.Set(k, v)
	}

	if len(qs) > 0 {
		path += "?" + qs.Encode()
	}

	encodedBody, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	fmt.Println(path)
	req, err := http.NewRequest(method, path, bytes.NewReader(encodedBody))
	if err != nil {
		return nil, err
	}

	// if the client has an auth, set it as a header
	if len(auth) > 0 {
		req.Header.Add("Authorization", "Bearer "+auth)
	}

	if accept != "" {
		req.Header.Add("Accept", accept)
	}

	req.Close = true

	return client.Do(req)
}

// Call invokes the appropriate HTTP method on a given Itembase URL.
func (f *itembaseAPI) Call(method, path, auth string, body interface{}, params map[string]string, dest interface{}) error {
	response, err := doItembaseRequest(httpClient, method, path, auth, "", body, params)
	if err != nil {
		fmt.Println("error")
		fmt.Println(err)
		return err
	}

	defer response.Body.Close()

	decoder := json.NewDecoder(response.Body)
	if response.StatusCode >= 400 {
		err := &Error{Code: response.StatusCode, Message: response.Status}
		decoder.Decode(err)
		return err
	}

	if dest != nil && response.ContentLength != 0 {
		err = decoder.Decode(dest)
		if err != nil {
			fmt.Println("error 3")
			fmt.Println(err)
			return err
		}
	}

	return nil
}

func newTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {
	return &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout:      readWriteTimeout,
			DialTimeout:         connectTimeout,
			MaxTries:            60,
			MaxIdleConnsPerHost: 5,
			RetryAfterTimeout:   true,
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

const (
	headerTaId       = "X-Edo-Ta-Id"
	headerTaToken    = "X-Edo-Ta-Token"
	headerTaTokenSig = "X-Edo-Ta-Token-Sign"
	headerHashFunc   = "X-Edo-Hash-Function"

	headerTaAuthErr = "X-Edo-Ta-Auth-Error"

	cookieTaSess = "X-Edo-Ta-Session"
)

func uriBase(url *url.URL) string {
	return url.Scheme + "://" + url.Host + url.Path
}

// Web プロキシ。
func proxyApi(sys *system, w http.ResponseWriter, r *http.Request) error {

	taId := r.Header.Get(headerTaId)
	if taId == "" {
		taId = sys.taId
	}

	sess, _, err := sys.session(uriBase(r.URL), taId, nil)
	if err != nil {
		return erro.Wrap(err)
	}

	if sess != nil {
		// セッション確立済み。
		log.Debug("authenticated session is exist")
		return forward(sys, w, r, taId, sess)
	} else {
		// セッション未確立。
		log.Debug("session is not exist")
		return startSession(sys, w, r, taId)
	}
}

// 転送する。
func forward(sys *system, w http.ResponseWriter, r *http.Request, taId string, sess *session) error {
	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.id})
	r.RequestURI = ""

	resp, err := sess.cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("forwarded")

	if resp.StatusCode == http.StatusUnauthorized && resp.Header.Get(headerTaAuthErr) != "" {
		// edo-auth で 401 Unauthorized なら、タイミングの問題なので startSession からやり直す。
		// 古いセッションは上書きされるので消す必要無し。
		return startSession(sys, w, r, taId)
	}

	return copyResponse(resp, w)
}

// セッション開始。
func startSession(sys *system, w http.ResponseWriter, r *http.Request, taId string) error {

	cli := &http.Client{}

	r.RequestURI = ""
	resp, err := cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("sent raw request")

	if resp.Header.Get(headerTaAuthErr) == "" || resp.StatusCode != http.StatusUnauthorized {
		// 相手側が TA 認証を必要としていなかったのかもしれない。
		return copyResponse(resp, w)
	}

	// 相手側 TA も認証始めた。
	log.Debug("authentication started")

	sess, sessToken := parseSession(resp)
	if sess == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no cookie "+cookieTaSess, nil))
	} else if sessToken == "" {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no header field "+headerTaToken, nil))
	}

	expiDate := getExpirationDate(sess)

	// 認証用データが揃ってた。
	log.Debug("authentication data was found")

	priKey, _, err := sys.privateKey(taId, nil)
	if err != nil {
		return erro.Wrap(err)
	} else if priKey == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no private key of "+taId, nil))
	}

	// 秘密鍵を用意できた。
	log.Debug("private key of " + taId + " is exist")

	hashName := r.Header.Get(headerHashFunc)
	if hashName == "" {
		hashName = sys.hashName
	}

	sign, err := sign(priKey, hashName, sessToken)
	if err != nil {
		return erro.Wrap(err)
	}

	// 署名できた。
	log.Debug("signed")

	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.Value})
	r.Header.Set(headerTaId, taId)
	r.Header.Set(headerTaTokenSig, sign)
	r.Header.Set(headerHashFunc, hashName)
	r.RequestURI = ""

	resp, err = cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	// 認証された。
	log.Debug("authentication finished")

	if resp.Header.Get(headerTaAuthErr) != "" {
		// セッションを保存。
		if _, err := sys.addSession(&session{id: sess.Value, uri: uriBase(r.URL), taId: taId, cli: cli}, expiDate); err != nil {
			return erro.Wrap(err)
		}
	}

	return copyResponse(resp, w)
}

// 相手側 TA の認証開始レスポンスから必要情報を抜き出す。
func parseSession(resp *http.Response) (sess *http.Cookie, sessToken string) {
	for _, cookie := range resp.Cookies() {
		if cookie.Name == cookieTaSess {
			sess = cookie
			break
		}
	}

	return sess, resp.Header.Get(headerTaToken)
}

// 相手側 TA からのレスポンスをリクエスト元へのレスポンスに写す。
func copyResponse(resp *http.Response, w http.ResponseWriter) error {
	// ヘッダフィールドのコピー。
	for key, values := range resp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	// ステータスのコピー。
	w.WriteHeader(resp.StatusCode)

	// ボディのコピー。
	if _, err := io.Copy(w, resp.Body); err != nil {
		return erro.Wrap(err)
	}

	return nil
}

// 相手側 TA からのお題に署名する。
func sign(priKey *rsa.PrivateKey, hashName, token string) (string, error) {
	hash, err := util.ParseHashFunction(hashName)
	if err != nil {
		return "", erro.Wrap(err)
	}

	h := hash.New()
	h.Write([]byte(token))
	buff, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, h.Sum(nil))
	if err != nil {
		return "", erro.Wrap(err)
	}

	return base64.StdEncoding.EncodeToString(buff), nil
}

// 相手側 TA が提示したセッションの有効期限を読み取る。
func getExpirationDate(sess *http.Cookie) (expiDate time.Time) {
	if sess.MaxAge != 0 {
		return time.Now().Add(time.Duration(sess.MaxAge))
	} else {
		return sess.Expires
	}
}
<commit_msg>関数名と被っていた変数名を変更<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

const (
	headerTaId       = "X-Edo-Ta-Id"
	headerTaToken    = "X-Edo-Ta-Token"
	headerTaTokenSig = "X-Edo-Ta-Token-Sign"
	headerHashFunc   = "X-Edo-Hash-Function"

	headerTaAuthErr = "X-Edo-Ta-Auth-Error"

	cookieTaSess = "X-Edo-Ta-Session"
)

func uriBase(url *url.URL) string {
	return url.Scheme + "://" + url.Host + url.Path
}

// Web プロキシ。
func proxyApi(sys *system, w http.ResponseWriter, r *http.Request) error {

	taId := r.Header.Get(headerTaId)
	if taId == "" {
		taId = sys.taId
	}

	sess, _, err := sys.session(uriBase(r.URL), taId, nil)
	if err != nil {
		return erro.Wrap(err)
	}

	if sess != nil {
		// セッション確立済み。
		log.Debug("authenticated session is exist")
		return forward(sys, w, r, taId, sess)
	} else {
		// セッション未確立。
		log.Debug("session is not exist")
		return startSession(sys, w, r, taId)
	}
}

// 転送する。
func forward(sys *system, w http.ResponseWriter, r *http.Request, taId string, sess *session) error {
	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.id})
	r.RequestURI = ""

	resp, err := sess.cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("forwarded")

	if resp.StatusCode == http.StatusUnauthorized && resp.Header.Get(headerTaAuthErr) != "" {
		// edo-auth で 401 Unauthorized なら、タイミングの問題なので startSession からやり直す。
		// 古いセッションは上書きされるので消す必要無し。
		return startSession(sys, w, r, taId)
	}

	return copyResponse(resp, w)
}

// セッション開始。
func startSession(sys *system, w http.ResponseWriter, r *http.Request, taId string) error {

	cli := &http.Client{}

	r.RequestURI = ""
	resp, err := cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("sent raw request")

	if resp.Header.Get(headerTaAuthErr) == "" || resp.StatusCode != http.StatusUnauthorized {
		// 相手側が TA 認証を必要としていなかったのかもしれない。
		return copyResponse(resp, w)
	}

	// 相手側 TA も認証始めた。
	log.Debug("authentication started")

	sess, sessToken := parseSession(resp)
	if sess == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no cookie "+cookieTaSess, nil))
	} else if sessToken == "" {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no header field "+headerTaToken, nil))
	}

	expiDate := getExpirationDate(sess)

	// 認証用データが揃ってた。
	log.Debug("authentication data was found")

	priKey, _, err := sys.privateKey(taId, nil)
	if err != nil {
		return erro.Wrap(err)
	} else if priKey == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no private key of "+taId, nil))
	}

	// 秘密鍵を用意できた。
	log.Debug("private key of " + taId + " is exist")

	hashName := r.Header.Get(headerHashFunc)
	if hashName == "" {
		hashName = sys.hashName
	}

	tokenSign, err := sign(priKey, hashName, sessToken)
	if err != nil {
		return erro.Wrap(err)
	}

	// 署名できた。
	log.Debug("signed")

	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.Value})
	r.Header.Set(headerTaId, taId)
	r.Header.Set(headerTaTokenSig, tokenSign)
	r.Header.Set(headerHashFunc, hashName)
	r.RequestURI = ""

	resp, err = cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	// 認証された。
	log.Debug("authentication finished")

	if resp.Header.Get(headerTaAuthErr) != "" {
		// セッションを保存。
		if _, err := sys.addSession(&session{id: sess.Value, uri: uriBase(r.URL), taId: taId, cli: cli}, expiDate); err != nil {
			return erro.Wrap(err)
		}
	}

	return copyResponse(resp, w)
}

// 相手側 TA の認証開始レスポンスから必要情報を抜き出す。
func parseSession(resp *http.Response) (sess *http.Cookie, sessToken string) {
	for _, cookie := range resp.Cookies() {
		if cookie.Name == cookieTaSess {
			sess = cookie
			break
		}
	}

	return sess, resp.Header.Get(headerTaToken)
}

// 相手側 TA からのレスポンスをリクエスト元へのレスポンスに写す。
func copyResponse(resp *http.Response, w http.ResponseWriter) error {
	// ヘッダフィールドのコピー。
	for key, values := range resp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	// ステータスのコピー。
	w.WriteHeader(resp.StatusCode)

	// ボディのコピー。
	if _, err := io.Copy(w, resp.Body); err != nil {
		return erro.Wrap(err)
	}

	return nil
}

// 相手側 TA からのお題に署名する。
func sign(priKey *rsa.PrivateKey, hashName, token string) (string, error) {
	hash, err := util.ParseHashFunction(hashName)
	if err != nil {
		return "", erro.Wrap(err)
	}

	h := hash.New()
	h.Write([]byte(token))
	buff, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, h.Sum(nil))
	if err != nil {
		return "", erro.Wrap(err)
	}

	return base64.StdEncoding.EncodeToString(buff), nil
}

// 相手側 TA が提示したセッションの有効期限を読み取る。
func getExpirationDate(sess *http.Cookie) (expiDate time.Time) {
	if sess.MaxAge != 0 {
		return time.Now().Add(time.Duration(sess.MaxAge))
	} else {
		return sess.Expires
	}
}
<|endoftext|>


<commit_before>package osdn

import (
	"fmt"

	log "github.com/golang/glog"

	"github.com/openshift/openshift-sdn/pkg/netutils"

	kapi "k8s.io/kubernetes/pkg/api"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/container"
)

const (
	// Maximum VXLAN Network Identifier as per RFC#7348
	MaxVNID = ((1 << 24) - 1)
	// VNID for the admin namespaces
	AdminVNID = uint(0)
)

func populateVNIDMap(oc *OsdnController) error {
	nets, err := oc.Registry.GetNetNamespaces()
	if err != nil {
		return err
	}

	for _, net := range nets {
		oc.VNIDMap[net.Name] = net.NetID
	}
	return nil
}

func (oc *OsdnController) VnidStartMaster() error {
	err := populateVNIDMap(oc)
	if err != nil {
		return err
	}

	inUse := make([]uint, 0)
	for _, netid := range oc.VNIDMap {
		if netid != AdminVNID {
			inUse = append(inUse, netid)
		}
	}
	// VNID: 0 reserved for default namespace and can reach any network in the cluster
	// VNID: 1 to 9 are internally reserved for any special cases in the future
	oc.netIDManager, err = netutils.NewNetIDAllocator(10, MaxVNID, inUse)
	if err != nil {
		return err
	}

	// 'default' namespace is currently always an admin namespace
	oc.adminNamespaces = append(oc.adminNamespaces, "default")

	go watchNamespaces(oc)
	return nil
}

func (oc *OsdnController) isAdminNamespace(nsName string) bool {
	for _, name := range oc.adminNamespaces {
		if name == nsName {
			return true
		}
	}
	return false
}

func (oc *OsdnController) assignVNID(namespaceName string) error {
	_, err := oc.Registry.GetNetNamespace(namespaceName)
	if err == nil {
		return nil
	}
	var netid uint
	if oc.isAdminNamespace(namespaceName) {
		netid = AdminVNID
	} else {
		var err error
		netid, err = oc.netIDManager.GetNetID()
		if err != nil {
			return err
		}
	}
	err = oc.Registry.WriteNetNamespace(namespaceName, netid)
	if err != nil {
		e := oc.netIDManager.ReleaseNetID(netid)
		if e != nil {
			log.Errorf("Error while releasing Net ID: %v", e)
		}
		return err
	}
	oc.VNIDMap[namespaceName] = netid
	log.Infof("Assigned id %d to namespace %q", netid, namespaceName)
	return nil
}

func (oc *OsdnController) revokeVNID(namespaceName string) error {
	err := oc.Registry.DeleteNetNamespace(namespaceName)
	if err != nil {
		return err
	}
	netid, found := oc.VNIDMap[namespaceName]
	if !found {
		return fmt.Errorf("Error while fetching Net ID for namespace: %s", namespaceName)
	}
	delete(oc.VNIDMap, namespaceName)

	// Skip AdminVNID as it is not part of Net ID allocation
	if netid == AdminVNID {
		return nil
	}

	// Check if this netid is used by any other namespaces
	// If not, then release the netid
	netid_inuse := false
	for name, id := range oc.VNIDMap {
		if id == netid {
			netid_inuse = true
			log.V(5).Infof("Net ID %d for namespace %q is still in use by namespace %q", netid, namespaceName, name)
			break
		}
	}
	if !netid_inuse {
		err = oc.netIDManager.ReleaseNetID(netid)
		if err != nil {
			return fmt.Errorf("Error while releasing Net ID: %v", err)
		} else {
			log.Infof("Released netid %d for namespace %q", netid, namespaceName)
		}
	}
	return nil
}

func watchNamespaces(oc *OsdnController) {
	nsevent := make(chan *NamespaceEvent)
	go oc.Registry.WatchNamespaces(nsevent)
	for {
		ev := <-nsevent
		switch ev.Type {
		case Added:
			err := oc.assignVNID(ev.Namespace.Name)
			if err != nil {
				log.Errorf("Error assigning Net ID: %v", err)
				continue
			}
		case Deleted:
			err := oc.revokeVNID(ev.Namespace.Name)
			if err != nil {
				log.Errorf("Error revoking Net ID: %v", err)
				continue
			}
		}
	}
}

func (oc *OsdnController) VnidStartNode() error {
	// Populate vnid map synchronously so that existing services can fetch vnid
	err := populateVNIDMap(oc)
	if err != nil {
		return err
	}

	// Populate pod info map synchronously so that kube proxy can filter endpoints to support isolation
	err = oc.Registry.PopulatePodsByIP()
	if err != nil {
		return err
	}

	go watchNetNamespaces(oc)
	go watchPods(oc)
	go watchServices(oc)

	return nil
}

func (oc *OsdnController) updatePodNetwork(namespace string, netID uint) error {
	// Update OF rules for the existing/old pods in the namespace
	pods, err := oc.GetLocalPods(namespace)
	if err != nil {
		return err
	}
	for _, pod := range pods {
		err := oc.pluginHooks.UpdatePod(pod.Namespace, pod.Name, kubetypes.DockerID(GetPodContainerID(&pod)))
		if err != nil {
			return err
		}
	}

	// Update OF rules for the old services in the namespace
	services, err := oc.Registry.GetServicesForNamespace(namespace)
	if err != nil {
		return err
	}
	for _, svc := range services {
		oc.pluginHooks.DeleteServiceRules(&svc)
		oc.pluginHooks.AddServiceRules(&svc, netID)
	}
	return nil
}

func watchNetNamespaces(oc *OsdnController) {
	netNsEvent := make(chan *NetNamespaceEvent)
	go oc.Registry.WatchNetNamespaces(netNsEvent)
	for {
		ev := <-netNsEvent
		switch ev.Type {
		case Added:
			// Skip this event if the old and new network ids are same
			if oldNetID, ok := oc.VNIDMap[ev.NetNamespace.NetName]; ok && (oldNetID == ev.NetNamespace.NetID) {
				continue
			}
			oc.VNIDMap[ev.NetNamespace.Name] = ev.NetNamespace.NetID
			err := oc.updatePodNetwork(ev.NetNamespace.NetName, ev.NetNamespace.NetID)
			if err != nil {
				log.Errorf("Failed to update pod network for namespace '%s', error: %s", ev.NetNamespace.NetName, err)
			}
		case Deleted:
			err := oc.updatePodNetwork(ev.NetNamespace.NetName, AdminVNID)
			if err != nil {
				log.Errorf("Failed to update pod network for namespace '%s', error: %s", ev.NetNamespace.NetName, err)
			}
			delete(oc.VNIDMap, ev.NetNamespace.NetName)
		}
	}
}

func isServiceChanged(oldsvc, newsvc *kapi.Service) bool {
	if len(oldsvc.Spec.Ports) == len(newsvc.Spec.Ports) {
		for i := range oldsvc.Spec.Ports {
			if oldsvc.Spec.Ports[i].Protocol != newsvc.Spec.Ports[i].Protocol ||
				oldsvc.Spec.Ports[i].Port != newsvc.Spec.Ports[i].Port {
				return true
			}
		}
		return false
	}
	return true
}

func watchServices(oc *OsdnController) {
	svcevent := make(chan *ServiceEvent)
	services := make(map[string]*kapi.Service)
	go oc.Registry.WatchServices(svcevent)

	for {
		ev := <-svcevent
		switch ev.Type {
		case Added:
			netid, found := oc.VNIDMap[ev.Service.Namespace]
			if !found {
				log.Errorf("Error fetching Net ID for namespace: %s, skipped serviceEvent: %v", ev.Service.Namespace, ev)
				continue
			}

			oldsvc, exists := services[string(ev.Service.UID)]
			if exists {
				if !isServiceChanged(oldsvc, ev.Service) {
					continue
				}
				oc.pluginHooks.DeleteServiceRules(oldsvc)
			}
			services[string(ev.Service.UID)] = ev.Service
			oc.pluginHooks.AddServiceRules(ev.Service, netid)
		case Deleted:
			delete(services, string(ev.Service.UID))
			oc.pluginHooks.DeleteServiceRules(ev.Service)
		}
	}
}

func watchPods(oc *OsdnController) {
	oc.Registry.WatchPods()
}
<commit_msg>Fix updating VNID map<commit_after>package osdn

import (
	"fmt"

	log "github.com/golang/glog"

	"github.com/openshift/openshift-sdn/pkg/netutils"

	kapi "k8s.io/kubernetes/pkg/api"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/container"
)

const (
	// Maximum VXLAN Network Identifier as per RFC#7348
	MaxVNID = ((1 << 24) - 1)
	// VNID for the admin namespaces
	AdminVNID = uint(0)
)

func populateVNIDMap(oc *OsdnController) error {
	nets, err := oc.Registry.GetNetNamespaces()
	if err != nil {
		return err
	}

	for _, net := range nets {
		oc.VNIDMap[net.Name] = net.NetID
	}
	return nil
}

func (oc *OsdnController) VnidStartMaster() error {
	err := populateVNIDMap(oc)
	if err != nil {
		return err
	}

	inUse := make([]uint, 0)
	for _, netid := range oc.VNIDMap {
		if netid != AdminVNID {
			inUse = append(inUse, netid)
		}
	}
	// VNID: 0 reserved for default namespace and can reach any network in the cluster
	// VNID: 1 to 9 are internally reserved for any special cases in the future
	oc.netIDManager, err = netutils.NewNetIDAllocator(10, MaxVNID, inUse)
	if err != nil {
		return err
	}

	// 'default' namespace is currently always an admin namespace
	oc.adminNamespaces = append(oc.adminNamespaces, "default")

	go watchNamespaces(oc)
	return nil
}

func (oc *OsdnController) isAdminNamespace(nsName string) bool {
	for _, name := range oc.adminNamespaces {
		if name == nsName {
			return true
		}
	}
	return false
}

func (oc *OsdnController) assignVNID(namespaceName string) error {
	// Nothing to do if the netid is in the VNIDMap
	if _, ok := oc.VNIDMap[namespaceName]; ok {
		return nil
	}

	// If NetNamespace is present, update VNIDMap
	netns, err := oc.Registry.GetNetNamespace(namespaceName)
	if err == nil {
		oc.VNIDMap[namespaceName] = netns.NetID
		return nil
	}

	// NetNamespace not found, so allocate new NetID
	var netid uint
	if oc.isAdminNamespace(namespaceName) {
		netid = AdminVNID
	} else {
		var err error
		netid, err = oc.netIDManager.GetNetID()
		if err != nil {
			return err
		}
	}

	// Create NetNamespace Object and update VNIDMap
	err = oc.Registry.WriteNetNamespace(namespaceName, netid)
	if err != nil {
		e := oc.netIDManager.ReleaseNetID(netid)
		if e != nil {
			log.Errorf("Error while releasing Net ID: %v", e)
		}
		return err
	}
	oc.VNIDMap[namespaceName] = netid
	log.Infof("Assigned id %d to namespace %q", netid, namespaceName)
	return nil
}

func (oc *OsdnController) revokeVNID(namespaceName string) error {
	err := oc.Registry.DeleteNetNamespace(namespaceName)
	if err != nil {
		return err
	}
	netid, found := oc.VNIDMap[namespaceName]
	if !found {
		return fmt.Errorf("Error while fetching Net ID for namespace: %s", namespaceName)
	}
	delete(oc.VNIDMap, namespaceName)

	// Skip AdminVNID as it is not part of Net ID allocation
	if netid == AdminVNID {
		return nil
	}

	// Check if this netid is used by any other namespaces
	// If not, then release the netid
	netid_inuse := false
	for name, id := range oc.VNIDMap {
		if id == netid {
			netid_inuse = true
			log.V(5).Infof("Net ID %d for namespace %q is still in use by namespace %q", netid, namespaceName, name)
			break
		}
	}
	if !netid_inuse {
		err = oc.netIDManager.ReleaseNetID(netid)
		if err != nil {
			return fmt.Errorf("Error while releasing Net ID: %v", err)
		} else {
			log.Infof("Released netid %d for namespace %q", netid, namespaceName)
		}
	}
	return nil
}

func watchNamespaces(oc *OsdnController) {
	nsevent := make(chan *NamespaceEvent)
	go oc.Registry.WatchNamespaces(nsevent)
	for {
		ev := <-nsevent
		switch ev.Type {
		case Added:
			err := oc.assignVNID(ev.Namespace.Name)
			if err != nil {
				log.Errorf("Error assigning Net ID: %v", err)
				continue
			}
		case Deleted:
			err := oc.revokeVNID(ev.Namespace.Name)
			if err != nil {
				log.Errorf("Error revoking Net ID: %v", err)
				continue
			}
		}
	}
}

func (oc *OsdnController) VnidStartNode() error {
	// Populate vnid map synchronously so that existing services can fetch vnid
	err := populateVNIDMap(oc)
	if err != nil {
		return err
	}

	// Populate pod info map synchronously so that kube proxy can filter endpoints to support isolation
	err = oc.Registry.PopulatePodsByIP()
	if err != nil {
		return err
	}

	go watchNetNamespaces(oc)
	go watchPods(oc)
	go watchServices(oc)

	return nil
}

func (oc *OsdnController) updatePodNetwork(namespace string, netID uint) error {
	// Update OF rules for the existing/old pods in the namespace
	pods, err := oc.GetLocalPods(namespace)
	if err != nil {
		return err
	}
	for _, pod := range pods {
		err := oc.pluginHooks.UpdatePod(pod.Namespace, pod.Name, kubetypes.DockerID(GetPodContainerID(&pod)))
		if err != nil {
			return err
		}
	}

	// Update OF rules for the old services in the namespace
	services, err := oc.Registry.GetServicesForNamespace(namespace)
	if err != nil {
		return err
	}
	for _, svc := range services {
		oc.pluginHooks.DeleteServiceRules(&svc)
		oc.pluginHooks.AddServiceRules(&svc, netID)
	}
	return nil
}

func watchNetNamespaces(oc *OsdnController) {
	netNsEvent := make(chan *NetNamespaceEvent)
	go oc.Registry.WatchNetNamespaces(netNsEvent)
	for {
		ev := <-netNsEvent
		switch ev.Type {
		case Added:
			// Skip this event if the old and new network ids are same
			if oldNetID, ok := oc.VNIDMap[ev.NetNamespace.NetName]; ok && (oldNetID == ev.NetNamespace.NetID) {
				continue
			}
			oc.VNIDMap[ev.NetNamespace.Name] = ev.NetNamespace.NetID
			err := oc.updatePodNetwork(ev.NetNamespace.NetName, ev.NetNamespace.NetID)
			if err != nil {
				log.Errorf("Failed to update pod network for namespace '%s', error: %s", ev.NetNamespace.NetName, err)
			}
		case Deleted:
			err := oc.updatePodNetwork(ev.NetNamespace.NetName, AdminVNID)
			if err != nil {
				log.Errorf("Failed to update pod network for namespace '%s', error: %s", ev.NetNamespace.NetName, err)
			}
			delete(oc.VNIDMap, ev.NetNamespace.NetName)
		}
	}
}

func isServiceChanged(oldsvc, newsvc *kapi.Service) bool {
	if len(oldsvc.Spec.Ports) == len(newsvc.Spec.Ports) {
		for i := range oldsvc.Spec.Ports {
			if oldsvc.Spec.Ports[i].Protocol != newsvc.Spec.Ports[i].Protocol ||
				oldsvc.Spec.Ports[i].Port != newsvc.Spec.Ports[i].Port {
				return true
			}
		}
		return false
	}
	return true
}

func watchServices(oc *OsdnController) {
	svcevent := make(chan *ServiceEvent)
	services := make(map[string]*kapi.Service)
	go oc.Registry.WatchServices(svcevent)

	for {
		ev := <-svcevent
		switch ev.Type {
		case Added:
			netid, found := oc.VNIDMap[ev.Service.Namespace]
			if !found {
				log.Errorf("Error fetching Net ID for namespace: %s, skipped serviceEvent: %v", ev.Service.Namespace, ev)
				continue
			}

			oldsvc, exists := services[string(ev.Service.UID)]
			if exists {
				if !isServiceChanged(oldsvc, ev.Service) {
					continue
				}
				oc.pluginHooks.DeleteServiceRules(oldsvc)
			}
			services[string(ev.Service.UID)] = ev.Service
			oc.pluginHooks.AddServiceRules(ev.Service, netid)
		case Deleted:
			delete(services, string(ev.Service.UID))
			oc.pluginHooks.DeleteServiceRules(ev.Service)
		}
	}
}

func watchPods(oc *OsdnController) {
	oc.Registry.WatchPods()
}
<|endoftext|>


<commit_before>package uno

import (
	"errors"
	"strings"

	"github.com/belak/go-seabird"
	"github.com/belak/go-seabird/plugins"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("uno", newUnoPlugin)
}

type unoPlugin struct {
	games   map[string]*Game
	tracker *plugins.ChannelTracker
}

func newUnoPlugin(cm *seabird.CommandMux, tracker *plugins.ChannelTracker) {
	p := &unoPlugin{
		games:   make(map[string]*Game),
		tracker: tracker,
	}

	// TODO: Track channel parts

	cm.Channel("uno", p.unoCallback, &seabird.HelpInfo{
		Usage:       "[create|join|start|stop]",
		Description: "Flow control and stuff",
	})

	cm.Channel("hand", p.handCallback, &seabird.HelpInfo{
		Usage:       "hand",
		Description: "Messages you your hand in an UNO game",
	})

	cm.Channel("play", p.playCallback, &seabird.HelpInfo{
		Usage:       "play <hand_index>",
		Description: "Plays card from your hand at <hand_index> and ends your turn",
	})

	cm.Channel("draw", p.drawCallback, &seabird.HelpInfo{
		Usage:       "draw",
		Description: "Draws a card and possibly ends your turn",
	})

	cm.Channel("draw_play", p.drawPlayCallback, &seabird.HelpInfo{
		Usage:       "draw_play [yes|no]",
		Description: "Used after a call to <prefix>draw to possibly play a card",
	})

	cm.Channel("color", p.colorCallback, &seabird.HelpInfo{
		Usage:       "color red|yellow|green|blue",
		Description: "Selects next color to play",
	})

	cm.Channel("uno_state", p.stateCallback, &seabird.HelpInfo{
		Usage: "uno_state",
		Description: "Return the top card and current player.",
	})
}

func (p *unoPlugin) lookupDataRaw(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game) {
	user := p.tracker.LookupUser(m.Prefix.Name)
	game := p.games[m.Params[0]]

	return user, game
}

func (p *unoPlugin) lookupData(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game, error) {
	user, game := p.lookupDataRaw(b, m)

	if user == nil {
		return user, game, errors.New("Couldn't find user")
	}

	if game == nil {
		return user, game, errors.New("No game in this channel")
	}

	return user, game, nil
}

// sendMessages is an abstraction around sending the uno Message
// type. This simplifies the translation between that and IRC.
func (p *unoPlugin) sendMessages(b *seabird.Bot, m *irc.Message, uMsgs []*Message) {
	for _, uMsg := range uMsgs {
		if uMsg.Target == nil {
			b.Reply(m, "%s", uMsg.Message)
		} else if uMsg.Private {
			b.Send(&irc.Message{
				Command: "PRIVMSG",
				Params: []string{
					uMsg.Target.Nick,
					uMsg.Message,
				},
			})
		} else {
			b.Reply(m, "%s: %s", uMsg.Target.Nick, uMsg.Message)
		}
	}
}

func (p *unoPlugin) stateCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game == nil {
		b.MentionReply(m, "There's no game in this channel")
		return
	}

	b.MentionReply(m, "Current Player: %s", game.currentPlayer().User.Nick)
	b.MentionReply(m, "Top Card: %s", game.lastPlayed())
}

func (p *unoPlugin) unoCallback(b *seabird.Bot, m *irc.Message) {
	trailing := strings.TrimSpace(m.Trailing())

	if len(trailing) == 0 {
		p.rawUnoCallback(b, m)
		return
	}

	switch trailing {
	case "create":
		p.createCallback(b, m)
	case "join":
		p.joinCallback(b, m)
	case "start":
		p.startCallback(b, m)
	case "stop":
		p.stopCallback(b, m)
	default:
		b.MentionReply(m, "Usage: <prefix>uno [create|join|start|stop]")
	}
}

func (p *unoPlugin) rawUnoCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SayUno(user))
}

func (p *unoPlugin) createCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game != nil {
		b.MentionReply(m, "There's already a game in this channel")
		return
	}

	// Create a new game, add the current user and store it.
	game, messages := NewGame(user)
	p.sendMessages(b, m, messages)
	p.games[m.Params[0]] = game
}

func (p *unoPlugin) joinCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.AddPlayer(user))
}

func (p *unoPlugin) startCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Start(user))
}

func (p *unoPlugin) stopCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, ok := game.Stop(user)

	p.sendMessages(b, m, messages)

	if ok {
		delete(p.games, m.Params[0])
	}
}

func (p *unoPlugin) handCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.GetHand(user))
}

func (p *unoPlugin) playCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, done := game.Play(user, m.Trailing())
	if done {
		delete(p.games, m.Params[0])
	}

	p.sendMessages(b, m, messages)
}

func (p *unoPlugin) drawCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Draw(user))
}

func (p *unoPlugin) drawPlayCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.DrawPlay(user, m.Trailing()))
}

func (p *unoPlugin) colorCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SetColor(user, m.Trailing()))
}
<commit_msg>uno: add another TODO<commit_after>package uno

import (
	"errors"
	"strings"

	"github.com/belak/go-seabird"
	"github.com/belak/go-seabird/plugins"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("uno", newUnoPlugin)
}

type unoPlugin struct {
	games   map[string]*Game
	tracker *plugins.ChannelTracker
}

func newUnoPlugin(cm *seabird.CommandMux, tracker *plugins.ChannelTracker) {
	p := &unoPlugin{
		games:   make(map[string]*Game),
		tracker: tracker,
	}

	// TODO: Track channel parts

	cm.Channel("uno", p.unoCallback, &seabird.HelpInfo{
		Usage:       "[create|join|start|stop]",
		Description: "Flow control and stuff",
	})

	cm.Channel("hand", p.handCallback, &seabird.HelpInfo{
		Usage:       "hand",
		Description: "Messages you your hand in an UNO game",
	})

	cm.Channel("play", p.playCallback, &seabird.HelpInfo{
		Usage:       "play <hand_index>",
		Description: "Plays card from your hand at <hand_index> and ends your turn",
	})

	cm.Channel("draw", p.drawCallback, &seabird.HelpInfo{
		Usage:       "draw",
		Description: "Draws a card and possibly ends your turn",
	})

	cm.Channel("draw_play", p.drawPlayCallback, &seabird.HelpInfo{
		Usage:       "draw_play [yes|no]",
		Description: "Used after a call to <prefix>draw to possibly play a card",
	})

	cm.Channel("color", p.colorCallback, &seabird.HelpInfo{
		Usage:       "color red|yellow|green|blue",
		Description: "Selects next color to play",
	})

	cm.Channel("uno_state", p.stateCallback, &seabird.HelpInfo{
		Usage: "uno_state",
		Description: "Return the top card and current player.",
	})
}

func (p *unoPlugin) lookupDataRaw(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game) {
	user := p.tracker.LookupUser(m.Prefix.Name)
	game := p.games[m.Params[0]]

	return user, game
}

func (p *unoPlugin) lookupData(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game, error) {
	user, game := p.lookupDataRaw(b, m)

	if user == nil {
		return user, game, errors.New("Couldn't find user")
	}

	if game == nil {
		return user, game, errors.New("No game in this channel")
	}

	return user, game, nil
}

// sendMessages is an abstraction around sending the uno Message
// type. This simplifies the translation between that and IRC.
func (p *unoPlugin) sendMessages(b *seabird.Bot, m *irc.Message, uMsgs []*Message) {
	for _, uMsg := range uMsgs {
		if uMsg.Target == nil {
			b.Reply(m, "%s", uMsg.Message)
		} else if uMsg.Private {
			b.Send(&irc.Message{
				Command: "PRIVMSG",
				Params: []string{
					uMsg.Target.Nick,
					uMsg.Message,
				},
			})
		} else {
			b.Reply(m, "%s: %s", uMsg.Target.Nick, uMsg.Message)
		}
	}
}

func (p *unoPlugin) stateCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game == nil {
		b.MentionReply(m, "There's no game in this channel")
		return
	}

	// TODO: This should pull from some State struct or similar from
	// the Game
	b.MentionReply(m, "Current Player: %s", game.currentPlayer().User.Nick)
	b.MentionReply(m, "Top Card: %s", game.lastPlayed())
}

func (p *unoPlugin) unoCallback(b *seabird.Bot, m *irc.Message) {
	trailing := strings.TrimSpace(m.Trailing())

	if len(trailing) == 0 {
		p.rawUnoCallback(b, m)
		return
	}

	switch trailing {
	case "create":
		p.createCallback(b, m)
	case "join":
		p.joinCallback(b, m)
	case "start":
		p.startCallback(b, m)
	case "stop":
		p.stopCallback(b, m)
	default:
		b.MentionReply(m, "Usage: <prefix>uno [create|join|start|stop]")
	}
}

func (p *unoPlugin) rawUnoCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SayUno(user))
}

func (p *unoPlugin) createCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game != nil {
		b.MentionReply(m, "There's already a game in this channel")
		return
	}

	// Create a new game, add the current user and store it.
	game, messages := NewGame(user)
	p.sendMessages(b, m, messages)
	p.games[m.Params[0]] = game
}

func (p *unoPlugin) joinCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.AddPlayer(user))
}

func (p *unoPlugin) startCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Start(user))
}

func (p *unoPlugin) stopCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, ok := game.Stop(user)

	p.sendMessages(b, m, messages)

	if ok {
		delete(p.games, m.Params[0])
	}
}

func (p *unoPlugin) handCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.GetHand(user))
}

func (p *unoPlugin) playCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, done := game.Play(user, m.Trailing())
	if done {
		delete(p.games, m.Params[0])
	}

	p.sendMessages(b, m, messages)
}

func (p *unoPlugin) drawCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Draw(user))
}

func (p *unoPlugin) drawPlayCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.DrawPlay(user, m.Trailing()))
}

func (p *unoPlugin) colorCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SetColor(user, m.Trailing()))
}
<|endoftext|>


<commit_before>package buffalo

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"strings"
	"sync"
	"syscall"

	"github.com/sirupsen/logrus"

	"github.com/gobuffalo/envy"
	"github.com/gorilla/mux"
	"github.com/markbates/going/defaults"
	"github.com/markbates/refresh/refresh/web"
	"github.com/markbates/sigtx"
	"github.com/pkg/errors"
)

// App is where it all happens! It holds on to options,
// the underlying router, the middleware, and more.
// Without an App you can't do much!
type App struct {
	Options
	// Middleware returns the current MiddlewareStack for the App/Group.
	Middleware    *MiddlewareStack
	ErrorHandlers ErrorHandlers
	router        *mux.Router
	moot          *sync.Mutex
	routes        RouteList
	root          *App
	children      []*App
}

// Start is deprecated, and will be removed in v0.11.0. Use app.Serve instead.
func (a *App) Start(port string) error {
	warningMsg := "Start is deprecated, and will be removed in v0.11.0. Use app.Serve instead."
	_, file, no, ok := runtime.Caller(1)
	if ok {
		warningMsg = fmt.Sprintf("%s Called from %s:%d", warningMsg, file, no)
	}

	logrus.Info(warningMsg)

	a.Addr = defaults.String(a.Addr, fmt.Sprintf("%s:%s", envy.Get("ADDR", "127.0.0.1"), port))
	return a.Serve()
}

// Serve the application at the specified address/port and listen for OS
// interrupt and kill signals and will attempt to stop the application
// gracefully. This will also start the Worker process, unless WorkerOff is enabled.
func (a *App) Serve() error {
	logrus.Infof("Starting application at %s", a.Options.Addr)
	server := http.Server{
		Handler: a,
	}
	ctx, cancel := sigtx.WithCancel(a.Context, syscall.SIGTERM, os.Interrupt)
	defer cancel()

	go func() {
		// gracefully shut down the application when the context is cancelled
		<-ctx.Done()
		logrus.Info("Shutting down application")

		err := a.Stop(ctx.Err())
		if err != nil {
			logrus.Error(err)
		}

		if !a.WorkerOff {
			// stop the workers
			logrus.Info("Shutting down worker")
			err = a.Worker.Stop()
			if err != nil {
				logrus.Error(err)
			}
		}

		err = server.Shutdown(ctx)
		if err != nil {
			logrus.Error(err)
		}

	}()

	// if configured to do so, start the workers
	if !a.WorkerOff {
		go func() {
			err := a.Worker.Start(ctx)
			if err != nil {
				a.Stop(err)
			}
		}()
	}

	var err error

	if strings.HasPrefix(a.Options.Addr, "unix:") {
		// Use an UNIX socket
		listener, err := net.Listen("unix", a.Options.Addr[5:])
		if err != nil {
			return a.Stop(err)
		}
		// start the web server
		err = server.Serve(listener)
	} else {
		// Use a TCP socket
		server.Addr = a.Options.Addr

		// start the web server
		err = server.ListenAndServe()
	}

	if err != nil {
		return a.Stop(err)
	}

	return nil
}

// Stop the application and attempt to gracefully shutdown
func (a *App) Stop(err error) error {
	a.cancel()
	if err != nil && errors.Cause(err) != context.Canceled {
		logrus.Error(err)
		return err
	}
	return nil
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ws := &Response{
		ResponseWriter: w,
	}
	if a.MethodOverride != nil {
		a.MethodOverride(w, r)
	}
	if ok := a.processPreHandlers(ws, r); !ok {
		return
	}

	var h http.Handler
	h = a.router
	if a.Env == "development" {
		h = web.ErrorChecker(h)
	}
	h.ServeHTTP(ws, r)
}

// New returns a new instance of App and adds some sane, and useful, defaults.
func New(opts Options) *App {
	envy.Load()
	opts = optionsWithDefaults(opts)

	a := &App{
		Options:    opts,
		Middleware: newMiddlewareStack(),
		ErrorHandlers: ErrorHandlers{
			404: defaultErrorHandler,
			500: defaultErrorHandler,
		},
		router:   mux.NewRouter().StrictSlash(!opts.LooseSlash),
		moot:     &sync.Mutex{},
		routes:   RouteList{},
		children: []*App{},
	}
	a.router.NotFoundHandler = http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		c := a.newContext(RouteInfo{}, res, req)
		err := errors.Errorf("path not found: %s", req.URL.Path)
		a.ErrorHandlers.Get(404)(404, err, c)
	})

	if a.MethodOverride == nil {
		a.MethodOverride = MethodOverride
	}
	a.Use(a.PanicHandler)
	a.Use(RequestLogger)
	a.Use(sessionSaver)

	return a
}

func (a *App) processPreHandlers(res http.ResponseWriter, req *http.Request) bool {
	sh := func(h http.Handler) bool {
		h.ServeHTTP(res, req)
		if br, ok := res.(*Response); ok {
			if br.Status > 0 || br.Size > 0 {
				return false
			}
		}
		return true
	}

	for _, ph := range a.PreHandlers {
		if ok := sh(ph); !ok {
			return false
		}
	}

	last := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {}))
	for _, ph := range a.PreWares {
		last = ph(last)
		if ok := sh(last); !ok {
			return false
		}
	}
	return true
}
<commit_msg>removed deprecations<commit_after>package buffalo

import (
	"context"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"syscall"

	"github.com/sirupsen/logrus"

	"github.com/gobuffalo/envy"
	"github.com/gorilla/mux"
	"github.com/markbates/refresh/refresh/web"
	"github.com/markbates/sigtx"
	"github.com/pkg/errors"
)

// App is where it all happens! It holds on to options,
// the underlying router, the middleware, and more.
// Without an App you can't do much!
type App struct {
	Options
	// Middleware returns the current MiddlewareStack for the App/Group.
	Middleware    *MiddlewareStack
	ErrorHandlers ErrorHandlers
	router        *mux.Router
	moot          *sync.Mutex
	routes        RouteList
	root          *App
	children      []*App
}

// Serve the application at the specified address/port and listen for OS
// interrupt and kill signals and will attempt to stop the application
// gracefully. This will also start the Worker process, unless WorkerOff is enabled.
func (a *App) Serve() error {
	logrus.Infof("Starting application at %s", a.Options.Addr)
	server := http.Server{
		Handler: a,
	}
	ctx, cancel := sigtx.WithCancel(a.Context, syscall.SIGTERM, os.Interrupt)
	defer cancel()

	go func() {
		// gracefully shut down the application when the context is cancelled
		<-ctx.Done()
		logrus.Info("Shutting down application")

		err := a.Stop(ctx.Err())
		if err != nil {
			logrus.Error(err)
		}

		if !a.WorkerOff {
			// stop the workers
			logrus.Info("Shutting down worker")
			err = a.Worker.Stop()
			if err != nil {
				logrus.Error(err)
			}
		}

		err = server.Shutdown(ctx)
		if err != nil {
			logrus.Error(err)
		}

	}()

	// if configured to do so, start the workers
	if !a.WorkerOff {
		go func() {
			err := a.Worker.Start(ctx)
			if err != nil {
				a.Stop(err)
			}
		}()
	}

	var err error

	if strings.HasPrefix(a.Options.Addr, "unix:") {
		// Use an UNIX socket
		listener, err := net.Listen("unix", a.Options.Addr[5:])
		if err != nil {
			return a.Stop(err)
		}
		// start the web server
		err = server.Serve(listener)
	} else {
		// Use a TCP socket
		server.Addr = a.Options.Addr

		// start the web server
		err = server.ListenAndServe()
	}

	if err != nil {
		return a.Stop(err)
	}

	return nil
}

// Stop the application and attempt to gracefully shutdown
func (a *App) Stop(err error) error {
	a.cancel()
	if err != nil && errors.Cause(err) != context.Canceled {
		logrus.Error(err)
		return err
	}
	return nil
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ws := &Response{
		ResponseWriter: w,
	}
	if a.MethodOverride != nil {
		a.MethodOverride(w, r)
	}
	if ok := a.processPreHandlers(ws, r); !ok {
		return
	}

	var h http.Handler
	h = a.router
	if a.Env == "development" {
		h = web.ErrorChecker(h)
	}
	h.ServeHTTP(ws, r)
}

// New returns a new instance of App and adds some sane, and useful, defaults.
func New(opts Options) *App {
	envy.Load()
	opts = optionsWithDefaults(opts)

	a := &App{
		Options:    opts,
		Middleware: newMiddlewareStack(),
		ErrorHandlers: ErrorHandlers{
			404: defaultErrorHandler,
			500: defaultErrorHandler,
		},
		router:   mux.NewRouter().StrictSlash(!opts.LooseSlash),
		moot:     &sync.Mutex{},
		routes:   RouteList{},
		children: []*App{},
	}
	a.router.NotFoundHandler = http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		c := a.newContext(RouteInfo{}, res, req)
		err := errors.Errorf("path not found: %s", req.URL.Path)
		a.ErrorHandlers.Get(404)(404, err, c)
	})

	if a.MethodOverride == nil {
		a.MethodOverride = MethodOverride
	}
	a.Use(a.PanicHandler)
	a.Use(RequestLogger)
	a.Use(sessionSaver)

	return a
}

func (a *App) processPreHandlers(res http.ResponseWriter, req *http.Request) bool {
	sh := func(h http.Handler) bool {
		h.ServeHTTP(res, req)
		if br, ok := res.(*Response); ok {
			if br.Status > 0 || br.Size > 0 {
				return false
			}
		}
		return true
	}

	for _, ph := range a.PreHandlers {
		if ok := sh(ph); !ok {
			return false
		}
	}

	last := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {}))
	for _, ph := range a.PreWares {
		last = ph(last)
		if ok := sh(last); !ok {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Package app provides a full featured framework for any web app.
package app

import (
	"context"
	"flag"
	"github.com/gowww/compress"
	"github.com/gowww/fatal"
	"github.com/gowww/i18n"
	gowwwlog "github.com/gowww/log"
	"github.com/gowww/router"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
)

var (
	address      = flag.String("a", ":8080", "the address to listen and serving on")
	production   = flag.Bool("p", false, "run the server in production environment")
	rt           = router.New()
	errorHandler Handler
)

func init() {
	flag.Parse()

	// Serve static content
	rt.Get("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// Parse views
	files, _ := ioutil.ReadDir("views")
	for _, f := range files {
		if !f.IsDir() && filepath.Ext(f.Name()) == ".gohtml" {
			parseViews()
			return
		}
	}
}

// A Handler handles a request.
type Handler func(*Context)

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(&Context{w, r})
}

// A Middleware is a handler that wraps another one.
type Middleware func(http.Handler) http.Handler

// wrapHandler returns handler h wrapped with middlewares mm.
func wrapHandler(h http.Handler, mm ...Middleware) http.Handler {
	for i := len(mm) - 1; i >= 0; i-- {
		h = mm[i](h)
	}
	return h
}

// Route makes a route for method and path.
func Route(method, path string, handler Handler, middlewares ...Middleware) {
	rt.Handle(method, path, wrapHandler(handler, middlewares...))
}

// Get makes a route for GET method.
func Get(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodGet, path, handler, middlewares...)
}

// Post makes a route for POST method.
func Post(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPost, path, handler, middlewares...)
}

// Put makes a route for PUT method.
func Put(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPut, path, handler, middlewares...)
}

// Patch makes a route for PATCH method.
func Patch(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPatch, path, handler, middlewares...)
}

// Delete makes a route for DELETE method.
func Delete(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodDelete, path, handler, middlewares...)
}

// NotFound registers the "not found" handler.
func NotFound(handler Handler) {
	if rt.NotFoundHandler != nil {
		panic(`app: "not found" handler set multiple times`)
	}
	rt.NotFoundHandler = handler
}

// Error registers the "internal error" handler.
func Error(handler Handler) {
	if rt.NotFoundHandler != nil {
		panic(`app: "internal error" handler set multiple times`)
	}
	errorHandler = handler
}

// EnvProduction tells if the app is run with the production flag.
func EnvProduction() bool {
	return *production
}

// Address gives the address on which the app is running.
func Address() string {
	return *address
}

// Run starts the server.
func Run(mm ...Middleware) {
	handler := wrapHandler(rt, mm...)
	handler = contextHandle(handler)
	if confI18n != nil {
		ll := make(i18n.Locales)
		for lang, trans := range confI18n.Locales {
			ll[lang] = i18n.Translations(trans)
		}
		var pp []i18n.Parser
		for _, parser := range confI18n.Parsers {
			pp = append(pp, i18n.Parser(parser))
		}
		handler = i18n.Handle(handler, ll, confI18n.Fallback, pp...)
	}

	if errorHandler != nil {
		handler = fatal.Handle(handler, &fatal.Options{RecoverHandler: errorHandler})
	} else {
		handler = fatal.Handle(handler, &fatal.Options{RecoverHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		})})
	}
	handler = compress.Handle(handler)
	if !*production {
		handler = gowwwlog.Handle(handler, &gowwwlog.Options{Color: true})
	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	srv := &http.Server{Addr: *address, Handler: handler}
	go func() {
		<-quit
		log.Print("Shutting down...")
		if err := srv.Shutdown(context.Background()); err != nil {
			log.Fatalf("Could not shutdown: %v", err)
		}
	}()
	log.Printf("Running on %v", *address)
	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		log.Fatal(err)
	}
	log.Println("Gracefully shutted down")
}
<commit_msg>Fix Error<commit_after>// Package app provides a full featured framework for any web app.
package app

import (
	"context"
	"flag"
	"github.com/gowww/compress"
	"github.com/gowww/fatal"
	"github.com/gowww/i18n"
	gowwwlog "github.com/gowww/log"
	"github.com/gowww/router"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
)

var (
	address      = flag.String("a", ":8080", "the address to listen and serving on")
	production   = flag.Bool("p", false, "run the server in production environment")
	rt           = router.New()
	errorHandler Handler
)

func init() {
	flag.Parse()

	// Serve static content
	rt.Get("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// Parse views
	files, _ := ioutil.ReadDir("views")
	for _, f := range files {
		if !f.IsDir() && filepath.Ext(f.Name()) == ".gohtml" {
			parseViews()
			return
		}
	}
}

// A Handler handles a request.
type Handler func(*Context)

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(&Context{w, r})
}

// A Middleware is a handler that wraps another one.
type Middleware func(http.Handler) http.Handler

// wrapHandler returns handler h wrapped with middlewares mm.
func wrapHandler(h http.Handler, mm ...Middleware) http.Handler {
	for i := len(mm) - 1; i >= 0; i-- {
		h = mm[i](h)
	}
	return h
}

// Route makes a route for method and path.
func Route(method, path string, handler Handler, middlewares ...Middleware) {
	rt.Handle(method, path, wrapHandler(handler, middlewares...))
}

// Get makes a route for GET method.
func Get(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodGet, path, handler, middlewares...)
}

// Post makes a route for POST method.
func Post(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPost, path, handler, middlewares...)
}

// Put makes a route for PUT method.
func Put(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPut, path, handler, middlewares...)
}

// Patch makes a route for PATCH method.
func Patch(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodPatch, path, handler, middlewares...)
}

// Delete makes a route for DELETE method.
func Delete(path string, handler Handler, middlewares ...Middleware) {
	Route(http.MethodDelete, path, handler, middlewares...)
}

// NotFound registers the "not found" handler.
func NotFound(handler Handler) {
	if rt.NotFoundHandler != nil {
		panic(`app: "not found" handler set multiple times`)
	}
	rt.NotFoundHandler = handler
}

// Error registers the "internal error" handler.
func Error(handler Handler) {
	if errorHandler != nil {
		panic(`app: "internal error" handler set multiple times`)
	}
	errorHandler = handler
}

// EnvProduction tells if the app is run with the production flag.
func EnvProduction() bool {
	return *production
}

// Address gives the address on which the app is running.
func Address() string {
	return *address
}

// Run starts the server.
func Run(mm ...Middleware) {
	handler := wrapHandler(rt, mm...)
	handler = contextHandle(handler)
	if confI18n != nil {
		ll := make(i18n.Locales)
		for lang, trans := range confI18n.Locales {
			ll[lang] = i18n.Translations(trans)
		}
		var pp []i18n.Parser
		for _, parser := range confI18n.Parsers {
			pp = append(pp, i18n.Parser(parser))
		}
		handler = i18n.Handle(handler, ll, confI18n.Fallback, pp...)
	}

	if errorHandler != nil {
		handler = fatal.Handle(handler, &fatal.Options{RecoverHandler: errorHandler})
	} else {
		handler = fatal.Handle(handler, &fatal.Options{RecoverHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		})})
	}
	handler = compress.Handle(handler)
	if !*production {
		handler = gowwwlog.Handle(handler, &gowwwlog.Options{Color: true})
	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	srv := &http.Server{Addr: *address, Handler: handler}
	go func() {
		<-quit
		log.Print("Shutting down...")
		if err := srv.Shutdown(context.Background()); err != nil {
			log.Fatalf("Could not shutdown: %v", err)
		}
	}()
	log.Printf("Running on %v", *address)
	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		log.Fatal(err)
	}
	log.Println("Gracefully shutted down")
}
<|endoftext|>