Browse Source

moved logging and log requests into module format

Vishnu S Iyengar 6 years ago
parent
commit
dff79ab0d3

+ 91
- 0
add_text_events.coffee View File

@@ -0,0 +1,91 @@
1
+_ = require "./utils"
2
+
3
+user_modes = {
4
+  v: "voiced user",
5
+  h: "half operator",
6
+  o: "operator",
7
+  a: "administrator",
8
+  q: "founder",
9
+}
10
+
11
+channel_modes = {
12
+  n: ["permit outside messages", "prohibit outside messages"],
13
+  t: _(["require", "not require"]).map((p) =>
14
+    p + " operator status to change the topic"
15
+  ),
16
+  m: ["moderated", "not moderated"],
17
+  i: ["invite only", "not require invitation"],
18
+  p: ["private", "public"],
19
+  s: ["secret", "no longer remain a secret"],
20
+}
21
+
22
+module.exports = (channel_name, self_nick, bot) ->
23
+  emit_text = (t) => bot.emit 'text', t
24
+  listeners = [{
25
+      type: "join"
26
+      listener: (channel, nick) =>
27
+        emit_text "#{nick} has joined the channel"
28
+    },{
29
+      type: "part"
30
+      listener: (channel, nick, reason) =>
31
+        emit_text "#{nick} has left the channel#{if reason then " (#{reason})" else ''}"
32
+    },{
33
+      type: "kick"
34
+      listener: (channel, nick, actor, reason) =>
35
+        emit_text "#{nick} has been kicked by #{actor}#{if reason then " (#{reason})" else ''}"
36
+    },{
37
+      type: "quit"
38
+      listener: (nick, message, channels) =>
39
+        emit_text "#{nick} quit the channel (#{message})"
40
+    },{
41
+      type: "nick"
42
+      listener: (oldnick, newnick) =>
43
+        emit_text "#{oldnick} is now known as #{newnick}"
44
+    },{
45
+      type: "message"
46
+      listener: (from, to, message) =>
47
+        emit_text "<#{from}>#{message}" if channel_name is to
48
+    },{
49
+      type: "selfMessage"
50
+      listener: (to, message) =>
51
+        emit_text "<#{self_nick}> #{message}" if channel_name is to
52
+    },{
53
+      type: "action"
54
+      listener: (from, to, message) =>
55
+        emit_text "*#{from} message"
56
+    },{
57
+      type: "notice"
58
+      listener: (from, to, message) =>
59
+        emit_text "---<#{from}> #{message}" if channel_name is to
60
+    },{
61
+      type: "topic"
62
+      listener: (channel, topic, nick) =>
63
+        emit_text "#{nick} changed the channel topic to #{topic}"
64
+    },{
65
+      type: "raw"
66
+      listener: (message) =>
67
+        emit_text "#{message.nick} changed the channel topic to #{message.args[1]}" if message.command is "TOPIC"
68
+        if message.command is "MODE" and channel_name is message.args[0]
69
+          modes = message.args[1].split("")
70
+          adding = modes.shift() is "+"
71
+          other_params = message.args.slice(2)
72
+          _(modes).each (mode) =>
73
+            if _(["+", "-"]).include(mode)
74
+              adding = mode is "+"
75
+              return
76
+            if _(user_modes).chain().keys().include(mode).value()
77
+              emit_text "#{other_params.shift()} has been #{if adding then "promoted to " else "demoted from "} #{user_modes[mode]} by #{message.nick}"
78
+            else if mode is "b"
79
+              emit_text "#{message.nick} #{if adding then " set a ban on " else " removed the ban on "} #{other_params.shift()}"
80
+            else if mode is "k"
81
+              emit_text "#{message.nick} changed the room to #{if adding then "require a key of #{other_params.shift()}" else "not require a key"}"
82
+            else if mode is "l"
83
+              emit_text "#{message.nick} changed the room to #{if adding then "limit the number of users to #{other_params.shift()}" else "remove the limit on room members"}"
84
+            else if _(channel_modes).chain().keys().include(mode).value()
85
+              emit_text "#{message.nick} changed the room to #{if adding then channel_modes[mode][0] else channel_modes[mode][1]}"
86
+            else
87
+              emit_text "#{message.nick} changed the mode to #{if adding then "+" else "-"} #{mode}"
88
+  }]
89
+  _(listeners).each (l) -> bot.on l.type, l.listener
90
+
91
+

+ 4
- 4
bot.coffee View File

@@ -1,9 +1,9 @@
1 1
 _ = require("./utils")
2 2
 fs = require("fs")
3 3
 settings = JSON.parse(fs.readFileSync("#{__dirname}/data/settings.json", "ascii"))
4
-IrcToText = require("./irc_to_text")
5
-ircToText = new IrcToText(settings['channel'], settings['nick'])
6
-ircLogger = require("./irc_log").Logger(ircToText)
4
+
5
+# ircToText = new IrcToText(settings['channel'], settings['nick'])
6
+# ircLogger = require("./irc_log").Logger(ircToText)
7 7
 Modules = require('./modules')
8 8
 {app, start_webserver} = require("./web/app")
9 9
 users = require("./model")
@@ -13,7 +13,7 @@ create_bot = require('./create_bot')
13 13
 users.on 'load', ->
14 14
   bot = create_bot(settings)
15 15
   _(users.listeners).each (l) -> bot.on l.type, l.listener
16
-  _(ircToText.listeners()).each (l) -> bot.on l.type, l.listener
16
+  # _(ircToText.listeners()).each (l) -> bot.on l.type, l.listener
17 17
   modules.initialize(bot, app)
18 18
   start_webserver(settings.port)
19 19
 

+ 3
- 0
create_bot.coffee View File

@@ -2,6 +2,7 @@ EventEmitter = require('events').EventEmitter
2 2
 irc = require("irc")
3 3
 fs = require("fs")
4 4
 misaka_adjectives = JSON.parse(fs.readFileSync("#{__dirname}/misaka_adjectives.json", "ascii"))
5
+add_text_events = require("./add_text_events")
5 6
 
6 7
 module.exports = ({channel, server, nick, server_password}) ->
7 8
   bot = new irc.Client(server, nick, {
@@ -9,9 +10,11 @@ module.exports = ({channel, server, nick, server_password}) ->
9 10
     floodProtection: true,
10 11
     floodProtectionDelay: 500,
11 12
   })
13
+  add_text_events(channel, nick, bot)
12 14
   bot.addListener "registered", ->
13 15
     bot.say "nickserv", "identify #{server_password}"
14 16
 
17
+
15 18
   misakify = (command, result) ->
16 19
     adjectives = misaka_adjectives["generic"]
17 20
     "#{result}, said #{nick} #{_(adjectives).rand()}"

+ 0
- 98
irc_to_text.coffee View File

@@ -1,98 +0,0 @@
1
-_ = require("underscore")
2
-require "./utils"
3
-util = require("util")
4
-EventEmitter = require("events").EventEmitter
5
-
6
-user_modes = {
7
-  v: "voiced user",
8
-  h: "half operator",
9
-  o: "operator",
10
-  a: "administrator",
11
-  q: "founder",
12
-}
13
-
14
-channel_modes = {
15
-  n: ["permit outside messages", "prohibit outside messages"],
16
-  t: _(["require", "not require"]).map((p) =>
17
-    p + " operator status to change the topic"
18
-  ),
19
-  m: ["moderated", "not moderated"],
20
-  i: ["invite only", "not require invitation"],
21
-  p: ["private", "public"],
22
-  s: ["secret", "no longer remain a secret"],
23
-}
24
-
25
-class IrcToText extends EventEmitter
26
-  constructor: (@channel, @selfNick) ->
27
-
28
-  text: (t) =>
29
-    @emit 'text', t
30
-
31
-  listeners: => [{
32
-      type: "join"
33
-      listener: (channel, nick) =>
34
-        @text "#{nick} has joined the channel"
35
-    },{
36
-      type: "part"
37
-      listener: (channel, nick, reason) =>
38
-        @text "#{nick} has left the channel#{if reason then " (#{reason})" else ''}"
39
-    },{
40
-      type: "kick"
41
-      listener: (channel, nick, actor, reason) =>
42
-        @text "#{nick} has been kicked by #{actor}#{if reason then " (#{reason})" else ''}"
43
-    },{
44
-      type: "quit"
45
-      listener: (nick, message, channels) =>
46
-        @text "#{nick} quit the channel (#{message})"
47
-    },{
48
-      type: "nick"
49
-      listener: (oldnick, newnick) =>
50
-        @text "#{oldnick} is now known as #{newnick}"
51
-    },{
52
-      type: "message"
53
-      listener: (from, to, message) =>
54
-        @text "<#{from}>#{message}" if @channel is to
55
-    },{
56
-      type: "selfMessage"
57
-      listener: (to, message) =>
58
-        @text "<#{@selfNick}> #{message}" if @channel is to
59
-    },{
60
-      type: "action"
61
-      listener: (from, to, message) =>
62
-        @text "*#{from} message"
63
-    },{
64
-      type: "notice"
65
-      listener: (from, to, message) =>
66
-        @text "---<#{from}> #{message}" if @channel is to
67
-    },{
68
-      type: "topic"
69
-      listener: (channel, topic, nick) =>
70
-        @text "#{nick} changed the channel topic to #{topic}"
71
-    },{
72
-      type: "raw"
73
-      listener: (message) =>
74
-        @text "#{message.nick} changed the channel topic to #{message.args[1]}" if message.command is "TOPIC"
75
-        if message.command is "MODE" and @channel is message.args[0]
76
-          modes = message.args[1].split("")
77
-          adding = modes.shift() is "+"
78
-          other_params = message.args.slice(2)
79
-          _(modes).each (mode) =>
80
-            if _(["+", "-"]).include(mode)
81
-              adding = mode is "+"
82
-              return
83
-            if _(user_modes).chain().keys().include(mode).value()
84
-              @text "#{other_params.shift()} has been #{if adding then "promoted to " else "demoted from "} #{user_modes[mode]} by #{message.nick}"
85
-            else if mode is "b"
86
-              @text "#{message.nick} #{if adding then " set a ban on " else " removed the ban on "} #{other_params.shift()}"
87
-            else if mode is "k"
88
-              @text "#{message.nick} changed the room to #{if adding then "require a key of #{other_params.shift()}" else "not require a key"}"
89
-            else if mode is "l"
90
-              @text "#{message.nick} changed the room to #{if adding then "limit the number of users to #{other_params.shift()}" else "remove the limit on room members"}"
91
-            else if _(channel_modes).chain().keys().include(mode).value()
92
-              @text "#{message.nick} changed the room to #{if adding then channel_modes[mode][0] else channel_modes[mode][1]}"
93
-            else
94
-              @text "#{message.nick} changed the mode to #{if adding then "+" else "-"} #{mode}"
95
-  }]
96
-
97
-module.exports = IrcToText
98
-

+ 2
- 1
modules.coffee View File

@@ -22,6 +22,7 @@ class Modules
22 22
     @_private_commands = _({}).extend(_(instances).pluck('private_commands')...)
23 23
     @_message_listeners = extract_array_prop instances, 'message_listeners'
24 24
     @_private_listeners = extract_array_prop instances, 'private_listeners'
25
+    @_text_listeners = extract_array_prop instances, 'text_listeners'
25 26
     @web_extensions = @extract_web_extensions instances
26 27
     _(['high', 'medium', 'low']).each (priority) =>
27 28
       _(@web_extensions[priority]).each (ext_fn) -> ext_fn(app)
@@ -30,12 +31,12 @@ class Modules
30 31
     channel = @options['settings']['channel']
31 32
     @bot.on "message#{channel}", @on_channel_msg
32 33
     @bot.on 'action', (from, to, msg) => @on_channel_msg(from, msg) if to is channel
33
-
34 34
     @bot.on 'pm', (from, msg) =>
35 35
       _(@_private_listeners).each (l) -> l(from, msg)
36 36
       [command, rest...] = _(msg.split(" ")).compact()
37 37
       if command and typeof (@_private_commands[command]) is "function"
38 38
         @_private_commands[command] from, rest, (r) => @bot.say from, r
39
+    _(@_text_listeners).each (l) => @bot.on 'text', l
39 40
 
40 41
   on_channel_msg: (from, msg) =>
41 42
     _(@_message_listeners).each (l) -> l(from, msg)

+ 11
- 7
modules/Readme.md View File

@@ -16,7 +16,7 @@ your constructor will get called with a map containing the keys
16 16
 * emitter: an emitter which you can use to emit text onto the channel
17 17
 
18 18
 ## Functionality ##
19
-	Any module can provide any combination of the following types of functionality.
19
+Any module can provide any combination of the following types of functionality.
20 20
 
21 21
 1. any number of commands executed by typing *!&lt;command_name&gt; &lt;arguments&gt;* on the channel.
22 22
 2. any number of private commands executed by pming the bot.
@@ -28,8 +28,7 @@ of the above types but any combination that makes sense as a whole.
28 28
 
29 29
 ### Commands ###
30 30
 
31
-	to expose commands your module must expose a property called *commands* which is a mapping from
32
-	the command_name to functions that are invoked when the command is called.
31
+to expose commands your module must expose a property called *commands* which is a mapping from the command_name to functions that are invoked when the command is called.
33 32
 
34 33
 * the command gets these parameters
35 34
 	1. receives the nick of the person who invoked it.
@@ -41,8 +40,7 @@ types *!help &lt;command_name&gt;*
41 40
 
42 41
 ### Private Commands ###
43 42
 
44
-	to expose private commands your module must expose a property called *private_commands* which is a mapping from
45
-	the command name to functions that are invoked when the command is invoked.
43
+to expose private commands your module must expose a property called *private_commands* which is a mapping from the command name to functions that are invoked when the command is invoked.
46 44
 
47 45
 * the private command gets these parameters
48 46
 	1. receives the nick of the person who invoked it.
@@ -52,7 +50,7 @@ types *!help &lt;command_name&gt;*
52 50
 * for examples look at the modules **alert** or **msg_box**.
53 51
 
54 52
 ### Message Listeners ###
55
-	to expose message_listeners your module must expose a property called *message_listeners* which is an array of functions.
53
+to expose message\_listeners your module must expose a property called *message_listeners* which is an array of functions.
56 54
 
57 55
 * message\_listeners get a copy of every message and action and can react to them if necessary. When invoked a
58 56
 message\_listener receives
@@ -62,11 +60,17 @@ message\_listener receives
62 60
 * for examples look at the modules **imdb\_url\_identifier** or **tell**
63 61
 
64 62
 ### Private Listeners ###
65
-	to expose private_listeners your module must expose a property called *message_listeners* which is an array of functions. private_listeners get a copy of every message sent via pm. When invoked a private_listener receives
63
+to expose private\_listeners your module must expose a property called *private_listeners* which is an array of functions. private\_listeners get a copy of every message sent via pm. When invoked a private_listener receives
66 64
 
67 65
 1. the nick of the person who sent the message
68 66
 2. the remaining text on that line
69 67
 
68
+### Text Listeners ###
69
+
70
+to expose text\_listeners, your module must expose a property called *text_listeners* which is an array of functions. text\_listeners get a copy of nearly all events in the channel in a standard text format. This includes messages by the bot itself. The primary purpose of this is to display irc text to a user. When invoked a text\_listener receives
71
+
72
+1. a line of text indicating what has just occurred.
73
+
70 74
 ### Web Extensions ###
71 75
 the web server runs a web framework called express. documentation for express can be seen [here](http://expressjs.com/)
72 76
 

modules/log_request.coffee → modules/irc_logs.coffee View File

@@ -1,13 +1,18 @@
1 1
 fs = require("fs")
2 2
 _ = require('../utils')
3 3
 PEG = require("pegjs")
4
+Logger = require('./irc_logs/logger')
5
+express = require('express')
6
+ejs = require('ejs')
4 7
 parser = PEG.buildParser(fs.readFileSync("#{__dirname}/log_request/log_request.pegjs", "ascii"))
5 8
 
6
-class LogRequest
7
-  constructor: ({settings}) ->
9
+class IrcLogs
10
+  constructor: (settings: {baseURL, port}) ->
8 11
     @commands = {logs: @command}
9 12
     @command._help = "Display logs for the channel for some point in time. usage: !logs <x days, y hours, z mins ago> or !logs now or !logs q <search terms>"
10
-    @url = "#{settings["baseURL"]}:#{settings["port"]}"
13
+    @url = "#{baseURL}:#{port}"
14
+    @text_listeners = [new Logger().log]
15
+    @web_extensions = {'low': @display_logs}
11 16
 
12 17
   command: (from, tokens, cb) =>
13 18
     cb @parse(tokens)
@@ -33,4 +38,12 @@ class LogRequest
33 38
     catch err
34 39
       "that makes no sense"
35 40
 
36
-module.exports = LogRequest
41
+  display_logs: (app) =>
42
+    display_logs = fs.readFileSync("#{__dirname}/irc_logs/display_logs.ejs", "utf8")
43
+    app.use('/logs', express.static("#{__dirname}/../data/irclogs"))
44
+    app.use('/irc_logs', express.static("#{__dirname}/irc_logs/static"))
45
+    app.get "/", (req, res) =>
46
+      res.send ejs.render(display_logs, locals: title: "MISAKA logs")
47
+
48
+
49
+module.exports = IrcLogs

web/views/index.ejs → modules/irc_logs/display_logs.ejs View File

@@ -3,19 +3,19 @@
3 3
 <head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
4 4
 	<title><%= title %></title>
5 5
 	<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
6
-	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
6
+	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
7 7
 	<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
8
-	<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js"></script>
9
-	<script type="text/javascript" src="javascripts/logs.js"></script>	
8
+	<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
9
+	<script type="text/javascript" src="irc_logs/logs.js"></script>
10 10
 	<script type="text/javascript" src="javascripts/underscore.date.min.js"></script>
11
-	<script id="logTemplate" type="text/x-jquery-tmpl"> 
11
+	<script id="logTemplate" type="text/x-jquery-tmpl">
12 12
 		{{each Logs}}
13 13
 			<span>
14 14
 				<a href='#${$value.timestamp}' name='${$value.timestamp}'>${$value.date}</a>:&nbsp;&nbsp;${$value.msg}
15 15
 			</span>
16 16
 			<br/>
17 17
 		{{/each}}
18
-	</script>	
18
+	</script>
19 19
 </head>
20 20
 <body id="content">
21 21
 </body>

irc_log.coffee → modules/irc_logs/logger.coffee View File

@@ -1,17 +1,18 @@
1 1
 fs = require("fs")
2
-_ = require("underscore")
3
-require "./utils"
2
+path = require("path")
3
+_ = require "../../utils"
4
+basepath = path.join(__dirname, "../../data/irclogs")
4 5
 
5 6
 class Logger
6 7
   constructor: ->
7 8
     @_msgs = []
8 9
     @_flushing = false
9 10
 
10
-  _writestream: (gmtDate) ->
11
+  _writestream: (gmtDate) =>
11 12
     return @_ws  if @_gmtDate and @_gmtDate is gmtDate
12 13
     @_ws.end()  if @_ws
13 14
     @_gmtDate = gmtDate
14
-    @_ws = fs.createWriteStream("#{__dirname}/data/irclogs/" + gmtDate + ".log",
15
+    @_ws = fs.createWriteStream("#{basepath}/#{gmtDate}.log",
15 16
       encoding: "utf-8"
16 17
       flags: "a"
17 18
     )
@@ -37,8 +38,5 @@ class Logger
37 38
       @_flushing = false
38 39
       process.nextTick @_maybeFlush unless _(@_msgs).isEmpty()
39 40
 
40
-exports.Logger = (textEmittor) ->
41
-  logger = new Logger
42
-  textEmittor.on "text", logger.log
43
-  logger
41
+module.exports = Logger
44 42
 

web/public/javascripts/logs.js → modules/irc_logs/static/logs.js View File

@@ -118,6 +118,7 @@ function init() {
118 118
       var location = _(data).sortedIndex({timestamp: timestamp}, function(log){
119 119
         return log.timestamp;
120 120
       });
121
+      if (location >= data.length) location = data.length - 1
121 122
       topMarker = {date: date, location: location};
122 123
       bottomMarker = {date: date, location: location};
123 124
       logTemplate.tmpl({Logs: [data[location]]}).appendTo("#content");
@@ -133,7 +134,7 @@ function getLog(dateString, cb) {
133 134
     if (dateString in logs) {
134 135
         cb(logs[dateString]);
135 136
     } else {
136
-        $.get("/" + dateString + ".log", function(data){
137
+        $.get("/logs/" + dateString + ".log", function(data){
137 138
             logs[dateString] = _(data.split('\n')).chain().
138 139
             reject(function(l) {
139 140
                 return l === ''

+ 0
- 2
web/app.coffee View File

@@ -58,8 +58,6 @@ module.exports =
58 58
 
59 59
   #
60 60
   # app.use(express.static("#{__dirname}/../data/irclogs"))
61
-  # app.use(express.cookieParser())
62
-  # app.use(auth)
63 61
   # app.get "/", (req, res, next) ->
64 62
   #   res.type("html")
65 63
   #   res.send ejs.render(views["index"], locals: title: "MISAKA logs")

Loading…
Cancel
Save