Skip to content

Commit

Permalink
Enable plugin to work with latest versions of Mattermost
Browse files Browse the repository at this point in the history
  • Loading branch information
seansackowitz committed May 5, 2019
1 parent 513cfbf commit 1315d1d
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 25 deletions.
4 changes: 2 additions & 2 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"id": "jitsi",
"name": "Jitsi",
"description": "Jitsi audio and video conferencing plugin for Mattermost. Follow https://github.com/seansackowitz/mattermost-plugin-jitsi for notifications on updates.",
"version": "1.0.0",
"backend": {
"version": "1.1.0",
"server": {
"executable": "server/plugin.exe"
},
"webapp": {
Expand Down
97 changes: 97 additions & 0 deletions server/configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License for license information.

package main

import (
"fmt"
"reflect"

"github.com/pkg/errors"
)

// configuration captures the plugin's external configuration as exposed in the Mattermost server
// configuration, as well as values computed from the configuration. Any public fields will be
// deserialized from the Mattermost server configuration in OnConfigurationChange.
//
// As plugins are inherently concurrent (hooks being called asynchronously), and the plugin
// configuration can change at any time, access to the configuration must be synchronized. The
// strategy used in this plugin is to guard a pointer to the configuration, and clone the entire
// struct whenever it changes. You may replace this with whatever strategy you choose.
//
// If you add non-reference types to your configuration struct, be sure to rewrite Clone as a deep
// copy appropriate for your types.
type configuration struct {
JitsiURL string
}

// Clone shallow copies the configuration. Your implementation may require a deep copy if
// your configuration has reference types.
func (c *configuration) Clone() *configuration {
var clone = *c
return &clone
}

// IsValid checks if all needed fields are set.
func (c *configuration) IsValid() error {
if len(c.JitsiURL) == 0 {
return fmt.Errorf("JitsiUrl is not configured.")
}

return nil
}

// getConfiguration retrieves the active configuration under lock, making it safe to use
// concurrently. The active configuration may change underneath the client of this method, but
// the struct returned by this API call is considered immutable.
func (p *Plugin) getConfiguration() *configuration {
p.configurationLock.RLock()
defer p.configurationLock.RUnlock()

if p.configuration == nil {
return &configuration{}
}

return p.configuration
}

// setConfiguration replaces the active configuration under lock.
//
// Do not call setConfiguration while holding the configurationLock, as sync.Mutex is not
// reentrant. In particular, avoid using the plugin API entirely, as this may in turn trigger a
// hook back into the plugin. If that hook attempts to acquire this lock, a deadlock may occur.
//
// This method panics if setConfiguration is called with the existing configuration. This almost
// certainly means that the configuration was modified without being cloned and may result in
// an unsafe access.
func (p *Plugin) setConfiguration(configuration *configuration) {
p.configurationLock.Lock()
defer p.configurationLock.Unlock()

if configuration != nil && p.configuration == configuration {
// Ignore assignment if the configuration struct is empty. Go will optimize the
// allocation for same to point at the same memory address, breaking the check
// above.
if reflect.ValueOf(*configuration).NumField() == 0 {
return
}

panic("setConfiguration called with the existing configuration")
}

p.configuration = configuration
}

// OnConfigurationChange is invoked when configuration changes may have been made.
func (p *Plugin) OnConfigurationChange() error {
var configuration = new(configuration)

// Load the public configuration fields from the Mattermost server configuration.
if err := p.API.LoadPluginConfiguration(configuration); err != nil {
return errors.Wrap(err, "failed to load plugin configuration")
}

p.setConfiguration(configuration)

return nil
}
36 changes: 14 additions & 22 deletions server/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"regexp"
"strings"
"sync"

"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
Expand All @@ -19,29 +20,20 @@ const (
type Plugin struct {
plugin.MattermostPlugin

JitsiURL string
}

// func (p *Plugin) OnActivate() error {
// if err := p.IsConfigurationValid(); err != nil {
// return err
// }

// return nil
// }
// configurationLock synchronizes access to the configuration.
configurationLock sync.RWMutex

// func (p *Plugin) OnConfigurationChange() error {
// if err := p.IsConfigurationValid(); err != nil {
// return err
// }

// return nil
// }
// configuration is the active plugin configuration. Consult getConfiguration and
// setConfiguration for usage.
configuration *configuration
}

func (p *Plugin) IsConfigurationValid() error {
if len(p.JitsiURL) == 0 {
return fmt.Errorf("Jitsi URL is not configured")
func (p *Plugin) OnActivate() error {
config := p.getConfiguration()
if err := config.IsValid(); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -70,7 +62,7 @@ func encodeJitsiMeetingID(meeting string) string {
}

func (p *Plugin) handleStartMeeting(w http.ResponseWriter, r *http.Request) {
if err := p.IsConfigurationValid(); err != nil {
if err := p.getConfiguration().IsValid(); err != nil {
http.Error(w, err.Error(), http.StatusTeapot)
return
}
Expand Down Expand Up @@ -105,7 +97,7 @@ func (p *Plugin) handleStartMeeting(w http.ResponseWriter, r *http.Request) {
if len(req.Topic) < 1 {
meetingID = generateRoomWithoutSeparator()
}
jitsiURL := strings.TrimSpace(p.JitsiURL)
jitsiURL := strings.TrimSpace(p.getConfiguration().JitsiURL)
meetingURL := jitsiURL + "/" + meetingID

post := &model.Post{
Expand Down
2 changes: 1 addition & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jitsi",
"version": "1.0.0",
"version": "1.1.0",
"description": "Jitsi audio and video conferencing plugin for Mattermost",
"dependencies": {
"mattermost-redux": "1.0.1",
Expand Down

0 comments on commit 1315d1d

Please sign in to comment.