refactor: runtimes into xurfer/runtime + better URI errorhandling + added lua runtime

This commit is contained in:
Leon van Kammen 2026-06-24 15:56:15 +02:00
parent a11a0d1889
commit d25a33a160
124 changed files with 244 additions and 90 deletions

View file

@ -10,7 +10,7 @@ Developers can run it via [Lua](https://lua.org), [LÖVR](https://lovr.org) or [
$ cd xurfer $ cd xurfer
$ love . <url_or_file> [..] # if you have LÖVE2D installed (>v12) $ love . <url_or_file> [..] # if you have LÖVE2D installed (>v12)
$ lovr . <url_or_file> [..] # if you have LÖVR installed $ lovr . <url_or_file> [..] # if you have LÖVR installed
$ lua main.lua <url_or_file> [..] # if you have lua installed $ ./main.lua <url_or_file> [..] # if you have lua installed
``` ```
**Example**: lovr xurfer <a href="https://snips.sh/f/_U5-XctEVE?r=1">https://snips.sh/f/_U5-XctEVE?r=1</a> **Example**: lovr xurfer <a href="https://snips.sh/f/_U5-XctEVE?r=1">https://snips.sh/f/_U5-XctEVE?r=1</a>
@ -39,8 +39,9 @@ The aim of this project is providing **a [XR Hypermedia browser](https://xrhf.is
## very hackable extensions ## very hackable extensions
* XURFER does everything via browser extensions.<br> * XURFER does everything via browser extensions.
* XURFER is the total sum of browser extensions.<br> * XURFER is the total sum of browser extensions.
* XURFER can proxy missing api-calls to cli-cmds (like [wget/curl](xurfer/runtime/lua/main.lua) via the [unixy](xurfer/ext/unixy/main.lua) extension)
So you can strip/bloat however you want, or build one yourself: So you can strip/bloat however you want, or build one yourself:
@ -51,3 +52,9 @@ $ ./lovr xurfer
[i] loading 'myextension' [i] loading 'myextension'
... ...
``` ```
## Security
Instead of the traditional sandbox-in-a-browser-model (Chromium/Firefox e.g.), we suggest running XURFER via [bubblewrap](https://github.com/meta-quest/bubblewrap)
> TODO: suggest cli flags

View file

@ -1,14 +1,16 @@
-- sync lovr/love positional cli arguments -- sync lovr/love positional cli arguments
if arg[0] == nil and arg[1] ~= nil then arg[0] = arg[1] end if arg[0] == nil and arg[1] ~= nil then arg[0] = arg[1] end
runtime = "" package.path = package.path .. ';' ..
'?.lua;' ..
'?/init.lua;' ..
'lib/?.lua;'
if lovr ~= nil then runtime = "lovr" end local runtime = require("runtime/detect")
if love ~= nil then runtime = "love" end
package.path = package.path .. ';' .. package.path = package.path .. ';' ..
arg[0] .. '/' .. runtime .. '/?.lua;' .. arg[0] .. '/' .. runtime.path .. '/?.lua;' ..
arg[0] .. '/' .. runtime .. '/?/init.lua;' .. arg[0] .. '/' .. runtime.path .. '/?/init.lua;' ..
arg[0] .. '/lib/?.lua' arg[0] .. '/lib/?.lua'
require( runtime .. "/conf") require( runtime.path .. "/conf")

View file

@ -1,6 +1,6 @@
local ecs = require("tiny-ecs") local ecs = require("tiny-ecs")
ecs.init = function() ecs.init = function(api)
print("[i] loading ecs") print("[i] loading ecs")
baseEntify = ecs.processingSystem() baseEntify = ecs.processingSystem()
baseEntify.filter = ecs.rejectAll('commit') baseEntify.filter = ecs.rejectAll('commit')
@ -24,6 +24,7 @@ ecs.init = function()
end end
ecs.clear = function() ecs.clear = function()
trace("[ecs] ecs.clear() scene")
api.ext.exec("onClear") api.ext.exec("onClear")
api.ecs.clearEntities( api.world ) api.ecs.clearEntities( api.world )
api.world.commit() api.world.commit()

View file

@ -28,7 +28,7 @@ return {
api.ecs.add( api.world, obj ) api.ecs.add( api.world, obj )
obj.commit('on3DFile') -- notify systems obj.commit('on3DFile') -- notify systems
else else
print("[3DFile] error: could not load " .. obj.URL.string ) print("[3DFile] error: could not load " .. obj.URL.string .. ": " .. obj.URLResponse.data )
end end
end end
end end

View file

@ -43,8 +43,8 @@ http = {
req.headers = headers req.headers = headers
channel:pop() -- remove last channel:pop() -- remove last
channel:push(req) -- re-push but with status (which thread ignores) channel:push(req) -- re-push but with status (which thread ignores)
lovr.timer.sleep(.1)
end end
lovr.timer.sleep(.1)
end end
]] ]]
http.channel = lovr.thread.getChannel('http') http.channel = lovr.thread.getChannel('http')
@ -57,7 +57,11 @@ http = {
local msg local msg
local res, present = http.channel:peek() local res, present = http.channel:peek()
if present and res.status ~= nil then if present then
if res.status == nil and res.data == "Could not connect to server" then
res.status = 503 -- service unavailable
end
if res.status ~= nil then
msg = http.channel:pop() msg = http.channel:pop()
-- we got our urlrequest response -- we got our urlrequest response
if http.cache[ msg.url ] then if http.cache[ msg.url ] then
@ -67,6 +71,7 @@ http = {
error("msg-object was not found in cache") error("msg-object was not found in cache")
end end
end end
end
end end
end, end,

View file

@ -26,11 +26,11 @@ return {
sample.load({ sample.load({
gameSunsetImage = lovr.graphics.newTexture( gameSunsetImage = lovr.graphics.newTexture(
"lovr/sample/assets/game-sunset.png", {} "runtime/lovr/sample/assets/game-sunset.png", {}
), ),
nineSliceImage = { nineSliceImage = {
image = lovr.graphics.newTexture( image = lovr.graphics.newTexture(
"lovr/sample/assets/ui-box-slice.png", { mipmaps = false } "runtime/lovr/sample/assets/ui-box-slice.png", { mipmaps = false }
), ),
l = 8, l = 8,
t = 8, t = 8,
@ -40,14 +40,14 @@ return {
smileMSDFLayeredImage = { smileMSDFLayeredImage = {
{ {
image = lovr.graphics.newTexture( image = lovr.graphics.newTexture(
"lovr/sample/assets/smile-bg.png", "runtime/lovr/sample/assets/smile-bg.png",
{ linear = true, mipmaps = false } { linear = true, mipmaps = false }
), ),
color = iui.newColor(0.944, 0.794, 0.468) color = iui.newColor(0.944, 0.794, 0.468)
}, },
{ {
image = lovr.graphics.newTexture( image = lovr.graphics.newTexture(
"lovr/sample/assets/smile-fg.png", "runtime/lovr/sample/assets/smile-fg.png",
{ linear = true, mipmaps = false } { linear = true, mipmaps = false }
), ),
color = iui.newColor(0.157, 0.157, 0.157) color = iui.newColor(0.157, 0.157, 0.157)
@ -57,7 +57,7 @@ return {
{ {
image = { image = {
image = lovr.graphics.newTexture( image = lovr.graphics.newTexture(
"lovr/sample/assets/nine-slice-interior.png", "runtime/lovr/sample/assets/nine-slice-interior.png",
{ linear = true, mipmaps = false } { linear = true, mipmaps = false }
), ),
l = 16, l = 16,
@ -70,7 +70,7 @@ return {
{ {
image = { image = {
image = lovr.graphics.newTexture( image = lovr.graphics.newTexture(
"lovr/sample/assets/nine-slice-frame.png", "runtime/lovr/sample/assets/nine-slice-frame.png",
{ linear = true, mipmaps = false } { linear = true, mipmaps = false }
), ),
l = 16, l = 16,

View file

@ -16,7 +16,7 @@ return {
load = function() load = function()
--if api.iui.idiom == "vr" then --if api.iui.idiom == "vr" then
envTex = api.graphics.newTexture("lovr/assets/img/env.png", {}) envTex = api.graphics.newTexture("runtime/lovr/assets/img/env.png", {})
api.world.skybox = api.graphics.newTexture({ api.world.skybox = api.graphics.newTexture({
px = 'ext/startupscene/skybox/Dayright.jpg', -- 'px.png', px = 'ext/startupscene/skybox/Dayright.jpg', -- 'px.png',
nx = 'ext/startupscene/skybox/Dayleft.jpg', -- 'nx.png', nx = 'ext/startupscene/skybox/Dayleft.jpg', -- 'nx.png',

View file

@ -39,10 +39,16 @@ unixy = {
init = function() init = function()
end, end,
proxyCLI = function( cmdfunc, callback ) proxyCLI = function( cmd, cmdfunc, callback )
if api.util.cmdExist(cmd) then
print("[i] attaching ".. cmd .. " cli-cmd to api")
return function(...) return function(...)
return unixy.addjob( cmdfunc, callback, ...) return unixy.addjob( cmdfunc, callback, ...)
end end
else
print("[!] could not attach ".. cmd .. " cli-cmd to api: not found")
return function()end
end
end, end,
update = function(dt) update = function(dt)
@ -79,7 +85,6 @@ unixy = {
callback = callback callback = callback
}) })
trace("[unixy] start job with pid " .. pid .. " => 1> " .. stdout_file .. " 2> " .. stderr_file) trace("[unixy] start job with pid " .. pid .. " => 1> " .. stdout_file .. " 2> " .. stderr_file)
print_r(unixy.jobs)
end, end,
check_jobs = function() check_jobs = function()
@ -98,7 +103,7 @@ unixy = {
-- Clean up -- Clean up
os.remove(job.stdout_file) os.remove(job.stdout_file)
os.remove(job.stderr_file) os.remove(job.stderr_file)
job.callback(stdout, stderr, retcode, unpack(job.args) ) job.callback(stdout, stderr, retcode, table.unpack(job.args) )
table.remove(unixy.jobs, i) table.remove(unixy.jobs, i)
else else
io.write(".") io.write(".")

View file

@ -113,6 +113,7 @@ end
-- utility function to traverse recursive table -- utility function to traverse recursive table
xrf.traverse = function(arr, cb, key) xrf.traverse = function(arr, cb, key)
if arr == nil then return end
if key == nil then key = 'children' end if key == nil then key = 'children' end
for k, child in pairs(arr) do for k, child in pairs(arr) do
if type(child) == 'table' then if type(child) == 'table' then

View file

@ -1,5 +1,3 @@
module(..., package.seeall)
--------------------------------------------------------------------------------- ---------------------------------------------------------------------------------
--------------------------------------------------------------------------------- ---------------------------------------------------------------------------------
-- --

22
xurfer/main.lua Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env lua
-- -- GLB URLS -- -- GLB URLS
-- ./lovr xurfer https://coderofsalvation.codeberg.page/xrfragment-haxe/example/assets/example.glb?bar=1&f=2#foo' -- ./lovr xurfer https://coderofsalvation.codeberg.page/xrfragment-haxe/example/assets/example.glb?bar=1&f=2#foo'
-- ./lovr xurfer https://codeberg.org/coderofsalvation/xrfragment/raw/branch/main/assets/template/website/website.glb' -- ./lovr xurfer https://codeberg.org/coderofsalvation/xrfragment/raw/branch/main/assets/template/website/website.glb'
@ -9,23 +10,18 @@
-- ./lovr xurfer https://snips.sh/f/rHFLg-cewi?r=1' -- cube -- ./lovr xurfer https://snips.sh/f/rHFLg-cewi?r=1' -- cube
-- ./lovr xurfer https://snips.sh/f/_U5-XctEVE?r=1' -- cube, monkey, scene -- ./lovr xurfer https://snips.sh/f/_U5-XctEVE?r=1' -- cube, monkey, scene
local runtime = nil print("\n X U R F Ξ R")
print(" ⠭ ⠥ ⠗ ⠋ ⠑ ⠗\n")
if lovr ~= nil then package.path = package.path .. ';' .. '?.lua;'
runtime = { path = "lovr", api = lovr }
elseif love ~= nil then
runtime = { path = "love", api = love };
end
if runtime == nil then
package.path = package.path .. ';' .. 'xurfer/?.lua'
require('conf') require('conf')
end
local runtime = require("runtime/detect")
local util = require("util") local util = require("util")
local ecs = require("ecs") local ecs = require("ecs")
api = { api = {
runtime = runtime,
parser = { parser = {
json = require("json"), json = require("json"),
xml = require("xmlSimple"), xml = require("xmlSimple"),
@ -46,7 +42,8 @@ require( runtime.path .. "/main")
util.loaddir( "ext", api, api.ext ) util.loaddir( "ext", api, api.ext )
util.loaddir( "media", api, api.media ) util.loaddir( "media", api, api.media )
ecs.init()
ecs.init(api)
api.ext.exec('init') api.ext.exec('init')
-- load urls passed on the cli -- load urls passed on the cli
@ -55,3 +52,6 @@ foreach( arg, function(k,uri)
api.ecs.add( api.world, { URI = { url = uri, method = 'GET', target = '_top' } }) api.ecs.add( api.world, { URI = { url = uri, method = 'GET', target = '_top' } })
end end
end) end)
-- for runtimes (runtime/lua) which dont automatically run an update-loop (like love/lovr)
api.ext.exec('main')

17
xurfer/runtime/detect.lua Normal file
View file

@ -0,0 +1,17 @@
local runtime = nil
-- determine runtime
if lovr ~= nil then
runtime = { name = "lovr", path = "runtime/lovr", api = lovr }
elseif love ~= nil then
runtime = { name = "lua", path = "runtime/love", api = love }
else
runtime = { name = "lua", path = "runtime/lua", api = require("runtime/lua/api") }
end
runtime.os = "unixy"
if package.config:sub(1,1) == "\\" then
runtime.os = "windows"
end
return runtime

View file

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 175 KiB

View file

Before

Width:  |  Height:  |  Size: 599 B

After

Width:  |  Height:  |  Size: 599 B

View file

Before

Width:  |  Height:  |  Size: 232 B

After

Width:  |  Height:  |  Size: 232 B

View file

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 405 B

View file

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 628 B

View file

Before

Width:  |  Height:  |  Size: 617 B

After

Width:  |  Height:  |  Size: 617 B

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -9,8 +9,8 @@ local iui = require "lib.iui"
local backend = require "lib.lovr-iui" local backend = require "lib.lovr-iui"
-- modify for nested lovr path for api -- modify for nested lovr path for api
iui.resourcePath = "lovr/" .. iui.resourcePath iui.resourcePath = "runtime/lovr/" .. iui.resourcePath
backend.resourcePath = "lovr/" .. backend.resourcePath backend.resourcePath = "runtime/lovr/" .. backend.resourcePath
api.iui = iui api.iui = iui
api.backend = backend api.backend = backend
-- decorate api -- decorate api

View file

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View file

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 636 B

View file

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 191 B

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 919 B

After

Width:  |  Height:  |  Size: 919 B

Some files were not shown because too many files have changed in this diff Show more