Created
June 1, 2024 00:06
-
-
Save martandrMC/11e8cafa79a072be071b48957bc8de7b to your computer and use it in GitHub Desktop.
Computercraft Virtual Filesystem Library (Written with Google Drive in mind though other services could work)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local export = {} | |
---------------- | |
local link_pref, cache_path | |
local root_dir = {} | |
local curr_dir = {} | |
local curr_path = {} | |
---------------- | |
-- Private Functions | |
---------------- | |
local function getDirFile(link) | |
local handle, err, flag | |
local local_path = cache_path .. link .. ".dir" | |
-- If the needed directory has been cached | |
if fs.exists(local_path) then | |
-- Open cached directory list from FS | |
handle, err = fs.open(local_path, "r") | |
flag = false | |
else | |
-- Open handle to download directory list | |
handle, err = http.get(link_pref .. link) | |
flag = true | |
end | |
if handle == nil then error(err, 0) end | |
-- Read each line and add it to array | |
local lines = {} | |
local line = handle.readLine() | |
while line ~= nil do | |
table.insert(lines, line) | |
line = handle.readLine() | |
end | |
handle.close() | |
-- If the directory was downloaded, cache it | |
if flag then | |
handle, err = fs.open(local_path, "w") | |
if handle == nil then error(err, 0) end | |
for i=1, #lines do handle.writeLine(lines[i]) end | |
handle.close() | |
end | |
-- Parse the directory list's lines | |
local dir_table = {} | |
for i=1, #lines do | |
-- Line format: <type> <name> <link> | |
-- or $ <link>, used for the parent directory | |
local f = lines[i]:gmatch("%S+") | |
local type = f() | |
if type == "$" then | |
dir_table.parent = f() | |
else | |
local entry = {} | |
entry.type = type | |
entry.name = f() | |
entry.link = f() | |
table.insert(dir_table, entry) | |
end | |
end | |
return dir_table | |
end | |
local function lookup(dir, name) | |
-- Search the directory for an entry named xx | |
for i=1, #dir do | |
if dir[i].name == name then | |
-- Return the index of that entry | |
return i | |
end | |
end | |
-- Zero used as a not-found signal | |
-- since zero is an invalid index | |
return 0 | |
end | |
---------------- | |
-- Public Functions | |
---------------- | |
function export.getPath() | |
-- Append every entry in the curr_path array | |
-- separated with slashes | |
local path = "/" | |
for i=1, #curr_path do | |
path = path .. curr_path[i] .. "/" | |
end | |
return path | |
end | |
function export.getDir() | |
-- Create a new directory table | |
-- without the sub-dir links and return that | |
local dir = {} | |
for i=1, #curr_dir do | |
local entry = {} | |
entry.name = curr_dir[i].name | |
entry.type = curr_dir[i].type | |
if entry.type ~= "dir" then | |
entry.link = curr_dir[i].link | |
end | |
table.insert(dir, entry) | |
end | |
dir.isRoot = (curr_dir.parent == nil) | |
return dir | |
end | |
function export.getFile(filename, binary) | |
-- Find a non-directory entry in curr_dir | |
local index = lookup(curr_dir, filename) | |
if index == 0 then return false end | |
if curr_dir[index].type == "dir" then return false end | |
-- Open a http handle and return it | |
local link = link_pref .. curr_dir[index].link | |
handle, err = http.get({url=link, binary=binary}) | |
if handle == nil then error(err, 0) end | |
return true, handle | |
end | |
---------------- | |
function export.find(filename) | |
-- lookup() but only at the current directory | |
return lookup(curr_dir, filename) | |
end | |
function export.changeDir(new_path) | |
local tmp_dir, tmp_path | |
-- If the path is just /, go to root | |
if new_path == "/" then | |
curr_dir = root_dir | |
curr_path = {} | |
return true | |
-- If the path starts with /, begin at root | |
elseif string.sub(new_path, 1, 1) == "/" then | |
tmp_dir = root_dir | |
tmp_path = {} | |
-- If it doesn't start with /, begin at current dir | |
else | |
tmp_dir = curr_dir | |
tmp_path = curr_path | |
end | |
-- Run loop once for every substring within slashes | |
local f = new_path:gmatch("[^/]+") | |
local part = f() | |
while part ~= nil do | |
-- If the substring is .. follow the parent link | |
if part == ".." then | |
if tmp_dir.parent == nil then return false end | |
table.remove(tmp_path) | |
tmp_dir = getDirFile(tmp_dir.parent) | |
-- Else lookup current dir for that name and follow that | |
else | |
local index = lookup(tmp_dir, part) | |
if index == 0 then return false end | |
table.insert(tmp_path, tmp_dir[index].name) | |
tmp_dir = getDirFile(tmp_dir[index].link) | |
end | |
part = f() | |
end | |
curr_dir = tmp_dir | |
curr_path = tmp_path | |
return true | |
end | |
function export.clearCache() | |
-- Go over all files in the cache directory | |
-- and call fs.delete on them | |
local files = fs.list(cache_path) | |
for i=1, #files do fs.delete(cache_path .. files[i]) end | |
end | |
function export.init(pref, root, cache, clear) | |
-- Setup link prefix | |
link_pref = pref | |
-- Setup directory caching location | |
cache_path = cache .. ".webfscache/" | |
fs.makeDir(cache_path) | |
if clear then export.clearCache() end | |
-- Fetch the root directory | |
root_dir = getDirFile(root) | |
curr_dir = root_dir | |
end | |
---------------- | |
return export |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment