You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
4.7 KiB
Ruby
228 lines
4.7 KiB
Ruby
#!/usr/bin/ruby
|
|
|
|
require 'socket'
|
|
require './database.rb'
|
|
|
|
ANSI_GREEN = "\e[32m"
|
|
ANSI_BLUE = "\e[34m"
|
|
ANSI_CLEAR = "\e[0m"
|
|
APPNAME = "#{ANSI_GREEN}APOCRYPHA#{ANSI_CLEAR}"
|
|
HTTP_GET = "GET"
|
|
HTTP_POST = "POST"
|
|
HTTP_QUERY = "QUERY"
|
|
HTTP_NIL = "NIL"
|
|
ROOT = ARGV[0]
|
|
PORT = ARGV[1]
|
|
|
|
db = Database.new('db.rb')
|
|
|
|
def message(msg)
|
|
puts "#{APPNAME}: #{msg}"
|
|
end
|
|
|
|
def error(msg)
|
|
puts "#{APPNAME}: #{msg}"
|
|
exit 1
|
|
end
|
|
|
|
#just to make the rest of the code look prettier
|
|
class String
|
|
def as_root
|
|
return "#{ROOT}/#{self}"
|
|
end
|
|
|
|
def tag(tag)
|
|
return "<#{tag}>#{self}</#{tag}>"
|
|
end
|
|
|
|
def tag_href(tag, href)
|
|
return "<#{tag} href=#{href}>#{self}</#{tag}>"
|
|
end
|
|
|
|
|
|
def tag_attrs(tag, attrs)
|
|
#this is kinda yucky
|
|
return "<#{tag} #{attrs.keys[0]}=\"#{attrs.values[0]}\">#{self}</#{tag}>"
|
|
end
|
|
end
|
|
|
|
def tmpl_not_found(data)
|
|
"<!DOCTYPE html><html><body><h>404 File not found: #{data}</h></body></html>"
|
|
end
|
|
|
|
def http_ok(data)
|
|
return "HTTP/1.1 200 OK\r\n\r\n #{data.join}" if data.class == Array
|
|
return "HTTP/1.1 200 OK\r\n\r\n #{data}" if data.class == String
|
|
message("could not :(")
|
|
end
|
|
|
|
def http_png(data)
|
|
return "HTTP/1.1 200 OK\r\nContent-Type: image/png\r\n\r\n #{data}" if data.class == String
|
|
message("could not :(")
|
|
end
|
|
|
|
def http_not_found(uri)
|
|
return "HTTP/1.1 404 Not Found\r\n\r\n #{tmpl_not_found(uri)}"
|
|
end
|
|
|
|
def init_database(db)
|
|
#get all files and check if theyre already in the database
|
|
keys = db.get(:key)
|
|
files = Dir.children(ROOT).filter {|x| x.end_with? ".pdf"}
|
|
|
|
not_files = files - keys
|
|
|
|
threads = []
|
|
mtx = Mutex.new
|
|
|
|
#if not make a thumbnail and add it
|
|
not_files.each do |file|
|
|
threads << Thread.new {
|
|
make_thumbnail "#{ROOT}/#{file}"
|
|
mtx.synchronize {
|
|
db.append(file, "#{File.basename(file, ".pdf")}.png")
|
|
}
|
|
}
|
|
end
|
|
|
|
threads.each { |t| t.join }
|
|
until threads.map {|t| t.alive?}.include? false
|
|
end unless threads.empty?
|
|
end
|
|
|
|
#generate html to send on requesting "/"
|
|
def gen_html(db)
|
|
keys = db.get(:key)
|
|
hrefs = db.get(:value)
|
|
key = 0
|
|
value = 1
|
|
|
|
content = keys.zip(hrefs).map { |x|
|
|
img_tag = "<img src=#{x[value]}>"
|
|
img_tag = img_tag.tag_href("a", x[key])
|
|
img_tag = img_tag.tag_attrs("div", {:class => "grid-item"})
|
|
}
|
|
|
|
content = content.join
|
|
content = content.tag_attrs("div", {:class => "grid-container"})
|
|
|
|
stylesheet = File.read("#{ROOT}/style.css")
|
|
stylesheet = stylesheet.tag("style")
|
|
head = stylesheet.tag("head")
|
|
body = content.tag("pre").tag("body")
|
|
|
|
html = (head + body).tag("html")
|
|
html = "<!DOCTYPE html>" + html
|
|
end
|
|
|
|
HANDLERS = {"/" => lambda { |cli| cli.puts http_ok gen_html(db)}}
|
|
|
|
DEFAULT = lambda { |cli, uri|
|
|
unless File.exist? "#{uri.as_root}"
|
|
message("could not open file: #{uri}")
|
|
cli.puts http_not_found uri
|
|
return
|
|
end
|
|
|
|
cli.puts http_ok File.read("#{uri.as_root}")
|
|
}
|
|
|
|
IMAGE_HANDLER = lambda { |cli, uri|
|
|
unless File.exist? "#{uri.as_root}"
|
|
message("could not open file: #{uri}")
|
|
cli.puts http_not_found uri
|
|
return
|
|
end
|
|
|
|
cli.puts File.read("#{uri.as_root}")
|
|
}
|
|
|
|
def make_thumbnail(file)
|
|
`convert -thumbnail "140x200" -background white -alpha remove -crop 178x178+0+0 "#{file}"[0] "#{ROOT}/#{File.basename(file, ".pdf")}.png"`
|
|
end
|
|
|
|
def get_file(cli, uri)
|
|
if HANDLERS[uri]
|
|
HANDLERS[uri].call(cli)
|
|
elsif uri.end_with? ".png"
|
|
IMAGE_HANDLER.call(cli, uri.split("/")[1])
|
|
#never wants the ico?
|
|
elsif uri.end_with? ".ico"
|
|
lambda { |cli, uri|
|
|
unless File.exist? uri.as_root
|
|
message "could not open file: #{uri}"
|
|
cli.puts http_not_found uri
|
|
return
|
|
end
|
|
cli.puts "HTTP/1.1 200 OK\r\nContent-Type: image/icon\r\n\r\n" + File.read(uri.as_root)
|
|
}.call(cli, uri.split("/")[1])
|
|
else
|
|
DEFAULT.call(cli, uri.split("/")[1])
|
|
end
|
|
end
|
|
|
|
def put_file(cli, uri, data)
|
|
"handle it"
|
|
end
|
|
|
|
class Request
|
|
attr_reader :method
|
|
attr_reader :data
|
|
attr_reader :uri
|
|
attr_reader :version
|
|
attr_reader :headers
|
|
|
|
def parse_request(str)
|
|
if @data[0].nil?
|
|
@method = HTTP_NIL
|
|
return
|
|
end
|
|
@method = @data[0].split(" ")[0]
|
|
@uri = @data[0].split(" ")[1]
|
|
@version = @data[0].split(" ")[2]
|
|
|
|
@headers = @data.map.drop(1) { |header|
|
|
{header.split(": ")[0] => header.split(": ")[1]}
|
|
}
|
|
end
|
|
|
|
def initialize(cli)
|
|
@data = [cli.gets]
|
|
parse_request(@data)
|
|
end
|
|
end
|
|
|
|
error("specify root folder") if ROOT.nil?
|
|
error("specify port") if PORT.nil?
|
|
message("starting server on port: #{PORT}")
|
|
|
|
init_database(db)
|
|
|
|
TCPServer.open("127.0.0.1", PORT) { |srv|
|
|
mutex = Mutex.new
|
|
loop do
|
|
Thread.start(srv.accept) { |cli|
|
|
mutex.synchronize do
|
|
h = Request.new(cli)
|
|
|
|
case h.method
|
|
when HTTP_GET
|
|
cli.puts get_file(cli, h.uri)
|
|
when HTTP_POST
|
|
message("unknown method: #{h.method}")
|
|
when HTTP_QUERY
|
|
cli.write Dir.children(ROOT).join("\n")
|
|
when HTTP_NIL
|
|
break
|
|
else
|
|
message("unknown method: #{h.method}")
|
|
end
|
|
|
|
cli.close
|
|
end
|
|
}
|
|
|
|
end
|
|
}
|
|
|