|
1 #!/usr/bin/ruby |
|
2 # |
|
3 # A DRb interface to one or more ezmlm-idx mailing lists. |
|
4 # |
|
5 # == Version |
|
6 # |
|
7 # $Id$ |
|
8 # |
|
9 # == Authors |
|
10 # |
|
11 # * Michael Granger <mgranger@laika.com> |
|
12 # * Jeremiah Jordan <jjordan@laika.com> |
|
13 # |
|
14 # :include: LICENSE |
|
15 # |
|
16 #--- |
|
17 # |
|
18 # Please see the file LICENSE in the base directory for licensing details. |
|
19 # |
|
20 |
|
21 require 'pathname' |
|
22 require 'ezmlm' |
|
23 require 'ezmlm/list' |
|
24 require 'drb' |
|
25 require 'ostruct' |
|
26 |
|
27 |
|
28 ### A DRb interface to one or more ezmlm-idx mailing lists |
|
29 class Ezmlm::ListDaemon |
|
30 |
|
31 # The default port to listen on |
|
32 DEFAULT_PORT = 32315 |
|
33 |
|
34 # The default address to bind to |
|
35 DEFAULT_ADDRESS = '127.0.0.1' |
|
36 |
|
37 |
|
38 ### The interface that is presented to DRb |
|
39 class Service |
|
40 include Enumerable |
|
41 |
|
42 ### Create a new service endpoint for the specified +listsdir+, which is a directory |
|
43 ### which contains ezmlm-idx list directories. |
|
44 def initialize( listsdir ) |
|
45 listsdir = Pathname.new( listsdir ) |
|
46 @listsdir = listsdir |
|
47 end |
|
48 |
|
49 |
|
50 ###### |
|
51 public |
|
52 ###### |
|
53 |
|
54 # The directory which contains the list directories that should be served. |
|
55 attr_reader :listsdir |
|
56 |
|
57 |
|
58 ### Create a new Ezmlm::List object for the list directory with the specified +name+. |
|
59 def get_list( name ) |
|
60 name = validate_listdir_name( name ) |
|
61 return Ezmlm::List.new( self.listsdir + name ) |
|
62 end |
|
63 |
|
64 |
|
65 ### Iterate over each current list in the Service's listsdir, yielding an Ezmlm::List object |
|
66 ### for each one. |
|
67 def each_list( &block ) # :yields: list_object |
|
68 Ezmlm.each_list( self.listsdir, &block ) |
|
69 end |
|
70 alias_method :each, :each_list |
|
71 |
|
72 |
|
73 ####### |
|
74 private |
|
75 ####### |
|
76 |
|
77 VALID_LISTNAME_PATTERN = /^[a-z0-9.-]+$/i |
|
78 |
|
79 ### Ensure that the given +name+ is a valid list name, raising an exception if not. Returns |
|
80 ### an untainted copy of +name+. |
|
81 def validate_listdir_name( name ) |
|
82 unless match = VALID_LISTNAME_PATTERN.match( name ) |
|
83 raise ArgumentError, "invalid list name %p" % [ name ] |
|
84 end |
|
85 |
|
86 return match[0].untaint |
|
87 end |
|
88 |
|
89 end # class Service |
|
90 |
|
91 |
|
92 |
|
93 ### Return an OpenStruct that contains the default options |
|
94 def self::default_options |
|
95 opts = OpenStruct.new |
|
96 |
|
97 opts.bind_addr = DEFAULT_ADDRESS |
|
98 opts.bind_port = DEFAULT_PORT |
|
99 opts.debugmode = false |
|
100 opts.helpmode = false |
|
101 opts.foreground = false |
|
102 |
|
103 return opts |
|
104 end |
|
105 |
|
106 |
|
107 ################################################################# |
|
108 ### I N S T A N C E M E T H O D S |
|
109 ################################################################# |
|
110 |
|
111 ### Create a new Ezmlm::ListDaemon that will serve objects for the list directories |
|
112 ### contained in +listsdir+. The +options+ argument, if given, is an object (such as the one |
|
113 ### returned from ::default_options) that contains values for the following methods: |
|
114 ### |
|
115 ### bind_addr:: |
|
116 ### The address to bind to. Defaults to DEFAULT_ADDRESS. |
|
117 ### bind_port:: |
|
118 ### The port to listen on. Defaults to DEFAULT_PORT. |
|
119 ### debugmode:: |
|
120 ### Whether to run in debugging mode, which causes the daemon to run in the foreground |
|
121 ### and send any output to STDERR. Defaults to +false+. |
|
122 ### foreground:: |
|
123 ### Don't go into the background. |
|
124 def initialize( listsdir, options=nil ) |
|
125 @service = Service.new( listsdir ) |
|
126 @options = options || self.class.default_options |
|
127 end |
|
128 |
|
129 |
|
130 ###### |
|
131 public |
|
132 ###### |
|
133 |
|
134 # The daemon's configuration options |
|
135 attr_reader :options |
|
136 |
|
137 # The Ezmlm::ListDaemon::Service object that serves as the DRb interface |
|
138 attr_reader :service |
|
139 |
|
140 |
|
141 ### Daemonize unless configured otherwise, start the DRb service and return the listening |
|
142 ### Thread object |
|
143 def start |
|
144 uri = "druby://%s:%d" % [ self.options.bind_addr, self.options.bind_port ] |
|
145 DRb.start_service( uri, @service ) |
|
146 |
|
147 return DRb.thread |
|
148 end |
|
149 |
|
150 |
|
151 end # class Ezmlm::ListDaemon |
|
152 |
|
153 # vim: set nosta noet ts=4 sw=4: |