Skip to content

Commit 7ea96e9

Browse files
committed
Add basic plugin support
1 parent 9d76559 commit 7ea96e9

File tree

6 files changed

+212
-57
lines changed

6 files changed

+212
-57
lines changed

ROADMAP.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
## 0.2.0 – Developer Customization
44

5-
- [ ] Add settings:
5+
- [x] Add settings and about page:
66
- [x] custom port
77
- [x] custom URL
88
- [x] dark/light mode
99
- [x] custom editor deeplinking
1010
- [x] default settings
1111
- [x] download feather rock file for the version you are using
12-
- [ ] Add basic plugin support
12+
- [x] Add basic plugin support
1313
- [ ] Add optional plugins:
14-
- SIGNAL
15-
- LUA STATE
16-
- CARGO
14+
- [ ] SIGNAL
15+
- [ ] LUA STATE
16+
- [ ] CARGO
1717
- [ ] Mini overlay mode
1818

1919
---

src-lua/feather/init.lua

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local Class = require(PATH .. ".lib.class")
1111
local errorhandler = require(PATH .. ".error_handler")
1212
local get_current_dir = require(PATH .. ".utils").get_current_dir
1313
local Performance = require(PATH .. ".plugins.performance")
14+
local FeatherPluginManager = require(PATH .. ".plugin_manager")
1415

1516
local performance = Performance()
1617

@@ -75,6 +76,7 @@ function Feather:init(config)
7576
self.autoRegisterErrorHandler = conf.autoRegisterErrorHandler or false
7677
self.plugins = conf.plugins or {}
7778
self.lastDelivery = 0
79+
self.lastError = 0
7880
self.observers = {}
7981

8082
if not self.debug then
@@ -126,6 +128,8 @@ function Feather:init(config)
126128
selfRef.print(self, ...)
127129
end
128130
end
131+
132+
self.pluginManager = FeatherPluginManager(self, logs)
129133
end
130134

131135
function Feather:__buildResponse(body)
@@ -148,15 +152,24 @@ function Feather:__getConfig()
148152
root_path = root_path .. "/" .. self.baseDir
149153
end
150154

155+
local pluginKeys = {}
156+
157+
for _, plugin in ipairs(self.plugins) do
158+
table.insert(pluginKeys, plugin.identifier)
159+
end
160+
151161
local config = {
152-
plugins = self.plugins,
162+
plugins = pluginKeys,
153163
root_path = root_path,
154164
version = FEATHER_VERSION,
155165
}
156166

157167
return config
158168
end
159169

170+
--- Builds a request object from a raw request string
171+
---@param request string
172+
---@return table
160173
function Feather:__buildRequest(request)
161174
local method, pathWithQuery = request:match("^(%u+)%s+([^%s]+)")
162175
local path, queryString = pathWithQuery:match("^([^?]+)%??(.*)$")
@@ -196,28 +209,6 @@ function Feather:__defaultObservers()
196209
self:observe("Lua Version", _VERSION)
197210
end
198211

199-
--- Tracks the value of a key in the observers table
200-
---@alias FeatherObserve fun(self: Feather, key: string, value: table | string | number | boolean)
201-
---@type FeatherObserve
202-
function Feather:observe(key, value)
203-
if not self.debug then
204-
return
205-
end
206-
207-
self.observers = self.observers or {}
208-
209-
local curr = self:__format(value)
210-
211-
for _, observer in ipairs(self.observers) do
212-
if observer.key == key then
213-
observer.value = curr
214-
return
215-
end
216-
end
217-
218-
table.insert(self.observers, { key = key, value = curr })
219-
end
220-
221212
function Feather:__errorTraceback(msg)
222213
local trace = debug.traceback()
223214

@@ -253,18 +244,6 @@ function Feather:__errorTraceback(msg)
253244
return p
254245
end
255246

256-
---@alias FeatherClear fun(self: Feather)
257-
---@type FeatherClear
258-
function Feather:clear()
259-
logs = {}
260-
end
261-
262-
---@alias FeatherFinish fun(self: Feather)
263-
---@type FeatherFinish
264-
function Feather:finish()
265-
self:log({ type = "feather:finish" })
266-
end
267-
268247
function Feather:__onerror(msg, finish)
269248
if not self.debug then
270249
return
@@ -276,12 +255,49 @@ function Feather:__onerror(msg, finish)
276255
self.logger("[Feather] ERROR: " .. err)
277256
end
278257
self.lastError = os.time()
258+
self.pluginManager:onerror(msg, self)
279259

280260
if finish then
281261
self:finish()
282262
end
283263
end
284264

265+
--- Tracks the value of a key in the observers table
266+
---@alias FeatherObserve fun(self: Feather, key: string, value: table | string | number | boolean)
267+
---@type FeatherObserve
268+
function Feather:observe(key, value)
269+
if not self.debug then
270+
return
271+
end
272+
273+
self.observers = self.observers or {}
274+
275+
local curr = self:__format(value)
276+
277+
for _, observer in ipairs(self.observers) do
278+
if observer.key == key then
279+
observer.value = curr
280+
return
281+
end
282+
end
283+
284+
table.insert(self.observers, { key = key, value = curr })
285+
end
286+
287+
---@alias FeatherClear fun(self: Feather)
288+
---@type FeatherClear
289+
function Feather:clear()
290+
logs = {}
291+
end
292+
293+
---@alias FeatherFinish fun(self: Feather)
294+
---@type FeatherFinish
295+
function Feather:finish()
296+
self:log({ type = "feather:finish" })
297+
298+
self.pluginManager:finish(self)
299+
end
300+
285301
---@alias FeatherError fun(self: Feather, msg: string)
286302
---@type FeatherError
287303
function Feather:error(msg)
@@ -342,11 +358,19 @@ function Feather:update(dt)
342358
response = self:__buildResponse(body)
343359
end
344360

361+
if request.path == "/plugins" then
362+
local pluginResponse = self.pluginManager:handleRequest(request, self)
363+
364+
local body = json.encode(pluginResponse)
365+
response = self:__buildResponse(body)
366+
end
367+
345368
client:send(response)
346369
end
347370

348371
client:close()
349372
end
373+
self.pluginManager:update(dt, self)
350374
end
351375

352376
---@alias FeatherTrace fun(self: Feather, ...)

src-lua/feather/plugin_manager.lua

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
local PATH = string.sub(..., 1, string.len(...) - string.len("plugin_manager"))
2+
3+
local Class = require(PATH .. ".lib.class")
4+
5+
local FeatherPluginManager = Class({})
6+
7+
function FeatherPluginManager:init(feather, logs)
8+
self.plugins = {}
9+
10+
if not feather.plugins then
11+
return
12+
end
13+
14+
for i = 1, #feather.plugins do
15+
local plugin = feather.plugins[i]
16+
17+
local ok, pluginInstance = pcall(plugin.plugin, {
18+
options = plugin.options,
19+
feather = feather,
20+
})
21+
22+
if ok then
23+
pluginInstance.logger = feather.logger
24+
25+
table.insert(self.plugins, {
26+
instance = pluginInstance,
27+
identifier = plugin.identifier,
28+
})
29+
else
30+
-- TODO: Make logger a shared plugin independent from feather
31+
logs[#logs + 1] = {
32+
type = "error",
33+
str = debug.traceback(pluginInstance),
34+
count = 1,
35+
time = os.time(),
36+
}
37+
end
38+
end
39+
end
40+
41+
function FeatherPluginManager:update(dt, feather)
42+
for _, plugin in ipairs(self.plugins) do
43+
pcall(plugin.instance.update, plugin.instance, dt, feather)
44+
end
45+
end
46+
47+
function FeatherPluginManager:onerror(msg, feather)
48+
for _, plugin in ipairs(self.plugins) do
49+
pcall(plugin.instance.onerror, plugin.instance, msg, feather)
50+
end
51+
end
52+
53+
function FeatherPluginManager:handleRequest(request, feather)
54+
for _, plugin in ipairs(self.plugins) do
55+
pcall(plugin.instance.handleRequest, plugin.instance, request, feather)
56+
end
57+
end
58+
59+
function FeatherPluginManager:finish(feather)
60+
for _, plugin in ipairs(self.plugins) do
61+
pcall(plugin.instance.finish, plugin.instance, feather)
62+
end
63+
end
64+
65+
--- Create a plugin object to be used in the plugin manager
66+
---@param plugin FeatherPlugin
67+
---@param identifier string
68+
---@param options table
69+
function FeatherPluginManager.createPlugin(plugin, identifier, options)
70+
return {
71+
plugin = plugin,
72+
identifier = identifier,
73+
options = options,
74+
}
75+
end
76+
77+
return FeatherPluginManager

src-lua/feather/plugins/base.lua

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,35 @@ local PATH = string.sub(..., 1, string.len(...) - string.len("plugins.base"))
22

33
local Class = require(PATH .. ".lib.class")
44

5-
local FeatherPlugin = Class({
6-
init = function(self, config)
7-
self.config = config
8-
end,
9-
update = function(self, dt)
10-
return self, dt
11-
end,
12-
onerror = function(self, msg)
13-
return self, msg
14-
end,
15-
onerrorhandler = function(self, msg)
16-
return self, msg
17-
end,
18-
getResponseBody = function(self)
19-
return self, "Hello World"
20-
end,
21-
})
5+
---@class FeatherPlugin
6+
---@field options table
7+
---@field logger fun(...)
8+
---@field init fun(self: FeatherPlugin, config: table)
9+
---@field update fun(self: FeatherPlugin, dt: number, feather: Feather): ...
10+
---@field onerror fun(self: FeatherPlugin, msg: string, feather: Feather): ...
11+
---@field handleRequest fun(self: FeatherPlugin, request: table, feather: Feather): ...
12+
---@field finish fun(self: FeatherPlugin, feather: Feather): ...
13+
local FeatherPlugin = Class({})
14+
15+
function FeatherPlugin:init(config)
16+
self.options = config.options or {}
17+
self.logger = function(...) end
18+
end
19+
20+
function FeatherPlugin:update(dt)
21+
return self, dt
22+
end
23+
24+
function FeatherPlugin:onerror(msg)
25+
return self, msg
26+
end
27+
28+
function FeatherPlugin:handleRequest(request)
29+
return self, request
30+
end
31+
32+
function FeatherPlugin:finish()
33+
return self, "Finish"
34+
end
2235

2336
return FeatherPlugin

src-lua/main.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local FeatherDebugger = require("feather")
2+
local FeatherPluginManager = require("feather.plugin_manager")
23

34
local test = require("test.another.lib")
45

@@ -140,6 +141,8 @@ local function customerrorhandler(msg)
140141
end
141142
end
142143

144+
local TestPlugin = require("test.plugin")
145+
143146
local debugger = FeatherDebugger({
144147
errorHandler = customerrorhandler,
145148
wrappedPrint = true,
@@ -148,6 +151,15 @@ local debugger = FeatherDebugger({
148151
autoRegisterErrorHandler = true,
149152
baseDir = "src-lua",
150153
debug = true,
154+
plugins = {
155+
FeatherPluginManager.createPlugin(TestPlugin, "test", {
156+
test = true,
157+
}),
158+
---@diagnostic disable-next-line: missing-fields
159+
FeatherPluginManager.createPlugin({ 2 }, "test2", {
160+
test = true,
161+
}),
162+
},
151163
})
152164

153165
local a = 0

src-lua/test/plugin.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
local FeatherPlugin = require("feather.plugins.base")
2+
local Class = require("feather.lib.class")
3+
4+
---@type FeatherPlugin
5+
local TestPlugin = Class({
6+
__includes = FeatherPlugin,
7+
})
8+
9+
function TestPlugin:init(config)
10+
FeatherPlugin.init(self, config)
11+
end
12+
13+
function TestPlugin:update(dt, feather)
14+
FeatherPlugin.update(self, dt, feather)
15+
end
16+
17+
function TestPlugin:onerror(msg, feather)
18+
FeatherPlugin.onerror(self, msg, feather)
19+
end
20+
21+
function TestPlugin:handleRequest(request, feather)
22+
FeatherPlugin.handleRequest(self, request, feather)
23+
end
24+
25+
function TestPlugin:finish(feather)
26+
FeatherPlugin.finish(self, feather)
27+
end
28+
29+
return TestPlugin

0 commit comments

Comments
 (0)