<commit_before>package main

import (
	"encoding/json"
	"fmt"
	//	"github.com/fatih/color"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
)

func buildAndGetObjectFiles(sourceFilesPath []string, sourceFiles []string,
	headersFolders []string, externIncludes []string,
	externLibs []string, extension string,
	outFolder string, folderInfos ObakeBuildFolder,
	staticLibs []string, allLibs []*StaticLibType) (success bool, objectFilesPath []string) {
	for i, srcFilePath := range sourceFilesPath {
		oFilePath := outFolder + "/" + strings.Replace(sourceFiles[i], extension, ".o", -1)
		objectFilesPath = append(objectFilesPath, oFilePath)

		//		fmt.Printf("SrcFilePath: %s\n", srcFilePath)
		args := []string{"-c", folderInfos.path + "/" + srcFilePath, "-o", oFilePath}
		args = append(args, compilerFlags...)

		for _, headerFolder := range headersFolders {
			if headerFolder == "." {
				args = append(args, "-I"+folderInfos.path+"/")
			} else {
				args = append(args, "-I"+folderInfos.path+"/"+headerFolder+"/")
			}
		}

		_, linkNames, linkIncludes := getStaticLibsLinks(staticLibs, allLibs, folderInfos.name)

		args = append(args, linkIncludes...)
		args = append(args, linkNames...)

		args = append(args, getExternIncludesArgs(externIncludes)...)
		args = append(args, getExternLibsArgs(externLibs)...)

		boldCyan.Printf("[%d/%d] ObjFile: ", (i + 1), len(sourceFiles))
		fmt.Printf("%s %v\n", toolchain, args)
		cmd := exec.Command(toolchain, args...)
		_, err := cmd.CombinedOutput()
		if err != nil {
			boldRed.Printf("ObjFile: %s | Error: %s\n", srcFilePath, fmt.Sprint(err))
			//fmt.Printf("ObjFile: %s | Error: %s\n", srcFilePath, fmt.Sprint(err))
			success = false
			return
		}
		/*
			fmt.Printf("Obj files: %s %v\n", toolchain, args)
			_, err := exec.Command(toolchain, args...).Output()
			if err != nil {
				fmt.Printf("ObjFile: %s | Error: %s\n", srcFilePath, err)
			}
		*/
	}
	success = true
	return
}

func buildDependencies(staticLibs []string, allLibs []*StaticLibType) bool {

	for _, dependencyLib := range staticLibs {
		dependencyFound, dependency := getStaticLibByName(dependencyLib, allLibs)

		if dependencyFound && dependency.isBuilt == false {
			if handleStatic(dependency, allLibs) == false {
				return false
			}
		}
	}
	return true
}

func handleBinary(binary *BinaryType, allLibs []*StaticLibType) bool {

	linkPaths, linkNames, linkIncludes := getStaticLibsLinks(binary.staticLibs, allLibs, binary.name)

	boldCyan.Printf("(%d files) Compiling Binary: %s\n", len(binary.sources), binary.name)

	if buildDependencies(binary.staticLibs, allLibs) == false {
		return false
	}

	objSuccess, objectFilesPath := buildAndGetObjectFiles(binary.sources, binary.sourceFileNames, binary.headerFolders,
		binary.externIncludes, binary.externLibs, binary.sourceExtension, binary.outFolder, binary.folderInfos,
		binary.staticLibs, allLibs)

	if objSuccess == false {
		boldRed.Printf("Build Binary: %s FAILED\n\n", binary.name)
		return false
	}

	binaryExtension := getBinaryOSExtension()

	args := []string{"-o", binary.outFolder + "/" + binary.name + binaryExtension}

	args = append(args, compilerFlags...)
	args = append(args, objectFilesPath...)

	args = append(args, linkIncludes...)
	args = append(args, linkPaths...)
	args = append(args, linkNames...)

	//args = append(args, getExternIncludesArgs(binary.externIncludes)...)
	args = append(args, getExternLibsArgs(binary.externLibs)...)

	fmt.Printf("Handle Binary args: %v\n", args)

	cmd := exec.Command(toolchain, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		boldGreen.Printf("Binary: %s | Error: %s\n", binary.name, fmt.Sprint(err))
		fmt.Printf("Out: %s\n\n", out)
		return false
	}
	fmt.Printf("Out: %s\n\n", out)

	return true
}

func handleStatic(staticLib *StaticLibType, allLibs []*StaticLibType) bool {

	if staticLib.isBuilt == false {

		boldCyan.Printf("(%d files) Compiling StaticLib: %s\n", len(staticLib.sources), staticLib.name)

		linkPaths, linkNames, linkIncludes := getStaticLibsLinks(staticLib.staticLibs, allLibs, staticLib.name)

		if buildDependencies(staticLib.staticLibs, allLibs) == false {
			return false
		}

		objSuccess, objectFilesPath := buildAndGetObjectFiles(staticLib.sources, staticLib.sourceFileNames, staticLib.headerFolders,
			staticLib.externIncludes, staticLib.externLibs, staticLib.sourceExtension, staticLib.outFolder,
			staticLib.folderInfos, staticLib.staticLibs, allLibs)

		if objSuccess == false {
			boldRed.Printf("Build StaticLib: %s FAILED\n\n", staticLib.name)
			return false
		}

		staticLibExtension := getStaticLibOSExtension()

		args := []string{"rcs", staticLib.outFolder + "/" + staticLib.name + staticLibExtension}

		args = append(args, objectFilesPath...)

		args = append(args, linkIncludes...)
		args = append(args, linkPaths...)
		args = append(args, linkNames...)

		//	args = append(args, getExternIncludesArgs(staticLib.externIncludes)...)
		args = append(args, getExternLibsArgs(staticLib.externLibs)...)

		fmt.Printf("Handle Static args: %v\n", args)

		//	executeCommandWithPrintErr("ar", args)

		cmd := exec.Command("ar", args...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			boldRed.Printf("StaticLib: %s | Error: %s\n", staticLib.name, fmt.Sprint(err))
			fmt.Printf("Out: %s\n\n", out)
			return false
		}
		fmt.Printf("Out: %s\n\n", out)

		/*out, err := exec.Command("ar", args...).Output()

		if err != nil {
			fmt.Printf("StaticLib: %s | Error: %s\n\n", staticLib.name, err)
			return false
		} else {
			fmt.Printf("Out: %s\n\n", out)
		}
		*/
		staticLib.isBuilt = true
	}
	return true
}

func handlePlugin(plugin *PluginType, allLibs []*StaticLibType) bool {

	boldCyan.Printf("(%d files) Compiling Plugin: %s\n", len(plugin.sources), plugin.name)

	linkPaths, linkNames, linkIncludes := getStaticLibsLinks(plugin.staticLibs, allLibs, "")

	if buildDependencies(plugin.staticLibs, allLibs) == false {
		return false
	}
	objSuccess, objectFilesPath := buildAndGetObjectFiles(plugin.sources, plugin.sourceFileNames, plugin.headerFolders,
		plugin.externIncludes, plugin.externLibs, plugin.sourceExtension, plugin.outFolder, plugin.folderInfos,
		plugin.staticLibs, allLibs)

	if objSuccess == false {
		boldRed.Printf("Build Plugin: %s FAILED\n\n", plugin.name)
		return false
	}

	pluginLibExtension := getSharedLibOsExtension()

	args := []string{"-shared", "-o", plugin.outFolder + "/" + plugin.name + pluginLibExtension}

	args = append(args, compilerFlags...)
	args = append(args, objectFilesPath...)

	args = append(args, linkIncludes...)
	args = append(args, linkPaths...)
	args = append(args, linkNames...)

	//	args = append(args, getExternIncludesArgs(plugin.externIncludes)...)
	args = append(args, getExternLibsArgs(plugin.externLibs)...)

	fmt.Printf("Handle Plugin args: %v\n", args)

	//executeCommandWithPrintErr(toolchain, args)

	cmd := exec.Command(toolchain, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		boldRed.Printf("Plugin: %s | Error: %s\n", plugin.name, fmt.Sprint(err))
		fmt.Printf("Out: %s\n\n", out)
		return false
	}
	fmt.Printf("Out: %s\n\n", out)
	/*
		out, err := exec.Command(toolchain, args...).Output()

		if err != nil {
			fmt.Printf("PluginLib: %s | Error: %s\n\n", plugin.name, err)
			return false
		}
		fmt.Printf("Out: %s\n\n", out)
	*/
	return true
}

func handleBuilder(builder BuilderJSON, binaries []*BinaryType,
	staticLibs []*StaticLibType, plugins []*PluginType) bool {
	outBinaryFound := false
	var outBinary *BinaryType

	for _, binary := range binaries {
		if binary.isOutBinary == true {
			outBinary = binary
			outBinaryFound = true
			break
		}
	}

	if outBinaryFound == false {
		return false
	}

	binaryExtension := getBinaryOSExtension()
	staticExtension := getStaticLibOSExtension()
	pluginExtension := getSharedLibOsExtension()

	success, _ := exists(builder.OutFolder)
	if !success {
		os.MkdirAll(builder.OutFolder, os.ModePerm)
	}
	success, _ = exists(builder.OutFolder + "Plugins")
	if !success {
		os.MkdirAll(builder.OutFolder+"/Plugins", os.ModePerm)
	}

	copy(outBinary.outFolder+"/"+outBinary.name+binaryExtension, builder.OutFolder+"/"+outBinary.name+binaryExtension)

	for _, plugin := range plugins {
		copy(plugin.outFolder+"/"+plugin.name+pluginExtension, builder.OutFolder+"/Plugins/"+plugin.name+pluginExtension)
	}

	for _, lib := range staticLibs {
		copy(lib.outFolder+"/"+lib.name+staticExtension, builder.OutFolder+lib.name+staticExtension)
	}

	return true
}

func handleFiles(rootOBSFile []byte, subFiles []ObakeBuildFolder) {
	var binaries []*BinaryType
	var staticLibs []*StaticLibType
	var plugins []*PluginType
	var obakeRootFileObj ObjectJSON

	json.Unmarshal(rootOBSFile, &obakeRootFileObj)
	//fmt.Printf("RootOBSFile: %v\n", obakeRootFileObj)

	osType = getOsType(obakeRootFileObj.Builder.Os)
	compilerFlags = obakeRootFileObj.Builder.CompilerFlags

	if isValidToolchain(obakeRootFileObj.Builder.Toolchain) {
		toolchain = obakeRootFileObj.Builder.Toolchain
	} else {
		toolchain = DEFAULT_TOOLCHAIN
	}
	boldRed.Printf("Volund: OsType: %s | Toolchain: %s\n", obakeRootFileObj.Builder.Os, toolchain)
	//	fmt.Printf("SubFilesNB: %d\n", len(subFiles))

	if osType != UNKNOWN {
		for _, buildFolder := range subFiles {

			boldGreen.Print("ReadFile: ")
			fmt.Printf("%s\n", "./"+buildFolder.name+"/"+OBAKE_BS_FILENAME)
			buildFolder.obakeBuildFile, _ = ioutil.ReadFile("./" + buildFolder.name + "/" + OBAKE_BS_FILENAME)
			obakeCurrentFile := getBuildFileJSONObj(buildFolder)

			if obakeCurrentFile.Binary.Name != "" {
				buildFolder.buildType = BINARY
				binaries = append(binaries, makeBinaryType(buildFolder, obakeRootFileObj.Builder.OutBinary))
			} else if obakeCurrentFile.Plugin.Name != "" {
				buildFolder.buildType = PLUGIN
				plugins = append(plugins, makePluginType(buildFolder))
			} else if obakeCurrentFile.StaticLib.Name != "" {
				buildFolder.buildType = STATIC_LIB
				staticLibs = append(staticLibs, makeStaticLibType(buildFolder))
			}
		}
		fmt.Printf("\n")
		for i, staticType := range staticLibs {
			if handleStatic(staticType, staticLibs) == false {
				staticLibs = append(staticLibs[:i], staticLibs[:i+1]...)
			}
		}
		for i, pluginType := range plugins {
			if handlePlugin(pluginType, staticLibs) == false {
				plugins = append(plugins[:i], plugins[:i+1]...)
			}
		}
		for i, binaryType := range binaries {
			if handleBinary(binaryType, staticLibs) == false {
				binaries = append(binaries[:i], binaries[:i+1]...)
			}
		}

		handleBuilder(obakeRootFileObj.Builder, binaries, staticLibs, plugins)
	}
}

func main() {
	//	var argsWithProg []string = os.Args
	var subFiles []ObakeBuildFolder
	var rootOBSFile []byte
	var subOBSFile []byte

	// argsWithProg = os.Args[1:]

	initCustomColors()

	files, err := ioutil.ReadDir(".")
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		filename := file.Name()
		if file.IsDir() {
			filetest := "./" + filename
			//	fmt.Printf("DirFound: %s\n", filetest)
			files, err := ioutil.ReadDir(filetest)
			if err == nil {
				subfolderName := filename
				for _, file := range files {
					filename = file.Name()
					if filename == OBAKE_BS_FILENAME {

						//	fmt.Printf("	Obake SubBuild File Found\n")
						subOBSFile, _ = ioutil.ReadFile(filename)
						var subFolderInfo ObakeBuildFolder
						subFolderInfo.buildType = NONE
						subFolderInfo = ObakeBuildFolder{path: "./" + subfolderName, name: subfolderName, obakeBuildFile: subOBSFile}
						subFiles = append(subFiles, subFolderInfo)
					}
				}
			} else {
				fmt.Printf("ERR: %s\n", err)
				log.Fatal(err)
			}
		} else if filename == OBAKE_BS_FILENAME {
			rootOBSFile, _ = ioutil.ReadFile(filename)
			//	fmt.Printf("Obake RootBuild File Found\n\n")

		}
	}

	handleFiles(rootOBSFile, subFiles)
}
<commit_msg>[UPD] err messages<commit_after>package main

import (
	"encoding/json"
	"fmt"
	//	"github.com/fatih/color"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
)

func buildAndGetObjectFiles(sourceFilesPath []string, sourceFiles []string,
	headersFolders []string, externIncludes []string,
	externLibs []string, extension string,
	outFolder string, folderInfos ObakeBuildFolder,
	staticLibs []string, allLibs []*StaticLibType) (success bool, objectFilesPath []string) {
	for i, srcFilePath := range sourceFilesPath {
		oFilePath := outFolder + "/" + strings.Replace(sourceFiles[i], extension, ".o", -1)
		objectFilesPath = append(objectFilesPath, oFilePath)

		//		fmt.Printf("SrcFilePath: %s\n", srcFilePath)
		args := []string{"-c", folderInfos.path + "/" + srcFilePath, "-o", oFilePath}
		args = append(args, compilerFlags...)

		for _, headerFolder := range headersFolders {
			if headerFolder == "." {
				args = append(args, "-I"+folderInfos.path+"/")
			} else {
				args = append(args, "-I"+folderInfos.path+"/"+headerFolder+"/")
			}
		}

		_, linkNames, linkIncludes := getStaticLibsLinks(staticLibs, allLibs, folderInfos.name)

		args = append(args, linkIncludes...)
		args = append(args, linkNames...)

		args = append(args, getExternIncludesArgs(externIncludes)...)
		args = append(args, getExternLibsArgs(externLibs)...)

		boldCyan.Printf("[%d/%d] ObjFile: ", (i + 1), len(sourceFiles))
		fmt.Printf("%s %v\n", toolchain, args)
		cmd := exec.Command(toolchain, args...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			boldRed.Printf("ObjFile: %s | Error: %s:\n\n", srcFilePath, fmt.Sprint(err))
			fmt.Printf("%s\n", string(out))
			//fmt.Printf("ObjFile: %s | Error: %s\n", srcFilePath, fmt.Sprint(err))
			success = false
			return
		}
		/*
			fmt.Printf("Obj files: %s %v\n", toolchain, args)
			_, err := exec.Command(toolchain, args...).Output()
			if err != nil {
				fmt.Printf("ObjFile: %s | Error: %s\n", srcFilePath, err)
			}
		*/
	}
	success = true
	return
}

func buildDependencies(staticLibs []string, allLibs []*StaticLibType) bool {

	for _, dependencyLib := range staticLibs {
		dependencyFound, dependency := getStaticLibByName(dependencyLib, allLibs)

		if dependencyFound && dependency.isBuilt == false {
			if handleStatic(dependency, allLibs) == false {
				return false
			}
		}
	}
	return true
}

func handleBinary(binary *BinaryType, allLibs []*StaticLibType) bool {

	linkPaths, linkNames, linkIncludes := getStaticLibsLinks(binary.staticLibs, allLibs, binary.name)

	boldCyan.Printf("(%d files) Compiling Binary: %s\n", len(binary.sources), binary.name)

	if buildDependencies(binary.staticLibs, allLibs) == false {
		return false
	}

	objSuccess, objectFilesPath := buildAndGetObjectFiles(binary.sources, binary.sourceFileNames, binary.headerFolders,
		binary.externIncludes, binary.externLibs, binary.sourceExtension, binary.outFolder, binary.folderInfos,
		binary.staticLibs, allLibs)

	if objSuccess == false {
		boldRed.Printf("Build Binary: %s FAILED\n\n", binary.name)
		return false
	}

	binaryExtension := getBinaryOSExtension()

	args := []string{"-o", binary.outFolder + "/" + binary.name + binaryExtension}

	args = append(args, compilerFlags...)
	args = append(args, objectFilesPath...)

	args = append(args, linkIncludes...)
	args = append(args, linkPaths...)
	args = append(args, linkNames...)

	//args = append(args, getExternIncludesArgs(binary.externIncludes)...)
	args = append(args, getExternLibsArgs(binary.externLibs)...)

	fmt.Printf("Handle Binary args: %v\n", args)

	cmd := exec.Command(toolchain, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		boldGreen.Printf("Binary: %s | Error: %s\n\n", binary.name, fmt.Sprint(err))
		fmt.Printf("%s\n", string(out))
		return false
	}
	fmt.Printf("%s\n\n", out)

	return true
}

func handleStatic(staticLib *StaticLibType, allLibs []*StaticLibType) bool {

	if staticLib.isBuilt == false {

		boldCyan.Printf("(%d files) Compiling StaticLib: %s\n", len(staticLib.sources), staticLib.name)

		linkPaths, linkNames, linkIncludes := getStaticLibsLinks(staticLib.staticLibs, allLibs, staticLib.name)

		if buildDependencies(staticLib.staticLibs, allLibs) == false {
			return false
		}

		objSuccess, objectFilesPath := buildAndGetObjectFiles(staticLib.sources, staticLib.sourceFileNames, staticLib.headerFolders,
			staticLib.externIncludes, staticLib.externLibs, staticLib.sourceExtension, staticLib.outFolder,
			staticLib.folderInfos, staticLib.staticLibs, allLibs)

		if objSuccess == false {
			boldRed.Printf("Build StaticLib: %s FAILED\n\n", staticLib.name)
			return false
		}

		staticLibExtension := getStaticLibOSExtension()

		args := []string{"rcs", staticLib.outFolder + "/" + staticLib.name + staticLibExtension}

		args = append(args, objectFilesPath...)

		args = append(args, linkIncludes...)
		args = append(args, linkPaths...)
		args = append(args, linkNames...)

		//	args = append(args, getExternIncludesArgs(staticLib.externIncludes)...)
		args = append(args, getExternLibsArgs(staticLib.externLibs)...)

		fmt.Printf("Handle Static args: %v\n", args)

		//	executeCommandWithPrintErr("ar", args)

		cmd := exec.Command("ar", args...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			boldRed.Printf("StaticLib: %s | Error: %s\n\n", staticLib.name, fmt.Sprint(err))
			fmt.Printf("%s\n", string(out))
			return false
		}
		fmt.Printf("%s\n\n", out)

		/*out, err := exec.Command("ar", args...).Output()

		if err != nil {
			fmt.Printf("StaticLib: %s | Error: %s\n\n", staticLib.name, err)
			return false
		} else {
			fmt.Printf("Out: %s\n\n", out)
		}
		*/
		staticLib.isBuilt = true
	}
	return true
}

func handlePlugin(plugin *PluginType, allLibs []*StaticLibType) bool {

	boldCyan.Printf("(%d files) Compiling Plugin: %s\n", len(plugin.sources), plugin.name)

	linkPaths, linkNames, linkIncludes := getStaticLibsLinks(plugin.staticLibs, allLibs, "")

	if buildDependencies(plugin.staticLibs, allLibs) == false {
		return false
	}
	objSuccess, objectFilesPath := buildAndGetObjectFiles(plugin.sources, plugin.sourceFileNames, plugin.headerFolders,
		plugin.externIncludes, plugin.externLibs, plugin.sourceExtension, plugin.outFolder, plugin.folderInfos,
		plugin.staticLibs, allLibs)

	if objSuccess == false {
		boldRed.Printf("Build Plugin: %s FAILED\n\n", plugin.name)
		return false
	}

	pluginLibExtension := getSharedLibOsExtension()

	args := []string{"-shared", "-o", plugin.outFolder + "/" + plugin.name + pluginLibExtension}

	args = append(args, compilerFlags...)
	args = append(args, objectFilesPath...)

	args = append(args, linkIncludes...)
	args = append(args, linkPaths...)
	args = append(args, linkNames...)

	//	args = append(args, getExternIncludesArgs(plugin.externIncludes)...)
	args = append(args, getExternLibsArgs(plugin.externLibs)...)

	fmt.Printf("Handle Plugin args: %v\n", args)

	//executeCommandWithPrintErr(toolchain, args)

	cmd := exec.Command(toolchain, args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		boldRed.Printf("Plugin: %s | Error: %s\n\n", plugin.name, fmt.Sprint(err.Error()))
		fmt.Printf("Out: %s\n\n", out)
		return false
	}
	fmt.Printf("Out: %s\n\n", out)
	/*
		out, err := exec.Command(toolchain, args...).Output()

		if err != nil {
			fmt.Printf("PluginLib: %s | Error: %s\n\n", plugin.name, err)
			return false
		}
		fmt.Printf("Out: %s\n\n", out)
	*/
	return true
}

func handleBuilder(builder BuilderJSON, binaries []*BinaryType,
	staticLibs []*StaticLibType, plugins []*PluginType) bool {
	outBinaryFound := false
	var outBinary *BinaryType

	for _, binary := range binaries {
		if binary.isOutBinary == true {
			outBinary = binary
			outBinaryFound = true
			break
		}
	}

	if outBinaryFound == false {
		return false
	}

	binaryExtension := getBinaryOSExtension()
	staticExtension := getStaticLibOSExtension()
	pluginExtension := getSharedLibOsExtension()

	success, _ := exists(builder.OutFolder)
	if !success {
		os.MkdirAll(builder.OutFolder, os.ModePerm)
	}
	success, _ = exists(builder.OutFolder + "Plugins")
	if !success {
		os.MkdirAll(builder.OutFolder+"/Plugins", os.ModePerm)
	}

	copy(outBinary.outFolder+"/"+outBinary.name+binaryExtension, builder.OutFolder+"/"+outBinary.name+binaryExtension)

	for _, plugin := range plugins {
		copy(plugin.outFolder+"/"+plugin.name+pluginExtension, builder.OutFolder+"/Plugins/"+plugin.name+pluginExtension)
	}

	for _, lib := range staticLibs {
		copy(lib.outFolder+"/"+lib.name+staticExtension, builder.OutFolder+lib.name+staticExtension)
	}

	return true
}

func handleFiles(rootOBSFile []byte, subFiles []ObakeBuildFolder) {
	var binaries []*BinaryType
	var staticLibs []*StaticLibType
	var plugins []*PluginType
	var obakeRootFileObj ObjectJSON

	json.Unmarshal(rootOBSFile, &obakeRootFileObj)
	//fmt.Printf("RootOBSFile: %v\n", obakeRootFileObj)

	osType = getOsType(obakeRootFileObj.Builder.Os)
	compilerFlags = obakeRootFileObj.Builder.CompilerFlags

	if isValidToolchain(obakeRootFileObj.Builder.Toolchain) {
		toolchain = obakeRootFileObj.Builder.Toolchain
	} else {
		toolchain = DEFAULT_TOOLCHAIN
	}
	boldRed.Printf("Volund: OsType: %s | Toolchain: %s\n", obakeRootFileObj.Builder.Os, toolchain)
	//	fmt.Printf("SubFilesNB: %d\n", len(subFiles))

	if osType != UNKNOWN {
		for _, buildFolder := range subFiles {

			boldGreen.Print("ReadFile: ")
			fmt.Printf("%s\n", "./"+buildFolder.name+"/"+OBAKE_BS_FILENAME)
			buildFolder.obakeBuildFile, _ = ioutil.ReadFile("./" + buildFolder.name + "/" + OBAKE_BS_FILENAME)
			obakeCurrentFile := getBuildFileJSONObj(buildFolder)

			if obakeCurrentFile.Binary.Name != "" {
				buildFolder.buildType = BINARY
				binaries = append(binaries, makeBinaryType(buildFolder, obakeRootFileObj.Builder.OutBinary))
			} else if obakeCurrentFile.Plugin.Name != "" {
				buildFolder.buildType = PLUGIN
				plugins = append(plugins, makePluginType(buildFolder))
			} else if obakeCurrentFile.StaticLib.Name != "" {
				buildFolder.buildType = STATIC_LIB
				staticLibs = append(staticLibs, makeStaticLibType(buildFolder))
			}
		}
		fmt.Printf("\n")
		for i, staticType := range staticLibs {
			if handleStatic(staticType, staticLibs) == false {
				staticLibs = append(staticLibs[:i], staticLibs[:i+1]...)
			}
		}
		for i, pluginType := range plugins {
			if handlePlugin(pluginType, staticLibs) == false {
				plugins = append(plugins[:i], plugins[:i+1]...)
			}
		}
		for i, binaryType := range binaries {
			if handleBinary(binaryType, staticLibs) == false {
				binaries = append(binaries[:i], binaries[:i+1]...)
			}
		}

		handleBuilder(obakeRootFileObj.Builder, binaries, staticLibs, plugins)
	}
}

func main() {
	//	var argsWithProg []string = os.Args
	var subFiles []ObakeBuildFolder
	var rootOBSFile []byte
	var subOBSFile []byte

	// argsWithProg = os.Args[1:]

	initCustomColors()

	files, err := ioutil.ReadDir(".")
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		filename := file.Name()
		if file.IsDir() {
			filetest := "./" + filename
			//	fmt.Printf("DirFound: %s\n", filetest)
			files, err := ioutil.ReadDir(filetest)
			if err == nil {
				subfolderName := filename
				for _, file := range files {
					filename = file.Name()
					if filename == OBAKE_BS_FILENAME {

						//	fmt.Printf("	Obake SubBuild File Found\n")
						subOBSFile, _ = ioutil.ReadFile(filename)
						var subFolderInfo ObakeBuildFolder
						subFolderInfo.buildType = NONE
						subFolderInfo = ObakeBuildFolder{path: "./" + subfolderName, name: subfolderName, obakeBuildFile: subOBSFile}
						subFiles = append(subFiles, subFolderInfo)
					}
				}
			} else {
				fmt.Printf("ERR: %s\n", err)
				log.Fatal(err)
			}
		} else if filename == OBAKE_BS_FILENAME {
			rootOBSFile, _ = ioutil.ReadFile(filename)
			//	fmt.Printf("Obake RootBuild File Found\n\n")

		}
	}

	handleFiles(rootOBSFile, subFiles)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"os"
)

const (
	unknownFormat uint = iota
	jsonFormat
	xmlFormat
)

func main() {
	pretty(os.Stdin, os.Stdout)
}

func pretty(r io.Reader, w io.Writer) (int64, error) {

	buf := bufio.NewReaderSize(r, 4)

	var format uint
	for {
		ch, _, err := buf.ReadRune()
		if err != nil {
			return 0, err
		}
		if f, ok := formats(ch); ok {
			format = f
			if err := buf.UnreadRune(); err != nil {
				return 0, err
			}
			break
		}
		if endOfLine(ch) {
			return 0, errors.New("unable to recognize this format")
		}
	}

	b, err := ioutil.ReadAll(buf)
	if err != nil {
		return 0, err
	}

	var out bytes.Buffer
	switch format {
	case jsonFormat:
		if err := json.Indent(&out, b, "", "\t"); err != nil {
			return 0, err
		}
	case xmlFormat:
		return 0, errors.New("xml is not yet supported")
	default:
		return 0, errors.New("known format error, please file a bug")
	}

	return out.WriteTo(w)
}

func whitespace(ch rune) bool {
	return ch == ' ' || ch == '\t'
}

func endOfLine(ch rune) bool {
	return ch == '\n' || ch == '\r'
}

func formats(ch rune) (uint, bool) {
	switch ch {
	case '{':
		return jsonFormat, true
	case '<':
		return xmlFormat, true
	default:
		return unknownFormat, false
	}
}
<commit_msg>removing dead whitespace func<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"os"
)

const (
	unknownFormat uint = iota
	jsonFormat
	xmlFormat
)

func main() {
	pretty(os.Stdin, os.Stdout)
}

func pretty(r io.Reader, w io.Writer) (int64, error) {

	buf := bufio.NewReaderSize(r, 4)

	var format uint
	for {
		ch, _, err := buf.ReadRune()
		if err != nil {
			return 0, err
		}
		if f, ok := formats(ch); ok {
			format = f
			if err := buf.UnreadRune(); err != nil {
				return 0, err
			}
			break
		}
		if endOfLine(ch) {
			return 0, errors.New("unable to recognize this format")
		}
	}

	b, err := ioutil.ReadAll(buf)
	if err != nil {
		return 0, err
	}

	var out bytes.Buffer
	switch format {
	case jsonFormat:
		if err := json.Indent(&out, b, "", "\t"); err != nil {
			return 0, err
		}
	case xmlFormat:
		return 0, errors.New("xml is not yet supported")
	default:
		return 0, errors.New("known format error, please file a bug")
	}

	return out.WriteTo(w)
}

func endOfLine(ch rune) bool {
	return ch == '\n' || ch == '\r'
}

func formats(ch rune) (uint, bool) {
	switch ch {
	case '{':
		return jsonFormat, true
	case '<':
		return xmlFormat, true
	default:
		return unknownFormat, false
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	b64 "encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strconv"

	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
)

const (
	AUTHED_CLIENTS_BUCKET = "authed_clients"
	TOKEN_BYTES_LENGTH    = 32
)

type AuthClient struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Gun struct {
	ammoFile string
	bolt     *bolt.DB
	users    []AuthClient
	router   *mux.Router
}

func openTextFile(path string) []byte {
	fileBytes, err := ioutil.ReadFile(path)
	if err != nil {
		panic("Could not read file: " + path + "\nExiting...")
	}
	return fileBytes
}

func createAuthBucket(db *bolt.DB) {
	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(AUTHED_CLIENTS_BUCKET))
		if err != nil {
			return fmt.Errorf("Couldn't create auth clients bucket: %s", err)
		}
		return nil
	})
}

func jSONEqual(a string, b string) (bool, error) {
	var o1 interface{}
	var o2 interface{}

	var err error
	err = json.Unmarshal([]byte(a), &o1)
	if err != nil {
		log.Print(a)
		_, errorMsg := fmt.Printf("Error marshalling JSON A during comparison :: %s", err.Error())
		return false, errorMsg
	}
	err = json.Unmarshal([]byte(b), &o2)
	if err != nil {
		log.Print(b)
		_, errorMsg := fmt.Printf("Error marshalling JSON B during comparison :: %s", err.Error())
		return false, errorMsg
	}

	return reflect.DeepEqual(o1, o2), nil
}

func getAuthToken(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		keyFound := false
		body, bodyReadErr := ioutil.ReadAll(r.Body)
		if bodyReadErr != nil {
			log.Printf("Error reading request body: %v", bodyReadErr)
			http.Error(w, "Unable to read request body!", http.StatusBadRequest)
			return
		}
		w.WriteHeader(http.StatusOK)
		// Check to make sure that the body
		// can be read as an authclient
		var authClient AuthClient
		unmarshalErr := json.Unmarshal(body, &authClient)
		if unmarshalErr != nil {
			log.Printf("Error marshaling request body: %v", unmarshalErr)
			http.Error(w, "Invalid request body!", http.StatusBadRequest)
			return
		}
		// Search DB for matching key
		// If found, return as JSON
		// If not, return JSON error
		db.View(func(tx *bolt.Tx) error {
			// Assume bucket exists and has keys
			b := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET))
			c := b.Cursor()
			for k, v := c.First(); k != nil; k, v = c.Next() {
				// if json key = json client
				clientFound, comparisonError := jSONEqual(string(k), string(body))
				if comparisonError != nil {
					log.Fatal()
				}
				if clientFound {
					keyFound = true
					tokenResponse := struct {
						Token string `json:"token"`
					}{
						b64.StdEncoding.EncodeToString([]byte(v)),
					}
					response, marshalErr := json.Marshal(tokenResponse)
					if marshalErr != nil {
						http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
					}
					fmt.Fprintln(w, string(response))
				}
			}
			return nil
		})
		if keyFound == false {
			errorResponse := struct {
				ErrorMsg string `json:"error"`
			}{
				"Unable to authenticate!",
			}
			response, marshalErr := json.Marshal(errorResponse)
			if marshalErr != nil {
				http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
			}
			fmt.Fprintln(w, string(response))
		}
	}
}

func updateDB(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO
		// Check to see if bucket exists. If not, error
		// Update or create key in bucket
		// Return success
		// cursor.delete() see authenticate
	}
}

func retrieveDB(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO
		// Check to see if bucket exists. If not, error
		// Access key in bucket
		// Return as JSON
	}
}

func Init(ammoFilePath string, dbFilePath string) *Gun {
	// Open ammo file from directory
	ammoFileContents := openTextFile(ammoFilePath)
	// Parse JSON into AuthClients
	authenticatedClients := make([]AuthClient, 0)
	json.Unmarshal(ammoFileContents, &authenticatedClients)
	// Connect to / open db file
	db, err := bolt.Open(dbFilePath, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	// For each authed user / client, assign them an auth token if don't have one
	createAuthBucket(db)
	for i := range authenticatedClients {
		// Get key used to identify a client with their token
		clientKey, jsonErr := json.Marshal(authenticatedClients[i])
		if jsonErr != nil {
			log.Fatal("Error storing auth token in DB.")
		}
		db.Update(func(tx *bolt.Tx) error {
			// Open the auth bucket
			b := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET))
			// Generate a client token to be associated with the key
			clientToken := make([]byte, TOKEN_BYTES_LENGTH)
			_, tokenErr := io.ReadFull(rand.Reader, clientToken)
			if tokenErr != nil {
				log.Fatal("Error generating token.")
			}
			// Store the key with its associated token
			txionErr := b.Put(clientKey, clientToken)
			return txionErr
		})
	}
	// Create router
	router := mux.NewRouter()
	router.HandleFunc("/authenticate", getAuthToken(db)).
		Methods("POST")
	router.HandleFunc("/{bucket}/update", updateDB(db)).
		Methods("POST")
	router.HandleFunc("/{bucket}/retrieve", retrieveDB(db)).
		Methods("GET")
	// Init Boltgun instance
	return &Gun{
		ammoFilePath,
		db,
		authenticatedClients,
		router,
	}
}

func (g *Gun) Fire(port int64) {
	actualPort := ":" + strconv.FormatInt(port, 10)
	http.ListenAndServe(actualPort, g.router)
	defer g.bolt.Close()
}
<commit_msg>Successful v1. Works with storing and retrieving strings<commit_after>package main

import (
	"crypto/rand"
	b64 "encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strconv"

	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
)

const (
	AUTHED_CLIENTS_BUCKET = "authed_clients"
	TOKEN_BYTES_LENGTH    = 32
)

type AuthClient struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Gun struct {
	ammoFile string
	bolt     *bolt.DB
	users    []AuthClient
	router   *mux.Router
}

func openTextFile(path string) []byte {
	fileBytes, err := ioutil.ReadFile(path)
	if err != nil {
		panic("Could not read file: " + path + "\nExiting...")
	}
	return fileBytes
}

func createAuthBucket(db *bolt.DB) {
	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(AUTHED_CLIENTS_BUCKET))
		if err != nil {
			return fmt.Errorf("Couldn't create auth clients bucket: %s", err)
		}
		return nil
	})
}

func jSONEqual(a string, b string) (bool, error) {
	var o1 interface{}
	var o2 interface{}

	var err error
	err = json.Unmarshal([]byte(a), &o1)
	if err != nil {
		log.Print(a)
		_, errorMsg := fmt.Printf("Error marshalling JSON A during comparison :: %s", err.Error())
		return false, errorMsg
	}
	err = json.Unmarshal([]byte(b), &o2)
	if err != nil {
		log.Print(b)
		_, errorMsg := fmt.Printf("Error marshalling JSON B during comparison :: %s", err.Error())
		return false, errorMsg
	}

	return reflect.DeepEqual(o1, o2), nil
}

func getAuthToken(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		keyFound := false
		body, bodyReadErr := ioutil.ReadAll(r.Body)
		if bodyReadErr != nil {
			log.Printf("Error reading request body: %v", bodyReadErr)
			http.Error(w, "Unable to read request body!", http.StatusBadRequest)
			return
		}
		// Check to make sure that the body
		// can be read as an authclient
		var authClient AuthClient
		unmarshalErr := json.Unmarshal(body, &authClient)
		if unmarshalErr != nil {
			log.Printf("Error marshaling request body: %v", unmarshalErr)
			http.Error(w, "Invalid request body!", http.StatusBadRequest)
			return
		}
		// Search DB for matching key
		// If found, return as JSON
		// If not, return JSON error
		db.View(func(tx *bolt.Tx) error {
			// Assume bucket exists and has keys
			b := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET))
			c := b.Cursor()
			for k, v := c.First(); k != nil; k, v = c.Next() {
				// if json key = json client
				clientFound, comparisonError := jSONEqual(string(k), string(body))
				if comparisonError != nil {
					log.Fatal()
				}
				if clientFound {
					keyFound = true
					tokenResponse := struct {
						Token string `json:"token"`
					}{
						b64.StdEncoding.EncodeToString([]byte(v)),
					}
					response, marshalErr := json.Marshal(tokenResponse)
					if marshalErr != nil {
						http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
					}
					w.WriteHeader(http.StatusOK)
					fmt.Fprintln(w, string(response))
				}
			}
			return nil
		})
		if keyFound == false {
			errorResponse := struct {
				ErrorMsg string `json:"error"`
			}{
				"Unable to authenticate!",
			}
			response, marshalErr := json.Marshal(errorResponse)
			if marshalErr != nil {
				http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
			}
			fmt.Fprintln(w, string(response))
		}
	}
}

func updateDB(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		requestIsAuthed := false
		vars := mux.Vars(r)
		bucketName := vars["bucket"]
		body, bodyReadErr := ioutil.ReadAll(r.Body)
		if bodyReadErr != nil {
			log.Printf("Error reading request body: %v", bodyReadErr)
			http.Error(w, "Unable to read request body!", http.StatusBadRequest)
			return
		}
		// Check to make sure that the body
		// can be read as a struct
		var updateRequest struct {
			Key   string `json:"key"`
			Value string `json:"value"`
			Token string `json:"token"`
		}
		unmarshalErr := json.Unmarshal(body, &updateRequest)
		if unmarshalErr != nil {
			log.Printf("Error marshaling request body: %v", unmarshalErr)
			http.Error(w, "Invalid request body!", http.StatusBadRequest)
			return
		}
		db.Update(func(tx *bolt.Tx) error {
			// Open the given bucket
			b, bucketCreateErr := tx.CreateBucketIfNotExists([]byte(bucketName))
			if bucketCreateErr != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("Unable to create or open requested bucket!"))
			}
			c := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET)).Cursor()
			for k, v := c.First(); k != nil && requestIsAuthed == false; k, v = c.Next() {
				// if token is valid then proceed
				// if not, stop there
				if b64.StdEncoding.EncodeToString([]byte(v)) == updateRequest.Token {
					requestIsAuthed = true
				}
			}
			if requestIsAuthed {
				txionErr := b.Put([]byte(updateRequest.Key), []byte(updateRequest.Value))
				if txionErr != nil {
					w.WriteHeader(http.StatusOK)
				} else {
					w.WriteHeader(http.StatusInternalServerError)
				}
				successResponse := struct {
					Success bool `json:"success"`
				}{
					true,
				}
				response, marshalErr := json.Marshal(successResponse)
				if marshalErr != nil {
					http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
				}
				fmt.Fprintln(w, string(response))
				return txionErr
			}
			errorResponse := struct {
				ErrorMsg string `json:"error"`
			}{
				"Invalid request token!",
			}
			response, marshalErr := json.Marshal(errorResponse)
			if marshalErr != nil {
				http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
			}
			fmt.Fprintln(w, string(response))
			return fmt.Errorf("Unable to complete response")
		})
	}
}

func retrieveDB(db *bolt.DB) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO
		requestIsAuthed := false
		vars := mux.Vars(r)
		bucketName := vars["bucket"]
		body, bodyReadErr := ioutil.ReadAll(r.Body)
		if bodyReadErr != nil {
			log.Printf("Error reading request body: %v", bodyReadErr)
			http.Error(w, "Unable to read request body!", http.StatusBadRequest)
			return
		}
		// Check to make sure that the body
		// can be read as a struct
		var retrieveRequest struct {
			Key   string `json:"key"`
			Token string `json:"token"`
		}
		unmarshalErr := json.Unmarshal(body, &retrieveRequest)
		if unmarshalErr != nil {
			log.Printf("Error marshaling request body: %v", unmarshalErr)
			http.Error(w, "Invalid request body!", http.StatusBadRequest)
			return
		}
		// Check to see if bucket exists
		db.View(func(tx *bolt.Tx) error {
			// Open the given bucket
			b := tx.Bucket([]byte(bucketName))
			c := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET)).Cursor()
			for k, v := c.First(); k != nil && requestIsAuthed == false; k, v = c.Next() {
				// if token is valid then proceed
				// if not, stop there
				if b64.StdEncoding.EncodeToString([]byte(v)) == retrieveRequest.Token {
					requestIsAuthed = true
				}
			}
			if requestIsAuthed {
				v := b.Get([]byte(retrieveRequest.Key))
				if v != nil {
					w.WriteHeader(http.StatusOK)
				} else {
					w.WriteHeader(http.StatusBadRequest)
				}
				successResponse := struct {
					Value string `json:"value"`
				}{
					string(v),
				}
				response, marshalErr := json.Marshal(successResponse)
				if marshalErr != nil {
					http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
				}
				fmt.Fprintln(w, string(response))
				return nil
			}
			errorResponse := struct {
				ErrorMsg string `json:"error"`
			}{
				"Invalid request token!",
			}
			response, marshalErr := json.Marshal(errorResponse)
			if marshalErr != nil {
				http.Error(w, "{ \"error\": \"Unable to provide response!\" }", http.StatusInternalServerError)
			}
			fmt.Fprintln(w, string(response))
			return fmt.Errorf("Unable to complete response")
		})
	}
}

func Init(ammoFilePath string, dbFilePath string) *Gun {
	// Open ammo file from directory
	ammoFileContents := openTextFile(ammoFilePath)
	// Parse JSON into AuthClients
	authenticatedClients := make([]AuthClient, 0)
	json.Unmarshal(ammoFileContents, &authenticatedClients)
	// Connect to / open db file
	db, err := bolt.Open(dbFilePath, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	// For each authed user / client, assign them an auth token if don't have one
	createAuthBucket(db)
	for i := range authenticatedClients {
		// Get key used to identify a client with their token
		clientKey, jsonErr := json.Marshal(authenticatedClients[i])
		if jsonErr != nil {
			log.Fatal("Error storing auth token in DB.")
		}
		db.Update(func(tx *bolt.Tx) error {
			// Open the auth bucket
			b := tx.Bucket([]byte(AUTHED_CLIENTS_BUCKET))
			// Generate a client token to be associated with the key
			clientToken := make([]byte, TOKEN_BYTES_LENGTH)
			_, tokenErr := io.ReadFull(rand.Reader, clientToken)
			if tokenErr != nil {
				log.Fatal("Error generating token.")
			}
			// Store the key with its associated token
			txionErr := b.Put(clientKey, clientToken)
			return txionErr
		})
	}
	// Create router
	router := mux.NewRouter()
	router.HandleFunc("/authenticate", getAuthToken(db)).
		Methods("POST")
	router.HandleFunc("/{bucket}/update", updateDB(db)).
		Methods("POST")
	router.HandleFunc("/{bucket}/retrieve", retrieveDB(db)).
		Methods("POST")
	// Init Boltgun instance
	return &Gun{
		ammoFilePath,
		db,
		authenticatedClients,
		router,
	}
}

func (g *Gun) Fire(port int64) {
	actualPort := ":" + strconv.FormatInt(port, 10)
	http.ListenAndServe(actualPort, g.router)
	defer g.bolt.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

	"github.com/sim4life/go_blog/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
)

func main() {
	r := httprouter.New()
	r.GET("/", HomeHandler)

	// Posts collection
	r.GET("/posts", PostsIndexHandler)
	r.POST("/posts", PostsCreateHandler)

	// Posts singular
	r.GET("/posts/:id", PostShowHandler)
	r.PUT("/posts/:id", PostUpdateHandler)
	r.GET("/posts/:id/edit", PostEditHandler)

	fmt.Println("Starting server on :8080")
	http.ListenAndServe(":8080", r)
}

func HomeHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Home")
}

func PostsIndexHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "posts index")
}

func PostsCreateHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "posts create")
}

func PostShowHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	id := p.ByName("id")
	fmt.Fprintln(rw, "showing post", id)
}

func PostUpdateHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post update")
}

func PostDeleteHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post delete")
}

func PostEditHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post edit")
}
<commit_msg>Update<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/sim4life/go_blog/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
)

func main() {
	r := httprouter.New()
	r.GET("/", HomeHandler)

	// Posts collection
	r.GET("/posts", PostsIndexHandler)
	r.POST("/posts", PostsCreateHandler)

	// Posts singular
	r.GET("/posts/:id", PostShowHandler)
	r.PUT("/posts/:id", PostUpdateHandler)
	r.GET("/posts/:id/edit", PostEditHandler)

	fmt.Println("Starting server on :8080")
	log.Fatal(http.ListenAndServe(":8080", r))
}

func HomeHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Home")
}

func PostsIndexHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "posts index")
}

func PostsCreateHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "posts create")
}

func PostShowHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	id := p.ByName("id")
	fmt.Fprintln(rw, "showing post", id)
}

func PostUpdateHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post update")
}

func PostDeleteHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post delete")
}

func PostEditHandler(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "post edit")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"net/http"
	"os"
	"os/signal"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	"github.com/skynetservices/skydns/cache"
)

var (
	showVersion     = flag.Bool("version", false, "Show version")
	debug           = flag.Bool("debug", false, "Debug")
	listen          = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	listenReload    = flag.String("listenReload", "127.0.0.1:8113", "Address to listen to for reload requests (TCP)")
	answersFile     = flag.String("answers", "./answers.yaml", "File containing the answers to respond with")
	defaultTtl      = flag.Uint("ttl", 600, "TTL for answers")
	recurserTimeout = flag.Uint("recurser-timeout", 2, "timeout (in seconds) for recurser")
	ndots           = flag.Uint("ndots", 0, "Queries with more than this number of dots will not use search paths")
	cacheCapacity   = flag.Uint("cache-capacity", 1000, "Cache capacity")
	logFile         = flag.String("log", "", "Log file")
	pidFile         = flag.String("pid-file", "", "PID to write to")
	metadataServer  = flag.String("metadata-server", "", "Metadata server url")
	metadataAnswer  = flag.String("rancher-metadata-answer", "169.254.169.250", "Metadata IP address(es), comma-delimited (adds static A records)")
	neverRecurseTo  = flag.String("never-recurse-to", "169.254.169.250", "Never recurse to IP address(es), comma-delimited")

	answers                   Answers
	globalCache               *cache.Cache
	clientSpecificCaches      map[string]*cache.Cache
	clientSpecificCachesMutex sync.RWMutex
	VERSION                   string
	reloadChan                = make(chan chan error)
	serial                    = uint32(1)
	configGenerator           *ConfigGenerator
)

func metadataDriven() bool {
	return *metadataServer != ""
}

func main() {
	parseFlags()

	log.Infof("Starting rancher-dns %s", VERSION)
	err := loadAnswers()
	if err != nil {
		log.Fatal("Cannot startup without a valid Answers file")
	}

	if *showVersion {
		fmt.Printf("%s\n", VERSION)
		os.Exit(0)
	}

	if metadataDriven() {
		configGenerator = &ConfigGenerator{}
		err = configGenerator.Init(metadataServer)
		if err != nil {
			log.Fatalf("Cannot startup: failed to init config generator: %v", err)
		}
	}

	watchSignals()
	watchHttp()

	seed := time.Now().UTC().UnixNano()
	log.Debug("Set random seed to ", seed)
	rand.Seed(seed)

	udpServer := &dns.Server{Addr: *listen, Net: "udp"}
	tcpServer := &dns.Server{Addr: *listen, Net: "tcp"}

	globalCache = cache.New(int(*cacheCapacity), int(*defaultTtl))
	clientSpecificCaches = make(map[string]*cache.Cache)

	dns.HandleFunc(".", route)

	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	log.Info("Listening on ", *listen)
	log.Fatal(tcpServer.ListenAndServe())
}

func parseFlags() {
	flag.Parse()

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	if *logFile != "" {
		if output, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
			log.Fatalf("Failed to log to file %s: %v", *logFile, err)
		} else {
			log.SetOutput(output)
		}
	}

	if *pidFile != "" {
		log.Infof("Writing pid %d to %s", os.Getpid(), *pidFile)
		if err := ioutil.WriteFile(*pidFile, []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
			log.Fatalf("Failed to write pid file %s: %v", *pidFile, err)
		}
	}
}

func loadAnswersFromMeta(name string) {
	newAnswers, err := configGenerator.GenerateAnswers()
	if err != nil {
		log.Errorf("Failed to generate answers: %v", err)
	}
	ConvertPtrIps(&newAnswers)

	if reflect.DeepEqual(newAnswers, answers) {
		log.Debug("No changes in dns data")
		return
	}

	log.Infof("Reloading answers")
	clearClientSpecificCaches()
	answers = newAnswers
	// write to file (debugging purposes)
	b, err := json.Marshal(answers)
	if err != nil {
		log.Errorf("Failed to marshall answers: %v", err)
	}
	err = ioutil.WriteFile(*answersFile, b, 0644)
	if err != nil {
		log.Errorf("Failed to write answers to file: %v", err)
	}
	log.Infof("Reloaded answers")
}

func loadAnswers() (err error) {
	log.Debug("Loading answers")
	temp, err := ParseAnswers(*answersFile)
	if err == nil {
		clearClientSpecificCaches()
		answers = temp
		log.Infof("Loaded answers")
	} else {
		log.Errorf("Failed to load answers: %v", err)
	}

	return err
}

func watchSignals() {
	if metadataDriven() {
		go configGenerator.metaFetcher.OnChange(5, loadAnswersFromMeta)
	} else {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)

		go func() {
			for _ = range c {
				log.Info("Received HUP signal")
				reloadChan <- nil
			}
		}()

		go func() {
			for resp := range reloadChan {
				err := loadAnswers()
				if resp != nil {
					resp <- err
				}
			}
		}()
	}

}

func watchHttp() {
	reloadRouter := mux.NewRouter()
	reloadRouter.HandleFunc("/v1/reload", httpReload).Methods("POST")
	log.Info("Listening for Reload on ", *listenReload)
	go http.ListenAndServe(*listenReload, reloadRouter)
}

func httpReload(w http.ResponseWriter, req *http.Request) {
	log.Debugf("Received HTTP reload request")
	respChan := make(chan error)
	reloadChan <- respChan
	err := <-respChan

	if err == nil {
		io.WriteString(w, "OK")
	} else {
		w.WriteHeader(500)
		io.WriteString(w, err.Error())
	}
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	// Setup reply
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Compress = true

	clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String())

	// One question at a time please
	if len(req.Question) != 1 {
		dns.HandleFailed(w, req)
		log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query")
		return
	}

	question := req.Question[0]
	rrString := dns.Type(question.Qtype).String()

	// We are assuming the config has all names as lower case
	fqdn := strings.ToLower(question.Name)

	// Internets only
	if question.Qclass != dns.ClassINET {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query")
		return
	}

	// ANY queries are bad, mmmkay...
	if question.Qtype == dns.TypeANY {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query")
		return
	}

	proto := "UDP"
	if isTcp(w) {
		proto = "TCP"
	}

	log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request")

	if msg := clientSpecificCacheHit(clientIp, req); msg != nil {
		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent client-specific cached response")
		return
	}

	if msg := globalCacheHit(req); msg != nil {
		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent globally cached response")
		return
	}

	// A records may return CNAME answer(s) plus A answer(s)
	if question.Qtype == dns.TypeA {
		found, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok && len(found) > 0 {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered locally")
			m.Answer = found
			addToClientSpecificCache(clientIp, req, m)
			Respond(w, req, m)
			return
		}
	} else if question.Qtype == dns.TypeAAAA {
		_, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Answered locally, no error and empty answer")
			m.Authoritative = true
			m.Rcode = dns.RcodeSuccess
			addToClientSpecificCache(clientIp, req, m)
			Respond(w, req, m)
			return
		}

	} else {
		// Specific request for another kind of record
		keys := []string{clientIp, DEFAULT_KEY}
		for _, key := range keys {
			// Client-specific answers
			found, ok := answers.Matching(question.Qtype, key, fqdn)
			if ok {
				log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered from config for ", key)
				m.Answer = found
				addToClientSpecificCache(clientIp, req, m)
				Respond(w, req, m)
				return
			}
		}

		log.Debug("No match found in config")
	}

	// If we are authoritative for a suffix the label has, there's no point trying the recursive DNS
	authoritativeFor := answers.AuthoritativeSuffixes()
	for _, suffix := range authoritativeFor {
		if strings.HasSuffix(fqdn, suffix) {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debugf("Not answered locally, but I am authoritative for %s", suffix)
			m.Authoritative = true
			m.RecursionAvailable = false
			m.Rcode = dns.RcodeNameError
			me := strings.TrimLeft(suffix, ".")
			hdr := dns.RR_Header{Name: me, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: uint32(*defaultTtl)}
			serial++
			record := &dns.SOA{Hdr: hdr, Ns: me, Mbox: me, Serial: serial, Refresh: 60, Retry: 10, Expire: 86400, Minttl: 1}
			m.Ns = append(m.Ns, record)
			Respond(w, req, m)
			return
		}
	}

	// Phone a friend - Forward original query
	msg, err := ResolveTryAll(req, answers.Recursers(clientIp))
	if err == nil && msg != nil {
		msg.Compress = true
		msg.Id = req.Id

		// We don't support AAAA, but an NXDOMAIN from the recursive resolver
		// doesn't necessarily mean there are never any records for that domain,
		// so rewrite the response code to NOERROR.
		if (question.Qtype == dns.TypeAAAA) && (msg.Rcode == dns.RcodeNameError) {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Rewrote AAAA NXDOMAIN to NOERROR")
			msg.Rcode = dns.RcodeSuccess
		}

		addToGlobalCache(req, msg)

		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent recursive response")
		return
	}

	// I give up
	log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("No answer found")
	dns.HandleFailed(w, req)
}

func isTcp(w dns.ResponseWriter) bool {
	_, ok := w.RemoteAddr().(*net.TCPAddr)
	return ok
}
<commit_msg>randomizing the answers from cache hit<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"net/http"
	"os"
	"os/signal"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	"github.com/skynetservices/skydns/cache"
)

var (
	showVersion     = flag.Bool("version", false, "Show version")
	debug           = flag.Bool("debug", false, "Debug")
	listen          = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	listenReload    = flag.String("listenReload", "127.0.0.1:8113", "Address to listen to for reload requests (TCP)")
	answersFile     = flag.String("answers", "./answers.yaml", "File containing the answers to respond with")
	defaultTtl      = flag.Uint("ttl", 600, "TTL for answers")
	recurserTimeout = flag.Uint("recurser-timeout", 2, "timeout (in seconds) for recurser")
	ndots           = flag.Uint("ndots", 0, "Queries with more than this number of dots will not use search paths")
	cacheCapacity   = flag.Uint("cache-capacity", 1000, "Cache capacity")
	logFile         = flag.String("log", "", "Log file")
	pidFile         = flag.String("pid-file", "", "PID to write to")
	metadataServer  = flag.String("metadata-server", "", "Metadata server url")
	metadataAnswer  = flag.String("rancher-metadata-answer", "169.254.169.250", "Metadata IP address(es), comma-delimited (adds static A records)")
	neverRecurseTo  = flag.String("never-recurse-to", "169.254.169.250", "Never recurse to IP address(es), comma-delimited")

	answers                   Answers
	globalCache               *cache.Cache
	clientSpecificCaches      map[string]*cache.Cache
	clientSpecificCachesMutex sync.RWMutex
	VERSION                   string
	reloadChan                = make(chan chan error)
	serial                    = uint32(1)
	configGenerator           *ConfigGenerator
)

func metadataDriven() bool {
	return *metadataServer != ""
}

func main() {
	parseFlags()

	log.Infof("Starting rancher-dns %s", VERSION)
	err := loadAnswers()
	if err != nil {
		log.Fatal("Cannot startup without a valid Answers file")
	}

	if *showVersion {
		fmt.Printf("%s\n", VERSION)
		os.Exit(0)
	}

	if metadataDriven() {
		configGenerator = &ConfigGenerator{}
		err = configGenerator.Init(metadataServer)
		if err != nil {
			log.Fatalf("Cannot startup: failed to init config generator: %v", err)
		}
	}

	watchSignals()
	watchHttp()

	seed := time.Now().UTC().UnixNano()
	log.Debug("Set random seed to ", seed)
	rand.Seed(seed)

	udpServer := &dns.Server{Addr: *listen, Net: "udp"}
	tcpServer := &dns.Server{Addr: *listen, Net: "tcp"}

	globalCache = cache.New(int(*cacheCapacity), int(*defaultTtl))
	clientSpecificCaches = make(map[string]*cache.Cache)

	dns.HandleFunc(".", route)

	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	log.Info("Listening on ", *listen)
	log.Fatal(tcpServer.ListenAndServe())
}

func parseFlags() {
	flag.Parse()

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	if *logFile != "" {
		if output, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
			log.Fatalf("Failed to log to file %s: %v", *logFile, err)
		} else {
			log.SetOutput(output)
		}
	}

	if *pidFile != "" {
		log.Infof("Writing pid %d to %s", os.Getpid(), *pidFile)
		if err := ioutil.WriteFile(*pidFile, []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
			log.Fatalf("Failed to write pid file %s: %v", *pidFile, err)
		}
	}
}

func loadAnswersFromMeta(name string) {
	newAnswers, err := configGenerator.GenerateAnswers()
	if err != nil {
		log.Errorf("Failed to generate answers: %v", err)
	}
	ConvertPtrIps(&newAnswers)

	if reflect.DeepEqual(newAnswers, answers) {
		log.Debug("No changes in dns data")
		return
	}

	log.Infof("Reloading answers")
	clearClientSpecificCaches()
	answers = newAnswers
	// write to file (debugging purposes)
	b, err := json.Marshal(answers)
	if err != nil {
		log.Errorf("Failed to marshall answers: %v", err)
	}
	err = ioutil.WriteFile(*answersFile, b, 0644)
	if err != nil {
		log.Errorf("Failed to write answers to file: %v", err)
	}
	log.Infof("Reloaded answers")
}

func loadAnswers() (err error) {
	log.Debug("Loading answers")
	temp, err := ParseAnswers(*answersFile)
	if err == nil {
		clearClientSpecificCaches()
		answers = temp
		log.Infof("Loaded answers")
	} else {
		log.Errorf("Failed to load answers: %v", err)
	}

	return err
}

func watchSignals() {
	if metadataDriven() {
		go configGenerator.metaFetcher.OnChange(5, loadAnswersFromMeta)
	} else {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)

		go func() {
			for _ = range c {
				log.Info("Received HUP signal")
				reloadChan <- nil
			}
		}()

		go func() {
			for resp := range reloadChan {
				err := loadAnswers()
				if resp != nil {
					resp <- err
				}
			}
		}()
	}

}

func watchHttp() {
	reloadRouter := mux.NewRouter()
	reloadRouter.HandleFunc("/v1/reload", httpReload).Methods("POST")
	log.Info("Listening for Reload on ", *listenReload)
	go http.ListenAndServe(*listenReload, reloadRouter)
}

func httpReload(w http.ResponseWriter, req *http.Request) {
	log.Debugf("Received HTTP reload request")
	respChan := make(chan error)
	reloadChan <- respChan
	err := <-respChan

	if err == nil {
		io.WriteString(w, "OK")
	} else {
		w.WriteHeader(500)
		io.WriteString(w, err.Error())
	}
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	// Setup reply
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Compress = true

	clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String())

	// One question at a time please
	if len(req.Question) != 1 {
		dns.HandleFailed(w, req)
		log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query")
		return
	}

	question := req.Question[0]
	rrString := dns.Type(question.Qtype).String()

	// We are assuming the config has all names as lower case
	fqdn := strings.ToLower(question.Name)

	// Internets only
	if question.Qclass != dns.ClassINET {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query")
		return
	}

	// ANY queries are bad, mmmkay...
	if question.Qtype == dns.TypeANY {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query")
		return
	}

	proto := "UDP"
	if isTcp(w) {
		proto = "TCP"
	}

	log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request")

	if msg := clientSpecificCacheHit(clientIp, req); msg != nil {
		if len(msg.Answer) > 1 {
			shuffle(&msg.Answer)
		}
		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent client-specific cached response")
		return
	}

	if msg := globalCacheHit(req); msg != nil {
		if len(msg.Answer) > 1 {
			shuffle(&msg.Answer)
		}
		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent globally cached response")
		return
	}

	// A records may return CNAME answer(s) plus A answer(s)
	if question.Qtype == dns.TypeA {
		found, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok && len(found) > 0 {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered locally")
			m.Answer = found
			addToClientSpecificCache(clientIp, req, m)
			Respond(w, req, m)
			return
		}
	} else if question.Qtype == dns.TypeAAAA {
		_, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Answered locally, no error and empty answer")
			m.Authoritative = true
			m.Rcode = dns.RcodeSuccess
			addToClientSpecificCache(clientIp, req, m)
			Respond(w, req, m)
			return
		}

	} else {
		// Specific request for another kind of record
		keys := []string{clientIp, DEFAULT_KEY}
		for _, key := range keys {
			// Client-specific answers
			found, ok := answers.Matching(question.Qtype, key, fqdn)
			if ok {
				log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered from config for ", key)
				m.Answer = found
				addToClientSpecificCache(clientIp, req, m)
				Respond(w, req, m)
				return
			}
		}

		log.Debug("No match found in config")
	}

	// If we are authoritative for a suffix the label has, there's no point trying the recursive DNS
	authoritativeFor := answers.AuthoritativeSuffixes()
	for _, suffix := range authoritativeFor {
		if strings.HasSuffix(fqdn, suffix) {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debugf("Not answered locally, but I am authoritative for %s", suffix)
			m.Authoritative = true
			m.RecursionAvailable = false
			m.Rcode = dns.RcodeNameError
			me := strings.TrimLeft(suffix, ".")
			hdr := dns.RR_Header{Name: me, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: uint32(*defaultTtl)}
			serial++
			record := &dns.SOA{Hdr: hdr, Ns: me, Mbox: me, Serial: serial, Refresh: 60, Retry: 10, Expire: 86400, Minttl: 1}
			m.Ns = append(m.Ns, record)
			Respond(w, req, m)
			return
		}
	}

	// Phone a friend - Forward original query
	msg, err := ResolveTryAll(req, answers.Recursers(clientIp))
	if err == nil && msg != nil {
		msg.Compress = true
		msg.Id = req.Id

		// We don't support AAAA, but an NXDOMAIN from the recursive resolver
		// doesn't necessarily mean there are never any records for that domain,
		// so rewrite the response code to NOERROR.
		if (question.Qtype == dns.TypeAAAA) && (msg.Rcode == dns.RcodeNameError) {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Rewrote AAAA NXDOMAIN to NOERROR")
			msg.Rcode = dns.RcodeSuccess
		}

		addToGlobalCache(req, msg)

		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent recursive response")
		return
	}

	// I give up
	log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("No answer found")
	dns.HandleFailed(w, req)
}

func isTcp(w dns.ResponseWriter) bool {
	_, ok := w.RemoteAddr().(*net.TCPAddr)
	return ok
}
<|endoftext|>


<commit_before>package main

import (
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	masterServer "github.com/030io/whalefs/master"
	"github.com/030io/whalefs/volume/manager"
	"github.com/030io/whalefs/volume"
	"github.com/030io/whalefs/tool/benchmark"
	parser "github.com/030io/whalefs/utils/kingpin_parser"
	"fmt"
	"net"
	"net/http"
	"os/signal"
	"syscall"
	"runtime/debug"
	"github.com/030io/whalefs/tool/check"
)

const version = "2.6 beta"

var (
	app = kingpin.New("whalefs", "A simple filesystem for small file.  Version: " + version)

	verbose = app.Flag("verbose", "verbose level").Short('v').Default("0").Int()
	gcpercent = app.Flag("gcpercent", "gc percent(default: 300)").Default("300").Int()
	keepAlive = app.Flag("keepAlive", "keep alive per host(default: 1000)").Default("1000").Int()

	master = app.Command("master", "master server")
	masterPort = master.Flag("port", "master port(CRUD)").Short('p').Default("8888").Int()
	masterPublicPort = master.Flag("publicPort", "master public port(only 'GET')").Default("8899").Int()
	masterReplication = master.Flag("replication", "replication setting").Short('r').Default("000").String()
	masterRedisServer = master.Flag("redisIP", "ip of redis server").Default("localhost").String()
	masterRedisPort = master.Flag("redisPort", "ip of redis server").Default("6379").Int()
	masterRedisPW = master.Flag("redisPW", "password of redis server").String()
	masterRedisN = master.Flag("redisN", "database of redis server").Default("0").Int()
	masterHeartbeat = master.Flag("heartbeat", "max volume manager heartbeat duration").Default("10s").Duration()

	volumeManager = app.Command("volume", "volume manager server")
	vmDir = volumeManager.Flag("dir", "directory to store data").Short('d').Required().String()
	vmAdminHost = volumeManager.Flag("adminHost", "for manage files (default: auto detect by master)").String()
	vmAdminPort = volumeManager.Flag("adminPort", "for manage files (default: 7800-7899)").Int()
	vmPublicHost = volumeManager.Flag("publicHost", "for access files (default: auto detect by master)").String()
	vmPublicPort = volumeManager.Flag("publicPort", "for access files (default: 7900-7999)").Int()
	vmMasterHost = volumeManager.Flag("masterHost", "host of master server").Default("localhost").String()
	vmMasterPort = volumeManager.Flag("masterPort", "port of master server").Default("8888").Int()
	vmMachine = volumeManager.Flag("machine", "machine tag of volume manager server (defalut: auto detect by master)").String()
	vmDataCenter = volumeManager.Flag("dataCenter", "datacenter tag of volume manager server (defalut: \"\")").String()
	vmDiskPercent = volumeManager.Flag("diskPercent", "max disk used percent(max: 99)").Default("99").Uint()
	vmHeartbeat = volumeManager.Flag("heartbeat", "heartbeat duration").Default("5s").Duration()
	vmTruncateSize = parser.Size(volumeManager.Flag("truncate", "volume truncate size(B/K/M/G)").Default("1G"))
	vmMaxSize = parser.Size(volumeManager.Flag("maxSize", "volume max size(B/K/M/G)").Default("512G"))
	vmReadonly = volumeManager.Flag("readOnly", "all volume read only").Default("false").Bool()

	benchmark_ = app.Command("benchmark", "benchmark")
	bmMasterHost = benchmark_.Flag("masterHost", "host of master server").Default("localhost").String()
	bmMasterPort = benchmark_.Flag("masterPort", "post of master server").Default("8888").Int()
	bmConcurrent = benchmark_.Flag("concurrent", "concurrent").Default("16").Int()
	bmNum = benchmark_.Flag("num", "number of file write/read").Default("1000").Int()
	bmSize = parser.Size(benchmark_.Flag("size", "size of file write/read").Default("1024B"))

	check_ = app.Command("check", "check volume path")
	cPath = check_.Arg("path", "path").String()
)

func main() {
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	command := kingpin.MustParse(app.Parse(os.Args[1:]))

	debug.SetGCPercent(*gcpercent)
	http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = *keepAlive

	switch command {
	case master.FullCommand():
		masterServer.MaxHeartbeatDuration = *masterHeartbeat

		m, err := masterServer.NewMaster()
		if err != nil {
			panic(m)
		}
		m.Metadata, err = masterServer.NewMetadataRedis(*masterRedisServer, *masterRedisPort, *masterRedisPW, *masterRedisN)
		if err != nil {
			panic(err)
		}
		m.Port = *masterPort
		m.PublicPort = *masterPublicPort
		for i, c := range *masterReplication {
			m.Replication[i] = int(c) - int('0')
		}

		go func() {
			sig := <-signals
			m.Stop()
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		m.Start()
	case volumeManager.FullCommand():
		if *vmDiskPercent > 99 {
			panic(fmt.Sprintf("max disk used percent %d > 99", *vmDiskPercent))
		} else if *vmDiskPercent < 2 {
			panic(fmt.Sprintf("max disk used percent < %d, Are you serious?", *vmDiskPercent))
		}
		manager.MaxDiskUsedPercent = *vmDiskPercent
		manager.HeartbeatDuration = *vmHeartbeat
		manager.ReadOnly = *vmReadonly

		if *vmMaxSize < 1 << 20 {
			panic("volume max size < 1M, Are you serious?")
		}
		volume.MaxVolumeSize = *vmMaxSize

		if *vmTruncateSize < 1 << 20 {
			panic("volume truncate size < 1M, Are you serious?")
		}
		volume.TruncateSize = *vmTruncateSize

		vm, err := manager.NewVolumeManager(*vmDir)
		if err != nil {
			panic(err)
		}

		vm.AdminHost = *vmAdminHost
		if *vmAdminPort == 0 {
			*vmAdminPort, err = getFreeTcpPort(7800, 7900)
			if err != nil {
				panic(err)
			}
		}
		vm.AdminPort = *vmAdminPort

		vm.PublicHost = *vmPublicHost
		if *vmPublicPort == 0 {
			*vmPublicPort, err = getFreeTcpPort(7900, 8000)
			if err != nil {
				panic(err)
			}
		}
		vm.PublicPort = *vmPublicPort

		vm.MasterHost = *vmMasterHost
		vm.MasterPort = *vmMasterPort
		vm.Machine = *vmMachine
		vm.DataCenter = *vmDataCenter

		go func() {
			sig := <-signals
			vm.Stop()
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		vm.Start()
	case benchmark_.FullCommand():
		go func() {
			sig := <-signals
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		benchmark.Benchmark(*bmMasterHost, *bmMasterPort, *bmConcurrent, *bmNum, int(*bmSize))
	case check_.FullCommand():
		check.Check(*cPath)
	}
}

func getFreeTcpPort(start, end int) (int, error) {
	for i := start; i < end; i++ {
		if ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", i)); err == nil {
			ln.Close()
			return ln.Addr().(*net.TCPAddr).Port, nil
		}
	}
	return 0, fmt.Errorf("can't get a free port between [%d, %d)", start, end)
}
<commit_msg>v2.7 release<commit_after>package main

import (
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	masterServer "github.com/030io/whalefs/master"
	"github.com/030io/whalefs/volume/manager"
	"github.com/030io/whalefs/volume"
	"github.com/030io/whalefs/tool/benchmark"
	parser "github.com/030io/whalefs/utils/kingpin_parser"
	"fmt"
	"net"
	"net/http"
	"os/signal"
	"syscall"
	"runtime/debug"
	"github.com/030io/whalefs/tool/check"
)

const version = "2.7 release"

var (
	app = kingpin.New("whalefs", "A simple filesystem for small file.  Version: " + version)

	verbose = app.Flag("verbose", "verbose level").Short('v').Default("0").Int()
	gcpercent = app.Flag("gcpercent", "gc percent(default: 300)").Default("300").Int()
	keepAlive = app.Flag("keepAlive", "keep alive per host(default: 1000)").Default("1000").Int()

	master = app.Command("master", "master server")
	masterPort = master.Flag("port", "master port(CRUD)").Short('p').Default("8888").Int()
	masterPublicPort = master.Flag("publicPort", "master public port(only 'GET')").Default("8899").Int()
	masterReplication = master.Flag("replication", "replication setting").Short('r').Default("000").String()
	masterRedisServer = master.Flag("redisIP", "ip of redis server").Default("localhost").String()
	masterRedisPort = master.Flag("redisPort", "ip of redis server").Default("6379").Int()
	masterRedisPW = master.Flag("redisPW", "password of redis server").String()
	masterRedisN = master.Flag("redisN", "database of redis server").Default("0").Int()
	masterHeartbeat = master.Flag("heartbeat", "max volume manager heartbeat duration").Default("10s").Duration()

	volumeManager = app.Command("volume", "volume manager server")
	vmDir = volumeManager.Flag("dir", "directory to store data").Short('d').Required().String()
	vmAdminHost = volumeManager.Flag("adminHost", "for manage files (default: auto detect by master)").String()
	vmAdminPort = volumeManager.Flag("adminPort", "for manage files (default: 7800-7899)").Int()
	vmPublicHost = volumeManager.Flag("publicHost", "for access files (default: auto detect by master)").String()
	vmPublicPort = volumeManager.Flag("publicPort", "for access files (default: 7900-7999)").Int()
	vmMasterHost = volumeManager.Flag("masterHost", "host of master server").Default("localhost").String()
	vmMasterPort = volumeManager.Flag("masterPort", "port of master server").Default("8888").Int()
	vmMachine = volumeManager.Flag("machine", "machine tag of volume manager server (defalut: auto detect by master)").String()
	vmDataCenter = volumeManager.Flag("dataCenter", "datacenter tag of volume manager server (defalut: \"\")").String()
	vmDiskPercent = volumeManager.Flag("diskPercent", "max disk used percent(max: 99)").Default("99").Uint()
	vmHeartbeat = volumeManager.Flag("heartbeat", "heartbeat duration").Default("5s").Duration()
	vmTruncateSize = parser.Size(volumeManager.Flag("truncate", "volume truncate size(B/K/M/G)").Default("1G"))
	vmMaxSize = parser.Size(volumeManager.Flag("maxSize", "volume max size(B/K/M/G)").Default("512G"))
	vmReadonly = volumeManager.Flag("readOnly", "all volume read only").Default("false").Bool()

	benchmark_ = app.Command("benchmark", "benchmark")
	bmMasterHost = benchmark_.Flag("masterHost", "host of master server").Default("localhost").String()
	bmMasterPort = benchmark_.Flag("masterPort", "post of master server").Default("8888").Int()
	bmConcurrent = benchmark_.Flag("concurrent", "concurrent").Default("16").Int()
	bmNum = benchmark_.Flag("num", "number of file write/read").Default("1000").Int()
	bmSize = parser.Size(benchmark_.Flag("size", "size of file write/read").Default("1024B"))

	check_ = app.Command("check", "check volume path")
	cPath = check_.Arg("path", "path").String()
)

func main() {
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	command := kingpin.MustParse(app.Parse(os.Args[1:]))

	debug.SetGCPercent(*gcpercent)
	http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = *keepAlive

	switch command {
	case master.FullCommand():
		masterServer.MaxHeartbeatDuration = *masterHeartbeat

		m, err := masterServer.NewMaster()
		if err != nil {
			panic(m)
		}
		m.Metadata, err = masterServer.NewMetadataRedis(*masterRedisServer, *masterRedisPort, *masterRedisPW, *masterRedisN)
		if err != nil {
			panic(err)
		}
		m.Port = *masterPort
		m.PublicPort = *masterPublicPort
		for i, c := range *masterReplication {
			m.Replication[i] = int(c) - int('0')
		}

		go func() {
			sig := <-signals
			m.Stop()
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		m.Start()
	case volumeManager.FullCommand():
		if *vmDiskPercent > 99 {
			panic(fmt.Sprintf("max disk used percent %d > 99", *vmDiskPercent))
		} else if *vmDiskPercent < 2 {
			panic(fmt.Sprintf("max disk used percent < %d, Are you serious?", *vmDiskPercent))
		}
		manager.MaxDiskUsedPercent = *vmDiskPercent
		manager.HeartbeatDuration = *vmHeartbeat
		manager.ReadOnly = *vmReadonly

		if *vmMaxSize < 1 << 20 {
			panic("volume max size < 1M, Are you serious?")
		}
		volume.MaxVolumeSize = *vmMaxSize

		if *vmTruncateSize < 1 << 20 {
			panic("volume truncate size < 1M, Are you serious?")
		}
		volume.TruncateSize = *vmTruncateSize

		vm, err := manager.NewVolumeManager(*vmDir)
		if err != nil {
			panic(err)
		}

		vm.AdminHost = *vmAdminHost
		if *vmAdminPort == 0 {
			*vmAdminPort, err = getFreeTcpPort(7800, 7900)
			if err != nil {
				panic(err)
			}
		}
		vm.AdminPort = *vmAdminPort

		vm.PublicHost = *vmPublicHost
		if *vmPublicPort == 0 {
			*vmPublicPort, err = getFreeTcpPort(7900, 8000)
			if err != nil {
				panic(err)
			}
		}
		vm.PublicPort = *vmPublicPort

		vm.MasterHost = *vmMasterHost
		vm.MasterPort = *vmMasterPort
		vm.Machine = *vmMachine
		vm.DataCenter = *vmDataCenter

		go func() {
			sig := <-signals
			vm.Stop()
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		vm.Start()
	case benchmark_.FullCommand():
		go func() {
			sig := <-signals
			switch sig {
			case syscall.SIGINT:
				os.Exit(int(syscall.SIGINT))
			case syscall.SIGTERM:
				os.Exit(int(syscall.SIGTERM))
			}
		}()

		benchmark.Benchmark(*bmMasterHost, *bmMasterPort, *bmConcurrent, *bmNum, int(*bmSize))
	case check_.FullCommand():
		check.Check(*cPath)
	}
}

func getFreeTcpPort(start, end int) (int, error) {
	for i := start; i < end; i++ {
		if ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", i)); err == nil {
			ln.Close()
			return ln.Addr().(*net.TCPAddr).Port, nil
		}
	}
	return 0, fmt.Errorf("can't get a free port between [%d, %d)", start, end)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"net/http"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/jacksontj/dnms/mapper"
	"github.com/jacksontj/memberlist"
)

func main() {
	// Some CLI args for better testing

	advertiseStr := flag.String("gossipAddr", "", "address to advertise gossip on")
	peerStr := flag.String("peer", "", "address to gossip with")

	flag.Parse()

	m := mapper.NewMapper()
	m.Start()

	// #TODO: load from a config file
	cfg := memberlist.DefaultLANConfig()

	delegate := NewDNMSDelegate(m)
	cfg.Delegate = delegate
	cfg.Events = delegate

	// TODO: load from config
	cfg.BindPort = 33434
	cfg.AdvertisePort = 33434

	if *advertiseStr != "" {
		cfg.AdvertiseAddr = *advertiseStr
		logrus.Infof("addr: %v", *advertiseStr)
	}

	mlist, err := memberlist.Create(cfg)
	delegate.Mlist = mlist

	if err != nil {
		logrus.Fatalf("Unable to create memberlist: %v", err)
	}

	mlist.Join([]string{*peerStr})

	// start the pinger
	p := Pinger{
		M: m,
		Self: mapper.Peer{
			Name: mlist.LocalNode().Addr.String(),
			Port: int(mlist.LocalNode().Port),
		},
	}
	p.Start()

	// TODO: API endpoint
	// Create helpful HTTP endpoint for debugging
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ret, err := json.Marshal(m.RouteMap.NodeRouteMap)
		if err != nil {
			logrus.Errorf("Unable to marshal graph: %v", err)
		} else {
			w.Header().Set("Content-Type", "application/json")
			w.Write(ret)
		}
	})

	go http.ListenAndServe(":12345", nil)

	for {
		time.Sleep(time.Second)
		logrus.Infof("peers=%d nodes=%d links=%d routes=%d",
			mlist.NumMembers()-1,
			m.Graph.GetNodeCount(),
			m.Graph.GetLinkCount(),
			m.Graph.GetRouteCount(),
		)
	}

}
<commit_msg>Misc code cleanup in main<commit_after>package main

import (
	"encoding/json"
	"flag"
	"net/http"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/jacksontj/dnms/mapper"
	"github.com/jacksontj/memberlist"
)

func main() {
	// Some CLI args for better testing

	advertiseStr := flag.String("gossipAddr", "", "address to advertise gossip on")
	peerStr := flag.String("peer", "", "address to gossip with")

	flag.Parse()

	// Start the mapper (at this point no peers-- so it will do nothing)
	m := mapper.NewMapper()
	m.Start()

	// #TODO: load from a config file
	cfg := memberlist.DefaultLANConfig()

	// Wire up the delegate-- he'll handle pings and node up/down events
	delegate := NewDNMSDelegate(m)
	cfg.Delegate = delegate
	cfg.Events = delegate

	// TODO: load from config
	cfg.BindPort = 33434
	cfg.AdvertisePort = 33434
	if *advertiseStr != "" {
		cfg.AdvertiseAddr = *advertiseStr
		logrus.Infof("addr: %v", *advertiseStr)
	}

	// Create the memberlist with the config we just made
	mlist, err := memberlist.Create(cfg)
	delegate.Mlist = mlist
	if err != nil {
		logrus.Fatalf("Unable to create memberlist: %v", err)
	}

	// TODO: background thing to join if we end up alone?
	// Join if we can
	mlist.Join([]string{*peerStr})

	// start the pinger
	p := Pinger{
		M: m,
		Self: mapper.Peer{
			Name: mlist.LocalNode().Addr.String(),
			Port: int(mlist.LocalNode().Port),
		},
	}
	p.Start()

	// TODO: API endpoint
	// Create helpful HTTP endpoint for debugging
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ret, err := json.Marshal(m.RouteMap.NodeRouteMap)
		if err != nil {
			logrus.Errorf("Unable to marshal graph: %v", err)
		} else {
			w.Header().Set("Content-Type", "application/json")
			w.Write(ret)
		}
	})
	go http.ListenAndServe(":12345", nil)

	// print state of the world for ease of debugging
	for {
		time.Sleep(time.Second)
		logrus.Infof("peers=%d nodes=%d links=%d routes=%d",
			mlist.NumMembers()-1,
			m.Graph.GetNodeCount(),
			m.Graph.GetLinkCount(),
			m.Graph.GetRouteCount(),
		)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/spf13/cobra"

	"github.com/hellofresh/kandalf/cmd"
)

var (
	version     string
	configPath  string
	versionFlag bool
)

func main() {
	versionString := "Kandalf v" + version
	cobra.OnInitialize(func() {
		if versionFlag {
			fmt.Println(versionString)
			os.Exit(0)
		}
	})

	var RootCmd = &cobra.Command{
		Use:   "kandalf",
		Short: versionString,
		Long: versionString + `. RabbitMQ to Kafka bridge.

Complete documentation is available at https://github.com/hellofresh/kandalf`,
		RunE: func(c *cobra.Command, args []string) error {
			return cmd.RunApp(version, configPath)
		},
	}
	RootCmd.Flags().StringVarP(&configPath, "config", "c", "", "Source of a configuration file")
	RootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "Print application version")

	err := RootCmd.Execute()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Use built-in cobra version parameter<commit_after>package main

import (
	"log"

	"github.com/spf13/cobra"

	"github.com/hellofresh/kandalf/cmd"
)

var (
	version    string
	configPath string
)

func main() {
	var RootCmd = &cobra.Command{
		Use:     "kandalf",
		Version: version,
		Short:   `RabbitMQ to Kafka bridge.`,
		Long: `RabbitMQ to Kafka bridge.

Complete documentation is available at https://github.com/hellofresh/kandalf`,
		RunE: func(c *cobra.Command, args []string) error {
			return cmd.RunApp(version, configPath)
		},
	}
	RootCmd.Flags().StringVarP(&configPath, "config", "c", "", "Source of a configuration file")

	err := RootCmd.Execute()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"log"
	"net/http"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	httpPort = flag.Uint("http-port", 8080, "http port to run on")
)

var (
	boundry = "spiderman"
	m       = image.NewRGBA(image.Rect(0, 0, 800, 800))
	mut     = sync.RWMutex{}

	numOnline int64

	bc = newBroadcast()
)

func init() {
	flag.Parse()
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	fmt.Fprint(w, `
<form target="frame" method="get" action="/click">

Color

	<input type="color" name="color" value="#e66465">

Size

	<input type="range" name="size" min="1" max="99" value="10">
		<input type="image" name="imgbtn" src="/image">

</form>`)
}

func mjpegHandler(w http.ResponseWriter, r *http.Request) {
	atomic.AddInt64(&numOnline, 1)

	n, ok := w.(http.CloseNotifier)
	if !ok {
		http.Error(w, "cannot stream - no closer", http.StatusInternalServerError)
		return
	}

	f, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "cannot stream - no flush", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Cache-Control", "private")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Content-type", "multipart/x-mixed-replace; boundary="+boundry)

	datac := bc.Register()

	data := imgbytes()
	for i := 0; i <= 10; i++ {
		writeFrame(w, data)
		f.Flush()
	}
	fmt.Println("...")

	for {

		t := time.NewTimer(5 * time.Second)

		select {
		case data = <-datac:
			for i := 0; i <= 1; i++ {
				writeFrame(w, data)
				f.Flush()
			}
		case <-n.CloseNotify():
			atomic.AddInt64(&numOnline, -1)
			fmt.Println("...closed")

			bc.Clear(datac)

			return
		case <-t.C:
			writeFrame(w, data)
			f.Flush()
		}

	}
}

func writeFrame(w http.ResponseWriter, data []byte) {
	fmt.Fprintf(w, "--%s\n", boundry)
	fmt.Fprint(w, "Content-Type: image/jpeg\n\n")
	w.Write(data)
	fmt.Fprint(w, "\n\n")
}

func clickHandler(w http.ResponseWriter, r *http.Request) {
	x, err := strconv.Atoi(r.FormValue("imgbtn.x"))
	if err != nil {
		http.Error(w, "invalid int for x", 400)
		return
	}

	y, err := strconv.Atoi(r.FormValue("imgbtn.y"))
	if err != nil {
		http.Error(w, "invalid int for y", 400)
		return
	}

	c := color.RGBA{255, 255, 0, 255}

	s, err := strconv.Atoi(r.FormValue("size"))
	if err != nil {
		http.Error(w, "invalid int for size", 400)
		return
	}

	if s < 0 || s > 100 {
		http.Error(w, "invalid size", 400)
		return
	}

	fc := r.FormValue("color")
	if fc != "" {
		if len(fc) != 7 || fc[0] != '#' {
			http.Error(w, "invalid color", 400)
			return
		}

		cr, err1 := strconv.ParseUint(fc[1:3], 16, 8)
		cg, err2 := strconv.ParseUint(fc[3:5], 16, 8)
		cb, err3 := strconv.ParseUint(fc[5:7], 16, 8)

		if err1 != nil || err2 != nil || err3 != nil {
			http.Error(w, "invalid color", 400)
			return
		}

		c = color.RGBA{uint8(cr), uint8(cg), uint8(cb), 255}
	}

	mut.Lock()
	for xx := 0 - s; xx <= s; xx++ {
		for yy := 0 - s; yy <= s; yy++ {
			m.Set(x+xx, y+yy, c)
		}
	}
	mut.Unlock()

	bc.Broadcast(imgbytes())

	fmt.Println(x, y)
	w.WriteHeader(http.StatusNoContent)

}

func imgbytes() []byte {
	mut.Lock()
	defer mut.Unlock()

	var bb bytes.Buffer
	jpeg.Encode(&bb, m, &jpeg.Options{Quality: 70})
	return bb.Bytes()
}

func main() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/click", clickHandler)
	http.HandleFunc("/image", mjpegHandler)

	go func() {
		for {
			log.Println(atomic.LoadInt64(&numOnline), " users online")
			time.Sleep(10 * time.Second)
		}
	}()

	err := http.ListenAndServe(fmt.Sprintf(":%d", *httpPort), nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Makes the log output just a little bit nicer<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"log"
	"net/http"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	httpPort = flag.Uint("http-port", 8080, "http port to run on")
)

var (
	boundry = "spiderman"
	m       = image.NewRGBA(image.Rect(0, 0, 800, 800))
	mut     = sync.RWMutex{}

	numOnline int64

	bc = newBroadcast()
)

func init() {
	flag.Parse()
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	fmt.Fprint(w, `
<form target="frame" method="get" action="/click">

Color

	<input type="color" name="color" value="#e66465">

Size

	<input type="range" name="size" min="1" max="99" value="10">
		<input type="image" name="imgbtn" src="/image">

</form>`)
}

func mjpegHandler(w http.ResponseWriter, r *http.Request) {
	atomic.AddInt64(&numOnline, 1)

	n, ok := w.(http.CloseNotifier)
	if !ok {
		http.Error(w, "cannot stream - no closer", http.StatusInternalServerError)
		return
	}

	f, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "cannot stream - no flush", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Cache-Control", "private")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Content-type", "multipart/x-mixed-replace; boundary="+boundry)

	datac := bc.Register()

	data := imgbytes()
	for i := 0; i <= 10; i++ {
		writeFrame(w, data)
		f.Flush()
	}
	fmt.Println("...")

	for {

		t := time.NewTimer(5 * time.Second)

		select {
		case data = <-datac:
			for i := 0; i <= 1; i++ {
				writeFrame(w, data)
				f.Flush()
			}
		case <-n.CloseNotify():
			atomic.AddInt64(&numOnline, -1)
			fmt.Println("...closed")

			bc.Clear(datac)

			return
		case <-t.C:
			writeFrame(w, data)
			f.Flush()
		}

	}
}

func writeFrame(w http.ResponseWriter, data []byte) {
	fmt.Fprintf(w, "--%s\n", boundry)
	fmt.Fprint(w, "Content-Type: image/jpeg\n\n")
	w.Write(data)
	fmt.Fprint(w, "\n\n")
}

func clickHandler(w http.ResponseWriter, r *http.Request) {
	x, err := strconv.Atoi(r.FormValue("imgbtn.x"))
	if err != nil {
		http.Error(w, "invalid int for x", 400)
		return
	}

	y, err := strconv.Atoi(r.FormValue("imgbtn.y"))
	if err != nil {
		http.Error(w, "invalid int for y", 400)
		return
	}

	c := color.RGBA{255, 255, 0, 255}

	s, err := strconv.Atoi(r.FormValue("size"))
	if err != nil {
		http.Error(w, "invalid int for size", 400)
		return
	}

	if s < 0 || s > 100 {
		http.Error(w, "invalid size", 400)
		return
	}

	fc := r.FormValue("color")
	if fc != "" {
		if len(fc) != 7 || fc[0] != '#' {
			http.Error(w, "invalid color", 400)
			return
		}

		cr, err1 := strconv.ParseUint(fc[1:3], 16, 8)
		cg, err2 := strconv.ParseUint(fc[3:5], 16, 8)
		cb, err3 := strconv.ParseUint(fc[5:7], 16, 8)

		if err1 != nil || err2 != nil || err3 != nil {
			http.Error(w, "invalid color", 400)
			return
		}

		c = color.RGBA{uint8(cr), uint8(cg), uint8(cb), 255}
	}

	mut.Lock()
	for xx := 0 - s; xx <= s; xx++ {
		for yy := 0 - s; yy <= s; yy++ {
			m.Set(x+xx, y+yy, c)
		}
	}
	mut.Unlock()

	bc.Broadcast(imgbytes())

	fmt.Println(x, y)
	w.WriteHeader(http.StatusNoContent)

}

func imgbytes() []byte {
	mut.Lock()
	defer mut.Unlock()

	var bb bytes.Buffer
	jpeg.Encode(&bb, m, &jpeg.Options{Quality: 70})
	return bb.Bytes()
}

func main() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/click", clickHandler)
	http.HandleFunc("/image", mjpegHandler)

	go func() {
		var lastOnline int64
		for {
			online := atomic.LoadInt64(&numOnline)
			if online != lastOnline {
				log.Println(online, " users online")
			}
			time.Sleep(time.Second / 2)
			lastOnline = online
		}
	}()

	err := http.ListenAndServe(fmt.Sprintf(":%d", *httpPort), nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>