<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/s-aska/anaconda"
	"strings"
	"sync"
	"time"
)
import _ "github.com/go-sql-driver/mysql"

var m = new(sync.Mutex)
var d = map[string]chan bool{}

func disconnect(id string) {
	m.Lock()
	defer m.Unlock()

	ch, ok := d[id]
	if ok {
		ch <- true
	}
}

func cleanup(id string) {
	m.Lock()
	defer m.Unlock()

	ch, ok := d[id]
	if ok {
		close(ch)
		delete(d, id)
	}

	fmt.Printf("[%s] cleanup\n", id)
}

func connect(id string) {
	m.Lock()
	defer m.Unlock()

	_, ok := d[id]
	if ok {
		return
	}

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtOut, err := db.Prepare("SELECT access_token, access_token_secret FROM account WHERE user_id = ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtOut.Close()

	var accessToken string
	var accessTokenSecret string

	err = stmtOut.QueryRow(id).Scan(&accessToken, &accessTokenSecret)

	fmt.Printf("[%s] accessToken:%s accessTokenSecret:%s\n", id, accessToken, accessTokenSecret)

	ch := make(chan bool)
	d[id] = ch
	go connectStream(ch, id, accessToken, accessTokenSecret)
}

func connectStream(ch <-chan bool, id string, accessToken string, accessTokenSecret string) {
	api := anaconda.NewTwitterApi(accessToken, accessTokenSecret)
	api.SetLogger(anaconda.BasicLogger)
	s := api.UserStream(nil)
	fmt.Printf("[%s] connect\n", id)
	for {
		select {
		case x, ok := <-s.C:
			if !ok {
				fmt.Printf("[%s] disconnect\n", id)
				s.Stop()
				cleanup(id)
				return
			}
			switch data := x.(type) {

			case anaconda.FriendsList:
				// pass

			case anaconda.Tweet:
				// fmt.Printf("[%s] status: @%s `%s`\n", id, data.User.ScreenName, data.Text)
				if data.RetweetedStatus != nil && data.RetweetedStatus.User.IdStr == id {
					go createActivityWithReferenceId(
						id,
						data.RetweetedStatus.IdStr,
						"retweet",
						data.User.IdStr,
						data.IdStr,
						encodeJson(data))
				} else if data.InReplyToUserIdStr == id {
					go createActivityWithReferenceId(
						id,
						data.InReplyToStatusIdStr,
						"reply",
						data.User.IdStr,
						data.IdStr,
						encodeJson(data))
				}

			case anaconda.DirectMessage:
				// fmt.Printf("[%s] message: @%s => @%s `%s`\n", id, data.SenderScreenName, data.RecipientScreenName, data.Text)

			case anaconda.StatusDeletionNotice:
				// fmt.Printf("[%s] status delete: %s:%s\n", id, data.UserIdStr, data.IdStr)
				go deleteActivityByStatusId(data.IdStr)
				go deleteActivityByReferenceId(data.IdStr)

			case anaconda.DirectMessageDeletionNotice:
				// fmt.Printf("[%s] message delete: %s:%s\n", id, data.UserId, data.IdStr)

			case anaconda.EventTweet:

				if data.Event.Event == "quoted_tweet" && data.TargetObject.QuotedStatus.User.IdStr == id {
					go createActivityWithReferenceId(
						id,
						data.TargetObject.QuotedStatus.IdStr,
						data.Event.Event,
						data.Event.Source.IdStr,
						data.TargetObject.IdStr,
						encodeJson(data))

				} else if data.TargetObject.User.IdStr == id {

					if data.Event.Event == "favorite" || data.Event.Event == "favorited_retweet" || data.Event.Event == "retweeted_retweet" {
						go createReactionActivity(
							id,
							data.TargetObject.IdStr,
							data.Event.Event,
							data.Event.Source.IdStr,
							encodeJson(data))

					} else if data.Event.Event == "unfavorite" {
						go deleteReactionActivity(
							data.TargetObject.IdStr,
							data.Event.Event,
							data.Event.Source.IdStr)
					}
				}

			case anaconda.EventList:
				fmt.Printf("[%s] eventList: %s %s\n", id, data.Event.Event, encodeJson(data))

			case anaconda.Event:
				fmt.Printf("[%s] event: %s %s\n", id, data.Event, encodeJson(data))

			case anaconda.DisconnectMessage:
				fmt.Printf("[%s] disconnectMessage\n", id)
				s.Stop()
				cleanup(id)

			default:
				fmt.Printf("[%s] unknown type(%T) : %v\n", id, x, x)
			}
		case <-ch:
			fmt.Printf("[%s] stop\n", id)
			s.Stop()
			cleanup(id)
			return
		}
	}
}

func encodeJson(d interface{}) (j string) {
	b, _ := json.Marshal(d)
	return string(b)
}

func createActivity(userId string, uniqueId string, data string) {
	fmt.Printf("[%s] createActivity: %s\n", userId, uniqueId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtIns, err := db.Prepare(`
		INSERT IGNORE INTO activity(
			user_id,
			unique_id,
			data,
			created_on
		) VALUES(?, ?, ?, ?)
	`)
	if err != nil {
		panic(err.Error())
	}
	defer stmtIns.Close()

	_, err = stmtIns.Exec(userId, uniqueId, data, time.Now().Unix())
	if err != nil {
		panic(err.Error())
	}
}

func createReactionActivity(userId string, statusId string, event string, sourceUserId string, data string) {
	createActivity(userId, strings.Join([]string{"status", statusId, event, sourceUserId}, ":"), data)
}

func deleteReactionActivity(statusId string, event string, sourceUserId string) {
	deleteActivity(strings.Join([]string{"status", statusId, event, sourceUserId}, ":"))
}

func deleteActivity(uniqueId string) {
	fmt.Printf("[%s] deleteActivity: %s\n", "-", uniqueId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	ope := "="
	if strings.HasSuffix(uniqueId, "%") {
		ope = "LIKE"
	}

	stmtDel, err := db.Prepare("DELETE FROM activity WHERE unique_id " + ope + " ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtDel.Close()

	_, err = stmtDel.Exec(uniqueId)
	if err != nil {
		panic(err.Error())
	}
}

func deleteActivityByStatusId(statusId string) {
	deleteActivity(strings.Join([]string{"status", statusId, "%"}, ":"))
}

func createActivityWithReferenceId(userId string, statusId string, event string, sourceUserId string, referenceId string, data string) {
	uniqueId := strings.Join([]string{"status", statusId, event, sourceUserId}, ":")
	fmt.Printf("[%s] createActivityWithReferenceId: %s %s\n", userId, uniqueId, referenceId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtIns, err := db.Prepare(`
		INSERT IGNORE INTO activity(
			user_id,
			unique_id,
			reference_id,
			data,
			created_on
		) VALUES(?, ?, ?, ?, ?)
	`)
	if err != nil {
		panic(err.Error())
	}
	defer stmtIns.Close()

	_, err = stmtIns.Exec(userId, uniqueId, referenceId, data, time.Now().Unix())
	if err != nil {
		panic(err.Error())
	}
}

func deleteActivityByReferenceId(referenceId string) {
	fmt.Printf("[%s] deleteActivityByReferenceId: %s\n", "-", referenceId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtDel, err := db.Prepare("DELETE FROM activity WHERE reference_id = ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtDel.Close()

	_, err = stmtDel.Exec(referenceId)
	if err != nil {
		panic(err.Error())
	}
}
<commit_msg>Can multi reply<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/s-aska/anaconda"
	"strings"
	"sync"
	"time"
)
import _ "github.com/go-sql-driver/mysql"

var m = new(sync.Mutex)
var d = map[string]chan bool{}

func disconnect(id string) {
	m.Lock()
	defer m.Unlock()

	ch, ok := d[id]
	if ok {
		ch <- true
	}
}

func cleanup(id string) {
	m.Lock()
	defer m.Unlock()

	ch, ok := d[id]
	if ok {
		close(ch)
		delete(d, id)
	}

	fmt.Printf("[%s] cleanup\n", id)
}

func connect(id string) {
	m.Lock()
	defer m.Unlock()

	_, ok := d[id]
	if ok {
		return
	}

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtOut, err := db.Prepare("SELECT access_token, access_token_secret FROM account WHERE user_id = ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtOut.Close()

	var accessToken string
	var accessTokenSecret string

	err = stmtOut.QueryRow(id).Scan(&accessToken, &accessTokenSecret)

	fmt.Printf("[%s] accessToken:%s accessTokenSecret:%s\n", id, accessToken, accessTokenSecret)

	ch := make(chan bool)
	d[id] = ch
	go connectStream(ch, id, accessToken, accessTokenSecret)
}

func connectStream(ch <-chan bool, id string, accessToken string, accessTokenSecret string) {
	api := anaconda.NewTwitterApi(accessToken, accessTokenSecret)
	api.SetLogger(anaconda.BasicLogger)
	s := api.UserStream(nil)
	fmt.Printf("[%s] connect\n", id)
	for {
		select {
		case x, ok := <-s.C:
			if !ok {
				fmt.Printf("[%s] disconnect\n", id)
				s.Stop()
				cleanup(id)
				return
			}
			switch data := x.(type) {

			case anaconda.FriendsList:
				// pass

			case anaconda.Tweet:
				// fmt.Printf("[%s] status: @%s `%s`\n", id, data.User.ScreenName, data.Text)
				if data.RetweetedStatus != nil && data.RetweetedStatus.User.IdStr == id {
					go createActivityWithReferenceId(
						id,
						data.RetweetedStatus.IdStr,
						"retweet",
						data.User.IdStr,
						data.IdStr,
						encodeJson(data))
				} else if data.InReplyToUserIdStr == id {
					go createActivityWithReferenceId(
						id,
						data.InReplyToStatusIdStr,
						"reply",
						data.IdStr,
						data.IdStr,
						encodeJson(data))
				}

			case anaconda.DirectMessage:
				// fmt.Printf("[%s] message: @%s => @%s `%s`\n", id, data.SenderScreenName, data.RecipientScreenName, data.Text)

			case anaconda.StatusDeletionNotice:
				// fmt.Printf("[%s] status delete: %s:%s\n", id, data.UserIdStr, data.IdStr)
				go deleteActivityByStatusId(data.IdStr)
				go deleteActivityByReferenceId(data.IdStr)

			case anaconda.DirectMessageDeletionNotice:
				// fmt.Printf("[%s] message delete: %s:%s\n", id, data.UserId, data.IdStr)

			case anaconda.EventTweet:

				if data.Event.Event == "quoted_tweet" && data.TargetObject.QuotedStatus.User.IdStr == id {
					go createActivityWithReferenceId(
						id,
						data.TargetObject.QuotedStatus.IdStr,
						data.Event.Event,
						data.Event.Source.IdStr,
						data.TargetObject.IdStr,
						encodeJson(data))

				} else if data.TargetObject.User.IdStr == id {

					if data.Event.Event == "favorite" || data.Event.Event == "favorited_retweet" || data.Event.Event == "retweeted_retweet" {
						go createReactionActivity(
							id,
							data.TargetObject.IdStr,
							data.Event.Event,
							data.Event.Source.IdStr,
							encodeJson(data))

					} else if data.Event.Event == "unfavorite" {
						go deleteReactionActivity(
							data.TargetObject.IdStr,
							data.Event.Event,
							data.Event.Source.IdStr)
					}
				}

			case anaconda.EventList:
				fmt.Printf("[%s] eventList: %s %s\n", id, data.Event.Event, encodeJson(data))

			case anaconda.Event:
				fmt.Printf("[%s] event: %s %s\n", id, data.Event, encodeJson(data))

			case anaconda.DisconnectMessage:
				fmt.Printf("[%s] disconnectMessage\n", id)
				s.Stop()
				cleanup(id)

			default:
				fmt.Printf("[%s] unknown type(%T) : %v\n", id, x, x)
			}
		case <-ch:
			fmt.Printf("[%s] stop\n", id)
			s.Stop()
			cleanup(id)
			return
		}
	}
}

func encodeJson(d interface{}) (j string) {
	b, _ := json.Marshal(d)
	return string(b)
}

func createActivity(userId string, uniqueId string, data string) {
	fmt.Printf("[%s] createActivity: %s\n", userId, uniqueId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtIns, err := db.Prepare(`
		INSERT IGNORE INTO activity(
			user_id,
			unique_id,
			data,
			created_on
		) VALUES(?, ?, ?, ?)
	`)
	if err != nil {
		panic(err.Error())
	}
	defer stmtIns.Close()

	_, err = stmtIns.Exec(userId, uniqueId, data, time.Now().Unix())
	if err != nil {
		panic(err.Error())
	}
}

func createReactionActivity(userId string, statusId string, event string, sourceUserId string, data string) {
	createActivity(userId, strings.Join([]string{"status", statusId, event, sourceUserId}, ":"), data)
}

func deleteReactionActivity(statusId string, event string, sourceUserId string) {
	deleteActivity(strings.Join([]string{"status", statusId, event, sourceUserId}, ":"))
}

func deleteActivity(uniqueId string) {
	fmt.Printf("[%s] deleteActivity: %s\n", "-", uniqueId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	ope := "="
	if strings.HasSuffix(uniqueId, "%") {
		ope = "LIKE"
	}

	stmtDel, err := db.Prepare("DELETE FROM activity WHERE unique_id " + ope + " ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtDel.Close()

	_, err = stmtDel.Exec(uniqueId)
	if err != nil {
		panic(err.Error())
	}
}

func deleteActivityByStatusId(statusId string) {
	deleteActivity(strings.Join([]string{"status", statusId, "%"}, ":"))
}

func createActivityWithReferenceId(userId string, statusId string, event string, sourceUserId string, referenceId string, data string) {
	uniqueId := strings.Join([]string{"status", statusId, event, sourceUserId}, ":")
	fmt.Printf("[%s] createActivityWithReferenceId: %s %s\n", userId, uniqueId, referenceId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtIns, err := db.Prepare(`
		INSERT IGNORE INTO activity(
			user_id,
			unique_id,
			reference_id,
			data,
			created_on
		) VALUES(?, ?, ?, ?, ?)
	`)
	if err != nil {
		panic(err.Error())
	}
	defer stmtIns.Close()

	_, err = stmtIns.Exec(userId, uniqueId, referenceId, data, time.Now().Unix())
	if err != nil {
		panic(err.Error())
	}
}

func deleteActivityByReferenceId(referenceId string) {
	fmt.Printf("[%s] deleteActivityByReferenceId: %s\n", "-", referenceId)

	db, err := sql.Open("mysql", "root:@/justaway")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	stmtDel, err := db.Prepare("DELETE FROM activity WHERE reference_id = ?")
	if err != nil {
		panic(err.Error())
	}
	defer stmtDel.Close()

	_, err = stmtDel.Exec(referenceId)
	if err != nil {
		panic(err.Error())
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Ludovic Fauvet
// Licensed under the MIT license

package main

import (
	"bytes"
	"fmt"
	"github.com/op/go-logging"
	stdlog "log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	log     = logging.MustGetLogger("main")
	rlogger RuntimeLogger
	dlogger DownloadsLogger
)

type RuntimeLogger struct {
	f *os.File
}

type DownloadsLogger struct {
	sync.RWMutex
	l *stdlog.Logger
	f *os.File
}

// ReloadLogs will reopen the logs to allow rotations
func ReloadLogs() {
	ReloadRuntimeLogs()
	ReloadDownloadLogs()
}

func ReloadRuntimeLogs() {
	logging.SetFormatter(logging.MustStringFormatter("%{time:2006/01/02 15:04:05.000 MST} %{message}"))
	logFlags := 0

	if os.Getenv("DEBUG") != "" {
		logFlags = stdlog.Lshortfile
		logging.SetLevel(logging.DEBUG, "main")
	} else {
		logging.SetLevel(logging.INFO, "main")
	}

	logColor := true //TODO make it optionnal

	if rlogger.f != nil {
		rlogger.f.Close()
	} else {
		rlogger.f = os.Stderr
	}

	if runLog != "" {
		var err error
		rlogger.f, err = os.OpenFile(runLog, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Cannot open log file for writing")
			rlogger.f = os.Stderr
		} else {
			logColor = false
		}
	}

	logBackend := logging.NewLogBackend(rlogger.f, "", logFlags)
	logBackend.Color = logColor

	logging.SetBackend(logBackend)
}

func ReloadDownloadLogs() {
	dlogger.Lock()
	defer dlogger.Unlock()

	if GetConfig().LogDir == "" {
		if dlogger.f != nil {
			dlogger.f.Close()
		}
		dlogger.f = nil
		dlogger.l = nil
		return
	}

	logfile := GetConfig().LogDir + "/downloads.log"
	createHeader := true

	s, err := os.Stat(logfile)
	if err == nil && s.Size() > 0 {
		createHeader = false
	}

	if dlogger.f != nil {
		dlogger.f.Close()
	}
	dlogger.f, err = os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)

	if err != nil {
		log.Critical("Warning: cannot open log file %s", logfile)
		return
	}

	if createHeader {
		var buf bytes.Buffer
		hostname, _ := os.Hostname()
		fmt.Fprintf(&buf, "# Log file created at: %s\n", time.Now().Format("2006/01/02 15:04:05"))
		fmt.Fprintf(&buf, "# Running on machine: %s\n", hostname)
		fmt.Fprintf(&buf, "# Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
		dlogger.f.Write(buf.Bytes())
	}

	dlogger.l = stdlog.New(dlogger.f, "", stdlog.Ldate|stdlog.Lmicroseconds)
}

// This function will write a download result in the logs.
func logDownload(typ string, statuscode int, p *MirrorlistPage, err error) {
	dlogger.RLock()
	defer dlogger.RUnlock()

	if dlogger.l == nil {
		// Logs are disabled
		return
	}

	if statuscode == 302 || statuscode == 200 {
		var distance, countries string
		m := p.MirrorList[0]
		distance = strconv.FormatFloat(float64(m.Distance), 'f', 2, 32)
		countries = strings.Join(m.CountryFields, ",")
		fallback := ""
		if p.Fallback == true {
			fallback = " fallback:true"
		}
		sameASNum := ""
		if m.Asnum > 0 && m.Asnum == p.ClientInfo.ASNum {
			sameASNum = "same"
		}

		dlogger.l.Printf("%s %d \"%s\" ip:%s mirror:%s%s %sasn:%d distance:%skm countries:%s",
			typ, statuscode, p.FileInfo.Path, p.IP, m.ID, fallback, sameASNum, m.Asnum, distance, countries)
	} else if statuscode == 404 {
		dlogger.l.Printf("%s 404 \"%s\" %s", typ, p.FileInfo.Path, p.IP)
	} else if statuscode == 500 {
		mirrorID := "unknown"
		if len(p.MirrorList) > 0 {
			mirrorID = p.MirrorList[0].ID
		}
		dlogger.l.Printf("%s 500 \"%s\" ip:%s mirror:%s error:%s", typ, p.FileInfo.Path, p.IP, mirrorID, err.Error())
	} else {
		dlogger.l.Printf("%s %d \"%s\" ip:%s error:%s", typ, statuscode, p.FileInfo.Path, p.IP, err.Error())
	}
}
<commit_msg>logs: enable colors only if supported by the terminal<commit_after>// Copyright (c) 2014 Ludovic Fauvet
// Licensed under the MIT license

package main

import (
	"bytes"
	"fmt"
	"github.com/op/go-logging"
	stdlog "log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	log     = logging.MustGetLogger("main")
	rlogger RuntimeLogger
	dlogger DownloadsLogger
)

type RuntimeLogger struct {
	f *os.File
}

type DownloadsLogger struct {
	sync.RWMutex
	l *stdlog.Logger
	f *os.File
}

// ReloadLogs will reopen the logs to allow rotations
func ReloadLogs() {
	ReloadRuntimeLogs()
	ReloadDownloadLogs()
}

func ReloadRuntimeLogs() {
	logging.SetFormatter(logging.MustStringFormatter("%{time:2006/01/02 15:04:05.000 MST} %{message}"))
	logFlags := 0

	if os.Getenv("DEBUG") != "" {
		logFlags = stdlog.Lshortfile
		logging.SetLevel(logging.DEBUG, "main")
	} else {
		logging.SetLevel(logging.INFO, "main")
	}

	logColor := false

	stat, _ := os.Stdout.Stat()
	if (stat.Mode() & os.ModeCharDevice) != 0 {
		logColor = true //TODO make it optionnal
	}

	if rlogger.f != nil {
		rlogger.f.Close()
	} else {
		rlogger.f = os.Stderr
	}

	if runLog != "" {
		var err error
		rlogger.f, err = os.OpenFile(runLog, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Cannot open log file for writing")
			rlogger.f = os.Stderr
		} else {
			logColor = false
		}
	}

	logBackend := logging.NewLogBackend(rlogger.f, "", logFlags)
	logBackend.Color = logColor

	logging.SetBackend(logBackend)
}

func ReloadDownloadLogs() {
	dlogger.Lock()
	defer dlogger.Unlock()

	if GetConfig().LogDir == "" {
		if dlogger.f != nil {
			dlogger.f.Close()
		}
		dlogger.f = nil
		dlogger.l = nil
		return
	}

	logfile := GetConfig().LogDir + "/downloads.log"
	createHeader := true

	s, err := os.Stat(logfile)
	if err == nil && s.Size() > 0 {
		createHeader = false
	}

	if dlogger.f != nil {
		dlogger.f.Close()
	}
	dlogger.f, err = os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)

	if err != nil {
		log.Critical("Warning: cannot open log file %s", logfile)
		return
	}

	if createHeader {
		var buf bytes.Buffer
		hostname, _ := os.Hostname()
		fmt.Fprintf(&buf, "# Log file created at: %s\n", time.Now().Format("2006/01/02 15:04:05"))
		fmt.Fprintf(&buf, "# Running on machine: %s\n", hostname)
		fmt.Fprintf(&buf, "# Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
		dlogger.f.Write(buf.Bytes())
	}

	dlogger.l = stdlog.New(dlogger.f, "", stdlog.Ldate|stdlog.Lmicroseconds)
}

// This function will write a download result in the logs.
func logDownload(typ string, statuscode int, p *MirrorlistPage, err error) {
	dlogger.RLock()
	defer dlogger.RUnlock()

	if dlogger.l == nil {
		// Logs are disabled
		return
	}

	if statuscode == 302 || statuscode == 200 {
		var distance, countries string
		m := p.MirrorList[0]
		distance = strconv.FormatFloat(float64(m.Distance), 'f', 2, 32)
		countries = strings.Join(m.CountryFields, ",")
		fallback := ""
		if p.Fallback == true {
			fallback = " fallback:true"
		}
		sameASNum := ""
		if m.Asnum > 0 && m.Asnum == p.ClientInfo.ASNum {
			sameASNum = "same"
		}

		dlogger.l.Printf("%s %d \"%s\" ip:%s mirror:%s%s %sasn:%d distance:%skm countries:%s",
			typ, statuscode, p.FileInfo.Path, p.IP, m.ID, fallback, sameASNum, m.Asnum, distance, countries)
	} else if statuscode == 404 {
		dlogger.l.Printf("%s 404 \"%s\" %s", typ, p.FileInfo.Path, p.IP)
	} else if statuscode == 500 {
		mirrorID := "unknown"
		if len(p.MirrorList) > 0 {
			mirrorID = p.MirrorList[0].ID
		}
		dlogger.l.Printf("%s 500 \"%s\" ip:%s mirror:%s error:%s", typ, p.FileInfo.Path, p.IP, mirrorID, err.Error())
	} else {
		dlogger.l.Printf("%s %d \"%s\" ip:%s error:%s", typ, statuscode, p.FileInfo.Path, p.IP, err.Error())
	}
}
<|endoftext|>


<commit_before>func main(){
	print("start beegoDIY")
}
<commit_msg>minor<commit_after>package main

func main(){
	print("start beegoDIY")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hawkingrei/g53/servers"
	"os"
	"runtime"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	servers.StartServer(os.Args[1:])
}
<commit_msg>feat: remove Multi-core<commit_after>package main

import (
	"github.com/hawkingrei/g53/servers"
	"os"
)

func main() {
	servers.StartServer(os.Args[1:])
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"

	"golang.org/x/sys/unix"
)

const (
	defaultBufferSize = 1024
	SPLICE_F_MOVE     = 1
	SPLICE_F_NONBLOCK = 2
	SPLICE_F_MORE     = 4
	SPLICE_F_GIFT     = 8
	MaxUint           = ^uint(0)
	MaxInt            = int(MaxUint >> 1)
)

type mirror struct {
	addr   string
	conn   net.Conn
	closed bool
}

func readAndDiscard(m mirror, errCh chan error) {
	for {
		var b [defaultBufferSize]byte
		_, err := m.conn.Read(b[:])
		if err != nil {
			m.conn.Close()
			m.closed = true
			select {
			case errCh <- err:
			default:
			}
			return
		}
	}
}

func forward(from net.Conn, to net.Conn, errCh chan error) {
	for {
		var b [defaultBufferSize]byte

		n, err := from.Read(b[:])
		if err != nil {
			errCh <- err
			return
		}

		_, err = to.Write(b[:n])
		if err != nil {
			errCh <- err
			return
		}
	}
}

func forwardZeroCopy(from net.Conn, to net.Conn, errCh chan error) {
	var (
		p       [2]int
		nullPtr *int64
	)

	err := unix.Pipe(p[:])
	if err != nil {
		log.Fatalf("pipe() error: %s", err)
	}

	fromFile, err := from.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from incoming connection: %s", err)
	}

	toFile, err := to.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from outgoing connection: %s", err)
	}

	for {
		_, err = unix.Splice(int(fromFile.Fd()), nullPtr, p[1], nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errCh <- fmt.Errorf("error while splicing from conn to pipe: %s", err)
			return
		}
		_, err = unix.Splice(p[0], nullPtr, int(toFile.Fd()), nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errCh <- fmt.Errorf("error while splicing from pipe to conn: %s", err)
			return
		}
	}
}

func forwardAndZeroCopy(from net.Conn, to net.Conn, mirrors []mirror, errChForwardee, errChMirrors chan error) {
	type mirrorInt struct {
		mirror
		mirrorFile *os.File
		mirrorPipe [2]int
	}

	var (
		p          [2]int
		nullPtr    *int64
		mirrorsInt []mirrorInt
	)

	err := unix.Pipe(p[:])
	if err != nil {
		log.Fatalf("pipe() error: %s", err)
	}

	fromFile, err := from.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from incoming connection: %s", err)
	}

	toFile, err := to.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from outgoing connection: %s", err)
	}

	for _, m := range mirrors {
		mFile, err := m.conn.(*net.TCPConn).File()
		if err != nil {
			log.Fatalf("error while creating File() from incoming connection: %s", err)
		}

		var mPipe [2]int

		err = unix.Pipe(mPipe[:])
		if err != nil {
			log.Fatalf("pipe() error: %s", err)
		}

		mirrorsInt = append(mirrorsInt, mirrorInt{
			mirror:     m,
			mirrorPipe: mPipe,
			mirrorFile: mFile,
		})
	}

	for _, m := range mirrorsInt {

		go func(m mirrorInt) { // splice data from pipe to conn
			for {
				_, err = unix.Splice(m.mirrorPipe[0], nullPtr, int(m.mirrorFile.Fd()), nullPtr, MaxInt, SPLICE_F_MOVE)
				if err != nil {
					select {
					case errChMirrors <- fmt.Errorf("error while splicing from pipe to conn: %s", err):
					default:
					}
					return
				}
			}
		}(m)
	}

	for {
		_, err = unix.Splice(int(fromFile.Fd()), nullPtr, p[1], nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errChForwardee <- fmt.Errorf("error while splicing from conn to pipe: %s", err)
			return
		}

		nteed := int64(MaxInt)

		for _, m := range mirrorsInt {
			if m.closed {
				continue
			}

			nteed, err = unix.Tee(p[0], m.mirrorPipe[1], MaxInt, SPLICE_F_MOVE)
			if err != nil {
				m.conn.Close()
				m.closed = true
				select {
				case errChMirrors <- fmt.Errorf("error while tee(): %s", err):
				default:
				}
				return
			}
		}

		_, err = unix.Splice(p[0], nullPtr, int(toFile.Fd()), nullPtr, int(nteed), SPLICE_F_MOVE)
		if err != nil {
			errChForwardee <- fmt.Errorf("error while splice(): %s", err)
			return
		}
	}

}

func forwardAndCopy(from net.Conn, to net.Conn, mirrors []mirror, errChForwardee, errChMirrors chan error) {
	for {
		var b [defaultBufferSize]byte

		n, err := from.Read(b[:])
		if err != nil {
			errChForwardee <- err
			return
		}

		_, err = to.Write(b[:n])
		if err != nil {
			errChForwardee <- err
			return
		}

		for i := 0; i < len(mirrors); i++ {
			if mirrors[i].closed {
				continue
			}
			_, err = mirrors[i].conn.Write(b[:n])
			if err != nil {
				mirrors[i].conn.Close()
				mirrors[i].closed = true
				select {
				case errChMirrors <- err:
				default:
				}

			}
		}
	}
}

func connect(origin net.Conn, forwarder net.Conn, mirrors []mirror, useZeroCopy bool, errChForwardee, errChMirrors chan error) {

	for i := 0; i < len(mirrors); i++ {
		go readAndDiscard(mirrors[i], errChMirrors)
	}

	if useZeroCopy {
		go forwardZeroCopy(forwarder, origin, errChForwardee)
		go forwardAndZeroCopy(origin, forwarder, mirrors, errChForwardee, errChMirrors)
	} else {
		go forward(forwarder, origin, errChForwardee)
		go forwardAndCopy(origin, forwarder, mirrors, errChForwardee, errChMirrors)
	}

}

type mirrorList []string

func (l *mirrorList) String() string {
	return fmt.Sprint(*l)
}

func (l *mirrorList) Set(value string) error {
	for _, m := range strings.Split(value, ",") {
		*l = append(*l, m)
	}
	return nil
}

func main() {

	var (
		listenAddress   string
		forwardAddress  string
		mirrorAddresses mirrorList
		useZeroCopy     bool
	)

	flag.BoolVar(&useZeroCopy, "z", false, "use zero copy")
	flag.StringVar(&listenAddress, "l", "", "listen address (e.g. 'localhost:8080')")
	flag.StringVar(&forwardAddress, "f", "", "forward to address (e.g. 'localhost:8081')")
	flag.Var(&mirrorAddresses, "m", "comma separated list of mirror addresses (e.g. 'localhost:8082,localhost:8083')")
	flag.Parse()

	if listenAddress == "" || forwardAddress == "" {
		flag.Usage()
		return
	}

	l, err := net.Listen("tcp", listenAddress)
	if err != nil {
		log.Fatalf("error while listening: %s", err)
	}

	connNo := uint64(1)

	for {
		c, err := l.Accept()
		if err != nil {
			log.Fatalf("Error while accepting: %s", err)
		}

		log.Printf("accepted connection %d (%s <-> %s)", connNo, c.RemoteAddr(), c.LocalAddr())

		go func(c net.Conn) {

			cF, err := net.Dial("tcp", forwardAddress)
			if err != nil {
				log.Fatalf("error while connecting to forwarder: %s", err)
			}

			var mirrors []mirror

			for _, addr := range mirrorAddresses {
				c, err := net.Dial("tcp", addr)
				if err != nil {
					log.Printf("error while connecting to mirror %s: %s", addr, err)
				} else {
					mirrors = append(mirrors, mirror{
						addr:   addr,
						conn:   c,
						closed: false,
					})
				}
			}

			errChForwardee := make(chan error, 2)
			errChMirrors := make(chan error, len(mirrors))

			connect(c, cF, mirrors, useZeroCopy, errChForwardee, errChMirrors)

			done := false
			for !done {
				select {
				case err := <-errChMirrors:
					log.Printf("got error from mirror: %s", err)
				case err := <-errChForwardee:
					log.Printf("got error from forwardee: %s", err)
					done = true
				}
			}

			c.Close()
			cF.Close()

			for _, m := range mirrors {
				m.conn.Close()
			}
		}(c)

		connNo += 1
	}
}
<commit_msg>fixed race on mirror.closed variable<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync/atomic"

	"golang.org/x/sys/unix"
)

const (
	defaultBufferSize = 1024
	SPLICE_F_MOVE     = 1
	SPLICE_F_NONBLOCK = 2
	SPLICE_F_MORE     = 4
	SPLICE_F_GIFT     = 8
	MaxUint           = ^uint(0)
	MaxInt            = int(MaxUint >> 1)
)

type mirror struct {
	addr   string
	conn   net.Conn
	closed uint32
}

func readAndDiscard(m mirror, errCh chan error) {
	for {
		var b [defaultBufferSize]byte
		_, err := m.conn.Read(b[:])
		if err != nil {
			m.conn.Close()
			atomic.StoreUint32(&m.closed, 1)
			select {
			case errCh <- err:
			default:
			}
			return
		}
	}
}

func forward(from net.Conn, to net.Conn, errCh chan error) {
	for {
		var b [defaultBufferSize]byte

		n, err := from.Read(b[:])
		if err != nil {
			errCh <- err
			return
		}

		_, err = to.Write(b[:n])
		if err != nil {
			errCh <- err
			return
		}
	}
}

func forwardZeroCopy(from net.Conn, to net.Conn, errCh chan error) {
	var (
		p       [2]int
		nullPtr *int64
	)

	err := unix.Pipe(p[:])
	if err != nil {
		log.Fatalf("pipe() error: %s", err)
	}

	fromFile, err := from.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from incoming connection: %s", err)
	}

	toFile, err := to.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from outgoing connection: %s", err)
	}

	for {
		_, err = unix.Splice(int(fromFile.Fd()), nullPtr, p[1], nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errCh <- fmt.Errorf("error while splicing from conn to pipe: %s", err)
			return
		}
		_, err = unix.Splice(p[0], nullPtr, int(toFile.Fd()), nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errCh <- fmt.Errorf("error while splicing from pipe to conn: %s", err)
			return
		}
	}
}

func forwardAndZeroCopy(from net.Conn, to net.Conn, mirrors []mirror, errChForwardee, errChMirrors chan error) {
	type mirrorInt struct {
		mirror
		mirrorFile *os.File
		mirrorPipe [2]int
	}

	var (
		p          [2]int
		nullPtr    *int64
		mirrorsInt []mirrorInt
	)

	err := unix.Pipe(p[:])
	if err != nil {
		log.Fatalf("pipe() error: %s", err)
	}

	fromFile, err := from.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from incoming connection: %s", err)
	}

	toFile, err := to.(*net.TCPConn).File()
	if err != nil {
		log.Fatalf("error while creating File() from outgoing connection: %s", err)
	}

	for _, m := range mirrors {
		mFile, err := m.conn.(*net.TCPConn).File()
		if err != nil {
			log.Fatalf("error while creating File() from incoming connection: %s", err)
		}

		var mPipe [2]int

		err = unix.Pipe(mPipe[:])
		if err != nil {
			log.Fatalf("pipe() error: %s", err)
		}

		mirrorsInt = append(mirrorsInt, mirrorInt{
			mirror:     m,
			mirrorPipe: mPipe,
			mirrorFile: mFile,
		})
	}

	for _, m := range mirrorsInt {

		go func(m mirrorInt) { // splice data from pipe to conn
			for {
				_, err = unix.Splice(m.mirrorPipe[0], nullPtr, int(m.mirrorFile.Fd()), nullPtr, MaxInt, SPLICE_F_MOVE)
				if err != nil {
					select {
					case errChMirrors <- fmt.Errorf("error while splicing from pipe to conn: %s", err):
					default:
					}
					return
				}
			}
		}(m)
	}

	for {
		_, err = unix.Splice(int(fromFile.Fd()), nullPtr, p[1], nullPtr, MaxInt, SPLICE_F_MOVE)
		if err != nil {
			errChForwardee <- fmt.Errorf("error while splicing from conn to pipe: %s", err)
			return
		}

		nteed := int64(MaxInt)

		for _, m := range mirrorsInt {
			if closed := atomic.LoadUint32(&m.closed); closed == 1 {
				continue
			}

			nteed, err = unix.Tee(p[0], m.mirrorPipe[1], MaxInt, SPLICE_F_MOVE)
			if err != nil {
				m.conn.Close()
				atomic.StoreUint32(&m.closed, 1)
				select {
				case errChMirrors <- fmt.Errorf("error while tee(): %s", err):
				default:
				}
				return
			}
		}

		_, err = unix.Splice(p[0], nullPtr, int(toFile.Fd()), nullPtr, int(nteed), SPLICE_F_MOVE)
		if err != nil {
			errChForwardee <- fmt.Errorf("error while splice(): %s", err)
			return
		}
	}

}

func forwardAndCopy(from net.Conn, to net.Conn, mirrors []mirror, errChForwardee, errChMirrors chan error) {
	for {
		var b [defaultBufferSize]byte

		n, err := from.Read(b[:])
		if err != nil {
			errChForwardee <- err
			return
		}

		_, err = to.Write(b[:n])
		if err != nil {
			errChForwardee <- err
			return
		}

		for i := 0; i < len(mirrors); i++ {
			if closed := atomic.LoadUint32(&mirrors[i].closed); closed == 1 {
				continue
			}
			_, err = mirrors[i].conn.Write(b[:n])
			if err != nil {
				mirrors[i].conn.Close()
				atomic.StoreUint32(&mirrors[i].closed, 1)
				select {
				case errChMirrors <- err:
				default:
				}

			}
		}
	}
}

func connect(origin net.Conn, forwarder net.Conn, mirrors []mirror, useZeroCopy bool, errChForwardee, errChMirrors chan error) {

	for i := 0; i < len(mirrors); i++ {
		go readAndDiscard(mirrors[i], errChMirrors)
	}

	if useZeroCopy {
		go forwardZeroCopy(forwarder, origin, errChForwardee)
		go forwardAndZeroCopy(origin, forwarder, mirrors, errChForwardee, errChMirrors)
	} else {
		go forward(forwarder, origin, errChForwardee)
		go forwardAndCopy(origin, forwarder, mirrors, errChForwardee, errChMirrors)
	}

}

type mirrorList []string

func (l *mirrorList) String() string {
	return fmt.Sprint(*l)
}

func (l *mirrorList) Set(value string) error {
	for _, m := range strings.Split(value, ",") {
		*l = append(*l, m)
	}
	return nil
}

func main() {

	var (
		listenAddress   string
		forwardAddress  string
		mirrorAddresses mirrorList
		useZeroCopy     bool
	)

	flag.BoolVar(&useZeroCopy, "z", false, "use zero copy")
	flag.StringVar(&listenAddress, "l", "", "listen address (e.g. 'localhost:8080')")
	flag.StringVar(&forwardAddress, "f", "", "forward to address (e.g. 'localhost:8081')")
	flag.Var(&mirrorAddresses, "m", "comma separated list of mirror addresses (e.g. 'localhost:8082,localhost:8083')")
	flag.Parse()

	if listenAddress == "" || forwardAddress == "" {
		flag.Usage()
		return
	}

	l, err := net.Listen("tcp", listenAddress)
	if err != nil {
		log.Fatalf("error while listening: %s", err)
	}

	connNo := uint64(1)

	for {
		c, err := l.Accept()
		if err != nil {
			log.Fatalf("Error while accepting: %s", err)
		}

		log.Printf("accepted connection %d (%s <-> %s)", connNo, c.RemoteAddr(), c.LocalAddr())

		go func(c net.Conn) {

			cF, err := net.Dial("tcp", forwardAddress)
			if err != nil {
				log.Fatalf("error while connecting to forwarder: %s", err)
			}

			var mirrors []mirror

			for _, addr := range mirrorAddresses {
				c, err := net.Dial("tcp", addr)
				if err != nil {
					log.Printf("error while connecting to mirror %s: %s", addr, err)
				} else {
					mirrors = append(mirrors, mirror{
						addr:   addr,
						conn:   c,
						closed: 0,
					})
				}
			}

			errChForwardee := make(chan error, 2)
			errChMirrors := make(chan error, len(mirrors))

			connect(c, cF, mirrors, useZeroCopy, errChForwardee, errChMirrors)

			done := false
			for !done {
				select {
				case err := <-errChMirrors:
					log.Printf("got error from mirror: %s", err)
				case err := <-errChForwardee:
					log.Printf("got error from forwardee: %s", err)
					done = true
				}
			}

			c.Close()
			cF.Close()

			for _, m := range mirrors {
				m.conn.Close()
			}
		}(c)

		connNo += 1
	}
}
<|endoftext|>


<commit_before>// Declare this file to be part of the main package so it can be compiled into
// an executable.
package main

// Import all Go packages required for this file.
import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/bwmarrin/discordgo"
)

// Declare a constant that stores the Disgord version information.
const Version = "v0.0.0-alpha"

// Declare a DiscordGo Session in the global space so it can be easily used
// throughout this program.
// In this use case, there is no error that would be returned.
var Session, _ = discordgo.New()

// Read it all configuration options from both environment variables and
// command line arguments.
func init() {

	// Discord Authentication Token
	Session.Token = os.Getenv("DG_TOKEN")
	if Session.Token == "" {
		flag.StringVar(&Session.Token, "t", "", "Discord Authentication Token")
	}
}

func main() {

	// Declare any variables needed later.
	var err error

	// Print out a fancy logo!
	fmt.Printf(`
	________  .__                               .___
	\______ \ |__| ______ ____   ___________  __| _/
	||    |  \|  |/  ___// ___\ /  _ \_  __ \/ __ |
	||    '   \  |\___ \/ /_/  >  <_> )  | \/ /_/ |
	||______  /__/____  >___  / \____/|__|  \____ |
	\_______\/        \/_____/   %-16s\/`+"\n\n", Version)

	// Parse command line arguments
	flag.Parse()

	// Verify a Token was provided
	if Session.Token == "" {
		log.Println("You must provide a Discord authentication token.")
		return
	}

	// Verify the Token is valid and grab user information
	Session.State.User, err = Session.User("@me")
	if err != nil {
		log.Printf("error fetching user information, %s\n", err)
	}

	// Open a websocket connection to Discord
	err = Session.Open()
	if err != nil {
		log.Printf("error opening connection to Discord, %s\n", err)
	}

	// Wait for a CTRL-C
	log.Printf(`Now running. Press CTRL-C to exit.`)
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Clean up
	Session.Close()

	// Exit Normally.
}
<commit_msg>spelling.<commit_after>// Declare this file to be part of the main package so it can be compiled into
// an executable.
package main

// Import all Go packages required for this file.
import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/bwmarrin/discordgo"
)

// Declare a constant that stores the Disgord version information.
const Version = "v0.0.0-alpha"

// Declare a DiscordGo Session in the global space so it can be easily used
// throughout this program.
// In this use case, there is no error that would be returned.
var Session, _ = discordgo.New()

// Read in all configuration options from both environment variables and
// command line arguments.
func init() {

	// Discord Authentication Token
	Session.Token = os.Getenv("DG_TOKEN")
	if Session.Token == "" {
		flag.StringVar(&Session.Token, "t", "", "Discord Authentication Token")
	}
}

func main() {

	// Declare any variables needed later.
	var err error

	// Print out a fancy logo!
	fmt.Printf(`
	________  .__                               .___
	\______ \ |__| ______ ____   ___________  __| _/
	||    |  \|  |/  ___// ___\ /  _ \_  __ \/ __ |
	||    '   \  |\___ \/ /_/  >  <_> )  | \/ /_/ |
	||______  /__/____  >___  / \____/|__|  \____ |
	\_______\/        \/_____/   %-16s\/`+"\n\n", Version)

	// Parse command line arguments
	flag.Parse()

	// Verify a Token was provided
	if Session.Token == "" {
		log.Println("You must provide a Discord authentication token.")
		return
	}

	// Verify the Token is valid and grab user information
	Session.State.User, err = Session.User("@me")
	if err != nil {
		log.Printf("error fetching user information, %s\n", err)
	}

	// Open a websocket connection to Discord
	err = Session.Open()
	if err != nil {
		log.Printf("error opening connection to Discord, %s\n", err)
	}

	// Wait for a CTRL-C
	log.Printf(`Now running. Press CTRL-C to exit.`)
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Clean up
	Session.Close()

	// Exit Normally.
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
	"github.com/spirit-contrib/inlet_http"
)

const (
	SPIRIT_NAME    = "inlet_http_api"
	METHOD_OPTIONS = "OPTIONS"
)

var (
	conf InletHTTPAPIConfig

	proxyAPI = make(map[string]bool)
)

func main() {
	conf = LoadConfig("./conf/inlet_http_api.conf")

	graphProvider := NewAPIGraphProvider(API_HEADER, conf.Address, conf.Graphs)

	httpConf := inlet_http.Config{
		Address:    conf.HTTP.Address,
		Domain:     conf.HTTP.CookiesDomain,
		EnableStat: conf.HTTP.EnableStat,
	}

	inletHTTP := inlet_http.NewInletHTTP(
		inlet_http.SetHTTPConfig(httpConf),
		inlet_http.SetGraphProvider(graphProvider),
		inlet_http.SetResponseHandler(responseHandle),
		inlet_http.SetErrorResponseHandler(errorResponseHandler),
		inlet_http.SetRequestDecoder(requestDecoder),
		inlet_http.SetRequestPayloadHook(requestPayloadHook),
		inlet_http.SetTimeoutHeader(API_CALL_TIMEOUT))

	httpAPISpirit := spirit.NewClassicSpirit(SPIRIT_NAME, "an http inlet with POST request", "1.0.0")
	httpAPIComponent := spirit.NewBaseComponent(SPIRIT_NAME)

	httpAPIComponent.RegisterHandler("callback", inletHTTP.CallBack)
	httpAPIComponent.RegisterHandler("error", inletHTTP.Error)

	httpAPISpirit.Hosting(httpAPIComponent).Build()

	inletHTTP.Requester().SetMessageSenderFactory(httpAPISpirit.GetMessageSenderFactory())

	go inletHTTP.Run(conf.HTTP.PATH, func(r martini.Router) {
		r.Post("", inletHTTP.Handler)
		r.Options("", optionHandle)
	})

	httpAPISpirit.Run()
}

type APIResponse struct {
	Code           uint64      `json:"code"`
	ErrorId        string      `json:"error_id,omitempty"`
	ErrorNamespace string      `json:"error_namespace,omitempty"`
	Message        string      `json:"message"`
	Result         interface{} `json:"result"`
}

func requestDecoder(data []byte) (ret map[string]interface{}, err error) {
	str := strings.TrimSpace(string(data))
	if str != "" {
		ret = make(map[string]interface{})
		err = json.Unmarshal(data, &ret)
	}
	return
}

func requestPayloadHook(r *http.Request, apiName string, body []byte, payload *spirit.Payload) (err error) {
	if r.Header.Get(MULTI_CALL) == "1" {
		multiAPIReq := map[string]interface{}{}
		if e := json.Unmarshal(body, &multiAPIReq); e != nil {
			err = ERR_UNMARSHAL_MULTI_REQUEST_FAILED.New(errors.Params{"err": e, "api": apiName})
			return
		} else if reqContent, exist := multiAPIReq[apiName]; exist {
			payload.SetContent(reqContent)
		} else {
			err = ERR_MULTI_API_REQUEST_NOT_EXIST.New(errors.Params{"api": apiName})
			return
		}
	}

	if apiName == "" {
		err = ERR_API_NAME_IS_EMPTY.New()
		return
	}

	if proxyAPI != nil {
		if isProxy, _ := proxyAPI[apiName]; isProxy {
			newPayload := spirit.Payload{}

			if e := newPayload.UnSerialize(body); e != nil {
				err = ERR_PARSE_PROXY_PAYLOAD_FIALED.New(errors.Params{"api": apiName, "err": e})
				logs.Error(err)
				return
			} else {
				payload.CopyFrom(&newPayload)
			}
		}
	}

	payload.SetContext(conf.HTTP.APIHeader, apiName)

	return
}

func optionHandle(w http.ResponseWriter, r *http.Request) {
	if r.Method == METHOD_OPTIONS {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Write([]byte(""))
	}
}

func errorResponseHandler(err error, w http.ResponseWriter, r *http.Request) {
	//statusCode := http.StatusInternalServerError

	// if ERR_API_GRAPH_IS_NOT_EXIST.IsEqual(err) {
	// 	statusCode = http.StatusNotFound
	// } else if inlet_http.ERR_REQUEST_TIMEOUT.IsEqual(err) {
	// 	statusCode = http.StatusRequestTimeout
	// 	apiName := r.Header.Get(conf.HTTP.APIHeader)
	// 	err = ERR_API_REQUEST_TIMEOUT.New(errors.Params{"api": apiName})
	// }

	//for temp support client side to receive
	statusCode := http.StatusOK

	var resp APIResponse
	if errCode, ok := err.(errors.ErrCode); ok {
		resp = APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}
	} else {
		resp = APIResponse{
			Code:           500,
			ErrorId:        "",
			ErrorNamespace: INLET_HTTP_API_ERR_NS,
			Message:        err.Error(),
			Result:         nil,
		}
	}

	writeResponseWithStatusCode(&resp, w, r, statusCode)
}

func responseHandle(graphsResponse map[string]inlet_http.GraphResponse, w http.ResponseWriter, r *http.Request) {
	//TODO: improve handle logic
	//X-X-API-MULTI-CALL PROCESS

	multiResp := map[string]APIResponse{}
	for apiName, graphResponse := range graphsResponse {
		if graphResponse.Error != nil {
			if errCode, ok := graphResponse.Error.(errors.ErrCode); ok {
				multiResp[apiName] = APIResponse{
					Code:           errCode.Code(),
					ErrorId:        errCode.Id(),
					ErrorNamespace: errCode.Namespace(),
					Message:        errCode.Error(),
					Result:         nil,
				}
			} else {
				multiResp[apiName] = APIResponse{
					Code:           500,
					ErrorId:        "",
					ErrorNamespace: INLET_HTTP_API_ERR_NS,
					Message:        graphResponse.Error.Error(),
					Result:         nil,
				}
			}
		} else if graphResponse.RespPayload.IsCorrect() {
			multiResp[apiName] = APIResponse{
				Code:   graphResponse.RespPayload.Error().Code,
				Result: graphResponse.RespPayload.GetContent(),
			}
		} else {
			multiResp[apiName] = APIResponse{
				Code:           graphResponse.RespPayload.Error().Code,
				ErrorId:        graphResponse.RespPayload.Error().Id,
				ErrorNamespace: graphResponse.RespPayload.Error().Namespace,
				Message:        graphResponse.RespPayload.Error().Message,
				Result:         nil,
			}
		}
	}

	if r.Header.Get(MULTI_CALL) == "1" {
		resp := APIResponse{
			Code:   0,
			Result: multiResp,
		}
		writeResponse(&resp, w, r)
		return
	}

	lenGraphsResponse := len(graphsResponse)

	//response count is did not equal 1
	if lenGraphsResponse != 1 {
		err := ERR_PAYLOAD_RESPONSE_COUNT_NOT_MATCH.New()
		errCode, _ := err.(errors.ErrCode)
		resp := APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}

		writeResponse(&resp, w, r)
		return
	}

	for _, resp := range multiResp {
		writeResponse(&resp, w, r)
		return
	}
}

func writeResponse(v interface{}, w http.ResponseWriter, r *http.Request) {
	writeResponseWithStatusCode(v, w, r, http.StatusOK)
}

func writeResponseWithStatusCode(v interface{}, w http.ResponseWriter, r *http.Request, code int) {
	if data, e := json.Marshal(v); e != nil {
		err := ERR_MARSHAL_STRUCT_ERROR.New(errors.Params{"err": e})
		logs.Error(err)
		if _, ok := v.(error); !ok {
			writeResponseWithStatusCode(&err, w, r, code)
		}
	} else {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(code)
		w.Write(data)
	}
}

func writeAccessHeaders(w http.ResponseWriter, r *http.Request) {
	refer := r.Referer()
	if refer == "" {
		refer = r.Header.Get("Origin")
	}

	if refProtocol, refDomain, isAllowd := conf.HTTP.ParseOrigin(refer); isAllowd {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		origin := refProtocol + "://" + refDomain
		if origin == "://" ||
			refProtocol == "chrome-extension" { //issue of post man, chrome limit.
			origin = "*"
		}
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST")
	w.Header().Set("Access-Control-Allow-Headers", conf.HTTP.allowHeaders())
}

func writeBasicHeaders(w http.ResponseWriter, r *http.Request) {
	for key, value := range conf.HTTP.responseHeaders {
		w.Header().Set(key, value)
	}
}
<commit_msg>improve start func<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
	"github.com/spirit-contrib/inlet_http"
)

const (
	SPIRIT_NAME    = "inlet_http_api"
	METHOD_OPTIONS = "OPTIONS"
)

var (
	conf InletHTTPAPIConfig

	proxyAPI = make(map[string]bool)
)

func main() {

	httpAPISpirit := spirit.NewClassicSpirit(SPIRIT_NAME, "an http inlet with POST request", "1.0.0")
	httpAPIComponent := spirit.NewBaseComponent(SPIRIT_NAME)

	inletHTTP := inlet_http.NewInletHTTP()

	httpAPIComponent.RegisterHandler("callback", inletHTTP.CallBack)
	httpAPIComponent.RegisterHandler("error", inletHTTP.Error)

	funcStartInletHTTP := func() error {
		conf = LoadConfig("./conf/inlet_http_api.conf")

		graphProvider := NewAPIGraphProvider(API_HEADER, conf.Address, conf.Graphs)

		httpConf := inlet_http.Config{
			Address:    conf.HTTP.Address,
			Domain:     conf.HTTP.CookiesDomain,
			EnableStat: conf.HTTP.EnableStat,
		}

		inletHTTP.Option(inlet_http.SetHTTPConfig(httpConf),
			inlet_http.SetGraphProvider(graphProvider),
			inlet_http.SetResponseHandler(responseHandle),
			inlet_http.SetErrorResponseHandler(errorResponseHandler),
			inlet_http.SetRequestDecoder(requestDecoder),
			inlet_http.SetRequestPayloadHook(requestPayloadHook),
			inlet_http.SetTimeoutHeader(API_CALL_TIMEOUT))

		inletHTTP.Requester().SetMessageSenderFactory(httpAPISpirit.GetMessageSenderFactory())

		go inletHTTP.Run(conf.HTTP.PATH, func(r martini.Router) {
			r.Post("", inletHTTP.Handler)
			r.Options("", optionHandle)
		})

		return nil
	}

	httpAPISpirit.Hosting(httpAPIComponent).Build().Run(funcStartInletHTTP)
}

type APIResponse struct {
	Code           uint64      `json:"code"`
	ErrorId        string      `json:"error_id,omitempty"`
	ErrorNamespace string      `json:"error_namespace,omitempty"`
	Message        string      `json:"message"`
	Result         interface{} `json:"result"`
}

func requestDecoder(data []byte) (ret map[string]interface{}, err error) {
	str := strings.TrimSpace(string(data))
	if str != "" {
		ret = make(map[string]interface{})
		err = json.Unmarshal(data, &ret)
	}
	return
}

func requestPayloadHook(r *http.Request, apiName string, body []byte, payload *spirit.Payload) (err error) {
	if r.Header.Get(MULTI_CALL) == "1" {
		multiAPIReq := map[string]interface{}{}
		if e := json.Unmarshal(body, &multiAPIReq); e != nil {
			err = ERR_UNMARSHAL_MULTI_REQUEST_FAILED.New(errors.Params{"err": e, "api": apiName})
			return
		} else if reqContent, exist := multiAPIReq[apiName]; exist {
			payload.SetContent(reqContent)
		} else {
			err = ERR_MULTI_API_REQUEST_NOT_EXIST.New(errors.Params{"api": apiName})
			return
		}
	}

	if apiName == "" {
		err = ERR_API_NAME_IS_EMPTY.New()
		return
	}

	if proxyAPI != nil {
		if isProxy, _ := proxyAPI[apiName]; isProxy {
			newPayload := spirit.Payload{}

			if e := newPayload.UnSerialize(body); e != nil {
				err = ERR_PARSE_PROXY_PAYLOAD_FIALED.New(errors.Params{"api": apiName, "err": e})
				logs.Error(err)
				return
			} else {
				payload.CopyFrom(&newPayload)
			}
		}
	}

	payload.SetContext(conf.HTTP.APIHeader, apiName)

	return
}

func optionHandle(w http.ResponseWriter, r *http.Request) {
	if r.Method == METHOD_OPTIONS {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Write([]byte(""))
	}
}

func errorResponseHandler(err error, w http.ResponseWriter, r *http.Request) {
	//statusCode := http.StatusInternalServerError

	// if ERR_API_GRAPH_IS_NOT_EXIST.IsEqual(err) {
	// 	statusCode = http.StatusNotFound
	// } else if inlet_http.ERR_REQUEST_TIMEOUT.IsEqual(err) {
	// 	statusCode = http.StatusRequestTimeout
	// 	apiName := r.Header.Get(conf.HTTP.APIHeader)
	// 	err = ERR_API_REQUEST_TIMEOUT.New(errors.Params{"api": apiName})
	// }

	//for temp support client side to receive
	statusCode := http.StatusOK

	var resp APIResponse
	if errCode, ok := err.(errors.ErrCode); ok {
		resp = APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}
	} else {
		resp = APIResponse{
			Code:           500,
			ErrorId:        "",
			ErrorNamespace: INLET_HTTP_API_ERR_NS,
			Message:        err.Error(),
			Result:         nil,
		}
	}

	writeResponseWithStatusCode(&resp, w, r, statusCode)
}

func responseHandle(graphsResponse map[string]inlet_http.GraphResponse, w http.ResponseWriter, r *http.Request) {
	//TODO: improve handle logic
	//X-X-API-MULTI-CALL PROCESS

	multiResp := map[string]APIResponse{}
	for apiName, graphResponse := range graphsResponse {
		if graphResponse.Error != nil {
			if errCode, ok := graphResponse.Error.(errors.ErrCode); ok {
				multiResp[apiName] = APIResponse{
					Code:           errCode.Code(),
					ErrorId:        errCode.Id(),
					ErrorNamespace: errCode.Namespace(),
					Message:        errCode.Error(),
					Result:         nil,
				}
			} else {
				multiResp[apiName] = APIResponse{
					Code:           500,
					ErrorId:        "",
					ErrorNamespace: INLET_HTTP_API_ERR_NS,
					Message:        graphResponse.Error.Error(),
					Result:         nil,
				}
			}
		} else if graphResponse.RespPayload.IsCorrect() {
			multiResp[apiName] = APIResponse{
				Code:   graphResponse.RespPayload.Error().Code,
				Result: graphResponse.RespPayload.GetContent(),
			}
		} else {
			multiResp[apiName] = APIResponse{
				Code:           graphResponse.RespPayload.Error().Code,
				ErrorId:        graphResponse.RespPayload.Error().Id,
				ErrorNamespace: graphResponse.RespPayload.Error().Namespace,
				Message:        graphResponse.RespPayload.Error().Message,
				Result:         nil,
			}
		}
	}

	if r.Header.Get(MULTI_CALL) == "1" {
		resp := APIResponse{
			Code:   0,
			Result: multiResp,
		}
		writeResponse(&resp, w, r)
		return
	}

	lenGraphsResponse := len(graphsResponse)

	//response count is did not equal 1
	if lenGraphsResponse != 1 {
		err := ERR_PAYLOAD_RESPONSE_COUNT_NOT_MATCH.New()
		errCode, _ := err.(errors.ErrCode)
		resp := APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}

		writeResponse(&resp, w, r)
		return
	}

	for _, resp := range multiResp {
		writeResponse(&resp, w, r)
		return
	}
}

func writeResponse(v interface{}, w http.ResponseWriter, r *http.Request) {
	writeResponseWithStatusCode(v, w, r, http.StatusOK)
}

func writeResponseWithStatusCode(v interface{}, w http.ResponseWriter, r *http.Request, code int) {
	if data, e := json.Marshal(v); e != nil {
		err := ERR_MARSHAL_STRUCT_ERROR.New(errors.Params{"err": e})
		logs.Error(err)
		if _, ok := v.(error); !ok {
			writeResponseWithStatusCode(&err, w, r, code)
		}
	} else {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(code)
		w.Write(data)
	}
}

func writeAccessHeaders(w http.ResponseWriter, r *http.Request) {
	refer := r.Referer()
	if refer == "" {
		refer = r.Header.Get("Origin")
	}

	if refProtocol, refDomain, isAllowd := conf.HTTP.ParseOrigin(refer); isAllowd {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		origin := refProtocol + "://" + refDomain
		if origin == "://" ||
			refProtocol == "chrome-extension" { //issue of post man, chrome limit.
			origin = "*"
		}
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST")
	w.Header().Set("Access-Control-Allow-Headers", conf.HTTP.allowHeaders())
}

func writeBasicHeaders(w http.ResponseWriter, r *http.Request) {
	for key, value := range conf.HTTP.responseHeaders {
		w.Header().Set(key, value)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
)

var commands = []*Command{
	cmdLogin,
	cmdLogout,
	cmdLogins,
	cmdActive,
	cmdWhoami,
	cmdSobject,
	cmdField,
	cmdRecord,
	cmdBulk,
	cmdFetch,
	cmdExport,
	cmdFetch,
	cmdImport,
	cmdQuery,
	cmdApex,
	cmdOauth,
	cmdVersion,
	cmdUpdate,
	cmdHelp,
	cmdPush,
	cmdPassword,
}

func main() {
	args := os.Args[1:]
	if len(args) < 1 {
		usage()
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() {
				cmd.printUsage()
			}
			if err := cmd.Flag.Parse(args[1:]); err != nil {
				os.Exit(2)
			}
			cmd.Run(cmd, cmd.Flag.Args())
			return
		}
	}
	usage()
}
<commit_msg>adding cmdTest to main.go<commit_after>package main

import (
	"os"
)

var commands = []*Command{
	cmdLogin,
	cmdLogout,
	cmdLogins,
	cmdActive,
	cmdWhoami,
	cmdSobject,
	cmdField,
	cmdRecord,
	cmdBulk,
	cmdFetch,
	cmdExport,
	cmdFetch,
	cmdImport,
	cmdQuery,
	cmdApex,
	cmdOauth,
	cmdTest,
	cmdVersion,
	cmdUpdate,
	cmdHelp,
	cmdPush,
	cmdPassword,
}

func main() {
	args := os.Args[1:]
	if len(args) < 1 {
		usage()
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() {
				cmd.printUsage()
			}
			if err := cmd.Flag.Parse(args[1:]); err != nil {
				os.Exit(2)
			}
			cmd.Run(cmd, cmd.Flag.Args())
			return
		}
	}
	usage()
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		if content != nil && content.IsOperation && content.OpType == linebot.OpTypeAddedAsFriend {
			op, err := content.OperationContent()
			if err != nil {
				log.Println(err)
				return
			}
			from := op.Params[0]

			user, err := bot.GetUserProfile([]string{from})
			if err != nil {
				log.Println(err)
				return
			}
			_, err = bot.SendText([]string{from}, user.Contacts[0].DisplayName+" 您好，目前可用指令為：「加入」「退出」「雨量」「警報」「貓圖」「狀態」「時間」")
			if err != nil {
				log.Println(err)
			}
		}

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {
			user, err := bot.GetUserProfile([]string{content.From})
			if err != nil {
				return
			}
			text, err := content.TextContent()
			if err != nil {
				log.Println(err)
			}
			cmd := strings.Fields(text.Text)

			switch cmd[0] {
			case "加入":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, addErr := c.Do("SADD", "user", content.From)
				if addErr != nil {
					log.Println("SADD to redis error", addErr, status)
				} else {
					_, err = bot.SendText([]string{content.From}, user.Contacts[0].DisplayName+" 您好，已將您加入傳送對象，未來將會傳送天氣警報資訊給您 ^＿^ ")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "退出":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, setErr := c.Do("SREM", "user", content.From)
				if setErr != nil {
					log.Println("DEL to redis error", setErr, status)
				} else {
					_, err = bot.SendText([]string{content.From}, user.Contacts[0].DisplayName+" 掰掰 Q＿Q")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "服務":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				count, countErr := redis.Int(c.Do("SCARD", "user"))
				if countErr != nil {
					log.Println(countErr)
				} else {
					_, err = bot.SendText([]string{content.From}, fmt.Sprintf("目前有 %d 人加入自動警訊服務。", count))
					if err != nil {
						log.Println(err)
					}
				}

				defer c.Close()

			case "狀態":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, getErr := redis.Int(c.Do("SISMEMBER", "user", content.From))
				if getErr != nil || status == 0 {
					_, err = bot.SendText([]string{content.From}, "目前沒有登記您的編號喔！")
					if err != nil {
						log.Println(err)
					}
				} else {
					_, err = bot.SendText([]string{content.From}, "您已經是傳送對象 :D")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "時間":
				local := time.Now()
				location, timezoneErr := time.LoadLocation(timeZone)
				if timezoneErr == nil {
					local = local.In(location)
				}
				_, err = bot.SendText([]string{content.From}, local.Format("2006/01/02 15:04:05"))
				if err != nil {
					log.Println(err)
				}

			case "雨量":
				target := []string{"新竹市"}
				if len(cmd) > 1 {
					target[0] = cmd[1]
				}

				msgs, _ := rain.GetRainingInfo(target, true)
				if len(msgs) == 0 {
					_, err = bot.SendText([]string{content.From}, "目前沒有雨量資訊！")
					if err != nil {
						log.Println(err)
					}
				} else {
					for _, msg := range msgs {
						_, err = bot.SendText([]string{content.From}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}

			case "警報":
				msgs, _ := rain.GetWarningInfo(nil)
				for _, msg := range msgs {
					_, err = bot.SendText([]string{content.From}, msg)
					if err != nil {
						log.Println(err)
					}
				}

			case "重開":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status0, clearErr0 := c.Do("DEL", "token0")
				if clearErr0 != nil {
					log.Println("DEL to redis error", clearErr0, status0)
				}
				status1, clearErr1 := c.Do("DEL", "token1")
				if clearErr1 != nil {
					log.Println("DEL to redis error", clearErr1, status1)
				}

				_, err = bot.SendText([]string{content.From}, "已重開")
				if err != nil {
					log.Println(err)
				}

			case "貓圖":
				type Cat struct {
					File string `json:"file"`
				}
				cat := new(Cat)
				getJSON("http://random.cat/meow", &cat)
				if cat.File != "" {
					_, err = bot.SendImage([]string{content.From}, cat.File, cat.File)
					if err != nil {
						log.Println(err)
					}
				}

			case "正妹":
				type Beauty struct {
					Count   int      `json:"count"`
					PhotoID []string `json:"photoId"`
				}
				beauty := new(Beauty)
				getJSON("", &beauty)
				if beauty.PhotoID[0] != "" {
					_, err = bot.SendImage([]string{content.From}, beauty.PhotoID[0], beauty.PhotoID[0])
					if err != nil {
						log.Println(err)
					}
				}

			default:
				_, err = bot.SendText([]string{content.From}, "指令錯誤，請重試")
				if err != nil {
					log.Println(err)
				}

			}
		}
	}
}

// getJSON func
func getJSON(url string, target interface{}) error {
	r, err := http.Get(url)
	if err != nil {
		return err
	}
	defer r.Body.Close()

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

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		if content != nil && content.IsOperation && content.OpType == linebot.OpTypeAddedAsFriend {
			op, err := content.OperationContent()
			if err != nil {
				log.Println(err)
				return
			}
			from := op.Params[0]

			user, err := bot.GetUserProfile([]string{from})
			if err != nil {
				log.Println(err)
				return
			}
			_, err = bot.SendText([]string{from}, user.Contacts[0].DisplayName+" 您好，目前可用指令為：「加入」「退出」「雨量」「警報」「貓圖」「狀態」「時間」")
			if err != nil {
				log.Println(err)
			}
		}

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {
			user, err := bot.GetUserProfile([]string{content.From})
			if err != nil {
				return
			}
			text, err := content.TextContent()
			if err != nil {
				log.Println(err)
			}
			cmd := strings.Fields(text.Text)

			switch cmd[0] {
			case "加入":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, addErr := c.Do("SADD", "user", content.From)
				if addErr != nil {
					log.Println("SADD to redis error", addErr, status)
				} else {
					_, err = bot.SendText([]string{content.From}, user.Contacts[0].DisplayName+" 您好，已將您加入傳送對象，未來將會傳送天氣警報資訊給您 ^＿^ ")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "退出":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, setErr := c.Do("SREM", "user", content.From)
				if setErr != nil {
					log.Println("DEL to redis error", setErr, status)
				} else {
					_, err = bot.SendText([]string{content.From}, user.Contacts[0].DisplayName+" 掰掰 Q＿Q")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "服務":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				count, countErr := redis.Int(c.Do("SCARD", "user"))
				if countErr != nil {
					log.Println(countErr)
				} else {
					_, err = bot.SendText([]string{content.From}, fmt.Sprintf("目前有 %d 人加入自動警訊服務。", count))
					if err != nil {
						log.Println(err)
					}
				}

				defer c.Close()

			case "狀態":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status, getErr := redis.Int(c.Do("SISMEMBER", "user", content.From))
				if getErr != nil || status == 0 {
					_, err = bot.SendText([]string{content.From}, "目前沒有登記您的編號喔！")
					if err != nil {
						log.Println(err)
					}
				} else {
					_, err = bot.SendText([]string{content.From}, "您已經是傳送對象 :D")
					if err != nil {
						log.Println(err)
					}
				}
				defer c.Close()

			case "時間":
				local := time.Now()
				location, timezoneErr := time.LoadLocation(timeZone)
				if timezoneErr == nil {
					local = local.In(location)
				}
				_, err = bot.SendText([]string{content.From}, local.Format("2006/01/02 15:04:05"))
				if err != nil {
					log.Println(err)
				}

			case "雨量":
				target := []string{"新竹市"}
				if len(cmd) > 1 {
					target[0] = cmd[1]
				}

				msgs, _ := rain.GetRainingInfo(target, true)
				if len(msgs) == 0 {
					_, err = bot.SendText([]string{content.From}, "目前沒有雨量資訊！")
					if err != nil {
						log.Println(err)
					}
				} else {
					for _, msg := range msgs {
						_, err = bot.SendText([]string{content.From}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}

			case "警報":
				msgs, _ := rain.GetWarningInfo(nil)
				for _, msg := range msgs {
					_, err = bot.SendText([]string{content.From}, msg)
					if err != nil {
						log.Println(err)
					}
				}

			case "重開":
				c := db.Connect(os.Getenv("REDISTOGO_URL"))
				status0, clearErr0 := c.Do("DEL", "token0")
				if clearErr0 != nil {
					log.Println("DEL to redis error", clearErr0, status0)
				}
				status1, clearErr1 := c.Do("DEL", "token1")
				if clearErr1 != nil {
					log.Println("DEL to redis error", clearErr1, status1)
				}

				_, err = bot.SendText([]string{content.From}, "已重開")
				if err != nil {
					log.Println(err)
				}

			case "貓圖":
				type Cat struct {
					File string `json:"file"`
				}
				cat := new(Cat)
				getJSON("http://random.cat/meow", &cat)
				if cat.File != "" {
					_, err = bot.SendImage([]string{content.From}, cat.File, cat.File)
					if err != nil {
						log.Println(err)
					}
				}

			case "妹子":
				type MeisData struct {
					ID         string    `json:"id"`
					Name       string    `json:"name"`
					ImgNo      int       `json:"img_no"`
					Fanpage    int       `json:"fanpage"`
					Creator    int       `json:"creator"`
					UpdateTime time.Time `json:"update_time"`
				}

				type Beauty struct {
					Meis map[string]MeisData `json:"meis"`
				}

				beauty := new(Beauty)
				getJSON("http://beauty.zones.gamebase.com.tw/wall?json", &beauty)
				if len(beauty.Meis) > 0 {
					for no, data := range beauty.Meis {
						_, err = bot.SendText([]string{content.From}, fmt.Sprintf("%s %v", no, data))
						if err != nil {
							log.Println(err)
						}
						break
					}

					//_, err = bot.SendImage([]string{content.From}, "", "")
					if err != nil {
						log.Println(err)
					}
				}

			default:
				_, err = bot.SendText([]string{content.From}, "指令錯誤，請重試")
				if err != nil {
					log.Println(err)
				}

			}
		}
	}
}

// getJSON func
func getJSON(url string, target interface{}) error {
	r, err := http.Get(url)
	if err != nil {
		return err
	}
	defer r.Body.Close()

	return json.NewDecoder(r.Body).Decode(target)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"mime"
	"net/http"
	"path"
	"strconv"
	"time"
)

// readSeekCloser provides io.Close interface to io.ReadSeeker
type readSeekCloser interface {
	io.ReadSeeker
	io.Closer
}

// store is the interface to be implemented by backends for basic
// operations
type store interface {
	Post(name string, rd io.Reader, modTime time.Time) (newpath string, err error)
	Get(name string) (rd readSeekCloser, modTime time.Time, err error)
	Delete(name string) error
}

var st store

func init() {
	st = fsStore{"data"}
}

func main() {
	http.HandleFunc("/", handler)
	log.Println("Serving on :8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Println(err)
	}
}

// handler dispatches the request to the proper handler depending on the
// method.
// As a security measure, any internal error is printed on stderr but
// never sent to the client; they have no business knowing how the
// server works.
func handler(w http.ResponseWriter, r *http.Request) {
	if !check(r) {
		http.Error(w, "Invalid request", http.StatusBadRequest)
		return
	}
	switch r.Method {
	case "POST":
		handlePost(w, r)
	case "GET", "HEAD":
		handleGet(w, r, r.Method)
	case "DELETE":
		handleDelete(w, r)
	}
}

// check makes sure the request has the correct method, params and
// header values we expect
func check(r *http.Request) bool {
	if r.Method != "GET" && r.Method != "POST" && r.Method != "HEAD" && r.Method != "DELETE" {
		return false
	}
	if err := r.ParseForm(); err != nil {
		return false
	}
	if r.Form.Get("name") == "" {
		return false
	}
	if dir, file := path.Split(r.Form.Get("name")); dir == "" || file == "" {
		return false
	}
	if r.Method == "POST" {
		_, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
		if err != nil {
			return false
		}
		if _, err := strconv.Atoi(r.Header.Get("Content-Length")); err != nil {
			return false
		}
	}
	return true
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	newpath, err := st.Post(r.Form.Get("name"), r.Body, time.Now())
	r.Body.Close()
	if err != nil {
		log.Println("Error putting:", err)
		http.Error(w, "Error putting file", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Location", "/?name="+newpath)
	w.WriteHeader(http.StatusCreated)
}

func handleGet(w http.ResponseWriter, r *http.Request, method string) {
	rd, modTime, err := st.Get(r.Form.Get("name"))
	if err != nil {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}
	responseWriter := w
	if method == "HEAD" {
		responseWriter = nullWriter{w}
	}
	random := path.Dir(r.Form.Get("name"))
	w.Header().Set("Etag", random)
	http.ServeContent(responseWriter, r, "", modTime, rd)
	rd.Close()
}

// nullWriter is a wrapper around a http.ResponseWriter that doesn't
// actually write anything. It is useful for requests that are
// interested in writing all information except the actual content, such
// as HEAD requests.
type nullWriter struct {
	http.ResponseWriter
}

func (nw nullWriter) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func handleDelete(w http.ResponseWriter, r *http.Request) {
	err := st.Delete(r.Form.Get("name"))
	if err != nil {
		log.Println("Couldn't delete:", err)
		http.Error(w, "Couldn't delete", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)
}
<commit_msg>Check for random in name param only for non-POST<commit_after>package main

import (
	"io"
	"log"
	"mime"
	"net/http"
	"path"
	"strconv"
	"time"
)

// readSeekCloser provides io.Close interface to io.ReadSeeker
type readSeekCloser interface {
	io.ReadSeeker
	io.Closer
}

// store is the interface to be implemented by backends for basic
// operations
type store interface {
	Post(name string, rd io.Reader, modTime time.Time) (newpath string, err error)
	Get(name string) (rd readSeekCloser, modTime time.Time, err error)
	Delete(name string) error
}

var st store

func init() {
	st = fsStore{"data"}
}

func main() {
	http.HandleFunc("/", handler)
	log.Println("Serving on :8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Println(err)
	}
}

// handler dispatches the request to the proper handler depending on the
// method.
// As a security measure, any internal error is printed on stderr but
// never sent to the client; they have no business knowing how the
// server works.
func handler(w http.ResponseWriter, r *http.Request) {
	if !check(r) {
		http.Error(w, "Invalid request", http.StatusBadRequest)
		return
	}
	switch r.Method {
	case "POST":
		handlePost(w, r)
	case "GET", "HEAD":
		handleGet(w, r, r.Method)
	case "DELETE":
		handleDelete(w, r)
	}
}

// check makes sure the request has the correct method, params and
// header values we expect
func check(r *http.Request) bool {
	if r.Method != "GET" && r.Method != "POST" && r.Method != "HEAD" && r.Method != "DELETE" {
		return false
	}
	if err := r.ParseForm(); err != nil {
		return false
	}
	if r.Form.Get("name") == "" {
		return false
	}
	if r.Method == "POST" {
		_, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
		if err != nil {
			return false
		}
		if _, err := strconv.Atoi(r.Header.Get("Content-Length")); err != nil {
			return false
		}
	} else {
		if dir, file := path.Split(r.Form.Get("name")); dir == "" || file == "" {
			return false
		}
	}
	return true
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	newpath, err := st.Post(r.Form.Get("name"), r.Body, time.Now())
	r.Body.Close()
	if err != nil {
		log.Println("Error putting:", err)
		http.Error(w, "Error putting file", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Location", "/?name="+newpath)
	w.WriteHeader(http.StatusCreated)
}

func handleGet(w http.ResponseWriter, r *http.Request, method string) {
	rd, modTime, err := st.Get(r.Form.Get("name"))
	if err != nil {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}
	responseWriter := w
	if method == "HEAD" {
		responseWriter = nullWriter{w}
	}
	random := path.Dir(r.Form.Get("name"))
	w.Header().Set("Etag", random)
	http.ServeContent(responseWriter, r, "", modTime, rd)
	rd.Close()
}

// nullWriter is a wrapper around a http.ResponseWriter that doesn't
// actually write anything. It is useful for requests that are
// interested in writing all information except the actual content, such
// as HEAD requests.
type nullWriter struct {
	http.ResponseWriter
}

func (nw nullWriter) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func handleDelete(w http.ResponseWriter, r *http.Request) {
	err := st.Delete(r.Form.Get("name"))
	if err != nil {
		log.Println("Couldn't delete:", err)
		http.Error(w, "Couldn't delete", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
	"net/url"
	"time"
)

var mongoUrl = flag.String("url", "mongodb://localhost:27017/test", "MongoDB connection URI.")
var collection = flag.String("c", "sessions", "MongoDB collection to cleanup.")
var field = flag.String("f", "updated_at", "MongoDB collection field with type 'time.Time'.")
var retention = flag.Int("r", 168, "MongoDB retention delai in hour(s). Default is 7 days (168 hours).")

// Version is initialized at compilation time
var Version = "0.0.0"

// BuildTime is initialized at compilation time
var BuildTime = time.Now().Format(time.RFC3339)

func main() {
	flag.Parse()

	hostPort, err := url.Parse(*mongoUrl)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("MongoDB connection URL:              ", hostPort.Host)
	fmt.Println("MongoDB collection to clean:         ", *collection)
	fmt.Println("MongoDB collection field:            ", *field)
	fmt.Println("MongoDB retention periode in hour(s):", *retention)
	fmt.Println()

	session, err := mgo.Dial(*mongoUrl)
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	Sessions := session.DB("").C(*collection)
	counter, err := Sessions.Count()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf("Number of item(s) in           %s: %d", *collection, counter))

	duration := time.Now().Add(time.Duration(-*retention) * time.Hour)
	query := bson.M{fmt.Sprintf("%s", *field): bson.M{"$lte": duration}}

	counter_to_delete, err := Sessions.Find(query).Count()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf("Number of item(s) to delete in %s: %d", *collection, counter_to_delete))

	info, err := Sessions.RemoveAll(query)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf("Number of item(s) deleted in   %s: %d", *collection, info.Removed))
}
<commit_msg>Add a simulation mode<commit_after>package main

import (
	"flag"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
	"net/url"
	"time"
)

var mongoUrl = flag.String("url", "mongodb://localhost:27017/test", "MongoDB connection URI.")
var collection = flag.String("c", "sessions", "MongoDB collection to cleanup.")
var field = flag.String("f", "updated_at", "MongoDB collection field with type 'time.Time'.")
var retention = flag.Int("r", 168, "MongoDB retention delai in hour(s). Default is 7 days (168 hours).")
var simulation = flag.Bool("s", false, "Simulation mode, no deletion are send to the MongoDB database.")

// Version is initialized at compilation time
var Version = "0.0.0"

// BuildTime is initialized at compilation time
var BuildTime = time.Now().Format(time.RFC3339)

func main() {
	flag.Parse()

	hostPort, err := url.Parse(*mongoUrl)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("MongoDB connection URL:              ", hostPort.Host)
	fmt.Println("MongoDB collection to clean:         ", *collection)
	fmt.Println("MongoDB collection field:            ", *field)
	fmt.Println("MongoDB retention periode in hour(s):", *retention)
	fmt.Println("Simulation mode:                     ", *simulation)
	fmt.Println()

	session, err := mgo.Dial(*mongoUrl)
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	Sessions := session.DB("").C(*collection)
	counter, err := Sessions.Count()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf("Number of item(s) in           %s: %d", *collection, counter))

	duration := time.Now().Add(time.Duration(-*retention) * time.Hour)
	query := bson.M{fmt.Sprintf("%s", *field): bson.M{"$lte": duration}}

	counter_to_delete, err := Sessions.Find(query).Count()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf("Number of item(s) to delete in %s: %d", *collection, counter_to_delete))

	if *simulation == false {
		info, err := Sessions.RemoveAll(query)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(fmt.Sprintf("Number of item(s) deleted in   %s: %d", *collection, info.Removed))
	} else {
		fmt.Println("[SIMULATION_MODE] In simulation mode no elements are deleted!!!")
	}
}
<|endoftext|>


<commit_before>package main

// vouch
// github.com/vouch/vouch-proxy

import (
	"log"
	"net/http"
	"path/filepath"
	"strconv"
	"time"

	"github.com/gorilla/mux"
	"go.uber.org/zap"

	"github.com/vouch/vouch-proxy/handlers"
	"github.com/vouch/vouch-proxy/pkg/cfg"
	"github.com/vouch/vouch-proxy/pkg/timelog"
	tran "github.com/vouch/vouch-proxy/pkg/transciever"
)

// version and semver get overwritten by build with
// go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)"
var (
	version   = "undefined"
	builddt   = "undefined"
	host      = "undefined"
	semver    = "undefined"
	branch    = "undefined"
	staticDir = "/static/"
	logger    = cfg.Cfg.Logger
	fastlog   = cfg.Cfg.FastLogger
)

// fwdToZapWriter allows us to use the zap.Logger as our http.Server ErrorLog
// see https://stackoverflow.com/questions/52294334/net-http-set-custom-logger
type fwdToZapWriter struct {
	logger *zap.Logger
}

func (fw *fwdToZapWriter) Write(p []byte) (n int, err error) {
	fw.logger.Error(string(p))
	return len(p), nil
}

func main() {
	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	logger.Infow("starting "+cfg.Branding.CcName,
		// "semver":    semver,
		"version", version,
		"buildtime", builddt,
		"buildhost", host,
		"branch", branch,
		"semver", semver,
		"listen", listen,
		"oauth.provider", cfg.GenOAuth.Provider)

	muxR := mux.NewRouter()

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	muxR.HandleFunc("/validate", timelog.TimeLog(authH))
	muxR.HandleFunc("/_external-auth-{id}", timelog.TimeLog(authH))

	loginH := http.HandlerFunc(handlers.LoginHandler)
	muxR.HandleFunc("/login", timelog.TimeLog(loginH))

	logoutH := http.HandlerFunc(handlers.LogoutHandler)
	muxR.HandleFunc("/logout", timelog.TimeLog(logoutH))

	callH := http.HandlerFunc(handlers.CallbackHandler)
	muxR.HandleFunc("/auth", timelog.TimeLog(callH))

	healthH := http.HandlerFunc(handlers.HealthcheckHandler)
	muxR.HandleFunc("/healthcheck", timelog.TimeLog(healthH))

	if logger.Desugar().Core().Enabled(zap.DebugLevel) {
		path, err := filepath.Abs(staticDir)
		if err != nil {
			logger.Errorf("couldn't find static assets at %s", path)
		}
		logger.Debugf("serving static files from %s", path)
	}
	// https://golangcode.com/serve-static-assets-using-the-mux-router/
	muxR.PathPrefix(staticDir).Handler(http.StripPrefix(staticDir, http.FileServer(http.Dir("."+staticDir))))

	if cfg.Cfg.WebApp {
		logger.Info("enabling websocket")
		tran.ExplicitInit()
		muxR.Handle("/ws", tran.WS)
	}

	// socketio := tran.NewServer()
	// muxR.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	srv := &http.Server{
		Handler: muxR,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
		ErrorLog:     log.New(&fwdToZapWriter{fastlog}, "", 0),
	}

	log.Fatal(srv.ListenAndServe())

}
<commit_msg>#120 set path to static assets using VOUCH_ROOT<commit_after>package main

// vouch
// github.com/vouch/vouch-proxy

import (
	"log"
	"net/http"
	"path/filepath"
	"strconv"
	"time"

	"github.com/gorilla/mux"
	"go.uber.org/zap"

	"github.com/vouch/vouch-proxy/handlers"
	"github.com/vouch/vouch-proxy/pkg/cfg"
	"github.com/vouch/vouch-proxy/pkg/timelog"
	tran "github.com/vouch/vouch-proxy/pkg/transciever"
)

// version and semver get overwritten by build with
// go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)"
var (
	version   = "undefined"
	builddt   = "undefined"
	host      = "undefined"
	semver    = "undefined"
	branch    = "undefined"
	staticDir = "/static/"
	logger    = cfg.Cfg.Logger
	fastlog   = cfg.Cfg.FastLogger
)

// fwdToZapWriter allows us to use the zap.Logger as our http.Server ErrorLog
// see https://stackoverflow.com/questions/52294334/net-http-set-custom-logger
type fwdToZapWriter struct {
	logger *zap.Logger
}

func (fw *fwdToZapWriter) Write(p []byte) (n int, err error) {
	fw.logger.Error(string(p))
	return len(p), nil
}

func main() {
	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	logger.Infow("starting "+cfg.Branding.CcName,
		// "semver":    semver,
		"version", version,
		"buildtime", builddt,
		"buildhost", host,
		"branch", branch,
		"semver", semver,
		"listen", listen,
		"oauth.provider", cfg.GenOAuth.Provider)

	muxR := mux.NewRouter()

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	muxR.HandleFunc("/validate", timelog.TimeLog(authH))
	muxR.HandleFunc("/_external-auth-{id}", timelog.TimeLog(authH))

	loginH := http.HandlerFunc(handlers.LoginHandler)
	muxR.HandleFunc("/login", timelog.TimeLog(loginH))

	logoutH := http.HandlerFunc(handlers.LogoutHandler)
	muxR.HandleFunc("/logout", timelog.TimeLog(logoutH))

	callH := http.HandlerFunc(handlers.CallbackHandler)
	muxR.HandleFunc("/auth", timelog.TimeLog(callH))

	healthH := http.HandlerFunc(handlers.HealthcheckHandler)
	muxR.HandleFunc("/healthcheck", timelog.TimeLog(healthH))

	// setup static
	sPath, err := filepath.Abs(cfg.RootDir + staticDir)
	if logger.Desugar().Core().Enabled(zap.DebugLevel) {
		if err != nil {
			logger.Errorf("couldn't find static assets at %s", sPath)
		}
		logger.Debugf("serving static files from %s", sPath)
	}
	// https://golangcode.com/serve-static-assets-using-the-mux-router/
	muxR.PathPrefix(staticDir).Handler(http.StripPrefix(staticDir, http.FileServer(http.Dir(sPath))))

	if cfg.Cfg.WebApp {
		logger.Info("enabling websocket")
		tran.ExplicitInit()
		muxR.Handle("/ws", tran.WS)
	}

	// socketio := tran.NewServer()
	// muxR.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	srv := &http.Server{
		Handler: muxR,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
		ErrorLog:     log.New(&fwdToZapWriter{fastlog}, "", 0),
	}

	log.Fatal(srv.ListenAndServe())

}
<|endoftext|>


<commit_before>// Package main hosts the main function for taskcluter-worker.
//
// The code is structured in 4 kinds of extension registries. The
// commands, config, engines and plugins packages each define interfaces and
// registries where implementations of these interfaces can be registered.
//
// To add a new command to taskcluster-worker you must create new sub-package of
// commands/ which implements and registers commands.CommandProvider with the
// commands.Register(name, provider) method. The same pattern is followed for
// implementation of config transformers, engines, and plugins.
//
// All the sub-packages are then imported here, which ensure that they'll all
// be included in the respective extension registries. Exceptions to this
// pattern is the runtime and worker packages. The runtime package and its
// sub-packages implements generic abstractions and utilities to be used by all
// other packages. The worker package implements task execution flow to be used
// by commands.
package main

import "github.com/taskcluster/taskcluster-worker/commands"

// Import all sub-packages from commands/, config/, engines/ and plugins/
// as they will register themselves using extension registries.
import (
	_ "github.com/taskcluster/taskcluster-worker/commands/daemon"
	_ "github.com/taskcluster/taskcluster-worker/commands/help"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-build"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-guest-tools"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-run"
	_ "github.com/taskcluster/taskcluster-worker/commands/schema"
	_ "github.com/taskcluster/taskcluster-worker/commands/shell"
	_ "github.com/taskcluster/taskcluster-worker/commands/shell-server"
	_ "github.com/taskcluster/taskcluster-worker/commands/work"
	_ "github.com/taskcluster/taskcluster-worker/config/abs"
	_ "github.com/taskcluster/taskcluster-worker/config/configtest"
	_ "github.com/taskcluster/taskcluster-worker/config/env"
	_ "github.com/taskcluster/taskcluster-worker/config/packet"
	_ "github.com/taskcluster/taskcluster-worker/config/secrets"
	_ "github.com/taskcluster/taskcluster-worker/engines/enginetest"
	_ "github.com/taskcluster/taskcluster-worker/engines/mock"
	_ "github.com/taskcluster/taskcluster-worker/engines/native"
	_ "github.com/taskcluster/taskcluster-worker/engines/osxnative"
	_ "github.com/taskcluster/taskcluster-worker/engines/qemu"
	_ "github.com/taskcluster/taskcluster-worker/engines/script"
	_ "github.com/taskcluster/taskcluster-worker/plugins/artifacts"
	_ "github.com/taskcluster/taskcluster-worker/plugins/env"
	_ "github.com/taskcluster/taskcluster-worker/plugins/interactive"
	_ "github.com/taskcluster/taskcluster-worker/plugins/livelog"
	_ "github.com/taskcluster/taskcluster-worker/plugins/maxruntime"
	_ "github.com/taskcluster/taskcluster-worker/plugins/plugintest"
	_ "github.com/taskcluster/taskcluster-worker/plugins/reboot"
	_ "github.com/taskcluster/taskcluster-worker/plugins/success"
)

func main() {
	commands.Run(nil)
}
<commit_msg>Remove import of osxnative package<commit_after>// Package main hosts the main function for taskcluter-worker.
//
// The code is structured in 4 kinds of extension registries. The
// commands, config, engines and plugins packages each define interfaces and
// registries where implementations of these interfaces can be registered.
//
// To add a new command to taskcluster-worker you must create new sub-package of
// commands/ which implements and registers commands.CommandProvider with the
// commands.Register(name, provider) method. The same pattern is followed for
// implementation of config transformers, engines, and plugins.
//
// All the sub-packages are then imported here, which ensure that they'll all
// be included in the respective extension registries. Exceptions to this
// pattern is the runtime and worker packages. The runtime package and its
// sub-packages implements generic abstractions and utilities to be used by all
// other packages. The worker package implements task execution flow to be used
// by commands.
package main

import "github.com/taskcluster/taskcluster-worker/commands"

// Import all sub-packages from commands/, config/, engines/ and plugins/
// as they will register themselves using extension registries.
import (
	_ "github.com/taskcluster/taskcluster-worker/commands/daemon"
	_ "github.com/taskcluster/taskcluster-worker/commands/help"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-build"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-guest-tools"
	_ "github.com/taskcluster/taskcluster-worker/commands/qemu-run"
	_ "github.com/taskcluster/taskcluster-worker/commands/schema"
	_ "github.com/taskcluster/taskcluster-worker/commands/shell"
	_ "github.com/taskcluster/taskcluster-worker/commands/shell-server"
	_ "github.com/taskcluster/taskcluster-worker/commands/work"
	_ "github.com/taskcluster/taskcluster-worker/config/abs"
	_ "github.com/taskcluster/taskcluster-worker/config/configtest"
	_ "github.com/taskcluster/taskcluster-worker/config/env"
	_ "github.com/taskcluster/taskcluster-worker/config/packet"
	_ "github.com/taskcluster/taskcluster-worker/config/secrets"
	_ "github.com/taskcluster/taskcluster-worker/engines/enginetest"
	_ "github.com/taskcluster/taskcluster-worker/engines/mock"
	_ "github.com/taskcluster/taskcluster-worker/engines/native"
	_ "github.com/taskcluster/taskcluster-worker/engines/qemu"
	_ "github.com/taskcluster/taskcluster-worker/engines/script"
	_ "github.com/taskcluster/taskcluster-worker/plugins/artifacts"
	_ "github.com/taskcluster/taskcluster-worker/plugins/env"
	_ "github.com/taskcluster/taskcluster-worker/plugins/interactive"
	_ "github.com/taskcluster/taskcluster-worker/plugins/livelog"
	_ "github.com/taskcluster/taskcluster-worker/plugins/maxruntime"
	_ "github.com/taskcluster/taskcluster-worker/plugins/plugintest"
	_ "github.com/taskcluster/taskcluster-worker/plugins/reboot"
	_ "github.com/taskcluster/taskcluster-worker/plugins/success"
)

func main() {
	commands.Run(nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func main() {
	fmt.Println("Starting new game\n")
	deck := NewDeck()
	for i := 0; i < 16; i++ {
		err, card := deck.Draw()
		if err != nil {
			fmt.Println(err)
		} else {
			card.Describe()
		}
	}
}
<commit_msg>Fleshing out a CLI<commit_after>package main

import (
	"fmt"
)

var currentRound *Round

func getPlayers() []*Player {
	var name string
	var players []*Player
	for i := 0; i < 2; i++ {
		fmt.Printf("Enter Player%d name:", i)
		_, err := fmt.Scanln(&name)
		if err != nil {
			fmt.Print(err)
			continue
		}
		players = append(players, NewPlayer(name))
	}
	return players
}

func main() {
	fmt.Println("Starting new game\n")
	players := getPlayers()
	currentRound = NewRound(players)
	fmt.Printf("there are %d players\n", currentRound.NumberOfPlayers())
	for i := 0; i < currentRound.NumberOfActivePlayers(); i++ {
		fmt.Printf("%s has %s in their hand\n", players[i].Name, players[i].Hand[0].Name())
	}
}

// Order of play:
// Deal cards to all players.
// Current player takes second card
// Current player makes decision + Discards card
// Action is resolved
// Next player
<|endoftext|>