-
Notifications
You must be signed in to change notification settings - Fork 15
/
Item_Cache_Helper.xml
238 lines (170 loc) · 6.27 KB
/
Item_Cache_Helper.xml
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
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="Item_Cache_Helper"
author="Nick Gammon"
id="928dc37b201539cd14239ff0"
language="Lua"
purpose="Manages cached item information for various plugins"
date_written="2010-03-02"
requires="4.50"
version="1.0"
>
<description trim="y">
<![CDATA[
Install required for new telnet negotiation plugins.
]]>
</description>
</plugin>
<!-- Script -->
<script>
<![CDATA[
local PPI = require("ppi")
item_not_in_database = {}
requested_items = {}
count_items_found_in_db = 0
count_items_not_found_in_db = 0
count_items_requested_from_server = 0
count_items_received_from_server = 0
time_to_receive_items = 0
time_to_read_from_db = 0
time_to_write_to_db = 0
function dbcheck (code)
if code ~= sqlite3.OK and -- no error
code ~= sqlite3.ROW and -- completed OK with another row of data
code ~= sqlite3.DONE then -- completed OK, no more rows
local err = db:errmsg () -- the rollback will change the error message
db:exec ("ROLLBACK") -- rollback any transaction to unlock the database
error (err, 2) -- show error in caller's context
end -- if
end -- dbcheck
function fixsql (s)
if s then
return "'" .. (string.gsub (s, "'", "''")) .. "'" -- replace single quotes with two lots of single quotes
else
return "NULL"
end -- if
end -- fixsql
function load_item_from_database (hash)
local item
assert (hash, "hash is nil in load_item_from_database")
-- if not in database, don't look again
if item_not_in_database [hash] then
return nil
end -- no point looking
local start_time = GetInfo (232)
for row in db:nrows(string.format ("SELECT item FROM items WHERE hash = %s", fixsql (hash))) do
item = row.item
end -- finding item
time_to_read_from_db = time_to_read_from_db + (GetInfo (232) - start_time)
if item then
count_items_found_in_db = count_items_found_in_db + 1
return item
end -- if found
count_items_not_found_in_db = count_items_not_found_in_db + 1
item_not_in_database [hash] = true
return nil
end -- load_item_from_database
local IAC, SB, SE = 0xFF, 0xFA, 0xF0
-- check if single item cached
function get_item (hash)
-- see if in database
local item = load_item_from_database (hash)
-- yes? just return it then
if item then
-- print ("found item for", hash, "hash of it is", utils.tohex (utils.md5 (item)))
local t = {}
setfenv (assert (loadstring (item)), t) () -- compile and load into t
return t
end -- if found
if requested_items [hash] then
return nil
end -- if already asked for it
SendPkt (string.char (IAC, SB, 102) .. "hash_info = \"" .. hash .. "\"" .. string.char (IAC, SE))
-- Note ("Requested cache ID: ", hash)
-- DEBUG
CallPlugin ("b9cfe98d6a35dd98cd8ceacc", "LogIt", "Requested cache ID: " .. hash)
requested_items [hash] = GetInfo (232) -- don't request twice
count_items_requested_from_server = count_items_requested_from_server + 1
return nil
end -- get_item
function save_item_to_database (hash, item)
dbcheck (db:execute (string.format ("INSERT INTO items (hash, item, date_added) VALUES (%s, %s, DATETIME('NOW'));",
fixsql (hash), fixsql (item)
)))
item_not_in_database [hash] = false
end -- function
function OnPluginInstall ()
-- open database on disk (uses world address, that is which MUD we are playing)
db = assert (sqlite3.open( GetInfo (66) .. Trim (WorldAddress ()) .. "_" .. WorldPort () .. ".db"))
-- create items table
dbcheck (db:execute[[
CREATE TABLE IF NOT EXISTS
items(
itemid INTEGER PRIMARY KEY AUTOINCREMENT,
hash STRING NOT NULL, -- hash of contents
item TEXT, -- item contents
date_added DATE, -- date added to database
UNIQUE (hash)
);
]])
PPI.Expose "get_item"
end -- function OnPluginInstall
function OnPluginClose ()
-- close database
db:close()
end -- OnPluginClose
function OnPluginTelnetOption (option)
local t = {} -- incoming server variables will go into table t
setfenv (assert (loadstring (option)), t) () -- compile and load into t
-- cache incoming item information
if t.hash_info then
local received_hashes = {}
local start_time = GetInfo (232)
if next (t.hash_info) then
dbcheck (db:execute "BEGIN TRANSACTION;")
end -- if at least one item
for k, v in pairs (t.hash_info) do
local time_now = GetInfo (232)
local time_elapsed = 0
if requested_items [k] then
time_elapsed = GetInfo (232) - requested_items [k]
time_to_receive_items = time_to_receive_items + time_elapsed
count_items_received_from_server = count_items_received_from_server + 1
end -- if
-- Note (string.format ("RECEIVED item ID: %s in %.2f seconds.", k, time_elapsed))
requested_items [k] = nil
if v then
save_item_to_database (k, v)
table.insert (received_hashes, k)
end -- if item data found
end -- for
if next (t.hash_info) then
dbcheck (db:execute "COMMIT;")
end -- if at least one item
time_to_write_to_db = time_to_write_to_db + (GetInfo (232) - start_time)
for _, v in ipairs (received_hashes) do
BroadcastPlugin (1, v)
end -- for
end -- if t.hash_info
if (count_items_found_in_db + count_items_not_found_in_db) > 0 and
count_items_received_from_server > 0 then
SetStatus (string.format ("%i db reads, %i db fails: %0.5f sec avg, %i sent, %i received in %0.3f sec avg, writes: %0.5f sec avg",
count_items_found_in_db,
count_items_not_found_in_db,
time_to_read_from_db / (count_items_found_in_db + count_items_not_found_in_db),
count_items_requested_from_server,
count_items_received_from_server,
time_to_receive_items / count_items_received_from_server,
time_to_write_to_db / count_items_received_from_server))
end -- if
end -- function OnPluginTelnetOption
function OnPluginTelnetRequest (type, data)
if type == 102 and data == "WILL" then
return true
end -- if
end -- function OnPluginTelnetRequest
]]>
</script>
</muclient>