<commit_before>// Copyright 2016 Jacob Taylor jacob.taylor@gmail.com
// License: Apache2
package main

import (
    "fmt"
    "net"
    "./utils"
    "bufio"
    "encoding/binary"
    "time"
    "os"
    "bytes"
    "io"
    "io/ioutil"
    "log"
)

const nbd_folder = "/sample_disks/"

func send_export_list_item(output *bufio.Writer, export_name string) {
    data := make([]byte, 1024)
    length := len(export_name)
    offset := 0

    // length of export name
    binary.BigEndian.PutUint32(data[offset:], uint32(length))  // length of string
    offset += 4

    // export name
    copy(data[offset:], export_name)
    offset += length

    reply_type := uint32(2)     // reply_type: NBD_REP_SERVER
    send_message(output, reply_type, uint32(offset), data)
}

func send_ack(output *bufio.Writer) {
    send_message(output, utils.NBD_COMMAND_ACK, 0, nil)
}

func export_name(output *bufio.Writer, conn net.Conn, payload_size int, payload []byte) {
    fmt.Printf("have request to bind to: %s\n", string(payload[:payload_size]))

    defer conn.Close()

    var filename bytes.Buffer
    current_directory, err := os.Getwd()
    utils.ErrorCheck(err)
    filename.WriteString(current_directory + nbd_folder)

    actual_filename := string(payload[:payload_size])

    if actual_filename == "export" {
        actual_filename = "test_fake_hdd"
    }

    filename.WriteString(actual_filename)
    fmt.Printf("Opening file: %s", filename.String())

    // attempt to open the file read only
    file, err := os.OpenFile(filename.String(), os.O_RDWR, 0644)
    utils.ErrorCheck(err)

    buffer := make([]byte, 256)
    offset := 0

    fs, err := file.Stat()
    file_size := uint64(fs.Size())

    binary.BigEndian.PutUint64(buffer[offset:], file_size)  // size
    offset += 8

    binary.BigEndian.PutUint16(buffer[offset:], 1)  // flags
    offset += 2

    data_out, err := output.Write(buffer[:offset])
    output.Flush()
    utils.ErrorCheck(err)
    fmt.Printf("Wrote %d chars: %v\n", data_out, buffer[:offset])

    buffer = make([]byte, 512*1024)
    conn_reader := bufio.NewReader(conn)
    abort := false
    for {
        offset := 0
        waiting_for := 28       // wait for at least the minimum payload size

// Duplicate
        for offset < waiting_for {
            length, err := conn_reader.Read(buffer[offset:waiting_for])
            offset += length
            utils.ErrorCheck(err)
            if err == io.EOF {
                abort = true
                break
            }
            utils.LogData("Reading instruction\n", offset, buffer)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }
// Duplicate
        if abort {
            fmt.Printf("Abort detected, escaping processing loop\n")
            break
        }

        fmt.Printf("We read the buffer %v\n", buffer[:waiting_for])

        //magic := binary.BigEndian.Uint32(buffer)
        command := binary.BigEndian.Uint32(buffer[4:8])
        handle := binary.BigEndian.Uint64(buffer[8:16])
        from := binary.BigEndian.Uint64(buffer[16:24])
        length := binary.BigEndian.Uint32(buffer[24:28])

        switch command {
        case utils.NBD_COMMAND_READ:
            fmt.Printf("We have a request to read handle: %v, from: %v, length: %v\n", handle, from, length)
            fmt.Printf("Read Resquest    Offset:%x length: %v     Handle %X\n", from, length, handle)

            data_out, err = file.ReadAt(buffer[16:16+length], int64(from))
            utils.ErrorCheck(err)

            binary.BigEndian.PutUint32(buffer[:4], utils.NBD_REPLY_MAGIC)
            binary.BigEndian.PutUint32(buffer[4:8], 0)                      // error bits

            utils.LogData("About to reply with", int(16+length), buffer)

            conn.Write(buffer[:16+length])

            continue
        case utils.NBD_COMMAND_WRITE:
            fmt.Printf("We have a request to write handle: %v, from: %v, length: %v\n", handle, from, length)

            waiting_for += int(length)                   // wait for the additional payload

// Duplicate
            for offset < waiting_for {
                length, err := conn_reader.Read(buffer[offset:waiting_for])
                offset += length
                utils.ErrorCheck(err)
                if err == io.EOF {
                    abort = true
                    break
                }
                utils.LogData("Reading write data\n", offset, buffer)
                if offset < waiting_for {
                    time.Sleep(5 * time.Millisecond)
                }
            }
// Duplicate

            data_out, err = file.WriteAt(buffer[16:16+length], int64(from))
            utils.ErrorCheck(err)
            file.Sync()

            continue
        case utils.NBD_COMMAND_DISCONNECT:
            fmt.Printf("We have received a request to disconnect\n")
            // close the file and return
            return
        }
    }
}

func send_export_list(output *bufio.Writer) {
    current_directory, err := os.Getwd()
    files, err := ioutil.ReadDir(current_directory + nbd_folder)
    if err != nil {
        log.Fatal(err)
    }
    for _, file := range files {
        send_export_list_item(output, file.Name())
    }

    send_ack(output)
}

func send_message(output *bufio.Writer, reply_type uint32, length uint32, data []byte ) {
    endian := binary.BigEndian
    buffer := make([]byte, 1024)
    offset := 0

    endian.PutUint64(buffer[offset:], utils.NBD_SERVER_SEND_REPLY_MAGIC)
    offset += 8

    endian.PutUint32(buffer[offset:], uint32(3))  // Flags (3 = supports list)
    offset += 4

    endian.PutUint32(buffer[offset:], reply_type)  // reply_type: NBD_REP_SERVER
    offset += 4

    endian.PutUint32(buffer[offset:], length)  // length of package
    offset += 4

    if data != nil {
        copy(buffer[offset:], data[0:length])
        offset += int(length)
    }

    data_to_send := buffer[:offset]
    output.Write(data_to_send)
    output.Flush()

    utils.LogData("Just sent:", offset, data_to_send)
}

func main() {

    if len(os.Args) <  3 {
        panic("missing arguments:  (ipaddress) (portnumber)")
        return
    }

    listener, err := net.Listen("tcp", os.Args[1] + ":" + os.Args[2])
    utils.ErrorCheck(err)

    fmt.Printf("Hello World, we have %v\n", listener)
    reply_magic := make([]byte, 4)
    binary.BigEndian.PutUint32(reply_magic, utils.NBD_REPLY_MAGIC)

    for {
        conn, err := listener.Accept()
        utils.ErrorCheck(err)

        fmt.Printf("We have a new connection from: %s\n", conn.RemoteAddr())
        output := bufio.NewWriter(conn)

        output.WriteString("NBDMAGIC")      // init password
        output.Flush()
        output.WriteString("IHAVEOPT")      // Magic
        output.Flush()
        output.Write([]byte{0, 3})          // Flags (3 = supports list)
        output.Flush()

        // Fetch the data until we get the initial options
        data := make([]byte, 1024)
        offset := 0
        waiting_for := 16       // wait for at least the minimum payload size

        for offset < waiting_for {
            length, err := conn.Read(data[offset:])
            offset += length
            utils.ErrorCheck(err)
            utils.LogData("Reading instruction", offset, data)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }

        // Skip the first 8 characters (options)
        command := binary.BigEndian.Uint32(data[12:])
        payload_size := int(binary.BigEndian.Uint32(data[16:]))

        fmt.Sprintf("command is: %d\npayload_size is: %d\n", command, payload_size)
        waiting_for += int(payload_size)
        for offset < waiting_for {
            length, err := conn.Read(data[offset:])
            offset += length
            utils.ErrorCheck(err)
            utils.LogData("Reading instruction", offset, data)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }
        payload := make([]byte, payload_size)

        if payload_size > 0{
            copy(payload, data[20:])
        }

        utils.LogData("Payload is:", payload_size, payload)
        fmt.Printf("command is: %v\n", command)

        // At this point, we have the command, payload size, and payload.
        switch command {
        case utils.NBD_COMMAND_LIST:
            send_export_list(output)
            conn.Close()
            break
        case utils.NBD_COMMAND_EXPORT_NAME:
            go export_name(output, conn, payload_size, payload)
            break
        }
    }

}
<commit_msg>cleaning up some print statements and fixing what data is written.<commit_after>// Copyright 2016 Jacob Taylor jacob.taylor@gmail.com
// License: Apache2
package main

import (
    "fmt"
    "net"
    "./utils"
    "bufio"
    "encoding/binary"
    "time"
    "os"
    "bytes"
    "io"
    "io/ioutil"
    "log"
)

const nbd_folder = "/sample_disks/"

func send_export_list_item(output *bufio.Writer, export_name string) {
    data := make([]byte, 1024)
    length := len(export_name)
    offset := 0

    // length of export name
    binary.BigEndian.PutUint32(data[offset:], uint32(length))  // length of string
    offset += 4

    // export name
    copy(data[offset:], export_name)
    offset += length

    reply_type := uint32(2)     // reply_type: NBD_REP_SERVER
    send_message(output, reply_type, uint32(offset), data)
}

func send_ack(output *bufio.Writer) {
    send_message(output, utils.NBD_COMMAND_ACK, 0, nil)
}

func export_name(output *bufio.Writer, conn net.Conn, payload_size int, payload []byte) {
    fmt.Printf("have request to bind to: %s\n", string(payload[:payload_size]))

    defer conn.Close()

    var filename bytes.Buffer
    current_directory, err := os.Getwd()
    utils.ErrorCheck(err)
    filename.WriteString(current_directory + nbd_folder)

    actual_filename := string(payload[:payload_size])

    if actual_filename == "export" {
        actual_filename = "test_fake_hdd"
    }

    filename.WriteString(actual_filename)
    fmt.Printf("Opening file: %s\n", filename.String())

    // attempt to open the file read only
    file, err := os.OpenFile(filename.String(), os.O_RDWR, 0644)
    utils.ErrorCheck(err)

    buffer := make([]byte, 256)
    offset := 0

    fs, err := file.Stat()
    file_size := uint64(fs.Size())

    binary.BigEndian.PutUint64(buffer[offset:], file_size)  // size
    offset += 8

    binary.BigEndian.PutUint16(buffer[offset:], 1)  // flags
    offset += 2

    data_out, err := output.Write(buffer[:offset])
    output.Flush()
    utils.ErrorCheck(err)
    fmt.Printf("Wrote %d chars: %v\n", data_out, buffer[:offset])

    buffer = make([]byte, 512*1024)
    conn_reader := bufio.NewReader(conn)
    abort := false
    for {
        offset := 0
        waiting_for := 28       // wait for at least the minimum payload size

// Duplicate
        for offset < waiting_for {
            length, err := conn_reader.Read(buffer[offset:waiting_for])
            offset += length
            utils.ErrorCheck(err)
            if err == io.EOF {
                abort = true
                break
            }
            utils.LogData("Reading instruction\n", offset, buffer)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }
// Duplicate
        if abort {
            fmt.Printf("Abort detected, escaping processing loop\n")
            break
        }

        fmt.Printf("We read the buffer %v\n", buffer[:waiting_for])

        //magic := binary.BigEndian.Uint32(buffer)
        command := binary.BigEndian.Uint32(buffer[4:8])
        handle := binary.BigEndian.Uint64(buffer[8:16])
        from := binary.BigEndian.Uint64(buffer[16:24])
        length := binary.BigEndian.Uint32(buffer[24:28])

        switch command {
        case utils.NBD_COMMAND_READ:
            fmt.Printf("We have a request to read. handle: %v, from: %v, length: %v\n", handle, from, length)
            fmt.Printf("Read Resquest    Offset:%x length: %v     Handle %X\n", from, length, handle)

            data_out, err = file.ReadAt(buffer[16:16+length], int64(from))
            utils.ErrorCheck(err)

            binary.BigEndian.PutUint32(buffer[:4], utils.NBD_REPLY_MAGIC)
            binary.BigEndian.PutUint32(buffer[4:8], 0)                      // error bits

            utils.LogData("About to reply with", int(16+length), buffer)

            conn.Write(buffer[:16+length])

            continue
        case utils.NBD_COMMAND_WRITE:
            fmt.Printf("We have a request to write. handle: %v, from: %v, length: %v\n", handle, from, length)

            waiting_for += int(length)                   // wait for the additional payload

// Duplicate
            for offset < waiting_for {
                length, err := conn_reader.Read(buffer[offset:waiting_for])
                offset += length
                utils.ErrorCheck(err)
                if err == io.EOF {
                    abort = true
                    break
                }
                utils.LogData("Reading write data\n", offset, buffer)
                if offset < waiting_for {
                    time.Sleep(5 * time.Millisecond)
                }
            }
// Duplicate

            data_out, err = file.WriteAt(buffer[28:28+length], int64(from))
            utils.ErrorCheck(err)
            file.Sync()

            continue

        case utils.NBD_COMMAND_DISCONNECT:
            fmt.Printf("We have received a request to disconnect\n")
            // close the file and return
            return
        }
    }
}

func send_export_list(output *bufio.Writer) {
    current_directory, err := os.Getwd()
    files, err := ioutil.ReadDir(current_directory + nbd_folder)
    if err != nil {
        log.Fatal(err)
    }
    for _, file := range files {
        send_export_list_item(output, file.Name())
    }

    send_ack(output)
}

func send_message(output *bufio.Writer, reply_type uint32, length uint32, data []byte ) {
    endian := binary.BigEndian
    buffer := make([]byte, 1024)
    offset := 0

    endian.PutUint64(buffer[offset:], utils.NBD_SERVER_SEND_REPLY_MAGIC)
    offset += 8

    endian.PutUint32(buffer[offset:], uint32(3))  // Flags (3 = supports list)
    offset += 4

    endian.PutUint32(buffer[offset:], reply_type)  // reply_type: NBD_REP_SERVER
    offset += 4

    endian.PutUint32(buffer[offset:], length)  // length of package
    offset += 4

    if data != nil {
        copy(buffer[offset:], data[0:length])
        offset += int(length)
    }

    data_to_send := buffer[:offset]
    output.Write(data_to_send)
    output.Flush()

    utils.LogData("Just sent:", offset, data_to_send)
}

func main() {

    if len(os.Args) <  3 {
        panic("missing arguments:  (ipaddress) (portnumber)")
        return
    }

    listener, err := net.Listen("tcp", os.Args[1] + ":" + os.Args[2])
    utils.ErrorCheck(err)

    fmt.Printf("Hello World, we have %v\n", listener)
    reply_magic := make([]byte, 4)
    binary.BigEndian.PutUint32(reply_magic, utils.NBD_REPLY_MAGIC)

    for {
        conn, err := listener.Accept()
        utils.ErrorCheck(err)

        fmt.Printf("We have a new connection from: %s\n", conn.RemoteAddr())
        output := bufio.NewWriter(conn)

        output.WriteString("NBDMAGIC")      // init password
        output.Flush()
        output.WriteString("IHAVEOPT")      // Magic
        output.Flush()
        output.Write([]byte{0, 3})          // Flags (3 = supports list)
        output.Flush()

        // Fetch the data until we get the initial options
        data := make([]byte, 1024)
        offset := 0
        waiting_for := 16       // wait for at least the minimum payload size

        for offset < waiting_for {
            length, err := conn.Read(data[offset:])
            offset += length
            utils.ErrorCheck(err)
            utils.LogData("Reading instruction", offset, data)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }

        // Skip the first 8 characters (options)
        command := binary.BigEndian.Uint32(data[12:])
        payload_size := int(binary.BigEndian.Uint32(data[16:]))

        fmt.Sprintf("command is: %d\npayload_size is: %d\n", command, payload_size)
        waiting_for += int(payload_size)
        for offset < waiting_for {
            length, err := conn.Read(data[offset:])
            offset += length
            utils.ErrorCheck(err)
            utils.LogData("Reading instruction", offset, data)
            if offset < waiting_for {
                time.Sleep(5 * time.Millisecond)
            }
        }
        payload := make([]byte, payload_size)

        if payload_size > 0{
            copy(payload, data[20:])
        }

        utils.LogData("Payload is:", payload_size, payload)
        fmt.Printf("command is: %v\n", command)

        // At this point, we have the command, payload size, and payload.
        switch command {
        case utils.NBD_COMMAND_LIST:
            send_export_list(output)
            conn.Close()
            break
        case utils.NBD_COMMAND_EXPORT_NAME:
            go export_name(output, conn, payload_size, payload)
            break
        }
    }

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/anachronistic/apns"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Post struct {
	ID           bson.ObjectId `bson:"_id,omitempty"`
	User         string
	Position     string
	FileName     string
	IsHorizontal string
	Filter       string
	Separator    string
}

type Push struct {
	ID    bson.ObjectId `bson:"_id,omitempty"`
	User  string
	Token string
}

func getDeviceTokenForUser(user string) string {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("push")
	var result Push
	c.Find(bson.M{"user": user}).One(&result)
	return result.Token
}

func setPushTokenForUser(user string, token string) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("push")
	c.Insert(&Push{User: user, Token: token})
}

func sendPushToUser(user string, fromUser string) {
	payload := apns.NewPayload()
	payload.Alert = fromUser + " vous a envoyé un shot 😏📸"
	payload.Badge = 1
	payload.Sound = "bingbong.aiff"

	pn := apns.NewPushNotification()
	pn.DeviceToken = getDeviceTokenForUser(user)
	pn.AddPayload(payload)

	client := apns.NewClient("gateway.sandbox.push.apple.com:2195", "PushChocoshotCert.pem", "key.unencrypted.pem")
	client.Send(pn)
}

func insertDatabase(p Post) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("post")
	c.Insert(&Post{User: p.User, Position: p.Position, FileName: p.FileName, IsHorizontal: p.IsHorizontal, Filter: p.Filter, Separator: p.Separator})
}

func getFromDataBaseWithUser(u string, deletation bool) Post {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("post")
	var results Post
	c.Find(bson.M{"user": u}).One(&results)
	if deletation == true {
		c.Remove(bson.M{"filename": results.FileName})
	}
	return results
}

func getPost(w http.ResponseWriter, r *http.Request) {
	user := r.Header.Get("user")
	deletation := r.Header.Get("deletation")
	var res = getFromDataBaseWithUser(user, deletation == "true")
	json.NewEncoder(w).Encode(res)
}

func updatePushToken(w http.ResponseWriter, r *http.Request) {
	user := strings.TrimSpace(r.FormValue("user"))
	token := strings.TrimSpace(r.FormValue("token"))
	setPushTokenForUser(user, token)
	var res = getDeviceTokenForUser(user)
	json.NewEncoder(w).Encode(res)
}

func uploadPost(w http.ResponseWriter, r *http.Request) {
	user := strings.TrimSpace(r.FormValue("user"))
	destination := strings.TrimSpace(r.FormValue("destination"))
	position := strings.TrimSpace(r.FormValue("position"))
	isHorizontal := strings.TrimSpace(r.FormValue("isHorizontal"))
	filter := strings.TrimSpace(r.FormValue("filter"))
	separator := strings.TrimSpace(r.FormValue("separator"))

	r.ParseMultipartForm(32 << 20)
	file, _, err := r.FormFile("uploadfile")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	fileName := RandomString(20)
	f, err := os.OpenFile("./img/"+fileName+".png", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}

	insertDatabase(Post{User: destination, Position: position, FileName: fileName + ".png", IsHorizontal: isHorizontal, Filter: filter, Separator: separator})

	sendPushToUser(destination, user)

	defer f.Close()
	io.Copy(f, file)
}

func RandomString(strlen int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := make([]byte, strlen)
	for i := 0; i < strlen; i++ {
		result[i] = chars[rand.Intn(len(chars))]
	}
	return string(result)
}

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			getPost(w, r)
		} else {
			uploadPost(w, r)
		}
	})

	mux.HandleFunc("/push", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			updatePushToken(w, r)
		}
	})

	mux.Handle("/image/", http.StripPrefix("/image/", http.FileServer(http.Dir("./img/"))))
	/*if strings.HasPrefix(r.URL.RequestURI(), "/image/") {
		file := strings.Replace(r.URL.RequestURI(), "/image/", "./img/", 1)
		fmt.Println("deleting " + file)
		defer os.Remove(file)
	}*/

	fmt.Println("listening at :9000")
	http.ListenAndServe(":9000", mux)
}
<commit_msg>add / end points<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/anachronistic/apns"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Post struct {
	ID           bson.ObjectId `bson:"_id,omitempty"`
	User         string
	Position     string
	FileName     string
	IsHorizontal string
	Filter       string
	Separator    string
}

type Push struct {
	ID    bson.ObjectId `bson:"_id,omitempty"`
	User  string
	Token string
}

func getDeviceTokenForUser(user string) string {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("push")
	var result Push
	c.Find(bson.M{"user": user}).One(&result)
	return result.Token
}

func setPushTokenForUser(user string, token string) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("push")
	c.Insert(&Push{User: user, Token: token})
}

func sendPushToUser(user string, fromUser string) {
	payload := apns.NewPayload()
	payload.Alert = fromUser + " vous a envoyé un shot 😏📸"
	payload.Badge = 1
	payload.Sound = "bingbong.aiff"

	pn := apns.NewPushNotification()
	pn.DeviceToken = getDeviceTokenForUser(user)
	pn.AddPayload(payload)

	client := apns.NewClient("gateway.sandbox.push.apple.com:2195", "PushChocoshotCert.pem", "key.unencrypted.pem")
	client.Send(pn)
}

func insertDatabase(p Post) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("post")
	c.Insert(&Post{User: p.User, Position: p.Position, FileName: p.FileName, IsHorizontal: p.IsHorizontal, Filter: p.Filter, Separator: p.Separator})
}

func getFromDataBaseWithUser(u string, deletation bool) Post {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	c := session.DB("chocoshot").C("post")
	var results Post
	c.Find(bson.M{"user": u}).One(&results)
	if deletation == true {
		c.Remove(bson.M{"filename": results.FileName})
	}
	return results
}

func getPost(w http.ResponseWriter, r *http.Request) {
	user := r.Header.Get("user")
	deletation := r.Header.Get("deletation")
	var res = getFromDataBaseWithUser(user, deletation == "true")
	json.NewEncoder(w).Encode(res)
}

func updatePushToken(w http.ResponseWriter, r *http.Request) {
	user := strings.TrimSpace(r.FormValue("user"))
	token := strings.TrimSpace(r.FormValue("token"))
	setPushTokenForUser(user, token)
	var res = getDeviceTokenForUser(user)
	json.NewEncoder(w).Encode(res)
}

func uploadPost(w http.ResponseWriter, r *http.Request) {
	user := strings.TrimSpace(r.FormValue("user"))
	destination := strings.TrimSpace(r.FormValue("destination"))
	position := strings.TrimSpace(r.FormValue("position"))
	isHorizontal := strings.TrimSpace(r.FormValue("isHorizontal"))
	filter := strings.TrimSpace(r.FormValue("filter"))
	separator := strings.TrimSpace(r.FormValue("separator"))

	r.ParseMultipartForm(32 << 20)
	file, _, err := r.FormFile("uploadfile")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	fileName := RandomString(20)
	f, err := os.OpenFile("./img/"+fileName+".png", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}

	insertDatabase(Post{User: destination, Position: position, FileName: fileName + ".png", IsHorizontal: isHorizontal, Filter: filter, Separator: separator})

	sendPushToUser(destination, user)

	defer f.Close()
	io.Copy(f, file)
}

func RandomString(strlen int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := make([]byte, strlen)
	for i := 0; i < strlen; i++ {
		result[i] = chars[rand.Intn(len(chars))]
	}
	return string(result)
}

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/post", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			getPost(w, r)
		} else {
			uploadPost(w, r)
		}
	})

	mux.HandleFunc("/push", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			updatePushToken(w, r)
		}
	})

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "hello world")
	})

	mux.Handle("/image/", http.StripPrefix("/image/", http.FileServer(http.Dir("./img/"))))
	/*if strings.HasPrefix(r.URL.RequestURI(), "/image/") {
		file := strings.Replace(r.URL.RequestURI(), "/image/", "./img/", 1)
		fmt.Println("deleting " + file)
		defer os.Remove(file)
	}*/

	fmt.Println("listening at :9000")
	http.ListenAndServe(":9000", mux)
}
<|endoftext|>


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

package main

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

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/shadowsocks/go-shadowsocks2/core"
	ssnet "github.com/shadowsocks/go-shadowsocks2/net"
	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"github.com/shadowsocks/go-shadowsocks2/socks"
)

var config struct {
	UDPTimeout time.Duration
}

func shadowConn(conn ssnet.DuplexConn, cipherList []shadowaead.Cipher) (ssnet.DuplexConn, int, error) {
	cipher, index, shadowReader, err := findCipher(conn, cipherList)
	if err != nil {
		return nil, -1, err
	}
	shadowWriter := shadowaead.NewShadowsocksWriter(conn, cipher)
	return ssnet.WrapDuplexConn(conn, shadowReader, shadowWriter), index, nil
}

func findCipher(clientReader io.Reader, cipherList []shadowaead.Cipher) (shadowaead.Cipher, int, io.Reader, error) {
	if len(cipherList) == 0 {
		return nil, -1, nil, errors.New("Empty cipher list")
	} else if len(cipherList) == 1 {
		return cipherList[0], 0, shadowaead.NewShadowsocksReader(clientReader, cipherList[0]), nil
	}
	// buffer saves the bytes read from shadowConn, in order to allow for replays.
	var buffer bytes.Buffer
	// Try each cipher until we find one that authenticates successfully.
	// This assumes that all ciphers are AEAD.
	// TODO: Reorder list to try previously successful ciphers first for the client IP.
	// TODO: Ban and log client IPs with too many failures too quick to protect against DoS.
	for i, cipher := range cipherList {
		log.Printf("Trying cipher %v", i)
		// tmpReader reuses the bytes read so far, falling back to shadowConn if it needs more
		// bytes. All bytes read from shadowConn are saved in buffer.
		tmpReader := io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(clientReader, &buffer))
		// Override the Reader of shadowConn so we can reset it for each cipher test.
		cipherReader := shadowaead.NewShadowsocksReader(tmpReader, cipher)
		// Read should read just enough data to authenticate the payload size.
		_, err := cipherReader.Read(make([]byte, 0))
		if err != nil {
			log.Printf("Failed cipher %v: %v", i, err)
			continue
		}
		log.Printf("Selected cipher %v", i)
		// We don't need to replay the bytes anymore, but we don't want to drop those
		// read so far.
		return cipher, i, shadowaead.NewShadowsocksReader(io.MultiReader(&buffer, clientReader), cipher), nil
	}
	return nil, -1, nil, fmt.Errorf("could not find valid cipher")
}

func getNetKey(addr net.Addr) (string, error) {
	host, _, err := net.SplitHostPort(addr.String())
	if err != nil {
		return "", err
	}
	ip := net.ParseIP(host)
	if ip == nil {
		return "", errors.New("Failed to parse ip")
	}
	ipNet := net.IPNet{IP: ip}
	if ip.To4() != nil {
		ipNet.Mask = net.CIDRMask(24, 32)
	} else {
		ipNet.Mask = net.CIDRMask(32, 128)
	}
	return ipNet.String(), nil
}

type connectionError struct {
	// TODO: create status enums and move to metrics.go
	status  string
	message string
	cause   error
}

// Listen on addr for incoming connections.
func tcpRemote(addr string, cipherList []shadowaead.Cipher, m metrics.TCPMetrics) {
	accessKeyMetrics := metrics.NewMetricsMap()
	netMetrics := metrics.NewMetricsMap()
	l, err := net.Listen("tcp", addr)
	if err != nil {
		log.Printf("failed to listen on %s: %v", addr, err)
		return
	}

	log.Printf("listening TCP on %s", addr)
	for {
		var clientConn ssnet.DuplexConn
		clientConn, err := l.(*net.TCPListener).AcceptTCP()
		m.AddOpenTCPConnection()
		if err != nil {
			log.Printf("failed to accept: %v", err)
			return
		}

		go func() (connError *connectionError) {
			connStart := time.Now()
			clientConn.(*net.TCPConn).SetKeepAlive(true)
			netKey, err := getNetKey(clientConn.RemoteAddr())
			if err != nil {
				netKey = "INVALID"
			}
			accessKey := "INVALID"
			var proxyMetrics metrics.ProxyMetrics
			clientConn = metrics.MeasureConn(clientConn, &proxyMetrics.ProxyClient, &proxyMetrics.ClientProxy)
			defer func() {
				connEnd := time.Now()
				connDuration := connEnd.Sub(connStart)
				clientConn.Close()
				status := "OK"
				if connError != nil {
					log.Printf("%v: %v", connError.message, connError.cause)
					status = connError.status
				}
				log.Printf("Done with status %v, duration %v", status, connDuration)
				m.AddClosedTCPConnection(accessKey, status, connDuration)
				accessKeyMetrics.Add(accessKey, proxyMetrics)
				log.Printf("Key %v: %s", accessKey, metrics.SPrintMetrics(accessKeyMetrics.Get(accessKey)))
				netMetrics.Add(netKey, proxyMetrics)
				log.Printf("Net %v: %s", netKey, metrics.SPrintMetrics(netMetrics.Get(netKey)))
			}()

			clientConn, index, err := shadowConn(clientConn, cipherList)
			if err != nil {
				return &connectionError{"ERR_CIPHER", "Failed to find a valid cipher", err}
			}
			accessKey = strconv.Itoa(index)

			tgt, err := socks.ReadAddr(clientConn)
			if err != nil {
				return &connectionError{"ERR_READ_ADDRESS", "Failed to get target address", err}
			}

			c, err := net.Dial("tcp", tgt.String())
			if err != nil {
				return &connectionError{"ERR_CONNECT", "Failed to connect to target", err}
			}
			var tgtConn ssnet.DuplexConn = c.(*net.TCPConn)
			defer tgtConn.Close()
			tgtConn.(*net.TCPConn).SetKeepAlive(true)
			tgtConn = metrics.MeasureConn(tgtConn, &proxyMetrics.ProxyTarget, &proxyMetrics.TargetProxy)

			log.Printf("proxy %s <-> %s", clientConn.RemoteAddr(), tgt)
			_, _, err = ssnet.Relay(clientConn, tgtConn)
			if err != nil {
				return &connectionError{"ERR_RELAY", "Failed to relay traffic", err}
			}
			return nil
		}()
	}
}

type cipherList []shadowaead.Cipher

func main() {

	var flags struct {
		Server      string
		Ciphers     cipherList
		MetricsAddr string
	}

	flag.StringVar(&flags.Server, "s", "", "server listen address")
	flag.Var(&flags.Ciphers, "u", "available ciphers: "+strings.Join(core.ListCipher(), " "))
	flag.DurationVar(&config.UDPTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
	flag.StringVar(&flags.MetricsAddr, "metrics", "", "address for the Prometheus metrics")
	flag.Parse()

	if flags.Server == "" || len(flags.Ciphers) == 0 {
		flag.Usage()
		return
	}

	if flags.MetricsAddr != "" {
		http.Handle("/metrics", promhttp.Handler())
		go func() {
			log.Fatal(http.ListenAndServe(flags.MetricsAddr, nil))
		}()
		log.Printf("Metrics on http://%v/metrics", flags.MetricsAddr)
	}

	go udpRemote(flags.Server, flags.Ciphers)
	go tcpRemote(flags.Server, flags.Ciphers, metrics.NewPrometheusTCPMetrics())

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
}

func (sl *cipherList) Set(flagValue string) error {
	e := strings.SplitN(flagValue, ":", 2)
	if len(e) != 2 {
		return fmt.Errorf("Missing colon")
	}
	cipher, err := core.PickCipher(e[0], nil, e[1])
	if err != nil {
		return err
	}
	aead, ok := cipher.(shadowaead.Cipher)
	if !ok {
		log.Fatal("Only AEAD ciphers are supported")
	}
	*sl = append(*sl, aead)
	return nil
}

func (sl *cipherList) String() string {
	return fmt.Sprint(*sl)
}
<commit_msg>Add log TODO<commit_after>// Copyright 2018 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

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

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/shadowsocks/go-shadowsocks2/core"
	ssnet "github.com/shadowsocks/go-shadowsocks2/net"
	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"github.com/shadowsocks/go-shadowsocks2/socks"
)

var config struct {
	UDPTimeout time.Duration
}

func shadowConn(conn ssnet.DuplexConn, cipherList []shadowaead.Cipher) (ssnet.DuplexConn, int, error) {
	cipher, index, shadowReader, err := findCipher(conn, cipherList)
	if err != nil {
		return nil, -1, err
	}
	shadowWriter := shadowaead.NewShadowsocksWriter(conn, cipher)
	return ssnet.WrapDuplexConn(conn, shadowReader, shadowWriter), index, nil
}

func findCipher(clientReader io.Reader, cipherList []shadowaead.Cipher) (shadowaead.Cipher, int, io.Reader, error) {
	if len(cipherList) == 0 {
		return nil, -1, nil, errors.New("Empty cipher list")
	} else if len(cipherList) == 1 {
		return cipherList[0], 0, shadowaead.NewShadowsocksReader(clientReader, cipherList[0]), nil
	}
	// buffer saves the bytes read from shadowConn, in order to allow for replays.
	var buffer bytes.Buffer
	// Try each cipher until we find one that authenticates successfully.
	// This assumes that all ciphers are AEAD.
	// TODO: Reorder list to try previously successful ciphers first for the client IP.
	// TODO: Ban and log client IPs with too many failures too quick to protect against DoS.
	for i, cipher := range cipherList {
		log.Printf("Trying cipher %v", i)
		// tmpReader reuses the bytes read so far, falling back to shadowConn if it needs more
		// bytes. All bytes read from shadowConn are saved in buffer.
		tmpReader := io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(clientReader, &buffer))
		// Override the Reader of shadowConn so we can reset it for each cipher test.
		cipherReader := shadowaead.NewShadowsocksReader(tmpReader, cipher)
		// Read should read just enough data to authenticate the payload size.
		_, err := cipherReader.Read(make([]byte, 0))
		if err != nil {
			log.Printf("Failed cipher %v: %v", i, err)
			continue
		}
		log.Printf("Selected cipher %v", i)
		// We don't need to replay the bytes anymore, but we don't want to drop those
		// read so far.
		return cipher, i, shadowaead.NewShadowsocksReader(io.MultiReader(&buffer, clientReader), cipher), nil
	}
	return nil, -1, nil, fmt.Errorf("could not find valid cipher")
}

func getNetKey(addr net.Addr) (string, error) {
	host, _, err := net.SplitHostPort(addr.String())
	if err != nil {
		return "", err
	}
	ip := net.ParseIP(host)
	if ip == nil {
		return "", errors.New("Failed to parse ip")
	}
	ipNet := net.IPNet{IP: ip}
	if ip.To4() != nil {
		ipNet.Mask = net.CIDRMask(24, 32)
	} else {
		ipNet.Mask = net.CIDRMask(32, 128)
	}
	return ipNet.String(), nil
}

type connectionError struct {
	// TODO: create status enums and move to metrics.go
	status  string
	message string
	cause   error
}

// Listen on addr for incoming connections.
func tcpRemote(addr string, cipherList []shadowaead.Cipher, m metrics.TCPMetrics) {
	accessKeyMetrics := metrics.NewMetricsMap()
	netMetrics := metrics.NewMetricsMap()
	l, err := net.Listen("tcp", addr)
	if err != nil {
		log.Printf("failed to listen on %s: %v", addr, err)
		return
	}

	log.Printf("listening TCP on %s", addr)
	for {
		var clientConn ssnet.DuplexConn
		clientConn, err := l.(*net.TCPListener).AcceptTCP()
		m.AddOpenTCPConnection()
		if err != nil {
			log.Printf("failed to accept: %v", err)
			return
		}

		go func() (connError *connectionError) {
			connStart := time.Now()
			clientConn.(*net.TCPConn).SetKeepAlive(true)
			netKey, err := getNetKey(clientConn.RemoteAddr())
			if err != nil {
				netKey = "INVALID"
			}
			accessKey := "INVALID"
			var proxyMetrics metrics.ProxyMetrics
			clientConn = metrics.MeasureConn(clientConn, &proxyMetrics.ProxyClient, &proxyMetrics.ClientProxy)
			defer func() {
				connEnd := time.Now()
				connDuration := connEnd.Sub(connStart)
				clientConn.Close()
				status := "OK"
				if connError != nil {
					log.Printf("ERROR %v: %v", connError.message, connError.cause)
					status = connError.status
				}
				log.Printf("Done with status %v, duration %v", status, connDuration)
				m.AddClosedTCPConnection(accessKey, status, connDuration)
				accessKeyMetrics.Add(accessKey, proxyMetrics)
				log.Printf("Key %v: %s", accessKey, metrics.SPrintMetrics(accessKeyMetrics.Get(accessKey)))
				netMetrics.Add(netKey, proxyMetrics)
				log.Printf("Net %v: %s", netKey, metrics.SPrintMetrics(netMetrics.Get(netKey)))
			}()

			clientConn, index, err := shadowConn(clientConn, cipherList)
			if err != nil {
				return &connectionError{"ERR_CIPHER", "Failed to find a valid cipher", err}
			}
			accessKey = strconv.Itoa(index)

			tgt, err := socks.ReadAddr(clientConn)
			if err != nil {
				return &connectionError{"ERR_READ_ADDRESS", "Failed to get target address", err}
			}

			c, err := net.Dial("tcp", tgt.String())
			if err != nil {
				return &connectionError{"ERR_CONNECT", "Failed to connect to target", err}
			}
			var tgtConn ssnet.DuplexConn = c.(*net.TCPConn)
			defer tgtConn.Close()
			tgtConn.(*net.TCPConn).SetKeepAlive(true)
			tgtConn = metrics.MeasureConn(tgtConn, &proxyMetrics.ProxyTarget, &proxyMetrics.TargetProxy)

			// TODO: Disable logging in production. This is sensitive.
			log.Printf("proxy %s <-> %s", clientConn.RemoteAddr(), tgt)
			_, _, err = ssnet.Relay(clientConn, tgtConn)
			if err != nil {
				return &connectionError{"ERR_RELAY", "Failed to relay traffic", err}
			}
			return nil
		}()
	}
}

type cipherList []shadowaead.Cipher

func main() {

	var flags struct {
		Server      string
		Ciphers     cipherList
		MetricsAddr string
	}

	flag.StringVar(&flags.Server, "s", "", "server listen address")
	flag.Var(&flags.Ciphers, "u", "available ciphers: "+strings.Join(core.ListCipher(), " "))
	flag.DurationVar(&config.UDPTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
	flag.StringVar(&flags.MetricsAddr, "metrics", "", "address for the Prometheus metrics")
	flag.Parse()

	if flags.Server == "" || len(flags.Ciphers) == 0 {
		flag.Usage()
		return
	}

	if flags.MetricsAddr != "" {
		http.Handle("/metrics", promhttp.Handler())
		go func() {
			log.Fatal(http.ListenAndServe(flags.MetricsAddr, nil))
		}()
		log.Printf("Metrics on http://%v/metrics", flags.MetricsAddr)
	}

	go udpRemote(flags.Server, flags.Ciphers)
	go tcpRemote(flags.Server, flags.Ciphers, metrics.NewPrometheusTCPMetrics())

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
}

func (sl *cipherList) Set(flagValue string) error {
	e := strings.SplitN(flagValue, ":", 2)
	if len(e) != 2 {
		return fmt.Errorf("Missing colon")
	}
	cipher, err := core.PickCipher(e[0], nil, e[1])
	if err != nil {
		return err
	}
	aead, ok := cipher.(shadowaead.Cipher)
	if !ok {
		log.Fatal("Only AEAD ciphers are supported")
	}
	*sl = append(*sl, aead)
	return nil
}

func (sl *cipherList) String() string {
	return fmt.Sprint(*sl)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/hashicorp/consul/api"
	"math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type WebServer struct {
	ServiceID           string
	Address             string
	Port                int
	RegisterToConsul    bool
	ConsulApi           *api.Client
	ConsulAgent         *api.Agent
	ServiceRegistration *api.AgentServiceRegistration
	Listener            net.Listener
	Config              *WebServerConfiguration
	Server              http.Server
	FileServer          http.Handler
	RegexAngularMode    *regexp.Regexp
	err                 error
	Proxies             map[string]*httputil.ReverseProxy
}

func NewWebServer(s *WebServerConfiguration) *WebServer {
	p := new(WebServer)
	p.ServiceID = ""
	p.Config = s
	p.Address = s.EntryPoint.Address
	p.Port = s.EntryPoint.Port
	p.RegisterToConsul = s.Consul.Register
	p.ConsulApi = nil
	p.ConsulAgent = nil
	p.Listener = nil
	p.Server = http.Server{}
	p.FileServer = nil
	p.RegexAngularMode = nil
	p.Proxies = make(map[string]*httputil.ReverseProxy)
	return p
}

func (server *WebServer) AddExitHook() {
	/* Capture Signal */
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		for sig := range c {
			log.Warn(fmt.Sprintf("captured %v, exiting..", sig))
			server.DeInit()
			os.Exit(0)
		}
	}()
}

func (server *WebServer) Init() bool {
	server.Listener, server.err = net.Listen("tcp", fmt.Sprintf(":%d", server.Port))
	if server.err != nil {
		panic("bind failed")
	}
	hostname, err := os.Hostname()
	if err != nil {
		panic("Unable to get Hostname")
	}
	server.Address = hostname
	server.Port = server.Listener.Addr().(*net.TCPAddr).Port
	log.Info(fmt.Sprintf("Listening to %s:%d", server.Config.EntryPoint.Address, server.Port))

	// Init Name
	server.ServiceID = fmt.Sprintf("%s-%d-%s", server.Config.ServiceName, server.Port, server.GenerateUniqueID())

	// Fetch Tags
	if server.Config.TagsOrigin.Enabled == true {
		server.Config.Consul.Tags = NewTagsFetcher(server.Config.Consul, server.Config.TagsOrigin).Tags()
	}

	if server.RegisterToConsul == true {
		server.RegisterConsul()
	}
	server.AddExitHook()

	// Static file server
	server.FileServer = http.FileServer(http.Dir(server.Config.RootFolder))
	return true
}

func (server *WebServer) RegisterConsul() bool {
	var err error = nil

	// Bind HealthCheck
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "I'm OK !")
	})

	for _, t := range server.Config.Consul.Tags {
		log.Info(fmt.Sprintf("Adding tag: %s", t))
	}

	// Register to Consul
	server.ConsulApi, err = api.NewClient(api.DefaultConfig())
	if err != nil {
		panic("Unable to connect to consul")
	}
	server.ConsulAgent = server.ConsulApi.Agent()
	server.ServiceRegistration = &api.AgentServiceRegistration{
		ID:                server.ServiceID,
		Name:              server.Config.ServiceName,
		Tags:              server.Config.Consul.Tags,
		Port:              server.Port,
		Address:           server.Address,
		EnableTagOverride: false,
		Check: &api.AgentServiceCheck{
			Interval: "10s",
			Timeout:  "1s",
			HTTP:     fmt.Sprintf("http://%s:%d/health", server.Address, server.Port),
			DeregisterCriticalServiceAfter: "15m",
		}}

	err = server.ConsulAgent.ServiceRegister(server.ServiceRegistration)
	if err != nil {
		panic("Unable to register to Consul")
	}
	return true
}

func (server *WebServer) Run() {
	// Prepare Proxified stuff
	for _, pr := range server.Config.ProxyRoutes {
		d := &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				newUrl := req.URL.Path
				if pr.StripPath {
					newUrl = req.URL.Path[len(pr.Path):len(req.URL.Path)]
				}
				if pr.PrefixPath != "" {
					newUrl = pr.PrefixPath + newUrl
				}
				log.Info(fmt.Sprintf("[proxy] %s to %s://%s/%s", req.URL.Path, pr.Scheme, pr.Host, newUrl))
				req.URL.Path = newUrl
				req.URL.Scheme = pr.Scheme
				req.URL.Host = pr.Host
			},
		}
		server.Proxies[pr.Path] = d
		log.Info(fmt.Sprintf("[proxy] %s will be forworded to %s://%s/%s", pr.Path, pr.Scheme, pr.Host, pr.PrefixPath))
	}

	// Handle Static stuff
	log.Info(fmt.Sprintf("Serving %s", server.Config.RootFolder))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		srw := &StatusResponseWriter{ResponseWriter: w}
		defer func() {
			server.LogResponse(srw, r)
		}()

		// Check for Proxies
		for k, v := range server.Proxies {
			if strings.HasPrefix(r.URL.Path, k) {
				v.ServeHTTP(srw, r)
				return
			}
		}

		// Failback on Static Files
		if server.Config.AngularMode {
			rx, err := regexp.MatchString("^/([^/]+)\\.((ttf|eot|svg|js|woff2|map|ico)(\\?.*)?)", r.URL.Path)
			if !strings.HasPrefix(r.URL.Path, "/app/") && !strings.HasPrefix(r.URL.Path, "/assets/") && err == nil && rx == false {
				r.URL.Path = "/"
			}
		}
		server.FileServer.ServeHTTP(srw, r)
	})

	// Serve
	srv := server.Server.Serve(server.Listener)
	panic(srv)
}

func (server *WebServer) LogResponse(srw *StatusResponseWriter, r *http.Request) {
	log.WithFields(log.Fields{
		"status":      srw.status,
		"path":        r.RequestURI,
		"method":      r.Method,
		"proto":       r.Proto,
		"remote-addr": r.RemoteAddr,
	}).Info(fmt.Sprintf("[%d] %s", srw.status, r.RequestURI))
}

func (server *WebServer) UnregisterFromConsul() {
	if server.ServiceRegistration != nil {
		server.ConsulAgent.ServiceDeregister(server.ServiceRegistration.ID)
	}
}

func (server *WebServer) DeInit() {
	server.UnregisterFromConsul()
	server.Listener.Close()
}

func (server *WebServer) GenerateUniqueID() string {
	rand.Seed(time.Now().UnixNano())
	letters := "abcdef0123456789"

	b := make([]byte, 16)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<commit_msg>Update status of Health. Dynamic IP registering into Consul<commit_after>package main

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/hashicorp/consul/api"
	"math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type WebServer struct {
	ServiceID           string
	Address             string
	Port                int
	RegisterToConsul    bool
	ConsulApi           *api.Client
	ConsulAgent         *api.Agent
	ServiceRegistration *api.AgentServiceRegistration
	Listener            net.Listener
	Config              *WebServerConfiguration
	Server              http.Server
	FileServer          http.Handler
	RegexAngularMode    *regexp.Regexp
	err                 error
	Proxies             map[string]*httputil.ReverseProxy
}

func NewWebServer(s *WebServerConfiguration) *WebServer {
	p := new(WebServer)
	p.ServiceID = ""
	p.Config = s
	p.Address = s.EntryPoint.Address
	p.Port = s.EntryPoint.Port
	p.RegisterToConsul = s.Consul.Register
	p.ConsulApi = nil
	p.ConsulAgent = nil
	p.Listener = nil
	p.Server = http.Server{}
	p.FileServer = nil
	p.RegexAngularMode = nil
	p.Proxies = make(map[string]*httputil.ReverseProxy)
	return p
}

func (server *WebServer) AddExitHook() {
	/* Capture Signal */
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		for sig := range c {
			log.Warn(fmt.Sprintf("captured %v, exiting..", sig))
			server.DeInit()
			os.Exit(0)
		}
	}()
}

func (server *WebServer) GetExposedIpAddress() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		panic("Unable to get IPs")
	}
	for _, address := range addrs {
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String()
			}
		}
	}
	hostname, err := os.Hostname()
	if err != nil {
		panic("Unable to get Hostname")
	}
	return hostname
}

func (server *WebServer) Init() bool {
	server.Listener, server.err = net.Listen("tcp", fmt.Sprintf(":%d", server.Port))
	if server.err != nil {
		panic("bind failed")
	}

	server.Address = server.GetExposedIpAddress()
	server.Port = server.Listener.Addr().(*net.TCPAddr).Port
	log.Info(fmt.Sprintf("Listening to %s:%d", server.Config.EntryPoint.Address, server.Port))

	// Init Name
	server.ServiceID = fmt.Sprintf("%s-%d-%s", server.Config.ServiceName, server.Port, server.GenerateUniqueID())

	// Fetch Tags
	if server.Config.TagsOrigin.Enabled == true {
		server.Config.Consul.Tags = NewTagsFetcher(server.Config.Consul, server.Config.TagsOrigin).Tags()
	}

	if server.RegisterToConsul == true {
		server.RegisterConsul()
	}
	server.AddExitHook()

	// Static file server
	server.FileServer = http.FileServer(http.Dir(server.Config.RootFolder))
	return true
}

func (server *WebServer) RegisterConsul() bool {
	var err error = nil

	// Bind HealthCheck
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		srw := &StatusResponseWriter{ResponseWriter: w}
		srw.WriteHeader(200)
		fmt.Fprintf(srw, "I'm OK !")
	})

	for _, t := range server.Config.Consul.Tags {
		log.Info(fmt.Sprintf("Adding tag: %s", t))
	}

	// Register to Consul
	server.ConsulApi, err = api.NewClient(api.DefaultConfig())
	if err != nil {
		panic("Unable to connect to consul")
	}
	server.ConsulAgent = server.ConsulApi.Agent()
	server.ServiceRegistration = &api.AgentServiceRegistration{
		ID:                server.ServiceID,
		Name:              server.Config.ServiceName,
		Tags:              server.Config.Consul.Tags,
		Port:              server.Port,
		Address:           server.Address,
		EnableTagOverride: false,
		Check: &api.AgentServiceCheck{
			Interval: "10s",
			Timeout:  "1s",
			HTTP:     fmt.Sprintf("http://%s:%d/health", server.Address, server.Port),
			DeregisterCriticalServiceAfter: "15m",
		}}

	err = server.ConsulAgent.ServiceRegister(server.ServiceRegistration)
	if err != nil {
		panic("Unable to register to Consul")
	}
	return true
}

func (server *WebServer) Run() {
	// Prepare Proxified stuff
	for _, pr := range server.Config.ProxyRoutes {
		d := &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				newUrl := req.URL.Path
				if pr.StripPath {
					newUrl = req.URL.Path[len(pr.Path):len(req.URL.Path)]
				}
				if pr.PrefixPath != "" {
					newUrl = pr.PrefixPath + newUrl
				}
				log.Info(fmt.Sprintf("[proxy] %s to %s://%s/%s", req.URL.Path, pr.Scheme, pr.Host, newUrl))
				req.URL.Path = newUrl
				req.URL.Scheme = pr.Scheme
				req.URL.Host = pr.Host
			},
		}
		server.Proxies[pr.Path] = d
		log.Info(fmt.Sprintf("[proxy] %s will be forworded to %s://%s/%s", pr.Path, pr.Scheme, pr.Host, pr.PrefixPath))
	}

	// Handle Static stuff
	log.Info(fmt.Sprintf("Serving %s", server.Config.RootFolder))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		srw := &StatusResponseWriter{ResponseWriter: w}
		defer func() {
			server.LogResponse(srw, r)
		}()

		// Check for Proxies
		for k, v := range server.Proxies {
			if strings.HasPrefix(r.URL.Path, k) {
				v.ServeHTTP(srw, r)
				return
			}
		}

		// Failback on Static Files
		if server.Config.AngularMode {
			rx, err := regexp.MatchString("^/([^/]+)\\.((ttf|eot|svg|js|woff2|map|ico)(\\?.*)?)", r.URL.Path)
			if !strings.HasPrefix(r.URL.Path, "/app/") && !strings.HasPrefix(r.URL.Path, "/assets/") && err == nil && rx == false {
				r.URL.Path = "/"
			}
		}
		server.FileServer.ServeHTTP(srw, r)
	})

	// Serve
	srv := server.Server.Serve(server.Listener)
	panic(srv)
}

func (server *WebServer) LogResponse(srw *StatusResponseWriter, r *http.Request) {
	log.WithFields(log.Fields{
		"status":      srw.status,
		"path":        r.RequestURI,
		"method":      r.Method,
		"proto":       r.Proto,
		"remote-addr": r.RemoteAddr,
	}).Info(fmt.Sprintf("[%d] %s", srw.status, r.RequestURI))
}

func (server *WebServer) UnregisterFromConsul() {
	if server.ServiceRegistration != nil {
		server.ConsulAgent.ServiceDeregister(server.ServiceRegistration.ID)
	}
}

func (server *WebServer) DeInit() {
	server.UnregisterFromConsul()
	server.Listener.Close()
}

func (server *WebServer) GenerateUniqueID() string {
	rand.Seed(time.Now().UnixNano())
	letters := "abcdef0123456789"

	b := make([]byte, 16)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
	"encoding/json"
    "net/http"
    "log"
    "./utils"
)

type resp_struct struct {
	Text string
}

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func AcceptVote(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	decoder := json.NewDecoder(r.Body)
	var resp resp_struct
	err := decoder.Decode(&resp)
    utils.CheckError(err, "connection error")
	defer r.Body.Close()
	log.Println(resp)
	fmt.Fprintf(w, resp.Text)
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)
    router.POST("/vote/", AcceptVote)

    log.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>added start game<commit_after>package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
	"encoding/json"
    "net/http"
    "log"
    "./utils"
	"math/rand"
	"time"
)

type room struct {
	Key string
}

rooms := []room{}

type resp_struct struct {
	Text string
}

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func AcceptVote(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	decoder := json.NewDecoder(r.Body)
	var resp resp_struct
	err := decoder.Decode(&resp)
    utils.CheckError(err, "connection error")
	defer r.Body.Close()
	log.Println(resp)
	fmt.Fprintf(w, resp.Text)
}
func StartGame(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	hash := RandomString(5)
	var game_room := room{hash: hash}
	rooms = append(rooms, game_room)
	fmt.Fprintf(w, hash)
}
func RandomString(strlen int) string {
	var r *rand.Rand
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
	const chars = "0123456789"
	result := make([]byte, strlen)
	for i := range result {
		result[i] = chars[r.Intn(len(chars))]
	}
	return string(result)
}
func main() {
    router := httprouter.New()
    router.GET("/", Index)
    router.POST("/vote/", AcceptVote)
    router.POST("/start_game/", StartGame)
    log.Fatal(http.ListenAndServe(":8080", router))
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/braintree/manners"
	"github.com/elithrar/goji-logger"
	"github.com/lestrrat/go-server-starter/listener"
	"goji.io"
	"goji.io/pat"
)

type Server struct{}

func (s *Server) Help() string {
	return `sanrio-character-ranking-viewer server`
}

func (s *Server) Run(args []string) int {
	context, err := newContext()
	if err != nil {
		log.Fatal(err)
	}
	defer context.Close()

	signalChan := make(chan os.Signal)
	signal.Notify(signalChan, syscall.SIGTERM)
	go func() {
		for {
			s := <-signalChan
			if s == syscall.SIGTERM {
				manners.Close()
			}
		}
	}()

	listeners, err := listener.ListenAll()
	if err != nil {
		log.Fatal(err)
	}

	var l net.Listener
	if len(listeners) > 0 {
		l = listeners[0]
	} else {
		l, err = net.Listen("tcp", ":14000")
		if err != nil {
			log.Fatal(err)
		}
	}

	mux := goji.NewMux()
	mux.UseC(logger.RequestID)
	mux.UseC(logger.Logger)
	mux.Handle(pat.Get("/assets/*"), http.FileServer(AssetFileSystem{}))
	mux.Handle(pat.Get("/"), &appHandler{context, handleIndex})

	manners.Serve(l, mux)
	return 0
}

func (s *Server) Synopsis() string {
	return `Start server`
}

func handleIndex(c *appContext, w http.ResponseWriter, r *http.Request) {
	var ranking Ranking
	if err := c.dbMap.SelectOne(&ranking,
		`SELECT * FROM ranking WHERE started_on <= :today ORDER BY ended_on DESC, started_on DESC LIMIT 1`,
		map[string]interface{}{
			"today": time.Now(),
		}); err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	var rankingItems []RankingItem
	if _, err := c.dbMap.Select(&rankingItems, `
		SELECT
			character.name AS Name,
			x.count AS Count
		FROM (
			SELECT
				character_id, COUNT(*) AS count
			FROM vote
			WHERE vote.ranking_id = :ranking_id
			GROUP BY vote.character_id
		) x
		JOIN character ON character.id = x.character_id
		ORDER BY x.count DESC, character.name ASC
	`, map[string]interface{}{
		"ranking_id": ranking.Id,
	}); err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	_ = renderLayout(w, "Sanrio Character Ranking Viewer", func(w io.Writer) error {
		return renderIndex(w, ranking, rankingItems)
	})
}
<commit_msg>JOIN with entry<commit_after>package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/braintree/manners"
	"github.com/elithrar/goji-logger"
	"github.com/lestrrat/go-server-starter/listener"
	"goji.io"
	"goji.io/pat"
)

type Server struct{}

func (s *Server) Help() string {
	return `sanrio-character-ranking-viewer server`
}

func (s *Server) Run(args []string) int {
	context, err := newContext()
	if err != nil {
		log.Fatal(err)
	}
	defer context.Close()

	signalChan := make(chan os.Signal)
	signal.Notify(signalChan, syscall.SIGTERM)
	go func() {
		for {
			s := <-signalChan
			if s == syscall.SIGTERM {
				manners.Close()
			}
		}
	}()

	listeners, err := listener.ListenAll()
	if err != nil {
		log.Fatal(err)
	}

	var l net.Listener
	if len(listeners) > 0 {
		l = listeners[0]
	} else {
		l, err = net.Listen("tcp", ":14000")
		if err != nil {
			log.Fatal(err)
		}
	}

	mux := goji.NewMux()
	mux.UseC(logger.RequestID)
	mux.UseC(logger.Logger)
	mux.Handle(pat.Get("/assets/*"), http.FileServer(AssetFileSystem{}))
	mux.Handle(pat.Get("/"), &appHandler{context, handleIndex})

	manners.Serve(l, mux)
	return 0
}

func (s *Server) Synopsis() string {
	return `Start server`
}

func handleIndex(c *appContext, w http.ResponseWriter, r *http.Request) {
	var ranking Ranking
	if err := c.dbMap.SelectOne(&ranking,
		`SELECT * FROM ranking WHERE started_on <= :today ORDER BY ended_on DESC, started_on DESC LIMIT 1`,
		map[string]interface{}{
			"today": time.Now(),
		}); err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	var rankingItems []RankingItem
	if _, err := c.dbMap.Select(&rankingItems, `
		SELECT
			character.name AS Name,
			x.count AS Count
		FROM (
			SELECT
				vote.character_id, COUNT(*) AS count
			FROM vote
			JOIN entry ON
				entry.ranking_id = vote.ranking_id
				AND entry.character_id = vote.character_id
			WHERE vote.ranking_id = :ranking_id
			GROUP BY vote.character_id
		) x
		JOIN character ON character.id = x.character_id
		ORDER BY x.count DESC, character.name ASC
	`, map[string]interface{}{
		"ranking_id": ranking.Id,
	}); err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	_ = renderLayout(w, "Sanrio Character Ranking Viewer", func(w io.Writer) error {
		return renderIndex(w, ranking, rankingItems)
	})
}
<|endoftext|>


<commit_before>package util

import (
	"encoding/json"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"github.com/realglobe-Inc/go-lib-rg/rglog/level"
	"math/rand"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type HandlerFunc func(http.ResponseWriter, *http.Request) error

func Serve(socType, socPath string, socPort int, protType string, routes map[string]HandlerFunc) error {
	return TerminableServe(socType, socPath, socPort, protType, routes, make(chan struct{}, 1), PanicErrorWrapper)
}

func TerminableServe(socType, socPath string, socPort int, protType string,
	routes map[string]HandlerFunc, shutCh chan struct{},
	wrapper func(handler HandlerFunc) http.HandlerFunc) error {

	var serv func(net.Listener, http.Handler) error
	switch protType {
	case "http":
		serv = http.Serve
	case "fcgi":
		serv = fcgi.Serve
	default:
		return erro.New("invalid protocol type " + protType)
	}

	mux := http.NewServeMux()
	for path, handler := range routes {
		mux.HandleFunc(path, wrapper(handler))
	}

	if shutCh == nil {
		shutCh = make(chan struct{}, 1)
	}
	var lis net.Listener
	var lisLock sync.Mutex

	// SIGINT、SIGTERM を受け取ったら正常終了。
	sigCh := make(chan os.Signal, 10)
	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

	// 別スレッドで終了を監視する。
	go func() {
		select {
		case sig := <-sigCh:
			log.Info("Signal ", sig, " was caught")
		case <-shutCh:
			log.Info("Shutdown was operated")
		}
		shutCh <- struct{}{}
		lisLock.Lock()
		l := lis
		lisLock.Unlock()

		if l != nil {
			l.Close()
			log.Info("Socket was closed")
		} else {
			log.Info("No socket to close")
		}
	}()

	// エラー発生時の冷却期間はだんだん延ばす。
	var sleepTime time.Duration = 0
	// 一定期間以上エラー無しで動作したら冷却期間をリセットする。
	resetInterval := time.Minute
	for {
		if retry, err := func() (retry bool, err error) {

			var l net.Listener
			defer func() {
				if l != nil {
					l.Close()
				}
			}()

			switch socType {
			case "unix":
				l, err = net.Listen("unix", socPath)
				if err != nil {
					return true, erro.Wrap(err)
				}
				if err := os.Chmod(socPath, 0777); err != nil {
					return true, erro.Wrap(err)
				}
				log.Info("Wait on UNIX socket " + socPath)
			case "tcp":
				l, err = net.Listen("tcp", ":"+strconv.Itoa(socPort))
				if err != nil {
					return true, erro.Wrap(err)
				}
				log.Info("Wait on TCP socket ", socPort)
			default:
				return false, erro.New("invalid socket type " + socType)
			}

			lisLock.Lock()
			lis = l
			lisLock.Unlock()
			select {
			case <-shutCh:
				// 既に終了信号を受け取っていた。
				shutCh <- struct{}{}
				return false, nil
			default:
			}

			start := time.Now()
			if err := func() error {
				log.Debug("Service starts.")
				defer log.Debug("Service exits.")
				return erro.Wrap(serv(l, mux))
			}(); err != nil {
				err := erro.Wrap(err)

				select {
				case <-shutCh:
					// 既に終了信号を受け取っていた。
					shutCh <- struct{}{}
					return false, nil
				default:
				}

				end := time.Now()
				if end.Sub(start) > resetInterval {
					sleepTime = 0
				}

				return true, err
			}

			return true, nil
		}(); !retry {
			return erro.Wrap(err)
		} else {
			if err != nil {
				log.Err(erro.Unwrap(err))
				log.Debug(err)
			}

			sleepTime = serverNextSleepTime(sleepTime, resetInterval)
			log.Info("Retry after ", sleepTime)

			timeCh := time.After(sleepTime)
			select {
			case <-shutCh:
				shutCh <- struct{}{}
				return nil
			case <-timeCh:
			}
		}
	}

	return nil
}

func serverNextSleepTime(cur, max time.Duration) time.Duration {
	next := 2*cur + time.Duration(rand.Int63n(int64(time.Second)))
	if next >= max {
		next = time.Minute
	}
	return next
}

// パニックとエラーの処理をまとめる。
func PanicErrorWrapper(handler HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// panic時にプロセス終了しないようにrecoverする
		defer func() {
			if rcv := recover(); rcv != nil {
				responseError(w, erro.New(rcv))
				return
			}
		}()

		//////////////////////////////
		LogRequest(level.DEBUG, r, true)
		//////////////////////////////

		if err := handler(w, r); err != nil {
			responseError(w, erro.Wrap(err))
			return
		}
	}
}

func responseError(w http.ResponseWriter, err error) {

	var v struct {
		Stat int    `json:"status"`
		Msg  string `json:"message"`
	}
	switch e := erro.Unwrap(err).(type) {
	case *HttpStatusError:
		log.Err(e.Message())
		log.Debug(e)
		v.Stat = e.Status()
		v.Msg = e.Message()
	default:
		log.Err(e)
		log.Debug(err)
		v.Stat = http.StatusInternalServerError
		v.Msg = e.Error()
	}

	buff, err := json.Marshal(&v)
	if err != nil {
		err = erro.Wrap(err)
		log.Err(erro.Unwrap(err))
		log.Debug(err)
		// 最後の手段。たぶん正しい変換。
		buff = []byte(`{status="` + JsonStringEscape(strconv.Itoa(v.Stat)) +
			`",message="` + JsonStringEscape(v.Msg) + `"}`)
	}

	w.Header().Set("Content-Type", ContentTypeJson)
	w.Header().Set("Content-Length", strconv.Itoa(len(buff)))
	w.WriteHeader(v.Stat)
	if _, err := w.Write(buff); err != nil {
		err = erro.Wrap(err)
		log.Err(erro.Unwrap(err))
		log.Debug(err)
	}
	return
}
<commit_msg>サーバーの起動再試行間隔を狭めた<commit_after>package util

import (
	"encoding/json"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"github.com/realglobe-Inc/go-lib-rg/rglog/level"
	"math/rand"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type HandlerFunc func(http.ResponseWriter, *http.Request) error

func Serve(socType, socPath string, socPort int, protType string, routes map[string]HandlerFunc) error {
	return TerminableServe(socType, socPath, socPort, protType, routes, make(chan struct{}, 1), PanicErrorWrapper)
}

func TerminableServe(socType, socPath string, socPort int, protType string,
	routes map[string]HandlerFunc, shutCh chan struct{},
	wrapper func(handler HandlerFunc) http.HandlerFunc) error {

	var serv func(net.Listener, http.Handler) error
	switch protType {
	case "http":
		serv = http.Serve
	case "fcgi":
		serv = fcgi.Serve
	default:
		return erro.New("invalid protocol type " + protType)
	}

	mux := http.NewServeMux()
	for path, handler := range routes {
		mux.HandleFunc(path, wrapper(handler))
	}

	if shutCh == nil {
		shutCh = make(chan struct{}, 1)
	}
	var lis net.Listener
	var lisLock sync.Mutex

	// SIGINT、SIGTERM を受け取ったら正常終了。
	sigCh := make(chan os.Signal, 10)
	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

	// 別スレッドで終了を監視する。
	go func() {
		select {
		case sig := <-sigCh:
			log.Info("Signal ", sig, " was caught")
		case <-shutCh:
			log.Info("Shutdown was operated")
		}
		shutCh <- struct{}{}
		lisLock.Lock()
		l := lis
		lisLock.Unlock()

		if l != nil {
			l.Close()
			log.Info("Socket was closed")
		} else {
			log.Info("No socket to close")
		}
	}()

	// エラー発生時の冷却期間はだんだん延ばす。
	var sleepTime time.Duration = 0
	// 一定期間以上エラー無しで動作したら冷却期間をリセットする。
	resetInterval := time.Minute
	for {
		if retry, err := func() (retry bool, err error) {

			var l net.Listener
			defer func() {
				if l != nil {
					l.Close()
				}
			}()

			switch socType {
			case "unix":
				l, err = net.Listen("unix", socPath)
				if err != nil {
					return true, erro.Wrap(err)
				}
				if err := os.Chmod(socPath, 0777); err != nil {
					return true, erro.Wrap(err)
				}
				log.Info("Wait on UNIX socket " + socPath)
			case "tcp":
				l, err = net.Listen("tcp", ":"+strconv.Itoa(socPort))
				if err != nil {
					return true, erro.Wrap(err)
				}
				log.Info("Wait on TCP socket ", socPort)
			default:
				return false, erro.New("invalid socket type " + socType)
			}

			lisLock.Lock()
			lis = l
			lisLock.Unlock()
			select {
			case <-shutCh:
				// 既に終了信号を受け取っていた。
				shutCh <- struct{}{}
				return false, nil
			default:
			}

			start := time.Now()
			if err := func() error {
				log.Debug("Service starts.")
				defer log.Debug("Service exits.")
				return erro.Wrap(serv(l, mux))
			}(); err != nil {
				err := erro.Wrap(err)

				select {
				case <-shutCh:
					// 既に終了信号を受け取っていた。
					shutCh <- struct{}{}
					return false, nil
				default:
				}

				end := time.Now()
				if end.Sub(start) > resetInterval {
					sleepTime = 0
				}

				return true, err
			}

			return true, nil
		}(); !retry {
			return erro.Wrap(err)
		} else {
			if err != nil {
				log.Err(erro.Unwrap(err))
				log.Debug(err)
			}

			sleepTime = serverNextSleepTime(sleepTime, resetInterval)
			log.Info("Retry after ", sleepTime)

			timeCh := time.After(sleepTime)
			select {
			case <-shutCh:
				shutCh <- struct{}{}
				return nil
			case <-timeCh:
			}
		}
	}

	return nil
}

func serverNextSleepTime(cur, max time.Duration) time.Duration {
	next := 2*cur + time.Duration(rand.Int63n(int64(100*time.Millisecond)))
	if next >= max {
		next = time.Minute
	}
	return next
}

// パニックとエラーの処理をまとめる。
func PanicErrorWrapper(handler HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// panic時にプロセス終了しないようにrecoverする
		defer func() {
			if rcv := recover(); rcv != nil {
				responseError(w, erro.New(rcv))
				return
			}
		}()

		//////////////////////////////
		LogRequest(level.DEBUG, r, true)
		//////////////////////////////

		if err := handler(w, r); err != nil {
			responseError(w, erro.Wrap(err))
			return
		}
	}
}

func responseError(w http.ResponseWriter, err error) {

	var v struct {
		Stat int    `json:"status"`
		Msg  string `json:"message"`
	}
	switch e := erro.Unwrap(err).(type) {
	case *HttpStatusError:
		log.Err(e.Message())
		log.Debug(e)
		v.Stat = e.Status()
		v.Msg = e.Message()
	default:
		log.Err(e)
		log.Debug(err)
		v.Stat = http.StatusInternalServerError
		v.Msg = e.Error()
	}

	buff, err := json.Marshal(&v)
	if err != nil {
		err = erro.Wrap(err)
		log.Err(erro.Unwrap(err))
		log.Debug(err)
		// 最後の手段。たぶん正しい変換。
		buff = []byte(`{status="` + JsonStringEscape(strconv.Itoa(v.Stat)) +
			`",message="` + JsonStringEscape(v.Msg) + `"}`)
	}

	w.Header().Set("Content-Type", ContentTypeJson)
	w.Header().Set("Content-Length", strconv.Itoa(len(buff)))
	w.WriteHeader(v.Stat)
	if _, err := w.Write(buff); err != nil {
		err = erro.Wrap(err)
		log.Err(erro.Unwrap(err))
		log.Debug(err)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"filepicker"
	"fmt"
	"getcommandline"
	"hash"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"tokenize"
)

/*
  REVISION HISTORY
  ----------------
   6 Apr 13 -- First modified version of module.  I will use VLI to compare all digits of the hashes.
  23 Apr 13 -- Fixed problem of a single line in the hashes file, that does not contain an EOL character, causes
                an immediate return without processing of the characters just read in.
  24 Apr 13 -- Added output of which file either matches or does not match.
  19 Sep 16 -- Finished conversion to Go, that was started 13 Sep 16.  Added the removed of '*' which is part of a std linux formated hash file.  And I forgot that
                 the routine allowed either order in the file.  If the token has a '.' I assume it is a filename, else it is a hash value.
  21 Sep 16 -- Fixed the case issue in tokenize.GetToken.  Edited code here to correspond to this fix.
  25 Nov 16 -- Need to not panic when target file is not found, only panic when hash file is not found.
                 And added a LastCompiled message and string.
  13 Oct 17 -- No changes here, but tokenize was changed so that horizontal tab char is now a delim.
  14 Oct 17 -- Tweaked output a bit.  And added executable timestamp code.
  19 Oct 17 -- Added ability to ignore the * that standard hash files for linux use.
  22 Oct 17 -- Added filepicker.
  21 Jan 18 -- Really ignore *.  Before method did not work.
  26 Jan 18 -- Changed tokenize so that SetMapDelim change sticks.
  13 Nov 18 -- Will use "-" and "_" also to detech a filename token.
  10 Nov 19 -- Now uses ToLower to compare the string hashes, to ignore case.
  15 Jul 20 -- Decided to make better guesses.  Sha1 has 40 digits, Sha256 has 64 digits and Sha512 has 128 digits.
*/

const LastCompiled = "15 July 2020"

//* ************************* MAIN ***************************************************************
func main() {

	const K = 1024
	const M = 1024 * 1024

	const (
		undetermined = iota
		md5hash
		sha1hash
		sha256hash
		sha384hash
		sha512hash
	)

	const ReadBufferSize = M

	var HashName = [...]string{"undetermined", "md5", "sha1", "sha256", "sha384", "sha512"}
	var inbuf, ans, Filename string
	var WhichHash int
	var readErr error
	var TargetFilename, HashValueReadFromFile, HashValueComputedStr string
	var hasher hash.Hash
	var FileSize int64

	fmt.Print(" comparehashes written in Go.  GOOS =", runtime.GOOS, ".  ARCH=", runtime.GOARCH)

	fmt.Println(".  Last altered", LastCompiled)
	//            fmt.Println(".  HashType = md5, sha1, sha256, sha384, sha512.  WhichHash = ",HashName[WhichHash]);
	workingdir, _ := os.Getwd()
	execname, _ := os.Executable()
	ExecFI, _ := os.Stat(execname)
	LastLinkedTimeStamp := ExecFI.ModTime().Format("Mon Jan 2 2006 15:04:05 MST")
	fmt.Printf("%s has timestamp of %s.  Working directory is %s.  Full name of executable is %s.\n", ExecFI.Name(), LastLinkedTimeStamp, workingdir, execname)
	fmt.Println()

	// filepicker stuff.

	if len(os.Args) <= 1 { // need to use filepicker
		filenames := filepicker.GetFilenames("*.sha*")
		for i := 0; i < min(len(filenames), 10); i++ {
			fmt.Println("filename[", i, "] is", filenames[i])
		}
		fmt.Print(" Enter filename choice : ")
		fmt.Scanln(&ans)
		if len(ans) == 0 {
			ans = "0"
		}
		i, err := strconv.Atoi(ans)
		if err == nil {
			Filename = filenames[i]
		} else {
			s := strings.ToUpper(ans)
			s = strings.TrimSpace(s)
			s0 := s[0]
			i = int(s0 - 'A')
			Filename = filenames[i]
		}
		fmt.Println(" Picked filename is", Filename)
	} else { // will use filename entered on commandline
		Filename = getcommandline.GetCommandLineString()
	}

	fmt.Println()

	// process extension

	extension := filepath.Ext(Filename)
	extension = strings.ToLower(extension)
	switch extension {
	case ".md5":
		WhichHash = md5hash
	case ".sha1":
		WhichHash = sha1hash
	case ".sha256":
		WhichHash = sha256hash
	case ".sha384":
		WhichHash = sha384hash
	case ".sha512":
		WhichHash = sha512hash
	default:
		fmt.Println()
		fmt.Println()
		fmt.Println(" Not a recognized hash extension.  Will determine by hash length.")
		//WhichHash = sha256hash
	} // switch case on extension for HashType

	fmt.Println()

	// Read and parse the file with the hashes.

	HashesFile, err := os.Open(Filename)
	if os.IsNotExist(err) {
		fmt.Println(inbuf, " does not exist.")
		os.Exit(1)
	} else { // we know that the file exists
		check(err, " Error opening hashes file.")
	}
	defer HashesFile.Close()

	scanner := bufio.NewScanner(HashesFile)
	//	scanner.Split(bufio.ScanLines) // I believe this is the default.  I may experiment to see if I need this line for my code to work, AFTER I debug it as it is.

	for { /* to read multiple lines */
		FileSize = 0
		readSuccess := scanner.Scan()
		if !readSuccess {
			break
		} // end main reading loop

		inputline := scanner.Text()
		if readErr = scanner.Err(); readErr != nil {
			if readErr == io.EOF {
				break
			} // reached EOF condition, so there are no more lines to read.
			fmt.Fprintln(os.Stderr, "Unknown error while reading from the HashesFile :", readErr)
			os.Exit(1)
		}

		if strings.HasPrefix(inputline, ";") || strings.HasPrefix(inputline, "#") || (len(inputline) <= 10) {
			continue
		} /* allow comments and essentially blank lines */

		//	inputline = strings.Replace(inputline, "*", " ", -1) // just blank out the * char
		tokenize.INITKN(inputline)

		tokenize.SetMapDelim('*') // this should now work, as of 01/26/2018

		FirstToken, EOL := tokenize.GetTokenString(false)

		if EOL {
			fmt.Println(" EOL or other Error while getting 1st token in the hashing file.  Skipping to next line.")
			continue
		}
		hashlength := 0

		if strings.ContainsRune(FirstToken.Str, '.') || strings.ContainsRune(FirstToken.Str, '-') ||
			strings.ContainsRune(FirstToken.Str, '_') { /* have filename first on line */
			TargetFilename = FirstToken.Str
			SecondToken, EOL := tokenize.GetTokenString(false) // Get hash string from the line in the file
			if EOL {
				fmt.Println(" Got EOL while getting HashValue (2nd) token in the hashing file.  Skipping")
				continue
			} /* if EOL */
			HashValueReadFromFile = SecondToken.Str
			hashlength = len(SecondToken.Str)

		} else { /* have hash first on line */
			HashValueReadFromFile = FirstToken.Str
			hashlength = len(FirstToken.Str)
			SecondToken, EOL := tokenize.GetTokenString(false) // Get name of file on which to compute the hash
			if EOL {
				fmt.Println(" Error while gatting TargetFilename token in the hashing file.  Skipping")
				continue
			} /* if EOL */

			if strings.ContainsRune(SecondToken.Str, '*') { // If it contains a *, it will be the first position.
				SecondToken.Str = SecondToken.Str[1:]
				if strings.ContainsRune(SecondToken.Str, '*') { // this should not happen
					fmt.Println(" Filename token still contains a * character.  Str:", SecondToken.Str, "  Skipping.")
					continue
				}
			}
			TargetFilename = (SecondToken.Str)
		} /* if have filename first or hash value first */

		/*
		   now to compute the hash, compare them, and output results
		*/
		/* Create Hash Section */
		TargetFile, err := os.Open(TargetFilename)
		//    exists := true;
		if os.IsNotExist(err) {
			fmt.Println(TargetFilename, " does not exist.")
			continue
		} else { // we know that the file exists
			check(err, " Error opening TargetFilename.")
		}

		defer TargetFile.Close()

		if WhichHash == undetermined {
			if hashlength == 64 {
				WhichHash = sha256hash
			} else if hashlength == 128 {
				WhichHash = sha512hash
			} else {
				WhichHash = sha1hash
			}
			fmt.Println(" hash determined by length to be", HashName[WhichHash])
			fmt.Println()
		}

		switch WhichHash { // Initialing case switch on WhichHash
		case md5hash:
			hasher = md5.New()
		case sha1hash:
			hasher = sha1.New()
		case sha256hash:
			hasher = sha256.New()
		case sha384hash:
			hasher = sha512.New384()
		case sha512hash:
			hasher = sha512.New()
		default:
			hasher = sha256.New()
		} /* initializing switch case on WhichHash */

		/*    This loop works, but there is a much shorter way.  I got this after asking for help on the mailing list.
		      FileReadBuffer := make([]byte,ReadBufferSize);
		      for {   // Repeat Until eof loop.
		        n,err := TargetFile.Read(FileReadBuffer);
		        if n == 0 || err == io.EOF { break }
		        check(err," Unexpected error while reading the target file on which to compute the hash,");
		        hasher.Write(FileReadBuffer[:n]);
		        FileSize += int64(n);
		      } // Repeat Until TargetFile.eof loop;
		*/

		FileSize, readErr = io.Copy(hasher, TargetFile)
		HashValueComputedStr = hex.EncodeToString(hasher.Sum(nil))

		// I got the idea to use the different base64 versions and my own hex converter code, just to see.
		// And I can also use sfprintf with the %x verb.  base64 versions are not useful as they use a larger
		// character set than hex.  I deleted all references to the base64 versions.  And the hex encoded and
		// sprintf using %x were the same, so I removed the sprintf code.
		//    HashValueComputedSprintf := fmt.Sprintf("%x",hasher.Sum(nil));

		//		fmt.Println(" Filename  = ", TargetFilename, ", FileSize = ", FileSize, ", ", HashName[WhichHash], " computed hash string -- ")
		fmt.Printf(" Filename  = %s, filesize = %d, using hash %s.\n", TargetFilename, FileSize, HashName[WhichHash])
		fmt.Println("       Read From File:", HashValueReadFromFile)
		fmt.Println(" Computed hex encoded:", HashValueComputedStr)
		//    fmt.Println(" Computed sprintf:",HashValueComputedSprintf);

		if strings.ToLower(HashValueReadFromFile) == strings.ToLower(HashValueComputedStr) {
			fmt.Print(" Matched.")
		} else {
			fmt.Print(" Not matched.")
		} /* if hashes */
		TargetFile.Close() // Close the handle to allow opening a target from the next line, if there is one.
		fmt.Println()
		fmt.Println()
		fmt.Println()
	} /* outer LOOP to read multiple lines */

	HashesFile.Close() // Don't really need this because of the defer statement.
	fmt.Println()
} // Main for comparehashes.go.

// ------------------------------------------------------- check -------------------------------
func check(e error, msg string) {
	if e != nil {
		fmt.Println(msg)
		panic(e)
	}
}

// ------------------------------------------------------- min ---------------------------------
func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}
<commit_msg>09/27/2020 09:17:42 AM comparehashes/comparehashes.go -- recognizes md5 and sha384 by length<commit_after>package main

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"filepicker"
	"fmt"
	"getcommandline"
	"hash"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"tknptr"
)

/*
  REVISION HISTORY
  ----------------
   6 Apr 13 -- First modified version of module.  I will use VLI to compare all digits of the hashes.
  23 Apr 13 -- Fixed problem of a single line in the hashes file, that does not contain an EOL character, causes
                an immediate return without processing of the characters just read in.
  24 Apr 13 -- Added output of which file either matches or does not match.
  19 Sep 16 -- Finished conversion to Go, that was started 13 Sep 16.  Added the removed of '*' which is part of a std linux formated hash file.  And I forgot that
                 the routine allowed either order in the file.  If the token has a '.' I assume it is a filename, else it is a hash value.
  21 Sep 16 -- Fixed the case issue in tokenize.GetToken.  Edited code here to correspond to this fix.
  25 Nov 16 -- Need to not panic when target file is not found, only panic when hash file is not found.
                 And added a LastCompiled message and string.
  13 Oct 17 -- No changes here, but tokenize was changed so that horizontal tab char is now a delim.
  14 Oct 17 -- Tweaked output a bit.  And added executable timestamp code.
  19 Oct 17 -- Added ability to ignore the * that standard hash files for linux use.
  22 Oct 17 -- Added filepicker.
  21 Jan 18 -- Really ignore *.  Before method did not work.
  26 Jan 18 -- Changed tokenize so that SetMapDelim change sticks.
  13 Nov 18 -- Will use "-" and "_" also to detech a filename token.
  10 Nov 19 -- Now uses ToLower to compare the string hashes, to ignore case.
  15 Jul 20 -- Decided to make better guesses.  Sha1 has 40 digits, Sha256 has 64 digits and Sha512 has 128 digits.
  27 Sep 20 -- From help file of TakeCommand: MD-5 has 32 digits, SHA384 has 96 digits, and the lengths of Sha256 and Sha512 are correct.
                 And I'm going to change from tokenize to tknptr.  Just to see if it works.
*/

const LastCompiled = "27 Sep 2020"

//* ************************* MAIN ***************************************************************
func main() {

	const K = 1024
	const M = 1024 * 1024

	const (
		undetermined = iota
		md5hash
		sha1hash
		sha256hash
		sha384hash
		sha512hash
	)

	const ReadBufferSize = M

	var HashName = [...]string{"undetermined", "md5", "sha1", "sha256", "sha384", "sha512"}
	var inbuf, ans, Filename string
	var WhichHash int
	var readErr error
	var TargetFilename, HashValueReadFromFile, HashValueComputedStr string
	var hasher hash.Hash
	var FileSize int64

	fmt.Print(" comparehashes written in Go.  GOOS =", runtime.GOOS, ".  ARCH=", runtime.GOARCH)

	fmt.Println(".  Last altered", LastCompiled)
	//            fmt.Println(".  HashType = md5, sha1, sha256, sha384, sha512.  WhichHash = ",HashName[WhichHash]);
	workingdir, _ := os.Getwd()
	execname, _ := os.Executable()
	ExecFI, _ := os.Stat(execname)
	LastLinkedTimeStamp := ExecFI.ModTime().Format("Mon Jan 2 2006 15:04:05 MST")
	fmt.Printf("%s has timestamp of %s.  Working directory is %s.  Full name of executable is %s.\n", ExecFI.Name(), LastLinkedTimeStamp, workingdir, execname)
	fmt.Println()

	// filepicker stuff.

	if len(os.Args) <= 1 { // need to use filepicker
		filenames := filepicker.GetFilenames("*.sha*")
		for i := 0; i < min(len(filenames), 10); i++ {
			fmt.Println("filename[", i, "] is", filenames[i])
		}
		fmt.Print(" Enter filename choice : ")
		fmt.Scanln(&ans)
		if len(ans) == 0 {
			ans = "0"
		}
		i, err := strconv.Atoi(ans)
		if err == nil {
			Filename = filenames[i]
		} else {
			s := strings.ToUpper(ans)
			s = strings.TrimSpace(s)
			s0 := s[0]
			i = int(s0 - 'A')
			Filename = filenames[i]
		}
		fmt.Println(" Picked filename is", Filename)
	} else { // will use filename entered on commandline
		Filename = getcommandline.GetCommandLineString()
	}

	fmt.Println()

	// process extension

	extension := filepath.Ext(Filename)
	extension = strings.ToLower(extension)
	switch extension {
	case ".md5":
		WhichHash = md5hash
	case ".sha1":
		WhichHash = sha1hash
	case ".sha256":
		WhichHash = sha256hash
	case ".sha384":
		WhichHash = sha384hash
	case ".sha512":
		WhichHash = sha512hash
	default:
		fmt.Println()
		fmt.Println()
		fmt.Println(" Not a recognized hash extension.  Will determine by hash length.")
	} // switch case on extension for HashType

	fmt.Println()

	// Read and parse the file with the hashes.

	HashesFile, err := os.Open(Filename)
	if os.IsNotExist(err) {
		fmt.Println(inbuf, " does not exist.")
		os.Exit(1)
	} else { // we know that the file exists
		check(err, " Error opening hashes file.")
	}
	defer HashesFile.Close()

	scanner := bufio.NewScanner(HashesFile)
	//	scanner.Split(bufio.ScanLines)  This is the default.  I may experiment to see if I need this line for my code to work, AFTER I debug it as it is.

	for { /* to read multiple lines */
		FileSize = 0
		readSuccess := scanner.Scan()
		if !readSuccess {
			break
		} // end main reading loop

		inputline := scanner.Text()
		if readErr = scanner.Err(); readErr != nil {
			if readErr == io.EOF {
				break
			} // reached EOF condition, so there are no more lines to read.
			fmt.Fprintln(os.Stderr, "Unknown error while reading from the HashesFile :", readErr)
			os.Exit(1)
		}

		if strings.HasPrefix(inputline, ";") || strings.HasPrefix(inputline, "#") || (len(inputline) <= 10) {
			continue
		} /* allow comments and essentially blank lines */

		//	inputline = strings.Replace(inputline, "*", " ", -1) // just blank out the * char
		//tokenize.INITKN(inputline)
		tokenPtr := tknptr.INITKN(inputline) // I need to declare a pointer receiver, not like the static tokenize rtn.

		//tokenize.SetMapDelim('*') // this should now work, as of 01/26/2018
		tokenPtr.SetMapDelim('*')

		FirstToken, EOL := tokenPtr.GetTokenString(false)

		if EOL {
			fmt.Println(" EOL or other Error while getting 1st token in the hashing file.  Skipping to next line.")
			continue
		}
		hashlength := 0

		if strings.ContainsRune(FirstToken.Str, '.') || strings.ContainsRune(FirstToken.Str, '-') ||
			strings.ContainsRune(FirstToken.Str, '_') { // have filename first on line
			TargetFilename = FirstToken.Str
			SecondToken, EOL := tokenPtr.GetTokenString(false) // Get hash string from the line in the file
			if EOL {
				fmt.Println(" Got EOL while getting HashValue (2nd) token in the hashing file.  Skipping")
				continue
			} /* if EOL */
			HashValueReadFromFile = SecondToken.Str
			hashlength = len(SecondToken.Str)

		} else { /* have hash first on line */
			HashValueReadFromFile = FirstToken.Str
			hashlength = len(FirstToken.Str)
			SecondToken, EOL := tokenPtr.GetTokenString(false) // Get name of file on which to compute the hash
			if EOL {
				fmt.Println(" Error while gatting TargetFilename token in the hashing file.  Skipping")
				continue
			} /* if EOL */

			if strings.ContainsRune(SecondToken.Str, '*') { // If it contains a *, it will be the first position.
				SecondToken.Str = SecondToken.Str[1:]
				if strings.ContainsRune(SecondToken.Str, '*') { // this should not happen
					fmt.Println(" Filename token still contains a * character.  Str:", SecondToken.Str, "  Skipping.")
					continue
				}
			}
			TargetFilename = (SecondToken.Str)
		} /* if have filename first or hash value first */

		/*
		   now to compute the hash, compare them, and output results
		*/
		/* Create Hash Section */
		TargetFile, err := os.Open(TargetFilename)
		//    exists := true;
		if os.IsNotExist(err) {
			fmt.Println(TargetFilename, " does not exist.")
			continue
		} else { // we know that the file exists
			check(err, " Error opening TargetFilename.")
		}

		defer TargetFile.Close()

		if WhichHash == undetermined {
			if hashlength == 64 {
				WhichHash = sha256hash
			} else if hashlength == 128 {
				WhichHash = sha512hash
			} else if hashlength == 40 {
				WhichHash = sha1hash
			} else if hashlength == 96 {
				WhichHash = sha384hash
			} else if hashlength == 32 {
				WhichHash = md5hash
			} else {
				fmt.Fprintln(os.Stderr, " Could not determine hash type for file.  Exiting.")
				os.Exit(1)
			}
			fmt.Println(" hash determined by length to be", HashName[WhichHash])
			fmt.Println()
		}

		switch WhichHash { // Initialing case switch on WhichHash
		case md5hash:
			hasher = md5.New()
		case sha1hash:
			hasher = sha1.New()
		case sha256hash:
			hasher = sha256.New()
		case sha384hash:
			hasher = sha512.New384()
		case sha512hash:
			hasher = sha512.New()
		default:
			hasher = sha256.New()
		} /* initializing switch case on WhichHash */

		/*    This loop works, but there is a much shorter way.  I got this after asking for help on the mailing list.
		      FileReadBuffer := make([]byte,ReadBufferSize);
		      for {   // Repeat Until eof loop.
		        n,err := TargetFile.Read(FileReadBuffer);
		        if n == 0 || err == io.EOF { break }
		        check(err," Unexpected error while reading the target file on which to compute the hash,");
		        hasher.Write(FileReadBuffer[:n]);
		        FileSize += int64(n);
		      } // Repeat Until TargetFile.eof loop;
		*/

		FileSize, readErr = io.Copy(hasher, TargetFile)
		HashValueComputedStr = hex.EncodeToString(hasher.Sum(nil))

		// I got the idea to use the different base64 versions and my own hex converter code, just to see.
		// And I can also use sfprintf with the %x verb.  base64 versions are not useful as they use a larger
		// character set than hex.  I deleted all references to the base64 versions.  And the hex encoded and
		// sprintf using %x were the same, so I removed the sprintf code.
		//    HashValueComputedSprintf := fmt.Sprintf("%x",hasher.Sum(nil));

		//		fmt.Println(" Filename  = ", TargetFilename, ", FileSize = ", FileSize, ", ", HashName[WhichHash], " computed hash string -- ")
		fmt.Printf(" Filename  = %s, filesize = %d, using hash %s.\n", TargetFilename, FileSize, HashName[WhichHash])
		fmt.Println("       Read From File:", HashValueReadFromFile)
		fmt.Println(" Computed hex encoded:", HashValueComputedStr)
		//    fmt.Println(" Computed sprintf:",HashValueComputedSprintf);

		if strings.ToLower(HashValueReadFromFile) == strings.ToLower(HashValueComputedStr) {
			fmt.Print(" Matched.")
		} else {
			fmt.Print(" Not matched.")
		} /* if hashes */
		TargetFile.Close() // Close the handle to allow opening a target from the next line, if there is one.
		fmt.Println()
		fmt.Println()
		fmt.Println()
	} /* outer LOOP to read multiple lines */

	HashesFile.Close() // Don't really need this because of the defer statement.
	fmt.Println()
} // Main for comparehashes.go.

// ------------------------------------------------------- check -------------------------------
func check(e error, msg string) {
	if e != nil {
		fmt.Println(msg)
		panic(e)
	}
}

// ------------------------------------------------------- min ---------------------------------
func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/vlad-doru/fuzzyguy/fuzzy"
	"net/http"
)

var stores = map[string]*

func FuzzyHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		fmt.Fprintf(w, "Hi there, GET!")
	case "POST":
		fmt.Fprintf(w, "Hi there, POST!")
	case "PUT":
		fmt.Fprintf(w, "Hi there, PUT!")
	case "DELETE":
		fmt.Fprintf(w, "Hi there, DELETE!")
	default:
		http.Error(w, http.StatusText(405), 405)
	}
}

func main() {
	http.HandleFunc("/fuzzy", FuzzyHandler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Added a HTTP server in order to interact with the fuzzy service<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/vlad-doru/fuzzyguy/fuzzy"
	"net/http"
	"strconv"
)

var stores map[string]*fuzzy.FuzzyService = make(map[string]*fuzzy.FuzzyService)

func FuzzyHandler(w http.ResponseWriter, r *http.Request) {
	storeName := r.FormValue("store")
	if len(storeName) == 0 {
		http.Error(w, "Please provide the store name", http.StatusBadRequest)
		return
	}
	store, present := stores[storeName]
	if !present {
		if r.Method != "POST" {
			http.Error(w, "Please provide an existent store name", http.StatusBadRequest)
			return
		}
		stores[storeName] = fuzzy.NewFuzzyService()
		fmt.Fprintf(w, "Store has successfully been created")
		w.WriteHeader(http.StatusCreated)
		return
	}

	if r.Method == "POST" {
		http.Error(w, "This store already exists", http.StatusBadRequest)
		return
	}

	key := r.FormValue("key")
	if len(key) == 0 {
		http.Error(w, "Please provide a key parameter", http.StatusBadRequest)
		return
	}

	switch r.Method {
	case "GET":
		distance, err := strconv.Atoi(r.FormValue("distance"))
		if err != nil {
			http.Error(w, "Please provide a distance parameter", http.StatusBadRequest)
			return
		}
		if distance == 0 {
			value, present := store.Get(key)
			if !present {
				http.Error(w, "Key does not exist", http.StatusBadRequest)
				return
			}
			fmt.Fprintf(w, value)
			return
		}
		results, err := strconv.Atoi(r.FormValue("results"))
		if err != nil {
			http.Error(w, "Please provide a results parameter", http.StatusBadRequest)
			return
		}
		fuzzy_results := store.Query(key, distance, results)
		json_response, _ := json.Marshal(fuzzy_results)
		fmt.Fprintf(w, string(json_response))

	case "PUT":
		value := r.FormValue("value")
		if len(value) == 0 {
			http.Error(w, "Please provide a value parameter", http.StatusBadRequest)
			return
		}
		store.Set(key, value)
		fmt.Fprintf(w, "Successfully set the key")
	case "DELETE":
		deleted := store.Delete(key)
		if deleted {
			fmt.Fprintf(w, "Successfully deleted the key")
		} else {
			http.Error(w, "The key you deleted does not exist", http.StatusBadRequest)
		}
	default:
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
	}
}

func main() {
	http.HandleFunc("/fuzzy", FuzzyHandler)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>// package compatibility contains a bunch of tests to make sure that
// compatibility has been preserved with previous versions.
package compatibility
<commit_msg>Remove the compatibility package since it is of no use anymore<commit_after><|endoftext|>