From 87068eb18d8e7b69536ba15383da51af0a016587 Mon Sep 17 00:00:00 2001 From: Will Budic Date: Thu, 25 Jan 2024 12:46:58 +1100 Subject: [PATCH] further dev. prep. --- htdocs/cgi-bin/CNFServices.cgi | 1 - htdocs/cgi-bin/system/modules/CNFNode.pm | 1 + htdocs/cgi-bin/system/modules/CNFParser.pm | 15 +- .../system/modules/ClassicAppSettings.pm | 141 ++++++++++++++++++ 4 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 htdocs/cgi-bin/system/modules/ClassicAppSettings.pm diff --git a/htdocs/cgi-bin/CNFServices.cgi b/htdocs/cgi-bin/CNFServices.cgi index 6464182..c3fa25b 100755 --- a/htdocs/cgi-bin/CNFServices.cgi +++ b/htdocs/cgi-bin/CNFServices.cgi @@ -86,7 +86,6 @@ sub CNFHTMLService($cgi) { $ptr = $ptr->{'PAGE'}; $cgi-> add_response_header('Expires', '1s'); $cgi-> add_response_header('Cache-Control', 'no-cache'); - if( $ENV{'HTTP_ACCEPT_ENCODING'} =~ m/gzip/ ){ $cgi-> add_response_header('Content-Encoding', 'gzip'); $cgi-> add_response_header('Accept-Encoding','Vary'); diff --git a/htdocs/cgi-bin/system/modules/CNFNode.pm b/htdocs/cgi-bin/system/modules/CNFNode.pm index 28bb4fa..da0ffb6 100644 --- a/htdocs/cgi-bin/system/modules/CNFNode.pm +++ b/htdocs/cgi-bin/system/modules/CNFNode.pm @@ -27,6 +27,7 @@ sub list {shift -> {'@@'}} sub script {shift -> {'~'}} sub priority {shift -> {'^'}} sub evaluate {shift -> {'&'}} +sub attr {shift->{$_[0]}} ### # Obtains this nodes all public attributes. # What you usually only want. diff --git a/htdocs/cgi-bin/system/modules/CNFParser.pm b/htdocs/cgi-bin/system/modules/CNFParser.pm index 7e47b96..e5e58c8 100644 --- a/htdocs/cgi-bin/system/modules/CNFParser.pm +++ b/htdocs/cgi-bin/system/modules/CNFParser.pm @@ -408,6 +408,7 @@ sub template { my ($self, $property, %macros) = @_; #private to parser sub. sub doInstruction { my ($self,$e,$t,$v) = @_; my $DO_ENABLED = $self->{'DO_ENABLED'}; my $priority = 0; + $e = $t if not defined $e; $t = "" if not defined $t; if($t eq 'CONST' or $t eq 'CONSTANT'){#Single constant with mulit-line value; # It is NOT allowed to overwrite constant. @@ -734,27 +735,30 @@ sub parse { my ($self, $cnf_file, $content, $del_keys) = @_; foreach my $line(split '\n', $v) { my $isMETAConst = $line =~ s/$meta_const//se; $line =~ s/^\s+|\s+$//; # strip unwanted spaces + next if $line =~ m/^[\/\#]+/; #skip this line its a comment dud. $line =~ s/\s*>$//; - $line =~ m/([\$\w]*)(\s*=\s*)(.*)/g; + $line =~ m/([\$\w]*)(\s*[=:]\s*)(.*)/g; my $name = $1; - $line = $3; $line =~ s/^\s*(['"])(.*)\g{1}$/$2/ if $line;#strip quotes + $line = $3; + $line =~ s/\s*\#.*$//g; #strip any perl comment at end of line. + $line =~ s/^\s*(['"])(.*)\g{1}$/$2/ if $line;#strip quotes if(defined $name){ if($isVar && not $isMETAConst){ $anons ->{$name} = $line if $line }else{ $name =~ s/^\$// if $isMETAConst; # It is NOT allowed to overwrite a constant, so check an issue warning. - if($line and not $self->{$name}){ + if(defined $line and not defined $self->{$name}){ $self->{$name} = $line; }else{ my $w = "Skipping and keeping a previously set constance of -> [$name] in ". $self->{CNF_CONTENT}." the new value "; - $w .= ($line eq $self->{$name})?"matches it":"dosean't match -> $line."; $self->warn($w) + $w .= ($line eq $self->{$name})?"matches it":"dosean't match ($.) -> $line."; $self->warn($w) } } } } }else{ - doInstruction($self,$v,$t,undef); + doInstruction($self,undef,$t,$v); } }else{ $v =~ s/\s*>$//; @@ -1426,6 +1430,7 @@ sub addTree { } } ### Utility way to obtain CNFNodes from a configuration. +# Reference to the node is returned access like: my $tree = $cnf.getTree(..); my $attr = $$tree->{attribute}; sub getTree { my ($self, $name) = @_; return $NODES{$name} if exists $NODES{$name}; diff --git a/htdocs/cgi-bin/system/modules/ClassicAppSettings.pm b/htdocs/cgi-bin/system/modules/ClassicAppSettings.pm new file mode 100644 index 0000000..d42822c --- /dev/null +++ b/htdocs/cgi-bin/system/modules/ClassicAppSettings.pm @@ -0,0 +1,141 @@ +### +# This is a Classic CNF Application setup and wiring implementation. To provide proper syncing and priorities of setting, based on application defaults, +# script implemented change (release or user changed) and in user or application changed settings, that can now be now in a store, +# a rather retrieved change from there. +# +# Application provided app settings have also the benefit to rather keyword access properties directly avoiding method calls in the code. +# Further explanations is that this module, sets up in a standard way the settings from some application based or from package provided defaults. +# With by transition from what is in the script or not, comparing with expected defaults of settings. i.e. the app has English defaults for values. +# But we changed constants to a Japanese translation and feed it to the app, now not having to change the whole codebase. +# +# Or the config script might be missing a property setting, but the application package settings (this file package) +# will have the default. Use this module as a template to provide own settings for transitions or app requirements. +# +# Or only more commonly, employ the static ClassicAppSettings::_set_defaults method before initiating or calling the parser with a script. +# Containing a <...>> instruction. +# +# App Settings Transition Flow +# +# App.Defaults -> ClassicAppSettings -> CNF Merge Default -> ClassicAppSettings [<-> App.StoreSynch Resolve] optional -> App.Settings +# +# The app has a configuration file to obtain settings, if missing gets them from assigned code defaults. And if the settings have changed or stored. +# They get retrieved and replaced regardless what is in code default or in the configuration script. Is this complex? +# @TODO Also, what happens if script based settings are changed (by admin) and should have higher priority as from the old setting and/or the one in the store? +# This also happens when we have an new Application release having new settings or worse changed defaults, and an an upgrade shall merge. +# Can or does JSON do all this stuff too, that CNF is designed for? The answer is NO! +### +package ClassicAppSettings; + +use strict;use warnings; +use feature qw(signatures); + + +use constant VERSION => '1.0'; +our %global_defaults; +our $gl_clone_constances = 0; + +sub _set_defaults(%defaults){ + %global_defaults = %defaults +} +sub _set_clone_constances(){ + $gl_clone_constances = 1 +} + +## +# Called by the parser internally for the APP_Settings instruction. +## +sub new { + my ($class, $attrs, $self) = @_; + $self = {}; + if ($attrs){ + foreach(keys %$attrs) + { $self -> {$_} = $attrs -> {$_} if $_ !~ 'package|subroutine|property' } + } + bless $self, $class; +} + +my $global_config; +my %sync_state; + +sub global($this){ + return $$global_config +} + +sub expect($this){ + return \%global_defaults +} + +sub setConstant($this, $config, $CONSTANT){ + if($config->{$CONSTANT} && not $this ->{$CONSTANT}){ + $this ->{$CONSTANT} = $config->{$CONSTANT} + } +} +## +# Possible synch type status changes that can be detected. +# APP_SETTINGS_SYNC == 1 - Scripted setting not found as an default. +# APP_SETTINGS_SYNC == 2 - New Setting in script not declared. +# APP_SETTINGS_SYNC == 3 - Scripted setting changed from default. +# APP_SETTINGS_SYNC == 4 - Constance not programatically properly wired. +# APP_SETTINGS_SYNC == 5 - Constance synched in, can't be changed with store synch. +# APP_SETTINGS_SYNC == 6 - Added new during store synch. +# APP_SETTINGS_SYNC == 7 - Changed from scipt default during store synch.. +## +sub setup_with($this, $config, %constants){ + + $this->setConstant($config,'APP_NAME'); + $this->setConstant($config,'APP_VERSION'); + if($gl_clone_constances){ + foreach (%{$config}){ + if($_ =~ m/^[A-Z_0-9]+$/) {$this -> setConstant($config, $_); $sync_state{$_} = 5} + } + } + foreach my $key(keys %{$this}){ + if(not exists $global_defaults{$key}){ + $sync_state{$key} = 1; + } + } + foreach my $key(keys %global_defaults){ + if(not exists $this->{$key}){ + $this->{$key} = $global_defaults{$key}; + $sync_state{$key} = 2; + }else{ + my $v = $global_defaults{$key}; + if(not defined($this->{$key})){ + $sync_state{$key} = 4; + $this->{$key} = $global_defaults{$key}; + }elsif($this->{$key} ne $v){ + #Default changed in script + $sync_state{$key} = 3; + } + } + } + $global_config = \$config; +} +### +# Must be called by obtainer of this, that also handles the store. +# Just befoer the App uses the settings. +### +sub sync_with($this, %store){ + foreach my $key ( keys %store ) { + if(not exists $this->{$key}){ + $sync_state{$key} = 6; + }else{ + $sync_state{$key} = 7; + } + $this -> {$key} = $store{$key} + } + return \%sync_state; +} + +1; + +=begin copyright +Programed by : Will Budic +EContactHash : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md) +Source : https://github.com/wbudic/PerlCNF.git +Documentation : Specifications_For_CNF_ReadMe.md + This source file is copied and usually placed in a local directory, outside of its repository project. + So it could not be the actual or current version, can vary or has been modiefied for what ever purpose in another project. + Please leave source of origin in this file for future references. +Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md +=cut copyright \ No newline at end of file -- 2.34.1