salticid 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +7 -0
- data/README.markdown +11 -0
- data/lib/monkeypatch.rb +21 -0
- data/lib/salticid.rb +205 -0
- data/lib/salticid/config.rb +17 -0
- data/lib/salticid/gateway.rb +23 -0
- data/lib/salticid/group.rb +99 -0
- data/lib/salticid/host.rb +600 -0
- data/lib/salticid/host/ip.rb +19 -0
- data/lib/salticid/interface.rb +192 -0
- data/lib/salticid/interface/conversation_view.rb +150 -0
- data/lib/salticid/interface/host_view.rb +123 -0
- data/lib/salticid/interface/ncurses.rb +30 -0
- data/lib/salticid/interface/resizable.rb +28 -0
- data/lib/salticid/interface/tab_view.rb +134 -0
- data/lib/salticid/interface/view.rb +49 -0
- data/lib/salticid/message.rb +8 -0
- data/lib/salticid/role.rb +98 -0
- data/lib/salticid/role_proxy.rb +26 -0
- data/lib/salticid/task.rb +49 -0
- data/lib/salticid/version.rb +3 -0
- data/lib/snippets/init.rb +5 -0
- data/lib/snippets/object/__dir__.rb +23 -0
- data/lib/snippets/object/instance_exec.rb +14 -0
- data/lib/snippets/string/slash.rb +6 -0
- data/lib/snippets/symbol/slash.rb +6 -0
- data/lib/snippets/symbol/to_proc.rb +15 -0
- metadata +167 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Salticid::Host::IP
|
|
2
|
+
# Host methods for IP addresses
|
|
3
|
+
|
|
4
|
+
# Get all active IP addresses.
|
|
5
|
+
def ips
|
|
6
|
+
`ifconfig -a`.split("\n\n").map { |stanza|
|
|
7
|
+
stanza.split("\n").find { |line|
|
|
8
|
+
line =~ /inet addr:\s*([\d\.]{7..15})/
|
|
9
|
+
$1
|
|
10
|
+
}
|
|
11
|
+
}.compact
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def private_ips
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def public_ips
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
class Salticid
|
|
2
|
+
class Interface
|
|
3
|
+
require 'ncurses'
|
|
4
|
+
require 'salticid/interface/ncurses'
|
|
5
|
+
require 'salticid/interface/resizable'
|
|
6
|
+
require 'salticid/interface/view'
|
|
7
|
+
require 'salticid/interface/tab_view'
|
|
8
|
+
require 'salticid/interface/host_view'
|
|
9
|
+
|
|
10
|
+
COLORS = {
|
|
11
|
+
:info => Ncurses::COLOR_WHITE,
|
|
12
|
+
:error => Ncurses::COLOR_RED,
|
|
13
|
+
:warn => Ncurses::COLOR_YELLOW,
|
|
14
|
+
:debug => Ncurses::COLOR_CYAN,
|
|
15
|
+
:finished => Ncurses::COLOR_GREEN
|
|
16
|
+
}
|
|
17
|
+
COLOR_PAIRS = {}
|
|
18
|
+
|
|
19
|
+
# Keys
|
|
20
|
+
KEY_SPACE = 32
|
|
21
|
+
KEY_ENTER = 13
|
|
22
|
+
KEY_SCROLL_UP = 258
|
|
23
|
+
KEY_SCROLL_DOWN = 259
|
|
24
|
+
|
|
25
|
+
def self.interfaces
|
|
26
|
+
@interfaces ||= []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.shutdown *args
|
|
30
|
+
@interfaces.each do |i|
|
|
31
|
+
i.shutdown *args
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :hosts, :salticid
|
|
36
|
+
|
|
37
|
+
def initialize(salticid)
|
|
38
|
+
self.class.interfaces << self
|
|
39
|
+
|
|
40
|
+
# Set up ncurses
|
|
41
|
+
Ncurses.initscr
|
|
42
|
+
Ncurses.cbreak
|
|
43
|
+
Ncurses.noecho
|
|
44
|
+
Ncurses.nonl
|
|
45
|
+
Ncurses.stdscr.intrflush false
|
|
46
|
+
Ncurses.stdscr.keypad true
|
|
47
|
+
Ncurses.start_color
|
|
48
|
+
Ncurses.use_default_colors
|
|
49
|
+
|
|
50
|
+
@salticid = salticid
|
|
51
|
+
@hosts = []
|
|
52
|
+
@tabs = TabView.new(
|
|
53
|
+
self,
|
|
54
|
+
:height => 1
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@tabs.window.keypad true
|
|
58
|
+
|
|
59
|
+
colorize
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Add a new tab interface backed by source.
|
|
63
|
+
def add_tab(host)
|
|
64
|
+
@tabs.active.hide if tab
|
|
65
|
+
|
|
66
|
+
hv = HostView.new(
|
|
67
|
+
self,
|
|
68
|
+
:host => host,
|
|
69
|
+
:top => 1,
|
|
70
|
+
:height => Ncurses.LINES - 1
|
|
71
|
+
)
|
|
72
|
+
hv.on_state_change do |state|
|
|
73
|
+
@tabs.render
|
|
74
|
+
end
|
|
75
|
+
@tabs << hv
|
|
76
|
+
tab.show
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def colorize
|
|
80
|
+
COLORS.each_with_index do |c, i|
|
|
81
|
+
Ncurses.init_pair i + 1, c.last, -1
|
|
82
|
+
COLOR_PAIRS[c.first] = Ncurses.COLOR_PAIR(i + 1)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def delete_tab(target)
|
|
87
|
+
begin
|
|
88
|
+
target.hide
|
|
89
|
+
@tabs.delete target
|
|
90
|
+
ensure
|
|
91
|
+
tab.show if tab
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Join the mainloop.
|
|
96
|
+
def join
|
|
97
|
+
@main.join
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# List channels and topics
|
|
101
|
+
def list(*channels)
|
|
102
|
+
@connection.list *channels
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Mainloop
|
|
106
|
+
def main
|
|
107
|
+
@main = Thread.new do
|
|
108
|
+
Thread.current.priority = -1
|
|
109
|
+
trap("WINCH") { resize if Thread.current.alive? }
|
|
110
|
+
|
|
111
|
+
loop do
|
|
112
|
+
# Get character
|
|
113
|
+
if IO.select [$stdin], nil, nil, 1
|
|
114
|
+
char = @tabs.window.getch
|
|
115
|
+
else
|
|
116
|
+
Thread.pass
|
|
117
|
+
next
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Do stuff
|
|
121
|
+
case char
|
|
122
|
+
when ?\t
|
|
123
|
+
@tabs.scroll
|
|
124
|
+
when ?q
|
|
125
|
+
shutdown
|
|
126
|
+
when Ncurses::KEY_LEFT
|
|
127
|
+
@tabs.scroll -1
|
|
128
|
+
when Ncurses::KEY_RIGHT
|
|
129
|
+
@tabs.scroll 1
|
|
130
|
+
when Ncurses::KEY_PPAGE
|
|
131
|
+
tab.scroll -tab.height / 2
|
|
132
|
+
when Ncurses::KEY_NPAGE
|
|
133
|
+
tab.scroll tab.height / 2
|
|
134
|
+
when Ncurses::KEY_UP
|
|
135
|
+
tab.scroll -1
|
|
136
|
+
when Ncurses::KEY_DOWN
|
|
137
|
+
tab.scroll 1
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Resize to fit display
|
|
144
|
+
def resize
|
|
145
|
+
# We need to nuke ncurses to pick up the new dimensions
|
|
146
|
+
Ncurses.def_prog_mode
|
|
147
|
+
Ncurses.endwin
|
|
148
|
+
Ncurses.reset_prog_mode
|
|
149
|
+
height, width = Ncurses.dimensions
|
|
150
|
+
|
|
151
|
+
# Resize tabs
|
|
152
|
+
@tabs.resize(
|
|
153
|
+
:width => width,
|
|
154
|
+
:height => height
|
|
155
|
+
)
|
|
156
|
+
@tabs.render
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Shut down interface
|
|
160
|
+
def shutdown(and_exit = true)
|
|
161
|
+
# Shut down views
|
|
162
|
+
@tabs.shutdown
|
|
163
|
+
|
|
164
|
+
# Shut down ncurses
|
|
165
|
+
Ncurses.echo
|
|
166
|
+
Ncurses.nocbreak
|
|
167
|
+
Ncurses.nl
|
|
168
|
+
Ncurses.endwin
|
|
169
|
+
|
|
170
|
+
# Stop interface
|
|
171
|
+
@main.exit rescue nil
|
|
172
|
+
|
|
173
|
+
# Exit if okay
|
|
174
|
+
exit if and_exit
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Switch to a different conversation
|
|
178
|
+
def switch(target = nil)
|
|
179
|
+
if target
|
|
180
|
+
# Switch to a specific tab
|
|
181
|
+
@tabs.switch_to_label target
|
|
182
|
+
else
|
|
183
|
+
# Switch to the next tab
|
|
184
|
+
@tabs.scroll
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def tab
|
|
189
|
+
@tabs.active
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
module IRC
|
|
2
|
+
require ROOT + '/interface'
|
|
3
|
+
require ROOT + '/view'
|
|
4
|
+
class Interface
|
|
5
|
+
class ConversationView < View
|
|
6
|
+
|
|
7
|
+
attr_accessor :messages, :window
|
|
8
|
+
|
|
9
|
+
COLORS = [
|
|
10
|
+
Ncurses::COLOR_WHITE,
|
|
11
|
+
Ncurses::COLOR_RED,
|
|
12
|
+
Ncurses::COLOR_GREEN,
|
|
13
|
+
Ncurses::COLOR_YELLOW,
|
|
14
|
+
Ncurses::COLOR_BLUE,
|
|
15
|
+
Ncurses::COLOR_MAGENTA,
|
|
16
|
+
Ncurses::COLOR_CYAN
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def initialize(interface, params = {})
|
|
20
|
+
@messages = []
|
|
21
|
+
|
|
22
|
+
@scroll_position = -1
|
|
23
|
+
|
|
24
|
+
super
|
|
25
|
+
|
|
26
|
+
@color_index = 0
|
|
27
|
+
|
|
28
|
+
@color_map = Hash.new do |hash, key|
|
|
29
|
+
if key
|
|
30
|
+
hash[key] = @color_index.modulo Ncurses.COLOR_PAIRS
|
|
31
|
+
@color_index += 1
|
|
32
|
+
else
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
colorize
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def <<(message)
|
|
41
|
+
# Scroll if at bottom
|
|
42
|
+
@scroll_position += 1 if @scroll_position == @messages.size - 1
|
|
43
|
+
|
|
44
|
+
# Add color
|
|
45
|
+
if message.respond_to? :user
|
|
46
|
+
@color_map[message.user.nick]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@messages << message
|
|
50
|
+
render
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Set up colors
|
|
54
|
+
def colorize
|
|
55
|
+
COLORS.each_with_index do |color, i|
|
|
56
|
+
Ncurses.init_pair i, color, Ncurses::COLOR_BLACK
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def render
|
|
61
|
+
if @hidden
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@window.erase
|
|
66
|
+
|
|
67
|
+
lines_left = @height
|
|
68
|
+
message_i = @scroll_position
|
|
69
|
+
while message_i >= 0
|
|
70
|
+
# Message
|
|
71
|
+
message = @messages[message_i]
|
|
72
|
+
message_i -= 1
|
|
73
|
+
|
|
74
|
+
IRC.log "displaying message #{message}"
|
|
75
|
+
|
|
76
|
+
# Time
|
|
77
|
+
time = message.time.strftime "%H:%M:%S"
|
|
78
|
+
|
|
79
|
+
case message
|
|
80
|
+
when PrivMsg
|
|
81
|
+
color = Ncurses.COLOR_PAIR(@color_map[message.user.nick])
|
|
82
|
+
user = message.user.to_s || ''
|
|
83
|
+
text = message.text
|
|
84
|
+
when Event
|
|
85
|
+
user = ''
|
|
86
|
+
text = message.text
|
|
87
|
+
when Command
|
|
88
|
+
user = message.user.to_s || ''
|
|
89
|
+
text = message.text
|
|
90
|
+
else
|
|
91
|
+
user = message.user.to_s || ''
|
|
92
|
+
text = message.command + ' ' + message.params.join(" ")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
offset = time.length + user.length + 3
|
|
96
|
+
|
|
97
|
+
lines = [text[0, @width - offset]]
|
|
98
|
+
if remaining = text[@width - offset..-1]
|
|
99
|
+
lines += remaining.lines(@width - offset - 1)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Put lines in reverse
|
|
103
|
+
i = lines.size
|
|
104
|
+
while i > 0
|
|
105
|
+
i -= 1
|
|
106
|
+
line = lines[i]
|
|
107
|
+
|
|
108
|
+
lines_left -= 1
|
|
109
|
+
break if lines_left < 0
|
|
110
|
+
|
|
111
|
+
if i.zero?
|
|
112
|
+
# Put top line
|
|
113
|
+
@window.move lines_left, 0
|
|
114
|
+
@window.addstr time + ' '
|
|
115
|
+
@window.attron Ncurses::A_BOLD
|
|
116
|
+
@window.attron color if color
|
|
117
|
+
@window.addstr user
|
|
118
|
+
@window.attroff color if color
|
|
119
|
+
@window.attroff Ncurses::A_BOLD
|
|
120
|
+
@window.addstr ': '
|
|
121
|
+
@window.addstr line
|
|
122
|
+
else
|
|
123
|
+
# Put hanging line
|
|
124
|
+
@window.move lines_left, offset
|
|
125
|
+
@window.addstr line
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
unless @window.cursor[1] == 0
|
|
129
|
+
# Clear rest of line
|
|
130
|
+
@window.clrtoeol
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
@window.refresh
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Scrolls the window by delta messages
|
|
138
|
+
def scroll(delta)
|
|
139
|
+
@scroll_position += delta
|
|
140
|
+
if @scroll_position < 0
|
|
141
|
+
@scroll_position = 0
|
|
142
|
+
elsif @scroll_position >= @messages.size
|
|
143
|
+
@scroll_position = @messages.size - 1
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
render
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
class Salticid
|
|
2
|
+
class Interface
|
|
3
|
+
class HostView < View
|
|
4
|
+
|
|
5
|
+
attr_accessor :messages, :window, :state
|
|
6
|
+
|
|
7
|
+
def initialize(interface, params = {})
|
|
8
|
+
@messages = []
|
|
9
|
+
|
|
10
|
+
@scroll_position = -1
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
|
|
14
|
+
@host = params[:host]
|
|
15
|
+
@host.on_log do |message|
|
|
16
|
+
self << message
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@state = nil
|
|
20
|
+
@on_state_change = proc { |state| }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def <<(message)
|
|
24
|
+
# Scroll if at bottom
|
|
25
|
+
@scroll_position += 1 if @scroll_position == @messages.size - 1
|
|
26
|
+
|
|
27
|
+
@messages << message
|
|
28
|
+
|
|
29
|
+
if @state != message.severity
|
|
30
|
+
@state = message.severity
|
|
31
|
+
@on_state_change.call(@state)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
render
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def on_state_change(&block)
|
|
38
|
+
@on_state_change = block
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def render
|
|
42
|
+
return if @hidden
|
|
43
|
+
|
|
44
|
+
@window.erase
|
|
45
|
+
|
|
46
|
+
lines_left = @height
|
|
47
|
+
message_i = @scroll_position
|
|
48
|
+
while message_i >= 0
|
|
49
|
+
# Message
|
|
50
|
+
message = @messages[message_i]
|
|
51
|
+
message_i -= 1
|
|
52
|
+
|
|
53
|
+
# Time
|
|
54
|
+
time = message.time.strftime "%H:%M:%S"
|
|
55
|
+
|
|
56
|
+
text = message.text
|
|
57
|
+
color = Interface::COLOR_PAIRS[message.severity]
|
|
58
|
+
|
|
59
|
+
offset = time.length + 1
|
|
60
|
+
|
|
61
|
+
width = @width - offset
|
|
62
|
+
lines = text.scan(/[^\n]{1,#{width}}/m)
|
|
63
|
+
|
|
64
|
+
# Put lines in reverse
|
|
65
|
+
i = lines.size
|
|
66
|
+
while i > 0
|
|
67
|
+
i -= 1
|
|
68
|
+
line = lines[i]
|
|
69
|
+
|
|
70
|
+
lines_left -= 1
|
|
71
|
+
break if lines_left < 0
|
|
72
|
+
|
|
73
|
+
if i.zero?
|
|
74
|
+
# Put top line
|
|
75
|
+
@window.move lines_left, 0
|
|
76
|
+
@window.addstr time + ' '
|
|
77
|
+
@window.attron Ncurses::A_BOLD
|
|
78
|
+
@window.attron color if color
|
|
79
|
+
@window.addstr line
|
|
80
|
+
else
|
|
81
|
+
# Put hanging line
|
|
82
|
+
@window.attron Ncurses::A_BOLD
|
|
83
|
+
@window.attron color if color
|
|
84
|
+
@window.move lines_left, offset
|
|
85
|
+
@window.addstr line
|
|
86
|
+
end
|
|
87
|
+
@window.attroff color if color
|
|
88
|
+
@window.attroff Ncurses::A_BOLD
|
|
89
|
+
|
|
90
|
+
unless @window.cursor[1] == 0
|
|
91
|
+
# Clear rest of line
|
|
92
|
+
@window.clrtoeol
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
@window.refresh
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def to_s
|
|
100
|
+
@host.name
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Scrolls the window by delta messages
|
|
104
|
+
def scroll(delta)
|
|
105
|
+
@scroll_position += delta
|
|
106
|
+
if @scroll_position < 0
|
|
107
|
+
@scroll_position = 0
|
|
108
|
+
elsif @scroll_position >= @messages.size
|
|
109
|
+
@scroll_position = @messages.size - 1
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
render
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def shutdown
|
|
116
|
+
@host.on_log do |message|
|
|
117
|
+
puts message.text
|
|
118
|
+
end
|
|
119
|
+
@host = nil
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|