From 0788cdcadfb5d76b08758f42f01521b45ea76362 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 31 Jul 2018 16:29:52 -0400 Subject: MM-11420: plugins: compute bundle hash on load (#9172) * plugins: compute bundle hash on load Use this hash to bust client caches whenever the plugin bundle changes. * eliminate redundant pluginHandler * switch to 64-bit FNV-1a * Fix test --- plugin/environment.go | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'plugin') diff --git a/plugin/environment.go b/plugin/environment.go index 6f915fd80..5c3a98349 100644 --- a/plugin/environment.go +++ b/plugin/environment.go @@ -5,6 +5,7 @@ package plugin import ( "fmt" + "hash/fnv" "io/ioutil" "os" "path/filepath" @@ -133,29 +134,27 @@ func (env *Environment) Statuses() (model.PluginStatuses, error) { return pluginStatuses, nil } -// Activate activates the plugin with the given id. -func (env *Environment) Activate(id string) (reterr error) { - +func (env *Environment) Activate(id string) (manifest *model.Manifest, activated bool, reterr error) { // Check if we are already active if _, ok := env.activePlugins.Load(id); ok { - return nil + return nil, false, nil } plugins, err := env.Available() if err != nil { - return err + return nil, false, err } var pluginInfo *model.BundleInfo for _, p := range plugins { if p.Manifest != nil && p.Manifest.Id == id { if pluginInfo != nil { - return fmt.Errorf("multiple plugins found: %v", id) + return nil, false, fmt.Errorf("multiple plugins found: %v", id) } pluginInfo = p } } if pluginInfo == nil { - return fmt.Errorf("plugin not found: %v", id) + return nil, false, fmt.Errorf("plugin not found: %v", id) } activePlugin := activePlugin{BundleInfo: pluginInfo} @@ -171,43 +170,54 @@ func (env *Environment) Activate(id string) (reterr error) { if pluginInfo.Manifest.Webapp != nil { bundlePath := filepath.Clean(pluginInfo.Manifest.Webapp.BundlePath) if bundlePath == "" || bundlePath[0] == '.' { - return fmt.Errorf("invalid webapp bundle path") + return nil, false, fmt.Errorf("invalid webapp bundle path") } bundlePath = filepath.Join(env.pluginDir, id, bundlePath) destinationPath := filepath.Join(env.webappPluginDir, id) if err := os.RemoveAll(destinationPath); err != nil { - return errors.Wrapf(err, "unable to remove old webapp bundle directory: %v", destinationPath) + return nil, false, errors.Wrapf(err, "unable to remove old webapp bundle directory: %v", destinationPath) } if err := utils.CopyDir(filepath.Dir(bundlePath), destinationPath); err != nil { - return errors.Wrapf(err, "unable to copy webapp bundle directory: %v", id) + return nil, false, errors.Wrapf(err, "unable to copy webapp bundle directory: %v", id) } + sourceBundleFilepath := filepath.Join(destinationPath, filepath.Base(bundlePath)) + + sourceBundleFileContents, err := ioutil.ReadFile(sourceBundleFilepath) + if err != nil { + return nil, false, errors.Wrapf(err, "unable to read webapp bundle: %v", id) + } + + hash := fnv.New64a() + hash.Write(sourceBundleFileContents) + pluginInfo.Manifest.Webapp.BundleHash = hash.Sum([]byte{}) + if err := os.Rename( - filepath.Join(destinationPath, filepath.Base(bundlePath)), - filepath.Join(destinationPath, fmt.Sprintf("%s_bundle.js", id)), + sourceBundleFilepath, + filepath.Join(destinationPath, fmt.Sprintf("%s_%x_bundle.js", id, pluginInfo.Manifest.Webapp.BundleHash)), ); err != nil { - return errors.Wrapf(err, "unable to rename webapp bundle: %v", id) + return nil, false, errors.Wrapf(err, "unable to rename webapp bundle: %v", id) } } if pluginInfo.Manifest.HasServer() { supervisor, err := newSupervisor(pluginInfo, env.logger, env.newAPIImpl(pluginInfo.Manifest)) if err != nil { - return errors.Wrapf(err, "unable to start plugin: %v", id) + return nil, false, errors.Wrapf(err, "unable to start plugin: %v", id) } activePlugin.supervisor = supervisor } - return nil + return pluginInfo.Manifest, true, nil } // Deactivates the plugin with the given id. -func (env *Environment) Deactivate(id string) { +func (env *Environment) Deactivate(id string) bool { p, ok := env.activePlugins.Load(id) if !ok { - return + return false } env.activePlugins.Delete(id) @@ -219,6 +229,8 @@ func (env *Environment) Deactivate(id string) { } activePlugin.supervisor.Shutdown() } + + return true } // Shutdown deactivates all plugins and gracefully shuts down the environment. -- cgit v1.2.3-1-g7c22