diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c74ec3d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +test_files/* \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..6d9cf4f --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,20 @@ +builds: + - binary: srvc + ldflags: "-X cmd.version={{.Version}} -X cmd.buildDate={{.Date}} -X cmd.commit={{.Commit}}" + goos: + - windows + - darwin + - linux + goarch: + - amd64 +archive: + replacements: + amd64: 64-bit + darwin: macOS + +brew: + github: + owner: kevingimbel + name: homebrew-tap + homepage: https://github.com/kevingimbel/srvc + description: "Quick API prototyping tool" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..81cc2f8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2018 Kevin Gimbel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..54794ec --- /dev/null +++ b/README.md @@ -0,0 +1,127 @@ +# `srvc` + +`srvc` is a command line tool which allows you to quickly spin up a webserver with configurable routes. These routes can be configured to return HTML pages, XML, JSON, other files, custom headers, and inline-content directly from the config file. + +## How to install + +### Homebrew + +On MacOS you can get the latest version from `brew`. + +```sh +$ brew install kevingimbel/tap/srvc +``` + +### Binary + +Alternatively you can grab the latest release from the [releases page](/releases) and place it somewhere in your `$PATH`. + +## Usage + +```sh +$ srvc +$ srvc [-port 1313] +``` + +`-port` is optional and takes a HTTP port to serve to. The default port is 8080. + +## Config + +`srvc` needs a YAML configuration file in the directory it is executed in. See the sample configuration file in the [example](/example/) directory. + +The same configuration file is shown below. + +```yaml +# global header config, added to each route +headers: + - key: "client" + value: "srvc-alpha1" + +# route based config +routes: +# For the route "/demo/html-page" display the "index.html" file from the "html" fodler + /demo/html-page: + headers: + - key: "Content-Type" + value: "text/html" + file: "./html/index.html" + + # display HTML content defined inline for /demo/html-inline + /demo/html-inline: + headers: + - key: "Content-Type" + value: "text/html" + content: | +
The content is defined inside the srvc.yaml config file
+
+ # Display XML on /demo/xml
+ /demo/xml:
+ headers:
+ - key: "Content-Type"
+ value: "application/xml"
+ content: |
+
This is inline content!
+``` + +This route will respond with a HTML page containing the following code. + +```html +This is inline content!
+``` + +A route can be configured to respond with the content of a file, as shown below. + +```html +routes: + /hello/world/file: + headers: + - key: "custom" + value: "header for route /hello/world" + - key: "Content-Type" + value: "text/html" + file: "./relative/path/to/file.html" +``` + +The route `/hello/world/file` now responds with the contents of the file located at `./relative/path/to/file.html`. \ No newline at end of file diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 0000000..d40c9e6 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,77 @@ +package main + +import ( + "flag" + "fmt" + "os" + "os/signal" + "syscall" + + srvc "github.com/kevingimbel/srvc" +) + +var port string +var versionFlag bool + +var version string +var buildDate string +var commit string + +var usage = `USAGE: %s [-port] + +Arguments: +- port Port number, e.g. 1919, 1313, 1337 +` + +// osSignal captchers signals sent by the OS. This is used to close / exit the program +func osSignal(err chan<- error) { + osc := make(chan os.Signal) + signal.Notify(osc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + err <- fmt.Errorf("%s", <-osc) +} + +func init() { + flag.StringVar(&port, "port", "8080", "Assign a port to serve to") + flag.BoolVar(&versionFlag, "version", false, "Show version") +} + +func main() { + flag.Parse() + + if versionFlag { + fmt.Printf("Version %s", version) + if buildDate != "" { + fmt.Printf("Build date: %s\n", buildDate) + } + + if commit != "" { + fmt.Printf("Commit: %s", commit) + } + os.Exit(0) + } + + // If we have args there's something wrong. + // The only argument is "-port XXXX" which is (removed?) from + // flag.Args() or doesn't count towards it. + if len(flag.Args()) > 0 { + // os.Args[0] is the executable name + fmt.Printf(usage, os.Args[0]) + os.Exit(1) + } + + p := ":" + port + srv := srvc.New(p) + srv.CreateConfiguredHandlers() + + errch := make(chan error) + + go osSignal(errch) + + go func() { + fmt.Println("Server is running on port", port) + errch <- srv.Run() + }() + + exit := <-errch + fmt.Println("Stopping Service. Reason:", exit) +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..7895517 --- /dev/null +++ b/config.go @@ -0,0 +1,50 @@ +package srvc + +import ( + "fmt" + "io/ioutil" + + "gopkg.in/yaml.v2" +) + +var version string + +// Config represents the yaml config +type Config struct { + Headers []Header `yaml:"headers"` + Routes map[string]RouteConfig `yaml:"routes"` +} + +// Header defines +type Header struct { + Key string `yaml:"key"` + Value string `yaml:"value"` +} + +// RouteConfig represents the config for a single route +type RouteConfig struct { + Headers []Header `yaml:"headers"` + Content string `yaml:"content"` + File string `yaml:"file"` +} + +var config Config + +func init() { + f, err := ioutil.ReadFile("./srvc.yaml") + + if err != nil { + fmt.Println("Cannot open file srvc.yaml") + } + + err = yaml.Unmarshal(f, &config) + + if err != nil { + fmt.Println(err) + } +} + +// GetConfig returns the config +func GetConfig() Config { + return config +} diff --git a/example/html/index.html b/example/html/index.html new file mode 100644 index 0000000..a6483dd --- /dev/null +++ b/example/html/index.html @@ -0,0 +1,13 @@ + + + + + + +The srvc
cli tool works if this website can be accessed at localhost:<port|8080>/html/demo, as configured in the srvc.yaml file.
The content is defined inside the srvc.yaml config file
+
+ # Display XML on /demo/xml
+ /demo/xml:
+ headers:
+ - key: "Content-Type"
+ value: "application/xml"
+ content: |
+