-
Notifications
You must be signed in to change notification settings - Fork 0
/
luaoverview.html
329 lines (299 loc) · 8.23 KB
/
luaoverview.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
<style type="text/css">
p {
margin: 0.5ex 0.5ex;
text-indent: 1.2ex;
}
div {
margin: 0.5ex 0.5ex;
}
h1, h2, h3 {
margin: 15px 0px 10px 3px;
padding: 0px 0px;
}
pre {
margin: 0.8ex 1.0ex;
padding: 0.3ex 0.3ex;
background: none #eeeeee;
border: solid 1px #ccdddd;
font-size: 95%;
}
</style>
<h1>Scripting Extension of Kyoto Tycoon.</h1>
<p>This module is imported by the server program (ktserver) of Kyoto Tycoon. The server must be built enabling the scripting extension by Lua.</p>
<p>The start-up command has the option "-scr" to specify a script file defining functions in Lua.</p>
<pre>$ ktserver -scr myscript.lua
</pre>
<p>You can define your own functions in the global name space so that clients can call them by specifying the name of each function. The function name must be composed of ASCII alphabets and numbers because of security reasons. Each function receives two tables as arguments. The first table contains the input data specified by clients. The second table is to contain the output data to send to clients.</p>
<p>In the scripting environment, the global variable "__kyototycoon__" is defined by default. It contains objects to access server resources. The most important one is "__kyototycoon__.db", which is the primary database managed by the server. "__kyototycoon__.dbs" is an array of databases managed by the server. The return value of each function must be "__kyototycoon__.RVSUCCESS" for success or a related code for error.</p>
<p>Because the server uses respective instances of the Lua processor for each native thread, you cannot use global variables to share data among sessions. Use a cache database managed by the server for that purpose.</p>
<p>The following is an example code.</p>
<pre>kt = __kyototycoon__
db = kt.db
-- log the start-up message
if kt.thid == 0 then
kt.log("system", "the Lua script has been loaded")
end
-- echo back the input data as the output data
function echo(inmap, outmap)
for key, value in pairs(inmap) do
outmap[key] = value
end
return kt.RVSUCCESS
end
-- report the internal state of the server
function report(inmap, outmap)
outmap["__kyototycoon__.VERSION"] = kt.VERSION
outmap["__kyototycoon__.thid"] = kt.thid
outmap["__kyototycoon__.db"] = tostring(kt.db)
for i = 1, #kt.dbs do
local key = "__kyototycoon__.dbs[" .. i .. "]"
outmap[key] = tostring(kt.dbs[i])
end
local names = ""
for name, value in pairs(kt.dbs) do
if #names > 0 then names = names .. "," end
names = names .. name
end
outmap["names"] = names
return kt.RVSUCCESS
end
-- log a message
function log(inmap, outmap)
local kind = inmap.kind
local message = inmap.message
if not message then
return kt.RVEINVALID
end
if not kind then
kind = "info"
end
kt.log(kind, message)
return kt.RVSUCCESS
end
-- store a record
function set(inmap, outmap)
local key = inmap.key
local value = inmap.value
if not key or not value then
return kt.RVEINVALID
end
local xt = inmap.xt
if not db:set(key, value, xt) then
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
-- remove a record
function remove(inmap, outmap)
local key = inmap.key
if not key then
return kt.RVEINVALID
end
if not db:remove(key) then
local err = db:error()
if err:code() == kt.Error.NOREC then
return kt.RVELOGIC
end
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
-- increment the numeric string value
function increment(inmap, outmap)
local key = inmap.key
local num = inmap.num
if not key or not num then
return kt.RVEINVALID
end
local function visit(rkey, rvalue, rxt)
rvalue = tonumber(rvalue)
if not rvalue then rvalue = 0 end
num = rvalue + num
return num
end
if not db:accept(key, visit) then
return kt.REINTERNAL
end
outmap.num = num
return kt.RVSUCCESS
end
-- retrieve the value of a record
function get(inmap, outmap)
local key = inmap.key
if not key then
return kt.RVEINVALID
end
local value, xt = db:get(key)
if value then
outmap.value = value
outmap.xt = xt
else
local err = db:error()
if err:code() == kt.Error.NOREC then
return kt.RVELOGIC
end
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
-- store records at once
function setbulk(inmap, outmap)
local num = db:set_bulk(inmap)
if num < 0 then
return kt.RVEINTERNAL
end
outmap["num"] = num
return kt.RVSUCCESS
end
-- remove records at once
function removebulk(inmap, outmap)
local keys = {}
for key, value in pairs(inmap) do
table.insert(keys, key)
end
local num = db:remove_bulk(keys)
if num < 0 then
return kt.RVEINTERNAL
end
outmap["num"] = num
return kt.RVSUCCESS
end
-- retrieve records at once
function getbulk(inmap, outmap)
local keys = {}
for key, value in pairs(inmap) do
table.insert(keys, key)
end
local res = db:get_bulk(keys)
if not res then
return kt.RVEINTERNAL
end
for key, value in pairs(res) do
outmap[key] = value
end
return kt.RVSUCCESS
end
-- move the value of a record to another
function move(inmap, outmap)
local srckey = inmap.src
local destkey = inmap.dest
if not srckey or not destkey then
return kt.RVEINVALID
end
local keys = { srckey, destkey }
local first = true
local srcval = nil
local srcxt = nil
local function visit(key, value, xt)
if first then
srcval = value
srcxt = xt
first = false
return kt.Visitor.REMOVE
end
if srcval then
return srcval, srcxt
end
return kt.Visitor.NOP
end
if not db:accept_bulk(keys, visit) then
return kt.REINTERNAL
end
if not srcval then
return kt.RVELOGIC
end
return kt.RVSUCCESS
end
-- list all records
function list(inmap, outmap)
local cur = db:cursor()
cur:jump()
while true do
local key, value, xt = cur:get(true)
if not key then break end
outmap[key] = value
end
return kt.RVSUCCESS
end
-- upcate all characters in the value of a record
function upcase(inmap, outmap)
local key = inmap.key
if not key then
return kt.RVEINVALID
end
local function visit(key, value, xt)
if not value then
return kt.Visitor.NOP
end
return string.upper(value)
end
if not db:accept(key, visit) then
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
-- prolong the expiration time of a record
function survive(inmap, outmap)
local key = inmap.key
if not key then
return kt.RVEINVALID
end
local function visit(key, value, xt)
if not value then
return kt.Visitor.NOP
end
outmap.old_xt = xt
if xt > kt.time() + 3600 then
return kt.Visitor.NOP
end
return value, 3600
end
if not db:accept(key, visit) then
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
-- count words with the MapReduce framework
function countwords(inmap, outmap)
local function map(key, value, emit)
local values = kt.split(value, " ")
for i = 1, #values do
local word = kt.regex(values[i], "[ .?!:;]", "")
word = string.lower(word)
if #word > 0 then
if not emit(word, "") then
return false
end
end
end
return true
end
local function reduce(key, iter)
local count = 0
while true do
local value = iter()
if not value then
break
end
count = count + 1
end
outmap[key] = count
return true
end
if not db:mapreduce(map, reduce, nil, kt.DB.XNOLOCK) then
return kt.RVEINTERNAL
end
return kt.RVSUCCESS
end
</pre>
<p>To call the above functions, execute the following commands.</p>
<pre>$ ktremotemgr script -arg key1 value1 -arg key2 value2 echo
$ ktremotemgr script report
$ ktremotemgr script -arg kind info -arg message hello log
$ ktremotemgr script -arg key one -arg value first set
$ ktremotemgr script -arg key two -arg value second set
$ ktremotemgr script -arg key three -arg value third set
$ ktremotemgr script -arg key three remove
$ ktremotemgr script -arg key two get
$ ktremotemgr script list
</pre>