aboutsummaryrefslogtreecommitdiff
path: root/server.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server.lua')
-rw-r--r--server.lua90
1 files changed, 90 insertions, 0 deletions
diff --git a/server.lua b/server.lua
new file mode 100644
index 0000000..efdce32
--- /dev/null
+++ b/server.lua
@@ -0,0 +1,90 @@
+local lfs = require "lfs"
+local data_dir = "/home/gemini/data"
+
+local function handle_gopher()
+ local sock = ngx.req.socket(true)
+ if not sock then return end
+
+ sock:settimeout(4000)
+ local line, err = sock:receive("*l")
+ if not line then line = "" end
+
+ -- Очищаем запрос от перевода строки
+ local selector = line:gsub("%s+", "")
+ local out = {}
+
+ -- =========================================================================
+ -- ГЛАВНОЕ МЕНЮ
+ -- =========================================================================
+ if selector == "" or selector == "/" then
+ table.insert(out, "i[ GOPHER-АРХИВ ]\t\tlocalhost\t70")
+ table.insert(out, "i=========================================================\t\tlocalhost\t70")
+ table.insert(out, "iАвтономный листингдокументации.\t\tlocalhost\t70\n")
+
+ -- Сканируем папки проектов в data
+ for dir in lfs.dir(data_dir) do
+ if dir ~= "." and dir ~= ".." and dir ~= "README.md" then
+ local attr = lfs.attributes(data_dir .. "/" .. dir)
+ if attr and attr.mode == "directory" then
+ -- Тип 1 означает директорию (папку) в протоколе Gopher
+ table.insert(out, string.format("1// %s\t/%s\tasustem.ru\t70", dir, dir))
+ end
+ end
+ end
+
+ table.insert(out, "\n1[ ВЕРНУТЬСЯ В КОРЕНЬ ]\t/\tasustem.ru\t70")
+ table.insert(out, "i---------------------------------------------------------\t\tlocalhost\t70")
+ table.insert(out, "iGopher-сервер на базе OpenResty/LuaJIT. Ссылка на капсулу:\t\tlocalhost\t70")
+ table.insert(out, ".") -- Точка на отдельной строке — маркер конца передачи в Gopher
+
+ sock:send(table.concat(out, "\r\n") .. "\r\n")
+ return
+ end
+
+ -- =========================================================================
+ -- СЛУЖЕБНЫЙ ЛИСТИНГ КОНКРЕТНОЙ ПАПКИ ИЛИ ОТДАЧА ФАЙЛА
+ -- =========================================================================
+ local local_path = data_dir .. selector
+ local attr = lfs.attributes(local_path)
+
+ if not attr then
+ sock:send("Файл или папка не найдены на сервере.\t\tlocalhost\t70\r\n.\r\n")
+ return
+ end
+
+ -- Если это папка проекта — выводим список её файлов
+ if attr.mode == "directory" then
+ table.insert(out, string.format("i[ СОДЕРЖИМОЕ ПРОЕКТА: %s ]\t\tlocalhost\t70", selector:sub(2)))
+ table.insert(out, "i=========================================================\t\tlocalhost\t70")
+
+ for file in lfs.dir(local_path) do
+ if file ~= "." and file ~= ".." then
+ local f_path = selector .. "/" .. file
+ local g_type = "0" -- По умолчанию тип 0 (текст/документ)
+
+ if file:match("%.jpg$") or file:match("%.png$") then
+ g_type = "I" -- Тип I означает графический файл (image)
+ elseif file:match("%.qet$") or file:match("%.pdf$") then
+ g_type = "9" -- Тип 9 означает бинарный файл (binary)
+ end
+
+ table.insert(out, string.format("%s%s\t%s\t\t70", g_type, file, f_path))
+ end
+ end
+
+ table.insert(out, "\n1[ НАЗАД В ГЛАВНОЕ МЕНЮ ]\t/\\t70")
+ table.insert(out, ".")
+ sock:send(table.concat(out, "\r\n") .. "\r\n")
+
+ -- Если это файл — стримим его бинарное содержимое в сокет напрямую
+ elseif attr.mode == "file" then
+ local f = io.open(local_path, "rb")
+ if f then
+ local content = f:read("*all")
+ f:close()
+ sock:send(content) -- В Gopher файлы отдаются без заголовков, чистым потоком
+ end
+ end
+end
+
+handle_gopher()