DEV Community

Migsar Navarro
Migsar Navarro

Posted on

A very basic plugin for Filestash

This post is about how to create a very simple plugin for Filestash, the plugin does nothing at all but writing a line in the logs, it is not intended to be a guide for plugin development, just to summarize the first steps I didn't found anywhere else so myself or other developers can save a few minutes next time.

A few days ago I published A Docker development environment for Filestash in which I showed how to create a quick and simple development environment for Filestash, a web file manager. As I explore the software, I've been discovering things I would love to document, I think the best way to document it is writing this kind of practical, although very simplistic posts.

I am not a go programmer, so expect comments that may be obvious for developers familiarized with the language.

Why do I need to create a plugin?

Filestash's architecture is modular, and plugins play a huge role. Plugins are used for adding storage types, for authentication, authorization, for handling different types of files, for using different types of servers (starter plugins), etc. I am not 100% sure, but it seems most Filestash tasks are achievable through its plugin system.

The sad part is that I didn't find much documentation about how to customize things. At the beginning I didn't even know how to enable/disable plugins. Eventually this made me create a plugin to try to figure out how the system works.

The entry point: how to enable/disable plugins

Plugins are added to the app in server/plugin/index.go, there you have to add or remove the reference for the plugin package in the imports.

There are things you need to know about imports:

  • _ is called blank and means that the package is imported for its side effects, that is, the code in its initialization.
  • . is called a period, and it means that all the package's exported identifiers will be available in the importing package without a qualifier, which usually is the name of the imported package.

One additional note about go is that init is a special function that is automatically executed when the package is initialized. This happens before the main function runs and after all package-level variables are initialized.

In conclusion, to add the plugin we simply need to add it to the imports in server/plugin/index.go, to disable a plugin we can comment out or delete the importing line in this file.

A new plugin

To have a package to import we need to create it, here is the simplest plugin I could think of that has a visible output.

It does one simple thing, write an output line to the logs. Even so, there are some interesting remarks:

  • The logger is defined in the common package, so we need to import it. We could import fmt instead and use print, to immediately print the text, but it would feel out of chronological order.
  • If we plainly write the log it won't work because the logger is not ready, the best way to do it is to put our function inside a lifecycle hook for the app, more on this in the next section.
package plg_plugin_example

import (
    . "github.com/mickael-kerjean/filestash/server/common"
)

func init() {
    // Apparently Log is not initialized at this point
    // Log.Debug("Why this is not printed?")
    Hooks.Register.Onload(func() { Log.Debug("My plugin!") })
}

Enter fullscreen mode Exit fullscreen mode

Lifecycle hooks

I didn't find any docs about the lifecycle hooks, so here is a little summary without any detail, and probably with some errors or omissions, from their file server/common/plugin.go, part of the common package.

  • ProcessFileContentBeforeSend
  • HttpEndpoint
  • Static
  • Starter
  • AuthenticationMiddleware
  • AuthorisationMiddleware
  • SearchEngine
  • Thumbnailer
  • AuditEngine
  • FrontendOverrides
  • XDGOpen
  • CSS
  • CSSFunc
  • Favicon
  • Onload
  • Middleware
  • StaticPatch
  • Metadata
  • WorkflowTrigger
  • WorkflowAction

Just to be clear, I don't know yet the meaning, use case, or configuration of most of these, I am just listing them to keep them at hand. Some may be self-descriptive but a careful analysis of the code is recommended before using it for serious work.

Top comments (0)