From fc126c2e0e9ccc64e063519432729660b5554c6e Mon Sep 17 00:00:00 2001 From: Adrian Salceanu Date: Wed, 19 Jun 2024 13:36:47 +0200 Subject: [PATCH] Fix auto-model storage and reload --- Project.toml | 2 +- src/ModelStorage.jl | 8 +++++--- src/ReactiveTools.jl | 43 ++++++++++++++++++++++++------------------- src/Stipple.jl | 20 +++++++++++++------- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/Project.toml b/Project.toml index 52316498..4b791c34 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Stipple" uuid = "4acbeb90-81a0-11ea-1966-bdaff8155998" authors = ["Adrian "] -version = "0.28.11" +version = "0.28.12" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/src/ModelStorage.jl b/src/ModelStorage.jl index 17022228..9dc139e4 100644 --- a/src/ModelStorage.jl +++ b/src/ModelStorage.jl @@ -12,8 +12,10 @@ function model_id(::Type{M}) where M Symbol(Stipple.routename(M)) end -function store(model::M) where M - GenieSession.set!(model_id(M), model) +function store(model::M, force::Bool = false) where M + # do not overwrite stored model + (GenieSession.get(model_id(M), nothing) === nothing || force) && GenieSession.set!(model_id(M), model) + nothing end @@ -22,8 +24,8 @@ function init_from_storage( t::Type{M}; kwargs...) where M model = Stipple.init(M; channel, kwargs...) stored_model = GenieSession.get(model_id(M), nothing) - CM = Stipple.get_concrete_type(M) + for f in fieldnames(CM) field = getfield(model, f) if field isa Reactive diff --git a/src/ReactiveTools.jl b/src/ReactiveTools.jl index 6f2cd652..4b1c68bd 100644 --- a/src/ReactiveTools.jl +++ b/src/ReactiveTools.jl @@ -734,30 +734,35 @@ macro init(args...) quote local new_handlers = false - local initfn = - if isdefined($__module__, :init_from_storage) && Stipple.USE_MODEL_STORAGE[] - $__module__.init_from_storage - else - Stipple.init + local initfn = begin + if Stipple.use_model_storage() && $__module__ === Stipple + Stipple.ModelStorage.Sessions.init_from_storage + elseif isdefined($__module__, :Stipple) && isdefined($__module__.Stipple, :ModelStorage) && isdefined($__module__.Stipple.ModelStorage, :Sessions) && isdefined($__module__.Stipple.ModelStorage.Sessions, :init_from_storage) && Stipple.use_model_storage() + $__module__.Stipple.ModelStorage.Sessions.init_from_storage + elseif isdefined($__module__, :init_from_storage) && Stipple.use_model_storage() + $__module__.init_from_storage + else + Stipple.init + end end local handlersfn = - if !$called_without_type - # writing '$(init_kwargs[type_pos])' generates an error during a pre-evaluation - # possibly from Revise? - # we use 'get' instead of 'getindex' - Stipple.ReactiveTools.HANDLERS_FUNCTIONS[$(get(init_args, type_pos, "dummy"))] - else - if isdefined($__module__, :__GF_AUTO_HANDLERS__) - if length(methods($__module__.__GF_AUTO_HANDLERS__)) == 0 - @eval(@handlers()) - new_handlers = true - end - $__module__.__GF_AUTO_HANDLERS__ + if !$called_without_type + # writing '$(init_kwargs[type_pos])' generates an error during a pre-evaluation + # possibly from Revise? + # we use 'get' instead of 'getindex' + Stipple.ReactiveTools.HANDLERS_FUNCTIONS[$(get(init_args, type_pos, "dummy"))] else - identity + if isdefined($__module__, :__GF_AUTO_HANDLERS__) + if length(methods($__module__.__GF_AUTO_HANDLERS__)) == 0 + @eval(@handlers()) + new_handlers = true + end + $__module__.__GF_AUTO_HANDLERS__ + else + identity + end end - end instance = let model = initfn($(init_args...)) new_handlers ? Base.invokelatest(handlersfn, model) : handlersfn(model) diff --git a/src/Stipple.jl b/src/Stipple.jl index 20916995..5e0342fc 100644 --- a/src/Stipple.jl +++ b/src/Stipple.jl @@ -20,6 +20,10 @@ const PRECOMPILE = Ref(false) const ALWAYS_REGISTER_CHANNELS = Ref(true) const USE_MODEL_STORAGE = Ref(true) +function use_model_storage() + USE_MODEL_STORAGE[] +end + """ Disables the automatic storage and retrieval of the models in the session. Useful for large models. @@ -98,7 +102,7 @@ export setchannel, getchannel isempty(methods(notify, Observables)) && (Base.notify(observable::AbstractObservable) = Observables.notify!(observable)) include("ParsingTools.jl") -USE_MODEL_STORAGE[] && include("ModelStorage.jl") +use_model_storage() && include("ModelStorage.jl") include("NamedTuples.jl") include("stipple/reactivity.jl") @@ -357,7 +361,7 @@ function watch(vue_app_name::String, fieldname::Symbol, channel::String, debounc print(output, debounce == 0 ? """ $vue_app_name.\$watch(function(){return this.$fieldname}, function(newVal, oldVal){$jsfunction}, {deep: true}); - """ : + """ : """ $vue_app_name.\$watch(function(){return this.$fieldname}, _.debounce(function(newVal, oldVal){$jsfunction}, $debounce), {deep: true}); """ @@ -387,6 +391,8 @@ const CHANNELPARAM = :CHANNEL__ function sessionid(; encrypt::Bool = true) :: String + use_model_storage() || error("Model storage is disabled") + sessid = Stipple.ModelStorage.Sessions.GenieSession.session().id encrypt ? Genie.Encryption.encrypt(sessid) : sessid @@ -411,7 +417,7 @@ function channeldefault(::Type{M}) where M<:ReactiveModel model_id = Symbol(Stipple.routename(M)) - USE_MODEL_STORAGE[] || return nothing + use_model_storage() || return nothing stored_model = Stipple.ModelStorage.Sessions.GenieSession.get(model_id, nothing) stored_model === nothing ? nothing : getfield(stored_model, Stipple.CHANNELFIELDNAME) @@ -514,7 +520,7 @@ function init(t::Type{M}; setchannel(model, channel) # make sure we store the channel name in the model - USE_MODEL_STORAGE[] && Stipple.ModelStorage.Sessions.store(model) + use_model_storage() && Stipple.ModelStorage.Sessions.store(model) # add a timer that checks if the model is outdated and if so prepare the model to be garbage collected LAST_ACTIVITY[Symbol(getchannel(model))] = now() @@ -536,7 +542,7 @@ function init(t::Type{M}; client = transport == Genie.WebChannels ? Genie.WebChannels.id(Genie.Requests.wsclient()) : Genie.Requests.wtclient() try - haskey(payload, "sesstoken") && ! isempty(payload["sesstoken"]) && USE_MODEL_STORAGE[] && + haskey(payload, "sesstoken") && ! isempty(payload["sesstoken"]) && use_model_storage() && Genie.Router.params!(Stipple.ModelStorage.Sessions.GenieSession.PARAMS_SESSION_KEY, Stipple.ModelStorage.Sessions.GenieSession.load(payload["sesstoken"] |> Genie.Encryption.decrypt)) catch ex @@ -1309,14 +1315,14 @@ using Stipple.ReactiveTools end end - route("/") do + route("/") do model = Stipple.ReactiveTools.@init PrecompileApp page(model, ui) |> html end port = tryparse(Int, get(ENV, "STIPPLE_PRECOMPILE_PORT", "")) port === nothing && (port = rand(8081:8999)) up(port) - + precompile_get = tryparse(Bool, get(ENV, "STIPPLE_PRECOMPILE_GET", "1")) precompile_get === true && HTTP.get("http://localhost:$port") # The following lines (still) produce an error although