-
Notifications
You must be signed in to change notification settings - Fork 26
/
loader.lua
158 lines (133 loc) · 4.61 KB
/
loader.lua
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
assert(sys.provides "nested-nodes", "nested nodes feature missing")
local GLOBAL_CONTENTS, GLOBAL_CHILDS = node.make_nested()
local json = require "json"
local function setup(module_name)
local M = {}
local modules = {}
local modules_content_versions = {}
local function log(msg)
print(string.format("MODULE[%s]: %s", module_name, msg))
end
local function event_handler(child, event_name)
if not modules[child] then
return
end
return modules[child][event_name]
end
local function module_event(child, event_name, content, ...)
if not modules[child] then
return
end
local handler = event_handler(child, event_name)
if handler then
-- print('-> event', event_name, content)
return handler(content, ...)
end
end
local function module_unload(child)
log(child .. " is unloading")
for content, version in pairs(modules_content_versions[child]) do
module_event(child, 'content_remove', content)
end
module_event(child, 'unload')
modules[child] = nil
M.unload(child)
node.gc()
end
local function content_update_event(child, content, obj)
log(string.format("%s/%s updated", child, content))
if content:sub(-5) == ".json" then
local event_name = "updated_" .. content:gsub("[.]", "_")
local handler = event_handler(child, event_name)
if handler then
local data = json.decode(resource.load_file(
obj and obj:copy() or (child .. "/" .. content)
))
module_event(child, event_name, data)
end
end
return module_event(child, 'content_update', content)
end
local function module_load(child, module_func)
if modules[child] then
log("about to replace ".. child)
module_unload(child)
end
log("loading ".. child)
local api = {}
-- prepare exported API
api.localized = function(name)
return child .. "/" .. name
end
api.pinned_asset = function(asset)
log("localizing asset " .. asset.asset_name)
asset.file = resource.open_file(child .. "/" .. asset.asset_name)
return asset
end
M.before_load(child, api)
local module = module_func(
api,
GLOBAL_CHILDS[child],
GLOBAL_CONTENTS[child],
PATH .. "/" .. child
)
modules[child] = module
module_event(child, 'load')
local contents = {}
for content, version in pairs(modules_content_versions[child]) do
contents[#contents+1] = content
end
table.sort(contents)
for n, content in ipairs(contents) do
content_update_event(child, content)
end
node.gc()
end
local function module_update_content(child, content, version, obj)
local mcv = modules_content_versions[child]
if not mcv[content] or mcv[content] < version then
mcv[content] = version
return content_update_event(child, content, obj)
end
end
local function module_delete_content(child, content)
local mcv = modules_content_versions[child]
modules_content_versions[child][content] = nil
return module_event(child, 'content_remove', content)
end
node.event("child_add", function(child)
modules_content_versions[child] = {}
end)
node.event("child_remove", function(child)
modules_content_versions[child] = nil
end)
node.event("content_update", function(name, obj)
local child, content = util.splitpath(name)
if child == '' then -- not interested in top level events
return
elseif content == module_name then
return module_load(child, assert(
loadstring(resource.load_file(obj), "=" .. name)
))
else
return module_update_content(child, content, GLOBAL_CONTENTS[child][name], obj)
end
end)
node.event("content_remove", function(name)
local child, content = util.splitpath(name)
if child == '' then -- not interested in top level events
return
elseif content == module_name then
return module_unload(child)
else
return module_delete_content(child, content)
end
end)
M.modules = modules
M.before_load = function() end
M.unload = function() end
return M
end
return {
setup = setup;
}