diff src/luan/host/main.luan @ 1135:707a5d874f3e

add luan.host
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 28 Jan 2018 21:36:58 -0700
parents
children 1f9d34a6f308
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/host/main.luan	Sun Jan 28 21:36:58 2018 -0700
@@ -0,0 +1,187 @@
+java()
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local assert_string = Luan.assert_string or error()
+local ipairs = Luan.ipairs or error()
+local try = Luan.try or error()
+local Io = require "luan:Io.luan"
+local print = Io.print or error()
+local Rpc = require "luan:Rpc.luan"
+local Thread = require "luan:Thread.luan"
+local String = require "luan:String.luan"
+local literal = String.literal or error()
+local lower = String.lower or error()
+local matches = String.matches or error()
+local Hosting = require "luan:host/Hosting.luan"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "main"
+local WebHandler = require "java:luan.host.WebHandler"
+
+
+local sites_dir = Io.schemes.file(Hosting.sites_dir)
+
+sites_dir.mkdir()
+
+local function delete_unused(file)
+	if file.is_directory() then
+		if file.name() == "local" then
+			return false
+		end
+		local all_deleted = true
+		for _,child in ipairs(file.children()) do
+			all_deleted = delete_unused(child) and all_deleted
+		end
+		if not all_deleted then
+			return false
+		end
+	end
+	file.delete()
+	return true
+end
+
+
+local fns = Rpc.functions
+
+local function get_dir(domain,password)
+	assert_string(domain)
+	assert_string(password)
+	domain = lower(domain)
+	local dir = sites_dir.child(domain)
+	if dir.exists() then
+		local pwd = dir.child("password").read_text()
+		if pwd ~= password then
+			error "wrong password"
+		end
+		return dir.child("site")
+	else
+		return nil
+	end
+end
+
+function fns.get(domain,password)
+	local site_dir = get_dir(domain,password)
+	if site_dir == nil then
+		return nil
+	end
+
+	local children, file_info
+
+	function children(dir)
+		if dir.name() == "local" then
+			return {}
+		end
+		local rtn = {}
+		for _,child in ipairs(dir.children()) do
+			local info = file_info(child)
+			if info ~= nil then
+				rtn[info.name] = info
+			end
+		end
+		return rtn
+	end
+
+	function file_info(file)
+		local info = { name = file.name(), path = file.to_string() }
+		if file.is_directory() then
+			info.children = children(file)
+		elseif file.is_file() then
+			info.checksum = file.checksum()
+		else
+			return nil
+		end
+		return info
+	end
+
+	return file_info(site_dir)
+end
+
+function fns.create(domain,password)
+	assert_string(domain)
+	assert_string(password)
+	domain = lower(domain)
+	local dir = sites_dir.child(domain)
+	dir.exists() and error "already exists"
+	dir.mkdir()
+	dir.child("password").write(password)
+	dir = dir.child("site")
+	dir.mkdir()
+	return { name = dir.name(), path = dir.to_string(), children = {} }
+end
+
+local function security(site_dir,file)
+	matches( file.to_string(), "^"..literal(site_dir.to_string()) ) or error "security violation"
+end
+
+function fns.copy_file(domain,password,dir,name,content)
+	local site_dir = get_dir(domain,password)
+	site_dir or error "domain not found"
+	local file = Io.schemes.file(dir).child(name)
+	security(site_dir,file)
+	file.delete()
+	file.write(content)
+end
+
+function fns.mkdir(domain,password,dir,name)
+	local site_dir = get_dir(domain,password)
+	site_dir or error "domain not found"
+	local file = Io.schemes.file(dir).child(name)
+	security(site_dir,file)
+	file.mkdir()
+	return { name = file.name(), path = file.to_string(), children = {} }
+end
+
+function fns.delete_unused(domain,password,path)
+	local site_dir = get_dir(domain,password)
+	site_dir or error "domain not found"
+	local file = Io.schemes.file(path)
+	security(site_dir,file)
+	return delete_unused(file)
+end
+
+function fns.update_handler(domain,password)
+	local site_dir = get_dir(domain,password)
+	site_dir or error "domain not found"
+	domain = lower(domain)
+	WebHandler.removeHandler(domain)
+	WebHandler.loadHandler(domain)
+end
+
+function fns.delete(domain,password)
+	local site_dir = get_dir(domain,password)
+	site_dir or error "domain not found"
+	site_dir.parent().delete()
+	domain = lower(domain)
+	WebHandler.removeHandler(domain)
+end
+
+function fns.exists(domain)
+	assert_string(domain)
+	domain = lower(domain)
+	return sites_dir.child(domain).exists()
+end
+
+function fns.change_domain(old_domain,new_domain,password)
+	local old_dir = get_dir(old_domain,password)
+	old_dir or error "domain not found"
+	old_dir = old_dir.parent()
+	assert_string(new_domain)
+	new_domain = lower(new_domain)
+	local new_dir = sites_dir.child(new_domain)
+	new_dir.exists() and error "new_domain already exists"
+	WebHandler.removeHandler(old_domain)
+	old_dir.rename_to(new_dir.to_string())
+	WebHandler.removeHandler(old_domain)
+	WebHandler.loadHandler(new_domain)
+end
+
+function fns.change_password(domain,old_password,new_password)
+	local site_dir = get_dir(domain,old_password)
+	site_dir or error "domain not found"
+	site_dir.parent().child("password").write(new_password)
+	WebHandler.removeHandler(domain)
+	WebHandler.loadHandler(domain)
+end
+
+fns.call = WebHandler.callSite
+
+Thread.fork(Rpc.serve)