diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/aws.xml b/.idea/aws.xml new file mode 100644 index 0000000000000000000000000000000000000000..ec328d0bbf68db9e7322932181cc811412e3ca87 --- /dev/null +++ b/.idea/aws.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="accountSettings"> + <option name="activeProfile" value="profile:default" /> + <option name="activeRegion" value="eu-west-1" /> + <option name="recentlyUsedProfiles"> + <list> + <option value="profile:default" /> + </list> + </option> + <option name="recentlyUsedRegions"> + <list> + <option value="eu-west-1" /> + </list> + </option> + </component> +</project> \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000000000000000000000000000000000000..ec0b30fa7ea2824af6923493653e32595b0907a8 --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="MarkdownSettings"> + <enabledExtensions> + <entry key="MermaidLanguageExtension" value="false" /> + <entry key="PlantUMLLanguageExtension" value="true" /> + </enabledExtensions> + </component> +</project> \ No newline at end of file diff --git a/.idea/minerva.iml b/.idea/minerva.iml new file mode 100644 index 0000000000000000000000000000000000000000..25ed3f6e7b6e344b6ca91ebcc5d005f35357f9cf --- /dev/null +++ b/.idea/minerva.iml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="Go" enabled="true" /> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..639900d13c6182e452e33a3bd638e70a0146c785 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..6e6dd9acbdd939bf1c110062e928a9ee7c27aa96 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/minerva.iml" filepath="$PROJECT_DIR$/.idea/minerva.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/runConfigurations/minerva_serve.xml b/.idea/runConfigurations/minerva_serve.xml new file mode 100644 index 0000000000000000000000000000000000000000..06ff786f0a6d681a6672e8d11c78f705321c6f58 --- /dev/null +++ b/.idea/runConfigurations/minerva_serve.xml @@ -0,0 +1,12 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="minerva serve" type="GoApplicationRunConfiguration" factoryName="Go Application"> + <module name="minerva" /> + <working_directory value="$PROJECT_DIR$/application/source" /> + <parameters value="serve --config=../../development/examples/theme1/config.yaml" /> + <kind value="DIRECTORY" /> + <directory value="$PROJECT_DIR$/application/source" /> + <filePath value="$PROJECT_DIR$" /> + <output_directory value="$PROJECT_DIR$/development/build" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/minerva_version.xml b/.idea/runConfigurations/minerva_version.xml new file mode 100644 index 0000000000000000000000000000000000000000..14b3ed5a4e4296ef48f7adde2054a31c61cdbe63 --- /dev/null +++ b/.idea/runConfigurations/minerva_version.xml @@ -0,0 +1,12 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="minerva version" type="GoApplicationRunConfiguration" factoryName="Go Application"> + <module name="minerva" /> + <working_directory value="$PROJECT_DIR$/application/source" /> + <parameters value="version" /> + <kind value="DIRECTORY" /> + <directory value="$PROJECT_DIR$/application/source" /> + <filePath value="$PROJECT_DIR$" /> + <output_directory value="$PROJECT_DIR$/development/build" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/application/source/command/command.go b/application/source/command/command.go new file mode 100644 index 0000000000000000000000000000000000000000..a3518ff07b79ccb6f2ab20f38846bb171f2182ad --- /dev/null +++ b/application/source/command/command.go @@ -0,0 +1,33 @@ +package command + +import ( + "github.com/jessevdk/go-flags" + "gitlab.schukai.com/oss/minerva/config" + "gitlab.schukai.com/oss/minerva/utils" +) + +var parser *flags.Parser + +func GetParser() *flags.Parser { + + if parser == nil { + intiParser() + } + + return parser +} + +func intiParser() { + + def := new(options) + parser = flags.NewParser(def, flags.Default) + _, err := parser.Parse() + if err != nil { + utils.Exit(1) + } + + if def.Config != "" { + config.InitializeConfigFromFile(def.Config) + } + +} diff --git a/application/source/command/definition.go b/application/source/command/definition.go new file mode 100644 index 0000000000000000000000000000000000000000..f295b880677a131a63a16c6536a4398377a6a263 --- /dev/null +++ b/application/source/command/definition.go @@ -0,0 +1,28 @@ +package command + +type options struct { + Config string `short:"l" long:"config" description:"Path to the configuration file"` + Version struct { + } `command:"version"` + Serve struct { + } `command:"serve"` +} + +//// DebugLevel logs are typically voluminous, and are usually disabled in production. +// DebugLevel = zapcore.DebugLevel +//// InfoLevel is the default logging priority. +// InfoLevel = zapcore.InfoLevel +//// WarnLevel logs are more important than Info, but don't need individual +//// human review. +// WarnLevel = zapcore.WarnLevel +//// ErrorLevel logs are high-priority. If an application is running smoothly, +//// it shouldn't generate any error-level logs. +// ErrorLevel = zapcore.ErrorLevel +//// DPanicLevel logs are particularly important errors. In development the +//// logger panics after writing the message. +// DPanicLevel = zapcore.DPanicLevel +//// PanicLevel logs a message, then panics. +// PanicLevel = zapcore.PanicLevel +//// FatalLevel logs a message, then calls os.Exit(1). +// FatalLevel = zapcore.FatalLevel +// ALL > TRACE > DEBUG > INFO > WARN > ERROR > FATAL > OFF diff --git a/application/source/command/execute.go b/application/source/command/execute.go new file mode 100644 index 0000000000000000000000000000000000000000..97046d0e32fb686cbaf3482e3f070343dff06de0 --- /dev/null +++ b/application/source/command/execute.go @@ -0,0 +1,20 @@ +package command + +func Do() { + + parser := GetParser() + + active := parser.Command.Active + if active == nil { + return + } + + switch active.Name { + case "version": + printVersion() + + case "serve": + serve(active) + + } +} diff --git a/application/source/command/serve.go b/application/source/command/serve.go new file mode 100644 index 0000000000000000000000000000000000000000..b7c0e3c6dc252bc139cbdd76b1bb3bba49163e42 --- /dev/null +++ b/application/source/command/serve.go @@ -0,0 +1,11 @@ +package command + +import ( + "github.com/jessevdk/go-flags" + "gitlab.schukai.com/oss/minerva/server" +) + +func serve(command *flags.Command) { + server.Serve() + +} diff --git a/application/source/command/version.go b/application/source/command/version.go new file mode 100644 index 0000000000000000000000000000000000000000..ff7e5ae4c235e1c54418c9d648b0796fabc7c675 --- /dev/null +++ b/application/source/command/version.go @@ -0,0 +1,10 @@ +package command + +import ( + "fmt" + "gitlab.schukai.com/oss/minerva/utils" +) + +func printVersion() { + fmt.Println(utils.GetVersionString()) +} diff --git a/application/source/config/config.go b/application/source/config/config.go new file mode 100644 index 0000000000000000000000000000000000000000..25aa22cc1fe1656c85707567db41c2a22e6bb17f --- /dev/null +++ b/application/source/config/config.go @@ -0,0 +1,117 @@ +package config + +import ( + "github.com/kelseyhightower/envconfig" + "gitlab.schukai.com/oss/minerva/utils" + "gopkg.in/yaml.v3" + "os" + "path" +) + +func GetServerPort() string { + return configuration.Server.Port +} + +type Configuration struct { + //LogLevel string `yaml:"logLevel" envconfig:"LOG_LEVEL"` + + Server struct { + Port string `yaml:"Port" envconfig:"SERVER_PORT" default:"80"` + } `yaml:"Server"` + + Paths struct { + Web string `yaml:"Web" envconfig:"PATH_WEB" default:"/srv/web/"` + } `yaml:"Paths"` +} + +var configuration *Configuration + +func GetConfiguration() *Configuration { + + if configuration == nil { + intiConfiguration() + readEnv() + } + + return configuration +} + +func InitializeConfigFromFile(filename string) { + readFile(filename) +} + +func intiConfiguration() { + + current, err := os.Getwd() + if err == nil { + if readConfig(current) { + return + } + + } + + home, err := os.UserHomeDir() + if err == nil { + c := path.Join(home, "minerva", ".config") + if readConfig(c) { + return + } + } + + c := "/etc/minerva/.config" + if readConfig(c) { + return + } + + configuration = &Configuration{} + +} + +func readConfig(directory string) (found bool) { + + found = false + + if !utils.DirectoryExists(directory) { + return + } + + filename := path.Clean(path.Join(directory, "config.yaml")) + if utils.FileExists(filename) { + readFile(filename) + found = true + return + } + + return +} + +func readFile(filename string) { + + data, err := os.ReadFile(filename) + if err != nil { + utils.PrintErrorAndExit(err.Error()) + } + + defer func() { + if err := recover(); err != nil { + utils.PrintErrorAndExit("the configuration %s could not be read (%s).", filename, err) + } + }() + + c := Configuration{} + err = yaml.Unmarshal([]byte(data), &c) + + configuration = &c + + if err != nil { + utils.PrintErrorAndExit(err.Error()) + } +} + +func readEnv() { + + err := envconfig.Process("", configuration) + if err != nil { + utils.PrintErrorAndExit(err.Error()) + } +} diff --git a/application/source/go.mod b/application/source/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..2ff5c87943b0ec66d84ef994acaf9c609f47eb77 --- /dev/null +++ b/application/source/go.mod @@ -0,0 +1,22 @@ +module gitlab.schukai.com/oss/minerva + +go 1.18 + +require ( + github.com/go-playground/locales v0.14.0 + github.com/go-playground/universal-translator v0.18.0 + github.com/gookit/color v1.5.0 + github.com/jessevdk/go-flags v1.5.0 + github.com/kelseyhightower/envconfig v1.4.0 + go.uber.org/zap v1.21.0 + gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 +) + +require ( + github.com/go-chi/chi/v5 v5.0.7 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect +) diff --git a/application/source/go.sum b/application/source/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..152d9388bf935cf3c59b11d2a23c453216d114fc --- /dev/null +++ b/application/source/go.sum @@ -0,0 +1,82 @@ +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 h1:dbuHpmKjkDzSOMKAWl10QNlgaZUd3V1q99xc81tt2Kc= +gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/application/source/main.go b/application/source/main.go new file mode 100644 index 0000000000000000000000000000000000000000..1bb60e82bd6ab534dcfb1b4848904553113ac6bb --- /dev/null +++ b/application/source/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "gitlab.schukai.com/oss/minerva/command" + "gitlab.schukai.com/oss/minerva/utils" +) + +func main() { + + utils.Setup() + command.Do() + +} diff --git a/application/source/server/header.go b/application/source/server/header.go new file mode 100644 index 0000000000000000000000000000000000000000..7a720bf14d570715d133054c5d6ccb1da96da50c --- /dev/null +++ b/application/source/server/header.go @@ -0,0 +1,111 @@ +package server + +import ( + "context" + "net/http" + "net/textproto" +) + +const ( + Accept = "Accept" + AcceptCharset = "Accept-Charset" + AcceptEncoding = "Accept-Encoding" + AcceptLanguage = "Accept-Language" + Authorization = "Authorization" + CacheControl = "Cache-Control" + ContentLength = "Content-Length" + ContentMD5 = "Content-MD5" + ContentType = "Content-Type" + DoNotTrack = "DNT" + IfMatch = "If-Match" + IfModifiedSince = "If-Modified-Since" + IfNoneMatch = "If-None-Match" + IfRange = "If-Range" + IfUnmodifiedSince = "If-Unmodified-Since" + MaxForwards = "Max-Forwards" + ProxyAuthorization = "Proxy-Authorization" + Pragma = "Pragma" + Range = "Range" + Referer = "Referer" + UserAgent = "User-Agent" + TE = "TE" + Via = "Via" + Warning = "Warning" + Cookie = "Cookie" + Origin = "Origin" + AcceptDatetime = "Accept-Datetime" + XRequestedWith = "X-Requested-With" + AccessControlAllowOrigin = "Access-Control-Allow-Origin" + AccessControlAllowMethods = "Access-Control-Allow-Methods" + AccessControlAllowHeaders = "Access-Control-Allow-Headers" + AccessControlAllowCredentials = "Access-Control-Allow-Credentials" + AccessControlExposeHeaders = "Access-Control-Expose-Headers" + AccessControlMaxAge = "Access-Control-Max-Age" + AccessControlRequestMethod = "Access-Control-Request-Method" + AccessControlRequestHeaders = "Access-Control-Request-Headers" + AcceptPatch = "Accept-Patch" + AcceptRanges = "Accept-Ranges" + Allow = "Allow" + ContentEncoding = "Content-Encoding" + ContentLanguage = "Content-Language" + ContentLocation = "Content-Location" + ContentDisposition = "Content-Disposition" + ContentRange = "Content-Range" + ETag = "ETag" + Expires = "Expires" + LastModified = "Last-Modified" + Link = "Link" + Location = "Location" + P3P = "P3P" + ProxyAuthenticate = "Proxy-Authenticate" + Refresh = "Refresh" + RetryAfter = "Retry-After" + Server = "Server" + SetCookie = "Set-Cookie" + StrictTransportSecurity = "Strict-Transport-Security" + TransferEncoding = "Transfer-Encoding" + Upgrade = "Upgrade" + Vary = "Vary" + WWWAuthenticate = "WWW-Authenticate" + + // Non-Standard + XFrameOptions = "X-Frame-Options" + XXSSProtection = "X-XSS-Protection" + ContentSecurityPolicy = "Content-Security-Policy" + XContentSecurityPolicy = "X-Content-Security-Policy" + XWebKitCSP = "X-WebKit-CSP" + XContentTypeOptions = "X-Content-Type-Options" + XPoweredBy = "X-Powered-By" + XUACompatible = "X-UA-Compatible" + XForwardedProto = "X-Forwarded-Proto" + XHTTPMethodOverride = "X-HTTP-Method-Override" + XForwardedFor = "X-Forwarded-For" + XRealIP = "X-Real-IP" + XCSRFToken = "X-CSRF-Token" + XRatelimitLimit = "X-Ratelimit-Limit" + XRatelimitRemaining = "X-Ratelimit-Remaining" + XRatelimitReset = "X-Ratelimit-Reset" + XAlvineRequestID = "X-Alvine-Request-Id" +) + +// Normalize formats the input header to the formation of "Xxx-Xxx". +func Normalize(header string) string { + return textproto.CanonicalMIMEHeaderKey(header) +} + +func ApplicationJsonHeader(w http.ResponseWriter) { + w.Header().Set(ContentType, "application/json") +} + +// RequestIDMiddleware is a middleware that injects a request ID into the context of each +// request. A request ID is a uuid-string. +func RequestIDMiddleware(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + requestID := NewRequestUUID() + w.Header().Set(XAlvineRequestID, requestID.String()) + ctx = context.WithValue(ctx, XAlvineRequestID, &requestID) + next.ServeHTTP(w, r.WithContext(ctx)) + } + return http.HandlerFunc(fn) +} diff --git a/application/source/server/logger.go b/application/source/server/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..d920f74b1ce12401fce3afae9c327520d12ce6b6 --- /dev/null +++ b/application/source/server/logger.go @@ -0,0 +1,74 @@ +package server + +import ( + "github.com/go-chi/chi/v5/middleware" + "gitlab.schukai.com/oss/minerva/utils" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "net/http" + "time" +) + +var ( + logger *zap.Logger + sugar *zap.SugaredLogger +) + +func initLogger() { + + var mode string + + if utils.IsSnapshot() { + logger, _ = zap.NewDevelopment() + mode = "development" + } else { + logger, _ = zap.NewProduction() + mode = "production" + } + + defer logger.Sync() // flushes buffer, if any + + sugar = logger.Sugar() + sugar.Infof("init %s logger", mode) + +} + +func logInfo(template string, args ...interface{}) { + sugar.Infof(template, args) +} + +func logError(template string, args ...interface{}) { + sugar.Errorf(template, args) +} + +func loggerMiddleware(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) + next.ServeHTTP(ww, r) + + ctx := r.Context() + requestIDString := "" + requestID, ok := ctx.Value(XAlvineRequestID).(RequestUUID) + if ok { + requestIDString = requestID.String() + } + + latency := time.Since(start) + + fields := []zapcore.Field{ + zap.Int("status", ww.Status()), + zap.String("request-id", requestIDString), + zap.Duration("took", latency), + zap.Int64("measure.latency", latency.Nanoseconds()), + zap.String("remote", r.RemoteAddr), + zap.String("request", r.RequestURI), + zap.String("method", r.Method), + } + + logger.Info("request completed", fields...) + + } + + return http.HandlerFunc(fn) +} diff --git a/application/source/server/request-id.go b/application/source/server/request-id.go new file mode 100644 index 0000000000000000000000000000000000000000..de11fcd4b7ad012bce6c503945eb7bf11718cfa7 --- /dev/null +++ b/application/source/server/request-id.go @@ -0,0 +1,19 @@ +package server + +import ( + "github.com/google/uuid" +) + +type RequestUUID uuid.UUID + +func NewRequestUUID() RequestUUID { + return RequestUUID(uuid.New()) +} + +func (this RequestUUID) UUID() uuid.UUID { + return uuid.UUID(this) +} + +func (this RequestUUID) String() string { + return this.UUID().String() +} diff --git a/application/source/server/serve.go b/application/source/server/serve.go new file mode 100644 index 0000000000000000000000000000000000000000..47ff91db19f861a1a71e6d630e4c7af233c0c9ac --- /dev/null +++ b/application/source/server/serve.go @@ -0,0 +1,130 @@ +package server + +import ( + "context" + "crypto/tls" + "embed" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "gitlab.schukai.com/oss/minerva/config" + "net/http" + "sync" +) + +var ( + server http.Server + //go:embed web/* + embeddedFiles embed.FS +) + +func lookUp(path string) (content []byte) { + // Zuerst im Verzeichnis /web/asserts schauen (wird beim build inkludiert) + c, _ := embeddedFiles.ReadFile("web" + path) + if len(c) > 0 { + return c + } + + return nil +} + +func serveStaticFiles(next http.Handler) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + + content := lookUp(r.URL.Path) + if len(content) > 0 { + w.Write(content) + return + } + + next.ServeHTTP(w, r) + } +} + +const waitGroupContextKey = "wait.group" + +func waitGroupMiddleware() func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var wg sync.WaitGroup + next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), waitGroupContextKey, wg))) + wg.Wait() + }) + } +} + +func initRouting() *chi.Mux { + + /** x509: certificate signed by unknown authority */ + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + mux := chi.NewRouter() + + mux.Use(waitGroupMiddleware()) + + mux.Use(RequestIDMiddleware) + mux.Use(middleware.RealIP) + mux.Use(middleware.Heartbeat("/ping")) + + mux.Use(middleware.Compress(5)) + mux.Use(middleware.AllowContentType("application/json", "text/html")) + mux.Use(loggerMiddleware) + + // mux.Mount("/api/v1", v1.V1Api(cfg)) + + //mux.Get("/", func(w http.ResponseWriter, r *http.Request) { + // if negotiator.New(r.Header).Type("text/html") == "text/html" { + // http.Redirect(w, r, "https://www.alvine.cloud/en/products/media-services/juno/", http.StatusPermanentRedirect) + // } else { + // error2.StandardErrorResponse(w, r, + // error2.ErrorResponse{ + // Status: http.StatusNotFound, + // Hint: "did you want to call the juno-api? have a look at https://www.alvine.cloud/en/products/media-services/juno/documentation/", + // }) + // } + // + //}) + // + //p := cfg.Paths.Web + //zap.S().Info("use webpath " + p + "for static-file-server") + // + //if cfg.Server.Port == "" { + // zap.S().Error("missing server address") + // return nil + //} + + //d := http.Dir(p) + //mux.Get("/*", + // serveStaticFiles(fileserver.FileServerWith404(d, func(w http.ResponseWriter, r *http.Request) (doDefaultFileServe bool) { + // error2.StandardErrorResponse(w, r, error2.ErrorResponse{ + // Status: 404, + // }) + // return false + // + // }))) + + return mux + +} + +func Serve() { + initLogger() + + mux := initRouting() + + c := config.GetConfiguration() + + address := ":" + c.Server.Port + logInfo("server listen on address %s", address) + + server := http.Server{ + Handler: mux, + Addr: address, + } + + if err := server.ListenAndServe(); err != nil { + logError("server error %s", err.Error()) + } + + logInfo("server quit") + +} diff --git a/application/source/server/web/robots.txt b/application/source/server/web/robots.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/application/source/utils/exit.go b/application/source/utils/exit.go new file mode 100644 index 0000000000000000000000000000000000000000..a8bb30dd009ec8257277a45612e64f098870bddb --- /dev/null +++ b/application/source/utils/exit.go @@ -0,0 +1,40 @@ +package utils + +import ( + "github.com/gookit/color" + "os" +) + +func Exit(code int) { + os.Exit(code) +} + +var lastBlock string + +func PrintErrorAndExit(message string, a ...interface{}) { + PrintError(message, a...) + os.Exit(1) +} + +func PrintError(message string, a ...interface{}) { + + if lastBlock == "error" { + color.Error.Println("\t"+message, a) + return + } + + lastBlock = "error" + color.Error.Block(message, a...) + +} + +func PrintWarning(message string, a ...interface{}) { + + if lastBlock == "warning" { + color.Warn.Println("\t"+message, a) + return + } + + lastBlock = "warning" + color.Warn.Block(message, a...) +} diff --git a/application/source/utils/file.go b/application/source/utils/file.go new file mode 100644 index 0000000000000000000000000000000000000000..b7dca39a1a4016f260654371fc8485c09c8dbf0b --- /dev/null +++ b/application/source/utils/file.go @@ -0,0 +1,17 @@ +package utils + +import "os" + +func FileExists(name string) (found bool) { + if f, err := os.Stat(name); err == nil { + return f.Mode().IsRegular() + } + return false +} + +func DirectoryExists(name string) (found bool) { + if f, err := os.Stat(name); err == nil { + return f.Mode().IsDir() + } + return false +} diff --git a/application/source/utils/i18n.go b/application/source/utils/i18n.go new file mode 100644 index 0000000000000000000000000000000000000000..f3b62501f1fd75beae8b7b908a52b4f795ac6879 --- /dev/null +++ b/application/source/utils/i18n.go @@ -0,0 +1,79 @@ +package utils + +import ( + "github.com/go-playground/locales/de" + "github.com/go-playground/locales/en" + ut "github.com/go-playground/universal-translator" + "os" + "os/exec" + "runtime" + "strings" +) + +// only one instance as translators within are shared + goroutine safe +var ( + universalTraslator *ut.UniversalTranslator + Translator ut.Translator +) + +func setupI18n() { + + e := en.New() + universalTraslator = ut.New(e, e, de.New()) + + lang, _ := initLocale() + + var found bool + Translator, found = universalTraslator.GetTranslator(lang) + if !found { + + } + +} + +func initLocale() (string, string) { + + osHost := runtime.GOOS + defaultLang := "en" + defaultLoc := "US" + + switch osHost { + + case "windows": + // Exec powershell Get-Culture on Windows. + cmd := exec.Command("powershell", "Get-Culture | select -exp Name") + output, err := cmd.Output() + if err == nil { + langLocRaw := strings.TrimSpace(string(output)) + langLoc := strings.Split(langLocRaw, "-") + lang := langLoc[0] + loc := langLoc[1] + return lang, loc + } + + case "darwin": + // Exec powershell Get-Culture on MacOS. + cmd := exec.Command("sh", "osascript -e 'user locale of (get system info)'") + output, err := cmd.Output() + if err == nil { + langLocRaw := strings.TrimSpace(string(output)) + langLoc := strings.Split(langLocRaw, "_") + lang := langLoc[0] + loc := langLoc[1] + return lang, loc + } + + case "linux": + envlang, ok := os.LookupEnv("LANG") + if ok { + langLocRaw := strings.TrimSpace(envlang) + langLocRaw = strings.Split(envlang, ".")[0] + langLoc := strings.Split(langLocRaw, "_") + lang := langLoc[0] + loc := langLoc[1] + return lang, loc + } + } + + return defaultLang, defaultLoc +} diff --git a/application/source/utils/setup.go b/application/source/utils/setup.go new file mode 100644 index 0000000000000000000000000000000000000000..17645572b7c86257de1eda5c09d95aacef9f5008 --- /dev/null +++ b/application/source/utils/setup.go @@ -0,0 +1,5 @@ +package utils + +func Setup() { + setupI18n() +} diff --git a/application/source/utils/version.go b/application/source/utils/version.go new file mode 100644 index 0000000000000000000000000000000000000000..87ceee71dd3eb3a9a3a5bdb759d83d290bf9df55 --- /dev/null +++ b/application/source/utils/version.go @@ -0,0 +1,58 @@ +package utils + +import "fmt" + +// -ldflags "-X main.version=$app_version -X main.build=$(due --iso-8601 | tr -d "-" )" +var ( + version string + build string +) + +func printVersion() { + s := "" + if version != "" { + s += version + } + + if build != "" { + s += "(" + build + ")" + } + + if s == "" { + s = "snapshot" + } + + fmt.Println(s) +} + +func IsSnapshot() bool { + if version == "" && build == "" { + return true + } + return false +} + +func GetVersion() string { + return version +} + +func GetBuild() string { + return build +} + +func GetVersionString() string { + s := "" + if version != "" { + s += version + } + + if build != "" { + s += "(" + build + ")" + } + + if s == "" { + s = "snapshot" + } + + return s +} diff --git a/development/build/minerva_serve b/development/build/minerva_serve new file mode 100755 index 0000000000000000000000000000000000000000..1b11d616e1bd28e5a7ac032be5831c27186abde9 Binary files /dev/null and b/development/build/minerva_serve differ diff --git a/development/build/minerva_version b/development/build/minerva_version new file mode 100755 index 0000000000000000000000000000000000000000..036d80af452928f1761f54d01045dff3b7ba9e39 Binary files /dev/null and b/development/build/minerva_version differ diff --git a/development/examples/theme1/config.yaml b/development/examples/theme1/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..00b733cbec9eadc5ae0fe13c4c54500cbf258d60 --- /dev/null +++ b/development/examples/theme1/config.yaml @@ -0,0 +1,2 @@ +Server: + Port: 1212 \ No newline at end of file diff --git a/development/examples/theme1/home.html b/development/examples/theme1/home.html new file mode 100644 index 0000000000000000000000000000000000000000..566549bdf8fae810809c1a81066000687cb338f6 --- /dev/null +++ b/development/examples/theme1/home.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title</title> +</head> +<body> + +</body> +</html> \ No newline at end of file