<commit_before>package baa

import (
	"fmt"
	"strings"
	"sync"
)

// METHODS declare support HTTP method
var METHODS = map[string]bool{
	"GET":     true,
	"POST":    true,
	"PUT":     true,
	"DELETE":  true,
	"PATCH":   true,
	"OPTIONS": true,
	"HEAD":    true,
}

// optimize ...
var _radix [RouteMaxLength]byte
var _param [RouterParamMaxLength]byte

// Router provlider router for baa
type Router struct {
	autoHead        bool
	mu              sync.RWMutex
	notFoundHandler HandlerFunc
	routeMap        map[string]*Route
	routeNamedMap   map[string]string
	group           *Group
}

// Route is a tree node
// route use radix tree
type Route struct {
	pattern  string
	hasParam bool
	parent   *Route
	router   *Router
	children map[string]*Route
	handlers []HandlerFunc
}

// Group route
type Group struct {
	pattern  string
	handlers []HandlerFunc
	mu       sync.RWMutex
}

// newRouter create a router instance
func newRouter() *Router {
	r := new(Router)
	r.routeMap = make(map[string]*Route)
	for m := range METHODS {
		r.routeMap[m] = newRoute("/", nil, nil)
	}
	r.routeNamedMap = make(map[string]string)
	r.group = newGroup()
	return r
}

// newRoute create a route item
func newRoute(pattern string, handles []HandlerFunc, router *Router) *Route {
	r := new(Route)
	r.pattern = pattern
	r.handlers = handles
	r.router = router
	r.children = make(map[string]*Route)
	return r
}

// newGroup create a group router
func newGroup() *Group {
	g := new(Group)
	g.handlers = make([]HandlerFunc, 0)
	return g
}

// Match match the uri for handler
func (r *Router) match(method, uri string, c *Context) *Route {
	ru := r.lookup(uri, r.routeMap[method], c)
	if ru != nil && ru.handlers != nil {
		return ru
	}
	return nil
}

// URLFor use named route return format url
func (r *Router) URLFor(name string, args ...interface{}) string {
	if name == "" {
		return ""
	}
	url := r.routeNamedMap[name]
	if url == "" {
		return ""
	}
	return fmt.Sprintf(url, args...)
}

// groupAdd add a group route has same prefix and handle chain
func (r *Router) groupAdd(pattern string, f func(), handlers []HandlerFunc) {
	r.group.mu.Lock()
	defer r.group.mu.Unlock()

	r.group.pattern = pattern
	r.group.handlers = handlers

	f()

	r.group.reset()
}

// Handle registers a new request handle with the given pattern, method and handlers.
func (r *Router) add(method string, pattern string, handlers []HandlerFunc) *Route {
	if _, ok := METHODS[method]; !ok {
		panic("unsupport http method [" + method + "]")
	}
	if pattern == "" {
		panic("route pattern can not be emtpy!")
	}
	if pattern[0] != '/' {
		panic("route pattern must begin /")
	}
	if len(pattern) > RouteMaxLength {
		panic(fmt.Sprintf("route pattern max length limit %d", RouteMaxLength))
	}
	r.mu.Lock()
	defer r.mu.Unlock()

	// check group set, not concurrent safe
	if r.group.pattern != "" {
		pattern = r.group.pattern + pattern
		if len(r.group.handlers) > 0 {
			h := make([]HandlerFunc, 0, len(r.group.handlers)+len(handlers))
			h = append(h, r.group.handlers...)
			h = append(h, handlers...)
			handlers = h
		}
	}

	root := r.routeMap[method]
	radix := _radix[:0]
	var i, k int
	var tru *Route
	for i = 0; i < len(pattern); i++ {
		//param route
		if pattern[i] == ':' {
			// clear static route
			if len(radix) > 0 {
				root = r.insert(root, newRoute(string(radix), nil, nil))
				radix = _radix[:0]
			}
			// set param route
			param := _param[:0]
			k = 0
			for i = i + 1; i < len(pattern); i++ {
				if !isParamChar(pattern[i]) {
					i--
					break
				}
				param = append(param, pattern[i])
				k++
			}
			if k == 0 {
				panic("route pattern param is empty")
			}
			if k > RouterParamMaxLength {
				panic(fmt.Sprintf("route pattern param max length limit %d", RouterParamMaxLength))
			}
			// check last character
			p := ":" + string(param[:k])
			if i == len(pattern) {
				tru = newRoute(p, handlers, r)
			} else {
				tru = newRoute(p, nil, nil)
			}
			tru.hasParam = true
			root = r.insert(root, tru)
			continue
		}
		radix = append(radix, pattern[i])
	}

	// static route
	if len(radix) > 0 {
		tru = newRoute(string(radix), handlers, r)
		r.insert(root, tru)
	}

	return newRoute(pattern, handlers, r)
}

// insert build the route tree
func (r *Router) insert(root *Route, ru *Route) *Route {
	// same route
	if root.pattern == ru.pattern {
		if ru.handlers != nil {
			root.handlers = ru.handlers
		}
		return root
	}

	// param route
	if root.hasParam && ru.hasParam {
		if root.parent == nil {
			panic("Router.insert error route has no parent")
		}
		ru.parent = root.parent
		root.parent.children[ru.pattern] = ru
		return ru
	}

	var k string
	if root.hasParam && !ru.hasParam {
		for k = range root.children {
			if root.children[k].pattern == ru.pattern {
				if ru.handlers != nil {
					root.children[k].handlers = ru.handlers
				}
				return root.children[k]
			}
			if hasPrefix(root.children[k].pattern, ru.pattern) > 0 {
				return r.insert(root.children[k], ru)
			}
		}

		ru.parent = root
		root.children[ru.pattern] = ru
		return ru
	}

	var ok bool
	if !root.hasParam && ru.hasParam {
		if _, ok = root.children[ru.pattern]; ok {
			root.children[ru.pattern].handlers = ru.handlers
		} else {
			ru.parent = root
			root.children[ru.pattern] = ru
		}
		return root.children[ru.pattern]
	}

	// find radix
	pos := hasPrefix(root.pattern, ru.pattern)
	if pos == 0 {
		panic("Router.insert error root[" + root.pattern + "] and node[" + ru.pattern + "] not have both prefix")
	}
	if pos == len(ru.pattern) {
		ru.parent = root.parent
		ru.children[root.pattern] = root
		delete(root.parent.children, root.pattern)
		root.parent.children[ru.pattern] = ru
		root.pattern = root.pattern[pos:]
		root.parent = ru
		return ru
	}

	ru.pattern = ru.pattern[pos:]
	if pos == len(root.pattern) {
		for k = range root.children {
			if root.children[k].pattern == ru.pattern {
				if ru.handlers != nil {
					root.children[k].handlers = ru.handlers
				}
				return root.children[k]
			}
			if hasPrefix(root.children[k].pattern, ru.pattern) > 0 {
				return r.insert(root.children[k], ru)
			}
		}

		ru.parent = root
		root.children[ru.pattern] = ru
		return ru
	}

	delete(root.parent.children, root.pattern)
	_root := newRoute(root.pattern[:pos], nil, r)
	_root.parent = root.parent
	ru.parent = _root
	newRoot := &Route{
		pattern:  root.pattern[pos:],
		handlers: root.handlers,
		children: root.children,
		router:   r,
		parent:   _root,
	}
	_root.children[newRoot.pattern] = newRoot
	_root.children[ru.pattern] = ru
	root.parent.children[_root.pattern] = _root
	return ru
}

func (r *Router) lookup(pattern string, root *Route, c *Context) *Route {
	var ru *Route
	// static route
	if !root.hasParam {
		if pattern == root.pattern {
			return root
		}
		if strings.HasPrefix(pattern, root.pattern) {
			pattern = pattern[len(root.pattern):]
		} else {
			return nil
		}
	} else {
		var i int
		if len(root.children) == 0 {
			i = len(pattern)
		} else {
			for i = 0; i < len(pattern); i++ {
				if !isParamChar(pattern[i]) {
					break
				}
			}
		}
		c.SetParam(root.pattern[1:], pattern[:i])
		if i == len(pattern) {
			if root.handlers != nil {
				return root
			}
			return nil
		}
		pattern = pattern[i:]
	}
	if len(root.children) == 0 {
		return nil
	}

	// first, static route
	for _, v := range root.children {
		if ru = r.lookup(pattern, v, c); ru != nil {
			if ru.handlers != nil {
				return ru
			}
		}
	}

	return nil
}

// print the route map
func (r *Router) print(prefix string, root *Route) {
	if root == nil {
		for m := range r.routeMap {
			fmt.Println(m)
			r.print("", r.routeMap[m])
		}
		return
	}
	fmt.Println(prefix + " -> " + root.pattern)
	for i := range root.children {
		r.print(prefix+" -> "+root.pattern, root.children[i])
	}
}

// reset group data for next group set
func (g *Group) reset() {
	g.pattern = ""
	g.handlers = g.handlers[:0]
}

// Name set name of route
func (r *Route) Name(name string) {
	if name == "" {
		return
	}
	p := make([]byte, 0, len(r.pattern))
	for i := 0; i < len(r.pattern); i++ {
		if r.pattern[i] != ':' {
			p = append(p, r.pattern[i])
			continue
		}
		p = append(p, '%')
		p = append(p, 'v')
		for i = i + 1; i < len(r.pattern); i++ {
			if !isParamChar(r.pattern[i]) {
				i--
				break
			}
		}
	}
	r.router.routeNamedMap[name] = string(p)
}

// handle route hadnle chain
// if something wrote to http, break chain and return
func (r *Route) handle(c *Context) {
	for _, h := range r.handlers {
		h(c)
		if c.Resp.Wrote() {
			return
		}
	}
}

// isParamChar check the char can used for route params
func isParamChar(c byte) bool {
	if (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c == 95 {
		return true
	}
	return false
}

// hasPrefix returns the same prefix position
func hasPrefix(s1, s2 string) int {
	l := len(s1)
	var i int
	for i = 0; i < len(s2); i++ {
		if i >= l || s2[i] != s1[i] {
			break
		}
	}
	return i
}
<commit_msg>update router allow param use colon<commit_after>package baa

import (
	"fmt"
	"strings"
	"sync"
)

// METHODS declare support HTTP method
var METHODS = map[string]bool{
	"GET":     true,
	"POST":    true,
	"PUT":     true,
	"DELETE":  true,
	"PATCH":   true,
	"OPTIONS": true,
	"HEAD":    true,
}

// optimize ...
var _radix [RouteMaxLength]byte
var _param [RouterParamMaxLength]byte

// Router provlider router for baa
type Router struct {
	autoHead        bool
	mu              sync.RWMutex
	notFoundHandler HandlerFunc
	routeMap        map[string]*Route
	routeNamedMap   map[string]string
	group           *Group
}

// Route is a tree node
// route use radix tree
type Route struct {
	pattern  string
	hasParam bool
	parent   *Route
	router   *Router
	children map[string]*Route
	handlers []HandlerFunc
}

// Group route
type Group struct {
	pattern  string
	handlers []HandlerFunc
	mu       sync.RWMutex
}

// newRouter create a router instance
func newRouter() *Router {
	r := new(Router)
	r.routeMap = make(map[string]*Route)
	for m := range METHODS {
		r.routeMap[m] = newRoute("/", nil, nil)
	}
	r.routeNamedMap = make(map[string]string)
	r.group = newGroup()
	return r
}

// newRoute create a route item
func newRoute(pattern string, handles []HandlerFunc, router *Router) *Route {
	r := new(Route)
	r.pattern = pattern
	r.handlers = handles
	r.router = router
	r.children = make(map[string]*Route)
	return r
}

// newGroup create a group router
func newGroup() *Group {
	g := new(Group)
	g.handlers = make([]HandlerFunc, 0)
	return g
}

// Match match the uri for handler
func (r *Router) match(method, uri string, c *Context) *Route {
	ru := r.lookup(uri, r.routeMap[method], c)
	if ru != nil && ru.handlers != nil {
		return ru
	}
	return nil
}

// URLFor use named route return format url
func (r *Router) URLFor(name string, args ...interface{}) string {
	if name == "" {
		return ""
	}
	url := r.routeNamedMap[name]
	if url == "" {
		return ""
	}
	return fmt.Sprintf(url, args...)
}

// groupAdd add a group route has same prefix and handle chain
func (r *Router) groupAdd(pattern string, f func(), handlers []HandlerFunc) {
	r.group.mu.Lock()
	defer r.group.mu.Unlock()

	r.group.pattern = pattern
	r.group.handlers = handlers

	f()

	r.group.reset()
}

// Handle registers a new request handle with the given pattern, method and handlers.
func (r *Router) add(method string, pattern string, handlers []HandlerFunc) *Route {
	if _, ok := METHODS[method]; !ok {
		panic("unsupport http method [" + method + "]")
	}
	if pattern == "" {
		panic("route pattern can not be emtpy!")
	}
	if pattern[0] != '/' {
		panic("route pattern must begin /")
	}
	if len(pattern) > RouteMaxLength {
		panic(fmt.Sprintf("route pattern max length limit %d", RouteMaxLength))
	}
	r.mu.Lock()
	defer r.mu.Unlock()

	// check group set, not concurrent safe
	if r.group.pattern != "" {
		pattern = r.group.pattern + pattern
		if len(r.group.handlers) > 0 {
			h := make([]HandlerFunc, 0, len(r.group.handlers)+len(handlers))
			h = append(h, r.group.handlers...)
			h = append(h, handlers...)
			handlers = h
		}
	}

	root := r.routeMap[method]
	radix := _radix[:0]
	var i, k int
	var tru *Route
	for i = 0; i < len(pattern); i++ {
		//param route
		if pattern[i] == ':' {
			// clear static route
			if len(radix) > 0 {
				root = r.insert(root, newRoute(string(radix), nil, nil))
				radix = _radix[:0]
			}
			// set param route
			param := _param[:0]
			k = 0
			for i = i + 1; i < len(pattern); i++ {
				if !isParamChar(pattern[i]) {
					i--
					break
				}
				param = append(param, pattern[i])
				k++
			}
			if k == 0 {
				panic("route pattern param is empty")
			}
			if k > RouterParamMaxLength {
				panic(fmt.Sprintf("route pattern param max length limit %d", RouterParamMaxLength))
			}
			// check last character
			p := ":" + string(param[:k])
			if i == len(pattern) {
				tru = newRoute(p, handlers, r)
			} else {
				tru = newRoute(p, nil, nil)
			}
			tru.hasParam = true
			root = r.insert(root, tru)
			continue
		}
		radix = append(radix, pattern[i])
	}

	// static route
	if len(radix) > 0 {
		tru = newRoute(string(radix), handlers, r)
		r.insert(root, tru)
	}

	return newRoute(pattern, handlers, r)
}

// insert build the route tree
func (r *Router) insert(root *Route, ru *Route) *Route {
	// same route
	if root.pattern == ru.pattern {
		if ru.handlers != nil {
			root.handlers = ru.handlers
		}
		return root
	}

	// param route
	if root.hasParam && ru.hasParam {
		if root.parent == nil {
			panic("Router.insert error route has no parent")
		}
		ru.parent = root.parent
		root.parent.children[ru.pattern] = ru
		return ru
	}

	var k string
	if root.hasParam && !ru.hasParam {
		for k = range root.children {
			if root.children[k].pattern == ru.pattern {
				if ru.handlers != nil {
					root.children[k].handlers = ru.handlers
				}
				return root.children[k]
			}
			if hasPrefix(root.children[k].pattern, ru.pattern) > 0 {
				return r.insert(root.children[k], ru)
			}
		}

		ru.parent = root
		root.children[ru.pattern] = ru
		return ru
	}

	var ok bool
	if !root.hasParam && ru.hasParam {
		if _, ok = root.children[ru.pattern]; ok {
			root.children[ru.pattern].handlers = ru.handlers
		} else {
			ru.parent = root
			root.children[ru.pattern] = ru
		}
		return root.children[ru.pattern]
	}

	// find radix
	pos := hasPrefix(root.pattern, ru.pattern)
	if pos == 0 {
		panic("Router.insert error root[" + root.pattern + "] and node[" + ru.pattern + "] not have both prefix")
	}
	if pos == len(ru.pattern) {
		ru.parent = root.parent
		ru.children[root.pattern] = root
		delete(root.parent.children, root.pattern)
		root.parent.children[ru.pattern] = ru
		root.pattern = root.pattern[pos:]
		root.parent = ru
		return ru
	}

	ru.pattern = ru.pattern[pos:]
	if pos == len(root.pattern) {
		for k = range root.children {
			if root.children[k].pattern == ru.pattern {
				if ru.handlers != nil {
					root.children[k].handlers = ru.handlers
				}
				return root.children[k]
			}
			if hasPrefix(root.children[k].pattern, ru.pattern) > 0 {
				return r.insert(root.children[k], ru)
			}
		}

		ru.parent = root
		root.children[ru.pattern] = ru
		return ru
	}

	delete(root.parent.children, root.pattern)
	_root := newRoute(root.pattern[:pos], nil, r)
	_root.parent = root.parent
	ru.parent = _root
	newRoot := &Route{
		pattern:  root.pattern[pos:],
		handlers: root.handlers,
		children: root.children,
		router:   r,
		parent:   _root,
	}
	_root.children[newRoot.pattern] = newRoot
	_root.children[ru.pattern] = ru
	root.parent.children[_root.pattern] = _root
	return ru
}

func (r *Router) lookup(pattern string, root *Route, c *Context) *Route {
	var ru *Route
	// static route
	if !root.hasParam {
		if pattern == root.pattern {
			return root
		}
		if strings.HasPrefix(pattern, root.pattern) {
			pattern = pattern[len(root.pattern):]
		} else {
			return nil
		}
	} else {
		var i int
		if len(root.children) == 0 {
			i = len(pattern)
		} else {
			for i = 0; i < len(pattern); i++ {
				// find allow pattern contains :
				if !isParamChar(pattern[i]) && pattern[i] != ':' {
					break
				}
			}
		}
		c.SetParam(root.pattern[1:], pattern[:i])
		if i == len(pattern) {
			if root.handlers != nil {
				return root
			}
			return nil
		}
		pattern = pattern[i:]
	}
	if len(root.children) == 0 {
		return nil
	}

	// first, static route
	for _, v := range root.children {
		if ru = r.lookup(pattern, v, c); ru != nil {
			if ru.handlers != nil {
				return ru
			}
		}
	}

	return nil
}

// print the route map
func (r *Router) print(prefix string, root *Route) {
	if root == nil {
		for m := range r.routeMap {
			fmt.Println(m)
			r.print("", r.routeMap[m])
		}
		return
	}
	fmt.Println(prefix + " -> " + root.pattern)
	for i := range root.children {
		r.print(prefix+" -> "+root.pattern, root.children[i])
	}
}

// reset group data for next group set
func (g *Group) reset() {
	g.pattern = ""
	g.handlers = g.handlers[:0]
}

// Name set name of route
func (r *Route) Name(name string) {
	if name == "" {
		return
	}
	p := make([]byte, 0, len(r.pattern))
	for i := 0; i < len(r.pattern); i++ {
		if r.pattern[i] != ':' {
			p = append(p, r.pattern[i])
			continue
		}
		p = append(p, '%')
		p = append(p, 'v')
		for i = i + 1; i < len(r.pattern); i++ {
			if !isParamChar(r.pattern[i]) {
				i--
				break
			}
		}
	}
	r.router.routeNamedMap[name] = string(p)
}

// handle route hadnle chain
// if something wrote to http, break chain and return
func (r *Route) handle(c *Context) {
	for _, h := range r.handlers {
		h(c)
		if c.Resp.Wrote() {
			return
		}
	}
}

// isParamChar check the char can used for route params
func isParamChar(c byte) bool {
	if (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c == 95 {
		return true
	}
	return false
}

// hasPrefix returns the same prefix position
func hasPrefix(s1, s2 string) int {
	l := len(s1)
	var i int
	for i = 0; i < len(s2); i++ {
		if i >= l || s2[i] != s1[i] {
			break
		}
	}
	return i
}
<|endoftext|>


<commit_before>package mark

import "strings"

// Mark
type Mark struct {
	*Parse
	Input   string
	Options Options
}

// Mark options
type Options struct {
	Gfm, Tables bool
}

// Return new Mark
func New(input string) *Mark {
	// Preprocessing
	input = strings.Replace(input, "\t", "    ", -1)
	return &Mark{
		Input: input,
		Parse: newParse(input),
	}
}

// Parse and render input
func (m *Mark) Render() string {
	m.parse()
	m.render()
	return m.output
}

// AddRenderFn let you pass NodeType, and RenderFn function
// and override the default Node rendering
func (m *Mark) AddRenderFn(typ NodeType, fn RenderFn) {
	m.renderFn[typ] = fn
}

// Staic render function
func Render(input string) string {
	m := New(input)
	return m.Render()
}
<commit_msg>feat(mark): add smartypants to options<commit_after>package mark

import "strings"

// Mark
type Mark struct {
	*Parse
	Input   string
	Options Options
}

// Mark options
type Options struct {
	Gfm         bool
	Tables      bool
	Smartypants bool
}

// Return new Mark
func New(input string) *Mark {
	// Preprocessing
	input = strings.Replace(input, "\t", "    ", -1)
	return &Mark{
		Input: input,
		Parse: newParse(input),
	}
}

// Parse and render input
func (m *Mark) Render() string {
	m.parse()
	m.render()
	return m.output
}

// AddRenderFn let you pass NodeType, and RenderFn function
// and override the default Node rendering
func (m *Mark) AddRenderFn(typ NodeType, fn RenderFn) {
	m.renderFn[typ] = fn
}

// Staic render function
func Render(input string) string {
	m := New(input)
	return m.Render()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	// "io"
	"io/ioutil"
	"log"
	"net/http"
	// "os"
	"github.com/howeyc/fsnotify"
	"strings"
	"time"
)

var rules map[string]map[string]string
var status int = http.StatusNotFound
var size int = 19

func main() {
	address := flag.String("address", "127.0.0.1", "The address to listen on")
	path := flag.String("path", "", "Path to the csv of redirects")
	port := flag.String("port", "8080", "The port to listen on")
	// watch := flag.Bool("watch", false, "Watch for CSV file changes")
	flag.Parse()
	if *path == "" {
		log.Fatalln("You must supply a mapping file")
	}

	log.Println("Starting godir...")

	log.Println("Loading rules from:", *path)
	err := loadRules(*path)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println("Starting watcher for ", *path)
	watcher, err := fsnotify.NewWatcher()
	watcher.Watch(*path)
	if err != nil {
		log.Println("Can't watch file", *path)
	}
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				if ev.IsModify() {
					log.Println(ev.Name, "updated, attempting reload...")
					err := loadRules(ev.Name)
					if err != nil {
						log.Println("Couln't reload rules: ", err)
					} else {
						log.Println("Reloaded rules from", ev.Name)
					}
				}
			case err := <-watcher.Error:
				log.Println("Error watching file:", *path, err)
			}
		}
	}()

	http.HandleFunc("/", handler(redirectHandler, rules))
	log.Fatal(http.ListenAndServe(*address+":"+*port, Log(http.DefaultServeMux)))
}

func redirectHandler(w http.ResponseWriter, r *http.Request, rules map[string]map[string]string) {
	// this function does nothing remove it and setup the handler to have
	// the right signature for http.HandleFunc
	log.Println(rules)
}

func handler(fn func(http.ResponseWriter, *http.Request, map[string]map[string]string), rules map[string]map[string]string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		target := rules[strings.Split(r.Host, ":")[0]][r.URL.Path]
		if target == "" {
			http.NotFound(w, r)
			return
		}
		status = http.StatusMovedPermanently
		size = 0
		http.Redirect(w, r, target, status)
		return
	}
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t := time.Now()
		fmt.Printf("%s - %s [%s] \"%s %s %s\" %d %d \"%s\" \"%s\"\n",
			strings.Split(r.RemoteAddr, ":")[0], r.URL.User, t.Format("02/Jan/2006:15:04:05 -0700"), r.Method, r.URL, r.Proto, status, size, r.Referer(), r.UserAgent())
		handler.ServeHTTP(w, r)
	})
}

func loadRules(path string) (err error) {
	f, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	err = json.Unmarshal(f, &rules)
	if err != nil {
		return err
	}
	return
}
<commit_msg>sort variables<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	// "io"
	"io/ioutil"
	"log"
	"net/http"
	// "os"
	"github.com/howeyc/fsnotify"
	"strings"
	"time"
)

var rules map[string]map[string]string
var size int = 19
var status int = http.StatusNotFound

func main() {
	address := flag.String("address", "127.0.0.1", "The address to listen on")
	path := flag.String("path", "", "Path to the csv of redirects")
	port := flag.String("port", "8080", "The port to listen on")
	// watch := flag.Bool("watch", false, "Watch for CSV file changes")
	flag.Parse()
	if *path == "" {
		log.Fatalln("You must supply a mapping file")
	}

	log.Println("Starting godir...")

	log.Println("Loading rules from:", *path)
	err := loadRules(*path)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println("Starting watcher for ", *path)
	watcher, err := fsnotify.NewWatcher()
	watcher.Watch(*path)
	if err != nil {
		log.Println("Can't watch file", *path)
	}
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				if ev.IsModify() {
					log.Println(ev.Name, "updated, attempting reload...")
					err := loadRules(ev.Name)
					if err != nil {
						log.Println("Couln't reload rules: ", err)
					} else {
						log.Println("Reloaded rules from", ev.Name)
					}
				}
			case err := <-watcher.Error:
				log.Println("Error watching file:", *path, err)
			}
		}
	}()

	http.HandleFunc("/", handler(redirectHandler, rules))
	log.Fatal(http.ListenAndServe(*address+":"+*port, Log(http.DefaultServeMux)))
}

func redirectHandler(w http.ResponseWriter, r *http.Request, rules map[string]map[string]string) {
	// this function does nothing remove it and setup the handler to have
	// the right signature for http.HandleFunc
	log.Println(rules)
}

func handler(fn func(http.ResponseWriter, *http.Request, map[string]map[string]string), rules map[string]map[string]string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		target := rules[strings.Split(r.Host, ":")[0]][r.URL.Path]
		if target == "" {
			http.NotFound(w, r)
			return
		}
		status = http.StatusMovedPermanently
		size = 0
		http.Redirect(w, r, target, status)
		return
	}
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t := time.Now()
		fmt.Printf("%s - %s [%s] \"%s %s %s\" %d %d \"%s\" \"%s\"\n",
			strings.Split(r.RemoteAddr, ":")[0], r.URL.User, t.Format("02/Jan/2006:15:04:05 -0700"), r.Method, r.URL, r.Proto, status, size, r.Referer(), r.UserAgent())
		handler.ServeHTTP(w, r)
	})
}

func loadRules(path string) (err error) {
	f, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	err = json.Unmarshal(f, &rules)
	if err != nil {
		return err
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/aws/aws-sdk-go/service/cloudfront/sign"
  "os"
  "log"
  "time"
  "strings"
  "gopkg.in/gin-gonic/gin.v1"
)

// Sign URL to be valid for 1 hour from now.
func getCloudfrontSignedUrl(rawURL string) string {
  privKeyReader := strings.NewReader(os.Getenv("AWS_CLOUDFRONT_PRIVATE_KEY"))
  privKey, err := sign.LoadPEMPrivKey(privKeyReader)
  if err != nil {
      log.Fatalf("Failed load private key, err: %s\n", err.Error())
  }
  signer := sign.NewURLSigner(os.Getenv("AWS_CLOUDFRONT_KEYPAIR_ID"), privKey)
  signedURL, err := signer.Sign(rawURL, time.Now().Add(1*time.Hour))
  if err != nil {
      log.Fatalf("Failed to sign url, err: %s\n", err.Error())
  }

  return signedURL
}

func signHandler(c *gin.Context) {
  rawURL := c.Query("url")
  s := SignResponse{SignedURL: getCloudfrontSignedUrl(rawURL)}
  c.JSON(200, gin.H{
      "SignedURL": s,
  })
}

func main() {
  port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}

  r := gin.Default()
  r.GET("/sign", signHandler)
  r.Run(":" + port)
}
<commit_msg>Removing struct usage.<commit_after>package main

import (
  "github.com/aws/aws-sdk-go/service/cloudfront/sign"
  "os"
  "log"
  "time"
  "strings"
  "gopkg.in/gin-gonic/gin.v1"
)

// Sign URL to be valid for 1 hour from now.
func getCloudfrontSignedUrl(rawURL string) string {
  privKeyReader := strings.NewReader(os.Getenv("AWS_CLOUDFRONT_PRIVATE_KEY"))
  privKey, err := sign.LoadPEMPrivKey(privKeyReader)
  if err != nil {
      log.Fatalf("Failed load private key, err: %s\n", err.Error())
  }
  signer := sign.NewURLSigner(os.Getenv("AWS_CLOUDFRONT_KEYPAIR_ID"), privKey)
  signedURL, err := signer.Sign(rawURL, time.Now().Add(1*time.Hour))
  if err != nil {
      log.Fatalf("Failed to sign url, err: %s\n", err.Error())
  }

  return signedURL
}

func signHandler(c *gin.Context) {
  rawURL := c.Query("url")
  c.JSON(200, gin.H{
      "SignedURL": getCloudfrontSignedUrl(rawURL),
  })
}

func main() {
  port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}

  r := gin.Default()
  r.GET("/sign", signHandler)
  r.Run(":" + port)
}
<|endoftext|>


<commit_before>// Copyright 2014 Julien Schmidt. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
// SSE code based on https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c

// Package main provides the server application handling the server-sent-events
// for the remote photo show.
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/julienschmidt/httprouter"
)

// Set your config here
const (
	https    bool   = false
	host     string = ":8080"
	crtPath  string = "/etc/ssl/http.pem"
	keyPath  string = "/etc/ssl/http.key"
	photoDir string = "./photos/"
	username string = "gordon"
	password string = "secret!"
)

var (
	broker    *Broker
	imgID     uint
	endID     uint
	photoJSON []byte
	photoErr  error
)

type Broker struct {
	// Events are pushed to this channel by the main events-gathering routine
	Notifier chan string

	// New client connections
	newClients chan chan string

	// Closed client connections
	closingClients chan chan string

	// Client connections registry
	clients map[chan string]bool
}

func NewServer() (broker *Broker) {
	// Instantiate a broker
	broker = &Broker{
		Notifier:       make(chan string, 1),
		newClients:     make(chan chan string),
		closingClients: make(chan chan string),
		clients:        make(map[chan string]bool),
	}

	// Set it running - listening and broadcasting events
	go broker.listen()

	return
}

func (broker *Broker) ServeHTTP(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	// Make sure that the writer supports flushing.
	flusher, ok := rw.(http.Flusher)
	if !ok {
		http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
		return
	}

	rw.Header().Set("Content-Type", "text/event-stream")
	rw.Header().Set("Cache-Control", "no-cache")
	rw.Header().Set("Connection", "keep-alive")
	rw.Header().Set("Access-Control-Allow-Origin", "*")

	// Each connection registers its own message channel with the Broker's
	// connections registry
	messageChan := make(chan string)

	// Signal the broker that we have a new connection
	broker.newClients <- messageChan

	// Remove this client from the map of connected clients when this handler
	// exits.
	defer func() {
		broker.closingClients <- messageChan
	}()

	// Listen to connection close and deregister messageChan
	notify := rw.(http.CloseNotifier).CloseNotify()

	go func() {
		<-notify
		broker.closingClients <- messageChan
	}()

	for {
		// Write to the ResponseWriter
		// Server Sent Events compatible
		fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)

		// Flush the data immediately instead of buffering it for later.
		flusher.Flush()
	}
}

func (broker *Broker) listen() {
	for {
		select {
		case s := <-broker.newClients:
			// A new client has connected. Register their message channel
			broker.clients[s] = true
			log.Printf("Client added. %d registered clients", len(broker.clients))

		case s := <-broker.closingClients:
			// A client has disconnected and we want to stop sending messages
			// to this client.
			delete(broker.clients, s)
			log.Printf("Removed client. %d registered clients", len(broker.clients))

		case event := <-broker.Notifier:
			// We got a new event from the outside!
			// Send event to all connected clients
			fmt.Println("Send event:", event)
			for clientMessageChan, _ := range broker.clients {
				clientMessageChan <- event
			}
		}
	}
}

func BasicAuth(h httprouter.Handle, user, pass []byte) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		const basicAuthPrefix string = "Basic "

		// Get the Basic Authentication credentials
		auth := r.Header.Get("Authorization")
		if strings.HasPrefix(auth, basicAuthPrefix) {
			// Check credentials
			payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
			if err == nil {
				pair := bytes.SplitN(payload, []byte(":"), 2)
				if len(pair) == 2 && bytes.Equal(pair[0], user) && bytes.Equal(pair[1], pass) {
					// Delegate request to the given handle
					h(w, r, ps)
					return
				}
			}
		}

		// Request Basic Authentication otherwise
		w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	}
}

func reset() {
	imgID = 0
	photoJSON, photoErr = loadPhotos()
	broker.Notifier <- "r"
}

func setID(id uint) error {
	if id > endID {
		errors.New("Invalid ID")
	}

	imgID = id
	broker.Notifier <- fmt.Sprintf("s%d", id)

	return nil
}

func loadPhotos() ([]byte, error) {
	dir, err := os.Open(photoDir)
	if err != nil {
		return nil, err
	}
	defer dir.Close()

	fi, err := dir.Stat()
	if err != nil {
		return nil, err
	}

	filenames := make([]string, 0)
	if fi.IsDir() {
		fis, err := dir.Readdir(-1) // -1 means return all the FileInfos
		if err != nil {
			return nil, err
		}

		for _, fileinfo := range fis {
			if !fileinfo.IsDir() {
				filenames = append(filenames, fileinfo.Name())
			}
		}
	}

	return json.Marshal(filenames)
}

func PhotoShow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "remotephoto.html")
}

func PhotoMaster(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "remotemaster.html")
}

func PhotoMasterCMD(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	switch r.PostFormValue("cmd") {
	case "set":
		id, err := strconv.ParseUint(r.PostFormValue("id"), 10, 0)

		if err == nil {
			err = setID(uint(id))
		}

		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
		return

	case "reset":
		reset()
		return

	default:
		http.Error(w, "Illegal CMD", http.StatusInternalServerError)
		return
	}
}

func PhotosJSON(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	if photoErr != nil {
		http.Error(w, photoErr.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Cache-Control", "no-cache")
	fmt.Fprintf(w, `{"photos": %s, "id": %d}`, photoJSON, imgID)
}

func PhotosServer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w, r, photoDir+ps.ByName("photo"))
}

func AssetsServer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w, r, "assets/"+ps.ByName("asset"))
}

func Favicon(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "favicon.ico")
}

func main() {
	user := []byte(username)
	pass := []byte(password)

	router := httprouter.New()
	router.GET("/", PhotoShow)
	router.GET("/master", BasicAuth(PhotoMaster, user, pass))
	router.POST("/master", BasicAuth(PhotoMasterCMD, user, pass))
	router.GET("/photos.json", PhotosJSON)
	router.GET("/photos/:photo", PhotosServer)
	router.GET("/assets/:asset", AssetsServer)
	// router.GET("/favicon.ico", Favicon)

	// SSE client broker
	broker = NewServer()
	router.GET("/listen", broker.ServeHTTP)

	// Initialize photo show
	reset()

	if https {
		log.Fatal("HTTPS server error: ", http.ListenAndServeTLS(host, crtPath, keyPath, router))
	} else {
		log.Fatal("HTTP server error: ", http.ListenAndServe(host, router))
	}
}
<commit_msg>server: fix setID check + other small changes<commit_after>// Copyright 2014 Julien Schmidt. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
// SSE code based on https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c

// Package main provides the server application handling the server-sent-events
// for the remote photo show.
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/julienschmidt/httprouter"
)

// Set your config here
const (
	https    bool   = false
	host     string = ":8080"
	crtPath  string = "/etc/ssl/http.pem"
	keyPath  string = "/etc/ssl/http.key"
	photoDir string = "./photos/"

	// Credentials for master site
	username string = "gordon"
	password string = "secret!"
)

var (
	broker    *Broker
	imgID     uint
	endID     uint
	photoJSON []byte
	photoErr  error
)

type Broker struct {
	// Events are pushed to this channel by the main events-gathering routine
	Notifier chan string

	// New client connections
	newClients chan chan string

	// Closed client connections
	closingClients chan chan string

	// Client connections registry
	clients map[chan string]bool
}

func NewServer() (broker *Broker) {
	// Instantiate a broker
	broker = &Broker{
		Notifier:       make(chan string, 1),
		newClients:     make(chan chan string),
		closingClients: make(chan chan string),
		clients:        make(map[chan string]bool),
	}

	// Set it running - listening and broadcasting events
	go broker.listen()

	return
}

func (broker *Broker) ServeHTTP(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	// Make sure that the writer supports flushing.
	flusher, ok := rw.(http.Flusher)
	if !ok {
		http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
		return
	}

	rw.Header().Set("Content-Type", "text/event-stream")
	rw.Header().Set("Cache-Control", "no-cache")
	rw.Header().Set("Connection", "keep-alive")
	rw.Header().Set("Access-Control-Allow-Origin", "*")

	// Each connection registers its own message channel with the Broker's
	// connections registry
	messageChan := make(chan string)

	// Signal the broker that we have a new connection
	broker.newClients <- messageChan

	// Remove this client from the map of connected clients when this handler
	// exits.
	defer func() {
		broker.closingClients <- messageChan
	}()

	// Listen to connection close and deregister messageChan
	notify := rw.(http.CloseNotifier).CloseNotify()

	go func() {
		<-notify
		broker.closingClients <- messageChan
	}()

	for {
		// Write to the ResponseWriter
		// Server Sent Events compatible
		fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)

		// Flush the data immediately instead of buffering it for later.
		flusher.Flush()
	}
}

func (broker *Broker) listen() {
	for {
		select {
		case s := <-broker.newClients:
			// A new client has connected. Register their message channel
			broker.clients[s] = true
			log.Printf("Client added. %d registered clients", len(broker.clients))

		case s := <-broker.closingClients:
			// A client has disconnected and we want to stop sending messages
			// to this client.
			delete(broker.clients, s)
			log.Printf("Removed client. %d registered clients", len(broker.clients))

		case event := <-broker.Notifier:
			// We got a new event from the outside!
			// Send event to all connected clients
			fmt.Println("Send event:", event)
			for clientMessageChan, _ := range broker.clients {
				clientMessageChan <- event
			}
		}
	}
}

// BasicAuth is a httprouter.Handle wrapper for Basic HTTP Authentication
func BasicAuth(h httprouter.Handle, user, pass []byte) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		const basicAuthPrefix string = "Basic "

		// Get the Basic Authentication credentials
		auth := r.Header.Get("Authorization")
		if strings.HasPrefix(auth, basicAuthPrefix) {
			// Check credentials
			payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
			if err == nil {
				pair := bytes.SplitN(payload, []byte(":"), 2)
				if len(pair) == 2 && bytes.Equal(pair[0], user) && bytes.Equal(pair[1], pass) {
					// Delegate request to the given handle
					h(w, r, ps)
					return
				}
			}
		}

		// Request Basic Authentication otherwise
		w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	}
}

// reset reloads the photos and restarts the photo show
func reset() {
	imgID = 0
	photoJSON, photoErr = loadPhotos()
	broker.Notifier <- "r"
}

// setID sets the current photo show image ID and sends notifications to all clients
func setID(id uint) error {
	if id > endID {
		return errors.New("Invalid ID")
	}

	imgID = id
	broker.Notifier <- fmt.Sprintf("s%d", id)

	return nil
}

// loadPhotos gets all files in the photo dir and saves them as a list in JSON
func loadPhotos() ([]byte, error) {
	dir, err := os.Open(photoDir)
	if err != nil {
		return nil, err
	}
	defer dir.Close()

	fi, err := dir.Stat()
	if err != nil {
		return nil, err
	}

	filenames := make([]string, 0)
	if fi.IsDir() {
		fis, err := dir.Readdir(-1) // -1 means return all the FileInfos
		if err != nil {
			return nil, err
		}

		for _, fileinfo := range fis {
			if !fileinfo.IsDir() {
				filenames = append(filenames, fileinfo.Name())
			}
		}
	}

	return json.Marshal(filenames)
}

func PhotoShow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "remotephoto.html")
}

func PhotoMaster(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "remotemaster.html")
}

func PhotoMasterCMD(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	switch r.PostFormValue("cmd") {
	case "set":
		id, err := strconv.ParseUint(r.PostFormValue("id"), 10, 0)

		if err == nil {
			err = setID(uint(id))
		}

		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
		return

	case "reset":
		reset()
		return

	default:
		http.Error(w, "Invalid CMD", http.StatusInternalServerError)
		return
	}
}

func PhotosJSON(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	if photoErr != nil {
		http.Error(w, photoErr.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Cache-Control", "no-cache")
	fmt.Fprintf(w, `{"photos": %s, "id": %d}`, photoJSON, imgID)
}

func PhotosServer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w, r, photoDir+ps.ByName("photo"))
}

func Favicon(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	http.ServeFile(w, r, "favicon.ico")
}

func main() {
	user := []byte(username)
	pass := []byte(password)

	router := httprouter.New()
	router.GET("/", PhotoShow)
	router.GET("/master", BasicAuth(PhotoMaster, user, pass))
	router.POST("/master", BasicAuth(PhotoMasterCMD, user, pass))
	router.GET("/photos.json", PhotosJSON)
	router.GET("/photos/:photo", PhotosServer)
	// router.GET("/favicon.ico", Favicon)

	// SSE client broker
	broker = NewServer()
	router.GET("/listen", broker.ServeHTTP)

	// Initialize photo show
	reset()

	if https {
		log.Fatal("HTTPS server error: ", http.ListenAndServeTLS(host, crtPath, keyPath, router))
	} else {
		log.Fatal("HTTP server error: ", http.ListenAndServe(host, router))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-dockerclient"
	"github.com/flynn/go-flynn/cluster"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/titanous/go-tigertonic"
)

func main() {
	var err error
	clusterc, err = cluster.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	router, err = strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	mux := tigertonic.NewTrieServeMux()
	mux.Handle("PUT", "/apps/{app_id}/domains/{domain}", tigertonic.Marshaled(addDomain))
	mux.Handle("POST", "/apps/{app_id}/formation/{formation_id}", tigertonic.Marshaled(changeFormation))
	mux.Handle("GET", "/apps/{app_id}/jobs", tigertonic.Marshaled(getJobs))
	mux.HandleFunc("GET", "/apps/{app_id}/jobs/{job_id}/logs", getJobLog)
	mux.HandleFunc("POST", "/apps/{app_id}/jobs", runJob)
	http.ListenAndServe("127.0.0.1:1200", tigertonic.Logged(mux, nil))
}

var clusterc *cluster.Client
var router strowgerc.Client

type Job struct {
	ID   string `json:"id"`
	Type string `json:"type"`
}

func addDomain(u *url.URL, h http.Header, data *struct{}) (int, http.Header, struct{}, error) {
	q := u.Query()
	if err := router.AddFrontend(&strowger.Config{Service: q.Get("app_id"), HTTPDomain: q.Get("domain")}); err != nil {
		return 500, nil, struct{}{}, err
	}
	return 200, nil, struct{}{}, nil
}

// GET /apps/{app_id}/jobs
func getJobs(u *url.URL, h http.Header) (int, http.Header, []Job, error) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		return 500, nil, nil, err
	}

	q := u.Query()
	prefix := q.Get("app_id") + "-"
	jobs := make([]Job, 0)
	for _, host := range hosts {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				typ := strings.Split(job.ID[len(prefix):], ".")[0]
				jobs = append(jobs, Job{ID: job.ID, Type: typ})
			}
		}
	}

	return 200, nil, jobs, nil
}

type Formation struct {
	Quantity int    `json:"quantity"`
	Type     string `json:"type"`
}

func shelfURL() string {
	services, _ := discoverd.Services("shelf", discoverd.DefaultTimeout)
	if len(services) < 1 {
		panic("Shelf is not discoverable")
	}
	return services[0].Addr
}

// POST /apps/{app_id}/formation/{formation_id}
func changeFormation(u *url.URL, h http.Header, req *Formation) (int, http.Header, *Formation, error) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		log.Println("scheduler state error", err)
		return 500, nil, nil, err
	}

	q := u.Query()
	req.Type = q.Get("formation_id")
	prefix := q.Get("app_id") + "-" + req.Type + "."
	var jobs []*host.Job
	for _, h := range hosts {
		for _, job := range h.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				if job.Attributes == nil {
					job.Attributes = make(map[string]string)
				}
				job.Attributes["host_id"] = h.ID
				jobs = append(jobs, job)
			}
		}
	}

	if req.Quantity < 0 {
		req.Quantity = 0
	}
	diff := req.Quantity - len(jobs)
	log.Printf("have %d %s, diff %d", len(jobs), req.Type, diff)
	if diff > 0 {
		config := &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          []string{"start", req.Type},
			AttachStdout: true,
			AttachStderr: true,
			Env:          []string{"SLUG_URL=http://" + shelfURL() + "/" + q.Get("app_id") + ".tgz"},
		}
		if req.Type == "web" {
			config.Env = append(config.Env, "SD_NAME="+q.Get("app_id"))
		}
		addReq := &host.AddJobsReq{
			HostJobs: make(map[string][]*host.Job),
		}
	outer:
		for {
			for h := range hosts {
				addReq.HostJobs[h] = append(addReq.HostJobs[h], &host.Job{ID: cluster.RandomJobID(prefix), TCPPorts: 1, Config: config})
				diff--
				if diff == 0 {
					break outer
				}
			}
		}

		res, err := clusterc.AddJobs(addReq)
		if err != nil || !res.Success {
			log.Println("schedule error", err)
			return 500, nil, nil, err
		}
	} else if diff < 0 {
		for _, job := range jobs[:-diff] {
			host, err := clusterc.ConnectHost(job.Attributes["host_id"])
			if err != nil {
				log.Println("error connecting to", job.Attributes["host_id"], err)
				continue
			}
			if err := host.StopJob(job.ID); err != nil {
				log.Println("error stopping", job.ID, "on", job.Attributes["host_id"], err)
			}
		}
	}

	return 200, nil, req, nil
}

// GET /apps/{app_id}/jobs/{job_id}/logs
func getJobLog(w http.ResponseWriter, req *http.Request) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	q := req.URL.Query()
	jobID := q.Get("job_id")
	if prefix := q.Get("app_id") + "-"; !strings.HasPrefix(jobID, prefix) {
		jobID = prefix + jobID
	}
	var job *host.Job
	var h host.Host
outer:
	for _, h = range hosts {
		for _, job = range h.Jobs {
			if job.ID == jobID {
				break outer
			}
		}
		job = nil
	}
	if job == nil {
		w.WriteHeader(404)
		return
	}

	attachReq := &host.AttachReq{
		JobID: job.ID,
		Flags: host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagLogs,
	}

	client, err := clusterc.ConnectHost(h.ID)
	if err != nil {
		w.WriteHeader(500)
		log.Println("lorne connect failed", err)
		return
	}
	attachConn, _, err := client.Attach(attachReq, false)
	if err != nil {
		w.WriteHeader(500)
		log.Println("attach failed", err)
		return
	}
	defer attachConn.Close()
	io.Copy(w, attachConn)
}

type NewJob struct {
	Cmd     []string          `json:"cmd"`
	Env     map[string]string `json:"env"`
	Attach  bool              `json:"attach"`
	TTY     bool              `json:"tty"`
	Columns int               `json:"tty_columns"`
	Lines   int               `json:"tty_lines"`
}

// POST /apps/{app_id}/jobs
func runJob(w http.ResponseWriter, req *http.Request) {
	var jobReq NewJob
	if err := json.NewDecoder(req.Body).Decode(&jobReq); err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	hosts, err := clusterc.ListHosts()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}
	// pick a random host
	var hostID string
	for hostID = range hosts {
		break
	}
	if hostID == "" {
		w.WriteHeader(500)
		log.Println("no hosts found")
		return
	}

	env := make([]string, 0, len(jobReq.Env))
	for k, v := range jobReq.Env {
		env = append(env, k+"="+v)
	}

	q := req.URL.Query()
	job := &host.Job{
		ID: cluster.RandomJobID(q.Get("app_id") + "-run."),
		Config: &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          jobReq.Cmd,
			AttachStdin:  true,
			AttachStdout: true,
			AttachStderr: true,
			StdinOnce:    true,
			Env:          append(env, "SLUG_URL=http://"+shelfURL()+"/"+q.Get("app_id")+".tgz"),
		},
	}
	if jobReq.TTY {
		job.Config.Tty = true
	}
	if jobReq.Attach {
		job.Config.AttachStdin = true
		job.Config.StdinOnce = true
		job.Config.OpenStdin = true
	}

	var attachConn cluster.ReadWriteCloser
	var attachWait func() error
	if jobReq.Attach {
		attachReq := &host.AttachReq{
			JobID:  job.ID,
			Flags:  host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagStdin | host.AttachFlagStream,
			Height: jobReq.Lines,
			Width:  jobReq.Columns,
		}
		client, err := clusterc.ConnectHost(hostID)
		if err != nil {
			w.WriteHeader(500)
			log.Println("lorne connect failed", err)
			return
		}
		attachConn, attachWait, err = client.Attach(attachReq, true)
		if err != nil {
			w.WriteHeader(500)
			log.Println("attach failed", err)
			return
		}
		defer attachConn.Close()
	}

	res, err := clusterc.AddJobs(&host.AddJobsReq{HostJobs: map[string][]*host.Job{hostID: {job}}})
	if err != nil || !res.Success {
		w.WriteHeader(500)
		log.Println("schedule failed", err)
		return
	}

	if jobReq.Attach {
		if err := attachWait(); err != nil {
			w.WriteHeader(500)
			log.Println("attach wait failed", err)
			return
		}
		w.Header().Set("Content-Type", "application/vnd.flynn.hijack")
		w.Header().Set("Content-Length", "0")
		w.WriteHeader(200)
		conn, _, err := w.(http.Hijacker).Hijack()
		if err != nil {
			return
		}
		defer conn.Close()

		done := make(chan struct{})
		copy := func(to cluster.ReadWriteCloser, from io.Reader) {
			io.Copy(to, from)
			to.CloseWrite()
			done <- struct{}{}
		}
		go copy(conn.(cluster.ReadWriteCloser), attachConn)
		go copy(attachConn, conn)
		<-done
		<-done

		return
	}
	w.WriteHeader(200)
}
<commit_msg>Update flynn-host type usage<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-dockerclient"
	"github.com/flynn/go-flynn/cluster"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/titanous/go-tigertonic"
)

func main() {
	var err error
	clusterc, err = cluster.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	router, err = strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	mux := tigertonic.NewTrieServeMux()
	mux.Handle("PUT", "/apps/{app_id}/domains/{domain}", tigertonic.Marshaled(addDomain))
	mux.Handle("POST", "/apps/{app_id}/formation/{formation_id}", tigertonic.Marshaled(changeFormation))
	mux.Handle("GET", "/apps/{app_id}/jobs", tigertonic.Marshaled(getJobs))
	mux.HandleFunc("GET", "/apps/{app_id}/jobs/{job_id}/logs", getJobLog)
	mux.HandleFunc("POST", "/apps/{app_id}/jobs", runJob)
	http.ListenAndServe("127.0.0.1:1200", tigertonic.Logged(mux, nil))
}

var clusterc *cluster.Client
var router strowgerc.Client

type Job struct {
	ID   string `json:"id"`
	Type string `json:"type"`
}

func addDomain(u *url.URL, h http.Header, data *struct{}) (int, http.Header, struct{}, error) {
	q := u.Query()
	if err := router.AddFrontend(&strowger.Config{Service: q.Get("app_id"), HTTPDomain: q.Get("domain")}); err != nil {
		return 500, nil, struct{}{}, err
	}
	return 200, nil, struct{}{}, nil
}

// GET /apps/{app_id}/jobs
func getJobs(u *url.URL, h http.Header) (int, http.Header, []Job, error) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		return 500, nil, nil, err
	}

	q := u.Query()
	prefix := q.Get("app_id") + "-"
	jobs := make([]Job, 0)
	for _, host := range hosts {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				typ := strings.Split(job.ID[len(prefix):], ".")[0]
				jobs = append(jobs, Job{ID: job.ID, Type: typ})
			}
		}
	}

	return 200, nil, jobs, nil
}

type Formation struct {
	Quantity int    `json:"quantity"`
	Type     string `json:"type"`
}

func shelfURL() string {
	services, _ := discoverd.Services("shelf", discoverd.DefaultTimeout)
	if len(services) < 1 {
		panic("Shelf is not discoverable")
	}
	return services[0].Addr
}

// POST /apps/{app_id}/formation/{formation_id}
func changeFormation(u *url.URL, h http.Header, req *Formation) (int, http.Header, *Formation, error) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		log.Println("scheduler state error", err)
		return 500, nil, nil, err
	}

	q := u.Query()
	req.Type = q.Get("formation_id")
	prefix := q.Get("app_id") + "-" + req.Type + "."
	var jobs []*host.Job
	for _, h := range hosts {
		for _, job := range h.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				if job.Attributes == nil {
					job.Attributes = make(map[string]string)
				}
				job.Attributes["host_id"] = h.ID
				jobs = append(jobs, job)
			}
		}
	}

	if req.Quantity < 0 {
		req.Quantity = 0
	}
	diff := req.Quantity - len(jobs)
	log.Printf("have %d %s, diff %d", len(jobs), req.Type, diff)
	if diff > 0 {
		config := &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          []string{"start", req.Type},
			AttachStdout: true,
			AttachStderr: true,
			Env:          []string{"SLUG_URL=http://" + shelfURL() + "/" + q.Get("app_id") + ".tgz"},
		}
		if req.Type == "web" {
			config.Env = append(config.Env, "SD_NAME="+q.Get("app_id"))
		}
		addReq := &host.AddJobsReq{
			HostJobs: make(map[string][]*host.Job),
		}
	outer:
		for {
			for h := range hosts {
				addReq.HostJobs[h] = append(addReq.HostJobs[h], &host.Job{ID: cluster.RandomJobID(prefix), TCPPorts: 1, Config: config})
				diff--
				if diff == 0 {
					break outer
				}
			}
		}

		_, err = clusterc.AddJobs(addReq)
		if err != nil {
			log.Println("schedule error", err)
			return 500, nil, nil, err
		}
	} else if diff < 0 {
		for _, job := range jobs[:-diff] {
			host, err := clusterc.ConnectHost(job.Attributes["host_id"])
			if err != nil {
				log.Println("error connecting to", job.Attributes["host_id"], err)
				continue
			}
			if err := host.StopJob(job.ID); err != nil {
				log.Println("error stopping", job.ID, "on", job.Attributes["host_id"], err)
			}
		}
	}

	return 200, nil, req, nil
}

// GET /apps/{app_id}/jobs/{job_id}/logs
func getJobLog(w http.ResponseWriter, req *http.Request) {
	hosts, err := clusterc.ListHosts()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	q := req.URL.Query()
	jobID := q.Get("job_id")
	if prefix := q.Get("app_id") + "-"; !strings.HasPrefix(jobID, prefix) {
		jobID = prefix + jobID
	}
	var job *host.Job
	var h host.Host
outer:
	for _, h = range hosts {
		for _, job = range h.Jobs {
			if job.ID == jobID {
				break outer
			}
		}
		job = nil
	}
	if job == nil {
		w.WriteHeader(404)
		return
	}

	attachReq := &host.AttachReq{
		JobID: job.ID,
		Flags: host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagLogs,
	}

	client, err := clusterc.ConnectHost(h.ID)
	if err != nil {
		w.WriteHeader(500)
		log.Println("lorne connect failed", err)
		return
	}
	attachConn, _, err := client.Attach(attachReq, false)
	if err != nil {
		w.WriteHeader(500)
		log.Println("attach failed", err)
		return
	}
	defer attachConn.Close()
	io.Copy(w, attachConn)
}

type NewJob struct {
	Cmd     []string          `json:"cmd"`
	Env     map[string]string `json:"env"`
	Attach  bool              `json:"attach"`
	TTY     bool              `json:"tty"`
	Columns int               `json:"tty_columns"`
	Lines   int               `json:"tty_lines"`
}

// POST /apps/{app_id}/jobs
func runJob(w http.ResponseWriter, req *http.Request) {
	var jobReq NewJob
	if err := json.NewDecoder(req.Body).Decode(&jobReq); err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	hosts, err := clusterc.ListHosts()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}
	// pick a random host
	var hostID string
	for hostID = range hosts {
		break
	}
	if hostID == "" {
		w.WriteHeader(500)
		log.Println("no hosts found")
		return
	}

	env := make([]string, 0, len(jobReq.Env))
	for k, v := range jobReq.Env {
		env = append(env, k+"="+v)
	}

	q := req.URL.Query()
	job := &host.Job{
		ID: cluster.RandomJobID(q.Get("app_id") + "-run."),
		Config: &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          jobReq.Cmd,
			AttachStdin:  true,
			AttachStdout: true,
			AttachStderr: true,
			StdinOnce:    true,
			Env:          append(env, "SLUG_URL=http://"+shelfURL()+"/"+q.Get("app_id")+".tgz"),
		},
	}
	if jobReq.TTY {
		job.Config.Tty = true
	}
	if jobReq.Attach {
		job.Config.AttachStdin = true
		job.Config.StdinOnce = true
		job.Config.OpenStdin = true
	}

	var attachConn cluster.ReadWriteCloser
	var attachWait func() error
	if jobReq.Attach {
		attachReq := &host.AttachReq{
			JobID:  job.ID,
			Flags:  host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagStdin | host.AttachFlagStream,
			Height: jobReq.Lines,
			Width:  jobReq.Columns,
		}
		client, err := clusterc.ConnectHost(hostID)
		if err != nil {
			w.WriteHeader(500)
			log.Println("lorne connect failed", err)
			return
		}
		attachConn, attachWait, err = client.Attach(attachReq, true)
		if err != nil {
			w.WriteHeader(500)
			log.Println("attach failed", err)
			return
		}
		defer attachConn.Close()
	}

	_, err = clusterc.AddJobs(&host.AddJobsReq{HostJobs: map[string][]*host.Job{hostID: {job}}})
	if err != nil {
		w.WriteHeader(500)
		log.Println("schedule failed", err)
		return
	}

	if jobReq.Attach {
		if err := attachWait(); err != nil {
			w.WriteHeader(500)
			log.Println("attach wait failed", err)
			return
		}
		w.Header().Set("Content-Type", "application/vnd.flynn.hijack")
		w.Header().Set("Content-Length", "0")
		w.WriteHeader(200)
		conn, _, err := w.(http.Hijacker).Hijack()
		if err != nil {
			return
		}
		defer conn.Close()

		done := make(chan struct{})
		copy := func(to cluster.ReadWriteCloser, from io.Reader) {
			io.Copy(to, from)
			to.CloseWrite()
			done <- struct{}{}
		}
		go copy(conn.(cluster.ReadWriteCloser), attachConn)
		go copy(attachConn, conn)
		<-done
		<-done

		return
	}
	w.WriteHeader(200)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
<commit_msg>Added qps metric endpoint<commit_after>package main

import (
    "fmt"
    "net/http"
    "github.com/paulbellamy/ratecounter"
    "time"
)

var counter = ratecounter.NewRateCounter(1 * time.Second)
func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
    counter.Incr(1)
}

func metricsQpsHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Qps %d!", counter.Rate())
}

func main() {
    http.HandleFunc("/application", handler)
    http.HandleFunc("/metrics/qps", metricsQpsHandler)
    http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package hole

import (
    "log"
    "net"
    "bytes"
    "strings"
    "github.com/satori/go.uuid"
)

type Server struct {
    clientConn Conn
    clientAlive bool
    alive bool
    sessions map[string]Session
}

func (server Server) Serve(addr string) {
    parts := strings.SplitN(addr, "://", 2)
    listen, err := net.Listen(parts[0], parts[1])
    if err != nil {
        log.Fatal(err)
    }
    defer listen.Close()
    log.Printf("Hole proxy server started on %s\n", addr)
    for {
        if !server.alive {
            break
        }
        conn, err := listen.Accept()
        if err != nil {
            log.Fatal(err)
        }
        if server.clientAlive {
            go server.handleConnection(conn)
        } else {
            go server.handleClient(conn)
        }
    }
}

func (server *Server) handleConnection(conn net.Conn) {
    sessionId := uuid.NewV4().Bytes()
    session := NewSession(sessionId, server.clientConn)
    server.sessions[string(sessionId)] = session
    go PipeThenClose(conn, session.w)
    PipeThenClose(session.r, conn)
}

func (server *Server) handleClient(conn net.Conn) {
    server.clientConn = NewServerConn(conn)
    server.clientAlive = true
    defer server.clientConn.Close()
    var err error
    var payload []byte
    if _, err = server.clientConn.Receive(); err != nil {
        server.clientAlive = false
        return
    }
    var sessionId, data []byte
    var session Session
    for {
        if payload, err = server.clientConn.Receive(); err != nil {
            break
        }
        sessionId, data = DecodePacket(payload)
        session = server.sessions[string(sessionId)]
        if bytes.Equal(data, []byte("EOF")) {
            session.r.FeedEOF()
        } else {
            session.r.FeedData(data)
        }
    }
}
<commit_msg>delete session when session end<commit_after>package hole

import (
    "log"
    "net"
    "bytes"
    "strings"
    "github.com/satori/go.uuid"
)

type Server struct {
    clientConn Conn
    clientAlive bool
    alive bool
    sessions map[string]Session
}

func (server Server) Serve(addr string) {
    parts := strings.SplitN(addr, "://", 2)
    listen, err := net.Listen(parts[0], parts[1])
    if err != nil {
        log.Fatal(err)
    }
    defer listen.Close()
    log.Printf("Hole proxy server started on %s\n", addr)
    for {
        if !server.alive {
            break
        }
        conn, err := listen.Accept()
        if err != nil {
            log.Fatal(err)
        }
        if server.clientAlive {
            go server.handleConnection(conn)
        } else {
            go server.handleClient(conn)
        }
    }
}

func (server *Server) handleConnection(conn net.Conn) {
    sessionId := uuid.NewV4().Bytes()
    session := NewSession(sessionId, server.clientConn)
    server.sessions[string(sessionId)] = session
    go PipeThenClose(conn, session.w)
    PipeThenClose(session.r, conn)
    delete(server.sessions, string(session.Id))
}

func (server *Server) handleClient(conn net.Conn) {
    server.clientConn = NewServerConn(conn)
    server.clientAlive = true
    defer server.clientConn.Close()
    var err error
    var payload []byte
    if _, err = server.clientConn.Receive(); err != nil {
        server.clientAlive = false
        return
    }
    var sessionId, data []byte
    var session Session
    for {
        if payload, err = server.clientConn.Receive(); err != nil {
            break
        }
        sessionId, data = DecodePacket(payload)
        session = server.sessions[string(sessionId)]
        if bytes.Equal(data, []byte("EOF")) {
            session.r.FeedEOF()
        } else {
            session.r.FeedData(data)
        }
    }
}
<|endoftext|>


<commit_before>package main

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

	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/fasthttp"
	"github.com/ziutek/telnet"
)

type fusionResponse struct {
  // Page   int      `json:"page"`
	API_Rooms []fusionRoom
}

type fusionRoom struct {
	RoomID   string
	RoomName string
	Symbols  []fusionSymbol
}

type fusionSymbol struct {
	ConnectInfo string
}

type room struct {
	Hostname string
	Address  string
}

func checkErr(err error) {
	if err != nil {
		panic(err) // Don't forget your towel
	}
}

func health(c echo.Context) error {
	return c.String(http.StatusOK, "Uh, we had a slight weapons malfunction, but uh... everything's perfectly all right now. We're fine. We're all fine here now, thank you. How are you?")
}

func getTelnetOutput(address string, port string, command string) string {
	t, err := telnet.Dial("tcp", address+":"+port)
	checkErr(err)

	t.SetUnixWriteMode(true) // Convert any '\n' (LF) to '\r\n' (CR LF)

	command = command + "\nhostname" // Send two commands so we get a second prompt to use as a delimiter
	buf := make([]byte, len(command)+1)
	copy(buf, command)
	buf[len(command)] = '\n'
	_, err = t.Write(buf)
	checkErr(err)

	t.SkipUntil("TSW-750>") // Skip to the first prompt delimiter
	var output []byte
	output, err = t.ReadUntil("TSW-750>") // Read until the second prompt delimiter (provided by sending two commands in sendCommand)
	checkErr(err)

	t.Close() // Close the telnet session

	output = output[:len(output)-10] // Ghetto trim the prompt off the response

	return string(output)
}

func fusionRequest(requestType string, url string) []byte {
	client := &http.Client{}
	req, err := http.NewRequest(requestType, url, nil)
	checkErr(err)

	req.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(req)
	checkErr(err)

	body, err := ioutil.ReadAll(resp.Body)
	checkErr(err)

	return body
}

func getRooms(c echo.Context) error {
	response := fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/")
	return c.String(http.StatusOK, string(response)) // MAKE SURE YOU HAVE THE TRAILING SLASH
}

func getRoomByName(c echo.Context) error {
	// Get the room's ID from its name
	response := fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("room"))
	rooms := fusionResponse{}
	err := json.Unmarshal(response, &rooms)
	checkErr(err)

	// Get info about the room using its ID
	response = fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.API_Rooms[0].RoomID)
	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	checkErr(err)

  address := rooms.API_Rooms[0].Symbols[0].ConnectInfo

  room := room{
    Hostname: getTelnetOutput(address, "23", "hostname"),
    Address: address
  }

	jsonResponse, _ := json.Marshal(room)
	return c.String(http.StatusOK, string(jsonResponse))
}

func main() {
	port := ":8000"
	e := echo.New()

	// Echo doesn't like doing things "magically" which means it won't auto-redirect endpoints without a trailing slash to one with a trailing slash (and vice versa) which is why endpoints are duplicated
	e.Get("/health", health)
	e.Get("/health/", health)

	e.Get("/rooms", getRooms)
	e.Get("/rooms/", getRooms)
	e.Get("/rooms/:room", getRoomByName)
	e.Get("/rooms/:room/", getRoomByName)
	// e.Get("/buildings", ...)
	// e.Get("/buildings/:building", ...)
	// e.Get("/buildings/:building/room", ...)
	// e.Get("/buildings/:building/rooms/:room", ...)
	// e.Get("/buildings/:building/rooms/:room/signals", ...)
	// e.Get("/buildings/:building/rooms/:room/signals/:signal", ...)
	//
	// e.Post("/rooms", ...)
	// e.Post("/buildings", ...)
	// e.Post("/buildings/:building/rooms/:room/signals", ...)
	//
	// e.Put("/rooms/:room", ...)
	// e.Put("/buildings/:building", ...)
	// e.Put("/buildings/:building/rooms/:room", ...)
	// e.Put("/buildings/:building/rooms/:room/signals/:signal", ...)
	//
	// e.Delete("/rooms/:room", ...)
	// e.Delete("/buildings/:building", ...)
	// e.Delete("/buildings/:building/rooms/:room", ...)
	// e.Delete("/buildings/:building/rooms/:room/signals/:signal", ...)

	fmt.Printf("AV API is listening on %s\n", port)
	e.Run(fasthttp.New(port))
}
<commit_msg>Pulling hostname from Fusion<commit_after>package main

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

	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/fasthttp"
	"github.com/ziutek/telnet"
)

type fusionResponse struct {
	// Page   int      `json:"page"`
	API_Rooms []fusionRoom
}

type fusionRoom struct {
	RoomID   string
	RoomName string
	Symbols  []fusionSymbol
}

type fusionSymbol struct {
	ProcessorName string
	ConnectInfo   string
}

type room struct {
	Hostname string
	Address  string
}

func checkErr(err error) {
	if err != nil {
		panic(err) // Don't forget your towel
	}
}

func health(c echo.Context) error {
	return c.String(http.StatusOK, "Uh, we had a slight weapons malfunction, but uh... everything's perfectly all right now. We're fine. We're all fine here now, thank you. How are you?")
}

func getTelnetOutput(address string, port string, command string) string {
	t, err := telnet.Dial("tcp", address+":"+port)
	checkErr(err)

	t.SetUnixWriteMode(true) // Convert any '\n' (LF) to '\r\n' (CR LF)

	command = command + "\nhostname" // Send two commands so we get a second prompt to use as a delimiter
	buf := make([]byte, len(command)+1)
	copy(buf, command)
	buf[len(command)] = '\n'
	_, err = t.Write(buf)
	checkErr(err)

	t.SkipUntil("TSW-750>") // Skip to the first prompt delimiter
	var output []byte
	output, err = t.ReadUntil("TSW-750>") // Read until the second prompt delimiter (provided by sending two commands in sendCommand)
	checkErr(err)

	t.Close() // Close the telnet session

	output = output[:len(output)-10] // Ghetto trim the prompt off the response

	return string(output)
}

func fusionRequest(requestType string, url string) []byte {
	client := &http.Client{}
	req, err := http.NewRequest(requestType, url, nil)
	checkErr(err)

	req.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(req)
	checkErr(err)

	body, err := ioutil.ReadAll(resp.Body)
	checkErr(err)

	return body
}

func getRooms(c echo.Context) error {
	response := fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/")
	return c.String(http.StatusOK, string(response)) // MAKE SURE YOU HAVE THE TRAILING SLASH
}

func getRoomByName(c echo.Context) error {
	// Get the room's ID from its name
	response := fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("room"))
	rooms := fusionResponse{}
	err := json.Unmarshal(response, &rooms)
	checkErr(err)

	// Get info about the room using its ID
	response = fusionRequest("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.API_Rooms[0].RoomID)
	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	checkErr(err)

	hostname := rooms.API_Rooms[0].Symbols[0].ProcessorName
	address := rooms.API_Rooms[0].Symbols[0].ConnectInfo

	roomResponse := room{Hostname: hostname, Address: address}

	jsonResponse, _ := json.Marshal(roomResponse)
	return c.String(http.StatusOK, string(jsonResponse))
}

func main() {
	port := ":8000"
	e := echo.New()

	// Echo doesn't like doing things "magically" which means it won't auto-redirect endpoints without a trailing slash to one with a trailing slash (and vice versa) which is why endpoints are duplicated
	e.Get("/health", health)
	e.Get("/health/", health)

	e.Get("/rooms", getRooms)
	e.Get("/rooms/", getRooms)
	e.Get("/rooms/:room", getRoomByName)
	e.Get("/rooms/:room/", getRoomByName)
	// e.Get("/buildings", ...)
	// e.Get("/buildings/:building", ...)
	// e.Get("/buildings/:building/room", ...)
	// e.Get("/buildings/:building/rooms/:room", ...)
	// e.Get("/buildings/:building/rooms/:room/signals", ...)
	// e.Get("/buildings/:building/rooms/:room/signals/:signal", ...)
	//
	// e.Post("/rooms", ...)
	// e.Post("/buildings", ...)
	// e.Post("/buildings/:building/rooms/:room/signals", ...)
	//
	// e.Put("/rooms/:room", ...)
	// e.Put("/buildings/:building", ...)
	// e.Put("/buildings/:building/rooms/:room", ...)
	// e.Put("/buildings/:building/rooms/:room/signals/:signal", ...)
	//
	// e.Delete("/rooms/:room", ...)
	// e.Delete("/buildings/:building", ...)
	// e.Delete("/buildings/:building/rooms/:room", ...)
	// e.Delete("/buildings/:building/rooms/:room/signals/:signal", ...)

	fmt.Printf("AV API is listening on %s\n", port)
	e.Run(fasthttp.New(port))
}
<|endoftext|>


<commit_before>package gpio

import (
	"errors"
	"testing"
	"time"

	"github.com/hybridgroup/gobot"
)

const BUTTON_TEST_DELAY = 30

func initTestButtonDriver() *ButtonDriver {
	return NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1")
}

func TestButtonDriverHalt(t *testing.T) {
	d := initTestButtonDriver()
	go func() {
		<-d.halt
	}()
	gobot.Assert(t, len(d.Halt()), 0)
}

func TestButtonDriver(t *testing.T) {
	d := NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1")
	gobot.Assert(t, d.Name(), "bot")
	gobot.Assert(t, d.Connection().Name(), "adaptor")

	d = NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1", 30*time.Second)
	gobot.Assert(t, d.interval, BUTTON_TEST_DELAY * time.Second)
}

func TestButtonDriverStart(t *testing.T) {
	sem := make(chan bool, 0)
	d := initTestButtonDriver()
	gobot.Assert(t, len(d.Start()), 0)

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 1
		return
	}

	gobot.Once(d.Event(Push), func(data interface{}) {
		gobot.Assert(t, d.Active, true)
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Push\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 0
		return
	}

	gobot.Once(d.Event(Release), func(data interface{}) {
		gobot.Assert(t, d.Active, false)
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Release\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		err = errors.New("digital read error")
		return
	}

	gobot.Once(d.Event(Error), func(data interface{}) {
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Error\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 1
		return
	}

	gobot.Once(d.Event(Push), func(data interface{}) {
		sem <- true
	})

	d.halt <- true

	select {
	case <-sem:
		t.Errorf("Button Event \"Press\" should not published")
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
	}

}
<commit_msg>Change test delay to 50ms<commit_after>package gpio

import (
	"errors"
	"testing"
	"time"

	"github.com/hybridgroup/gobot"
)

const BUTTON_TEST_DELAY = 50

func initTestButtonDriver() *ButtonDriver {
	return NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1")
}

func TestButtonDriverHalt(t *testing.T) {
	d := initTestButtonDriver()
	go func() {
		<-d.halt
	}()
	gobot.Assert(t, len(d.Halt()), 0)
}

func TestButtonDriver(t *testing.T) {
	d := NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1")
	gobot.Assert(t, d.Name(), "bot")
	gobot.Assert(t, d.Connection().Name(), "adaptor")

	d = NewButtonDriver(newGpioTestAdaptor("adaptor"), "bot", "1", 30*time.Second)
	gobot.Assert(t, d.interval, 30 * time.Second)
}

func TestButtonDriverStart(t *testing.T) {
	sem := make(chan bool, 0)
	d := initTestButtonDriver()
	gobot.Assert(t, len(d.Start()), 0)

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 1
		return
	}

	gobot.Once(d.Event(Push), func(data interface{}) {
		gobot.Assert(t, d.Active, true)
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Push\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 0
		return
	}

	gobot.Once(d.Event(Release), func(data interface{}) {
		gobot.Assert(t, d.Active, false)
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Release\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		err = errors.New("digital read error")
		return
	}

	gobot.Once(d.Event(Error), func(data interface{}) {
		sem <- true
	})

	select {
	case <-sem:
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
		t.Errorf("Button Event \"Error\" was not published")
	}

	testAdaptorDigitalRead = func() (val int, err error) {
		val = 1
		return
	}

	gobot.Once(d.Event(Push), func(data interface{}) {
		sem <- true
	})

	d.halt <- true

	select {
	case <-sem:
		t.Errorf("Button Event \"Press\" should not published")
	case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
	}

}
<|endoftext|>


<commit_before>// Copyright 2016-2019 Authors of Cilium
//
// 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 maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/datapath/loader"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/endpointmanager"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	bpfconfig "github.com/cilium/cilium/pkg/maps/configmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")

	globalSweeper = newMapSweeper(&realEPManager{})
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	endpointExists(endpointID uint16) bool
	removeDatapathMapping(endpointID uint16) error
	removeMapPath(path string)
}

// realEPManager provides an implementatino of endpointManager that is backed
// by the endpointmanager and policymap packages, and when removeMapPath is
// invoked, it cleans up paths on the actual filesystem.
type realEPManager struct{}

func (gw *realEPManager) endpointExists(endpointID uint16) bool {
	if ep := endpointmanager.LookupCiliumID(endpointID); ep != nil {
		return true
	}
	return false
}

// removeDatapathMapping unlinks the endpointID from the global policy map, preventing
// packets that arrive on this node from being forwarded to the endpoint that
// used to exist with the specified ID.
func (gw *realEPManager) removeDatapathMapping(endpointID uint16) error {
	return policymap.RemoveGlobalMapping(uint32(endpointID))
}

// removeMapPath removes the specified path from the filesystem.
func (gw *realEPManager) removeMapPath(path string) {
	if err := os.RemoveAll(path); err != nil {
		log.WithError(err).WithField(logfields.Path, path).Warn("Error while deleting stale map file")
	} else {
		log.WithField(logfields.Path, path).Info("Removed stale bpf map")
	}
}

// mapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type mapSweeper struct {
	endpointManager
}

// newMapSweeper creates an object that walks map paths and garbage-collects
// them.
func newMapSweeper(g endpointManager) *mapSweeper {
	return &mapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *mapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.endpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.removeMapPath(path)
			}
		} else {
			err2 := ms.removeDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.removeMapPath(path)
		}
	}
}

func (ms *mapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := endpointmanager.HasGlobalCT()

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.removeMapPath(path)
	}
}

func (ms *mapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		loader.CallsMapName,
		bpfconfig.MapNamePrefix,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), globalSweeper.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_snat_v6_external",
			"cilium_proxy6"}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_snat_v4_external",
			"cilium_proxy4"}...)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			globalSweeper.removeMapPath(p)
		}
	}
}
<commit_msg>maps: Remove disabled svc v2 maps<commit_after>// Copyright 2016-2019 Authors of Cilium
//
// 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 maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/datapath/loader"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/endpointmanager"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	bpfconfig "github.com/cilium/cilium/pkg/maps/configmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")

	globalSweeper = newMapSweeper(&realEPManager{})
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	endpointExists(endpointID uint16) bool
	removeDatapathMapping(endpointID uint16) error
	removeMapPath(path string)
}

// realEPManager provides an implementatino of endpointManager that is backed
// by the endpointmanager and policymap packages, and when removeMapPath is
// invoked, it cleans up paths on the actual filesystem.
type realEPManager struct{}

func (gw *realEPManager) endpointExists(endpointID uint16) bool {
	if ep := endpointmanager.LookupCiliumID(endpointID); ep != nil {
		return true
	}
	return false
}

// removeDatapathMapping unlinks the endpointID from the global policy map, preventing
// packets that arrive on this node from being forwarded to the endpoint that
// used to exist with the specified ID.
func (gw *realEPManager) removeDatapathMapping(endpointID uint16) error {
	return policymap.RemoveGlobalMapping(uint32(endpointID))
}

// removeMapPath removes the specified path from the filesystem.
func (gw *realEPManager) removeMapPath(path string) {
	if err := os.RemoveAll(path); err != nil {
		log.WithError(err).WithField(logfields.Path, path).Warn("Error while deleting stale map file")
	} else {
		log.WithField(logfields.Path, path).Info("Removed stale bpf map")
	}
}

// mapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type mapSweeper struct {
	endpointManager
}

// newMapSweeper creates an object that walks map paths and garbage-collects
// them.
func newMapSweeper(g endpointManager) *mapSweeper {
	return &mapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *mapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.endpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.removeMapPath(path)
			}
		} else {
			err2 := ms.removeDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.removeMapPath(path)
		}
	}
}

func (ms *mapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := endpointmanager.HasGlobalCT()

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.removeMapPath(path)
	}
}

func (ms *mapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		loader.CallsMapName,
		bpfconfig.MapNamePrefix,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), globalSweeper.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_lb6_services_v2",
			"cilium_lb6_rr_seq_v2",
			"cilium_lb6_backends",
			"cilium_snat_v6_external",
			"cilium_proxy6"}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_lb4_services_v2",
			"cilium_lb4_rr_seq_v2",
			"cilium_lb4_backends",
			"cilium_snat_v4_external",
			"cilium_proxy4"}...)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			globalSweeper.removeMapPath(p)
		}
	}
}
<|endoftext|>