Skip to content

Commit

Permalink
Add Plugin architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
dkoch committed Sep 17, 2014
1 parent 07aeb8e commit f55c6ae
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ CrispyFi provides a command line-like interface to its internal playlist handlin
* `list rename <old name> <new name>` - Renames the specified list.
* `list <name>` - Selects the specified list and starts playback.

## Plugins
If CrispyFi doesn't do what you need, you can extend it. The plugin architecture is pretty minimal at this point, but at least there's a standardized interface. If none of the default trigger words matched, each plugin's `handle` method will be called until one is found that returns `true`. If a plugin returns `true`, the plugin chain is halted and the plugin's `status` attribute is checked for content. If it's not empty, its content will be replied to the Slack channel CrispyFi listens to. If it's empty, nothing further will happen (the plugin chain will *not* be traversed further, though).

Plugins live in `/plugins` and need a `name` attribute. A minimal example implementation is provided in `examples/my_first_plugin.coffee`.

## Getting your groove on(line)
Since your Pi will probably be behind a firewall/some sort of NAT or have a dynamic IP, you'll have difficulties tying Slack's webhooks to its IP address. We're currently using [ngrok](http://ngrok.com) to get around that, mainly because it's awesome and makes developing web services much easier. Also, using ngrok you avoid the hassle of updating some other service's configuration whenever your IP changes, instead you have to run a small binary all the time. YMMV, so use whatever you're comfortable with (but give ngrok a try).

Expand Down
15 changes: 15 additions & 0 deletions examples/my_first_plugin.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class MyFirstPlugin
constructor: () ->
@name = 'My First Plugin'
@response = null

handle: (auth, spotify, volume) ->
if auth.command == 'plugin'
# This will be replied to the channel. If nothing is set, no reply will be sent.
@response = "This is a reply from #{@name}."
return true
else
return false

module.exports = () ->
return new MyFirstPlugin()
29 changes: 29 additions & 0 deletions lib/plugin_handler.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class PluginHandler
constructor: () ->
# Plugin cache
@plugins = []

# Adds all plugins to the cache
load_plugins: () ->
# Reset the plugin cache
@plugins = []
console.log "Loading Plugins..."
root_dir = require('path').dirname require.main.filename
require("fs").readdirSync("#{root_dir}/plugins").forEach (file) =>
plugin = require("#{root_dir}/plugins/" + file)()
@plugins.push plugin
console.log " -- #{plugin.name}"
console.log "...done."
return

handle: (auth, spotify, volume) ->
state = false
for plugin in @plugins
if plugin.handle(auth, spotify, volume)
return plugin.response

module.exports = () ->
if !@handler?
@handler = new PluginHandler()
@handler.load_plugins()
return @handler
6 changes: 6 additions & 0 deletions lib/slack_interface/request_handler.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class SlackInterfaceRequestHandler
@auth = auth
@spotify = spotify
@volume = volume
@plugin_handler = require("../../lib/plugin_handler")()

@endpoints =
handle:
Expand Down Expand Up @@ -58,6 +59,11 @@ class SlackInterfaceRequestHandler
when 'help'
reply_data['text'] = "You seem lost. Maybe trying one of these commands will help you out:\n*play* [Spotify-URI] - Starts or resumes playback. If you provide a Spotify-URI it will be played immediately.\n*stop* - Stops playback.\n*pause* - Pauses playback (can be resumed using *play*).\n*skip*: Skips to the next track.\n*list* [listname] - Switches to the specified Spotify-Playlist. If no list name is provided, all available lists will be shown. Playlists need to be configured beforehand, please check the project's readme for details.\n*vol* [up|down|0-10] - Sets the output volume. Either goes up or down one notch or directly to a level ranging from 0 to 10 (inclusive). 0 is mute."

else
# Fallback to external plugins.
status = @plugin_handler.handle(@auth, @spotify, @volume)
if status?
reply_data['text'] = status

response.serveJSON reply_data
return
Expand Down

0 comments on commit f55c6ae

Please sign in to comment.