Skip to content

Commit

Permalink
Added easy link to sever/webapp component list (#1315)
Browse files Browse the repository at this point in the history
* Added easy link to sever/webapp component list

* Incorporated reviewer feedback

* Make SDKs obvious
  • Loading branch information
cwarnermm authored Nov 30, 2023
1 parent fd39a7b commit 0ec1c32
Show file tree
Hide file tree
Showing 20 changed files with 56 additions and 50 deletions.
4 changes: 2 additions & 2 deletions site/content/contribute/more-info/server/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ Plugins are generally made of at least two parts: a manifest and a server binary

The manifest tells Mattermost what the plugin is and provides a set of metadata used by the server to install and run the plugin. Please see the [manifest reference]({{< ref "/integrate/plugins/manifest-reference" >}}) for more information. Manifests may be defined in JSON or YAML.

The server binary is a compiled Go program that extends the {{< newtabref href="https://godoc.org/github.com/mattermost/mattermost/server/public/plugin#MattermostPlugin" title="MattermostPlugin" >}} struct of the {{< newtabref href="https://godoc.org/github.com/mattermost/mattermost/server/public/plugin" title="plugin" >}} package. When enabled, the plugin's server binary is started as a process by the Mattermost server. Plugin developers then have access to interact with the Mattermost server over RPC through the plugin [API]({{< ref "/integrate/plugins/components/server/reference#API" >}}) and [Hooks]({{< ref "/integrate/plugins/components/server/reference#Hooks" >}}). The server-side of plugins is built using the {{< newtabref href="https://github.com/hashicorp/go-plugin" title="go-plugin" >}} library from Hashicorp. More information is available in the [server side of the plugin author documentation]({{< ref "/integrate/plugins/components/server" >}}).
The server binary is a compiled Go program that extends the {{< newtabref href="https://godoc.org/github.com/mattermost/mattermost/server/public/plugin#MattermostPlugin" title="MattermostPlugin" >}} struct of the {{< newtabref href="https://godoc.org/github.com/mattermost/mattermost/server/public/plugin" title="plugin" >}} package. When enabled, the plugin's server binary is started as a process by the Mattermost server. Plugin developers then have access to interact with the Mattermost server over RPC through the plugin [API]({{< ref "/integrate/reference/server/server-reference#API" >}}) and [Hooks]({{< ref "/integrate/reference/server/server-reference#Hooks" >}}). The server-side of plugins is built using the {{< newtabref href="https://github.com/hashicorp/go-plugin" title="go-plugin" >}} library from Hashicorp. More information is available in the [server side of the plugin author documentation]({{< ref "/integrate/plugins/components/server" >}}).

The JavaScript bundle is a webpack-built collection of JavaScript code that will be run on the Mattermost web/desktop apps. When a plugin is enabled, the client is notified and it makes a request to add the JS bundle to the document. The plugin's client code then registers itself and its components with the Mattermost client through the client's [plugin registry]({{< ref "/integrate/plugins/components/webapp/reference#registry" >}}). The registry contains many methods for registering different components and callbacks. These are all stored as part of the app's {{< newtabref href="https://github.com/mattermost/mattermost/blob/master/webapp/channels/src/reducers/plugins/index.ts" title="plugin reducer" >}}. The {{< newtabref href="https://github.com/mattermost/mattermost/tree/master/webapp/channels/src/plugins/pluggable" title="Pluggable" >}} component is then inserted into various places in the app, allowing plugins to insert components into these locations in the UI. In some special cases, the Pluggable component is not used and we instead implement the plugs manually. More information is available in the [webapp side of the plugin author documentation]({{< ref "/integrate/plugins/components/webapp" >}}).
The JavaScript bundle is a webpack-built collection of JavaScript code that will be run on the Mattermost web/desktop apps. When a plugin is enabled, the client is notified and it makes a request to add the JS bundle to the document. The plugin's client code then registers itself and its components with the Mattermost client through the client's [plugin registry]({{< ref "/integrate/reference/webapp/webapp-reference#registry" >}}). The registry contains many methods for registering different components and callbacks. These are all stored as part of the app's {{< newtabref href="https://github.com/mattermost/mattermost/blob/master/webapp/channels/src/reducers/plugins/index.ts" title="plugin reducer" >}}. The {{< newtabref href="https://github.com/mattermost/mattermost/tree/master/webapp/channels/src/plugins/pluggable" title="Pluggable" >}} component is then inserted into various places in the app, allowing plugins to insert components into these locations in the UI. In some special cases, the Pluggable component is not used and we instead implement the plugs manually. More information is available in the [webapp side of the plugin author documentation]({{< ref "/integrate/plugins/components/webapp" >}}).

All these different components of a plugin are compressed into a .tar.gz bundle. Installing a plugin is the process of uploading this bundle to the Mattermost server (via the UI, REST API or CLI). The server then unpacks the bundle, performs some validation and extracts it into the configured directory for storing installed plugins. Installed plugins are not yet running. To start a plugin it must be enabled (again via the UI, REST API or CLI). Once it is enabled, the server will then start the server process and prepare the web app bundle for serving to the client. Plugin settings, configuration and enabled/disabled status are managed by the Mattermost `config.json` using a {{< newtabref href="https://godoc.org/github.com/mattermost/mattermost/server/public/model#PluginSettings" title="PluginSettings" >}} struct.

Expand Down
4 changes: 2 additions & 2 deletions site/content/integrate/apps/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ Each type of existing integration is sort of a la carte, whereas the App framewo

In the case of webhooks, the existing mechanism is only able to create posts, and only accepts an [incoming webhook]({{< ref "/integrate/webhooks/incoming" >}}) payload. It does not support other logic for handling arbitrary data structures from external systems.

A plugin should be used when you need to [directly alter the UI]({{< ref "integrate/plugins/components/webapp/best-practices" >}}) in Mattermost or you have a feature that requires low latency with the server (such as replacing characters in any message [before it is saved]({{< ref "integrate/plugins/components/server/reference#Hooks.MessageWillBePosted" >}})).
A plugin should be used when you need to [directly alter the UI]({{< ref "integrate/plugins/components/webapp/best-practices" >}}) in Mattermost or you have a feature that requires low latency with the server (such as replacing characters in any message [before it is saved]({{< ref "integrate/reference/server/server-reference#Hooks.MessageWillBePosted" >}})).

{{<note "Note:">}}
Plugins have several [UX hooks]({{< ref "integrate/plugins/components/server/reference#Hooks" >}}) that Apps cannot access. Please see the [plugin documentation]({{< ref "integrate/plugins" >}}) for more information.
Plugins have several [UX hooks]({{< ref "integrate/reference/server/server-reference#Hooks" >}}) that Apps cannot access. Please see the [plugin documentation]({{< ref "integrate/plugins" >}}) for more information.
{{</note>}}

### What's the difference between the Apps framework and the plugin framework?
Expand Down
4 changes: 4 additions & 0 deletions site/content/integrate/getting-started/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Plugins are the most comprehensive way to add new features and customization, bu

[Get started with plugins]({{< ref "/integrate/plugins" >}})

{{<note "Tip:">}}
See the [Mattermost Server SDK Reference]({{< ref "/integrate/reference/server/server-reference" >}}) and [Mattermost Client UI SDK Reference]({{< ref "/integrate/reference/webapp/webapp-reference" >}}) documentation for details on available server API endpoints and client methods.
{{</note>}}

## API

Interact with users, channels, and everything else that happens on your Mattermost server via a modern REST API that meets the OpenAPI specification. The API is for developers who want to build bots and other interactions that don’t rely on customizing the Mattermost user experience.
Expand Down
4 changes: 4 additions & 0 deletions site/content/integrate/plugins/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Launch and manage Server plugins as services from your Mattermost server over RP

Extend the Mattermost REST API with custom endpoints for use by Web App plugins or third-party services. Custom endpoints have access to all the features of the standard Mattermost REST API, including personal access tokens and OAuth 2.0.

{{<note "Tip:">}}
See the [Mattermost Server SDK Reference]({{< ref "/integrate/reference/server/server-reference" >}}) and [Mattermost Client UI SDK Reference]({{< ref "/integrate/reference/webapp/webapp-reference" >}}) documentation for details on available server API endpoints and client methods.
{{</note>}}

### Simple development and installation

It's simple to set up a plugin development environment with the {{< newtabref href="https://github.com/mattermost/mattermost-plugin-starter-template" title="mattermost-plugin-starter-template" >}}. Just select "Use this template" when cloning the repository. Please see the [developer setup](https://developers.mattermost.com/integrate/plugins/developer-setup) and [developer workflow](https://developers.mattermost.com/integrate/plugins/developer-workflow) pages for more information.
Expand Down
4 changes: 2 additions & 2 deletions site/content/integrate/plugins/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ See here for [server-specific best practices for plugins]({{< ref "/integrate/pl

Once a plugin is installed, Administrators have access to the plugin's configuration page in the __System Console > Plugins__ section. The configurable settings must first be defined in the plugin's manifest [setting schema]({{< ref "/integrate/plugins/manifest-reference#settings_schema" >}}). The web app supports several basic pre-defined settings type, e.g. `bool` and `dropdown`, for which the corresponding UI components are provided in order to complete configuration in the System Console.

These settings are stored within the server configuration under [`Plugins`] indexed by plugin ids. The plugin's server code can access their current configuration calling the [`getConfig`]({{< ref "/integrate/plugins/components/server/reference#API.GetConfig" >}}) API call and can also make changes as needed with [`saveConfig`]({{< ref "/integrate/plugins/components/server/reference#API.SaveConfig" >}}).
These settings are stored within the server configuration under [`Plugins`] indexed by plugin ids. The plugin's server code can access their current configuration calling the [`getConfig`]({{< ref "/integrate/reference/server/server-reference#API.GetConfig" >}}) API call and can also make changes as needed with [`saveConfig`]({{< ref "/integrate/reference/server/server-reference#API.SaveConfig" >}}).

## How can a plugin define its own setting type?

Expand All @@ -33,7 +33,7 @@ A plugin could define its own type of setting with a corresponding custom user i
}
```

2. In the plugin's web app code, define a custom component to manage the plugin's custom setting and register it in the web app with [`registerAdminConsoleCustomSetting`]({{< ref "/integrate/plugins/components/webapp/reference#registerAdminConsoleCustomSetting" >}}). This component will be instantiated in the System Console with the following `props` passed in:
2. In the plugin's web app code, define a custom component to manage the plugin's custom setting and register it in the web app with [`registerAdminConsoleCustomSetting`]({{< ref "/integrate/reference/webapp/webapp-reference#registerAdminConsoleCustomSetting" >}}). This component will be instantiated in the System Console with the following `props` passed in:

- `id`: The setting `key` as defined in the plugin manifest within `settings_schema.settings`.
- `label`: The text for the component label based on the setting's `displayName` defined in the manifest.
Expand Down
10 changes: 5 additions & 5 deletions site/content/integrate/plugins/components/server/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ Server plugins are subprocesses invoked by the server that communicate with Matt

Looking for a quick start? [See our "Hello, world!" tutorial]({{< ref "/integrate/plugins/components/server/hello-world" >}}).

Want the server plugin reference doc? [Find it here]({{< ref "/integrate/plugins/components/server/reference" >}}).
Want the Server SDK reference doc? [Find it here]({{< ref "/integrate/reference/server/server-reference" >}}).

## Features

#### RPC API

Use the [RPC API]({{< ref "/integrate/plugins/components/server/reference#API" >}}) to execute create, read, update and delete (CRUD) operations on server data models.
Use the [RPC API]({{< ref "/integrate/reference/server/server-reference#API" >}}) to execute create, read, update and delete (CRUD) operations on server data models.

For example, your plugin can consume events from a third-party webhook and create corresponding posts in Mattermost, without having to host your code outside Mattermost.

#### Hooks

Register for [hooks]({{< ref "/integrate/plugins/components/server/reference#Hooks" >}}) and get alerted when certain events occur.
Register for [hooks]({{< ref "/integrate/reference/server/server-reference#Hooks" >}}) and get alerted when certain events occur.

For example, consume the [OnConfigurationChange]({{< ref "/integrate/plugins/components/server/reference#Hooks.OnConfigurationChange" >}}) hook to respond to server configuration changes, or the [MessageHasBeenPosted]({{< ref "/integrate/plugins/components/server/reference#Hooks.MessageHasBeenPosted" >}}) hook to respond to posts.
For example, consume the [OnConfigurationChange]({{< ref "/integrate/reference/server/server-reference#Hooks.OnConfigurationChange" >}}) hook to respond to server configuration changes, or the [MessageHasBeenPosted]({{< ref "/integrate/reference/server/server-reference#Hooks.MessageHasBeenPosted" >}}) hook to respond to posts.

#### REST API

Expand All @@ -39,7 +39,7 @@ Plugins with both a web app and server component can leverage this REST API to e

When starting a plugin, the server consults the [plugin's manifest]({{< ref "/integrate/plugins/manifest-reference" >}}) to determine if a server component was included. If found, the server launches a new process using the executable included with the plugin.

The server will trigger the [OnActivate]({{< ref "/integrate/plugins/components/server/reference#Hooks.OnActivate" >}}) hook if the plugin is successfully started, allowing you to perform startup events. If the plugin is disabled, the server will trigger the [OnDeactivate]({{< ref "/integrate/plugins/components/server/reference#Hooks.OnDeactivate" >}}) hook. While running, the server plugin can consume hook events, make API calls, launch threads or subprocesses of its own, interact with third-party services or do anything else a regular program can do.
The server will trigger the [OnActivate]({{< ref "/integrate/reference/server/server-reference#Hooks.OnActivate" >}}) hook if the plugin is successfully started, allowing you to perform startup events. If the plugin is disabled, the server will trigger the [OnDeactivate]({{< ref "/integrate/reference/server/server-reference#Hooks.OnDeactivate" >}}) hook. While running, the server plugin can consume hook events, make API calls, launch threads or subprocesses of its own, interact with third-party services or do anything else a regular program can do.

## High availability

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ Add all static files under a file directory named `public` within the plugin dir

## How can plugins make sure http requests are authentic?

Plugins can implement the [`ServeHTTP`]({{< ref "/integrate/plugins/components/server/reference#Hooks.ServeHTTP" >}}) to listen to http requests. This can e.g. be used to receive post action requests when [Interactive Messages Buttons and Menus](https://docs.mattermost.com/developer/interactive-messages.html) are triggered by users. Since these requests are just http requests, anyone can send them to the plugin. Hence the plugin must make sure the requests are authentic. The Mattermost Server sets the http header `Mattermost-User-Id` if and only if the request is made by an authenticated client. The plugin therefore has to only check if this header is set and reject all other requests.
Plugins can implement the [`ServeHTTP`]({{< ref "/integrate/reference/server/server-reference#Hooks.ServeHTTP" >}}) to listen to http requests. This can e.g. be used to receive post action requests when [Interactive Messages Buttons and Menus](https://docs.mattermost.com/developer/interactive-messages.html) are triggered by users. Since these requests are just http requests, anyone can send them to the plugin. Hence the plugin must make sure the requests are authentic. The Mattermost Server sets the http header `Mattermost-User-Id` if and only if the request is made by an authenticated client. The plugin therefore has to only check if this header is set and reject all other requests.
2 changes: 1 addition & 1 deletion site/content/integrate/plugins/components/server/ha.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It is important that all plugins consider HA environments when being built.

Plugins are started as subprocesses of the main Mattermost process on each app server. This means a Mattermost deployment that has three app servers will have three separate copies of the same plugin running. Each running copy of the plugin will be isolated from one another on different servers. Therefore, to run properly in HA the plugin's server-side code must be stateless.

To be stateless, the plugin must not retain any information or status in memory that may be needed across multiple events (e.g. HTTP requests or in other hooks). This data should instead be stored in a place that all running copies of the plugin have access to. For example, the [key-value store]({{< ref "/integrate/plugins/components/server/reference#API.KVSet" >}}) the plugin API provides.
To be stateless, the plugin must not retain any information or status in memory that may be needed across multiple events (e.g. HTTP requests or in other hooks). This data should instead be stored in a place that all running copies of the plugin have access to. For example, the [key-value store]({{< ref "/integrate/reference/server/server-reference#API.KVSet" >}}) the plugin API provides.

To better explain the problem with having a plugin store data in-memory, consider this case:

Expand Down
Loading

0 comments on commit 0ec1c32

Please sign in to comment.