1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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()
|