daemon and stuff

This commit is contained in:
Izaya 2018-12-20 11:23:29 +11:00
parent 2cdedd9591
commit 022699f899
2 changed files with 144 additions and 0 deletions

10
example.cfg Normal file
View File

@ -0,0 +1,10 @@
local config = {}
config.path = "/var/gopher" -- the root path of the dir to be served
config.hostname = "shadowkat.net" -- the hostname of the server
config.port = 70 -- the external port of the server
config.bindport = 7000 -- the port to actually bind to
config.dirinfo = true -- whether to output some extra info in automatic directory indexes
config.timer = 0.1 -- main loop timer
return config

134
gopherd.lua Normal file
View File

@ -0,0 +1,134 @@
local socket = require "socket"
local fs = require "lfs"
local tArgs = {...}
local pcount = 0
local threads = {}
-- initial configuration
local config = {}
config.path = "/var/gopher"
config.hostname = "shadowkat.net"
config.port = 70
config.bindport = 7000
config.dirinfo = true
config.timer = 0.1
-- load the config as a lua script
if tArgs[1] then
local f = io.open(tArgs[1],"rb")
local fn = load(f:read("*a"))
f:close()
if fn then
for k,v in pairs(fn()) do
config[k] = v
end
end
end
local function cleanPath(p) -- canonicalizes the path in theory
local t,o = {},""
for s in p:gmatch("[^/]+") do
if s == ".." then
t[#t] = nil
else
t[#t+1] = s
end
end
for k,v in pairs(t) do
o=o.."/"..v
end
return o
end
local function logerr(msg)
-- todo: proper error logging logic
print("error: "..msg)
end
local function detectft(path) -- tries to detect the file type
local attr = fs.attributes(path)
if attr.mode:sub(1,3) == "dir" then
return "1"
end
if path:sub(-4) == ".png" or path:sub(-4) == ".jpg" or path:sub(-5) == ".jpeg" or path:sub(-4) == ".bmp" or path:sub(-4) == "gif" then
return "I"
end
if path:sub(-5) == ".html" or path:sub(-4) == ".htm" then
return "h"
end
return "0"
end
local function handleConnect(client)
client:settimeout(0)
threads[pcount+1] = coroutine.create(function() local w,err = pcall(function()
repeat
coroutine.yield()
line=client:receive()
until line
print(line)
local path,args = config.path .. cleanPath(line)
local attr = fs.attributes(path)
if attr then
if attr.mode:sub(1,3) == "dir" then
if lfs.attributes(path.."/.gopherdir.cgi") then
local f = io.popen(path.."/.gopherdir.cgi")
coroutine.yield()
client:send(f:read("*a"))
f:close()
elseif lfs.attributes(path.."/.gopherdir") then
local f = io.open(path.."/.gopherdir")
client:send(f:read("*a"))
f:close()
else
if config.dirinfo then
client:send(string.format("i%s\ni%s\n",config.hostname,cleanPath(line)))
end
for file in lfs.dir(path) do
if file:sub(1,1) ~= "." then
client:send(string.format("%s%s\t%s\t%s\t%d\n",detectft(path.."/"..file),file,string.format("%s/%s",cleanPath(line),file),config.hostname,config.port))
end
end
end
else
if path:sub(-4) == ".cgi" then
local f = io.popen(path)
coroutine.yield()
client:send(f:read("*a"))
f:close()
else
local f = io.open(path)
client:send(f:read("*a"))
f:close()
end
end
else
client:send("Not found.")
end
client:close()
end)
if not w then
logerr(err)
client:close()
end
end)
pcount=pcount+1
end
local server = socket.bind("*",config.bindport)
server:settimeout(config.timer)
while true do -- totally not a scheduler
client = server:accept()
if client then
handleConnect(client)
end
for k,v in pairs(threads) do
if coroutine.status(v) == "dead" then
threads[k] = nil
else
coroutine.resume(v)
end
end
end