<commit_before>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/bradfitz/http2"
	"github.com/tylerb/graceful"
	bolt "github.com/xyproto/permissionbolt"
	redis "github.com/xyproto/permissions2"
	mariadb "github.com/xyproto/permissionsql"
	"github.com/xyproto/pinterface"
	"github.com/xyproto/simpleredis"
	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString = "Algernon 0.8"
	description   = "HTTP/2 Web Server"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
)

func newServerConfiguration(mux *http.ServeMux, http2support bool, addr string) *http.Server {
	// Server configuration
	s := &http.Server{
		Addr:    addr,
		Handler: mux,

		// The timeout values is also the maximum time it can take
		// for a complete page of Server-Sent Events (SSE).
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,

		MaxHeaderBytes: 1 << 20,
	}
	if http2support {
		// Enable HTTP/2 support
		http2.ConfigureServer(s, nil)
	}
	return s
}

func main() {
	var (
		err  error
		perm pinterface.IPermissions
	)

	// Use all CPUs. Soon to be the default for Go.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Check if the given directory really is a directory
	if !isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// If Bolt is to be used and no filename is given
	if useBolt && (boltFilename == "") {
		boltFilename = defaultBoltFilename
	}

	// Use one of the databases for the permission middleware,
	// then assign a name to dbName (used for the status output)
	// TODO Refactor into functions
	dbName = ""
	if boltFilename != "" {
		// New permissions middleware, using a Bolt database
		perm, err = bolt.NewWithConf(boltFilename)
		if err != nil {
			log.Errorf("Could not use Bolt as database backend: %s", err)
		} else {
			dbName = "Bolt (" + boltFilename + ")"
		}
	}
	if dbName == "" && mariadbDSN != "" {
		// New permissions middleware, using a MariaDB/MySQL database
		perm, err = mariadb.NewWithDSN(mariadbDSN, mariaDatabase)
		if err != nil {
			log.Errorf("Could not use MariaDB/MySQL as database backend: %s", err)
		} else {
			// The connection string may contain a password, so don't include it in the dbName
			dbName = "MariaDB/MySQL"
		}
	}
	if dbName == "" && mariaDatabase != "" {
		// Given a database, but not a host, connect to localhost
		// New permissions middleware, using a MariaDB/MySQL database
		perm, err = mariadb.NewWithConf("test:@127.0.0.1/" + mariaDatabase)
		if err != nil {
			if mariaDatabase != "" {
				log.Errorf("Could not use MariaDB/MySQL as database backend: %s", err)
			} else {
				log.Warnf("Could not use MariaDB/MySQL as database backend: %s", err)
			}
		} else {
			// The connection string may contain a password, so don't include it in the dbName
			dbName = "MariaDB/MySQL"
		}
	}
	if dbName == "" {
		// New permissions middleware, using a Redis database
		if err := simpleredis.TestConnectionHost(redisAddr); err != nil {
			// Only output an error when a Redis host other than the default host+port was specified
			if redisAddrSpecified {
				if singleFileMode {
					log.Warnf("Could not use Redis as database backend: %s", err)
				} else {
					log.Errorf("Could not use Redis as database backend: %s", err)
				}
			}
		} else {
			perm = redis.NewWithRedisConf(redisDBindex, redisAddr)
			dbName = "Redis"
		}
	}
	if dbName == "" && boltFilename == "" {
		perm, err = bolt.NewWithConf(defaultBoltFilename)
		if err != nil {
			log.Errorf("Could not use Bolt as database backend: %s", err)
		} else {
			dbName = "Bolt (" + defaultBoltFilename + ")"
		}
	}
	if dbName == "" {
		// This may typically happen if Algernon is already running
		log.Fatalln("Could not find a usable database backend.")
	}

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	defer luapool.Shutdown()

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	// Register HTTP handler functions
	registerHandlers(mux, serverDir, perm, luapool, cache)

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// If we are not writing internal logs to a file, reduce the verboseness
	http2.VerboseLogs = (internalLogFilename != os.DevNull)

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()
	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		defer internalLogFile.Close()
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	if !serverMode {
		go REPL(perm, luapool, cache)
	}

	// Timeout when closing down the server
	shutdownTimeout := 30 * time.Second

	// Decide which protocol to listen to
	switch {
	case productionMode:
		// Listen for both HTTPS+HTTP/2 and HTTP requests, on different ports
		go func() {
			log.Info("Serving HTTPS + HTTP/2 on " + serverHost + ":443")
			// Start serving. Shut down gracefully at exit.
			// Listen for HTTPS + HTTP/2 requests
			HTTPS2server := newServerConfiguration(mux, true, serverHost+":443")
			// Start serving. Shut down gracefully at exit.
			if err := graceful.ListenAndServeTLS(HTTPS2server, serverCert, serverKey, shutdownTimeout); err != nil {
				log.Error(err)
			}
		}()
		log.Info("Serving HTTP on " + serverHost + ":80")
		HTTPserver := newServerConfiguration(mux, false, serverHost+":80")
		if err := graceful.ListenAndServe(HTTPserver, shutdownTimeout); err != nil {
			// If we can't serve regular HTTP on port 80, give up
			fatalExit(err)
		}
	case serveJustHTTP2: // It's unusual to serve HTTP/2 withoutHTTPS
		log.Info("Serving HTTP/2 on " + serverAddr)
		// Listen for HTTP/2 requests
		HTTP2server := newServerConfiguration(mux, true, serverAddr)
		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServe(HTTP2server, shutdownTimeout); err != nil {
			fatalExit(err)
		}
	case !(serveJustHTTP2 || serveJustHTTP):
		log.Info("Serving HTTPS + HTTP/2 on " + serverAddr)
		// Listen for HTTPS + HTTP/2 requests
		HTTPS2server := newServerConfiguration(mux, true, serverAddr)
		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServeTLS(HTTPS2server, serverCert, serverKey, shutdownTimeout); err != nil {
			log.Warn("Could not serve HTTPS + HTTP/2 (" + err.Error() + ")")
			log.Info("Use the -h flag to serve HTTP only")
			// If HTTPS failed (perhaps the key + cert are missing), serve
			// plain HTTP instead, by falling through to the next case, below.
		} else {
			// Don't fall through
			break
		}
		// Serve regular HTTP instead
		fallthrough
	default:
		log.Info("Serving HTTP on " + serverAddr)
		HTTPserver := newServerConfiguration(mux, false, serverAddr)

		//if err := HTTPserver.ListenAndServe(); err != nil {

		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServe(HTTPserver, shutdownTimeout); err != nil {
			// If we can't serve regular HTTP, give up
			fatalExit(err)
		}
	}
}
<commit_msg>Better error message<commit_after>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/bradfitz/http2"
	"github.com/tylerb/graceful"
	bolt "github.com/xyproto/permissionbolt"
	redis "github.com/xyproto/permissions2"
	mariadb "github.com/xyproto/permissionsql"
	"github.com/xyproto/pinterface"
	"github.com/xyproto/simpleredis"
	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString = "Algernon 0.8"
	description   = "HTTP/2 Web Server"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
)

func newServerConfiguration(mux *http.ServeMux, http2support bool, addr string) *http.Server {
	// Server configuration
	s := &http.Server{
		Addr:    addr,
		Handler: mux,

		// The timeout values is also the maximum time it can take
		// for a complete page of Server-Sent Events (SSE).
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,

		MaxHeaderBytes: 1 << 20,
	}
	if http2support {
		// Enable HTTP/2 support
		http2.ConfigureServer(s, nil)
	}
	return s
}

func main() {
	var (
		err  error
		perm pinterface.IPermissions
	)

	// Use all CPUs. Soon to be the default for Go.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Check if the given directory really is a directory
	if !isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// If Bolt is to be used and no filename is given
	if useBolt && (boltFilename == "") {
		boltFilename = defaultBoltFilename
	}

	// Use one of the databases for the permission middleware,
	// then assign a name to dbName (used for the status output)
	// TODO Refactor into functions
	dbName = ""
	if boltFilename != "" {
		// New permissions middleware, using a Bolt database
		perm, err = bolt.NewWithConf(boltFilename)
		if err != nil {
			if err.Error() == "timeout" {
				log.Error("The Bolt database timed out. The file is probably already in use.")
			} else {
				log.Errorf("Could not use Bolt as database backend: %s", err)
			}
		} else {
			dbName = "Bolt (" + boltFilename + ")"
		}
	}
	if dbName == "" && mariadbDSN != "" {
		// New permissions middleware, using a MariaDB/MySQL database
		perm, err = mariadb.NewWithDSN(mariadbDSN, mariaDatabase)
		if err != nil {
			log.Errorf("Could not use MariaDB/MySQL as database backend: %s", err)
		} else {
			// The connection string may contain a password, so don't include it in the dbName
			dbName = "MariaDB/MySQL"
		}
	}
	if dbName == "" && mariaDatabase != "" {
		// Given a database, but not a host, connect to localhost
		// New permissions middleware, using a MariaDB/MySQL database
		perm, err = mariadb.NewWithConf("test:@127.0.0.1/" + mariaDatabase)
		if err != nil {
			if mariaDatabase != "" {
				log.Errorf("Could not use MariaDB/MySQL as database backend: %s", err)
			} else {
				log.Warnf("Could not use MariaDB/MySQL as database backend: %s", err)
			}
		} else {
			// The connection string may contain a password, so don't include it in the dbName
			dbName = "MariaDB/MySQL"
		}
	}
	if dbName == "" {
		// New permissions middleware, using a Redis database
		if err := simpleredis.TestConnectionHost(redisAddr); err != nil {
			// Only output an error when a Redis host other than the default host+port was specified
			if redisAddrSpecified {
				if singleFileMode {
					log.Warnf("Could not use Redis as database backend: %s", err)
				} else {
					log.Errorf("Could not use Redis as database backend: %s", err)
				}
			}
		} else {
			perm = redis.NewWithRedisConf(redisDBindex, redisAddr)
			dbName = "Redis"
		}
	}
	if dbName == "" && boltFilename == "" {
		perm, err = bolt.NewWithConf(defaultBoltFilename)
		if err != nil {
			if err.Error() == "timeout" {
				log.Error("The Bolt database timed out. The file is probably already in use.")
			} else {
				log.Errorf("Could not use Bolt as database backend: %s", err)
			}
		} else {
			dbName = "Bolt (" + defaultBoltFilename + ")"
		}
	}
	if dbName == "" {
		// This may typically happen if Algernon is already running
		log.Fatalln("Could not find a usable database backend.")
	}

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	defer luapool.Shutdown()

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	// Register HTTP handler functions
	registerHandlers(mux, serverDir, perm, luapool, cache)

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// If we are not writing internal logs to a file, reduce the verboseness
	http2.VerboseLogs = (internalLogFilename != os.DevNull)

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()
	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		defer internalLogFile.Close()
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	if !serverMode {
		go REPL(perm, luapool, cache)
	}

	// Timeout when closing down the server
	shutdownTimeout := 30 * time.Second

	// Decide which protocol to listen to
	switch {
	case productionMode:
		// Listen for both HTTPS+HTTP/2 and HTTP requests, on different ports
		go func() {
			log.Info("Serving HTTPS + HTTP/2 on " + serverHost + ":443")
			// Start serving. Shut down gracefully at exit.
			// Listen for HTTPS + HTTP/2 requests
			HTTPS2server := newServerConfiguration(mux, true, serverHost+":443")
			// Start serving. Shut down gracefully at exit.
			if err := graceful.ListenAndServeTLS(HTTPS2server, serverCert, serverKey, shutdownTimeout); err != nil {
				log.Error(err)
			}
		}()
		log.Info("Serving HTTP on " + serverHost + ":80")
		HTTPserver := newServerConfiguration(mux, false, serverHost+":80")
		if err := graceful.ListenAndServe(HTTPserver, shutdownTimeout); err != nil {
			// If we can't serve regular HTTP on port 80, give up
			fatalExit(err)
		}
	case serveJustHTTP2: // It's unusual to serve HTTP/2 withoutHTTPS
		log.Info("Serving HTTP/2 on " + serverAddr)
		// Listen for HTTP/2 requests
		HTTP2server := newServerConfiguration(mux, true, serverAddr)
		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServe(HTTP2server, shutdownTimeout); err != nil {
			fatalExit(err)
		}
	case !(serveJustHTTP2 || serveJustHTTP):
		log.Info("Serving HTTPS + HTTP/2 on " + serverAddr)
		// Listen for HTTPS + HTTP/2 requests
		HTTPS2server := newServerConfiguration(mux, true, serverAddr)
		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServeTLS(HTTPS2server, serverCert, serverKey, shutdownTimeout); err != nil {
			log.Warn("Could not serve HTTPS + HTTP/2 (" + err.Error() + ")")
			log.Info("Use the -h flag to serve HTTP only")
			// If HTTPS failed (perhaps the key + cert are missing), serve
			// plain HTTP instead, by falling through to the next case, below.
		} else {
			// Don't fall through
			break
		}
		// Serve regular HTTP instead
		fallthrough
	default:
		log.Info("Serving HTTP on " + serverAddr)
		HTTPserver := newServerConfiguration(mux, false, serverAddr)

		//if err := HTTPserver.ListenAndServe(); err != nil {

		// Start serving. Shut down gracefully at exit.
		if err := graceful.ListenAndServe(HTTPserver, shutdownTimeout); err != nil {
			// If we can't serve regular HTTP, give up
			fatalExit(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"runtime"
	"runtime/debug"

	"github.com/eBay/fabio/admin"
	"github.com/eBay/fabio/config"
	"github.com/eBay/fabio/metrics"
	"github.com/eBay/fabio/proxy"
	"github.com/eBay/fabio/registry"
	"github.com/eBay/fabio/registry/consul"
	"github.com/eBay/fabio/registry/file"
	"github.com/eBay/fabio/registry/static"
	"github.com/eBay/fabio/route"
)

// version contains the version number
//
// It is set by build/release.sh for tagged releases
// so that 'go get' just works.
//
// It is also set by the linker when fabio
// is built via the Makefile or the build/docker.sh
// script to ensure the correct version nubmer
var version = "1.1.2"

func main() {
	var filename string
	var v bool
	flag.StringVar(&filename, "cfg", "", "path to config file")
	flag.BoolVar(&v, "v", false, "show version")
	flag.Parse()

	if v {
		fmt.Println(version)
		return
	}

	cfg, err := config.Load(filename)
	if err != nil {
		log.Fatalf("[FATAL] %s. %s", version, err)
	}

	log.Printf("[INFO] Runtime config\n" + toJSON(cfg))
	log.Printf("[INFO] Version %s starting", version)
	log.Printf("[INFO] Go runtime is %s", runtime.Version())

	initRuntime(cfg)
	initMetrics(cfg)
	initBackend(cfg)
	go watchBackend()
	startAdmin(cfg)
	startListeners(cfg.Listen, cfg.Proxy.ShutdownWait, newProxy(cfg))
	registry.Default.Deregister()
}

func newProxy(cfg *config.Config) *proxy.Proxy {
	if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil {
		log.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy)

	if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil {
		log.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher)

	tr := &http.Transport{
		ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout,
		MaxIdleConnsPerHost:   cfg.Proxy.MaxConn,
		Dial: (&net.Dialer{
			Timeout:   cfg.Proxy.DialTimeout,
			KeepAlive: cfg.Proxy.KeepAliveTimeout,
		}).Dial,
	}

	return proxy.New(tr, cfg.Proxy)
}

func startAdmin(cfg *config.Config) {
	log.Printf("[INFO] Admin server listening on %q", cfg.UI.Addr)
	go func() {
		if err := admin.ListenAndServe(cfg, version); err != nil {
			log.Fatal("[FATAL] ui: ", err)
		}
	}()
}

func initMetrics(cfg *config.Config) {
	if err := metrics.Init(cfg.Metrics); err != nil {
		log.Fatal("[FATAL] ", err)
	}
}

func initRuntime(cfg *config.Config) {
	if os.Getenv("GOGC") == "" {
		log.Print("[INFO] Setting GOGC=", cfg.Runtime.GOGC)
		debug.SetGCPercent(cfg.Runtime.GOGC)
	} else {
		log.Print("[INFO] Using GOGC=", os.Getenv("GOGC"), " from env")
	}

	if os.Getenv("GOMAXPROCS") == "" {
		log.Print("[INFO] Setting GOMAXPROCS=", cfg.Runtime.GOMAXPROCS)
		runtime.GOMAXPROCS(cfg.Runtime.GOMAXPROCS)
	} else {
		log.Print("[INFO] Using GOMAXPROCS=", os.Getenv("GOMAXPROCS"), " from env")
	}
}

func initBackend(cfg *config.Config) {
	var err error

	switch cfg.Registry.Backend {
	case "file":
		registry.Default, err = file.NewBackend(cfg.Registry.File.Path)
	case "static":
		registry.Default, err = static.NewBackend(cfg.Registry.Static.Routes)
	case "consul":
		registry.Default, err = consul.NewBackend(&cfg.Registry.Consul)
	default:
		log.Fatal("[FATAL] Unknown registry backend ", cfg.Registry.Backend)
	}

	if err != nil {
		log.Fatal("[FATAL] Error initializing backend. ", err)
	}
	if err := registry.Default.Register(); err != nil {
		log.Fatal("[FATAL] Error registering backend. ", err)
	}
}

func watchBackend() {
	var (
		last   string
		svccfg string
		mancfg string
	)

	svc := registry.Default.WatchServices()
	man := registry.Default.WatchManual()

	for {
		select {
		case svccfg = <-svc:
		case mancfg = <-man:
		}

		// manual config overrides service config
		// order matters
		next := svccfg + "\n" + mancfg
		if next == last {
			continue
		}

		t, err := route.ParseString(next)
		if err != nil {
			log.Printf("[WARN] %s", err)
			continue
		}
		route.SetTable(t)

		last = next
	}
}

func toJSON(v interface{}) string {
	data, err := json.MarshalIndent(v, "", "    ")
	if err != nil {
		panic("json: " + err.Error())
	}
	return string(data)
}
<commit_msg>Release v1.1.3rc1<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"runtime"
	"runtime/debug"

	"github.com/eBay/fabio/admin"
	"github.com/eBay/fabio/config"
	"github.com/eBay/fabio/metrics"
	"github.com/eBay/fabio/proxy"
	"github.com/eBay/fabio/registry"
	"github.com/eBay/fabio/registry/consul"
	"github.com/eBay/fabio/registry/file"
	"github.com/eBay/fabio/registry/static"
	"github.com/eBay/fabio/route"
)

// version contains the version number
//
// It is set by build/release.sh for tagged releases
// so that 'go get' just works.
//
// It is also set by the linker when fabio
// is built via the Makefile or the build/docker.sh
// script to ensure the correct version nubmer
var version = "1.1.3rc1"

func main() {
	var filename string
	var v bool
	flag.StringVar(&filename, "cfg", "", "path to config file")
	flag.BoolVar(&v, "v", false, "show version")
	flag.Parse()

	if v {
		fmt.Println(version)
		return
	}

	cfg, err := config.Load(filename)
	if err != nil {
		log.Fatalf("[FATAL] %s. %s", version, err)
	}

	log.Printf("[INFO] Runtime config\n" + toJSON(cfg))
	log.Printf("[INFO] Version %s starting", version)
	log.Printf("[INFO] Go runtime is %s", runtime.Version())

	initRuntime(cfg)
	initMetrics(cfg)
	initBackend(cfg)
	go watchBackend()
	startAdmin(cfg)
	startListeners(cfg.Listen, cfg.Proxy.ShutdownWait, newProxy(cfg))
	registry.Default.Deregister()
}

func newProxy(cfg *config.Config) *proxy.Proxy {
	if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil {
		log.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy)

	if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil {
		log.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher)

	tr := &http.Transport{
		ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout,
		MaxIdleConnsPerHost:   cfg.Proxy.MaxConn,
		Dial: (&net.Dialer{
			Timeout:   cfg.Proxy.DialTimeout,
			KeepAlive: cfg.Proxy.KeepAliveTimeout,
		}).Dial,
	}

	return proxy.New(tr, cfg.Proxy)
}

func startAdmin(cfg *config.Config) {
	log.Printf("[INFO] Admin server listening on %q", cfg.UI.Addr)
	go func() {
		if err := admin.ListenAndServe(cfg, version); err != nil {
			log.Fatal("[FATAL] ui: ", err)
		}
	}()
}

func initMetrics(cfg *config.Config) {
	if err := metrics.Init(cfg.Metrics); err != nil {
		log.Fatal("[FATAL] ", err)
	}
}

func initRuntime(cfg *config.Config) {
	if os.Getenv("GOGC") == "" {
		log.Print("[INFO] Setting GOGC=", cfg.Runtime.GOGC)
		debug.SetGCPercent(cfg.Runtime.GOGC)
	} else {
		log.Print("[INFO] Using GOGC=", os.Getenv("GOGC"), " from env")
	}

	if os.Getenv("GOMAXPROCS") == "" {
		log.Print("[INFO] Setting GOMAXPROCS=", cfg.Runtime.GOMAXPROCS)
		runtime.GOMAXPROCS(cfg.Runtime.GOMAXPROCS)
	} else {
		log.Print("[INFO] Using GOMAXPROCS=", os.Getenv("GOMAXPROCS"), " from env")
	}
}

func initBackend(cfg *config.Config) {
	var err error

	switch cfg.Registry.Backend {
	case "file":
		registry.Default, err = file.NewBackend(cfg.Registry.File.Path)
	case "static":
		registry.Default, err = static.NewBackend(cfg.Registry.Static.Routes)
	case "consul":
		registry.Default, err = consul.NewBackend(&cfg.Registry.Consul)
	default:
		log.Fatal("[FATAL] Unknown registry backend ", cfg.Registry.Backend)
	}

	if err != nil {
		log.Fatal("[FATAL] Error initializing backend. ", err)
	}
	if err := registry.Default.Register(); err != nil {
		log.Fatal("[FATAL] Error registering backend. ", err)
	}
}

func watchBackend() {
	var (
		last   string
		svccfg string
		mancfg string
	)

	svc := registry.Default.WatchServices()
	man := registry.Default.WatchManual()

	for {
		select {
		case svccfg = <-svc:
		case mancfg = <-man:
		}

		// manual config overrides service config
		// order matters
		next := svccfg + "\n" + mancfg
		if next == last {
			continue
		}

		t, err := route.ParseString(next)
		if err != nil {
			log.Printf("[WARN] %s", err)
			continue
		}
		route.SetTable(t)

		last = next
	}
}

func toJSON(v interface{}) string {
	data, err := json.MarshalIndent(v, "", "    ")
	if err != nil {
		panic("json: " + err.Error())
	}
	return string(data)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"time"

	"github.com/harlow/nsqd-discovery/dnscfg"
	"github.com/harlow/nsqd-discovery/httpcfg"
)

func main() {
	var (
		ldPort  = flag.Int("lookupd-tcp-port", 4160, "The nsqlookupd tcp port")
		dnsAddr = flag.String("lookupd-dns-address", "", "The DNS address of nsqlookupd")
		cfgAddr = flag.String("config-http-address", "", "The IP address of config endpoint")
	)
	flag.Parse()

	if *cfgAddr == "" {
		log.Fatal("arg -lookupd-cfg-address is required")
	}

	if *dnsAddr == "" {
		log.Fatal("arg -lookupd-dns-address is required")
	}

	cfgURL := "http://" + *cfgAddr + "/config/nsqlookupd_tcp_addresses"

	newIPs, err := dnscfg.Get(dnsAddr, ldPort)
	if err != nil {
		log.Fatalf("type=error msg=%s err=%s", "dns lookup", err)
	}

	if len(newIPs) == 0 {
		log.Printf("type=warn msg=%s addr=%s", "no dns records", *dnsAddr)
	}

	err = httpcfg.Set(cfgURL, newIPs)
	if err != nil {
		log.Printf("type=error msg=%s err=%s", "set config", err)
	}

	ticker := time.Tick(15 * time.Second)
	for {
		select {
		case <-ticker:
			newIPs, err = dnscfg.Get(dnsAddr, ldPort)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "dns lookup", err)
				continue
			}

			if len(newIPs) == 0 {
				log.Printf("type=warn msg=%s addr=%s", "no dns records", *dnsAddr)
				continue
			}

			oldIPs, err := httpcfg.Get(cfgURL)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "get config", err)
				continue
			}

			if eq(newIPs, oldIPs) {
				log.Printf("type=info msg=%s", "config up to date")
				continue
			}

			err = httpcfg.Set(cfgURL, newIPs)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "set config", err)
				continue
			}

			log.Printf("type=info msg=%s ips=%s", "set config", newIPs)
		}
	}
}

// test equality of two slices
func eq(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for _, v := range a {
		if !contains(b, v) {
			return false
		}
	}
	return true
}

// test if slice contains string
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<commit_msg>Extract the config loop<commit_after>package main

import (
	"flag"
	"log"
	"time"

	"github.com/harlow/nsqd-discovery/dnscfg"
	"github.com/harlow/nsqd-discovery/httpcfg"
)

var (
	ldPort  = flag.Int("lookupd-tcp-port", 4160, "The nsqlookupd TCP port")
	dnsAddr = flag.String("lookupd-dns-address", "", "The nsqlookupd DNS entry")
	cfgAddr = flag.String("config-http-address", "", "The config address")
)

func main() {
	flag.Parse()

	if *cfgAddr == "" {
		log.Fatal("arg -lookupd-cfg-address is required")
	}

	if *dnsAddr == "" {
		log.Fatal("arg -lookupd-dns-address is required")
	}

	cfgURL := "http://" + *cfgAddr + "/config/nsqlookupd_tcp_addresses"

	IPs, err := dnscfg.Get(dnsAddr, ldPort)
	if err != nil {
		log.Fatalf("type=error msg=%s err=%s", "dns lookup", err)
	}

	if len(IPs) == 0 {
		log.Printf("type=warn msg=%s addr=%s", "no dns records", *dnsAddr)
	}

	err = httpcfg.Set(cfgURL, IPs)
	if err != nil {
		log.Printf("type=error msg=%s err=%s", "set config", err)
	}

	configLoop(cfgURL)
}

// continue looking at dns entry for changes in config
func configLoop(cfgURL string) {
	ticker := time.Tick(15 * time.Second)

	for {
		select {
		case <-ticker:
			newIPs, err := dnscfg.Get(dnsAddr, ldPort)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "dns lookup", err)
				continue
			}

			if len(newIPs) == 0 {
				log.Printf("type=warn msg=%s addr=%s", "no dns records", *dnsAddr)
				continue
			}

			oldIPs, err := httpcfg.Get(cfgURL)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "get config", err)
				continue
			}

			if eq(newIPs, oldIPs) {
				log.Printf("type=info msg=%s", "config up to date")
				continue
			}

			err = httpcfg.Set(cfgURL, newIPs)
			if err != nil {
				log.Printf("type=error msg=%s err=%s", "set config", err)
				continue
			}

			log.Printf("type=info msg=%s ips=%s", "set config", newIPs)
		}
	}
}

// test equality of two slices
func eq(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for _, v := range a {
		if !contains(b, v) {
			return false
		}
	}
	return true
}

// test if slice contains string
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"./audio"
)

type flushWriter struct {
	f http.Flusher
	w io.Writer
}

func (fw *flushWriter) Write(p []byte) (n int, err error) {
	n, err = fw.w.Write(p)
	if fw.f != nil {
		fw.f.Flush()
	}
	return
}

func parseParameters(r *http.Request) (rv audio.RequestVars, err error) {
	qs := r.URL.Query()
	log.Println("Got request", qs)

	// Handle empty request
	if len(qs) == 0 {
		log.Println("Not enough request params")
		return rv, errors.New("bad request")
	}

	missionId := qs.Get("mission")
	rv.Mission, err = strconv.Atoi(missionId)
	if err != nil {
		log.Println("invalid mission id:", missionId)
		return rv, err
	}

	rv.Channels = strings.Split(qs.Get("channels"), ",")
	// Validate all channel numbers
	for _, a := range rv.Channels {
		if _, err := strconv.Atoi(a); err != nil {
			log.Println("invalid channel:", a)
			return rv, err
		}
	}

	rv.Format = qs.Get("format")

	stStr := qs.Get("start")
	rv.Start, err = strconv.Atoi(stStr)
	if err != nil {
		log.Println("invalid start:", stStr)
		return rv, err
	}

	durStr := qs.Get("duration")
	rv.Duration, err = strconv.Atoi(durStr)
	if err != nil {
		log.Println("invalid duration:", durStr)
		return rv, err
	}

	return rv, nil
}

func streamHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "audio/mpeg")

	/* PARRRAMETERS */
	rv, err := parseParameters(r)
	// Handle bad params
	if err != nil {
		log.Println("Error processing params:", err)
		http.Error(w, http.StatusText(500), 500)
		return
	}
	// All clear
	log.Println("Handling request for ", rv)

	/* DEEBEE */
	slices := audio.GetRequestSlices(rv)

	// Check for no audio
	if len(slices) == 0 {
		log.Println("No data found for request")
		http.Error(w, http.StatusText(404), 404)
		return
	}

	fw := flushWriter{w: w}
	if f, ok := w.(http.Flusher); ok {
		fw.f = f
	}

	audio.DownloadAndStream(slices, rv, &fw)
	log.Println("done")
}

func main() {
	audio.InitDirs()
	http.HandleFunc("/stream", streamHandler)
	ServerPort := "5000" // default port
	if len(os.Getenv("PORT")) > 0 {
		ServerPort = os.Getenv("PORT")
	}
	log.Println("Starting server on " + ServerPort)
	http.ListenAndServe(":"+ServerPort, nil)
}
<commit_msg>fix import<commit_after>package main

import (
	"errors"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/UTD-CRSS/audio.exploreapollo.org/audio"
)

type flushWriter struct {
	f http.Flusher
	w io.Writer
}

func (fw *flushWriter) Write(p []byte) (n int, err error) {
	n, err = fw.w.Write(p)
	if fw.f != nil {
		fw.f.Flush()
	}
	return
}

func parseParameters(r *http.Request) (rv audio.RequestVars, err error) {
	qs := r.URL.Query()
	log.Println("Got request", qs)

	// Handle empty request
	if len(qs) == 0 {
		log.Println("Not enough request params")
		return rv, errors.New("bad request")
	}

	missionId := qs.Get("mission")
	rv.Mission, err = strconv.Atoi(missionId)
	if err != nil {
		log.Println("invalid mission id:", missionId)
		return rv, err
	}

	rv.Channels = strings.Split(qs.Get("channels"), ",")
	// Validate all channel numbers
	for _, a := range rv.Channels {
		if _, err := strconv.Atoi(a); err != nil {
			log.Println("invalid channel:", a)
			return rv, err
		}
	}

	rv.Format = qs.Get("format")

	stStr := qs.Get("start")
	rv.Start, err = strconv.Atoi(stStr)
	if err != nil {
		log.Println("invalid start:", stStr)
		return rv, err
	}

	durStr := qs.Get("duration")
	rv.Duration, err = strconv.Atoi(durStr)
	if err != nil {
		log.Println("invalid duration:", durStr)
		return rv, err
	}

	return rv, nil
}

func streamHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "audio/mpeg")

	/* PARRRAMETERS */
	rv, err := parseParameters(r)
	// Handle bad params
	if err != nil {
		log.Println("Error processing params:", err)
		http.Error(w, http.StatusText(500), 500)
		return
	}
	// All clear
	log.Println("Handling request for ", rv)

	/* DEEBEE */
	slices := audio.GetRequestSlices(rv)

	// Check for no audio
	if len(slices) == 0 {
		log.Println("No data found for request")
		http.Error(w, http.StatusText(404), 404)
		return
	}

	fw := flushWriter{w: w}
	if f, ok := w.(http.Flusher); ok {
		fw.f = f
	}

	audio.DownloadAndStream(slices, rv, &fw)
	log.Println("done")
}

func main() {
	audio.InitDirs()
	http.HandleFunc("/stream", streamHandler)
	ServerPort := "5000" // default port
	if len(os.Getenv("PORT")) > 0 {
		ServerPort = os.Getenv("PORT")
	}
	log.Println("Starting server on " + ServerPort)
	http.ListenAndServe(":"+ServerPort, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"strings"
)

const defaultConfigPath = "lanky.json"

func main() {
	var configPath string

	flag.StringVar(&configPath, "config", "lanky.json", "path to lanky configuration file (default "+defaultConfigPath+")")
	flag.Parse()

	r, err := os.Open(configPath)
	if err != nil {
		log.Fatalf("Unable to open config file %v: %v", configPath, err)
	}

	config := &Config{}
	err = LoadConfig(r, config)
	if err != nil {
		log.Fatalf("Error reading config file %v: %v", configPath, err)
	}

	serve(config)
}

type ByteWriter struct {
	http.ResponseWriter
	Wrote  int
	Status int
}

func (bw *ByteWriter) Write(b []byte) (int, error) {
	i, err := bw.ResponseWriter.Write(b)
	bw.Wrote += i
	return i, err
}

func (bw *ByteWriter) WriteHeader(code int) {
	bw.Status = code
	bw.ResponseWriter.WriteHeader(code)
}

type LoggingHandler struct {
	http.Handler
}

func (lh *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// AFAICT WriteHeader is only called when not 200 OK.
	bw := &ByteWriter{w, 0, 200}

	lh.Handler.ServeHTTP(bw, r)

	ip := strings.Split(r.RemoteAddr, ":")[0]
	log.Printf("%v %v - \"%v %v %v\" %v %v", ip, r.Header.Get("User-Agent"), r.Method, r.URL.Path, r.Proto, bw.Status, bw.Wrote)
}

func serve(config *Config) {
	// GitHub Post-Receive requests
	http.HandleFunc("/_github", func(w http.ResponseWriter, r *http.Request) {
		githubHandler(w, r, config)
	})

	// Hubot API
	http.HandleFunc("/_hubot", func(w http.ResponseWriter, r *http.Request) {
		hubotHandler(w, r, config)
	})

	// Jenkins callback
	http.HandleFunc("/_builder", func(w http.ResponseWriter, r *http.Request) {
		builderHandler(w, r, config)
	})

	// landing page
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := rootHandler(w, r, config)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	})

	log.Printf("Starting server listening at %v.", config.Address)
	log.Fatal(http.ListenAndServe(config.Address, &LoggingHandler{http.DefaultServeMux}))
}
<commit_msg>Make Serve function an exported function.<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"strings"
)

const defaultConfigPath = "lanky.json"

func main() {
	var configPath string

	flag.StringVar(&configPath, "config", "lanky.json", "path to lanky configuration file (default "+defaultConfigPath+")")
	flag.Parse()

	r, err := os.Open(configPath)
	if err != nil {
		log.Fatalf("Unable to open config file %v: %v", configPath, err)
	}

	config := &Config{}
	err = LoadConfig(r, config)
	if err != nil {
		log.Fatalf("Error reading config file %v: %v", configPath, err)
	}

	Serve(config)
}

type ByteWriter struct {
	http.ResponseWriter
	Wrote  int
	Status int
}

func (bw *ByteWriter) Write(b []byte) (int, error) {
	i, err := bw.ResponseWriter.Write(b)
	bw.Wrote += i
	return i, err
}

func (bw *ByteWriter) WriteHeader(code int) {
	bw.Status = code
	bw.ResponseWriter.WriteHeader(code)
}

type LoggingHandler struct {
	http.Handler
}

func (lh *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// AFAICT WriteHeader is only called when not 200 OK.
	bw := &ByteWriter{w, 0, 200}

	lh.Handler.ServeHTTP(bw, r)

	ip := strings.Split(r.RemoteAddr, ":")[0]
	log.Printf("%v %v - \"%v %v %v\" %v %v", ip, r.Header.Get("User-Agent"), r.Method, r.URL.Path, r.Proto, bw.Status, bw.Wrote)
}

func Serve(config *Config) {
	// GitHub Post-Receive requests
	http.HandleFunc("/_github", func(w http.ResponseWriter, r *http.Request) {
		githubHandler(w, r, config)
	})

	// Hubot API
	http.HandleFunc("/_hubot", func(w http.ResponseWriter, r *http.Request) {
		hubotHandler(w, r, config)
	})

	// Jenkins callback
	http.HandleFunc("/_builder", func(w http.ResponseWriter, r *http.Request) {
		builderHandler(w, r, config)
	})

	// landing page
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := rootHandler(w, r, config)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	})

	log.Printf("Starting server listening at %v.", config.Address)
	log.Fatal(http.ListenAndServe(config.Address, &LoggingHandler{http.DefaultServeMux}))
}
<|endoftext|>


<commit_before>// main
package main

import (
	"flag"
	"fmt"
	"github.com/golang/glog"
	"os"
	"runtime"
	"sync"
)

const (
	LFATAL = iota
	LERROR
	LWARNING
	LINFO
	LDEBUG
)

const (
	Version = "2.1-rc1"
)

var (
	listenAddr, forwardAddr strSlice
	pv                      bool // print version

	listenArgs  []Args
	forwardArgs []Args
)

func init() {
	flag.Var(&listenAddr, "L", "listen address, can listen on multiple ports")
	flag.Var(&forwardAddr, "F", "forward address, can make a forward chain")
	flag.BoolVar(&pv, "V", false, "print version")
	flag.Parse()
}

func main() {
	defer glog.Flush()

	if flag.NFlag() == 0 {
		flag.PrintDefaults()
		return
	}
	if pv {
		fmt.Fprintf(os.Stderr, "gost %s (%s)\n", Version, runtime.Version())
		return
	}

	listenArgs = parseArgs(listenAddr)
	forwardArgs = parseArgs(forwardAddr)

	if len(listenArgs) == 0 {
		glog.Exitln("no listen addr")
	}

	var wg sync.WaitGroup
	for _, args := range listenArgs {
		wg.Add(1)
		go func(arg Args) {
			defer wg.Done()
			glog.V(LERROR).Infoln(listenAndServe(arg))
		}(args)
	}
	wg.Wait()
}
<commit_msg>2.1 release<commit_after>// main
package main

import (
	"flag"
	"fmt"
	"github.com/golang/glog"
	"os"
	"runtime"
	"sync"
)

const (
	LFATAL = iota
	LERROR
	LWARNING
	LINFO
	LDEBUG
)

const (
	Version = "2.1"
)

var (
	listenAddr, forwardAddr strSlice
	pv                      bool // print version

	listenArgs  []Args
	forwardArgs []Args
)

func init() {
	flag.Var(&listenAddr, "L", "listen address, can listen on multiple ports")
	flag.Var(&forwardAddr, "F", "forward address, can make a forward chain")
	flag.BoolVar(&pv, "V", false, "print version")
	flag.Parse()
}

func main() {
	defer glog.Flush()

	if flag.NFlag() == 0 {
		flag.PrintDefaults()
		return
	}
	if pv {
		fmt.Fprintf(os.Stderr, "gost %s (%s)\n", Version, runtime.Version())
		return
	}

	listenArgs = parseArgs(listenAddr)
	forwardArgs = parseArgs(forwardAddr)

	if len(listenArgs) == 0 {
		glog.Exitln("no listen addr")
	}

	var wg sync.WaitGroup
	for _, args := range listenArgs {
		wg.Add(1)
		go func(arg Args) {
			defer wg.Done()
			glog.V(LERROR).Infoln(listenAndServe(arg))
		}(args)
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

var (
	db *db.SQL
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func setup() {
	var err error
	db, err = sql.Open("mysql", DATABASE)
	if err != nil {
		log.Fatal(err.Error())
	}

}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	id := uniuri.NewLen(LENGTH)

	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			generateName()
		}
	}
	db.Close()

	return id

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)
	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			check(err)
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format("2006-01-02 15:04:05")
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format("2006-01-02 15:04:05")
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format("2006-01-02 15:04:05")
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format("2006-01-02 15:04:05")
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format("2006-01-02 15:04:05")
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format("2006-01-02 15:04:05")
		break

	case "forever":
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	default:
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	var title, s string
	var expiry string
	err := db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	setup()
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Fix incorrect db<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

var (
	db *sql.DB
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func setup() {
	var err error
	db, err = sql.Open("mysql", DATABASE)
	if err != nil {
		log.Fatal(err.Error())
	}

}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	id := uniuri.NewLen(LENGTH)

	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			generateName()
		}
	}
	db.Close()

	return id

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)
	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			check(err)
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format("2006-01-02 15:04:05")
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format("2006-01-02 15:04:05")
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format("2006-01-02 15:04:05")
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format("2006-01-02 15:04:05")
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format("2006-01-02 15:04:05")
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format("2006-01-02 15:04:05")
		break

	case "forever":
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	default:
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	var title, s string
	var expiry string
	err := db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	setup()
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// +build windows

package main

import (
	"flag"
	"io/ioutil"
	"log"
)

var start string
var read string
var stop string
var clear bool
var verbose bool
var list bool
var command string

func init() {
	flag.StringVar(&start, "start", "REQUIRED", "start timer")
	flag.StringVar(&read, "read", "REQUIRED", "read timer (elapsed time)")
	flag.StringVar(&stop, "stop", "REQUIRED", "stop timer and print elapsed time")
	flag.StringVar(&command, "C", "REQUIRED", "print elapsed time for command")
	flag.BoolVar(&clear, "clear", false, "clear all timers")
	flag.BoolVar(&verbose, "verbose", false, "verbose output")
	flag.BoolVar(&list, "list", false, "list timers")
}

func main() {
	registry = realRegistry{}

	// configure logging
	log.SetFlags(0)

	// parse command line arguments
	flag.Parse()

	if flag.NFlag() == 0 {
		flag.Usage()
	}

	if !verbose {
		log.SetOutput(ioutil.Discard)
	}

	if clear {
		clearAllTimers()
	}

	if start != "REQUIRED" {
		startTimer(start)
	}

	if read != "REQUIRED" {
		readTimer(read)
	}

	if stop != "REQUIRED" {
		readTimer(stop)
		clearTimer(stop)
	}

	if list {
		listTimers()
	}

	// http://bit.ly/1dMD2YN
	if command != "REQUIRED" {
		process("cmd", "/c", command)
	}
}
<commit_msg>add -version<commit_after>// +build windows

package main

import (
	"flag"
	"io/ioutil"
	"log"
	"fmt"
)

var start string
var read string
var stop string
var clear bool
var verbose bool
var list bool
var version bool
var command string

func init() {
	flag.StringVar(&start, "start", "REQUIRED", "start timer")
	flag.StringVar(&read, "read", "REQUIRED", "read timer (elapsed time)")
	flag.StringVar(&stop, "stop", "REQUIRED", "stop timer and print elapsed time")
	flag.StringVar(&command, "C", "REQUIRED", "print elapsed time for command")
	flag.BoolVar(&clear, "clear", false, "clear all timers")
	flag.BoolVar(&verbose, "verbose", false, "verbose output")
	flag.BoolVar(&version, "version", false, "print version")
	flag.BoolVar(&list, "list", false, "list timers")
}

func main() {
	registry = realRegistry{}

	// configure logging
	log.SetFlags(0)

	// parse command line arguments
	flag.Parse()

	if flag.NFlag() == 0 {
		flag.Usage()
	}

	if version {
		fmt.Println("timer v1.1.0")
		return
	}

	if !verbose {
		log.SetOutput(ioutil.Discard)
	}

	if clear {
		clearAllTimers()
	}

	if start != "REQUIRED" {
		startTimer(start)
	}

	if read != "REQUIRED" {
		readTimer(read)
	}

	if stop != "REQUIRED" {
		readTimer(stop)
		clearTimer(stop)
	}

	if list {
		listTimers()
	}

	// http://bit.ly/1dMD2YN
	if command != "REQUIRED" {
		process("cmd", "/c", command)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"sync"

	"github.com/yosisa/fluxion/buffer"
	"github.com/yosisa/fluxion/message"
	"github.com/yosisa/fluxion/plugin"
)

type Config struct {
	Listen string
}

type NetbufOutput struct {
	env    *plugin.Env
	conf   *Config
	ln     net.Listener
	bufs   map[string][]string
	lock   sync.Mutex
	locks  map[string]sync.Mutex
	closed bool
}

func (p *NetbufOutput) Init(env *plugin.Env) (err error) {
	p.env = env
	p.conf = &Config{}
	p.bufs = make(map[string][]string)
	p.locks = make(map[string]sync.Mutex)
	return env.ReadConfig(p.conf)
}

func (p *NetbufOutput) Start() (err error) {
	if p.ln, err = net.Listen("tcp", p.conf.Listen); err != nil {
		return
	}
	go p.accepter()
	return
}

func (p *NetbufOutput) Encode(ev *message.Event) (buffer.Sizer, error) {
	t := ev.Time.Format("2006/01/02 15:04:05 MST")
	s := buffer.StringItem(fmt.Sprintf("%s %s %s", t, ev.Tag, ev.Record["message"]))
	return s, nil
}

func (p *NetbufOutput) Write(l []buffer.Sizer) (int, error) {
	for name, lock := range p.locks {
		lock.Lock()
		for _, s := range l {
			p.bufs[name] = append(p.bufs[name], string(s.(buffer.StringItem)))
		}
		lock.Unlock()
	}
	return len(l), nil
}

func (p *NetbufOutput) Close() error {
	p.closed = true
	return p.ln.Close()
}

func (p *NetbufOutput) accepter() {
	for !p.closed {
		conn, err := p.ln.Accept()
		if err != nil {
			continue
		}
		go p.handler(conn)
	}
}

func (p *NetbufOutput) handler(conn net.Conn) {
	defer conn.Close()
	remote, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
	p.env.Log.Infof("Connected from %s", remote)
	lock, ok := p.locks[remote]
	if !ok {
		p.env.Log.Infof("No buffer found for %s, create now", remote)
		p.addBuffer(remote)
		return
	}

	lock.Lock()
	defer lock.Unlock()

	buf := p.bufs[remote]
	p.env.Log.Infof("Send %d line to %s", len(buf), remote)
	for i, s := range buf {
		if _, err := conn.Write([]byte(s + "\n")); err != nil {
			p.env.Log.Warning(err)
			p.bufs[remote] = buf[i:]
			return
		}
	}
	p.bufs[remote] = buf[:0]
}

func (p *NetbufOutput) addBuffer(name string) {
	p.lock.Lock()
	defer p.lock.Unlock()
	if _, ok := p.bufs[name]; ok {
		return
	}
	p.bufs[name] = nil
	p.locks[name] = sync.Mutex{}
}

func main() {
	plugin.New("out-netbuf", func() plugin.Plugin {
		return &NetbufOutput{}
	}).Run()
}
<commit_msg>Add Buffer struct<commit_after>package main

import (
	"fmt"
	"net"
	"sync"

	"github.com/yosisa/fluxion/buffer"
	"github.com/yosisa/fluxion/message"
	"github.com/yosisa/fluxion/plugin"
)

type Buffer struct {
	sync.Mutex
	Items []string
}

type Config struct {
	Listen string
}

type NetbufOutput struct {
	env    *plugin.Env
	conf   *Config
	ln     net.Listener
	bufs   map[string]*Buffer
	lock   sync.Mutex
	closed bool
}

func (p *NetbufOutput) Init(env *plugin.Env) (err error) {
	p.env = env
	p.conf = &Config{}
	p.bufs = make(map[string]*Buffer)
	return env.ReadConfig(p.conf)
}

func (p *NetbufOutput) Start() (err error) {
	if p.ln, err = net.Listen("tcp", p.conf.Listen); err != nil {
		return
	}
	go p.accepter()
	return
}

func (p *NetbufOutput) Encode(ev *message.Event) (buffer.Sizer, error) {
	t := ev.Time.Format("2006/01/02 15:04:05 MST")
	s := buffer.StringItem(fmt.Sprintf("%s %s %s", t, ev.Tag, ev.Record["message"]))
	return s, nil
}

func (p *NetbufOutput) Write(l []buffer.Sizer) (int, error) {
	for _, buf := range p.bufs {
		buf.Lock()
		for _, s := range l {
			buf.Items = append(buf.Items, string(s.(buffer.StringItem)))
		}
		buf.Unlock()
	}
	return len(l), nil
}

func (p *NetbufOutput) Close() error {
	p.closed = true
	return p.ln.Close()
}

func (p *NetbufOutput) accepter() {
	for !p.closed {
		conn, err := p.ln.Accept()
		if err != nil {
			continue
		}
		go p.handler(conn)
	}
}

func (p *NetbufOutput) handler(conn net.Conn) {
	defer conn.Close()
	remote, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
	p.env.Log.Infof("Connected from %s", remote)
	buf, ok := p.bufs[remote]
	if !ok {
		p.env.Log.Infof("No buffer found for %s, create now", remote)
		p.addBuffer(remote)
		return
	}

	buf.Lock()
	defer buf.Unlock()

	p.env.Log.Infof("Send %d line to %s", len(buf.Items), remote)
	for i, s := range buf.Items {
		if _, err := conn.Write([]byte(s + "\n")); err != nil {
			p.env.Log.Warning(err)
			buf.Items = buf.Items[i:]
			return
		}
	}
	buf.Items = buf.Items[:0]
}

func (p *NetbufOutput) addBuffer(name string) {
	p.lock.Lock()
	defer p.lock.Unlock()
	if _, ok := p.bufs[name]; ok {
		return
	}
	p.bufs[name] = &Buffer{}
}

func main() {
	plugin.New("out-netbuf", func() plugin.Plugin {
		return &NetbufOutput{}
	}).Run()
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/vishh/caggregator/sources"
	"github.com/golang/glog"
)

func main() {
	glog.Info("cAggregator is running")
	cadvisorSource, err := sources.NewCadvisorSource()
	if err != nil {
		glog.Error(err)
		os.Exit(1)
	}
	err := cadvisorSource.FetchData()
	if err != nil {
		glog.Error(err)
		os.Exit(1)
	}
	os.Exit(0)
}
<commit_msg>Parse the flags Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)<commit_after>package main

import (
	"flag"
	"os"

	"github.com/vishh/caggregator/sources"
	"github.com/golang/glog"
)

func main() {
	glog.Info("cAggregator is running")
	flag.Parse()
	cadvisorSource, err := sources.NewCadvisorSource()
	if err != nil {
		glog.Error(err)
		os.Exit(1)
	}
	err = cadvisorSource.FetchData()
	if err != nil {
		glog.Error(err)
		os.Exit(1)
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/ararog/petshop/resources"
  "github.com/ararog/petshop/models"
  "github.com/ararog/petshop/services"
  "github.com/appleboy/gin-jwt"
  "github.com/gin-gonic/gin"
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/sqlite"
  "time"
)

func main() {

  db, err := gorm.Open("sqlite3", "test.db")
  if err != nil {
    panic("failed to connect database")
  }

  db.AutoMigrate(&models.User{})
  db.Create(&models.User{Name: "Rogerio Araujo", Email: "rogerio.araujo@gmail.com", Password: ""})

  userResource := &resources.UserResource{DB: db}

  authMiddleware := &jwt.GinJWTMiddleware{
    Realm: "test zone",
    Key: []byte("petshop42016"),
    Timeout: time.Hour,
    MaxRefresh: time.Hour * 24,
    Authenticator: func(userId string, password string, c *gin.Context) (string, bool) {
      err, _ := services.Login(db, userId, password)
      if err == nil {
        return userId, true
      }

      return userId, false
    },
    Authorizator: func(userId string, c *gin.Context) bool {
      err, user := services.GetUserByEmail(db, userId)
      if err == nil {
        c.Set("user", user)
        return true
      }

      return false
    },
  }

  router := gin.Default()
  router.Use(gin.Logger())
  v1 := router.Group("/v1")
  v1.POST("/auth/login", authMiddleware.LoginHandler)

  users := v1.Group("/users")
  users.Use(authMiddleware.MiddlewareFunc())
  {
      users.GET("/me", userResource.User)
  }

  router.Run(":8080")
}
<commit_msg>Removing file<commit_after><|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

const (
	horizontal         int = iota // 0
	horizontalReversed            // 1
	vertical                      // 2
	verticalReversed              // 3
	endDirection
	// diagonalLTR
	// diagonalLTRReversed
	// diagonalRTL
	// diagonalRTLReversed
)

const (
	letterBytes     = "abcdefghijklmnopqrstuvwxyz"
	fitWordAttempts = 500
	boardAttempts   = 1000
)

type gameBoard [][]string

func readWordList(path string) (lines []string, err error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, strings.ToLower(scanner.Text()))
	}
	return lines, scanner.Err()
}

func makeBoard(x int, y int) (board gameBoard) {
	board = make(gameBoard, y)
	for i := range board {
		board[i] = make([]string, x)
	}
	return
}

func reverse(s string) string {
	chars := []rune(s)
	for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
		chars[i], chars[j] = chars[j], chars[i]
	}
	return string(chars)
}

func fitHorizontal(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = rand.Intn(y)
		found = iy+len(word) < y
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if c == " " {

		}
		if (*board)[ix][iy+j] == "" {
			(*board)[ix][iy+j] = c
		} else {
			return false
		}
	}
	return true
}

func fitHorizontalReversed(board *gameBoard, word string) bool {
	return fitHorizontal(board, reverse(word))
}

func fitVertical(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = rand.Intn(y)
		found = ix+len(word) < x
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if (*board)[ix+j][iy] == "" {
			(*board)[ix+j][iy] = c
		} else {
			return false
		}
	}
	return true
}

func fitVerticalReversed(board *gameBoard, word string) bool {
	return fitVertical(board, reverse(word))
}

func fitWord(board *gameBoard, word string) bool {
	wordDirection := rand.Intn(endDirection)
	w := strings.Replace(word, " ", "", -1)
	switch wordDirection {
	case horizontal:
		return fitHorizontal(board, w)
	case horizontalReversed:
		return fitHorizontalReversed(board, w)
	case vertical:
		return fitVertical(board, w)
	case verticalReversed:
		return fitVerticalReversed(board, w)
	}
	return false
}

func buildBoard(board *gameBoard, words []string) bool {
	for _, word := range words {
		if !fitWord(board, word) {
			return false
		}
	}
	return true
}

func getRandomLetter() string {
	return string(letterBytes[rand.Intn(len(letterBytes))])
	// return "$"
}

func fillBoard(board *gameBoard) {
	for i := range *board {
		for j := range (*board)[i] {
			if (*board)[i][j] == "" {
				(*board)[i][j] = getRandomLetter()
			}
		}
	}
}

func printBoard(board *gameBoard) {
	for i := range *board {
		for j := range (*board)[i] {
			c := (*board)[i][j]
			if c == "" {
				c = " "
			}
			fmt.Print(c)
		}
		fmt.Print("\n")
	}
}

func htmlBoard(board *gameBoard, words []string, output string) {
	f, err := os.Create(output)
	if err != nil {
		fmt.Println("Error:", err.Error())
		return
	}
	defer f.Close()
	fmt.Fprintln(f, `<div style="float:left">`)
	fmt.Fprintln(f, `<table style="font-family:'Lucida Console', monospace">`)
	for i := range *board {
		fmt.Fprintln(f, `<tr style="padding: 0; margin: 0">`)
		for j := range (*board)[i] {
			c := (*board)[i][j]
			fmt.Fprintf(f, `<td style="padding: 0; margin: 0; height: 20px; width: 20px">%s</td>`, c)
		}
		fmt.Fprintln(f, "
")
	}
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, `<div style="float:left">`)
	fmt.Fprintln(f, `<ul style="list-style: none;">`)
	for _, word := range words {
		fmt.Fprintf(f, "
%s
\n", word)
	}
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, "
")
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	wordList, err := readWordList("wordlist.txt")
	if err != nil {
		fmt.Println("Error:", err.Error())
		return
	}
	fmt.Println(wordList)
	for i := 0; i < boardAttempts; i++ {
		board := makeBoard(25, 25)
		built := buildBoard(&board, wordList)
		if built {
			fillBoard(&board)
			printBoard(&board)
			htmlBoard(&board, wordList, "output.html")
			fmt.Println("output.html saved")
			return
		}
	}
	fmt.Println("Error: couldn't fit words")
}
<commit_msg>add diagonal support<commit_after>package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

const (
	horizontal int = iota
	horizontalReversed
	vertical
	verticalReversed
	diagonalLTR
	diagonalLTRReversed
	diagonalRTL
	diagonalRTLReversed
)

const (
	letterBytes     = "abcdefghijklmnopqrstuvwxyz"
	fitWordAttempts = 500
	boardAttempts   = 1000
)

type gameBoard [][]string

func readWordList(path string) (lines []string, err error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, strings.ToLower(scanner.Text()))
	}
	return lines, scanner.Err()
}

func makeBoard(x int, y int) (board gameBoard) {
	board = make(gameBoard, y)
	for i := range board {
		board[i] = make([]string, x)
	}
	return
}

func reverse(s string) string {
	chars := []rune(s)
	for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
		chars[i], chars[j] = chars[j], chars[i]
	}
	return string(chars)
}

func fitHorizontal(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = rand.Intn(y)
		found = iy+len(word) < y
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if (*board)[ix][iy+j] == "" {
			(*board)[ix][iy+j] = c
		} else {
			return false
		}
	}
	return true
}

func fitHorizontalReversed(board *gameBoard, word string) bool {
	return fitHorizontal(board, reverse(word))
}

func fitVertical(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = rand.Intn(y)
		found = ix+len(word) < x
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if (*board)[ix+j][iy] == "" {
			(*board)[ix+j][iy] = c
		} else {
			return false
		}
	}
	return true
}

func fitVerticalReversed(board *gameBoard, word string) bool {
	return fitVertical(board, reverse(word))
}

func fitDiagonalLTR(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = rand.Intn(y)
		found = ix+len(word) < x && iy+len(word) < y
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if (*board)[ix+j][iy+j] == "" {
			(*board)[ix+j][iy+j] = c
		} else {
			return false
		}
	}
	return true
}

func fitDiagonalLTRReversed(board *gameBoard, word string) bool {
	return fitDiagonalLTR(board, reverse(word))
}

func fitDiagonalRTL(board *gameBoard, word string) bool {
	x := len(*board)
	y := len((*board)[0])
	var ix, iy int
	found := false
	attempts := 0
	for !found {
		ix = rand.Intn(x)
		iy = len(word) + rand.Intn(y-len(word))
		found = ix+len(word) < x && iy-len(word) >= 0
		attempts++
		if attempts > fitWordAttempts {
			return false
		}
	}

	for j, c := range strings.Split(word, "") {
		if (*board)[ix+j][iy-j] == "" {
			(*board)[ix+j][iy-j] = c
		} else {
			return false
		}
	}
	return true
}

func fitDiagonalRTLReversed(board *gameBoard, word string) bool {
	return fitDiagonalRTL(board, reverse(word))
}

func fitWord(board *gameBoard, word string) bool {
	wordDirection := rand.Intn(diagonalRTLReversed + 1)
	w := strings.Replace(word, " ", "", -1)
	switch wordDirection {
	case horizontal:
		return fitHorizontal(board, w)
	case horizontalReversed:
		return fitHorizontalReversed(board, w)
	case vertical:
		return fitVertical(board, w)
	case verticalReversed:
		return fitVerticalReversed(board, w)
	case diagonalLTR:
		return fitDiagonalLTR(board, w)
	case diagonalLTRReversed:
		return fitDiagonalLTRReversed(board, w)
	case diagonalRTL:
		return fitDiagonalRTL(board, w)
	case diagonalRTLReversed:
		return fitDiagonalRTLReversed(board, w)
	}
	return false
}

func buildBoard(board *gameBoard, words []string) bool {
	for _, word := range words {
		if !fitWord(board, word) {
			return false
		}
	}
	return true
}

func getRandomLetter() string {
	return string(letterBytes[rand.Intn(len(letterBytes))])
	// return "."
}

func fillBoard(board *gameBoard) {
	for i := range *board {
		for j := range (*board)[i] {
			if (*board)[i][j] == "" {
				(*board)[i][j] = getRandomLetter()
			}
		}
	}
}

func printBoard(board *gameBoard) {
	for i := range *board {
		for j := range (*board)[i] {
			c := (*board)[i][j]
			if c == "" {
				c = " "
			}
			fmt.Print(c)
		}
		fmt.Print("\n")
	}
}

func htmlBoard(board *gameBoard, words []string, output string) {
	f, err := os.Create(output)
	if err != nil {
		fmt.Println("Error:", err.Error())
		return
	}
	defer f.Close()
	fmt.Fprintln(f, `<div style="float:left">`)
	fmt.Fprintln(f, `<table style="font-family:'Lucida Console', monospace">`)
	for i := range *board {
		fmt.Fprintln(f, `<tr style="padding: 0; margin: 0">`)
		for j := range (*board)[i] {
			c := (*board)[i][j]
			fmt.Fprintf(f, `<td style="padding: 0; margin: 0; height: 20px; width: 20px">%s</td>`, c)
		}
		fmt.Fprintln(f, "
")
	}
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, `<div style="float:left">`)
	fmt.Fprintln(f, `<ul style="list-style: none;">`)
	for _, word := range words {
		fmt.Fprintf(f, "
%s
\n", word)
	}
	fmt.Fprintln(f, "
")
	fmt.Fprintln(f, "
")
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	wordList, err := readWordList("wordlist.txt")
	if err != nil {
		fmt.Println("Error:", err.Error())
		return
	}
	fmt.Println(wordList)
	for i := 0; i < boardAttempts; i++ {
		board := makeBoard(30, 30)
		built := buildBoard(&board, wordList)
		if built {
			fillBoard(&board)
			printBoard(&board)
			htmlBoard(&board, wordList, "output.html")
			fmt.Println("output.html saved")
			return
		}
	}
	fmt.Println("Error: couldn't fit words")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
	"html/template"
	"log"
	"net/http"
	"strings"
)

const (
	// Route names
	Index        = "/"
	Login        = "/login"
	SetAuthCode  = "/uber/setauthcode"
	ReceiptReady = "/uber/webooks/requests.receipt_ready"
	UberWebhook  = "/uber/webhook"
	MondoWebhook = "/mondo/webhook"
)

type session struct {
	sessionId        string
	mondoAccessToken string
	mondoAccountId   string
	mondoWebhookId   string
	uberAccessToken  string
}

var certFile = flag.String("certFile", "cert.pem", "SSL certificate")
var keyFile = flag.String("keyFile", "key.pem", "SSL certificate")
var addr = flag.String("addr", ":443", "https list addr")
var thisUrl = flag.String("url", "", "public url e.g. https://foo (required)")
var uberClientId = flag.String("uberClientId", "", "Uber client_id (required)")
var uberClientSecret = flag.String("uberClientSecret", "", "Uber client_secret (required)")
var uberApiHost = flag.String("uberApi", "https://api.uber.com/v1", "Uber API URL")
var mondoApiUrl = flag.String("mondoApi", "https://api.getmondo.co.uk", "Mondo API URL")

var indexTemplate = template.Must(template.ParseFiles("index.html"))
var loginSuccessTemplate = template.Must(template.ParseFiles("loginsuccess.html"))

var sessions = make(map[string]*session)
var router = mux.NewRouter()
var uberApiClient *UberApiClient
var mondoApiClient *MondoApiClient

func indexGet(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	indexTemplate.Execute(w, r.Host)
}

func loginPost(w http.ResponseWriter, r *http.Request) {
	mondoAccessToken := r.FormValue("mondo-access-token")
	mondoAccountId := r.FormValue("mondo-account-id")

	if mondoAccessToken == "" || mondoAccountId == "" {
		http.Error(w, "required: mondo-access-token, mondo-account-id", http.StatusBadRequest)
		log.Printf("%s required: mondo-access-token, mondo-account-id", Login)
		return
	}

	// Register session
	uuid, err := uuid.NewV4()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s generate session id error: %s", Login, err.Error())
		return
	}

	sessionId := uuid.String()
	session := &session{
		sessionId:        sessionId,
		mondoAccessToken: mondoAccessToken,
		mondoAccountId:   mondoAccountId}

	sessions[sessionId] = session

	// Send oauth/authorize request to uber with our redirect URL
	redirectUrlPath, err := router.Get(SetAuthCode).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", Login, err.Error())
		return
	}

	redirectUrl := fmt.Sprintf("%s%s", *thisUrl, redirectUrlPath)

	err = uberApiClient.OAuthAuthorize(sessionId, redirectUrl)

	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		log.Printf("%s uber authorize error: %s", Login, err.Error())
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	loginSuccessTemplate.Execute(w, r.Host)
}

func uberSetAuthCodeGet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	sessionId := vars["sessionId"]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	uberAuthorizationCode := r.URL.Query()["uberAuthorizationCode"]
	uberTokenResponse, err := uberApiClient.GetOAuthToken(uberAuthorizationCode[0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s uber oauth token error: %s", SetAuthCode, err.Error())
		return
	}

	session.uberAccessToken = uberTokenResponse.AccessToken
	log.Printf("%s assigned session id=% Uber access_token=%s\n", SetAuthCode, sessionId, uberTokenResponse.AccessToken)

	// Register Mondo webhook
	mondoWebhookPath, err := router.Get(MondoWebhook).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	log.Printf("%s registering mondo webhook url=%s", SetAuthCode, mondoWebhookPath)
	mondoWebhookUrl := fmt.Sprintf("%%", *thisUrl, mondoWebhookPath)
	mondoWebhookResponse, err := mondoApiClient.RegisterWebHook(session.uberAccessToken, session.mondoAccountId, mondoWebhookUrl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s register mondo webhook error: %s", SetAuthCode, err.Error())
		return
	}

	session.mondoWebhookId = mondoWebhookResponse.Webhook.Id
	log.Printf("%s successfully registered mondo webhook id=%s", SetAuthCode, mondoWebhookResponse.Webhook.Id)
}

func mondoWebhookPost(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	var request = &WebhookRequest{}
	err := json.NewDecoder(r.Body).Decode(request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Printf("%s json parse error: %s", MondoWebhook, err.Error())
		return
	}

	if !strings.Contains(strings.ToUpper(request.Data.Description), "UBER") {
		fmt.Printf("%s ignored transaction: %s", request.Data.Description)
	}

}

func middleware(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	flag.Parse()
	if *uberClientId == "" || *uberClientSecret == "" || *thisUrl == "" {
		flag.PrintDefaults()
		return
	}
	uberApiClient = &UberApiClient{clientSecret: *uberClientSecret, clientId: *uberClientId}
	mondoApiClient = &MondoApiClient{url: *mondoApiUrl}
	router.HandleFunc("/", indexGet).Methods("GET").Name(Index)
	router.HandleFunc("/login", loginPost).Methods("POST").Name(Login)
	router.HandleFunc("/uber/setauthcode/{sessionId}", uberSetAuthCodeGet).Methods("GET").Name(SetAuthCode)
	router.HandleFunc("/mondo/webhook/{sessionId}", mondoWebhookPost).Methods("POST").Name(MondoWebhook)
	log.Printf("Listening on %s\n", *addr)
	log.Fatal(http.ListenAndServeTLS(*addr, *certFile, *keyFile, middleware(router)))
}
<commit_msg>Fix query string<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
	"html/template"
	"log"
	"net/http"
	"strings"
)

const (
	// Route names
	Index        = "/"
	Login        = "/login"
	SetAuthCode  = "/uber/setauthcode"
	ReceiptReady = "/uber/webooks/requests.receipt_ready"
	UberWebhook  = "/uber/webhook"
	MondoWebhook = "/mondo/webhook"
)

type session struct {
	sessionId        string
	mondoAccessToken string
	mondoAccountId   string
	mondoWebhookId   string
	uberAccessToken  string
}

var certFile = flag.String("certFile", "cert.pem", "SSL certificate")
var keyFile = flag.String("keyFile", "key.pem", "SSL certificate")
var addr = flag.String("addr", ":443", "https list addr")
var thisUrl = flag.String("url", "", "public url e.g. https://foo (required)")
var uberClientId = flag.String("uberClientId", "", "Uber client_id (required)")
var uberClientSecret = flag.String("uberClientSecret", "", "Uber client_secret (required)")
var uberApiHost = flag.String("uberApi", "https://api.uber.com/v1", "Uber API URL")
var mondoApiUrl = flag.String("mondoApi", "https://api.getmondo.co.uk", "Mondo API URL")

var indexTemplate = template.Must(template.ParseFiles("index.html"))
var loginSuccessTemplate = template.Must(template.ParseFiles("loginsuccess.html"))

var sessions = make(map[string]*session)
var router = mux.NewRouter()
var uberApiClient *UberApiClient
var mondoApiClient *MondoApiClient

func indexGet(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	indexTemplate.Execute(w, r.Host)
}

func loginPost(w http.ResponseWriter, r *http.Request) {
	mondoAccessToken := r.FormValue("mondo-access-token")
	mondoAccountId := r.FormValue("mondo-account-id")

	if mondoAccessToken == "" || mondoAccountId == "" {
		http.Error(w, "required: mondo-access-token, mondo-account-id", http.StatusBadRequest)
		log.Printf("%s required: mondo-access-token, mondo-account-id", Login)
		return
	}

	// Register session
	uuid, err := uuid.NewV4()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s generate session id error: %s", Login, err.Error())
		return
	}

	sessionId := uuid.String()
	session := &session{
		sessionId:        sessionId,
		mondoAccessToken: mondoAccessToken,
		mondoAccountId:   mondoAccountId}

	sessions[sessionId] = session

	// Send oauth/authorize request to uber with our redirect URL
	redirectUrlPath, err := router.Get(SetAuthCode).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", Login, err.Error())
		return
	}

	redirectUrl := fmt.Sprintf("%s%s", *thisUrl, redirectUrlPath)

	err = uberApiClient.OAuthAuthorize(sessionId, redirectUrl)

	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		log.Printf("%s uber authorize error: %s", Login, err.Error())
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	loginSuccessTemplate.Execute(w, r.Host)
}

func uberSetAuthCodeGet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	sessionId := vars["sessionId"]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	uberAuthorizationCode := r.URL.Query()["code"]
	uberTokenResponse, err := uberApiClient.GetOAuthToken(uberAuthorizationCode[0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s uber oauth token error: %s", SetAuthCode, err.Error())
		return
	}

	session.uberAccessToken = uberTokenResponse.AccessToken
	log.Printf("%s assigned session id=% Uber access_token=%s\n", SetAuthCode, sessionId, uberTokenResponse.AccessToken)

	// Register Mondo webhook
	mondoWebhookPath, err := router.Get(MondoWebhook).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	log.Printf("%s registering mondo webhook url=%s", SetAuthCode, mondoWebhookPath)
	mondoWebhookUrl := fmt.Sprintf("%%", *thisUrl, mondoWebhookPath)
	mondoWebhookResponse, err := mondoApiClient.RegisterWebHook(session.uberAccessToken, session.mondoAccountId, mondoWebhookUrl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s register mondo webhook error: %s", SetAuthCode, err.Error())
		return
	}

	session.mondoWebhookId = mondoWebhookResponse.Webhook.Id
	log.Printf("%s successfully registered mondo webhook id=%s", SetAuthCode, mondoWebhookResponse.Webhook.Id)
}

func mondoWebhookPost(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	var request = &WebhookRequest{}
	err := json.NewDecoder(r.Body).Decode(request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Printf("%s json parse error: %s", MondoWebhook, err.Error())
		return
	}

	if !strings.Contains(strings.ToUpper(request.Data.Description), "UBER") {
		fmt.Printf("%s ignored transaction: %s", request.Data.Description)
	}

}

func middleware(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	flag.Parse()
	if *uberClientId == "" || *uberClientSecret == "" || *thisUrl == "" {
		flag.PrintDefaults()
		return
	}
	uberApiClient = &UberApiClient{clientSecret: *uberClientSecret, clientId: *uberClientId}
	mondoApiClient = &MondoApiClient{url: *mondoApiUrl}
	router.HandleFunc("/", indexGet).Methods("GET").Name(Index)
	router.HandleFunc("/login", loginPost).Methods("POST").Name(Login)
	router.HandleFunc("/uber/setauthcode/{sessionId}", uberSetAuthCodeGet).Methods("GET").Name(SetAuthCode)
	router.HandleFunc("/mondo/webhook/{sessionId}", mondoWebhookPost).Methods("POST").Name(MondoWebhook)
	log.Printf("Listening on %s\n", *addr)
	log.Fatal(http.ListenAndServeTLS(*addr, *certFile, *keyFile, middleware(router)))
}
<|endoftext|>