From 2f6c0832329c73dc2197c13dca2b85278b7858d3 Mon Sep 17 00:00:00 2001 From: Makis Maropoulos Date: Fri, 17 Jun 2016 01:51:42 +0300 Subject: [PATCH] update iriscontrol - no new feature added but now listens to the parent host https://github.com/kataras/iris/issues/191 --- plugin/editor/editor.go | 13 +- plugin/iriscontrol/README.md | 47 ------- plugin/iriscontrol/control_panel.go | 114 ---------------- plugin/iriscontrol/index.go | 7 - plugin/iriscontrol/iriscontrol.go | 195 +++++++++++++++------------- plugin/iriscontrol/main_controls.go | 20 --- plugin/iriscontrol/plugin.go | 79 +++++++++++ 7 files changed, 185 insertions(+), 290 deletions(-) delete mode 100644 plugin/iriscontrol/README.md delete mode 100644 plugin/iriscontrol/control_panel.go delete mode 100644 plugin/iriscontrol/index.go delete mode 100644 plugin/iriscontrol/main_controls.go create mode 100644 plugin/iriscontrol/plugin.go diff --git a/plugin/editor/editor.go b/plugin/editor/editor.go index 6666d9e3..0e67e2be 100644 --- a/plugin/editor/editor.go +++ b/plugin/editor/editor.go @@ -9,7 +9,6 @@ Would be readily available to anyone who could intercept the HTTP request. import ( "os" "strconv" - "strings" "github.com/iris-contrib/npm" "github.com/kataras/iris" @@ -91,17 +90,7 @@ func (e *Plugin) PreListen(s *iris.Framework) { e.certfile = s.Config.Server.CertFile if e.config.Host == "" { - h := s.Config.Server.ListeningAddr - - if idx := strings.Index(h, ":"); idx >= 0 { - h = h[0:idx] - } - if h == "" { - h = "127.0.0.1" - } - - e.config.Host = h - + e.config.Host = s.HTTPServer.VirtualHostname() } e.start() } diff --git a/plugin/iriscontrol/README.md b/plugin/iriscontrol/README.md deleted file mode 100644 index 0be191b5..00000000 --- a/plugin/iriscontrol/README.md +++ /dev/null @@ -1,47 +0,0 @@ -## Iris Control - -### THIS IS NOT READY YET - -This plugin will give you remotely ( and local ) access to your iris server's information via a web interface - - -### Assets -No assets here because this is go -getable folder I don't want to messup with the folder size, in order to solve this -I created a downloader manager inside this package which downloads the first time the assets and unzip them to the kataras/iris/plugin/iris-control/iris-control-assets/ . - - - -The assets files are inside [this repository](https://github.com/iris-contrib/iris-control-assets) - - -## How to use - -```go - -package main - -import ( - "github.com/kataras/iris" - "github.com/kataras/iris/plugin/iriscontrol" - "fmt" -) - -func main() { - - iris.Plugins.Add(iriscontrol.Web(9090, map[string]string{ - "irisusername1": "irispassword1", - "irisusername2": "irispassowrd2", - })) - - iris.Get("/", func(ctx *iris.Context) { - }) - - iris.Post("/something", func(ctx *iris.Context) { - }) - - iris.Listen(":8080") -} - - - -``` diff --git a/plugin/iriscontrol/control_panel.go b/plugin/iriscontrol/control_panel.go deleted file mode 100644 index a85c6793..00000000 --- a/plugin/iriscontrol/control_panel.go +++ /dev/null @@ -1,114 +0,0 @@ -package iriscontrol - -import ( - "os" - "strconv" - "time" - - "github.com/kataras/iris" - "github.com/kataras/iris/config" -) - -var pathSeperator = string(os.PathSeparator) -var pluginPath = os.Getenv("GOPATH") + pathSeperator + "src" + pathSeperator + "github.com" + pathSeperator + "kataras" + pathSeperator + "iris" + pathSeperator + "plugin" + pathSeperator + "iriscontrol" + pathSeperator -var assetsURL = "https://github.com/iris-contrib/iris-control-assets/archive/master.zip" -var assetsFolderName = "iris-control-assets-master" -var installationPath = pluginPath + assetsFolderName + pathSeperator - -// for the plugin server -func (i *irisControlPlugin) startControlPanel() { - - // install the assets first - if err := i.installAssets(); err != nil { - i.pluginContainer.Printf("[%s] %s Error %s: Couldn't install the assets from the internet,\n make sure you are connecting to the internet the first time running the iris-control plugin", time.Now().UTC().String(), Name, err.Error()) - i.Destroy() - return - } - - i.server = iris.New() - i.server.Config.DisableBanner = true - i.server.Config.Render.Template.Directory = installationPath + "templates" - //i.server.SetRenderConfig(i.server.Config.Render) - i.setPluginsInfo() - i.setPanelRoutes() - - go i.server.Listen(":" + strconv.Itoa(i.options.Port)) - - i.pluginContainer.Printf("[%s] %s is running at port %d", time.Now().UTC().String(), Name, i.options.Port) - -} - -// DashboardPage is the main data struct for the index -// contains a boolean if server is running, the routes and the plugins -type DashboardPage struct { - ServerIsRunning bool - Routes []iris.Route - Plugins []PluginInfo - LastOperationDateStr string -} - -func (i *irisControlPlugin) setPluginsInfo() { - plugins := i.pluginContainer.GetAll() - i.plugins = make([]PluginInfo, 0, len(plugins)) - for _, plugin := range plugins { - name := i.pluginContainer.GetName(plugin) - desc := i.pluginContainer.GetDescription(plugin) - if name == "" { - // means an iris internaly plugin or a nameless plugin - name = "Internal Iris Plugin" - } - if desc == "" { - // means an iris internaly plugin or a descriptionless plugin - desc = "Propably an internal Iris Plugin - no description provided" - } - - i.plugins = append(i.plugins, PluginInfo{Name: name, Description: desc}) - } -} - -// installAssets checks if must install ,if yes download the zip and unzip it, returns error. -func (i *irisControlPlugin) installAssets() (err error) { - //we know already what is the zip folder inside it, so we can check if it's exists, if yes then don't install it again. - if i.pluginContainer.GetDownloader().DirectoryExists(installationPath) { - return - } - //set the installationPath ,although we know it but do it here too - installationPath, err = i.pluginContainer.GetDownloader().Install(assetsURL, pluginPath) - return err - -} - -func (i *irisControlPlugin) setPanelRoutes() { - - i.server.Static("/public", installationPath+"static", 1) - - i.server.Use(i.authFunc) - i.server.Get("/", func(ctx *iris.Context) { - ctx.Render("index.html", DashboardPage{ - ServerIsRunning: i.station.HTTPServer.IsListening(), - Routes: i.routes, - Plugins: i.plugins, - LastOperationDateStr: i.lastOperationDate.Format(config.TimeFormat), - }) - }) - - //the controls - i.server.Post("/start_server", func(ctx *iris.Context) { - //println("server start") - i.lastOperationDate = time.Now() - old := i.stationServer - if !old.IsSecure() { - i.station.Listen(old.Config.ListeningAddr) - //yes but here it does re- post listen to this plugin so ... - } else { - i.station.ListenTLS(old.Config.ListeningAddr, old.Config.CertFile, old.Config.KeyFile) - } - - }) - - i.server.Post("/stop_server", func(ctx *iris.Context) { - //println("server stop") - i.station.Close() - }) - -} diff --git a/plugin/iriscontrol/index.go b/plugin/iriscontrol/index.go deleted file mode 100644 index 4355dea2..00000000 --- a/plugin/iriscontrol/index.go +++ /dev/null @@ -1,7 +0,0 @@ -package iriscontrol - -// PluginInfo the name and the description of a plugin -type PluginInfo struct { - Name string - Description string -} diff --git a/plugin/iriscontrol/iriscontrol.go b/plugin/iriscontrol/iriscontrol.go index 1d9e91d1..f30b0d21 100644 --- a/plugin/iriscontrol/iriscontrol.go +++ b/plugin/iriscontrol/iriscontrol.go @@ -1,6 +1,7 @@ package iriscontrol import ( + "strconv" "time" "github.com/kataras/iris" @@ -8,103 +9,117 @@ import ( "github.com/kataras/iris/middleware/basicauth" ) -// Name the name(string) of this plugin which is Iris Control -const Name = "Iris Control" +type ( + // IrisControl is the interface which the iriscontrol should implements + // it's empty for now because no need any public API + IrisControl interface{} + iriscontrol struct { + port int + users map[string]string -type irisControlPlugin struct { - options config.IrisControl - // the pluginContainer is the container which keeps this plugin from the main user's iris instance - pluginContainer iris.PluginContainer - // the station object of the main user's iris instance - station *iris.Framework - //a copy of the server which the main user's iris is listening for - stationServer *iris.Server - - // the server is this plugin's server object, it is managed by this plugin only - server *iris.Framework - // - //infos - routes []iris.Route - plugins []PluginInfo - // last time the server was on - lastOperationDate time.Time - // - - authFunc iris.HandlerFunc -} - -// New returns the plugin which is ready-to-use inside iris.Plugin method -// receives config.IrisControl -func New(cfg ...config.IrisControl) iris.Plugin { - c := config.DefaultIrisControl() - if len(cfg) > 0 { - c = cfg[0] - } - if c.Users == nil || len(c.Users) == 0 { - panic(Name + " Error: you should pass authenticated users map to the options, refer to the docs!") + // child is the plugin's standalone station + child *iris.Framework + // the station which this plugins is registed to + parent *iris.Framework + parentLastOp time.Time } - auth := basicauth.Default(c.Users) - - return &irisControlPlugin{options: c, authFunc: auth, routes: make([]iris.Route, 0)} -} - -// Web set the options for the plugin and return the plugin which is ready-to-use inside iris.Plugin method -// first parameter is port -// second parameter is map of users (username:password) -func Web(port int, users map[string]string) iris.Plugin { - return New(config.IrisControl{Port: port, Users: users}) -} - -// implement the base IPlugin - -func (i *irisControlPlugin) Activate(container iris.PluginContainer) error { - i.pluginContainer = container - return nil -} - -func (i irisControlPlugin) GetName() string { - return Name -} - -func (i irisControlPlugin) GetDescription() string { - return Name + " is just a web interface which gives you control of your Iris.\n" -} - -// - -// implement the rest of the plugin - -// PostListen sets the station object after the main server starts -// starts the actual work of the plugin -func (i *irisControlPlugin) PostListen(s *iris.Framework) { - //if the first time, because other times start/stop of the server so listen and no listen will be only from the control panel - if i.station == nil { - i.station = s - i.stationServer = i.station.HTTPServer - i.lastOperationDate = time.Now() - i.routes = s.Lookups() - i.startControlPanel() + pluginInfo struct { + Name string + Description string } +) +var _ IrisControl = &iriscontrol{} + +func (i *iriscontrol) listen(f *iris.Framework) { + i.parent = f + i.parentLastOp = time.Now() + i.initializeChild() } -func (i *irisControlPlugin) PreClose(s *iris.Framework) { - // Do nothing. This is a wrapper of the main server if we destroy when users stop the main server then we cannot continue the control panel i.Destroy() +func (i *iriscontrol) initializeChild() { + i.child = iris.New() + i.child.Config.DisableBanner = true + i.child.Config.Render.Template.Directory = assetsPath + "templates" + + // set the assets + i.child.Static("/public", assetsPath+"static", 1) + + // set the authentication middleware + i.child.Use(basicauth.New(config.BasicAuth{ + Users: i.users, + ContextKey: "user", + Realm: config.DefaultBasicAuthRealm, + Expires: time.Duration(1) * time.Hour, + })) + + i.child.Get("/", func(ctx *iris.Context) { + ctx.MustRender("index.html", iris.Map{ + "ServerIsRunning": i.parentIsRunning(), + "Routes": i.parentLookups(), + "Plugins": i.infoPlugins(), + "LastOperationDateStr": i.infoLastOp(), + }) + }) + + i.child.Post("/start_server", func(ctx *iris.Context) { + + if !i.parentIsRunning() { + // starts the server with its old configuration + go func() { + if err := i.parent.HTTPServer.Open(); err != nil { + i.parent.Logger.Warningf(err.Error()) + } + }() + i.parentLastOp = time.Now() + } + }) + + i.child.Post("/stop_server", func(ctx *iris.Context) { + + if i.parentIsRunning() { + i.parentLastOp = time.Now() + + go func() { + if err := i.parent.CloseWithErr(); err != nil { + i.parent.Logger.Warningf(err.Error()) + } + }() + } + }) + + go i.child.Listen(i.parent.HTTPServer.VirtualHostname() + strconv.Itoa(i.port)) } -// - -// Destroy removes entirely the plugin, the options and all of these properties, you cannot re-use this plugin after this method. -func (i *irisControlPlugin) Destroy() { - i.pluginContainer.Remove(Name) - - i.options = config.IrisControl{} - i.routes = nil - i.station = nil - i.lastOperationDate = config.CookieExpireNever - i.server.Close() - i.pluginContainer = nil - i.authFunc = nil - i.pluginContainer.Printf("[%s] %s is turned off", time.Now().UTC().String(), Name) +func (i *iriscontrol) parentIsRunning() bool { + return i.parent != nil && i.parent.HTTPServer.IsListening() +} + +func (i *iriscontrol) parentLookups() []iris.Route { + if i.parent == nil { + return nil + } + return i.parent.Lookups() +} + +func (i *iriscontrol) infoPlugins() (info []pluginInfo) { + plugins := i.parent.Plugins + for _, p := range plugins.GetAll() { + name := plugins.GetName(p) + description := plugins.GetDescription(p) + if name == "" { + name = "Unknown plugin name" + } + if description == "" { + description = "description is not available" + } + + info = append(info, pluginInfo{Name: name, Description: description}) + } + return +} + +func (i *iriscontrol) infoLastOp() string { + return i.parentLastOp.Format(config.TimeFormat) } diff --git a/plugin/iriscontrol/main_controls.go b/plugin/iriscontrol/main_controls.go deleted file mode 100644 index 9b17124b..00000000 --- a/plugin/iriscontrol/main_controls.go +++ /dev/null @@ -1,20 +0,0 @@ -package iriscontrol - -// for the main server -func (i *irisControlPlugin) StartServer() { - if i.station.HTTPServer.IsListening() == false { - if i.station.HTTPServer.IsSecure() { - //listen with ListenTLS - i.station.ListenTLS(i.station.Config.Server.ListeningAddr, i.station.Config.Server.CertFile, i.station.Config.Server.KeyFile) - } else { - //listen normal - i.station.Listen(i.station.Config.Server.ListeningAddr) - } - } -} - -func (i *irisControlPlugin) StopServer() { - if i.station.HTTPServer.IsListening() { - i.station.Close() - } -} diff --git a/plugin/iriscontrol/plugin.go b/plugin/iriscontrol/plugin.go new file mode 100644 index 00000000..30ec1df7 --- /dev/null +++ b/plugin/iriscontrol/plugin.go @@ -0,0 +1,79 @@ +package iriscontrol + +import ( + "os" + "runtime" + + "github.com/kataras/iris" + "github.com/kataras/iris/utils" +) + +// Name "Iris Control" +const Name = "Iris Control" + +var ( + assetsURL = "https://github.com/iris-contrib/iris-control-assets/archive/master.zip" + assetsUnzipname = "iris-control-assets" + assetsPath = "" +) + +// init just sets the assetsPath +func init() { + homepath := "" + if runtime.GOOS == "windows" { + homepath = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + } else { + homepath = os.Getenv("HOME") + } + assetsPath = homepath + utils.PathSeparator + ".iris" + utils.PathSeparator + "iris-control-assets" + utils.PathSeparator +} + +func installAssets() { + + if !utils.DirectoryExists(assetsPath) { + errMsg := "\nProblem while downloading the assets from the internet for the first time. Trace: %s" + + installedDir, err := utils.Install(assetsURL, assetsPath) + if err != nil { + panic(errMsg) + } + + err = utils.CopyDir(installedDir, assetsPath) + if err != nil { + panic(err) + } + + // try to remove the unzipped folder + utils.RemoveFile(installedDir[0 : len(installedDir)-1]) + } +} + +// New creates & returns a new iris control plugin +// receives two parameters +// first is the authenticated users which should be able to access the control panel +// second is the PORT which the iris control panel should be listened & served to +func New(port int, users map[string]string) IrisControl { + return &iriscontrol{port: port, users: users} +} + +// PreListen registers the iriscontrol plugin +func (i *iriscontrol) PreListen(s *iris.Framework) { + installAssets() + i.listen(s) +} + +// GetName returns the name of the plugin +func (i *iriscontrol) GetName() string { + return Name +} + +// GetDescription returns the description of the plugin +func (i *iriscontrol) GetDescription() string { + return Name + " is just a web interface which gives you control of your Iris.\n" +} + +// PreClose any clean-up +// temporary is empty because all resources are cleaned graceful by the iris' station +func (i *iriscontrol) PreClose(s *iris.Framework) { + s.Logger.Infof("Main server terminated") +}