mirror of
https://git.shadowkat.net/izaya/tiny-gopherd.git
synced 2024-10-08 15:33:43 -04:00
daemon and stuff
This commit is contained in:
parent
2cdedd9591
commit
022699f899
10
example.cfg
Normal file
10
example.cfg
Normal 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
134
gopherd.lua
Normal 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
|
Loading…
Reference in New Issue
Block a user