<commit_before>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

//VARIABILI
var Matrix [][]*Element
var Altezza int
var Larghezza int
var SaluteIniziale int
var Clock uint
var NumClock uint

func main() { //FUNZIONE MAIN
	SaluteIniziale = 50
	Clock = 1
	NumClock = 0
	height, err := strconv.Atoi(os.Args[1])
	if err != nil {
		panic("height not valid")
	}
	width, err2 := strconv.Atoi(os.Args[2])
	if err2 != nil {
		panic("width not valid")
	}
	Altezza = height
	Larghezza = width
	Matrix = make([][]*Element, height)
	for i := range Matrix { // inizializzazione matrice
		Matrix[i] = make([]*Element, width)
		for j := range Matrix[i] {
			chose := rand.Intn(2) //scelta rando cibo bug o vuoto (null)
			switch chose {
			case 0:
				Matrix[i][j] = new(Element) // insetto
				Matrix[i][j].IsFood = false
				Matrix[i][j].Age = 0
				Matrix[i][j].Health = SaluteIniziale
			case 1:
				Matrix[i][j] = nil //vuota
			case 2:
				Matrix[i][j] = new(Element) // cibo
				Matrix[i][j].IsFood = true
				Matrix[i][j].Health = 5
			}
		}
	}
	fmt.Println("Situazione iniziale: ")
	stampaMatrice()

	aggiorna()
}

func aggiorna() { //FUNZIONE AGGIORNA:	chiama la funzione muovi
	for {
		time.Sleep(time.Second * time.Duration(Clock))
		NumClock++
		for i := 0; i < Altezza; i++ {
			for j := 0; j < Larghezza; j++ {
				muovi(i, j)
			}
		}
		fmt.Printf("\nSituazione dopo %d movimenti:\n", NumClock)
		stampaMatrice()
	}
}

func muovi(h int, w int) { //FUNZIONE MUOVI:	aggiorna la posizione di tutti gli oggetti in tabella	// h verticale, w orizzontale
	elemento := Matrix[h][w]                //assegnamente del contenuto della cella in 'elemento'
	if elemento == nil || elemento.IsFood { //controllo se 'elemento' è cibo o un altro essere
		return
	}
	direzCasOriz := rand.Intn(2)
	direzCasOriz--
	direzCasVert := rand.Intn(2)
	direzCasVert--
	nuovaPosizioneH := h + direzCasVert //aggiornamento posiozione verticale
	nuovaPosizioneW := w + direzCasOriz //aggiornamento posizione orizzontale

	if nuovaPosizioneH >= Altezza || nuovaPosizioneH < 0 ||
		nuovaPosizioneW >= Larghezza || nuovaPosizioneW < 0 { //se esce dai bordi
		return
	}

	fmt.Println(nuovaPosizioneH, nuovaPosizioneW)

	if tmpNewElem := Matrix[nuovaPosizioneH][nuovaPosizioneW]; tmpNewElem != nil {
		if tmpNewElem.IsFood || tmpNewElem.Health < elemento.Health { // se e' cibo o un insetto piu debole
			elemento.Health += tmpNewElem.Health                //prelevamento energia essere fagocitato
			Matrix[nuovaPosizioneH][nuovaPosizioneW] = elemento //inglobamento essere perito
		} else {
			Matrix[h][w] = nil                   //perdita nel combattimento per la sopravvivenza
			tmpNewElem.Health += elemento.Health //il nemico prende l'energia
		}
	} else { //si muove sulla nuova casella
		Matrix[nuovaPosizioneH][nuovaPosizioneW] = elemento
		Matrix[h][w] = nil
	}
}

func stampaMatrice() {
	for i := 0; i < Altezza; i++ {
		fmt.Printf("Riga %d:\n", i)
		for j := 0; j < Larghezza; j++ {
			var stringa string
			elem := Matrix[i][j]
			if elem == nil {
				stringa = "Vuota"
			} else {
				stringa = elem.String()
			}
			fmt.Printf("  Colonna %d: %s\n", j, stringa)
		}
	}
}
<commit_msg>Init random seed<commit_after>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

//VARIABILI
var Matrix [][]*Element
var Altezza int
var Larghezza int
var SaluteIniziale int
var Clock uint
var NumClock uint

func main() { //FUNZIONE MAIN
	SaluteIniziale = 50
	Clock = 1
	NumClock = 0
	rand.Seed(time.Now().UTC().UnixNano()) //inizializzazione rand
	height, err := strconv.Atoi(os.Args[1])
	if err != nil {
		panic("height not valid")
	}
	width, err2 := strconv.Atoi(os.Args[2])
	if err2 != nil {
		panic("width not valid")
	}
	Altezza = height
	Larghezza = width
	Matrix = make([][]*Element, height)
	for i := range Matrix { // inizializzazione matrice
		Matrix[i] = make([]*Element, width)
		for j := range Matrix[i] {
			chose := rand.Intn(3) //scelta rando cibo bug o vuoto (null)
			switch chose {
			case 0:
				Matrix[i][j] = new(Element) // insetto
				Matrix[i][j].IsFood = false
				Matrix[i][j].Age = 0
				Matrix[i][j].Health = SaluteIniziale
			case 1:
				Matrix[i][j] = nil //vuota
			case 2:
				Matrix[i][j] = new(Element) // cibo
				Matrix[i][j].IsFood = true
				Matrix[i][j].Health = 5
			}
		}
	}
	fmt.Println("Situazione iniziale: ")
	stampaMatrice()

	aggiorna()
}

func aggiorna() { //FUNZIONE AGGIORNA:	chiama la funzione muovi
	for {
		time.Sleep(time.Second * time.Duration(Clock))
		NumClock++
		for i := 0; i < Altezza; i++ {
			for j := 0; j < Larghezza; j++ {
				muovi(i, j)
			}
		}
		fmt.Printf("\nSituazione dopo %d movimenti:\n", NumClock)
		stampaMatrice()
	}
}

func muovi(h int, w int) { //FUNZIONE MUOVI:	aggiorna la posizione di tutti gli oggetti in tabella	// h verticale, w orizzontale
	elemento := Matrix[h][w]                //assegnamente del contenuto della cella in 'elemento'
	if elemento == nil || elemento.IsFood { //controllo se 'elemento' è cibo o un altro essere
		return
	}
	direzCasOriz := rand.Intn(2)
	direzCasOriz--
	direzCasVert := rand.Intn(2)
	direzCasVert--
	nuovaPosizioneH := h + direzCasVert //aggiornamento posiozione verticale
	nuovaPosizioneW := w + direzCasOriz //aggiornamento posizione orizzontale

	if nuovaPosizioneH >= Altezza || nuovaPosizioneH < 0 ||
		nuovaPosizioneW >= Larghezza || nuovaPosizioneW < 0 { //se esce dai bordi
		return
	}

	fmt.Println(nuovaPosizioneH, nuovaPosizioneW)

	if tmpNewElem := Matrix[nuovaPosizioneH][nuovaPosizioneW]; tmpNewElem != nil {
		if tmpNewElem.IsFood || tmpNewElem.Health < elemento.Health { // se e' cibo o un insetto piu debole
			elemento.Health += tmpNewElem.Health                //prelevamento energia essere fagocitato
			Matrix[nuovaPosizioneH][nuovaPosizioneW] = elemento //inglobamento essere perito
		} else {
			Matrix[h][w] = nil                   //perdita nel combattimento per la sopravvivenza
			tmpNewElem.Health += elemento.Health //il nemico prende l'energia
		}
	} else { //si muove sulla nuova casella
		Matrix[nuovaPosizioneH][nuovaPosizioneW] = elemento
		Matrix[h][w] = nil
	}
}

func stampaMatrice() {
	for i := 0; i < Altezza; i++ {
		fmt.Printf("Riga %d:\n", i)
		for j := 0; j < Larghezza; j++ {
			var stringa string
			elem := Matrix[i][j]
			if elem == nil {
				stringa = "Vuota"
			} else {
				stringa = elem.String()
			}
			fmt.Printf("  Colonna %d: %s\n", j, stringa)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
)

func main() {
	log.Println("Listening on port 3000")
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "index.html")
	})
	http.ListenAndServe(":3000", nil)

}
<commit_msg>accepting port from Heroku CLI<commit_after>package main

import (

	"net/http"
	"os"
)

func main() {

	port := os.Getenv("PORT")
	if port == "" {
		port = "8000"
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "index.html")
	})
	http.ListenAndServe(":"+port, nil)

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"os/exec"
	"strings"
)

var queue chan string

func animeList(w http.ResponseWriter, r *http.Request) {
	seriesPage, err := FetchPageContents(UrlPseudoJoin("/"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	series, err := ExtractSeriesList(seriesPage)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	j, _ := json.Marshal(series)
	w.Write(j)
}

func animeDetail(w http.ResponseWriter, r *http.Request) {
	pathSplit := strings.Split(r.URL.Path, "/")
	if len(pathSplit[2]) < 1 {
		http.Error(w, "you must specify animeme", http.StatusBadRequest)
		return
	}
	episodesPage, err := FetchPageContents(UrlPseudoJoin("/a/" + pathSplit[2]))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	episodes, err := ExtractEpisodesList(episodesPage)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	j, _ := json.Marshal(episodes)
	w.Write(j)
}

func externPlay(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if len(url) <3 {
		http.Error(w, "you must specify url parameter", http.StatusBadRequest)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	select {
	case queue <- url:
		w.Write([]byte("{}"))
	default:
		http.Error(w, "queue full", http.StatusTooManyRequests)
	}
}

func animePlay(w http.ResponseWriter, r *http.Request) {
	pathSplit := strings.Split(r.URL.Path, "/")
	if len(pathSplit) < 4 {
		http.Error(w, "you must specify animeme and episode number", http.StatusBadRequest)
		return
	}
	if len(pathSplit[2]) < 1 {
		http.Error(w, "you must specify animeme", http.StatusBadRequest)
		return
	}
	if len(pathSplit[3]) < 1 {
		http.Error(w, "you must specify episode", http.StatusBadRequest)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	select {
	case queue <- UrlPseudoJoin("/a/" + r.URL.Path[len("/play/"):]):
		w.Write([]byte("{}"))
	default:
		http.Error(w, "queue full", http.StatusTooManyRequests)
	}
}

func handleQueue() {
	for {
		url := <-queue
		exec.Command("mpv", "--fs", url).Run()
	}
}

func main() {
	queue = make(chan string, 100)
	go handleQueue()
	http.HandleFunc("/list", animeList)
	http.HandleFunc("/detail/", animeDetail)
	http.HandleFunc("/play/", animePlay)
	http.HandleFunc("/extern/", externPlay)
	http.Handle("/", http.FileServer(http.Dir("static")))
	http.ListenAndServe(":3000", nil)
}
<commit_msg>more logging y'all<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os/exec"
	"strings"
)

var queue chan string

func animeList(w http.ResponseWriter, r *http.Request) {
	log.Print("anime list requested")
	seriesPage, err := FetchPageContents(UrlPseudoJoin("/"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	series, err := ExtractSeriesList(seriesPage)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	j, _ := json.Marshal(series)
	w.Write(j)
	log.Print("anime list request fulfilled")
}

func animeDetail(w http.ResponseWriter, r *http.Request) {
	pathSplit := strings.Split(r.URL.Path, "/")
	if len(pathSplit[2]) < 1 {
		http.Error(w, "you must specify animeme", http.StatusBadRequest)
		log.Print("episodes list requested for unspecified anime")
		return
	}
	log.Printf("episodes list requested for %v", pathSplit[2])
	episodesPage, err := FetchPageContents(UrlPseudoJoin("/a/" + pathSplit[2]))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	episodes, err := ExtractEpisodesList(episodesPage)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	j, _ := json.Marshal(episodes)
	w.Write(j)
	log.Printf("episodes list for %v fulfilled", pathSplit[2])
}

func enqueue(url string) bool {
	select {
	case queue <- url:
		log.Print("enqueued:", url)
		return true
	default:
		return false
	}
}

func externPlay(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if len(url) <3 {
		http.Error(w, "you must specify url parameter", http.StatusBadRequest)
		log.Print("extern request without url")
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	if !enqueue(url) {
		http.Error(w, "queue full", http.StatusTooManyRequests)
		log.Print("queue full for", url)
		return
	}
	w.Write([]byte("{}"))
}

func animePlay(w http.ResponseWriter, r *http.Request) {
	pathSplit := strings.Split(r.URL.Path, "/")
	if len(pathSplit) < 4 {
		http.Error(w, "you must specify animeme and episode number", http.StatusBadRequest)
		return
	}
	if len(pathSplit[2]) < 1 {
		http.Error(w, "you must specify animeme", http.StatusBadRequest)
		return
	}
	if len(pathSplit[3]) < 1 {
		http.Error(w, "you must specify episode", http.StatusBadRequest)
		return
	}
	h := w.Header()
	h.Add("Content-Type", "application/json")
	url := UrlPseudoJoin("/a/" + r.URL.Path[len("/play/"):])
	if !enqueue(url) {
		http.Error(w, "queue full", http.StatusTooManyRequests)
		log.Print("queue full for", url)
		return
	}
	w.Write([]byte("{}"))
}

func handleQueue() {
	for {
		url := <-queue
		log.Print("starting to play", url)
		exec.Command("mpv", "-v", "--fs", url).Run()
		log.Print("playback finished")
	}
}

func main() {
	queue = make(chan string, 100)
	go handleQueue()
	http.HandleFunc("/list", animeList)
	http.HandleFunc("/detail/", animeDetail)
	http.HandleFunc("/play/", animePlay)
	http.HandleFunc("/extern/", externPlay)
	http.Handle("/", http.FileServer(http.Dir("static")))
	log.Print("launching")
	http.ListenAndServe(":3000", nil)
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 is a simple wrapper of the real etcd entrypoint package
// (located at github.com/coreos/etcd/etcdmain) to ensure that etcd is still
// "go getable"; e.g. `go get github.com/coreos/etcd` works as expected and
// builds a binary in $GOBIN/etcd
//
// This package should NOT be extended or modified in any way; to modify the
// etcd binary, work in the `github.com/coreos/etcd/etcdmain` package.
//

package main

import (
	"flag"
	"fmt"
	"os"
	"regexp"

	"github.com/coreos/etcd-starter/starter"
)

const defaultInternalBinaryDir = "/usr/libexec/etcd/internal_versions/"

const usage = `usage: etcd-starter [flags]
start v0.4 or v2.0 etcd server based on the layout of data directory and the content inside wal and snapshot

etcd-starter --version
show the version of etcd-starter and exit.

etcd-starter -h | --help
show the help information about etcd

etcd-starter [etcd flags]
start v0.4 or v2.0 etcd using the given flags

Please check etcd documents for more information about etcd flag usage.
`

var (
	showVersion bool
)

func main() {
	fs := flag.NewFlagSet("etcd-starter", flag.ContinueOnError)
	fs.BoolVar(&showVersion, "version", false, "print version and exit")
	fs.Usage = func() {
		fmt.Println(usage)
		os.Exit(0)
	}

	mainArgs, etcdArgs := filterArgs()
	fs.Parse(mainArgs)

	dir := os.Getenv("ETCD_INTERNAL_BINARY_DIR")
	if dir == "" {
		dir = defaultInternalBinaryDir
	}

	if showVersion {
		printVersions(dir)
		os.Exit(0)
	}

	starter.StartDesiredVersion(dir, etcdArgs)
}

func filterArgs() ([]string, []string) {
	mainArgs := make([]string, 0)
	etcdArgs := make([]string, 0)
	pattern := regexp.MustCompile("--version|-version|-h|--help|-help")
	for _, arg := range os.Args[1:] {
		if pattern.MatchString(arg) {
			mainArgs = append(mainArgs, arg)
			continue
		}
		etcdArgs = append(etcdArgs, arg)
	}
	return mainArgs, etcdArgs
}
<commit_msg>Revert "etcd-starter: add version flag"<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 is a simple wrapper of the real etcd entrypoint package
// (located at github.com/coreos/etcd/etcdmain) to ensure that etcd is still
// "go getable"; e.g. `go get github.com/coreos/etcd` works as expected and
// builds a binary in $GOBIN/etcd
//
// This package should NOT be extended or modified in any way; to modify the
// etcd binary, work in the `github.com/coreos/etcd/etcdmain` package.
//

package main

import (
	"os"

	"github.com/coreos/etcd-starter/starter"
)

const defaultInternalBinaryDir = "/usr/libexec/etcd/internal_versions/"

func main() {
	dir := os.Getenv("ETCD_INTERNAL_BINARY_DIR")
	if dir == "" {
		dir = defaultInternalBinaryDir
	}
	starter.StartDesiredVersion(dir, os.Args[1:])
}
<|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 (
	"fmt"
	"io/ioutil"
	"log"
  //"unicode/utf8"
  //"container/list"
  //"bytes"
	"net/http"
	//"encoding/json"
	//"net/url"
    "strings"
	// "database/sql"
	"os"
	"github.com/line/line-bot-sdk-go/linebot"
	// _ "github.com/go-sql-driver/mysql"
)

var bot *linebot.Client
var echo string
var op string
var bottun bool

type Data struct{
    resultType string `json:"resultType"`
    resultQuestion string `json:"resultQuestion"`
    resultContent []content `json:"resultContent"`
    requirementType string `json:"requirementType"`
}

type content struct{
    entity string `json:"entity"`
    Type string `json:"Type"`
}

var d Data

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
    http.HandleFunc("/", sayhelloName) // set router
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)

    bottun = false
}

func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()  // parse arguments, you have to call this by yourself
    fmt.Println(r.Form)  // print form information in server side
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["user"])
    fmt.Println(r.Form["message"])
    bot.PushMessage(r.Form["user"][0], linebot.NewTextMessage(r.Form["message"][0])).Do()
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, r.Form["user"][0]+r.Form["message"][0]) // send data to client side
}

// func mysql(){
// 	var db, err = sql.Open("mysql","wmlab:wmlab@tcp(140.115.54.82:3306)/wmlab?charset=utf8")
// 	if err != nil {
// 		fmt.Println(err)
//          // Just for example purpose. You should use proper error handling instead of panic
//     }
//     defer db.Close()

//  	err = db.Ping()
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	rows, err := db.Query("select * from test")
// 	if err != nil {
// 		log.Println(err)
// 	}

// 	defer rows.Close()
// 	var col1 int
// 	for rows.Next() {
// 		err := rows.Scan(&col1)
// 		if err != nil {
// 			log.Fatal(err)
// 		}
// 		dbinfo=col1
// 	}
// }
func httpGet(q string , id string) {

    echo = "OK"
    bottun = false
    op = ""

    q = strings.Replace( q , " " , "," , -1)
    //q = strings.Replace("oink oink oink", "oink", "moo", -1)
    resp, err := http.Get("http://140.115.54.93:8088/?q="+q+"&id="+id)
    if err != nil {
        // handle error
       panic(err.Error())
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
       panic(err.Error())
    }

    echo = string(body)

    if echo == "location"{
       bottun = true
    }

    // _, err = bot.PushMessage("Uf6263c4b814700c680228b8b64a27dd6", linebot.NewTextMessage(echo)).Do()

    //------------for Luis
    // var r =  map[string]interface{}{}
    // var tempString string
    // tempString =string(body)

    // temp1 := strings.Split(tempString,"entity")
    // temp2 := strings.Split(tempString,"\"Type")
    // entity := list.New()
    // Type := list.New()
    // for i := 0; i < len(temp1); i++ {
    //   if i>=1{
    //     entity.PushBack( strings.Split(strings.Split(temp1[i],"\",")[0],":\"")[1] )
    //   }
    // }
    // for i := 0; i < len(temp2); i++ {
    //   if i>=1{
    //     Type.PushBack( strings.Split(strings.Split(temp2[i],"\"}")[0],":\"")[1] )
    //   }
    // }
    // json.Unmarshal(body, &r)

    // if r["resultType"].(string) == "none" {
    //   echo = "我不了解你在說什麼～@@"
    // } else if r["resultType"].(string) == "greeting" {
    //   echo = "你好！我是LUIS！我可以提供您數學的教材或是練習題喔！"
    // } else if r["resultType"].(string) == "appreciation" {
    //   echo = "歡迎您再次使用LUIS!我很樂意再次提供您服務！"
    // } else if r["resultType"].(string) == "connectionError" {
    //   echo = "對不起，我出了點問題，現在沒辦法回答你問題@@"
    // } else if r["resultType"].(string) == "unknown" {
    //   echo = "不好意思，我不知道你問的定理是什麼QQ"
    // } else if r["resultType"].(string) == "question" {
    //   if r["requirementType"].(string) == "none" {
    //     bottun = true
    //     for e:= entity.Front();e!=nil;e = e.Next(){

    //      op += e.Value.(string)
    //     }
    //   }
    // }

    //-----------------for luis

}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	//GG

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:

        if op!= ""{
          echo ="OK"
          bottun = false

        } else if event.Source.UserID == ""{
            _, err = bot.PushMessage("Uf6263c4b814700c680228b8b64a27dd6", linebot.NewTextMessage(message.Text)).Do()
            if err != nil {
            // handle error
            //    ..
            echo = err.Error()
            }

        } else {
        	httpGet(message.Text,event.Source.UserID)
        }
				// mysql()
				//message.ID+":"+message.Text
        if bottun {
           //_, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(echo)).Do()
            // var ff string
            // var gg string
            // ff = "我要"+op+"的練習題"
            // gg = "我要"+op+"的教材"
            // leftBtn := linebot.NewMessageTemplateAction("練習題", ff)
            // rightBtn := linebot.NewMessageTemplateAction("教材", gg)
            uri := linebot.NewURITemplateAction("提供地點",'line://nv/location')
            template := linebot.NewButtonsTemplate("請問您目前所處的地點是?",'','', uri)

            templatemessgage := linebot.NewTemplateMessage("Sorry :(, please update your app.", template)
            _, err = bot.ReplyMessage(event.ReplyToken, templatemessgage).Do()
           //op=""

        } else {
           _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage( echo )).Do()
           // _, err = bot.PushMessage(event.ReplyToken, linebot.NewTextMessage( echo )).Do()
           op=""
        }

			}
		}
	}
}
<commit_msg>FF<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 (
	"fmt"
	"io/ioutil"
	"log"
  //"unicode/utf8"
  //"container/list"
  //"bytes"
	"net/http"
	//"encoding/json"
	//"net/url"
    "strings"
	// "database/sql"
	"os"
	"github.com/line/line-bot-sdk-go/linebot"
	// _ "github.com/go-sql-driver/mysql"
)

var bot *linebot.Client
var echo string
var op string
var bottun bool

type Data struct{
    resultType string `json:"resultType"`
    resultQuestion string `json:"resultQuestion"`
    resultContent []content `json:"resultContent"`
    requirementType string `json:"requirementType"`
}

type content struct{
    entity string `json:"entity"`
    Type string `json:"Type"`
}

var d Data

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
    http.HandleFunc("/", sayhelloName) // set router
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)

    bottun = false
}

func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()  // parse arguments, you have to call this by yourself
    fmt.Println(r.Form)  // print form information in server side
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["user"])
    fmt.Println(r.Form["message"])
    bot.PushMessage(r.Form["user"][0], linebot.NewTextMessage(r.Form["message"][0])).Do()
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, r.Form["user"][0]+r.Form["message"][0]) // send data to client side
}

// func mysql(){
// 	var db, err = sql.Open("mysql","wmlab:wmlab@tcp(140.115.54.82:3306)/wmlab?charset=utf8")
// 	if err != nil {
// 		fmt.Println(err)
//          // Just for example purpose. You should use proper error handling instead of panic
//     }
//     defer db.Close()

//  	err = db.Ping()
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	rows, err := db.Query("select * from test")
// 	if err != nil {
// 		log.Println(err)
// 	}

// 	defer rows.Close()
// 	var col1 int
// 	for rows.Next() {
// 		err := rows.Scan(&col1)
// 		if err != nil {
// 			log.Fatal(err)
// 		}
// 		dbinfo=col1
// 	}
// }
func httpGet(q string , id string) {

    echo = "OK"
    bottun = false
    op = ""

    q = strings.Replace( q , " " , "," , -1)
    //q = strings.Replace("oink oink oink", "oink", "moo", -1)
    resp, err := http.Get("http://140.115.54.93:8088/?q="+q+"&id="+id)
    if err != nil {
        // handle error
       panic(err.Error())
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
       panic(err.Error())
    }

    echo = string(body)

    if echo == "location"{
       bottun = true
    }

    // _, err = bot.PushMessage("Uf6263c4b814700c680228b8b64a27dd6", linebot.NewTextMessage(echo)).Do()

    //------------for Luis
    // var r =  map[string]interface{}{}
    // var tempString string
    // tempString =string(body)

    // temp1 := strings.Split(tempString,"entity")
    // temp2 := strings.Split(tempString,"\"Type")
    // entity := list.New()
    // Type := list.New()
    // for i := 0; i < len(temp1); i++ {
    //   if i>=1{
    //     entity.PushBack( strings.Split(strings.Split(temp1[i],"\",")[0],":\"")[1] )
    //   }
    // }
    // for i := 0; i < len(temp2); i++ {
    //   if i>=1{
    //     Type.PushBack( strings.Split(strings.Split(temp2[i],"\"}")[0],":\"")[1] )
    //   }
    // }
    // json.Unmarshal(body, &r)

    // if r["resultType"].(string) == "none" {
    //   echo = "我不了解你在說什麼～@@"
    // } else if r["resultType"].(string) == "greeting" {
    //   echo = "你好！我是LUIS！我可以提供您數學的教材或是練習題喔！"
    // } else if r["resultType"].(string) == "appreciation" {
    //   echo = "歡迎您再次使用LUIS!我很樂意再次提供您服務！"
    // } else if r["resultType"].(string) == "connectionError" {
    //   echo = "對不起，我出了點問題，現在沒辦法回答你問題@@"
    // } else if r["resultType"].(string) == "unknown" {
    //   echo = "不好意思，我不知道你問的定理是什麼QQ"
    // } else if r["resultType"].(string) == "question" {
    //   if r["requirementType"].(string) == "none" {
    //     bottun = true
    //     for e:= entity.Front();e!=nil;e = e.Next(){

    //      op += e.Value.(string)
    //     }
    //   }
    // }

    //-----------------for luis

}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	//GG

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:

        if op!= ""{
          echo ="OK"
          bottun = false

        } else if event.Source.UserID == ""{
            _, err = bot.PushMessage("Uf6263c4b814700c680228b8b64a27dd6", linebot.NewTextMessage(message.Text)).Do()
            if err != nil {
            // handle error
            //    ..
            echo = err.Error()
            }

        } else {
        	httpGet(message.Text,event.Source.UserID)
        }
				// mysql()
				//message.ID+":"+message.Text
        if bottun {
           //_, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(echo)).Do()
            // var ff string
            // var gg string
            // ff = "我要"+op+"的練習題"
            // gg = "我要"+op+"的教材"
            // leftBtn := linebot.NewMessageTemplateAction("練習題", ff)
            // rightBtn := linebot.NewMessageTemplateAction("教材", gg)
            uri := linebot.NewURITemplateAction("提供地點","line://nv/location")
            template := linebot.NewButtonsTemplate("請問您目前所處的地點是?","","", uri)

            templatemessgage := linebot.NewTemplateMessage("Sorry :(, please update your app.", template)
            _, err = bot.ReplyMessage(event.ReplyToken, templatemessgage).Do()
           //op=""

        } else {
           _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage( echo )).Do()
           // _, err = bot.PushMessage(event.ReplyToken, linebot.NewTextMessage( echo )).Do()
           op=""
        }

			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	log "github.com/Sirupsen/logrus"
	_ "github.com/mattn/go-sqlite3"
	"math/rand"
	"net/http"
	"os"
	"path"
	"time"
)

const coreOSAppID = "{e96281a6-d1af-4bde-9a0a-97b76e56dc57}"

var db *userDB
var fileBE fileBackend
var myHostname string // local hostname advertised in responses

func main() {
	var err error
	flag.StringVar(&myHostname, "hostname", "", "hostname advertised when using local file backend")
	flag.Parse()
	if myHostname == "" {
		log.Error("You must set the 'hostname' parameter when using local file backend.")
		os.Exit(1)
	}

	log.SetLevel(log.DebugLevel)
	log.Info("COmaha update server starting")

	// seed the RNG
	rand.Seed(time.Now().UnixNano())

	// open db
	db, err = newUserDB("users.sqlite")
	if err != nil {
		log.Errorf("Could not open database: %v", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	cwd, err := os.Getwd()
	if err != nil {
		log.Errorf("Could not cwd: %v", err.Error())
	}
	lfbe := newLocalFileBackend(path.Join(cwd, "storage"))
	fileBE = &lfbe

	http.HandleFunc("/file", fileHandler)
	http.HandleFunc("/update", updateHandler)
	http.HandleFunc("/shutdown", shutdownHandler)
	//http.HandleFunc("/admin/add_group", addGroupHandler)
	http.HandleFunc("/admin/add_payload", addPayloadHandler)
	//http.HandleFunc("/admin/add_user", addUserHandler)
	http.HandleFunc("/", homeHandler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>allow to specify listening address<commit_after>package main

import (
	"flag"
	"fmt"
	log "github.com/Sirupsen/logrus"
	_ "github.com/mattn/go-sqlite3"
	"math/rand"
	"net/http"
	"os"
	"path"
	"time"
)

const coreOSAppID = "{e96281a6-d1af-4bde-9a0a-97b76e56dc57}"

var db *userDB
var fileBE fileBackend
var myHostname string // local hostname advertised in responses
var listenAddr string // address to listen on

func main() {
	var err error
	flag.StringVar(&myHostname, "hostname", "", "hostname advertised when using local file backend")
	flag.StringVar(&listenAddr, "listenaddr", "0.0.0.0", "address to listen on")
	flag.Parse()
	if myHostname == "" {
		log.Error("You must set the 'hostname' parameter when using local file backend.")
		os.Exit(1)
	}

	log.SetLevel(log.DebugLevel)
	log.Info("COmaha update server starting")

	// seed the RNG
	rand.Seed(time.Now().UnixNano())

	// open db
	db, err = newUserDB("users.sqlite")
	if err != nil {
		log.Errorf("Could not open database: %v", err.Error())
		os.Exit(1)
	}
	defer db.Close()

	cwd, err := os.Getwd()
	if err != nil {
		log.Errorf("Could not cwd: %v", err.Error())
	}
	lfbe := newLocalFileBackend(path.Join(cwd, "storage"))
	fileBE = &lfbe

	http.HandleFunc("/file", fileHandler)
	http.HandleFunc("/update", updateHandler)
	http.HandleFunc("/shutdown", shutdownHandler)
	//http.HandleFunc("/admin/add_group", addGroupHandler)
	http.HandleFunc("/admin/add_payload", addPayloadHandler)
	//http.HandleFunc("/admin/add_user", addUserHandler)
	http.HandleFunc("/", homeHandler)

	listenString := fmt.Sprintf("%v:8080", listenAddr)
	http.ListenAndServe(listenString, nil)
}
<|endoftext|>


<commit_before>// Copyright © 2016 Pennock Tech, LLC.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

// We are canonically imported from go.pennock.tech/fingerd but because we are
// not a library, we do not apply this as an import constraint on the package
// declarations.  You can fork and build elsewhere more easily this way, while
// still getting dependencies without a dependency manager in play.
//
// This comment is just to let you know that the canonical import path is
// go.pennock.tech/fingerd and not now, nor ever, using DNS pointing to a
// code-hosting site not under our direct control.  We keep our options open,
// for moving where we keep the code publicly available.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
)

// I initially set 64 and in my first tests hit this because of an 84K .pubkey
// Let's be a _little_ more generous; 256KB by default let's one use send up to
// very slightly more than three-quarters of a MB.
const defaultFileSizeLimit = 256 * 1024

var opts struct {
	aliasfile           string
	listen              string
	homesDir            string
	runAsUser           string
	pidFile             string
	fileSizeLimit       int64
	listenTime          time.Duration
	requestReadTimeout  time.Duration
	requestWriteTimeout time.Duration
	minPasswdUID        uint64
	showVersion         bool
}

func init() {
	flag.StringVar(&opts.aliasfile, "alias-file", "/etc/finger.conf", "file to read aliases from (if it exists)")
	flag.StringVar(&opts.homesDir, "homes-dir", "/home", "where end-user home-dirs live")
	flag.StringVar(&opts.listen, "listen", ":79", "address-spec to listen for finger requests on")
	flag.StringVar(&opts.runAsUser, "run-as-user", "", "if starting as root, setuid to this user")
	flag.StringVar(&opts.pidFile, "pidfile", "", "write pid to this file after bind but before listening")
	flag.DurationVar(&opts.listenTime, "listen.at-a-time", time.Second, "accepting socket listen time (defers program exit)")
	flag.DurationVar(&opts.requestReadTimeout, "request.timeout.read", 10*time.Second, "timeout for receiving the finger request")
	flag.DurationVar(&opts.requestWriteTimeout, "request.timeout.write", 30*time.Second, "timeout for each write of the response")
	flag.Int64Var(&opts.fileSizeLimit, "file.size-limit", defaultFileSizeLimit, "how large a file we will serve")
	flag.Uint64Var(&opts.minPasswdUID, "passwd.min-uid", 0, "set non-zero to enable passwd lookups")
	flag.BoolVar(&opts.showVersion, "version", false, "show version and exit")
}

func main() {
	flag.Parse()

	if opts.showVersion {
		version()
		return
	}

	// q: should this really be one global waitgroup instead of per-AF and entirely encapsulate in the TCPFingerListener?
	running := &sync.WaitGroup{}
	running.Add(1)
	shutdown := make(chan struct{})

	logger := setupLogging()
	masterThreadLogger := logrus.NewEntry(logger).WithFields(logrus.Fields{
		"uid": os.Getuid(),
		"gid": os.Getgid(),
		"pid": os.Getpid(),
	})

	haveListeners := make([]*TCPFingerListener, 0, 3)

	if tmp, ok := inheritedListeners(running, shutdown, logger); ok {
		masterThreadLogger.Infof("recovered %d listeners", len(tmp))
		haveListeners = tmp
	} else {
		for _, netFamily := range []string{"tcp4", "tcp6"} {
			fl, err := NewTCPFingerListener(netFamily, running, shutdown, logger)
			if err != nil {
				masterThreadLogger.WithError(err).Errorf("failed to listen/%s", netFamily)
			} else {
				haveListeners = append(haveListeners, fl)
				// start below, after dropping privs and loading aliases
			}
		}
	}

	running.Done()
	if len(haveListeners) == 0 {
		// avoid chewing CPU in a tight loop if we're being constantly respawned
		time.Sleep(time.Second)
		masterThreadLogger.Fatal("no listeners accepted; slept 1s before exiting")
	}

	if os.Getuid() == 0 {
		masterThreadLogger.Info("running as root, need to drop privileges")
		dropPrivileges(haveListeners, logger)
		// only reach here if something has gone wrong; dropPrivileges _should_ re-exec us
		time.Sleep(time.Second)
		masterThreadLogger.Fatal("we must drop privileges when running as root")
	}

	// Set up signal handling as soon as we've dropped privs, even though we'll
	// not act on it until late.
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)

	// We parse these _after_ dropping privileges, so the listening socket is open, but
	// before we start the listening, so that the aliases are available without race.
	if opts.aliasfile != "" {
		// It's okay for the file to not exist.  Also, if it doesn't exist but later comes into existence,
		// we accept it at that point.  A _missing_ file should not immediately blank data (might be a race
		// between updates in a bad editor) so write an empty file first, before deleting it, if you want that.
		//
		// Because it's okay to not exist, we never actually fail setup and abort service.  If we lose
		// the ability to dynamically reload then that will be logged.  It's thus in the audit trail and
		// an acceptable degradation of service.
		loadMappingData(logger)
		scheduleAutoMappingDataReload(logger)
	}

	// Pidfile must be after bind, but before listening.
	var weCreatedPidfile bool
	if opts.pidFile != "" {
		pf, err := os.Create(opts.pidFile)
		if err != nil {
			masterThreadLogger.WithError(err).WithField("pidfile", opts.pidFile).Info("unable to create pidfile")
		} else {
			fmt.Fprintf(pf, "%d\n", os.Getpid())
			_ = pf.Close()
			weCreatedPidfile = true
		}
	}

	// From this point on, we're sufficiently init-like to pass muster.
	go childReaper(logger)

	// From this point on, we're accepting connection.
	for _, fl := range haveListeners {
		fl.GoServeThenClose()
	}

	masterThreadLogger.WithFields(logrus.Fields{
		"argv":      os.Args,
		"version":   currentVersion(),
		"listeners": len(haveListeners),
	}).Info("running")

	// Hang around forever, or until signalled
	masterThreadLogger.WithField("signal", <-ch).Warn("shutdown signal received")

	close(shutdown)
	running.Wait()

	if weCreatedPidfile {
		_ = os.Remove(opts.pidFile)
	}

	masterThreadLogger.Info("exiting cleanly")
	logrus.Exit(0)
}
<commit_msg>Drop log-level of failure to listen to warn<commit_after>// Copyright © 2016 Pennock Tech, LLC.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

// We are canonically imported from go.pennock.tech/fingerd but because we are
// not a library, we do not apply this as an import constraint on the package
// declarations.  You can fork and build elsewhere more easily this way, while
// still getting dependencies without a dependency manager in play.
//
// This comment is just to let you know that the canonical import path is
// go.pennock.tech/fingerd and not now, nor ever, using DNS pointing to a
// code-hosting site not under our direct control.  We keep our options open,
// for moving where we keep the code publicly available.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
)

// I initially set 64 and in my first tests hit this because of an 84K .pubkey
// Let's be a _little_ more generous; 256KB by default let's one use send up to
// very slightly more than three-quarters of a MB.
const defaultFileSizeLimit = 256 * 1024

var opts struct {
	aliasfile           string
	listen              string
	homesDir            string
	runAsUser           string
	pidFile             string
	fileSizeLimit       int64
	listenTime          time.Duration
	requestReadTimeout  time.Duration
	requestWriteTimeout time.Duration
	minPasswdUID        uint64
	showVersion         bool
}

func init() {
	flag.StringVar(&opts.aliasfile, "alias-file", "/etc/finger.conf", "file to read aliases from (if it exists)")
	flag.StringVar(&opts.homesDir, "homes-dir", "/home", "where end-user home-dirs live")
	flag.StringVar(&opts.listen, "listen", ":79", "address-spec to listen for finger requests on")
	flag.StringVar(&opts.runAsUser, "run-as-user", "", "if starting as root, setuid to this user")
	flag.StringVar(&opts.pidFile, "pidfile", "", "write pid to this file after bind but before listening")
	flag.DurationVar(&opts.listenTime, "listen.at-a-time", time.Second, "accepting socket listen time (defers program exit)")
	flag.DurationVar(&opts.requestReadTimeout, "request.timeout.read", 10*time.Second, "timeout for receiving the finger request")
	flag.DurationVar(&opts.requestWriteTimeout, "request.timeout.write", 30*time.Second, "timeout for each write of the response")
	flag.Int64Var(&opts.fileSizeLimit, "file.size-limit", defaultFileSizeLimit, "how large a file we will serve")
	flag.Uint64Var(&opts.minPasswdUID, "passwd.min-uid", 0, "set non-zero to enable passwd lookups")
	flag.BoolVar(&opts.showVersion, "version", false, "show version and exit")
}

func main() {
	flag.Parse()

	if opts.showVersion {
		version()
		return
	}

	// q: should this really be one global waitgroup instead of per-AF and entirely encapsulate in the TCPFingerListener?
	running := &sync.WaitGroup{}
	running.Add(1)
	shutdown := make(chan struct{})

	logger := setupLogging()
	masterThreadLogger := logrus.NewEntry(logger).WithFields(logrus.Fields{
		"uid": os.Getuid(),
		"gid": os.Getgid(),
		"pid": os.Getpid(),
	})

	haveListeners := make([]*TCPFingerListener, 0, 3)

	if tmp, ok := inheritedListeners(running, shutdown, logger); ok {
		masterThreadLogger.Infof("recovered %d listeners", len(tmp))
		haveListeners = tmp
	} else {
		for _, netFamily := range []string{"tcp4", "tcp6"} {
			fl, err := NewTCPFingerListener(netFamily, running, shutdown, logger)
			if err != nil {
				// It's not an error to fail to listen on just one family (eg,
				// system which is missing IPv4) so only Warn level.  If we got
				// none at all, then we'll fatal out below, which will cover us.
				masterThreadLogger.WithError(err).Warnf("failed to listen/%s", netFamily)
			} else {
				haveListeners = append(haveListeners, fl)
				// start below, after dropping privs and loading aliases
			}
		}
	}

	running.Done()
	if len(haveListeners) == 0 {
		// avoid chewing CPU in a tight loop if we're being constantly respawned
		time.Sleep(time.Second)
		masterThreadLogger.Fatal("no listeners accepted; slept 1s before exiting")
	}

	if os.Getuid() == 0 {
		masterThreadLogger.Info("running as root, need to drop privileges")
		dropPrivileges(haveListeners, logger)
		// only reach here if something has gone wrong; dropPrivileges _should_ re-exec us
		time.Sleep(time.Second)
		masterThreadLogger.Fatal("we must drop privileges when running as root")
	}

	// Set up signal handling as soon as we've dropped privs, even though we'll
	// not act on it until late.
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)

	// We parse these _after_ dropping privileges, so the listening socket is open, but
	// before we start the listening, so that the aliases are available without race.
	if opts.aliasfile != "" {
		// It's okay for the file to not exist.  Also, if it doesn't exist but later comes into existence,
		// we accept it at that point.  A _missing_ file should not immediately blank data (might be a race
		// between updates in a bad editor) so write an empty file first, before deleting it, if you want that.
		//
		// Because it's okay to not exist, we never actually fail setup and abort service.  If we lose
		// the ability to dynamically reload then that will be logged.  It's thus in the audit trail and
		// an acceptable degradation of service.
		loadMappingData(logger)
		scheduleAutoMappingDataReload(logger)
	}

	// Pidfile must be after bind, but before listening.
	var weCreatedPidfile bool
	if opts.pidFile != "" {
		pf, err := os.Create(opts.pidFile)
		if err != nil {
			masterThreadLogger.WithError(err).WithField("pidfile", opts.pidFile).Info("unable to create pidfile")
		} else {
			fmt.Fprintf(pf, "%d\n", os.Getpid())
			_ = pf.Close()
			weCreatedPidfile = true
		}
	}

	// From this point on, we're sufficiently init-like to pass muster.
	go childReaper(logger)

	// From this point on, we're accepting connection.
	for _, fl := range haveListeners {
		fl.GoServeThenClose()
	}

	masterThreadLogger.WithFields(logrus.Fields{
		"argv":      os.Args,
		"version":   currentVersion(),
		"listeners": len(haveListeners),
	}).Info("running")

	// Hang around forever, or until signalled
	masterThreadLogger.WithField("signal", <-ch).Warn("shutdown signal received")

	close(shutdown)
	running.Wait()

	if weCreatedPidfile {
		_ = os.Remove(opts.pidFile)
	}

	masterThreadLogger.Info("exiting cleanly")
	logrus.Exit(0)
}
<|endoftext|>


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

package main

import (
	"fmt"
	"go/ast"
	"go/parser"

	"golang.org/x/tools/go/loader"
)

func apiLoader() (*loader.Program, error) {
	var ldr loader.Config
	ldr.ParserMode = parser.ParseComments
	ldr.Import("github.com/tsuru/tsuru/api")
	return ldr.Load()
}

func isHandler(object *ast.Object) bool {
	params := object.Decl.(*ast.FuncDecl).Type.Params.List
	if len(params) < 2 {
		return false
	}
	for _, param := range params {
		t, ok := param.Type.(*ast.SelectorExpr)
		if ok {
			if t.Sel.Name == "ResponseWriter" {
				return true
			}
		}
	}
	return false
}

func parse(prog *loader.Program) error {
	files := prog.Imported["github.com/tsuru/tsuru/api"].Files
	for _, f := range files {
		for _, object := range f.Scope.Objects {
			if object.Kind == ast.Fun && object.Name == "serviceList" {
				ok := isHandler(object)
				if !ok {
					continue
				}
				commentGroup := object.Decl.(*ast.FuncDecl).Doc
				for _, comment := range commentGroup.List {
					fmt.Println(comment.Text)
				}
			}
		}
	}
	return nil
}

func main() {
	prog, err := apiLoader()
	if err != nil {
		fmt.Println("error loading code ", err)
		return
	}
	err = parse(prog)
	if err != nil {
		fmt.Println("error parsing api ", err)
		return
	}
}
<commit_msg>show handlers without docs<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"go/ast"
	"go/parser"

	"golang.org/x/tools/go/loader"
)

func apiLoader() (*loader.Program, error) {
	var ldr loader.Config
	ldr.ParserMode = parser.ParseComments
	ldr.Import("github.com/tsuru/tsuru/api")
	return ldr.Load()
}

func isHandler(object *ast.Object) bool {
	params := object.Decl.(*ast.FuncDecl).Type.Params.List
	if len(params) < 2 {
		return false
	}
	for _, param := range params {
		t, ok := param.Type.(*ast.SelectorExpr)
		if ok {
			if t.Sel.Name == "ResponseWriter" {
				return true
			}
		}
	}
	return false
}

func parse(prog *loader.Program) error {
	files := prog.Imported["github.com/tsuru/tsuru/api"].Files
	for _, f := range files {
		for _, object := range f.Scope.Objects {
			if object.Kind == ast.Fun {
				// if object.Kind == ast.Fun && object.Name == "serviceList" {
				ok := isHandler(object)
				if !ok {
					continue
				}
				commentGroup := object.Decl.(*ast.FuncDecl).Doc
				if commentGroup == nil {
					fmt.Printf("missing docs for %s\n", object.Name)
					continue
				}
				for _, comment := range commentGroup.List {
					fmt.Println(comment.Text)
				}
			}
		}
	}
	return nil
}

func main() {
	prog, err := apiLoader()
	if err != nil {
		fmt.Println("error loading code ", err)
		return
	}
	err = parse(prog)
	if err != nil {
		fmt.Println("error parsing api ", err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/byxorna/goji/marathon"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var (
	configPath string
  // override the target in config
	target string
	config     Config
	// current state of services we know about
	services ServiceList
	// listen to this channel for update triggers
	eventChan chan string
	client    marathon.Client
	sigChan   chan os.Signal
	server    bool
)

func init() {
	flag.StringVar(&configPath, "conf", "", "config json file")
	flag.BoolVar(&server, "server", false, "start a HTTP server listening for Marathon events")
	flag.StringVar(&target, "target", "", "target file to write to")
	flag.Parse()
}

func main() {
	if configPath == "" {
		log.Fatal("You need to pass a -conf")
	}
	var err error
	config, err = LoadConfig(configPath)
	if err != nil {
		log.Fatal(err)
	}
  // allow -target to override the target specified in config for CLI testing
  if target != "" {
    config.TargetFile = target
  }
	log.Printf("Loaded config: %s\n", config)
	client = marathon.NewClient(config.MarathonHost, config.MarathonPort)
	services, err = NewServiceList(config.Services)
	if err != nil {
		log.Fatal(err.Error())
	}
	for _, s := range services {
		log.Printf("Loaded %s service %s at port %d\n", s.Protocol, s.AppId, s.Port)
	}

	// lets let people know when we get a signal, so we can clean up
	sigChan = make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	err = LoadTasksAndEmitConfig()
	if err != nil {
		log.Fatal(err.Error())
	}

	if server {
		// every event hits eventChan (buffer 10 events)
		eventChan = make(chan string, 10)

		go func() {
			coalesceEvents(eventChan, time.Duration(config.TemplateDelay)*time.Second, func() {
				err := LoadTasksAndEmitConfig()
				if err != nil {
					log.Printf(err.Error())
				}
			})
		}()

		var listenAddr = fmt.Sprintf(":%d", config.HttpPort)
		log.Printf("Listening for marathon events on %s/event\n", listenAddr)
		log.Fatal(ListenForEvents(listenAddr))
	}

}
<commit_msg>more gofmt<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/byxorna/goji/marathon"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var (
	configPath string
	// override the target in config
	target string
	config Config
	// current state of services we know about
	services ServiceList
	// listen to this channel for update triggers
	eventChan chan string
	client    marathon.Client
	sigChan   chan os.Signal
	server    bool
)

func init() {
	flag.StringVar(&configPath, "conf", "", "config json file")
	flag.BoolVar(&server, "server", false, "start a HTTP server listening for Marathon events")
	flag.StringVar(&target, "target", "", "target file to write to")
	flag.Parse()
}

func main() {
	if configPath == "" {
		log.Fatal("You need to pass a -conf")
	}
	var err error
	config, err = LoadConfig(configPath)
	if err != nil {
		log.Fatal(err)
	}
	// allow -target to override the target specified in config for CLI testing
	if target != "" {
		config.TargetFile = target
	}
	log.Printf("Loaded config: %s\n", config)
	client = marathon.NewClient(config.MarathonHost, config.MarathonPort)
	services, err = NewServiceList(config.Services)
	if err != nil {
		log.Fatal(err.Error())
	}
	for _, s := range services {
		log.Printf("Loaded %s service %s at port %d\n", s.Protocol, s.AppId, s.Port)
	}

	// lets let people know when we get a signal, so we can clean up
	sigChan = make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	err = LoadTasksAndEmitConfig()
	if err != nil {
		log.Fatal(err.Error())
	}

	if server {
		// every event hits eventChan (buffer 10 events)
		eventChan = make(chan string, 10)

		go func() {
			coalesceEvents(eventChan, time.Duration(config.TemplateDelay)*time.Second, func() {
				err := LoadTasksAndEmitConfig()
				if err != nil {
					log.Printf(err.Error())
				}
			})
		}()

		var listenAddr = fmt.Sprintf(":%d", config.HttpPort)
		log.Printf("Listening for marathon events on %s/event\n", listenAddr)
		log.Fatal(ListenForEvents(listenAddr))
	}

}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/pflag"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	"net/http/pprof"

	"k8s.io/kube-state-metrics/collectors"
)

const (
	metricsPath = "/metrics"
	healthzPath = "/healthz"
)

var (
	defaultCollectors = collectorSet{
		"daemonsets":             struct{}{},
		"deployments":            struct{}{},
		"limitranges":            struct{}{},
		"nodes":                  struct{}{},
		"pods":                   struct{}{},
		"replicasets":            struct{}{},
		"replicationcontrollers": struct{}{},
		"resourcequotas":         struct{}{},
		"services":               struct{}{},
		"jobs":                   struct{}{},
		"cronjobs":               struct{}{},
		"statefulsets":           struct{}{},
		"persistentvolumeclaims": struct{}{},
		"namespaces":             struct{}{},
	}
	availableCollectors = map[string]func(registry prometheus.Registerer, kubeClient clientset.Interface, namespace string){
		"cronjobs":               collectors.RegisterCronJobCollector,
		"daemonsets":             collectors.RegisterDaemonSetCollector,
		"deployments":            collectors.RegisterDeploymentCollector,
		"jobs":                   collectors.RegisterJobCollector,
		"limitranges":            collectors.RegisterLimitRangeCollector,
		"nodes":                  collectors.RegisterNodeCollector,
		"pods":                   collectors.RegisterPodCollector,
		"replicasets":            collectors.RegisterReplicaSetCollector,
		"replicationcontrollers": collectors.RegisterReplicationControllerCollector,
		"resourcequotas":         collectors.RegisterResourceQuotaCollector,
		"services":               collectors.RegisterServiceCollector,
		"statefulsets":           collectors.RegisterStatefulSetCollector,
		"persistentvolumeclaims": collectors.RegisterPersistentVolumeClaimCollector,
		"namespaces":             collectors.RegisterNamespaceCollector,
	}
)

type collectorSet map[string]struct{}

func (c *collectorSet) String() string {
	s := *c
	return strings.Join(s.asSlice(), ",")
}

func (c *collectorSet) Set(value string) error {
	s := *c
	cols := strings.Split(value, ",")
	for _, col := range cols {
		_, ok := availableCollectors[col]
		if !ok {
			glog.Fatalf("Collector \"%s\" does not exist", col)
		}
		s[col] = struct{}{}
	}
	return nil
}

func (c collectorSet) asSlice() []string {
	cols := []string{}
	for col, _ := range c {
		cols = append(cols, col)
	}
	return cols
}

func (c collectorSet) isEmpty() bool {
	return len(c.asSlice()) == 0
}

func (c *collectorSet) Type() string {
	return "string"
}

type options struct {
	inCluster  bool
	apiserver  string
	kubeconfig string
	help       bool
	port       int
	collectors collectorSet
	namespace  string
}

func main() {
	options := &options{collectors: make(collectorSet)}
	flags := pflag.NewFlagSet("", pflag.ExitOnError)
	// add glog flags
	flags.AddGoFlagSet(flag.CommandLine)
	flags.Lookup("logtostderr").Value.Set("true")
	flags.Lookup("logtostderr").DefValue = "true"
	flags.Lookup("logtostderr").NoOptDefVal = "true"
	flags.BoolVar(&options.inCluster, "in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)
	flags.StringVar(&options.apiserver, "apiserver", "", `The URL of the apiserver to use as a master`)
	flags.StringVar(&options.kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file")
	flags.BoolVarP(&options.help, "help", "h", false, "Print help text")
	flags.IntVar(&options.port, "port", 80, `Port to expose metrics on.`)
	flags.Var(&options.collectors, "collectors", fmt.Sprintf("Comma-separated list of collectors to be enabled. Defaults to %q", &defaultCollectors))
	flags.StringVar(&options.namespace, "namespace", api.NamespaceAll, "namespace to be enabled for collecting resources")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if options.help {
		flags.Usage()
		os.Exit(0)
	}

	var collectors collectorSet
	if len(options.collectors) == 0 {
		glog.Info("Using default collectors")
		collectors = defaultCollectors
	} else {
		collectors = options.collectors
	}

	if options.namespace == api.NamespaceAll {
		glog.Info("Using all namespace")
	} else {
		glog.Infof("Using %s namespace", options.namespace)
	}

	if isNotExists(options.kubeconfig) && !(options.inCluster) {
		glog.Fatalf("kubeconfig invalid and --in-cluster is false; kubeconfig must be set to a valid file(kubeconfig default file name: $HOME/.kube/config)")
	}
	if options.apiserver != "" {
		glog.Infof("apiserver set to: %v", options.apiserver)
	}

	proc.StartReaper()

	kubeClient, err := createKubeClient(options.inCluster, options.apiserver, options.kubeconfig)
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	registry := prometheus.NewRegistry()
	registerCollectors(registry, kubeClient, collectors, options.namespace)
	metricsServer(registry, options.port)
}

func isNotExists(file string) bool {
	if file == "" {
		file = clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
	}
	_, err := os.Stat(file)
	return os.IsNotExist(err)
}

func createKubeClient(inCluster bool, apiserver string, kubeconfig string) (kubeClient clientset.Interface, err error) {
	if inCluster {
		config, err := rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if apiserver != "" {
			config.Host = apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("Testing communication with server")
	_, err = kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}
	glog.Infof("Communication with server successful")

	return kubeClient, nil
}

func metricsServer(registry prometheus.Gatherer, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := fmt.Sprintf(":%d", port)

	glog.Infof("Starting metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	// Add metricsPath
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
	// Add healthzPath
	mux.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

// registerCollectors creates and starts informers and initializes and
// registers metrics for collection.
func registerCollectors(registry prometheus.Registerer, kubeClient clientset.Interface, enabledCollectors collectorSet, namespace string) {
	activeCollectors := []string{}
	for c, _ := range enabledCollectors {
		f, ok := availableCollectors[c]
		if ok {
			f(registry, kubeClient, namespace)
			activeCollectors = append(activeCollectors, c)
		}
	}

	glog.Infof("Active collectors: %s", strings.Join(activeCollectors, ","))
}
<commit_msg>Avoid a random result<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"sort"
	"strings"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/pflag"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	"net/http/pprof"

	"k8s.io/kube-state-metrics/collectors"
)

const (
	metricsPath = "/metrics"
	healthzPath = "/healthz"
)

var (
	defaultCollectors = collectorSet{
		"daemonsets":             struct{}{},
		"deployments":            struct{}{},
		"limitranges":            struct{}{},
		"nodes":                  struct{}{},
		"pods":                   struct{}{},
		"replicasets":            struct{}{},
		"replicationcontrollers": struct{}{},
		"resourcequotas":         struct{}{},
		"services":               struct{}{},
		"jobs":                   struct{}{},
		"cronjobs":               struct{}{},
		"statefulsets":           struct{}{},
		"persistentvolumeclaims": struct{}{},
		"namespaces":             struct{}{},
	}
	availableCollectors = map[string]func(registry prometheus.Registerer, kubeClient clientset.Interface, namespace string){
		"cronjobs":               collectors.RegisterCronJobCollector,
		"daemonsets":             collectors.RegisterDaemonSetCollector,
		"deployments":            collectors.RegisterDeploymentCollector,
		"jobs":                   collectors.RegisterJobCollector,
		"limitranges":            collectors.RegisterLimitRangeCollector,
		"nodes":                  collectors.RegisterNodeCollector,
		"pods":                   collectors.RegisterPodCollector,
		"replicasets":            collectors.RegisterReplicaSetCollector,
		"replicationcontrollers": collectors.RegisterReplicationControllerCollector,
		"resourcequotas":         collectors.RegisterResourceQuotaCollector,
		"services":               collectors.RegisterServiceCollector,
		"statefulsets":           collectors.RegisterStatefulSetCollector,
		"persistentvolumeclaims": collectors.RegisterPersistentVolumeClaimCollector,
		"namespaces":             collectors.RegisterNamespaceCollector,
	}
)

type collectorSet map[string]struct{}

func (c *collectorSet) String() string {
	s := *c
	ss := s.asSlice()
	sort.Strings(ss)
	return strings.Join(ss, ",")
}

func (c *collectorSet) Set(value string) error {
	s := *c
	cols := strings.Split(value, ",")
	for _, col := range cols {
		_, ok := availableCollectors[col]
		if !ok {
			glog.Fatalf("Collector \"%s\" does not exist", col)
		}
		s[col] = struct{}{}
	}
	return nil
}

func (c collectorSet) asSlice() []string {
	cols := []string{}
	for col, _ := range c {
		cols = append(cols, col)
	}
	return cols
}

func (c collectorSet) isEmpty() bool {
	return len(c.asSlice()) == 0
}

func (c *collectorSet) Type() string {
	return "string"
}

type options struct {
	inCluster  bool
	apiserver  string
	kubeconfig string
	help       bool
	port       int
	collectors collectorSet
	namespace  string
}

func main() {
	options := &options{collectors: make(collectorSet)}
	flags := pflag.NewFlagSet("", pflag.ExitOnError)
	// add glog flags
	flags.AddGoFlagSet(flag.CommandLine)
	flags.Lookup("logtostderr").Value.Set("true")
	flags.Lookup("logtostderr").DefValue = "true"
	flags.Lookup("logtostderr").NoOptDefVal = "true"
	flags.BoolVar(&options.inCluster, "in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)
	flags.StringVar(&options.apiserver, "apiserver", "", `The URL of the apiserver to use as a master`)
	flags.StringVar(&options.kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file")
	flags.BoolVarP(&options.help, "help", "h", false, "Print help text")
	flags.IntVar(&options.port, "port", 80, `Port to expose metrics on.`)
	flags.Var(&options.collectors, "collectors", fmt.Sprintf("Comma-separated list of collectors to be enabled. Defaults to %q", &defaultCollectors))
	flags.StringVar(&options.namespace, "namespace", api.NamespaceAll, "namespace to be enabled for collecting resources")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if options.help {
		flags.Usage()
		os.Exit(0)
	}

	var collectors collectorSet
	if len(options.collectors) == 0 {
		glog.Info("Using default collectors")
		collectors = defaultCollectors
	} else {
		collectors = options.collectors
	}

	if options.namespace == api.NamespaceAll {
		glog.Info("Using all namespace")
	} else {
		glog.Infof("Using %s namespace", options.namespace)
	}

	if isNotExists(options.kubeconfig) && !(options.inCluster) {
		glog.Fatalf("kubeconfig invalid and --in-cluster is false; kubeconfig must be set to a valid file(kubeconfig default file name: $HOME/.kube/config)")
	}
	if options.apiserver != "" {
		glog.Infof("apiserver set to: %v", options.apiserver)
	}

	proc.StartReaper()

	kubeClient, err := createKubeClient(options.inCluster, options.apiserver, options.kubeconfig)
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	registry := prometheus.NewRegistry()
	registerCollectors(registry, kubeClient, collectors, options.namespace)
	metricsServer(registry, options.port)
}

func isNotExists(file string) bool {
	if file == "" {
		file = clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
	}
	_, err := os.Stat(file)
	return os.IsNotExist(err)
}

func createKubeClient(inCluster bool, apiserver string, kubeconfig string) (kubeClient clientset.Interface, err error) {
	if inCluster {
		config, err := rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if apiserver != "" {
			config.Host = apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("Testing communication with server")
	_, err = kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}
	glog.Infof("Communication with server successful")

	return kubeClient, nil
}

func metricsServer(registry prometheus.Gatherer, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := fmt.Sprintf(":%d", port)

	glog.Infof("Starting metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	// Add metricsPath
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
	// Add healthzPath
	mux.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

// registerCollectors creates and starts informers and initializes and
// registers metrics for collection.
func registerCollectors(registry prometheus.Registerer, kubeClient clientset.Interface, enabledCollectors collectorSet, namespace string) {
	activeCollectors := []string{}
	for c, _ := range enabledCollectors {
		f, ok := availableCollectors[c]
		if ok {
			f(registry, kubeClient, namespace)
			activeCollectors = append(activeCollectors, c)
		}
	}

	glog.Infof("Active collectors: %s", strings.Join(activeCollectors, ","))
}
<|endoftext|>


<commit_before>package gron

import (
	"errors"
	"time"

	"github.com/roylee0704/gron/xtime"
)

// Schedule is the interface that wraps the basic Next method.
//
// Next deduces next occuring time based on t and underlying states.
type Schedule interface {
	Next(t time.Time) time.Time
}

// AtSchedule extends Schedule by enabling periodic-interval & time-specific setup
type AtSchedule interface {
	At(t string) Schedule
	Schedule
}

// Every returns a Schedule reoccurs every period p, p must be at least
// time.Second.
func Every(p time.Duration) AtSchedule {

	if p < time.Second {
		p = xtime.Second
	}

	p = p - time.Duration(p.Nanoseconds())%time.Second // truncates up to seconds

	return &periodicSchedule{
		period: p,
	}
}

type periodicSchedule struct {
	period time.Duration
}

// Next adds time t to underlying period, truncates up to unit of seconds.
func (ps periodicSchedule) Next(t time.Time) time.Time {
	return t.Truncate(time.Second).Add(ps.period)
}

// At returns a schedule which reoccurs every period p, at time t(hh:ss).
//
// Note: At panics when period p is less than xtime.Day, and error hh:ss format.
func (ps periodicSchedule) At(t string) Schedule {
	if ps.period < xtime.Day {
		panic("period must be at least in days")
	}

	// parse t naively
	h, m, err := parse(t)

	if err != nil {
		panic(err.Error())
	}

	return &atSchedule{
		period: ps.period,
		hh:     h,
		mm:     m,
	}
}

// parse naively tokenises hours and minutes.
//
// returns error when input format was incorrect.
func parse(hhmm string) (hh int, mm int, err error) {

	hh = int(hhmm[0]-'0')*10 + int(hhmm[1]-'0')
	mm = int(hhmm[3]-'0')*10 + int(hhmm[4]-'0')

	if hh < 0 || hh > 24 {
		hh, mm = 0, 0
		err = errors.New("invalid hh format")
	}
	if mm < 0 || mm > 59 {
		hh, mm = 0, 0
		err = errors.New("invalid mm format")
	}

	return
}

type atSchedule struct {
	period time.Duration
	hh     int
	mm     int
}

// reset returns new Date based on time instant t, and reconfigure its hh:ss
// according to atSchedule's hh:ss.
func (as atSchedule) reset(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), as.hh, as.mm, 0, 0, time.UTC)
}

// Next returns **next** time.
// if t passed its supposed schedule: reset(t), returns reset(t) + period,
// else returns reset(t).
func (as atSchedule) Next(t time.Time) time.Time {
	next := as.reset(t)
	if t.After(next) {
		return next.Add(as.period)
	}
	return next
}
<commit_msg>fix spelling mistake<commit_after>package gron

import (
	"errors"
	"time"

	"github.com/roylee0704/gron/xtime"
)

// Schedule is the interface that wraps the basic Next method.
//
// Next deduces next occurring time based on t and underlying states.
type Schedule interface {
	Next(t time.Time) time.Time
}

// AtSchedule extends Schedule by enabling periodic-interval & time-specific setup
type AtSchedule interface {
	At(t string) Schedule
	Schedule
}

// Every returns a Schedule reoccurs every period p, p must be at least
// time.Second.
func Every(p time.Duration) AtSchedule {

	if p < time.Second {
		p = xtime.Second
	}

	p = p - time.Duration(p.Nanoseconds())%time.Second // truncates up to seconds

	return &periodicSchedule{
		period: p,
	}
}

type periodicSchedule struct {
	period time.Duration
}

// Next adds time t to underlying period, truncates up to unit of seconds.
func (ps periodicSchedule) Next(t time.Time) time.Time {
	return t.Truncate(time.Second).Add(ps.period)
}

// At returns a schedule which reoccurs every period p, at time t(hh:ss).
//
// Note: At panics when period p is less than xtime.Day, and error hh:ss format.
func (ps periodicSchedule) At(t string) Schedule {
	if ps.period < xtime.Day {
		panic("period must be at least in days")
	}

	// parse t naively
	h, m, err := parse(t)

	if err != nil {
		panic(err.Error())
	}

	return &atSchedule{
		period: ps.period,
		hh:     h,
		mm:     m,
	}
}

// parse naively tokenises hours and minutes.
//
// returns error when input format was incorrect.
func parse(hhmm string) (hh int, mm int, err error) {

	hh = int(hhmm[0]-'0')*10 + int(hhmm[1]-'0')
	mm = int(hhmm[3]-'0')*10 + int(hhmm[4]-'0')

	if hh < 0 || hh > 24 {
		hh, mm = 0, 0
		err = errors.New("invalid hh format")
	}
	if mm < 0 || mm > 59 {
		hh, mm = 0, 0
		err = errors.New("invalid mm format")
	}

	return
}

type atSchedule struct {
	period time.Duration
	hh     int
	mm     int
}

// reset returns new Date based on time instant t, and reconfigure its hh:ss
// according to atSchedule's hh:ss.
func (as atSchedule) reset(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), as.hh, as.mm, 0, 0, time.UTC)
}

// Next returns **next** time.
// if t passed its supposed schedule: reset(t), returns reset(t) + period,
// else returns reset(t).
func (as atSchedule) Next(t time.Time) time.Time {
	next := as.reset(t)
	if t.After(next) {
		return next.Add(as.period)
	}
	return next
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"github.com/webx-top/com"
	"github.com/webx-top/echo"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/admpub/nging/v3/application/library/service"
)

type Log struct {
	Debug        bool   `json:"debug"`
	Colorable    bool   `json:"colorable"`    // for console
	SaveFile     string `json:"saveFile"`     // for file
	FileMaxBytes int64  `json:"fileMaxBytes"` // for file
	Targets      string `json:"targets" form_delimiter:","`
}

func (c *Log) Show(ctx echo.Context) error {
	category := ctx.Param(`category`, `app`)
	if strings.Contains(category, `..`) {
		return ctx.JSON(ctx.Data().SetInfo(ctx.T(`参数错误: %s`, category), 0).SetZone(`category`))
	}
	if !log.HasCategory(category) {
		return ctx.JSON(ctx.Data().SetInfo(ctx.T(`不存在日志分类: %s`, category), 0).SetZone(`category`))
	}
	_, _, timeformat, filename, err := log.DateFormatFilename(c.LogFile())
	if err != nil {
		return ctx.JSON(ctx.Data().SetError(err))
	}
	var logFile string
	if len(timeformat) > 0 {
		logFile = fmt.Sprintf(filename, time.Now().Format(timeformat))
	} else {
		logFile = filename
	}
	logFile = strings.Replace(logFile, `{category}`, category, -1)
	if !com.FileExists(logFile) {
		serviceAppLogFile := service.ServiceLogDir() + echo.FilePathSeparator + service.ServiceAppLogFile
		_, _, timeformat, filename, err = log.DateFormatFilename(serviceAppLogFile)
		if err == nil {
			if len(timeformat) > 0 {
				serviceAppLogFile = fmt.Sprintf(filename, time.Now().Format(timeformat))
			} else {
				serviceAppLogFile = filename
			}
			serviceAppLogFile = strings.Replace(serviceAppLogFile, `{category}`, category, -1)
			if com.FileExists(serviceAppLogFile) {
				logFile = serviceAppLogFile
			}
		}
	}
	return common.LogShow(ctx, logFile)
}

func (c *Log) SetBy(r echo.H, defaults echo.H) *Log {
	if !r.Has(`log`) && defaults != nil {
		r.Set(`log`, defaults.GetStore(`log`))
	}
	loge := r.GetStore(`log`)
	c.Colorable = loge.Bool(`colorable`)
	c.SaveFile = loge.String(`saveFile`)
	switch t := loge.Get(`targets`).(type) {
	case []interface{}:
		for k, v := range t {
			if k > 0 {
				c.Targets += `,`
			}
			c.Targets = fmt.Sprint(v)
		}
	case []string:
		c.Targets = strings.Join(t, `,`)
	case string:
		c.Targets = t
	}
	c.FileMaxBytes = loge.Int64(`fileMaxBytes`)
	return c
}

func (c *Log) LogFile() string {
	if len(c.SaveFile) > 0 {
		return c.SaveFile
	}
	return filepath.Join(echo.Wd(), `data/logs/{category}_{date:20060102}_info.log`)
}

func (c *Log) Init() {
	//======================================================
	// 配置日志
	//======================================================
	if c.Debug {
		log.DefaultLog.MaxLevel = log.LevelDebug
		//log.DefaultLog.Formatter = log.ShortFileFormatter
	} else {
		log.DefaultLog.MaxLevel = log.LevelInfo
	}
	targets := []log.Target{}
	for _, targetName := range strings.Split(c.Targets, `,`) {
		targetName = strings.TrimSpace(targetName)
		if len(targetName) == 0 {
			continue
		}
		switch targetName {
		case "file":
			//输出到文件
			fileTarget := log.NewFileTarget()
			fileTarget.FileName = c.LogFile()
			fileTarget.Filter.MaxLevel = log.DefaultLog.MaxLevel
			if c.FileMaxBytes > 0 {
				fileTarget.MaxBytes = c.FileMaxBytes
			}
			targets = append(targets, fileTarget)

		case "console":
			fallthrough
		default:
			//输出到命令行
			consoleTarget := log.NewConsoleTarget()
			consoleTarget.ColorMode = c.Colorable
			targets = append(targets, consoleTarget)
		}
	}

	log.SetTarget(targets...)
	log.SetFatalAction(log.ActionExit)
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"github.com/webx-top/com"
	"github.com/webx-top/echo"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/admpub/nging/v3/application/library/service"
)

type Log struct {
	Debug        bool   `json:"debug"`
	Colorable    bool   `json:"colorable"`    // for console
	SaveFile     string `json:"saveFile"`     // for file
	FileMaxBytes int64  `json:"fileMaxBytes"` // for file
	Targets      string `json:"targets" form_delimiter:","`
}

func (c *Log) Show(ctx echo.Context) error {
	category := ctx.Param(`category`, `app`)
	if strings.Contains(category, `..`) {
		return ctx.JSON(ctx.Data().SetInfo(ctx.T(`参数错误: %s`, category), 0).SetZone(`category`))
	}
	if category != log.DefaultLog.Category && !log.HasCategory(category) {
		return ctx.JSON(ctx.Data().SetInfo(ctx.T(`不存在日志分类: %s`, category), 0).SetZone(`category`))
	}
	_, _, timeformat, filename, err := log.DateFormatFilename(c.LogFile())
	if err != nil {
		return ctx.JSON(ctx.Data().SetError(err))
	}
	var logFile string
	if len(timeformat) > 0 {
		logFile = fmt.Sprintf(filename, time.Now().Format(timeformat))
	} else {
		logFile = filename
	}
	logFile = strings.Replace(logFile, `{category}`, category, -1)
	if !com.FileExists(logFile) {
		serviceAppLogFile := service.ServiceLogDir() + echo.FilePathSeparator + service.ServiceAppLogFile
		_, _, timeformat, filename, err = log.DateFormatFilename(serviceAppLogFile)
		if err == nil {
			if len(timeformat) > 0 {
				serviceAppLogFile = fmt.Sprintf(filename, time.Now().Format(timeformat))
			} else {
				serviceAppLogFile = filename
			}
			serviceAppLogFile = strings.Replace(serviceAppLogFile, `{category}`, category, -1)
			if com.FileExists(serviceAppLogFile) {
				logFile = serviceAppLogFile
			}
		}
	}
	return common.LogShow(ctx, logFile)
}

func (c *Log) SetBy(r echo.H, defaults echo.H) *Log {
	if !r.Has(`log`) && defaults != nil {
		r.Set(`log`, defaults.GetStore(`log`))
	}
	loge := r.GetStore(`log`)
	c.Colorable = loge.Bool(`colorable`)
	c.SaveFile = loge.String(`saveFile`)
	switch t := loge.Get(`targets`).(type) {
	case []interface{}:
		for k, v := range t {
			if k > 0 {
				c.Targets += `,`
			}
			c.Targets = fmt.Sprint(v)
		}
	case []string:
		c.Targets = strings.Join(t, `,`)
	case string:
		c.Targets = t
	}
	c.FileMaxBytes = loge.Int64(`fileMaxBytes`)
	return c
}

func (c *Log) LogFile() string {
	if len(c.SaveFile) > 0 {
		return c.SaveFile
	}
	return filepath.Join(echo.Wd(), `data/logs/{category}_{date:20060102}_info.log`)
}

func (c *Log) Init() {
	//======================================================
	// 配置日志
	//======================================================
	if c.Debug {
		log.DefaultLog.MaxLevel = log.LevelDebug
		//log.DefaultLog.Formatter = log.ShortFileFormatter
	} else {
		log.DefaultLog.MaxLevel = log.LevelInfo
	}
	targets := []log.Target{}
	for _, targetName := range strings.Split(c.Targets, `,`) {
		targetName = strings.TrimSpace(targetName)
		if len(targetName) == 0 {
			continue
		}
		switch targetName {
		case "file":
			//输出到文件
			fileTarget := log.NewFileTarget()
			fileTarget.FileName = c.LogFile()
			fileTarget.Filter.MaxLevel = log.DefaultLog.MaxLevel
			if c.FileMaxBytes > 0 {
				fileTarget.MaxBytes = c.FileMaxBytes
			}
			targets = append(targets, fileTarget)

		case "console":
			fallthrough
		default:
			//输出到命令行
			consoleTarget := log.NewConsoleTarget()
			consoleTarget.ColorMode = c.Colorable
			targets = append(targets, consoleTarget)
		}
	}

	log.SetTarget(targets...)
	log.SetFatalAction(log.ActionExit)
}
<|endoftext|>


<commit_before>package web

import (
	"github.com/ant0ine/go-json-rest"
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced"

	"mime"
	"net/http"
	"net/url"
)

type ServiceConfig struct {
	bindPort   string
	agentPort  string
	zookeepers []string
}

func NewServiceConfig(bindPort string, agentPort string, zookeepers []string) *ServiceConfig {
	cfg := ServiceConfig{bindPort, agentPort, zookeepers}
	if len(cfg.bindPort) == 0 {
		cfg.bindPort = ":8787"
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	if len(cfg.zookeepers) == 0 {
		cfg.zookeepers = []string{"127.0.0.1:2181"}
	}
	return &cfg
}

func (this *ServiceConfig) Serve() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}
	routes := []rest.Route{
		rest.Route{"GET", "/", MainPage},
		rest.Route{"GET", "/test", TestPage},
		// Hosts
		rest.Route{"GET", "/hosts", this.AuthorizedClient(RestGetHosts)},
		rest.Route{"POST", "/hosts/add", this.AuthorizedClient(RestAddHost)},
		rest.Route{"DELETE", "/hosts/:hostId", this.AuthorizedClient(RestRemoveHost)},
		rest.Route{"PUT", "/hosts/:hostId", this.AuthorizedClient(RestUpdateHost)},
		rest.Route{"GET", "/hosts/:hostId/running", this.AuthorizedClient(RestGetRunningForHost)},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", this.AuthorizedClient(RestKillRunning)},
		// Pools
		rest.Route{"POST", "/pools/add", this.AuthorizedClient(RestAddPool)},
		rest.Route{"GET", "/pools/:poolId/hosts", this.AuthorizedClient(RestGetHostsForResourcePool)},
		rest.Route{"DELETE", "/pools/:poolId", this.AuthorizedClient(RestRemovePool)},
		rest.Route{"PUT", "/pools/:poolId", this.AuthorizedClient(RestUpdatePool)},
		rest.Route{"GET", "/pools", this.AuthorizedClient(RestGetPools)},
		// Services (Apps)
		rest.Route{"GET", "/services", this.AuthorizedClient(RestGetAllServices)},
		rest.Route{"GET", "/services/:serviceId", this.AuthorizedClient(RestGetService)},
		rest.Route{"GET", "/services/:serviceId/running", this.AuthorizedClient(RestGetRunningForService)},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", this.AuthorizedClient(RestGetRunningService)},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", this.AuthorizedClient(RestGetServiceStateLogs)},
		rest.Route{"POST", "/services/add", this.AuthorizedClient(RestAddService)},
		rest.Route{"DELETE", "/services/:serviceId", this.AuthorizedClient(RestRemoveService)},
		rest.Route{"GET", "/services/:serviceId/logs", this.AuthorizedClient(RestGetServiceLogs)},
		rest.Route{"PUT", "/services/:serviceId", this.AuthorizedClient(RestUpdateService)},
		// Service templates (App templates)
		rest.Route{"GET", "/templates", this.AuthorizedClient(RestGetAppTemplates)},
		rest.Route{"POST", "/templates/deploy", this.AuthorizedClient(RestDeployAppTemplate)},
		// Login
		rest.Route{"POST", "/login", RestLogin},
		rest.Route{"DELETE", "/login", RestLogout},
		// "Misc" stuff
		rest.Route{"GET", "/top/services", this.AuthorizedClient(RestGetTopServices)},

		rest.Route{"GET", "/running", this.AuthorizedClient(RestGetAllRunning)},
		// Generic static data
		rest.Route{"GET", "/favicon.ico", FavIcon},
		rest.Route{"GET", "/static*resource", StaticData},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	routes = routeToInternalServiceProxy("/elastic", "http://127.0.0.1:9200/", routes)
	routes = routeToInternalServiceProxy("/metrics", "http://127.0.0.1:8888/", routes)

	handler.SetRoutes(routes...)

	http.ListenAndServe(this.bindPort, &handler)
}

var methods []string = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	// Wrap the normal http.Handler in a rest.HandlerFunc
	targetUrl, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := serviced.NewReverseProxy(path, targetUrl)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (this *ServiceConfig) AuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !LoginOk(r) {
			RestUnauthorized(w)
			return
		}
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) getClient() (c *serviced.ControlClient, err error) {
	// setup the client
	c, err = serviced.NewControlClient(this.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control plane client: %v", err)
	}
	return c, err
}
<commit_msg>Move comment to more appropriate place<commit_after>package web

import (
	"github.com/ant0ine/go-json-rest"
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced"

	"mime"
	"net/http"
	"net/url"
)

type ServiceConfig struct {
	bindPort   string
	agentPort  string
	zookeepers []string
}

func NewServiceConfig(bindPort string, agentPort string, zookeepers []string) *ServiceConfig {
	cfg := ServiceConfig{bindPort, agentPort, zookeepers}
	if len(cfg.bindPort) == 0 {
		cfg.bindPort = ":8787"
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	if len(cfg.zookeepers) == 0 {
		cfg.zookeepers = []string{"127.0.0.1:2181"}
	}
	return &cfg
}

func (this *ServiceConfig) Serve() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}
	routes := []rest.Route{
		rest.Route{"GET", "/", MainPage},
		rest.Route{"GET", "/test", TestPage},
		// Hosts
		rest.Route{"GET", "/hosts", this.AuthorizedClient(RestGetHosts)},
		rest.Route{"POST", "/hosts/add", this.AuthorizedClient(RestAddHost)},
		rest.Route{"DELETE", "/hosts/:hostId", this.AuthorizedClient(RestRemoveHost)},
		rest.Route{"PUT", "/hosts/:hostId", this.AuthorizedClient(RestUpdateHost)},
		rest.Route{"GET", "/hosts/:hostId/running", this.AuthorizedClient(RestGetRunningForHost)},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", this.AuthorizedClient(RestKillRunning)},
		// Pools
		rest.Route{"POST", "/pools/add", this.AuthorizedClient(RestAddPool)},
		rest.Route{"GET", "/pools/:poolId/hosts", this.AuthorizedClient(RestGetHostsForResourcePool)},
		rest.Route{"DELETE", "/pools/:poolId", this.AuthorizedClient(RestRemovePool)},
		rest.Route{"PUT", "/pools/:poolId", this.AuthorizedClient(RestUpdatePool)},
		rest.Route{"GET", "/pools", this.AuthorizedClient(RestGetPools)},
		// Services (Apps)
		rest.Route{"GET", "/services", this.AuthorizedClient(RestGetAllServices)},
		rest.Route{"GET", "/services/:serviceId", this.AuthorizedClient(RestGetService)},
		rest.Route{"GET", "/services/:serviceId/running", this.AuthorizedClient(RestGetRunningForService)},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", this.AuthorizedClient(RestGetRunningService)},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", this.AuthorizedClient(RestGetServiceStateLogs)},
		rest.Route{"POST", "/services/add", this.AuthorizedClient(RestAddService)},
		rest.Route{"DELETE", "/services/:serviceId", this.AuthorizedClient(RestRemoveService)},
		rest.Route{"GET", "/services/:serviceId/logs", this.AuthorizedClient(RestGetServiceLogs)},
		rest.Route{"PUT", "/services/:serviceId", this.AuthorizedClient(RestUpdateService)},
		// Service templates (App templates)
		rest.Route{"GET", "/templates", this.AuthorizedClient(RestGetAppTemplates)},
		rest.Route{"POST", "/templates/deploy", this.AuthorizedClient(RestDeployAppTemplate)},
		// Login
		rest.Route{"POST", "/login", RestLogin},
		rest.Route{"DELETE", "/login", RestLogout},
		// "Misc" stuff
		rest.Route{"GET", "/top/services", this.AuthorizedClient(RestGetTopServices)},

		rest.Route{"GET", "/running", this.AuthorizedClient(RestGetAllRunning)},
		// Generic static data
		rest.Route{"GET", "/favicon.ico", FavIcon},
		rest.Route{"GET", "/static*resource", StaticData},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	routes = routeToInternalServiceProxy("/elastic", "http://127.0.0.1:9200/", routes)
	routes = routeToInternalServiceProxy("/metrics", "http://127.0.0.1:8888/", routes)

	handler.SetRoutes(routes...)

	http.ListenAndServe(this.bindPort, &handler)
}

var methods []string = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	targetUrl, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	// Wrap the normal http.Handler in a rest.HandlerFunc
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := serviced.NewReverseProxy(path, targetUrl)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (this *ServiceConfig) AuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !LoginOk(r) {
			RestUnauthorized(w)
			return
		}
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) getClient() (c *serviced.ControlClient, err error) {
	// setup the client
	c, err = serviced.NewControlClient(this.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control plane client: %v", err)
	}
	return c, err
}
<|endoftext|>