syndi 0.1.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +12 -0
  3. data/CHANGELOG.md +0 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +28 -0
  6. data/README.md +104 -0
  7. data/Rakefile +30 -0
  8. data/WINDOWS.md +64 -0
  9. data/bin/syndi +102 -0
  10. data/bin/syndi-conf +47 -0
  11. data/conf/example.yml +101 -0
  12. data/docs/Events.md +103 -0
  13. data/docs/Upgrade.md +16 -0
  14. data/ext/csyndi/events.c +50 -0
  15. data/ext/csyndi/extconf.rb +20 -0
  16. data/ext/csyndi/integer.c +53 -0
  17. data/ext/csyndi/libauto.c +37 -0
  18. data/ext/csyndi/logger.c +229 -0
  19. data/include/syndi.h +22 -0
  20. data/include/syndi/csyndi.h +38 -0
  21. data/include/syndi/events.h +19 -0
  22. data/include/syndi/integer.h +17 -0
  23. data/include/syndi/logger.h +56 -0
  24. data/lib/csyndi.so +0 -0
  25. data/lib/syndi.rb +137 -0
  26. data/lib/syndi/actress.rb +12 -0
  27. data/lib/syndi/api.rb +7 -0
  28. data/lib/syndi/api/object.rb +29 -0
  29. data/lib/syndi/bot.rb +266 -0
  30. data/lib/syndi/config.rb +113 -0
  31. data/lib/syndi/dsl/base.rb +74 -0
  32. data/lib/syndi/dsl/irc.rb +13 -0
  33. data/lib/syndi/events.rb +130 -0
  34. data/lib/syndi/irc.rb +8 -0
  35. data/lib/syndi/irc/common.rb +63 -0
  36. data/lib/syndi/irc/library.rb +89 -0
  37. data/lib/syndi/irc/object/channel.rb +21 -0
  38. data/lib/syndi/irc/object/entity.rb +90 -0
  39. data/lib/syndi/irc/object/message.rb +99 -0
  40. data/lib/syndi/irc/object/user.rb +139 -0
  41. data/lib/syndi/irc/protocol.rb +161 -0
  42. data/lib/syndi/irc/protocol/numerics.rb +60 -0
  43. data/lib/syndi/irc/sasl/diffie_hellman.rb +36 -0
  44. data/lib/syndi/irc/sasl/mech.rb +7 -0
  45. data/lib/syndi/irc/sasl/mech/dh_blowfish.rb +83 -0
  46. data/lib/syndi/irc/sasl/mech/plain.rb +39 -0
  47. data/lib/syndi/irc/server.rb +301 -0
  48. data/lib/syndi/irc/state/channel_manager.rb +6 -0
  49. data/lib/syndi/irc/state/support.rb +142 -0
  50. data/lib/syndi/irc/state/user_manager.rb +6 -0
  51. data/lib/syndi/irc/std/commands.rb +99 -0
  52. data/lib/syndi/irc/std/numerics.rb +216 -0
  53. data/lib/syndi/jewel.rb +5 -0
  54. data/lib/syndi/jewel/specification.rb +121 -0
  55. data/lib/syndi/jewel/util.rb +27 -0
  56. data/lib/syndi/rubyext/string.rb +10 -0
  57. data/lib/syndi/verbosity.rb +10 -0
  58. data/lib/syndi/version.rb +38 -0
  59. data/spec/helper.rb +37 -0
  60. data/spec/syndi/events_spec.rb +89 -0
  61. data/tasks/compile.rake +15 -0
  62. data/tasks/install.rake +10 -0
  63. data/tasks/package.rake +13 -0
  64. data/tasks/spec.rake +12 -0
  65. metadata +243 -0
data/include/syndi.h ADDED
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright (c) 2013, Autumn Perrault, et al.
3
+ * All rights reserved.
4
+ * This free software is distributed under the FreeBSD license (see LICENSE).
5
+ *
6
+ */
7
+
8
+ #ifndef SYNDI_H
9
+ #define SYNDI_H
10
+
11
+ #include <stdio.h>
12
+ #include "ruby.h"
13
+
14
+ /* include csyndi headers */
15
+ #include "syndi/csyndi.h"
16
+ #include "syndi/logger.h"
17
+ #include "syndi/events.h"
18
+ #include "syndi/integer.h"
19
+
20
+ #endif // SYNDI_H
21
+
22
+ /* vim: set ts=4 sts=4 sw=4 et cindent: */
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (c) 2013, Autumn Perrault, et al.
3
+ * All rights reserved.
4
+ * This free software is distributed under the FreeBSD license (see LICENSE).
5
+ *
6
+ */
7
+
8
+ #ifndef __LIBSYNDI_H__
9
+ #define __LIBSYNDI_H__
10
+
11
+ /* SYM(x) returns rb_intern(x) */
12
+ #define SYM(str) rb_intern(#str)
13
+
14
+ /* variable for the Syndi module */
15
+ extern VALUE mSyndi;
16
+
17
+ /* Init_csyndi prototype */
18
+ void Init_csyndi();
19
+
20
+ /* Syndi's exceptions */
21
+ extern VALUE eLogError;
22
+ extern VALUE eConfigError;
23
+ extern VALUE eDatabaseError;
24
+ extern VALUE ePluginError;
25
+
26
+ /* line ending */
27
+ #ifdef _WIN32
28
+ #define OS_LINE_TERM "\r\n"
29
+ #else
30
+ #define OS_LINE_TERM "\n"
31
+ #endif
32
+
33
+ /* fetch the Syndi directory */
34
+ #define SYNDI_DIR RSTRING_PTR(rb_funcall(mSyndi, SYM(dir), 0))
35
+
36
+ #endif
37
+
38
+ /* vim: set ts=4 sts=4 sw=4 et cindent: */
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright (c) 2013, Autumn Perrault, et al.
3
+ * All rights reserved.
4
+ * This free software is distributed under the FreeBSD license (see LICENSE).
5
+ *
6
+ */
7
+
8
+ #ifndef WIN32
9
+ #include <pthread.h>
10
+ #endif
11
+
12
+ extern VALUE cEvents;
13
+
14
+ static VALUE events_initialize(VALUE self);
15
+ static VALUE events_on(VALUE self, VALUE event, VALUE rbpriority, VALUE prc);
16
+
17
+ static void init_events();
18
+
19
+ /* vim: set ts=4 sts=4 sw=4 et cindent: */
@@ -0,0 +1,17 @@
1
+ /*
2
+ * Copyright (c) 2013, Autumn Perrault, et al.
3
+ * All rights reserved.
4
+ * This free software is distributed under the FreeBSD license (see LICENSE).
5
+ *
6
+ */
7
+
8
+ #ifndef __SYNDI_INTEGER_H__
9
+ #define __SYNDI_INTEGER_H__
10
+
11
+ void init_integer();
12
+ VALUE swar_bits_set(VALUE self);
13
+ VALUE modular_power(VALUE self, VALUE exponent, VALUE modulus);
14
+
15
+ #endif
16
+
17
+ /* vim: set ts=4 sts=4 sw=4 et cindent: */
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright (c) 2013, Autumn Perrault, et al.
3
+ * All rights reserved.
4
+ * This free software is distributed under the FreeBSD license (see LICENSE).
5
+ *
6
+ */
7
+
8
+ #ifndef __SYNDI_LOGGER_H__
9
+ #define __SYNDI_LOGGER_H__
10
+
11
+ #include <errno.h>
12
+ #include <sys/stat.h>
13
+ #include <string.h>
14
+ #include <time.h>
15
+ #ifndef _WIN32
16
+ #include <unistd.h>
17
+ #endif
18
+
19
+ /* Set format based on target OS. */
20
+ #ifdef _WIN32
21
+ #define LOG_FILE_FORMAT "logs\\%Y%m%d.log"
22
+ #else
23
+ #define LOG_FILE_FORMAT "logs/%Y%m%d.log"
24
+ #endif
25
+
26
+ /* This is based on the desired output give or take a few characters. */
27
+ #define MAX_TIME_STRING_LENGTH 18
28
+
29
+ /* ("YYYY-MM-DD HH:MM:SS +ZZZZ") "YEAR-MONTH-DAY HOUR:MINUTES:SECONDS UTC_OFFSET" */
30
+ #define LOG_TIME_FORMAT_LENGTH 25
31
+
32
+ extern VALUE cLogger;
33
+ void init_syndi_logger();
34
+
35
+ /* Ruby-accessible methods */
36
+ VALUE logger_init(VALUE self);
37
+
38
+ VALUE logger_fatal(VALUE self, VALUE message);
39
+ VALUE logger_error(int argc, VALUE *argv, VALUE message);
40
+ VALUE logger_verbose(VALUE self, VALUE message, VALUE level);
41
+ VALUE logger_warning(VALUE self, VALUE message);
42
+ VALUE logger_info(VALUE self, VALUE message);
43
+
44
+ /* internal functions */
45
+ static void log_out2scrn(int type, const char *message, int level);
46
+ static void log_out2file(const char *type, const char *message);
47
+ static void log_dircheck();
48
+
49
+ /* symbolic constants for event types */
50
+ #define TYPE_FATAL 0
51
+ #define TYPE_ERROR 1
52
+ #define TYPE_WARNING 2
53
+ #define TYPE_INFO 3
54
+ #define TYPE_DEBUG 4
55
+
56
+ #endif
data/lib/csyndi.so ADDED
Binary file
data/lib/syndi.rb ADDED
@@ -0,0 +1,137 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (see LICENSE).
3
+
4
+ require 'syndi/rubyext/string'
5
+ require 'syndi/version'
6
+ require 'fileutils'
7
+
8
+ module Syndi
9
+ extend self
10
+
11
+ # @return [Boolean] Whether we're installed as a gem.
12
+ def gem?
13
+ begin
14
+ # If we already checked, just return the result of that.
15
+ return @gem if defined? @gem
16
+
17
+ # Otherwise, check.
18
+ result = Gem.path.each do |gempath|
19
+ break true if __FILE__ =~ /^#{Regexp.escape gempath}/
20
+ end
21
+ @gem = (result == true ? true : false)
22
+ ensure
23
+ @gem ||= false
24
+ end
25
+ end
26
+
27
+ # @return [Boolean] Whether we're running on Microsoft Windows.
28
+ def windows?
29
+ begin
30
+ return @windows if defined? @windows
31
+ if ::RbConfig::CONFIG['host_os'] =~ /bccwin|djgpp|mswin|mingw|cygwin|wince/i
32
+ @windows = true
33
+ else
34
+ @windows = false
35
+ end
36
+ ensure
37
+ @windows ||= false
38
+ end
39
+ end
40
+
41
+ # This fixes coloring issues on Windows--or at least, the ones with which we
42
+ # need be concerned.
43
+ def windows_colored
44
+ colors = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
45
+ extras = [:clear, :bold, :underline, :reversed]
46
+
47
+ colors.each do |col|
48
+ String.send(:define_method, col, proc { self })
49
+ end
50
+ extras.each do |extr|
51
+ String.send(:define_method, extr, proc { self })
52
+ end
53
+ end
54
+
55
+ ###################
56
+ # central methods #
57
+ ###################
58
+
59
+ # Retrieve the application data directory.
60
+ #
61
+ # @return [String]
62
+ def dir
63
+ @app_dir ||= File.join ENV['HOME'], '.syndi'
64
+ end
65
+
66
+ # Set the application data directory.
67
+ def dir= directory
68
+ FileUtils.mkdir_p directory unless Dir.exists? directory
69
+ Dir.chdir directory
70
+ @app_dir = directory
71
+ end
72
+
73
+ # Initiate Syndi with command-line +options+.
74
+ #
75
+ # @param [Slop] options The command-line options.
76
+ def go options
77
+
78
+ end
79
+
80
+ # Logger access.
81
+ #
82
+ # @return [Syndi::Logger]
83
+ def log
84
+ @logger ||= Syndi::Logger.new
85
+ end
86
+
87
+ # Central event system access.
88
+ #
89
+ # @return [Syndi::Events]
90
+ def events
91
+ @event_manager ||= Syndi::Events.new
92
+ end
93
+
94
+ # Configuration access.
95
+ #
96
+ # @return [Syndi::Config]
97
+ def conf
98
+ @configuration ||= Syndi::Config.new
99
+ end
100
+
101
+ # Central Syndi Celluloid actor.
102
+ #
103
+ # @return [Syndi::Actress] Subclass of {Celluloid::Actor}.
104
+ def actress
105
+ @actress ||= Syndi::Actress.new
106
+ end
107
+
108
+ # Execute some code after the given interval.
109
+ #
110
+ # @param [Integer] interval
111
+ #
112
+ # @return [Celluloid::Timer]
113
+ def after interval, &prc
114
+ actress.after interval, &prc
115
+ end
116
+
117
+ # Execute some code every +interval+.
118
+ #
119
+ # @param [Integer] interval
120
+ #
121
+ # @return [Celluloid::Timer]
122
+ def every interval, &prc
123
+ actress.every interval, &prc
124
+ end
125
+
126
+ end
127
+
128
+ if Syndi.windows?
129
+ Syndi.windows_colored
130
+ else
131
+ require 'colored'
132
+ end
133
+
134
+ require 'csyndi'
135
+ %w[events actress config bot].each { |lib| require "syndi/#{lib}" }
136
+
137
+ # vim: set ts=4 sts=2 sw=2 et:
@@ -0,0 +1,12 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (see LICENSE).
3
+
4
+ require 'celluloid'
5
+
6
+ module Syndi
7
+ class Actress
8
+ include Celluloid
9
+ end
10
+ end
11
+
12
+ # vim: set ts=4 sts=2 sw=2 et:
data/lib/syndi/api.rb ADDED
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (see LICENSE).
3
+
4
+ require 'syndi/api/events'
5
+ require 'syndi/api/timers'
6
+
7
+ # vim: set ts=4 sts=2 sw=2 et:
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (see LICENSE).
3
+
4
+ # Namespace: Syndi
5
+ module Syndi
6
+
7
+ # Namespace: API
8
+ module API
9
+
10
+ # A superclass for {Syndi::API::Timers} and {Syndi::API::Events}.
11
+ class Object
12
+
13
+ private
14
+
15
+ # Get a random character.
16
+ #
17
+ # @return [String] A random character.
18
+ def get_rand_char
19
+ chrs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".split(//)
20
+ chrs[rand(chrs.length)]
21
+ end
22
+
23
+ end # class Object
24
+
25
+ end # module API
26
+
27
+ end # module Syndi
28
+
29
+ # vim: set ts=4 sts=2 sw=2 et:
data/lib/syndi/bot.rb ADDED
@@ -0,0 +1,266 @@
1
+ # Copyright (c) 2013, Autumn Perrault, et al. All rights reserved.
2
+ # This free software is distributed under the FreeBSD license (see LICENSE).
3
+
4
+ require 'redis'
5
+
6
+ # Namespace: Syndi
7
+ module Syndi
8
+
9
+ # This is the central class of Syndi, providing all core functionality.
10
+ #
11
+ # It should be additionally noted that for each loaded core library, a readable
12
+ # instance attribute of the library's name will exist, typically pointing to
13
+ # an instance of its respective Library class. (e.g. @irc = <Syndi::IRC::Library>)
14
+ #
15
+ # @!attribute [r] opts
16
+ # @return [Slop] The options object.
17
+ #
18
+ #
19
+ # @!attribute [r] log
20
+ # @return [Syndi::Logger] The logging instance.
21
+ #
22
+ # @!attribute [r] conf
23
+ # @return [Syndi::Config] The configuration instance.
24
+ #
25
+ # @!attribute [r] events
26
+ # @return [Syndi::API::Events] The event system instance.
27
+ #
28
+ # @!attribute [r] clock
29
+ # @return [Syndi::API::Timers] The timer system instance.
30
+ #
31
+ # @!attribute [r] db
32
+ # @return [Redis] The Redis database.
33
+ #
34
+ # @!attribute [r] libs
35
+ # @return [Array<String>] List of loaded core libraries.
36
+ #
37
+ # @!attribute [r] netloop
38
+ # @return [Thread] The thread in which #main_loop is running.
39
+ #
40
+ # @!attribute [r] sockets
41
+ # @return [Array<Object>] A list of socket objects.
42
+ class Bot
43
+
44
+ attr_reader :opts, :log, :conf, :events, :clock, :db, :libs,
45
+ :netloop, :sockets
46
+
47
+ # Create a new instance of Syndi.
48
+ #
49
+ # @param [Hash{String => Object}] opts A hash of options.
50
+ def initialize opts
51
+ # Save options.
52
+ @opts = opts
53
+ end
54
+
55
+ # Initialize this instance.
56
+ def init
57
+
58
+ # Load configuration
59
+ load_config
60
+
61
+ # Initialize the central event system
62
+ @events = Syndi::API::Events.new
63
+
64
+ # Start the timer system.
65
+ @clock = Syndi::API::Timers.new
66
+
67
+ # Prepare for sockets.
68
+ @sockets = []
69
+
70
+ # Initialize the database
71
+ @db = load_database
72
+
73
+ # Load core libraries.
74
+ load_libraries
75
+
76
+ true
77
+ end
78
+
79
+ # Start the bot.
80
+ def start
81
+
82
+ # Call the start event.
83
+ @events.call :start
84
+
85
+ # Throw the program into the main loop.
86
+ @events.threads.each { |thr| thr.join } # block until we're ready to go
87
+ $log.verbose("Producing a thread and entering the main loop...", VUSEFUL) do
88
+ @netloop = Thread.new { main_loop }
89
+ @netloop.join
90
+ end
91
+
92
+ end
93
+
94
+ # Daemonize the bot.
95
+ def daemonize
96
+ $log.info "Forking into the background. . . ."
97
+
98
+ # Direct all incoming data on STDIN and outgoing data on STDOUT/STDERR to /dev/null.
99
+ $stdin = File.open '/dev/null'
100
+ $stdout = $stderr = File.open '/dev/null', 'w'
101
+
102
+ # Fork and retrieve the PID.
103
+ pid = fork
104
+
105
+ # Save it to syndi.pid.
106
+ unless pid.nil?
107
+ File.open('syndi.pid', 'w') { |io| io.puts pid }
108
+ exit 0
109
+ end
110
+ end
111
+
112
+ # Main loop.
113
+ def main_loop
114
+ loop do
115
+ # Build a list of sockets.
116
+ sockets = []
117
+ assoc_objects = {}
118
+ @sockets.each do |o|
119
+ unless o.socket.nil? or o.socket.closed?
120
+ sockets << o.socket
121
+ assoc_objects[o.socket] = o
122
+ end
123
+ end
124
+ next if sockets.empty?
125
+
126
+ # Call #select.
127
+ ready_read, _, _ = IO.select(sockets, [], [], nil)
128
+
129
+ # Iterate through sockets ready for reading.
130
+ ready_read.each do |socket|
131
+ @events.call :net_receive, assoc_objects[socket]
132
+ end
133
+ end
134
+ end
135
+
136
+ # Terminate the bot.
137
+ #
138
+ # @param [String] reason The reason for termination.
139
+ def terminate reason = 'Terminating'
140
+ info "Syndi is terminating owing to thus: #{reason}"
141
+
142
+ # Call :die
143
+ @events.call :die, reason
144
+
145
+ # Close the database.
146
+ @db.disconnect
147
+
148
+ # When dying, allow about three seconds for hooks to execute before
149
+ # fully terminating.
150
+ sleep 3
151
+
152
+ # Delete syndi.pid
153
+ File.delete 'syndi.pid' unless @opts.foreground?
154
+
155
+ exit 0
156
+ end
157
+
158
+ #######
159
+ private
160
+ #######
161
+
162
+ # Load the configuration.
163
+ def load_config
164
+
165
+ # Try to find the file
166
+ # if we're a gem, we'll try ~/.syndi/syndi.yml
167
+ # else we'll try ./conf/syndi.yml
168
+ confpath = nil
169
+ if Syndi.gem?
170
+ confpath = File.join(SYNDI_DIR, 'syndi.yml')
171
+ else
172
+ confpath = File.join('conf', 'syndi.yml')
173
+ end
174
+ confpath = @opts[:conf] if @opts.conf? # --conf=FILE has supreme precedence
175
+
176
+ $log.info "Reading the configuration file #{confpath}..."
177
+ @conf = Syndi::Config.new File.expand_path(confpath)
178
+
179
+ end
180
+
181
+ # Load Syndi libraries.
182
+ def load_libraries
183
+
184
+ $log.info 'Loading core libraries...'
185
+ @libs = []
186
+
187
+ # Iterate through each configured library.
188
+ @conf['libraries'].each do |lib|
189
+ lib.dc!
190
+
191
+ if @libs.include? lib
192
+ # Don't load a library more than once!
193
+ $log.error "Cannot load library twice (#{lib})! Please fix your configuration."
194
+ next
195
+ end
196
+
197
+ begin
198
+ load_library lib
199
+ @libs.push lib
200
+ rescue => e
201
+ $log.error_bt "Failed to load core library '#{lib}': #{e}", e.backtrace
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+
208
+ # Load a core library.
209
+ def load_library lib
210
+ # here is where magic occurs to load a library
211
+ require "syndi/#{lib}"
212
+ instance_variable_set "@#{lib}".to_sym, Object.const_get("LIBRARY_#{lib.uc}")
213
+ define_singleton_method(lib.to_sym) { self.instance_variable_get("@#{__method__}".to_sym) }
214
+ end
215
+
216
+ # Load the Redis database.
217
+ def load_database
218
+
219
+ driver = @conf['database']['driver'] || 'redis'
220
+
221
+ case driver
222
+ when 'redis'
223
+ load_db_redis
224
+ when 'flatfile'
225
+ load_db_flatfile
226
+ end
227
+
228
+ end
229
+
230
+ # Initializes Redis.
231
+ def load_db_redis
232
+
233
+ config = Hash.new
234
+ if host = @conf['database']['address']
235
+ config[:host] = host
236
+ end
237
+ if port = @conf['database']['port']
238
+ config[:port] = port
239
+ end
240
+ if path = @conf['database']['path']
241
+ config[:path] = path
242
+ end
243
+
244
+ redis = Redis.new config
245
+
246
+ if passwd = @conf['database']['password']
247
+ redis.auth passwd
248
+ end
249
+ if id = @conf['database']['number']
250
+ redis.select id
251
+ end
252
+
253
+ redis
254
+
255
+ end
256
+
257
+ # Initializes Flatfile.
258
+ def load_db_flatfile
259
+ FileKV.new 'syndi.db'
260
+ end
261
+
262
+ end # class Bot
263
+
264
+ end # module Syndi
265
+
266
+ # vim: set ts=4 sts=2 sw=2 et: