diff --git a/src/.args b/src/.args
index 8ba1cb2..baa52d4 100644
--- a/src/.args
+++ b/src/.args
@@ -1,8 +1,8 @@
-H
Access-Control-Allow-Origin: *
-H
-Access-Control-Allow-Method: GET, OPTIONS
+Access-Control-Allow-Method: GET, HEAD, OPTIONS
-H
-Allow: GET, POST, OPTIONS
+Allow: GET, HEAD, POST, OPTIONS
-D
.
diff --git a/src/.init.lua b/src/.init.lua
index d64f89b..2b9e889 100644
--- a/src/.init.lua
+++ b/src/.init.lua
@@ -26,6 +26,7 @@ app = require("soakbean") {
generate = {file="cmd/generate.lua", info="generate www-folder with XR experiences"},
test = {file="cmd/test.lua", info="run testsuite (selftest)"}
},
+
addPlugin = function(file)
local p = require(file)
table.insert(app.plugin,p)
@@ -40,6 +41,14 @@ app = require("soakbean") {
end)
app.set('app.opts', app.opts)
return p
+ end,
+
+ addExperience = function(experience, ino)
+ if app.cache.items[ino] then -- handle duplicate symlinks, symlinks to symlinks e.g.
+ app.cache.items[ino .. ' ' .. experience.parent.id ] = experience
+ else
+ app.cache.items[ino] = experience
+ end
end
}
@@ -78,9 +87,9 @@ print = function(...) Log(kLogInfo, ... or "''") end -- nice redbean logging fro
-- init URL router
app.url['^/data'] = '/data.lua' -- setup custom file endpoint
-app.use( require('middleware/onlyGET')({exclude={'^/admin'}}) ) -- we are staticwebgen-first server-last
app.use( app.plugin.global.middleware.homepage_2D_or_3D )
app.url['^/admin[/]?$'] = '/page/admin/index.lua'
+app.use( require('middleware/onlyGET')({exclude={'^/admin'}}) ) -- we are staticwebgen-first server-last
app.get('^/design[/]?$', util.pagerender('page/design.html'))
app.get('^/about[/]?$', util.pagerender('page/about.html'))
diff --git a/src/.lua/util.lua b/src/.lua/util.lua
index 2fde540..36b22ae 100644
--- a/src/.lua/util.lua
+++ b/src/.lua/util.lua
@@ -106,6 +106,7 @@ util.template = function(content,data)
-- set fallback vars
mdata.urlpath = util.baseURLify( GetPath() )
mdata.url = mdata.url or mdata.urlpath
+ mdata.janusurl = mdata.janusurl or mdata.urlpath
mdata.title = mdata.title or app.opts.subtitle
mdata.header_include = mdata.header_include or ''
mdata.footerlinks = {}
diff --git a/src/middleware/onlyGET.lua b/src/middleware/onlyGET.lua
index 6194010..f984294 100644
--- a/src/middleware/onlyGET.lua
+++ b/src/middleware/onlyGET.lua
@@ -3,7 +3,7 @@ return function(opts)
opts = opts or {exclude={"^/admin"}}
return function(req,res,next)
local pass = false
- if req.method == "GET" then
+ if req.method == "GET" or req.method == "HEAD" then
pass = true
else
foreach(opts.exclude, function(k,path)
diff --git a/src/page/admin/index.lua b/src/page/admin/index.lua
index ddc2bd1..f4214c8 100644
--- a/src/page/admin/index.lua
+++ b/src/page/admin/index.lua
@@ -57,9 +57,7 @@ end
app.on('set', function(k,v) -- clear url cache
if k:match("app.opts") then -- after (admin) updates to app.opts.*
- foreach( app.cache.url, function(k,v)
- app.cache.url = {}
- end)
+ app.cache.url = {}
end
end)
diff --git a/src/page/dir.html b/src/page/dir.html
index 81ce6fa..5211de6 100644
--- a/src/page/dir.html
+++ b/src/page/dir.html
@@ -22,8 +22,7 @@ end}
function getURL(url)
if app.arg[1] == 'generate' or url:match("://") then
- url = 'janusweb/index.html#janus.url=' ..
- EscapeFragment( url ) .. '&janus.referrer=' .. util.getURL(urlpath )
+ url = '?view=3D#janus.url=' .. EscapeFragment( url )
url = util.baseURLify(url)
else
url = util.stripPath( url )
diff --git a/src/page/dir.lua b/src/page/dir.lua
index b01c83d..a8f39e5 100644
--- a/src/page/dir.lua
+++ b/src/page/dir.lua
@@ -25,6 +25,7 @@ return {
local matchpath = urlpath
if urlpath == '/' then matchpath = rootpath end -- generate janusxr footer for root url
foreach( app.cache.items, function(k,v)
+ print("URL=" ..v.url)
if req.authenticated or app.plugin.moderation.isAllowed(v) then
if v.parent then
-- trace( "path = " .. util.stripPath(v.path) .. " " ..
@@ -57,7 +58,7 @@ return {
end)
local data = util.merge({
- url = req.param.url, -- query hint to render janus.url in iframe (index.html)
+ janusurl = req.param.url, -- query hint to render janus.url in iframe (index.html)
items = {},
isroot = isroot,
referrer = referrer,
@@ -71,7 +72,7 @@ return {
i=i+1
if v.view3D then
local isMarkupExperience = function(v)
- return v.janusxr and (v.janusxr.jml or v.janusxr.aframe)
+ return v.janusxr and (v.janusxr.jml or v.janusxr.wrap)
end
-- prioritize markup experience above binary 3D files as experience containers
if not data.item or (isMarkupExperience(v) and not isMarkupExperience(data.item)) then
@@ -80,9 +81,11 @@ return {
data.item = v
data.title = data.item.title
data.parent = v.parent
- data.url = app.opts.baseurl .. util.stripPath(v.url) -- because we are running in iframe
- -- .. EscapeFragment( (v.url:match("#") and "&" or "#" ) .. 'janus.referrer=' .. EscapeFragment(v.referrer) )
- if v.janusxr and (v.janusxr.jml or v.janusxr.aframe) then
+ data.janusurl = (v.janusxr and v.janusxr.wrap) and
+ app.opts.baseurl .. util.stripPath(v.parent.url)
+ or
+ app.opts.baseurl .. util.stripPath(v.url)
+ if v.janusxr and (v.janusxr.jml or v.janusxr.wrap and v.janusxr.wrap.aframe) then
-- what to do here? no generated portals?
data.janusxr = app.tpl( util.readfile(v.path), data )
end
diff --git a/src/page/index.html b/src/page/index.html
index 8ed8d73..97c2065 100644
--- a/src/page/index.html
+++ b/src/page/index.html
@@ -3,7 +3,7 @@ ${header}
-
+
{if defined(item) and item.parent and item.parent.info then
print([[
@@ -45,6 +45,10 @@ end}
}, 1000 )
});
});
+
+ // reroute janus.url to iframe if needed
+ let params = new URLSearchParams( document.location.href.replace(/.*#/,'') )
+ if( params?.get('janus.url') ) iframe.src = 'janusweb/index.html#janus.url=' + encodeURIComponent( params.get('janus.url') )
diff --git a/src/page/janusxr.html b/src/page/janusxr.html
index 5b75549..d7a4951 100644
--- a/src/page/janusxr.html
+++ b/src/page/janusxr.html
@@ -40,17 +40,21 @@ end}
end}
{if true then
- local room = app.opts.plugin_janusxr_portalroom
- if defined(item) and item.janusxr and item.janusxr.room then
- room = item.janusxr.room
+ local room = ''
+ pos = '0 0 0'
+ if not defined(item) and defined(items) then
+ room = app.opts.plugin_janusxr_portalroom
end
- if room == 'random' then room = app.plugin.janusxr.getRandomRoom() end
- if defined(item) and item.tag.xrfragments and item.tag.xrfragments.qualify then
+ if defined(item) and item.janusxr and item.janusxr.wrap then
+ pos = '0 0 2'
+ room = app.plugin.janusxr.wrapRoomAroundFile(item)
+ end
+ if defined(item) and item.tag.xrfragments and item.tag.xrfragments.href then
room = '' -- xrfragments 3D files dont need to be wrapped with room
end
- print(' ')
+ print(' ')
if defined(item) then
- print(' ')
+ print(' ')
end
end}
@@ -87,6 +91,10 @@ end}
local width = 3.2
local center = -((#itemsremote*width)/1.3) + (i*width)
local url = v.url
+ --if url:match("://") then
+ -- url = url .. ( url:match("#") and '&' or '#' ) .. 'janus.referrer=' ..
+ -- EscapeFragment( util.getURL() )
+ --end
local thumb = ' shader_id="defaultportal"'
if #v.thumbnail > 0 then
thumb = ' thumb_id="imgremote' .. i .. '" '
@@ -106,10 +114,10 @@ end}
url = referrer,
title = app.opts.plugin_janusxr_portal_up,
}
- addPortal('parent',4, v, v.url, 0, 0, ' shader_id="defaultportal"', '0 -90 0', '0.2 0.2 0.2')
+ addPortal('parent',5, v, v.url, 0, 0, ' shader_id="defaultportal"', '0 -90 0', '0.2 0.2 0.2')
end}
-
+
{if not defined(item) then
print('${janusxr_jml_deco}')
end}
diff --git a/src/plugin/diskscan.lua b/src/plugin/diskscan.lua
index 71b2795..0ec142d 100644
--- a/src/plugin/diskscan.lua
+++ b/src/plugin/diskscan.lua
@@ -37,7 +37,7 @@ return {
shouldHideFile = function(name)
return name == ".." -- parent
or name == "util" -- repository
- or name:match("^%.") -- hidden
+ or name:match("^%.[a-zA-Z0-9_-]") -- hidden
or name == "src" -- repository
or name == "result" -- repository
end,
@@ -46,7 +46,7 @@ return {
local me = app.plugin.diskscan
local seen = {symlinks={}}
-- ensure rootdir as experience
- app.cache.items[ scandir ] = {
+ app.addExperience({
path = scandir,
url = "/" .. util.stripPath(scandir),
name = scandir:gsub(".*/",""),
@@ -54,7 +54,7 @@ return {
title = scandir:gsub(".*/",""):gsub("-"," "),
file = { ino = scandir },
id = scandir
- }
+ },scandir)
me.scanDir(scandir, nil, seen )
-- deal with (circular) symlinks
foreach( seen.symlinks, function(ino,experience)
@@ -65,8 +65,8 @@ return {
print("✅ └─ plugin/diskscan: detected symlink..creating portal")
experience.file = refItem.file
experience.portal = refItem
- app.pub("scan_experience", nil, experience)
- app.cache.items[experience.id] = experience
+ app.pub("scan_experience" .. (experience.dir and '' or '_file') , nil, experience)
+ app.addExperience(experience,ino)
end
end
end)
@@ -100,26 +100,34 @@ return {
}
experience.parent = parent
- if seen[ino] then return end -- dont process dirs/files twice
-
if (kind == unix.DT_LNK) then
+ experience.symlink = true
local stat, err = unix.stat(fullpath)
if stat then
- experience.id_target = stat:ino()
+ experience.id_target = stat:ino() -- stat follows symlink by default
+ local realpath = unix.realpath(fullpath)
+ state,err = unix.opendir(realpath)
+ if not err then
+ experience.symlink = true
+ experience.dir = true
+ state:close()
+ end
seen.symlinks[ ino ] = experience
end
- return
end
+
+ --local already_seen = seen[ino] and seen[ino].parent.file.ino == experience.parent.file.ino and true or false -- process once
+ --if already_seen and not experience.symlink then return end
-- found directory
- if (kind == unix.DT_DIR and kind ~= unix.DT_LNK)
- and not me.shouldHideFile(name) then
- seen[ino] = experience -- prevent recursion with symlinks
- print("✅ ".. fullpath .. " " ..ino)
+ if not me.shouldHideFile(name) and
+ ( (kind == unix.DT_DIR and kind ~= unix.DT_LNK) or experience.dir )
+ then
+ print("✅ ".. fullpath )
experience.dir = true
experience.portal3D = true -- can be viewed as 3d portal
app.pub("scan_experience", nil, experience)
- app.cache.items[ino] = experience
+ app.addExperience(experience,ino)
-- check for directory thumbnail sidecarfile
local thumbExt = {"png","jpg","webp"}
foreach( thumbExt, function(k,ext)
@@ -136,14 +144,18 @@ return {
end
---- found file
- if (kind ~= unix.DT_DIR and kind ~= unix.DT_LNK)
- and not me.shouldHideFile(name) then
- seen[ino] = experience.file -- prevent recursion with symlinks
+ if not me.shouldHideFile(name) and
+ ( (kind ~= unix.DT_DIR and kind ~= unix.DT_LNK) or not experience.dir )
+ then
trace("ℹ️ ".. fullpath)
experience.tag.file = true
app.pub("scan_experience_file", nil, experience)
local size = attr:size()
end
+
+ -- remember file/parent relationship
+ seen[ino] = experience
+
end
local dref, derr;
diff --git a/src/plugin/janusxr.lua b/src/plugin/janusxr.lua
index cc60abf..c207828 100644
--- a/src/plugin/janusxr.lua
+++ b/src/plugin/janusxr.lua
@@ -13,7 +13,7 @@ app.on('dir', function(opts)
if #app.opts.plugin_janusxr_random_objects > 0 and
#app.opts.plugin_janusxr_random_colors > 0 then
opts.data.janusxr_jml_deco = app.plugin.janusxr.getRandomDeco(7,50,hash,0,30) ..
- app.plugin.janusxr.getRandomDeco(7,50,hash .. hash,30,30)
+ app.plugin.janusxr.getRandomDeco(7,50, "2" .. hash,30,30)
end
end)
@@ -31,10 +31,8 @@ app.on('scan_experience_file', function(exp)
end)
if wrap then
exp.view3D = true
- exp.janusxr = {
- room = app.opts.plugin_janusxr_wrap_3dfile
- }
- app.cache.items[ exp.file.ino ] = exp
+ exp.janusxr = { wrap = { object = true }}
+ app.addExperience( exp, exp.file.ino )
print("✅ └─ plugin/janusxr: wrapping " .. exp.path)
end
end
@@ -49,13 +47,13 @@ app.on('scan_experience_file', function(exp)
exp.title = title:gsub("<.*","")
end
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
- app.cache.items[ exp.file.ino ] = exp
+ app.addExperience( exp, exp.file.ino )
exp.view3D = true
exp.parent.redirect = exp.url -- mark parent to redirect to this standalone url instead (not glb assets e.g.)
exp.janusxr = {}
print("✅ └─ plugin/janusxr: " .. exp.file.name)
if data:match(pattern_aframe) and app.opts.plugin_janusxr_wrap_aframe == 'enabled' then
- exp.janusxr.aframe = true
+ exp.janusxr.wrap = {aframe = true }
print("✅ └─ plugin/janusxr: AFRAME markup detected")
end
end
@@ -68,7 +66,7 @@ end)
app.on('set', function(k,v) end)
-- this registers the plugin UI
-local rooms = {random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"}
+local rooms = {random="random room",randomurl="random room (URL-deterministic)",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"}
local plugin = {
name = "JanusXR",
@@ -95,29 +93,29 @@ local plugin = {
key='app.opts.plugin_janusxr_wrap_3dfile',
title='VR wrap 3D file',
info='render 3D files in janusxr.xml room',
- default="room_plane",
+ default="randomurl",
values=util.merge(rooms,{disabled="-- disabled --"})
},
{
key='app.opts.plugin_janusxr_wrap_image',
title='VR wrap images',
info='render images in janusxr.xml room',
- default="room_plane",
+ default="randomurl",
values=util.merge(rooms,{disabled="-- disabled --"})
},
{
key='app.opts.plugin_janusxr_wrap_video',
title='VR wrap videos',
info='render videos in janusxr.xml room',
- default="room_plane",
+ default="randomurl",
values=util.merge(rooms,{disabled="-- disabled --"})
},
{
key='app.opts.plugin_janusxr_wrap_aframe',
title='AFRAME support',
info='render AFRAME (geometry) markup when detected in URLs',
- default="enabled",
- values={enabled="enabled",disabled="disabled"}
+ default="room_plane",
+ values=util.merge(rooms,{disabled="-- disabled --"})
},
{
key='app.opts.plugin_janusxr_portalroom',
@@ -138,7 +136,7 @@ local plugin = {
key='app.opts.plugin_janusxr_random_objects',
title='Random objects',
info="Random object id's in portal rooms",
- default="capsule cone cube cylinder pyramid sphere torus",
+ default="capsule cone cylinder pyramid sphere torus",
placeholder="capsule cone cylinder pyramid sphere torus",
values="",
},
@@ -174,21 +172,54 @@ local plugin = {
}
},
- getRandomRoom = function()
+ wrapRoomAroundFile = function(item)
+ local room = ''
+ if item.janusxr.wrap.object then
+ room = app.opts.plugin_janusxr_wrap_3dfile
+ end
+ if room == 'random' then
+ room = app.plugin.janusxr.getRandomRoom()
+ end
+ if room == 'randomurl' then
+ room = app.plugin.janusxr.getRandomRoom(item.url)
+ end
+ return room
+ end,
+
+ getRandomRoom = function(url)
local me = app.plugin.janusxr
local room= ''
math.randomseed(os.time())
foreach( me.opts, function(k,v)
if v.key == 'app.opts.plugin_janusxr_portalroom' then
local ordered = {}
- foreach( v.values, function(k,v) table.insert(ordered,v) end)
- room = ordered[ math.random( #ordered ) ]
+ foreach( v.values, function(k,v)
+ if not v:match("random") then
+ table.insert(ordered,v)
+ end
+ end)
+ table.sort(ordered) -- ensure same order
+ if url then
+ room = ordered[ me.hash_string_to_number(url) % #ordered ]
+ else
+ room = ordered[ math.random( #ordered ) ]
+ end
end
end)
return room
end,
+ hash_string_to_number = function(str)
+ local hash = 5381
+ for i = 1, #str do
+ local char = string.byte(str, i)
+ hash = (hash * 33 + char) % 2147483647
+ end
+ return hash
+ end,
+
getRandomDeco = function(num_objects, radius, seed_string, y, scale)
+ local me = app.plugin.janusxr
num_objects = num_objects or 6
y = y or 0
radius = radius or 2 -- Configurable distance from (0, 0, 0)
@@ -196,18 +227,12 @@ local plugin = {
local JML = ''
local colors = util.split( app.opts.plugin_janusxr_random_colors, ' ')
local ids = util.split( app.opts.plugin_janusxr_random_objects, ' ')
+ table.sort(colors) -- ensure same order
+ table.sort(ids) -- ensure same order
- local function hash_string_to_number(str)
- local hash = 5381
- for i = 1, #str do
- local char = string.byte(str, i)
- hash = (hash * 33 + char) % 2147483647
- end
- return hash
- end
local index = {
- color= hash_string_to_number(seed_string) % #colors,
- id = hash_string_to_number(seed_string) % #ids
+ color= me.hash_string_to_number(seed_string) % #colors,
+ id = me.hash_string_to_number(seed_string) % #ids
}
for i = 1, num_objects do
diff --git a/src/plugin/xrfragments.lua b/src/plugin/xrfragments.lua
index 784d810..1c6fcbe 100644
--- a/src/plugin/xrfragments.lua
+++ b/src/plugin/xrfragments.lua
@@ -51,7 +51,7 @@ app.on('scan_experience_file', function(exp)
-- finally insert if viewable
if exp.view3D then
print("✅ └─ plugin/xrfragments: marking as 3D viewable")
- app.cache.items[ exp.file.ino ] = exp
+ app.addExperience(exp, exp.file.ino)
end
end
end)