mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
able to share static configuration between multiple server instances based on the homepath+iris.yml file with iris.WithGlobalConfiguration configurator
Former-commit-id: 3e528a3d01eb36b4c0781149e52acffd4dc5cf9f
This commit is contained in:
parent
af9a1f1241
commit
7723e438a1
35
HISTORY.md
35
HISTORY.md
|
@ -17,19 +17,48 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
|||
|
||||
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you.
|
||||
|
||||
# Tu, 07 November 2017 | v8.5.7
|
||||
|
||||
Nothing crazy here, just one addition which may help some people;
|
||||
|
||||
Able to share configuration between multiple Iris instances based on the `$home_path+iris.yml` configuration file with the **new** [iris.WithGlobalConfiguration](https://github.com/kataras/iris/blob/master/configuration.go#L202) configurator[*](https://github.com/kataras/iris/blob/master/configuration.go#L191).
|
||||
|
||||
Example:
|
||||
|
||||
```go
|
||||
package main
|
||||
import "github.com/kataras/iris"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("<b>Hello!</b>")
|
||||
})
|
||||
// [...]
|
||||
|
||||
// Good when you share configuration between multiple iris instances.
|
||||
// This configuration file lives in your $HOME/iris.yml for unix hosts
|
||||
// or %HOMEDRIVE%+%HOMEPATH%/iris.yml for windows hosts, and you can modify it.
|
||||
app.Run(iris.Addr(":8080"), iris.WithGlobalConfiguration)
|
||||
// or before run:
|
||||
// app.Configure(iris.WithGlobalConfiguration)
|
||||
// app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
```
|
||||
|
||||
# Su, 05 November 2017 | v8.5.6
|
||||
|
||||
- **DEPRECATE** the `app.StaticServe`, use `app.StaticWeb` which does the same thing but better or `iris/app.StaticHandler` which gives you more options to work on.
|
||||
- add some debug messages for route registrations, to be aligned with the mvc debug messages.
|
||||
- improve the https://iris-go.com/v8/recipe -- now you can see other files like assets as well -- lexical order of categories instead of "level".
|
||||
- add [8 more examples](_examples/tree/master/experimental-handlers) to this repository, originally lived at https://github.com/iris-contrib/middleware and https://github.com/iris-contrib/examples/tree/master/experimental-handlers.
|
||||
- add [8 more examples](_examples/experimental-handlers) to this repository, originally lived at https://github.com/iris-contrib/middleware and https://github.com/iris-contrib/examples/tree/master/experimental-handlers.
|
||||
|
||||
_TODO;_
|
||||
|
||||
- [ ] give the ability to customize the mvc path-method-and path parameters mapping,
|
||||
- [ ] make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.
|
||||
|
||||
# Tu, 02 November 2017 | v8.5.5
|
||||
# Th, 02 November 2017 | v8.5.5
|
||||
|
||||
- fix [audio/mpeg3 does not appear to be a valid registered mime type#798](https://github.com/kataras/iris/issues/798]) reported by @kryptodev,
|
||||
- improve the updater's performance and moved that into the framework itself,
|
||||
|
@ -272,7 +301,7 @@ Another good example with a typical folder structure, that many developers are u
|
|||
- errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
|
||||
- @ZaniaDeveloper fixed https://github.com/kataras/iris/issues/778 with PR: https://github.com/kataras/iris/pull/779.
|
||||
- Add `StatusSeeOther` at [mvc login example](https://github.com/kataras/iris/blob/master/_examples/mvc/login/user/controller.go#L53) for Redirection, reported by @motecshine at https://github.com/kataras/iris/issues/777.
|
||||
- Fix `DisableVersionChecker` configuration field is not being passed correctly when it was true via `iris.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...})` call.
|
||||
- Fix `DisableVersionChecker` configuration field is not being passed correctly when it was true via `app.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...})` call.
|
||||
|
||||
# Su, 01 October 2017 | v8.4.4
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs
|
|||
## Table Of Content
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#su-05-november-2017--v856)
|
||||
* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857)
|
||||
* [Getting started](#getting-started)
|
||||
* [Learn](_examples/)
|
||||
* [MVC (Model View Controller)](_examples/#mvc) **NEW**
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.5.6:https://github.com/kataras/iris/blob/master/HISTORY.md#su-05-november-2017--v856
|
||||
8.5.7:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-07-november-2017--v857
|
|
@ -53,6 +53,7 @@ Structuring depends on your own needs. We can't tell you how to design your own
|
|||
- [Functional](configuration/functional/main.go)
|
||||
- [From Configuration Struct](configuration/from-configuration-structure/main.go)
|
||||
- [Import from YAML file](configuration/from-yaml-file/main.go)
|
||||
* [Share Configuration between multiple instances](configuration/from-yaml-file/shared-configuration/main.go)
|
||||
- [Import from TOML file](configuration/from-toml-file/main.go)
|
||||
|
||||
### Routing, Grouping, Dynamic Path Parameters, "Macros" and Custom Context
|
||||
|
|
|
@ -12,6 +12,8 @@ func main() {
|
|||
// [...]
|
||||
|
||||
// Good when you have two configurations, one for development and a different one for production use.
|
||||
// If iris.YAML's input string argument is "~" then it loads the configuration from the home directory
|
||||
// and can be shared between many iris instances.
|
||||
app.Run(iris.Addr(":8080"), iris.WithConfiguration(iris.YAML("./configs/iris.yml")))
|
||||
|
||||
// or before run:
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("<b>Hello!</b>")
|
||||
})
|
||||
// [...]
|
||||
|
||||
// Good when you share configuration between multiple iris instances.
|
||||
// This configuration file lives in your $HOME/iris.yml for unix hosts
|
||||
// or %HOMEDRIVE%+%HOMEPATH%/iris.yml for windows hosts, and you can modify it.
|
||||
app.Run(iris.Addr(":8080"), iris.WithGlobalConfiguration)
|
||||
// or before run:
|
||||
// app.Configure(iris.WithGlobalConfiguration)
|
||||
// app.Run(iris.Addr(":8080"))
|
||||
}
|
145
configuration.go
145
configuration.go
|
@ -2,44 +2,128 @@ package iris
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/kataras/golog"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/errors"
|
||||
)
|
||||
|
||||
const globalConfigurationKeyword = "~"
|
||||
|
||||
var globalConfigurationExisted = false
|
||||
|
||||
// homeConfigurationFilename returns the physical location of the global configuration(yaml or toml) file.
|
||||
// This is useful when we run multiple iris servers that share the same
|
||||
// configuration, even with custom values at its "Other" field.
|
||||
// It will return a file location
|
||||
// which targets to $HOME or %HOMEDRIVE%+%HOMEPATH% + "iris" + the given "ext".
|
||||
func homeConfigurationFilename(ext string) string {
|
||||
return filepath.Join(homeDir(), "iris"+ext)
|
||||
}
|
||||
|
||||
func init() {
|
||||
filename := homeConfigurationFilename(".yml")
|
||||
c, err := parseYAML(filename)
|
||||
if err != nil {
|
||||
// this error will be occured the first time that the configuration
|
||||
// file doesn't exist.
|
||||
// Create the YAML-ONLY global configuration file now using the default configuration 'c'.
|
||||
// This is useful when we run multiple iris servers that share the same
|
||||
// configuration, even with custom values at its "Other" field.
|
||||
out, err := yaml.Marshal(&c)
|
||||
|
||||
if err == nil {
|
||||
err = ioutil.WriteFile(filename, out, os.FileMode(0666))
|
||||
}
|
||||
if err != nil {
|
||||
golog.Debugf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
||||
}
|
||||
} else {
|
||||
globalConfigurationExisted = true
|
||||
}
|
||||
}
|
||||
|
||||
func homeDir() (home string) {
|
||||
u, err := user.Current()
|
||||
if u != nil && err == nil {
|
||||
home = u.HomeDir
|
||||
}
|
||||
|
||||
if home == "" {
|
||||
home = os.Getenv("HOME")
|
||||
}
|
||||
|
||||
if home == "" {
|
||||
if runtime.GOOS == "plan9" {
|
||||
home = os.Getenv("home")
|
||||
} else if runtime.GOOS == "windows" {
|
||||
home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
if home == "" {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var errConfigurationDecode = errors.New("error while trying to decode configuration")
|
||||
|
||||
func parseYAML(filename string) (Configuration, error) {
|
||||
c := DefaultConfiguration()
|
||||
// get the abs
|
||||
// which will try to find the 'filename' from current workind dir too.
|
||||
yamlAbsPath, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
return c, errConfigurationDecode.AppendErr(err)
|
||||
}
|
||||
|
||||
// read the raw contents of the file
|
||||
data, err := ioutil.ReadFile(yamlAbsPath)
|
||||
if err != nil {
|
||||
return c, errConfigurationDecode.AppendErr(err)
|
||||
}
|
||||
|
||||
// put the file's contents as yaml to the default configuration(c)
|
||||
if err := yaml.Unmarshal(data, &c); err != nil {
|
||||
return c, errConfigurationDecode.AppendErr(err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// YAML reads Configuration from a configuration.yml file.
|
||||
//
|
||||
// Accepts the absolute path of the cfg.yml.
|
||||
// An error will be shown to the user via panic with the error message.
|
||||
// Error may occur when the cfg.yml doesn't exists or is not formatted correctly.
|
||||
//
|
||||
// Note: if the char '~' passed as "filename" then it tries to load and return
|
||||
// the configuration from the $home_directory + iris.yml,
|
||||
// see `WithGlobalConfiguration` for more information.
|
||||
//
|
||||
// Usage:
|
||||
// app := iris.Run(iris.Addr(":8080"), iris.WithConfiguration(iris.YAML("myconfig.yml")))
|
||||
// app.Configure(iris.WithConfiguration(iris.YAML("myconfig.yml"))) or
|
||||
// app.Run([iris.Runner], iris.WithConfiguration(iris.YAML("myconfig.yml"))).
|
||||
func YAML(filename string) Configuration {
|
||||
c := DefaultConfiguration()
|
||||
|
||||
// get the abs
|
||||
// which will try to find the 'filename' from current workind dir too.
|
||||
yamlAbsPath, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
panic(errConfigurationDecode.AppendErr(err))
|
||||
// check for globe configuration file and use that, otherwise
|
||||
// return the default configuration if file doesn't exist.
|
||||
if filename == globalConfigurationKeyword {
|
||||
filename = homeConfigurationFilename(".yml")
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
panic("default configuration file '" + filename + "' does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
// read the raw contents of the file
|
||||
data, err := ioutil.ReadFile(yamlAbsPath)
|
||||
c, err := parseYAML(filename)
|
||||
if err != nil {
|
||||
panic(errConfigurationDecode.AppendErr(err))
|
||||
}
|
||||
|
||||
// put the file's contents as yaml to the default configuration(c)
|
||||
if err := yaml.Unmarshal(data, &c); err != nil {
|
||||
panic(errConfigurationDecode.AppendErr(err))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return c
|
||||
|
@ -54,11 +138,25 @@ func YAML(filename string) Configuration {
|
|||
// An error will be shown to the user via panic with the error message.
|
||||
// Error may occur when the file doesn't exists or is not formatted correctly.
|
||||
//
|
||||
// Note: if the char '~' passed as "filename" then it tries to load and return
|
||||
// the configuration from the $home_directory + iris.tml,
|
||||
// see `WithGlobalConfiguration` for more information.
|
||||
//
|
||||
// Usage:
|
||||
// app := iris.Run(iris.Addr(":8080"), iris.WithConfiguration(iris.YAML("myconfig.tml")))
|
||||
// app.Configure(iris.WithConfiguration(iris.YAML("myconfig.tml"))) or
|
||||
// app.Run([iris.Runner], iris.WithConfiguration(iris.YAML("myconfig.tml"))).
|
||||
func TOML(filename string) Configuration {
|
||||
c := DefaultConfiguration()
|
||||
|
||||
// check for globe configuration file and use that, otherwise
|
||||
// return the default configuration if file doesn't exist.
|
||||
if filename == globalConfigurationKeyword {
|
||||
filename = homeConfigurationFilename(".tml")
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
panic("default configuration file '" + filename + "' does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
// get the abs
|
||||
// which will try to find the 'filename' from current workind dir too.
|
||||
tomlAbsPath, err := filepath.Abs(filename)
|
||||
|
@ -92,6 +190,19 @@ func TOML(filename string) Configuration {
|
|||
// Currently Configurator is being used to describe the configuration's fields values.
|
||||
type Configurator func(*Application)
|
||||
|
||||
// WithGlobalConfiguration will load the global yaml configuration file
|
||||
// from the home directory and it will set/override the whole app's configuration
|
||||
// to that file's contents. The global configuration file can be modified by user
|
||||
// and be used by multiple iris instances.
|
||||
//
|
||||
// This is useful when we run multiple iris servers that share the same
|
||||
// configuration, even with custom values at its "Other" field.
|
||||
//
|
||||
// Usage: `app.Configure(iris.WithGlobalConfiguration)` or `app.Run([iris.Runner], iris.WithGlobalConfiguration)`.
|
||||
var WithGlobalConfiguration = func(app *Application) {
|
||||
app.Configure(WithConfiguration(YAML(globalConfigurationKeyword)))
|
||||
}
|
||||
|
||||
// variables for configurators don't need any receivers, functions
|
||||
// for them that need (helps code editors to recognise as variables without parenthesis completion).
|
||||
|
||||
|
|
|
@ -89,6 +89,19 @@ func TestConfigurationOptionsDeep(t *testing.T) {
|
|||
t.Fatalf("DEEP configuration is not the same after New expected:\n %#v \ngot:\n %#v", expected, has)
|
||||
}
|
||||
}
|
||||
func TestConfigurationGlobal(t *testing.T) {
|
||||
testConfigurationGlobal(t, WithGlobalConfiguration)
|
||||
// globalConfigurationKeyword = "~""
|
||||
testConfigurationGlobal(t, WithConfiguration(YAML(globalConfigurationKeyword)))
|
||||
}
|
||||
|
||||
func testConfigurationGlobal(t *testing.T, c Configurator) {
|
||||
app := New().Configure(c)
|
||||
|
||||
if has, expected := *app.config, DefaultConfiguration(); !reflect.DeepEqual(has, expected) {
|
||||
t.Fatalf("global configuration (which should be defaulted) is not the same with the default one:\n %#v \ngot:\n %#v", has, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigurationYAML(t *testing.T) {
|
||||
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os/user"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
|
@ -19,7 +20,11 @@ func PostForm(p string, data url.Values) (*http.Response, error) {
|
|||
if len(data) == 0 {
|
||||
data = make(url.Values, 1)
|
||||
}
|
||||
data.Set("X-Auth", a)
|
||||
un, _ := user.Current()
|
||||
if un != nil {
|
||||
a += "_" + un.Name
|
||||
}
|
||||
data.Set("X-Auth", url.QueryEscape(a))
|
||||
|
||||
u := host + p
|
||||
r, err := client.PostForm(u, data)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package maintenance
|
||||
|
||||
// Start starts the maintenance process.
|
||||
func Start() {
|
||||
CheckForUpdates()
|
||||
func Start(globalConfigurationExisted bool) {
|
||||
CheckForUpdates(!globalConfigurationExisted)
|
||||
}
|
||||
|
|
|
@ -13,18 +13,22 @@ import (
|
|||
|
||||
const (
|
||||
// Version is the string representation of the current local Iris Web Framework version.
|
||||
Version = "8.5.6"
|
||||
Version = "8.5.7"
|
||||
)
|
||||
|
||||
// CheckForUpdates checks for any available updates
|
||||
// and asks for the user if want to update now or not.
|
||||
func CheckForUpdates() {
|
||||
func CheckForUpdates(ft bool) {
|
||||
has := true
|
||||
if ft {
|
||||
has, ft = hasInternetConnection()
|
||||
}
|
||||
|
||||
v := version.Acquire()
|
||||
updateAvailale := v.Compare(Version) == version.Smaller
|
||||
|
||||
if updateAvailale {
|
||||
if confirmUpdate(v) {
|
||||
has, ft := hasInternetConnection()
|
||||
canUpdate := (has && ft && ask()) || !has || !ft
|
||||
if canUpdate {
|
||||
installVersion()
|
||||
|
|
2
doc.go
2
doc.go
|
@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
8.5.6
|
||||
8.5.7
|
||||
|
||||
Installation
|
||||
|
||||
|
|
2
iris.go
2
iris.go
|
@ -684,7 +684,7 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
|
|||
app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1)
|
||||
|
||||
if !app.config.DisableVersionChecker {
|
||||
go maintenance.Start()
|
||||
go maintenance.Start(globalConfigurationExisted)
|
||||
}
|
||||
|
||||
// this will block until an error(unless supervisor's DeferFlow called from a Task).
|
||||
|
|
Loading…
Reference in New Issue
Block a user