dotfiles from arch
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
local service = require 'service.service'
|
||||
|
||||
return service
|
||||
@@ -0,0 +1,275 @@
|
||||
local socket = require "bee.socket"
|
||||
local select = require "bee.select"
|
||||
local fs = require "bee.filesystem"
|
||||
|
||||
local selector = select.create()
|
||||
local SELECT_READ <const> = select.SELECT_READ
|
||||
local SELECT_WRITE <const> = select.SELECT_WRITE
|
||||
|
||||
local function fd_set_read(s)
|
||||
if s._flags & SELECT_READ ~= 0 then
|
||||
return
|
||||
end
|
||||
s._flags = s._flags | SELECT_READ
|
||||
selector:event_mod(s._fd, s._flags)
|
||||
end
|
||||
|
||||
local function fd_clr_read(s)
|
||||
if s._flags & SELECT_READ == 0 then
|
||||
return
|
||||
end
|
||||
s._flags = s._flags & (~SELECT_READ)
|
||||
selector:event_mod(s._fd, s._flags)
|
||||
end
|
||||
|
||||
local function fd_set_write(s)
|
||||
if s._flags & SELECT_WRITE ~= 0 then
|
||||
return
|
||||
end
|
||||
s._flags = s._flags | SELECT_WRITE
|
||||
selector:event_mod(s._fd, s._flags)
|
||||
end
|
||||
|
||||
local function fd_clr_write(s)
|
||||
if s._flags & SELECT_WRITE == 0 then
|
||||
return
|
||||
end
|
||||
s._flags = s._flags & (~SELECT_WRITE)
|
||||
selector:event_mod(s._fd, s._flags)
|
||||
end
|
||||
|
||||
local function on_event(self, name, ...)
|
||||
local f = self._event[name]
|
||||
if f then
|
||||
return f(self, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function close(self)
|
||||
local fd = self._fd
|
||||
on_event(self, "close")
|
||||
selector:event_del(fd)
|
||||
fd:close()
|
||||
end
|
||||
|
||||
local stream_mt = {}
|
||||
local stream = {}
|
||||
stream_mt.__index = stream
|
||||
function stream_mt:__newindex(name, func)
|
||||
if name:sub(1, 3) == "on_" then
|
||||
self._event[name:sub(4)] = func
|
||||
end
|
||||
end
|
||||
function stream:write(data)
|
||||
if self.shutdown_w then
|
||||
return
|
||||
end
|
||||
if data == "" then
|
||||
return
|
||||
end
|
||||
if self._writebuf == "" then
|
||||
fd_set_write(self)
|
||||
end
|
||||
self._writebuf = self._writebuf .. data
|
||||
end
|
||||
function stream:is_closed()
|
||||
return self.shutdown_w and self.shutdown_r
|
||||
end
|
||||
function stream:close()
|
||||
if not self.shutdown_r then
|
||||
self.shutdown_r = true
|
||||
fd_clr_read(self)
|
||||
end
|
||||
if self.shutdown_w or self._writebuf == "" then
|
||||
self.shutdown_w = true
|
||||
fd_clr_write(self)
|
||||
close(self)
|
||||
end
|
||||
end
|
||||
local function close_write(self)
|
||||
fd_clr_write(self)
|
||||
if self.shutdown_r then
|
||||
close(self)
|
||||
end
|
||||
end
|
||||
local function update_stream(s, event)
|
||||
if event & SELECT_READ ~= 0 then
|
||||
local data = s._fd:recv()
|
||||
if data == nil then
|
||||
s:close()
|
||||
elseif data == false then
|
||||
else
|
||||
on_event(s, "data", data)
|
||||
end
|
||||
end
|
||||
if event & SELECT_WRITE ~= 0 then
|
||||
local n = s._fd:send(s._writebuf)
|
||||
if n == nil then
|
||||
s.shutdown_w = true
|
||||
close_write(s)
|
||||
elseif n == false then
|
||||
else
|
||||
s._writebuf = s._writebuf:sub(n + 1)
|
||||
if s._writebuf == "" then
|
||||
close_write(s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local listen_mt = {}
|
||||
local listen = {}
|
||||
listen_mt.__index = listen
|
||||
function listen_mt:__newindex(name, func)
|
||||
if name:sub(1, 3) == "on_" then
|
||||
self._event[name:sub(4)] = func
|
||||
end
|
||||
end
|
||||
function listen:is_closed()
|
||||
return self.shutdown_r
|
||||
end
|
||||
function listen:close()
|
||||
self.shutdown_r = true
|
||||
close(self)
|
||||
end
|
||||
|
||||
local connect_mt = {}
|
||||
local connect = {}
|
||||
connect_mt.__index = connect
|
||||
function connect_mt:__newindex(name, func)
|
||||
if name:sub(1, 3) == "on_" then
|
||||
self._event[name:sub(4)] = func
|
||||
end
|
||||
end
|
||||
function connect:write(data)
|
||||
if data == "" then
|
||||
return
|
||||
end
|
||||
self._writebuf = self._writebuf .. data
|
||||
end
|
||||
function connect:is_closed()
|
||||
return self.shutdown_w
|
||||
end
|
||||
function connect:close()
|
||||
self.shutdown_w = true
|
||||
close(self)
|
||||
end
|
||||
|
||||
local m = {}
|
||||
|
||||
function m.listen(protocol, address, port)
|
||||
local fd; do
|
||||
local err
|
||||
fd, err = socket.create(protocol)
|
||||
if not fd then
|
||||
return nil, err
|
||||
end
|
||||
if protocol == "unix" then
|
||||
fs.remove(address)
|
||||
end
|
||||
end
|
||||
do
|
||||
local ok, err = fd:bind(address, port)
|
||||
if not ok then
|
||||
fd:close()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
do
|
||||
local ok, err = fd:listen()
|
||||
if not ok then
|
||||
fd:close()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
local s = {
|
||||
_fd = fd,
|
||||
_flags = SELECT_READ,
|
||||
_event = {},
|
||||
shutdown_r = false,
|
||||
shutdown_w = true,
|
||||
}
|
||||
selector:event_add(fd, SELECT_READ, function ()
|
||||
local new_fd, err = fd:accept()
|
||||
if new_fd == nil then
|
||||
fd:close()
|
||||
on_event(s, "error", err)
|
||||
return
|
||||
elseif new_fd == false then
|
||||
else
|
||||
local new_s = setmetatable({
|
||||
_fd = new_fd,
|
||||
_flags = SELECT_READ,
|
||||
_event = {},
|
||||
_writebuf = "",
|
||||
shutdown_r = false,
|
||||
shutdown_w = false,
|
||||
}, stream_mt)
|
||||
if on_event(s, "accepted", new_s) then
|
||||
selector:event_add(new_fd, new_s._flags, function (event)
|
||||
update_stream(new_s, event)
|
||||
end)
|
||||
else
|
||||
new_fd:close()
|
||||
end
|
||||
end
|
||||
end)
|
||||
return setmetatable(s, listen_mt)
|
||||
end
|
||||
|
||||
function m.connect(protocol, address, port)
|
||||
local fd; do
|
||||
local err
|
||||
fd, err = socket.create(protocol)
|
||||
if not fd then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
do
|
||||
local ok, err = fd:connect(address, port)
|
||||
if ok == nil then
|
||||
fd:close()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
local s = {
|
||||
_fd = fd,
|
||||
_flags = SELECT_WRITE,
|
||||
_event = {},
|
||||
_writebuf = "",
|
||||
shutdown_r = false,
|
||||
shutdown_w = false,
|
||||
}
|
||||
selector:event_add(fd, SELECT_WRITE, function ()
|
||||
local ok, err = fd:status()
|
||||
if ok then
|
||||
on_event(s, "connected")
|
||||
setmetatable(s, stream_mt)
|
||||
if s._writebuf ~= "" then
|
||||
update_stream(s, SELECT_WRITE)
|
||||
if s._writebuf ~= "" then
|
||||
s._flags = SELECT_READ | SELECT_WRITE
|
||||
else
|
||||
s._flags = SELECT_READ
|
||||
end
|
||||
else
|
||||
s._flags = SELECT_READ
|
||||
end
|
||||
selector:event_add(s._fd, s._flags, function (event)
|
||||
update_stream(s, event)
|
||||
end)
|
||||
else
|
||||
s:close()
|
||||
on_event(s, "error", err)
|
||||
end
|
||||
end)
|
||||
return setmetatable(s, connect_mt)
|
||||
end
|
||||
|
||||
function m.update(timeout)
|
||||
for func, event in selector:wait(timeout or 0) do
|
||||
func(event)
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,295 @@
|
||||
---@diagnostic disable: deprecated
|
||||
local pub = require 'pub'
|
||||
local await = require 'await'
|
||||
local timer = require 'timer'
|
||||
local proto = require 'proto'
|
||||
local vm = require 'vm'
|
||||
local util = require 'utility'
|
||||
local files = require 'files'
|
||||
local lang = require 'language'
|
||||
local ws = require 'workspace'
|
||||
local time = require 'bee.time'
|
||||
local fw = require 'filewatch'
|
||||
local furi = require 'file-uri'
|
||||
local net = require 'service.net'
|
||||
local client = require 'client'
|
||||
|
||||
require 'jsonc'
|
||||
require 'json-beautify'
|
||||
|
||||
---@class service
|
||||
local m = {}
|
||||
m.type = 'service'
|
||||
m.idleClock = 0.0
|
||||
m.sleeping = false
|
||||
|
||||
local function countMemory()
|
||||
local mems = {}
|
||||
local total = 0
|
||||
mems[0] = collectgarbage 'count'
|
||||
total = total + collectgarbage 'count'
|
||||
for id, brave in ipairs(pub.braves) do
|
||||
mems[id] = brave.memory
|
||||
total = total + brave.memory
|
||||
end
|
||||
return total, mems
|
||||
end
|
||||
|
||||
function m.reportMemoryCollect()
|
||||
local totalMemBefore = countMemory()
|
||||
local clock = os.clock()
|
||||
collectgarbage()
|
||||
local passed = os.clock() - clock
|
||||
local totalMemAfter, mems = countMemory()
|
||||
|
||||
local lines = {}
|
||||
lines[#lines+1] = ' --------------- Memory ---------------'
|
||||
lines[#lines+1] = (' Total: %.3f(%.3f) MB'):format(totalMemAfter / 1000.0, totalMemBefore / 1000.0)
|
||||
for i = 0, #mems do
|
||||
lines[#lines+1] = (' # %02d : %.3f MB'):format(i, mems[i] / 1000.0)
|
||||
end
|
||||
lines[#lines+1] = (' Collect garbage takes [%.3f] sec'):format(passed)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function m.reportMemory()
|
||||
local totalMem, mems = countMemory()
|
||||
|
||||
local lines = {}
|
||||
lines[#lines+1] = ' --------------- Memory ---------------'
|
||||
lines[#lines+1] = (' Total: %.3f MB'):format(totalMem / 1000.0)
|
||||
for i = 0, #mems do
|
||||
lines[#lines+1] = (' # %02d : %.3f MB'):format(i, mems[i] / 1000.0)
|
||||
end
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function m.reportTask()
|
||||
local total = 0
|
||||
local running = 0
|
||||
local suspended = 0
|
||||
local normal = 0
|
||||
local dead = 0
|
||||
|
||||
for co in pairs(await.coMap) do
|
||||
total = total + 1
|
||||
local status = coroutine.status(co)
|
||||
if status == 'running' then
|
||||
running = running + 1
|
||||
elseif status == 'suspended' then
|
||||
suspended = suspended + 1
|
||||
elseif status == 'normal' then
|
||||
normal = normal + 1
|
||||
elseif status == 'dead' then
|
||||
dead = dead + 1
|
||||
end
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
lines[#lines+1] = ' --------------- Coroutine ---------------'
|
||||
lines[#lines+1] = (' Total: %d'):format(total)
|
||||
lines[#lines+1] = (' Running: %d'):format(running)
|
||||
lines[#lines+1] = (' Suspended: %d'):format(suspended)
|
||||
lines[#lines+1] = (' Normal: %d'):format(normal)
|
||||
lines[#lines+1] = (' Dead: %d'):format(dead)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function m.reportCache()
|
||||
local total = 0
|
||||
local dead = 0
|
||||
|
||||
for cache in pairs(vm.cacheTracker) do
|
||||
total = total + 1
|
||||
if cache.dead then
|
||||
dead = dead + 1
|
||||
end
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
lines[#lines+1] = ' --------------- Cache ---------------'
|
||||
lines[#lines+1] = (' Total: %d'):format(total)
|
||||
lines[#lines+1] = (' Dead: %d'):format(dead)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function m.reportProto()
|
||||
local holdon = 0
|
||||
local waiting = 0
|
||||
|
||||
for _ in pairs(proto.holdon) do
|
||||
holdon = holdon + 1
|
||||
end
|
||||
for _ in pairs(proto.waiting) do
|
||||
waiting = waiting + 1
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
lines[#lines+1] = ' --------------- RPC ---------------'
|
||||
lines[#lines+1] = (' Holdon: %d'):format(holdon)
|
||||
lines[#lines+1] = (' Waiting: %d'):format(waiting)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function m.report()
|
||||
local t = timer.loop(600.0, function ()
|
||||
local lines = {}
|
||||
lines[#lines+1] = ''
|
||||
lines[#lines+1] = '========= Medical Examination Report ========='
|
||||
lines[#lines+1] = m.reportMemory()
|
||||
lines[#lines+1] = m.reportTask()
|
||||
lines[#lines+1] = m.reportCache()
|
||||
lines[#lines+1] = m.reportProto()
|
||||
lines[#lines+1] = '=============================================='
|
||||
|
||||
log.info(table.concat(lines, '\n'))
|
||||
end)
|
||||
t:onTimer()
|
||||
end
|
||||
|
||||
function m.eventLoop()
|
||||
pub.task('timer', 1)
|
||||
pub.on('wakeup', function ()
|
||||
m.reportStatus()
|
||||
fw.update()
|
||||
end)
|
||||
|
||||
local function busy()
|
||||
if not m.workingClock then
|
||||
m.workingClock = time.monotonic()
|
||||
m.reportStatus()
|
||||
end
|
||||
end
|
||||
|
||||
local function idle()
|
||||
if m.workingClock then
|
||||
m.workingClock = nil
|
||||
m.reportStatus()
|
||||
end
|
||||
end
|
||||
|
||||
local function doSomething()
|
||||
net.update()
|
||||
timer.update()
|
||||
pub.step(false)
|
||||
if await.step() then
|
||||
busy()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function sleep()
|
||||
idle()
|
||||
for _ = 1, 10 do
|
||||
net.update(100)
|
||||
if doSomething() then
|
||||
return
|
||||
end
|
||||
end
|
||||
pub.step(true)
|
||||
end
|
||||
|
||||
while true do
|
||||
if doSomething() then
|
||||
goto CONTINUE
|
||||
end
|
||||
sleep()
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
local showStatusTip = math.random(100) == 1
|
||||
|
||||
function m.reportStatus()
|
||||
if not client.getOption('statusBar') then
|
||||
return
|
||||
end
|
||||
local info = {}
|
||||
if m.workingClock and time.monotonic() - m.workingClock > 100 then
|
||||
info.text = '$(loading~spin)Lua'
|
||||
elseif m.sleeping then
|
||||
info.text = "💤Lua"
|
||||
else
|
||||
info.text = '😺Lua'
|
||||
end
|
||||
|
||||
local tooltips = {}
|
||||
local params = {
|
||||
ast = files.countStates(),
|
||||
max = files.fileCount,
|
||||
mem = collectgarbage('count') / 1000,
|
||||
}
|
||||
for i, scp in ipairs(ws.folders) do
|
||||
tooltips[i] = lang.script('WINDOW_LUA_STATUS_WORKSPACE', furi.decode(scp.uri))
|
||||
end
|
||||
tooltips[#tooltips+1] = lang.script('WINDOW_LUA_STATUS_CACHED_FILES', params)
|
||||
tooltips[#tooltips+1] = lang.script('WINDOW_LUA_STATUS_MEMORY_COUNT', params)
|
||||
if showStatusTip then
|
||||
tooltips[#tooltips+1] = lang.script('WINDOW_LUA_STATUS_TIP')
|
||||
end
|
||||
|
||||
info.tooltip = table.concat(tooltips, '\n')
|
||||
if util.equal(m.lastInfo, info) then
|
||||
return
|
||||
end
|
||||
m.lastInfo = info
|
||||
proto.notify('$/status/report', info)
|
||||
end
|
||||
|
||||
function m.testVersion()
|
||||
local stack = debug.setcstacklimit(200)
|
||||
debug.setcstacklimit(stack + 1)
|
||||
if type(stack) == 'number' and debug.setcstacklimit(stack) == stack + 1 then
|
||||
proto.notify('window/showMessage', {
|
||||
type = 2,
|
||||
message = 'It seems to be running in Lua 5.4.0 or Lua 5.4.1 . Please upgrade to Lua 5.4.2 or above. Otherwise, it may encounter weird "C stack overflow", resulting in failure to work properly',
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function m.sayHello()
|
||||
proto.notify('$/hello', {'world'})
|
||||
end
|
||||
|
||||
function m.lockCache()
|
||||
local fs = require 'bee.filesystem'
|
||||
local sp = require 'bee.subprocess'
|
||||
local cacheDir = string.format('%s/cache', LOGPATH)
|
||||
local myCacheDir = string.format('%s/%d'
|
||||
, cacheDir
|
||||
, sp.get_id()
|
||||
)
|
||||
fs.create_directories(fs.path(myCacheDir))
|
||||
local err
|
||||
m.lockFile, err = io.open(myCacheDir .. '/.lock', 'wb')
|
||||
if err then
|
||||
log.error(err)
|
||||
end
|
||||
end
|
||||
|
||||
function m.start()
|
||||
util.enableCloseFunction()
|
||||
await.setErrorHandle(log.error)
|
||||
pub.recruitBraves(4)
|
||||
if COMPILECORES and COMPILECORES > 0 then
|
||||
pub.recruitBraves(COMPILECORES, 'compile')
|
||||
end
|
||||
if SOCKET then
|
||||
assert(math.tointeger(SOCKET), '`socket` must be integer')
|
||||
proto.listen('socket', SOCKET)
|
||||
else
|
||||
proto.listen('stdio')
|
||||
end
|
||||
m.report()
|
||||
m.testVersion()
|
||||
m.lockCache()
|
||||
|
||||
require 'provider'
|
||||
|
||||
m.sayHello()
|
||||
|
||||
m.eventLoop()
|
||||
end
|
||||
|
||||
return m
|
||||
Reference in New Issue
Block a user