nitro 0.1.2
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/AUTHORS +8 -0
- data/ChangeLog +1546 -0
- data/LICENCE +32 -0
- data/README +278 -0
- data/RELEASES +7 -0
- data/Rakefile +79 -0
- data/bin/cluster.rb +219 -0
- data/doc/architecture.txt +28 -0
- data/doc/bugs.txt +7 -0
- data/doc/css.txt +20 -0
- data/doc/ideas.txt +120 -0
- data/doc/pg.txt +47 -0
- data/doc/svn.txt +82 -0
- data/doc/todo.txt +30 -0
- data/etc/new-project.rb +18 -0
- data/examples/simple/README +15 -0
- data/examples/simple/app.rb +31 -0
- data/examples/simple/conf/apache.conf +100 -0
- data/examples/simple/conf/config.rb +89 -0
- data/examples/simple/conf/debug-config.rb +53 -0
- data/examples/simple/conf/live-config.rb +48 -0
- data/examples/simple/conf/overrides.rb +9 -0
- data/examples/simple/conf/requires.rb +51 -0
- data/examples/simple/ctl +32 -0
- data/examples/simple/env.rb +33 -0
- data/examples/simple/install.rb +12 -0
- data/examples/simple/lib/articles/entities.rb +35 -0
- data/examples/simple/lib/articles/lc-en.rb +36 -0
- data/examples/simple/lib/articles/methods.rb +55 -0
- data/examples/simple/lib/articles/part.rb +58 -0
- data/examples/simple/logs/access_log +2 -0
- data/examples/simple/logs/apache.log +3 -0
- data/examples/simple/logs/app.log +1 -0
- data/examples/simple/logs/events.log +1 -0
- data/examples/simple/root/add-article.sx +15 -0
- data/examples/simple/root/article-form.ss +20 -0
- data/examples/simple/root/comments-form.ss +16 -0
- data/examples/simple/root/comments.si +30 -0
- data/examples/simple/root/index.sx +44 -0
- data/examples/simple/root/shader/shader.xsl +100 -0
- data/examples/simple/root/shader/style.css +9 -0
- data/examples/simple/root/view-article.sx +30 -0
- data/examples/tiny/app.rb +30 -0
- data/examples/tiny/conf/apache.conf +100 -0
- data/examples/tiny/conf/config.rb +67 -0
- data/examples/tiny/conf/requires.rb +40 -0
- data/examples/tiny/ctl +31 -0
- data/examples/tiny/logs/access_log +9 -0
- data/examples/tiny/logs/apache.log +9 -0
- data/examples/tiny/root/index.sx +35 -0
- data/lib/n/app/cluster.rb +219 -0
- data/lib/n/app/cookie.rb +86 -0
- data/lib/n/app/filters/autologin.rb +50 -0
- data/lib/n/app/fragment.rb +67 -0
- data/lib/n/app/handlers.rb +120 -0
- data/lib/n/app/handlers/code-handler.rb +184 -0
- data/lib/n/app/handlers/page-handler.rb +612 -0
- data/lib/n/app/request-part.rb +59 -0
- data/lib/n/app/request.rb +653 -0
- data/lib/n/app/script.rb +398 -0
- data/lib/n/app/server.rb +53 -0
- data/lib/n/app/session.rb +224 -0
- data/lib/n/app/user.rb +47 -0
- data/lib/n/app/webrick-servlet.rb +213 -0
- data/lib/n/app/webrick.rb +70 -0
- data/lib/n/application.rb +187 -0
- data/lib/n/config.rb +31 -0
- data/lib/n/db.rb +217 -0
- data/lib/n/db/README +232 -0
- data/lib/n/db/connection.rb +369 -0
- data/lib/n/db/make-release.sh +26 -0
- data/lib/n/db/managed.rb +235 -0
- data/lib/n/db/mixins.rb +282 -0
- data/lib/n/db/mysql.rb +342 -0
- data/lib/n/db/psql.rb +378 -0
- data/lib/n/db/tools.rb +110 -0
- data/lib/n/db/utils.rb +99 -0
- data/lib/n/events.rb +118 -0
- data/lib/n/l10n.rb +22 -0
- data/lib/n/logger.rb +33 -0
- data/lib/n/macros.rb +53 -0
- data/lib/n/mixins.rb +46 -0
- data/lib/n/parts.rb +154 -0
- data/lib/n/properties.rb +194 -0
- data/lib/n/server.rb +61 -0
- data/lib/n/server/PLAYBACK.txt +8 -0
- data/lib/n/server/RESEARCH.txt +13 -0
- data/lib/n/server/filter.rb +77 -0
- data/lib/n/shaders.rb +167 -0
- data/lib/n/sitemap.rb +188 -0
- data/lib/n/std.rb +69 -0
- data/lib/n/sync/clc.rb +108 -0
- data/lib/n/sync/handler.rb +221 -0
- data/lib/n/sync/server.rb +170 -0
- data/lib/n/tools/README +11 -0
- data/lib/n/ui/date-select.rb +74 -0
- data/lib/n/ui/pager.rb +187 -0
- data/lib/n/ui/popup.rb +45 -0
- data/lib/n/ui/select.rb +41 -0
- data/lib/n/ui/tabs.rb +34 -0
- data/lib/n/utils/array.rb +92 -0
- data/lib/n/utils/cache.rb +144 -0
- data/lib/n/utils/gfx.rb +108 -0
- data/lib/n/utils/hash.rb +148 -0
- data/lib/n/utils/html.rb +147 -0
- data/lib/n/utils/http.rb +98 -0
- data/lib/n/utils/mail.rb +28 -0
- data/lib/n/utils/number.rb +31 -0
- data/lib/n/utils/pool.rb +66 -0
- data/lib/n/utils/string.rb +297 -0
- data/lib/n/utils/template.rb +38 -0
- data/lib/n/utils/time.rb +91 -0
- data/lib/n/utils/uri.rb +193 -0
- data/lib/xsl/base.xsl +205 -0
- data/lib/xsl/ce.xsl +30 -0
- data/lib/xsl/localization.xsl +23 -0
- data/lib/xsl/xforms.xsl +26 -0
- data/test/run.rb +95 -0
- metadata +187 -0
data/lib/n/shaders.rb
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# = Shader
|
|
2
|
+
#
|
|
3
|
+
# The equivalent of a 3d engine shader. Converts the page representation
|
|
4
|
+
# to the html output. Actually converts it to a dynamic page ready for
|
|
5
|
+
# evaluation.
|
|
6
|
+
#
|
|
7
|
+
# === Design:
|
|
8
|
+
#
|
|
9
|
+
# We follow the xp methodology: the shader as simple as possible.
|
|
10
|
+
# In the future we may add mulitple xsls (xsl pipeline) but
|
|
11
|
+
# we done need them now, so we wont code them!
|
|
12
|
+
#
|
|
13
|
+
# - when compiling get the default shader and keep it in the
|
|
14
|
+
# script structure.
|
|
15
|
+
#
|
|
16
|
+
# noo better push them in a request stack!
|
|
17
|
+
#
|
|
18
|
+
# - when rendering:
|
|
19
|
+
# if there is an override shader use it! (example: inject shader)
|
|
20
|
+
# if there is a parent shader use it!
|
|
21
|
+
# if there is a script shader use it!
|
|
22
|
+
# if there is a user shader use it!
|
|
23
|
+
# if there is an app shader use it!
|
|
24
|
+
# no shading!
|
|
25
|
+
#
|
|
26
|
+
# === Think:
|
|
27
|
+
#
|
|
28
|
+
# - are inject override shaders possible ? (no they are
|
|
29
|
+
# dynamic)
|
|
30
|
+
#
|
|
31
|
+
# === TODO:
|
|
32
|
+
#
|
|
33
|
+
# - add monitoring support for xsl's.
|
|
34
|
+
#
|
|
35
|
+
# code:
|
|
36
|
+
# George Moschovitis <gm@navel.gr>
|
|
37
|
+
#
|
|
38
|
+
# (c) 2004 Navel, all rights reserved.
|
|
39
|
+
# $Id: shaders.rb 89 2004-10-20 12:55:58Z gmosx $
|
|
40
|
+
|
|
41
|
+
module N;
|
|
42
|
+
|
|
43
|
+
# = Shader
|
|
44
|
+
#
|
|
45
|
+
# One shader can utilize several xsls to render different pages.
|
|
46
|
+
# the shader selection may be time consuming but is performed once
|
|
47
|
+
# when transforming the script, so its essentially for free (and
|
|
48
|
+
# anyway the xsl transoformation is orders of magnitude slower)
|
|
49
|
+
#
|
|
50
|
+
# There is no need to keep post xsl. I can reuse the same xsl
|
|
51
|
+
# by calling transform again.
|
|
52
|
+
#
|
|
53
|
+
class Shader
|
|
54
|
+
attr_accessor :name
|
|
55
|
+
attr_accessor :xsl_filename
|
|
56
|
+
# the xslt transoformer.
|
|
57
|
+
attr_accessor :xslt
|
|
58
|
+
attr_accessor :mtime
|
|
59
|
+
|
|
60
|
+
def initialize(name, xsl_filename)
|
|
61
|
+
# leave this require here. only inlcude the xslt
|
|
62
|
+
# library if the project needs it.
|
|
63
|
+
require "xml/xslt"
|
|
64
|
+
|
|
65
|
+
@name = name
|
|
66
|
+
@xsl_filename = xsl_filename
|
|
67
|
+
@xslt = XML::XSLT.new
|
|
68
|
+
parse_xsl!
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# transform the given document
|
|
72
|
+
#
|
|
73
|
+
def xsl_transform(document)
|
|
74
|
+
@xslt.xml = document
|
|
75
|
+
return @xslt.serve()
|
|
76
|
+
end
|
|
77
|
+
alias_method :transform, :xsl_transform
|
|
78
|
+
|
|
79
|
+
def xsl
|
|
80
|
+
parse_xsl! if $reload_xsl
|
|
81
|
+
return @xsl
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def to_s
|
|
85
|
+
@name
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# Parse the xsl.
|
|
91
|
+
#
|
|
92
|
+
def parse_xsl!
|
|
93
|
+
$log.debug "Parsing xsl '#{@xsl_filename}'" if $DBG
|
|
94
|
+
@mtime = File.stat(@xsl_filename).mtime
|
|
95
|
+
@xslt.xsl = File.read(@xsl_filename)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# = NilShader
|
|
101
|
+
#
|
|
102
|
+
# A shader that does absolutely nothing.
|
|
103
|
+
#
|
|
104
|
+
# === WARNING: not tested.
|
|
105
|
+
#
|
|
106
|
+
class NilShader < Shader
|
|
107
|
+
def initialize
|
|
108
|
+
@name = "nil"
|
|
109
|
+
@mtime = Time.at(0)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# No transform, just convert to a String.
|
|
113
|
+
def transform(document)
|
|
114
|
+
return document.to_s
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# = ShaderManager
|
|
119
|
+
#
|
|
120
|
+
# Manages the shaders for the webapp.
|
|
121
|
+
#
|
|
122
|
+
# TODO: integrate with sitemap.
|
|
123
|
+
#
|
|
124
|
+
# === Design:
|
|
125
|
+
#
|
|
126
|
+
# - the shader selection may be time consuming but is performed once
|
|
127
|
+
# when transforming the script, so its essentially for free (and
|
|
128
|
+
# anyway the xsl transoformation is orders of magnitude slower)
|
|
129
|
+
#
|
|
130
|
+
class ShaderManager
|
|
131
|
+
# corresponding arrays
|
|
132
|
+
attr_accessor :regex, :shaders
|
|
133
|
+
attr_accessor :default_shader
|
|
134
|
+
|
|
135
|
+
def initialize
|
|
136
|
+
@regex = []
|
|
137
|
+
@shaders = []
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def set_default(shader)
|
|
141
|
+
@default_shader = shader
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def add(regex, shader)
|
|
145
|
+
@regex << regex
|
|
146
|
+
@shaders << shader
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def shader_for_path(path)
|
|
150
|
+
@regex.each_with_index { |rx, idx|
|
|
151
|
+
if path =~ rx
|
|
152
|
+
return @shaders[idx]
|
|
153
|
+
end
|
|
154
|
+
}
|
|
155
|
+
return @default_shader
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def delete(regex)
|
|
159
|
+
if idx = @regex.index(regex)
|
|
160
|
+
@regex.delete_at(idx)
|
|
161
|
+
@shaders.delete_at(idx)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end # module;
|
data/lib/n/sitemap.rb
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# = SiteMap
|
|
2
|
+
#
|
|
3
|
+
# Encapsulates the page structure and additional metadata.
|
|
4
|
+
#
|
|
5
|
+
# === TODO:
|
|
6
|
+
#
|
|
7
|
+
# move out of the UI namespace.
|
|
8
|
+
# include url remapping functionality.
|
|
9
|
+
#
|
|
10
|
+
# === Design
|
|
11
|
+
#
|
|
12
|
+
# Unlike the original version, this is presentation agnostic, and
|
|
13
|
+
# greatly simplified.
|
|
14
|
+
#
|
|
15
|
+
# === Todo:
|
|
16
|
+
#
|
|
17
|
+
# - support strings as titles.
|
|
18
|
+
# - add support to read the map from a config file.
|
|
19
|
+
# - rename to appmap ?
|
|
20
|
+
#
|
|
21
|
+
# code:
|
|
22
|
+
# George Moschovitis <gm@navel.gr>
|
|
23
|
+
#
|
|
24
|
+
# (c) 2004 Navel, all rights reserved.
|
|
25
|
+
# $Id: sitemap.rb 71 2004-10-18 10:50:22Z gmosx $
|
|
26
|
+
|
|
27
|
+
require "n/utils/hash"
|
|
28
|
+
|
|
29
|
+
module N
|
|
30
|
+
|
|
31
|
+
# = SitePage
|
|
32
|
+
#
|
|
33
|
+
class SitePage
|
|
34
|
+
# the uri for this page
|
|
35
|
+
attr_accessor :uri
|
|
36
|
+
# the real uri to this page calculated by the page overloader)
|
|
37
|
+
attr_accessor :real_uri
|
|
38
|
+
attr_accessor :realm
|
|
39
|
+
# the shader for this page, overrided the shader calculated
|
|
40
|
+
# by the engine
|
|
41
|
+
attr_accessor :shader
|
|
42
|
+
attr_accessor :level
|
|
43
|
+
# title of the page
|
|
44
|
+
attr_accessor :title
|
|
45
|
+
# description of the page
|
|
46
|
+
attr_accessor :description
|
|
47
|
+
attr_accessor :parent, :children
|
|
48
|
+
attr_accessor :flag
|
|
49
|
+
|
|
50
|
+
# the realm this page belongs to, typically the part name.
|
|
51
|
+
# put symbols in this variable
|
|
52
|
+
attr_accessor :realm
|
|
53
|
+
|
|
54
|
+
def initialize(uri, title = nil, parent = nil, realm = nil)
|
|
55
|
+
@uri, @title, @parent = uri, title, parent
|
|
56
|
+
|
|
57
|
+
# inherit realm from parent if exists
|
|
58
|
+
if parent and parent.realm
|
|
59
|
+
@realm = parent.realm
|
|
60
|
+
else
|
|
61
|
+
@realm = realm
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@children = []
|
|
65
|
+
@parent.children << self if parent
|
|
66
|
+
|
|
67
|
+
# gmosx: is this good?
|
|
68
|
+
# automatically add to the sitemap.
|
|
69
|
+
$sitemap << self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Return string representation
|
|
73
|
+
#
|
|
74
|
+
def to_s
|
|
75
|
+
return @title
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# = SiteMap
|
|
80
|
+
#
|
|
81
|
+
# === TODO:
|
|
82
|
+
# Use a second class in the UI namespace for rendering
|
|
83
|
+
# related stuff?
|
|
84
|
+
#
|
|
85
|
+
class SiteMap < N::SafeHash
|
|
86
|
+
|
|
87
|
+
# The root page for this sitemap
|
|
88
|
+
attr_accessor :root
|
|
89
|
+
|
|
90
|
+
# The separator used when creating paths
|
|
91
|
+
attr_accessor :separator
|
|
92
|
+
|
|
93
|
+
def initialize(separator = " > ")
|
|
94
|
+
super
|
|
95
|
+
@separator = separator
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def << (page)
|
|
99
|
+
self[page.uri] = page
|
|
100
|
+
unless page.parent
|
|
101
|
+
@root = page
|
|
102
|
+
page.realm = :root
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Path as array of pages
|
|
107
|
+
#
|
|
108
|
+
def path(uri)
|
|
109
|
+
return nil unless uri
|
|
110
|
+
|
|
111
|
+
if page = self[uri]
|
|
112
|
+
res = Array.new;
|
|
113
|
+
|
|
114
|
+
res << page
|
|
115
|
+
while page = page.parent
|
|
116
|
+
res.unshift(page)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
return res
|
|
120
|
+
else
|
|
121
|
+
$log.warn "The uri #{uri} is not registered in the SiteMap!"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
return nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Calculates the linked path to the given uri.
|
|
128
|
+
#
|
|
129
|
+
def linked_path(uri, lc = nil, args = nil)
|
|
130
|
+
if the_path = path(uri)
|
|
131
|
+
i = -1
|
|
132
|
+
j, s = 0, the_path.size()
|
|
133
|
+
return the_path.collect { |p|
|
|
134
|
+
j += 1
|
|
135
|
+
if p.title.is_a?(String)
|
|
136
|
+
j == s ? p.title : %|<a href="#{p.uri}">#{p.title}</a>|
|
|
137
|
+
elsif p.title.is_a?(Symbol)
|
|
138
|
+
j == s ? lc[p.title] : %|<a href="#{p.uri}">#{lc[p.title]}</a>|
|
|
139
|
+
else
|
|
140
|
+
i += 1
|
|
141
|
+
title, qs = p.title.call(args[i])
|
|
142
|
+
j == s ? title : %|<a href="#{p.uri}#{qs}">#{title}</a>|
|
|
143
|
+
end
|
|
144
|
+
}.join(@separator)
|
|
145
|
+
|
|
146
|
+
else
|
|
147
|
+
return nil
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Calculates the path to the given uri.
|
|
152
|
+
#
|
|
153
|
+
def str_path(uri, lc = nil, args = nil)
|
|
154
|
+
if the_path = path(uri)
|
|
155
|
+
i = -1
|
|
156
|
+
return the_path.collect { |p|
|
|
157
|
+
if p.title.is_a?(String)
|
|
158
|
+
p.title
|
|
159
|
+
elsif p.title.is_a?(Symbol)
|
|
160
|
+
lc[p.title]
|
|
161
|
+
else
|
|
162
|
+
i += 1
|
|
163
|
+
p.title.call(args[i])[0]
|
|
164
|
+
end
|
|
165
|
+
}.join(@separator)
|
|
166
|
+
else
|
|
167
|
+
return nil
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Returns a String representation of the Sitemap.
|
|
172
|
+
#
|
|
173
|
+
def to_s
|
|
174
|
+
str = "#{root}"
|
|
175
|
+
arr = []
|
|
176
|
+
self.each_pair { |page, title|
|
|
177
|
+
arr << "#{title}: #{page}"
|
|
178
|
+
}
|
|
179
|
+
return "#{str} {" + arr.join(",") + "}"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end # module
|
|
185
|
+
|
|
186
|
+
# the default sitemap.
|
|
187
|
+
$sitemap = N::SiteMap.new
|
|
188
|
+
|
data/lib/n/std.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# = Navel Software Technology
|
|
2
|
+
#
|
|
3
|
+
# code: gmosx, drak, ekarak
|
|
4
|
+
#
|
|
5
|
+
# (c) 2001-2004 Navel, all rights reserved.
|
|
6
|
+
# $Id: std.rb 71 2004-10-18 10:50:22Z gmosx $
|
|
7
|
+
|
|
8
|
+
# we want readable code
|
|
9
|
+
|
|
10
|
+
require "English"
|
|
11
|
+
require "pp"
|
|
12
|
+
|
|
13
|
+
class NilClass
|
|
14
|
+
# to_i, to_s are handled by default.
|
|
15
|
+
|
|
16
|
+
def to_i
|
|
17
|
+
return nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_f
|
|
21
|
+
return 0.0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# quite usefull for error tolerant apps.
|
|
25
|
+
# a bit dangerous though.
|
|
26
|
+
#
|
|
27
|
+
def empty?
|
|
28
|
+
return true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
#
|
|
34
|
+
class Class
|
|
35
|
+
def to_i()
|
|
36
|
+
return self.hash()
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
#
|
|
42
|
+
module Kernel
|
|
43
|
+
# pretty prints an exception/error object
|
|
44
|
+
# usefull for helpfull debug messages
|
|
45
|
+
#
|
|
46
|
+
# Input:
|
|
47
|
+
# The Exception/StandardError object
|
|
48
|
+
#
|
|
49
|
+
# Output:
|
|
50
|
+
# the pretty printed string
|
|
51
|
+
#
|
|
52
|
+
def pp_exception(ex)
|
|
53
|
+
return %{#{ex.message}\n\tBACKTRACE:\n\t#{ex.backtrace.join("\n\t")}\n\tLOGGED FROM:\n\t#{caller[0]}}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# predefine some comonly used objects
|
|
59
|
+
|
|
60
|
+
EMPTY_STRING = ""
|
|
61
|
+
|
|
62
|
+
# This the default 72 chars separator, copy paste to use it
|
|
63
|
+
# in your source file. Btw all lines in your source file should
|
|
64
|
+
# be less than 72 chars. So you can use this as a ruler if your
|
|
65
|
+
# editor does not support it.
|
|
66
|
+
|
|
67
|
+
#-----------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
|
data/lib/n/sync/clc.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
|
2
|
+
|
|
3
|
+
# = A Command Line Client (clc) for the Sync Server
|
|
4
|
+
#
|
|
5
|
+
# code: tml, drak
|
|
6
|
+
#
|
|
7
|
+
# (c) 2004 Navel, all rights reserved.
|
|
8
|
+
# $Id: clc.rb 71 2004-10-18 10:50:22Z gmosx $
|
|
9
|
+
|
|
10
|
+
require "logger"
|
|
11
|
+
require "socket"
|
|
12
|
+
require "thread"
|
|
13
|
+
require "timeout"
|
|
14
|
+
require "getoptlong"
|
|
15
|
+
|
|
16
|
+
@opts = GetoptLong.new(
|
|
17
|
+
[ "--server", "-s", GetoptLong::REQUIRED_ARGUMENT ],
|
|
18
|
+
[ "--port", "-p", GetoptLong::REQUIRED_ARGUMENT ],
|
|
19
|
+
[ "--file", "-f", "-l", GetoptLong::REQUIRED_ARGUMENT ]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def prompt
|
|
23
|
+
printf(Time.now.strftime("%H:%M:%S> "))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def connect(srv, port)
|
|
27
|
+
begin
|
|
28
|
+
@socket = TCPSocket.new(srv, port)
|
|
29
|
+
rescue
|
|
30
|
+
$log.error "Cannot connect to server, is it online?"
|
|
31
|
+
exit(0)
|
|
32
|
+
end
|
|
33
|
+
$log.info "Connected to #{@socket.addr[3]}:#{@socket.addr[1]}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def send(str)
|
|
37
|
+
$log.info "write: #{str}"
|
|
38
|
+
@socket.send("#{str}\000", 0)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def read()
|
|
42
|
+
begin
|
|
43
|
+
loop do
|
|
44
|
+
timeout(0.7) do
|
|
45
|
+
while @socket.readline("\000")
|
|
46
|
+
$log.info "read: #{$_}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
rescue TimeoutError
|
|
51
|
+
#drink it
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write(cmd)
|
|
56
|
+
if cmd = cmd.strip() and not cmd.empty?
|
|
57
|
+
send(cmd)
|
|
58
|
+
else
|
|
59
|
+
$log.error "Syntax error"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if __FILE__ == $0
|
|
64
|
+
|
|
65
|
+
$log = Logger.new(STDERR)
|
|
66
|
+
|
|
67
|
+
@opts.each { |opt, arg|
|
|
68
|
+
case opt
|
|
69
|
+
when "--file"
|
|
70
|
+
@file = File.new(arg)
|
|
71
|
+
when "--server"
|
|
72
|
+
@server = arg
|
|
73
|
+
when "--port"
|
|
74
|
+
port = port.to_i
|
|
75
|
+
end
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@server ||= "localhost"
|
|
79
|
+
@port ||= 2121
|
|
80
|
+
|
|
81
|
+
connect(@server, @port)
|
|
82
|
+
|
|
83
|
+
reader = Thread.new {
|
|
84
|
+
loop do
|
|
85
|
+
read()
|
|
86
|
+
end
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
writer = Thread.new {
|
|
90
|
+
# replay input file
|
|
91
|
+
if @file
|
|
92
|
+
@file.each_line { |cmd|
|
|
93
|
+
write(cmd)
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# normal rep loop
|
|
98
|
+
loop do
|
|
99
|
+
prompt()
|
|
100
|
+
cmd = gets()
|
|
101
|
+
write(cmd)
|
|
102
|
+
end
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reader.join()
|
|
106
|
+
writer.join()
|
|
107
|
+
|
|
108
|
+
end
|