Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Features/nickserv #9

Merged
merged 8 commits into from almost 2 years ago

2 participants

Richo Healey Paul Annesley
Richo Healey
richo commented April 19, 2012

Cheap hook to perform some authentication routine on startup

and others added some commits April 19, 2012
Richo Healey Create model, tidy github notification 1eca8ae
Richo Healey Controllers are now just plugins which use the REST api b94f841
Richo Healey Remove dynamic reload support ab03cc5
Richo Healey Refactor plugin pattern
HTTP api is now just another aspect of the plugin API
0c3732b
Richo Healey Plugins are loaded according to a config file
The onus is still on the plugin to sanely teardown and recreate itself
preserving state via some external mechanism, unfortunately at this time
there is no hook beyond ruby's native GC for catching when your object
is unrouted and discarded
b019372
Richo Healey Refactor some comments 5a03847
Richo Healey Rebase out some renaming bb9c87e
Richo Healey Hook to authenticate with some service 3752798
Richo Healey
richo commented April 19, 2012

This PR will trim itself right down if/when the other one goes in.

Paul Annesley pda merged commit 00e0bf0 into from April 21, 2012
Paul Annesley pda closed this April 21, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 8 unique commits by 2 authors.

Apr 19, 2012
Richo Healey Create model, tidy github notification 1eca8ae
Apr 20, 2012
Richo Healey Controllers are now just plugins which use the REST api b94f841
Richo Healey Remove dynamic reload support ab03cc5
Richo Healey Refactor plugin pattern
HTTP api is now just another aspect of the plugin API
0c3732b
Richo Healey Plugins are loaded according to a config file
The onus is still on the plugin to sanely teardown and recreate itself
preserving state via some external mechanism, unfortunately at this time
there is no hook beyond ruby's native GC for catching when your object
is unrouted and discarded
b019372
Richo Healey Refactor some comments 5a03847
Richo Healey Rebase out some renaming bb9c87e
Richo Healey Hook to authenticate with some service 3752798
This page is out of date. Refresh to see the latest.
5  example.json
@@ -9,5 +9,8 @@
9 9
 	"udp_port": 8421,
10 10
 	"http_port": 8421,
11 11
 	"bind_address": "127.0.0.1",
12  
-	"ssl": false
  12
+	"ssl": false,
  13
+    "identify_command": "PRIVMSG nickserv :identify somepassword",
  14
+  "plugins":
  15
+    [ "Hello", "RestChannels", "GithubNotification" ]
13 16
 }
11  lib/irc_machine.rb
@@ -15,7 +15,16 @@
15 15
   state
16 16
   plugin
17 17
   plugin/base
18  
-  plugin/reloader
  18
+
  19
+  core
  20
+
  21
+  udp_server
  22
+
  23
+  http_router
  24
+  http_server
19 25
 }.each do |name|
20 26
   require "irc_machine/#{name}"
21 27
 end
  28
+
  29
+Dir[File.dirname(__FILE__) + '/irc_machine/models/*.rb'].each {|file| require file }
  30
+Dir[File.dirname(__FILE__) + '/irc_machine/plugin/*.rb'].each {|file| require file }
32  lib/irc_machine/controller/channels_controller.rb
... ...
@@ -1,32 +0,0 @@
1  
-module IrcMachine
2  
-  module Controller
3  
-    class ChannelsController < HttpController
4  
-
5  
-      def list
6  
-        content_type "application/json"
7  
-        ok session.state.channels.to_json << "\n"
8  
-      end
9  
-
10  
-      def join
11  
-        session.join channel(match), request.GET["key"]
12  
-      end
13  
-
14  
-      def part
15  
-        session.part channel(match)
16  
-      end
17  
-
18  
-      def message
19  
-        input = request.body.gets
20  
-        source = request.env["HTTP_X_AUTH"] || request.ip || "unknown"
21  
-        session.msg channel(match), "[#{source}] #{input.chomp}" if input
22  
-      end
23  
-
24  
-      private
25  
-
26  
-      def channel(match)
27  
-        "#" + match[1]
28  
-      end
29  
-
30  
-    end
31  
-  end
32  
-end
12  lib/irc_machine/controller/github_notifications_controller.rb
... ...
@@ -1,12 +0,0 @@
1  
-module IrcMachine
2  
-  module Controller
3  
-    class GithubNotificationsController < HttpController
4  
-
5  
-      def notify
6  
-        session.msg "##{match[1]}",
7  
-          Plugin::GithubNotification.new(request.body.read).message
8  
-      end
9  
-
10  
-    end
11  
-  end
12  
-end
1  lib/irc_machine/core.rb
@@ -7,6 +7,7 @@ def connected
7 7
       session.nick options.nick
8 8
       session.state.nick = options.nick
9 9
       EM::add_timer(5) do
  10
+        session.raw options.identify_command if options.identify_command
10 11
         options.channels.each { |c| session.join *c.split } if options.channels
11 12
       end
12 13
     end
16  lib/irc_machine/core_routes.rb
... ...
@@ -1,16 +0,0 @@
1  
-module IrcMachine
2  
-  module CoreRoutes
3  
-
4  
-    CHANNEL_REGEXP ||= %r{^/channels/([\w-]+)$}
5  
-
6  
-    def draw_routes
7  
-      get "/channels", "ChannelsController#list"
8  
-      put CHANNEL_REGEXP, "ChannelsController#join"
9  
-      delete CHANNEL_REGEXP, "ChannelsController#part"
10  
-      post CHANNEL_REGEXP, "ChannelsController#message"
11  
-
12  
-      post %r{^/channels/([\w-]+)/github$}, "GithubNotificationsController#notify"
13  
-    end
14  
-
15  
-  end
16  
-end
35  lib/irc_machine/http_controller.rb
... ...
@@ -1,35 +0,0 @@
1  
-module IrcMachine
2  
-  class HttpController
3  
-
4  
-    def self.dispatch(session, request, method, match)
5  
-      new(session, request, match).tap do |c|
6  
-        c.send method
7  
-      end.response
8  
-    end
9  
-
10  
-    def initialize(session, request, match)
11  
-      @session = session
12  
-      @request = request
13  
-      @match = match
14  
-      @response = Rack::Response.new
15  
-    end
16  
-
17  
-    attr_reader :session
18  
-    attr_reader :request, :response
19  
-    attr_reader :match
20  
-
21  
-    def ok(content)
22  
-      @response.status = 200
23  
-      @response.write content
24  
-    end
25  
-
26  
-    def not_found
27  
-      @response.status = 404
28  
-    end
29  
-
30  
-    def content_type(type)
31  
-      @response["Content-Type"] = type
32  
-    end
33  
-
34  
-  end
35  
-end
36  lib/irc_machine/http_router.rb
@@ -4,13 +4,20 @@
4 4
 module IrcMachine
5 5
   class HttpRouter
6 6
 
7  
-    include CoreRoutes
  7
+    @@routes = { get: [], put: [], delete:[], post: [] }
  8
+
  9
+    class << self
  10
+
  11
+      def connect(method, pattern, destination)
  12
+        @@routes[method] << [ pattern, destination ]
  13
+      end
  14
+
  15
+    end
8 16
 
9 17
     def initialize(session)
10 18
       @session = session
11  
-      @routes = { get: [], put: [], delete:[], post: [] }
12  
-      draw_routes
13 19
     end
  20
+    attr_reader :session
14 21
 
15 22
     def route(env)
16 23
       request = Rack::Request.new(env)
@@ -21,28 +28,23 @@ def route(env)
21 28
         self.class,
22 29
         request.request_method,
23 30
         request.path,
  31
+        # TODO Lambda's don't inspect tremendously well
24 32
         match.destination.inspect
25 33
       ]
26 34
 
27 35
       response = case match.destination
28  
-      when String
29  
-        name, method = match.destination.split("#")
30  
-        klass = IrcMachine::Controller.const_get(name)
31  
-        klass.dispatch(@session, request, method, match.match)
32  
-      else
  36
+      when nil
33 37
         Rack::Response.new "Unhandled destination: #{match.destination.class}", 500
  38
+      else
  39
+        match.destination.call(request, match.match)
34 40
       end
35  
-
36 41
       response.finish
37 42
     end
38 43
 
39  
-    def get(route, destination); connect :get, route, destination; end
40  
-    def put(route, destination); connect :put, route, destination; end
41  
-    def delete(route, destination); connect :delete, route, destination; end
42  
-    def post(route, destination); connect :post, route, destination; end
43  
-
44  
-    def connect(method, pattern, destination)
45  
-      @routes[method] << [ pattern, destination ]
  44
+    def flush_routes!
  45
+      @@routes.each do |k, v|
  46
+        @@routes[k] = []
  47
+      end
46 48
     end
47 49
 
48 50
     private
@@ -51,7 +53,7 @@ def lookup_route_match(request_method, path)
51 53
       # this is pretty bad..
52 54
       request_method = request_method.downcase.to_sym
53 55
       route_match = OpenStruct.new
54  
-      _, route_match.destination = @routes[request_method].detect do |(pattern,destination)|
  56
+      _, route_match.destination = @@routes[request_method].detect do |(pattern,destination)|
55 57
         if pattern.is_a? Regexp
56 58
           route_match.match = pattern.match(path)
57 59
         else
5  lib/irc_machine/plugin/github_notifier.rb → lib/irc_machine/models/github_notification.rb
@@ -3,10 +3,7 @@
3 3
 require "ostruct"
4 4
 
5 5
 module IrcMachine
6  
-  module Plugin
7  
-
8  
-    class GithubNotifier < Plugin::Base
9  
-    end
  6
+  module Models
10 7
 
11 8
     class GithubNotification
12 9
 
21  lib/irc_machine/plugin/base.rb
@@ -5,6 +5,27 @@ def initialize(session)
5 5
         @session = session
6 6
       end
7 7
       attr_reader :session
  8
+
  9
+      # Inherited from the old HttpController
  10
+      def ok(content, opts={})
  11
+        Rack::Response.new.tap do |response|
  12
+          response.status = 200
  13
+          response["Content-Type"] = opts[:content_type] || "text/plain"
  14
+          response.write content
  15
+        end
  16
+      end
  17
+
  18
+      def not_found
  19
+        Rack::Response.new.tap do |response|
  20
+          response.status = 404
  21
+        end
  22
+      end
  23
+
  24
+      def route(method, path, sym)
  25
+        # Close over the instance method and bind to a route.
  26
+        meta = lambda { |request, match| send(sym, request, match) }
  27
+        IrcMachine::HttpRouter.send(:connect, method, path, meta)
  28
+      end
8 29
     end
9 30
   end
10 31
 end
13  lib/irc_machine/plugin/github_notifications_controller.rb
... ...
@@ -0,0 +1,13 @@
  1
+class IrcMachine::Plugin::GithubNotification < IrcMachine::Plugin::Base
  2
+
  3
+  def initialize(*args)
  4
+    route(:post, %r{^/channels/([\w-]+)/github$}, :notify)
  5
+    super(*args)
  6
+  end
  7
+
  8
+  def notify
  9
+    session.msg "##{match[1]}",
  10
+      Models::GithubNotification.new(request.body.read).message
  11
+  end
  12
+
  13
+end
33  lib/irc_machine/plugin/reloader.rb
... ...
@@ -1,33 +0,0 @@
1  
-class IrcMachine::Plugin::Reloader < IrcMachine::Plugin::Base
2  
-
3  
-  def receive_line(line)
4  
-    if line =~ /^:\S+ PRIVMSG #{session.state.nick} :reload$/
5  
-      self.class.load_all
6  
-    end
7  
-  end
8  
-
9  
-  def self.load_all
10  
-    files = %w{
11  
-      core
12  
-      core_routes
13  
-
14  
-      udp_server
15  
-
16  
-      http_controller
17  
-      http_router
18  
-      http_server
19  
-
20  
-      controller/channels_controller
21  
-      controller/github_notifications_controller
22  
-
23  
-      plugin/github_notifier
24  
-      plugin/base
25  
-      plugin/hello
26  
-      plugin/reloader
27  
-    }.each do |name|
28  
-      puts "loading: #{name}"
29  
-      load "irc_machine/#{name}.rb"
30  
-    end
31  
-  end
32  
-
33  
-end
46  lib/irc_machine/plugin/rest_channels.rb
... ...
@@ -0,0 +1,46 @@
  1
+class IrcMachine::Plugin::RestChannels < IrcMachine::Plugin::Base
  2
+
  3
+  CHANNEL_REGEXP ||= %r{^/channels/([\w-]+)$}
  4
+  # Ditch the constant for reloadable code or bear the
  5
+  # consequences
  6
+
  7
+  # Can ditch dependence on instance if we load data
  8
+  # from the FS on each request?
  9
+
  10
+  # Looping args through is ugly, but it needs to be
  11
+  # instance specific
  12
+  def initialize(*args)
  13
+    route(:get, "/channels", :list)
  14
+    route(:put, CHANNEL_REGEXP, :join)
  15
+    route(:delete, CHANNEL_REGEXP, :part)
  16
+    route(:post, CHANNEL_REGEXP, :message)
  17
+    super(*args)
  18
+  end
  19
+
  20
+
  21
+  def list(request, match)
  22
+    ok session.state.channels.to_json << "\n",
  23
+      content_type: "application/json"
  24
+  end
  25
+
  26
+  def join(request, match)
  27
+    session.join channel(match), request.GET["key"]
  28
+  end
  29
+
  30
+  def part(request, match)
  31
+    session.part channel(match)
  32
+  end
  33
+
  34
+  def message(request, match)
  35
+    input = request.body.gets
  36
+    source = request.env["HTTP_X_AUTH"] || request.ip || "unknown"
  37
+    session.msg channel(match), "[#{source}] #{input.chomp}" if input
  38
+  end
  39
+
  40
+  private
  41
+
  42
+  def channel(match)
  43
+    "#" + match[1]
  44
+  end
  45
+
  46
+end
17  lib/irc_machine/session.rb
@@ -7,17 +7,18 @@ class Session
7 7
     attr_accessor :irc_connection
8 8
 
9 9
     def initialize(options)
10  
-      IrcMachine::Plugin::Reloader.load_all
11  
-
12 10
       @options = OpenStruct.new(options)
13 11
       @state = State.new
14 12
       @router = HttpRouter.new(self)
15  
-      @plugins = [
16  
-        Core.new(self),
17  
-        Plugin::Hello.new(self),
18  
-        Plugin::Reloader.new(self),
19  
-        Plugin::GithubNotifier.new(self)
20  
-      ]
  13
+      load_plugins!
  14
+    end
  15
+
  16
+    def load_plugins!
  17
+      @router.flush_routes!
  18
+      @plugins = [Core.new(self)]
  19
+      options.plugins.each do |plugin|
  20
+        @plugins << Plugin.const_get(plugin).new(self)
  21
+      end
21 22
     end
22 23
 
23 24
     def start
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.