diff --git a/vlib/vweb/dynamic_template_manager_test.v b/vlib/vweb/dynamic_template_manager_test.v deleted file mode 100644 index 0bea60e5aa9aa1..00000000000000 --- a/vlib/vweb/dynamic_template_manager_test.v +++ /dev/null @@ -1,403 +0,0 @@ -module vweb - -import os -import time - -const temp_dtm_dir = 'dynamic_template_manager_test' -const temp_cache_dir = 'vcache' -const temp_templates_dir = 'templates' -const temp_html_fp = 'temp.html' -const temp_html_n = 'temp' -const vtmp_dir = os.vtmp_dir() - -fn testsuite_begin() { - temp_folder := os.join_path(vweb.vtmp_dir, vweb.temp_dtm_dir) - os.mkdir_all(temp_folder) or { panic(err) } - - vcache_path := os.join_path(temp_folder, vweb.temp_cache_dir) - templates_path := os.join_path(temp_folder, vweb.temp_templates_dir) - - os.mkdir_all(vcache_path) or { panic(err) } - os.mkdir_all(templates_path) or { panic(err) } - - temp_html_file := os.join_path(templates_path, vweb.temp_html_fp) - - html_content := ' - - - - TEST - - -
-

TEST

-
- - ' - - os.write_file(temp_html_file, html_content) or { panic(err) } -} - -fn test_initialize_dtm() { - dtm := init_dtm(false, 0) - assert dtm.dtm_init_is_ok == true -} - -fn test_test_and_clear_cache_files() { - dtm := init_dtm(false, 0) - dtm.test_and_clear_cache_files() or { panic(err) } - - count_cache_files := os.ls(dtm.template_cache_folder) or { panic(err) } - assert count_cache_files.len == 0 -} - -fn test_create_template_cache_and_display_html() { - mut dtm := init_dtm(true, max_size_data_in_memory) - defer { - dtm.stop_cache_handler() - } - html := dtm.create_cache() - assert html.len > 10 -} - -fn test_get_cache() { - mut dtm := init_dtm(true, max_size_data_in_memory) - dtm.create_cache() - defer { - dtm.stop_cache_handler() - } - dtm_placeholers := map[string]DtmMultiTypeMap{} - temp_html_file := os.join_path(dtm.template_folder, vweb.temp_html_fp) - html_mem := dtm.get_cache(vweb.temp_html_n, temp_html_file, &dtm_placeholers) - assert html_mem.len > 10 -} - -fn test_return_cache_info_isexistent() { - mut dtm := init_dtm(false, 0) - path_template := os.join_path(dtm.template_folder, vweb.temp_html_fp) - lock dtm.template_caches { - dtm.template_caches << TemplateCache{ - id: 1 - path: path_template - } - } - lock dtm.nbr_of_remaining_template_request { - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 1 - } - } - cache_exists, _, _, _, _, _, _, _ := dtm.return_cache_info_isexistent(path_template) - assert cache_exists == true - lock dtm.template_caches { - dtm.template_caches[0].id_redirection = 2 - dtm.template_caches << TemplateCache{ - id: 2 - path: path_template - id_redirection: 3 - } - dtm.template_caches << TemplateCache{ - id: 3 - path: path_template - id_redirection: 4 - } - dtm.template_caches << TemplateCache{ - id: 4 - path: path_template - id_redirection: 5 - } - dtm.template_caches << TemplateCache{ - id: 5 - path: path_template - } - } - lock dtm.nbr_of_remaining_template_request { - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 2 - } - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 3 - } - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 4 - } - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 5 - } - } - _, id, _, _, _, _, _, _ := dtm.return_cache_info_isexistent(path_template) - assert id == 5 -} - -fn test_remaining_template_request() { - mut dtm := init_dtm(false, 0) - - lock dtm.nbr_of_remaining_template_request { - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 1 - } - - dtm.remaining_template_request(true, 1) - assert dtm.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 1 - dtm.remaining_template_request(true, 1) - assert dtm.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 2 - dtm.remaining_template_request(false, 1) - assert dtm.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 1 - dtm.remaining_template_request(false, 1) - assert dtm.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 0 - } -} - -fn test_check_html_and_placeholders_size() { - dtm := init_dtm(false, 0) - temp_html_file := os.join_path(dtm.template_folder, vweb.temp_html_fp) - placeholders := map[string]DtmMultiTypeMap{} - - path, filename := dtm.check_html_and_placeholders_size(temp_html_file, &placeholders) or { - panic(err) - } - - assert path.len > 10 - assert filename.len > 3 -} - -fn test_chandler_prevent_cache_duplicate_request() { - dtm := init_dtm(false, 0) - temp_html_file := os.join_path(dtm.template_folder, vweb.temp_html_fp) - - lock dtm.template_caches { - dtm.template_caches << TemplateCache{ - id: 1 - path: temp_html_file - cache_request: .new - } - dtm.template_caches << TemplateCache{ - id: 2 - path: temp_html_file - cache_request: .update - last_template_mod: i64(1) - } - dtm.template_caches << TemplateCache{ - id: 3 - path: temp_html_file - cache_request: .exp_update - last_template_mod: i64(1) - generate_at: i64(100) - } - dtm.template_caches << TemplateCache{ - id: 4 - cache_request: .delete - } - } - new_cache := TemplateCache{ - id: 5 - path: temp_html_file - cache_request: .new - } - update_cache := TemplateCache{ - id: 6 - path: temp_html_file - cache_request: .update - last_template_mod: i64(1) - } - exp_update_cache := TemplateCache{ - id: 7 - path: temp_html_file - cache_request: .exp_update - last_template_mod: i64(1) - generate_at: i64(10) - cache_delay_expiration: i64(10) - } - delete_cache := TemplateCache{ - id: 4 - cache_request: .delete - } - mut is_duplicate := dtm.chandler_prevent_cache_duplicate_request(&new_cache) - assert is_duplicate == true - is_duplicate = dtm.chandler_prevent_cache_duplicate_request(&update_cache) - assert is_duplicate == true - is_duplicate = dtm.chandler_prevent_cache_duplicate_request(&exp_update_cache) - assert is_duplicate == true - is_duplicate = dtm.chandler_prevent_cache_duplicate_request(&delete_cache) - assert is_duplicate == false - - lock dtm.template_caches { - dtm.template_caches.delete(3) - } - - is_duplicate = dtm.chandler_prevent_cache_duplicate_request(&delete_cache) - assert is_duplicate == true -} - -fn test_chandler_clear_specific_cache() { - mut dtm := init_dtm(true, 0) - defer { - dtm.stop_cache_handler() - } - dtm.create_cache() - lock dtm.template_caches { - cache_file := os.join_path(dtm.template_cache_folder, '${dtm.template_caches[0].name}_${dtm.template_caches[0].checksum}.cache') - index, is_success := dtm.chandler_clear_specific_cache(dtm.template_caches[0].id) - assert is_success == true - assert index == 0 - cache_exist := os.exists(cache_file) - assert cache_exist == false - } -} - -fn test_chandler_remaining_cache_template_used() { - mut dtm := init_dtm(false, 0) - lock dtm.nbr_of_remaining_template_request { - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 1 - nbr_of_remaining_request: 0 - } - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 2 - nbr_of_remaining_request: 1 - need_to_delete: true - } - dtm.nbr_of_remaining_template_request << RemainingTemplateRequest{ - id: 3 - nbr_of_remaining_request: 0 - need_to_delete: true - } - } - mut can_delete := dtm.chandler_remaining_cache_template_used(CacheRequest.update, - 3, 3) - assert can_delete == true - can_delete = dtm.chandler_remaining_cache_template_used(CacheRequest.update, 2, 2) - assert can_delete == false - can_delete = dtm.chandler_remaining_cache_template_used(CacheRequest.delete, 1, 0) - assert can_delete == true - can_delete = dtm.chandler_remaining_cache_template_used(CacheRequest.new, 4, 0) - assert can_delete == true -} - -fn test_parse_html_file() { - mut dtm := init_dtm(false, 0) - temp_folder := os.join_path(vweb.vtmp_dir, vweb.temp_dtm_dir) - templates_path := os.join_path(temp_folder, vweb.temp_templates_dir) - temp_html_file := os.join_path(templates_path, vweb.temp_html_fp) - - mut placeholders := map[string]DtmMultiTypeMap{} - - is_compressed := true - html, content_checksum := dtm.parse_html_file(temp_html_file, vweb.temp_html_n, &placeholders, - is_compressed) - - assert html.len > 0 - if placeholders.len > 0 { - assert content_checksum.len > 0 - } else { - assert content_checksum.len == 0 - } -} - -fn test_test_if_cache_delay_iscorrect() { - test_if_cache_delay_iscorrect(i64(300), vweb.temp_html_n) or { assert false } - - test_if_cache_delay_iscorrect(i64(-100), vweb.temp_html_n) or { assert true } -} - -fn test_cache_request_route() { - mut is_cache_exist := true - mut cache_delay_expiration := i64(400) - mut last_template_mod := get_current_unix_timestamp() - mut test_current_template_mod := last_template_mod - mut cache_del_exp := 300 - mut gen_at := last_template_mod - mut content_checksum := 'checksumtest1' - mut current_content_checksum := 'checksumtest2' - - mut request_type := cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, - test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), - content_checksum, current_content_checksum) - - assert request_type == CacheRequest.update - - current_content_checksum = 'checksumtest1' - - request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, - test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), - content_checksum, current_content_checksum) - - assert request_type == CacheRequest.cached - - gen_at = (last_template_mod - 500) - - request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, - test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), - content_checksum, current_content_checksum) - - assert request_type == CacheRequest.exp_update - - is_cache_exist = false - - request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, - test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), - content_checksum, current_content_checksum) - - assert request_type == CacheRequest.new -} - -fn test_cache_handler() { - mut dtm := init_dtm(true, max_size_data_in_memory) - defer { - dtm.stop_cache_handler() - } - dtm.create_cache() - path_f := os.join_path(dtm.template_folder, vweb.temp_html_fp) - lock dtm.template_caches { - assert dtm.template_caches[0].id == 1 - assert dtm.template_caches[0].name == vweb.temp_html_n - assert dtm.template_caches[0].path == path_f - } - dtm.id_to_handlered = 1 - dtm.ch_cache_handler <- TemplateCache{ - id: 1 - cache_request: .delete - } - time.sleep(1 * time.millisecond) - lock dtm.template_caches { - assert dtm.template_caches.len == 0 - } -} - -fn testsuite_end() { - temp_folder := os.join_path(vweb.vtmp_dir, vweb.temp_dtm_dir) - os.rmdir_all(temp_folder) or {} -} - -// Utilities function : - -fn init_dtm(b bool, m int) &DynamicTemplateManager { - temp_folder := os.join_path(vweb.vtmp_dir, vweb.temp_dtm_dir) - vcache_path := os.join_path(temp_folder, vweb.temp_cache_dir) - templates_path := os.join_path(temp_folder, vweb.temp_templates_dir) - - mut ctx := Context{} - mut dtm := create_dtm() - - init_params := DynamicTemplateManagerInitialisationParams{ - active_cache_server: b - max_size_data_in_mem: m - test_cache_dir: vcache_path - test_template_dir: templates_path - } - - ctx.initialize_dtm(mut dtm, init_params) or { panic(err) } - - return dtm -} - -fn (mut dtm DynamicTemplateManager) create_cache() string { - temp_html_file := os.join_path(dtm.template_folder, vweb.temp_html_fp) - html_last_mod := os.file_last_mod_unix(temp_html_file) - c_time := get_current_unix_timestamp() - cache_delay_exp := i64(500) - placeholder := map[string]DtmMultiTypeMap{} - html := dtm.create_template_cache_and_display_html(.new, html_last_mod, c_time, temp_html_file, - vweb.temp_html_n, cache_delay_exp, &placeholder) - time.sleep(1 * time.millisecond) - return html -} diff --git a/vlib/vweb/tests/dynamic_template_manager_test_server/dynamic_template_manager_test_server.v b/vlib/vweb/tests/dynamic_template_manager_test_server/dynamic_template_manager_test_server.v index fc1b01a3092676..ee2fcf882dc88c 100644 --- a/vlib/vweb/tests/dynamic_template_manager_test_server/dynamic_template_manager_test_server.v +++ b/vlib/vweb/tests/dynamic_template_manager_test_server/dynamic_template_manager_test_server.v @@ -1,13 +1,14 @@ import vweb import time +import x.templating.dtm struct App { vweb.Context pub mut: - dtm &vweb.DynamicTemplateManager = vweb.create_dtm() - shared_data_string []string = []string{} @[vweb_global] - shared_data_int []int = []int{} @[vweb_global] - shared_switch int = 1 @[vweb_global] + dtm &dtm.DynamicTemplateManager = dtm.create_dtm() @[vweb_global] + shared_data_string []string = []string{} @[vweb_global] + shared_data_int []int = []int{} @[vweb_global] + shared_switch int = 1 @[vweb_global] } fn main() { @@ -21,7 +22,7 @@ fn main() { app.shared_data_int << 123456 app.shared_data_int << 7891011 - app.initialize_dtm(mut app.dtm) or { eprintln(err) } + dtm.initialize_dtm(mut app.dtm) or { eprintln(err) } /* app.initialize_dtm(mut &app.dtm, compress_html: false @@ -35,17 +36,18 @@ fn main() { @['/'] pub fn (mut app App) index() vweb.Result { - mut tmpl_var := map[string]vweb.DtmMultiTypeMap{} + mut tmpl_var := map[string]dtm.DtmMultiTypeMap{} tmpl_var['title'] = app.shared_data_string[app.shared_switch] tmpl_var['non_string_type'] = app.shared_data_int[app.shared_switch] tmpl_var['string_type'] = app.shared_data_string[4] tmpl_var['html_#includehtml'] = app.shared_data_string[app.shared_switch + 2] // You can also modify the HTML template file directly without having to recompile the application. - return app.serve_dynamic_template('index.html', + html_content := app.dtm.serve_dynamic_template('index.html', placeholders: &tmpl_var - cache_delay_expiration: vweb.cache_delay_expiration_at_min + cache_delay_expiration: dtm.cache_delay_expiration_at_min ) + return app.html(html_content) } fn (mut app App) update_data() { diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 08930a46a1361d..fd7b4ff56473c4 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -158,8 +158,6 @@ pub: req http.Request // TODO Response pub mut: - // DTM reference field - dtm &DynamicTemplateManager = unsafe { nil } done bool // time.ticks() from start of vweb connection handle. // You can use it to determine how much time is spent on your request. @@ -647,10 +645,7 @@ fn new_request_app[T](global_app &T, ctx Context, tid int) &T { request_app.Context.static_files = global_app.static_files.clone() request_app.Context.static_mime_types = global_app.static_mime_types.clone() request_app.Context.static_hosts = global_app.static_hosts.clone() - // TODO: Temporarily using this, to assign DTM due to V's current limitations with shared field handling at comptime. Needs future revision. - unsafe { - request_app.Context.dtm = &voidptr(global_app.dtm) - } + return request_app } diff --git a/vlib/vweb/dynamic_template_manager.v b/vlib/x/templating/dtm/dynamic_template_manager.v similarity index 84% rename from vlib/vweb/dynamic_template_manager.v rename to vlib/x/templating/dtm/dynamic_template_manager.v index 2990be8c35dba5..d8c171038e4073 100644 --- a/vlib/vweb/dynamic_template_manager.v +++ b/vlib/x/templating/dtm/dynamic_template_manager.v @@ -1,10 +1,11 @@ -module vweb +module dtm import os import v.parser import crypto.sha256 import time import regex +import x.templating // These are all the types of dynamic values that the DTM allows to be returned in the context of a map type DtmMultiTypeMap = f32 | f64 | i16 | i64 | i8 | int | string | u16 | u32 | u64 | u8 @@ -26,9 +27,11 @@ const max_placeholders_key_size = 50 // Sets the maximum character length for placeholder values. const max_placeholders_value_size = 3000 -const message_signature = '[Vweb DTM]' -const message_signature_info = '[Vweb DTM] Info :' -const message_signature_error = '[Vweb DTM] Error :' +const internat_server_error = 'Internal Server Error' + +const message_signature = '[Dynamic Template Manager]' +const message_signature_info = '[Dynamic Template Manager] Info :' +const message_signature_error = '[Dynamic Template Manager] Error :' pub enum CacheStorageMode { memory @@ -57,7 +60,7 @@ mut: template_caches shared []TemplateCache = []TemplateCache{} // counter for each individual TemplateCache created/updated id_counter int = 1 - ch_cache_handler chan TemplateCache = chan TemplateCache{cap: vweb.cache_handler_channel_cap} + ch_cache_handler chan TemplateCache = chan TemplateCache{cap: dtm.cache_handler_channel_cap} // 'id_to_handlered' field is used exclusively by the cache handler to update or delete specific 'TemplateCache' in the cache database. id_to_handlered int close_cache_handler bool @@ -65,7 +68,7 @@ mut: compress_html bool = true active_cache_server bool = true // Initialisation of max data size in memory storage - max_size_data_in_memory int = vweb.max_size_data_in_memory + max_size_data_in_memory int = dtm.max_size_data_in_memory // This array is designed to store a control process that checks whether cached data is currently in use while simultaneously handling expiration. // This allows for the harmonious management of both aspects and facilitates the necessary actions. nbr_of_remaining_template_request shared []RemainingTemplateRequest = []RemainingTemplateRequest{} @@ -126,7 +129,7 @@ mut: @[params] pub struct TemplateCacheParams { placeholders &map[string]DtmMultiTypeMap = &map[string]DtmMultiTypeMap{} - cache_delay_expiration i64 = vweb.cache_delay_expiration_by_default + cache_delay_expiration i64 = dtm.cache_delay_expiration_by_default } // These parameters are used with 'initialize_dtm' function. (See below at initialize_dtm comment) @@ -134,7 +137,7 @@ pub struct TemplateCacheParams { pub struct DynamicTemplateManagerInitialisationParams { compress_html bool = true active_cache_server bool = true - max_size_data_in_mem int = vweb.max_size_data_in_memory + max_size_data_in_mem int = dtm.max_size_data_in_memory test_cache_dir string test_template_dir string } @@ -147,9 +150,9 @@ pub fn create_dtm() &DynamicTemplateManager { return &DynamicTemplateManager{} } -// pub fn (mut Context) initialize_dtm(&DynamicTemplateManager, string, DynamicTemplateManagerInitialisationParams) return ! +// pub fn initialize_dtm(&DynamicTemplateManager, string, DynamicTemplateManagerInitialisationParams) return ! // -// Initializes the 'DynamicTemplateManager' with the storage mode, cache folder path and set a persistent reference of DTM in the Vweb global Context +// Initializes the 'DynamicTemplateManager' with the storage mode, cache folder path and set a persistent reference of DTM in the dtm global Context // The Dynamic Template Manager (DTM) requires this initialization function to be operational. // A "vcache" directory must be created at the root of the project (where the executable is located) to use the DTM. // Initalisation params are : @@ -160,7 +163,7 @@ pub fn create_dtm() &DynamicTemplateManager { // - test_template_dir: 'type string' Used only for DTM test file, parameter is ignored otherwise. // // vfmt off -pub fn (mut ctx Context) initialize_dtm(mut dtm &DynamicTemplateManager, dtm_init_params DynamicTemplateManagerInitialisationParams) ! { +pub fn initialize_dtm(mut dtmref &DynamicTemplateManager, dtm_init_params DynamicTemplateManagerInitialisationParams) ! { // vfmt on mut dir_path := '' mut dir_html_path := '' @@ -173,48 +176,44 @@ pub fn (mut ctx Context) initialize_dtm(mut dtm &DynamicTemplateManager, dtm_ini } // Control if 'vcache' folder exist in the root project if os.exists(dir_path) && os.is_dir(dir_path) { - dtm.template_cache_folder = dir_path + dtmref.template_cache_folder = dir_path // WARNING: When setting the directory for caching files and for testing purposes, // 'test_and_clear_cache_files' function will delete all "*.cache" or "*.tmp" files inside the specified 'vcache' directory in the project root's. Ensure that // directory used for the cache does not contain any important files. - dtm.test_and_clear_cache_files()! + dtmref.test_and_clear_cache_files()! // Control if 'templates' folder exist in the root project if !os.exists(dir_html_path) && !os.is_dir(dir_html_path) { - return error('${vweb.message_signature_error} The templates directory at the project root does not exist. Please create a "templates" directory at the root of your project with appropriate read permissions. This is a mandatory step for using the Dynamic Template Manager (DTM). Current path attempted for create the templates folder: "${dir_html_path}"') + return error('${dtm.message_signature_error} The templates directory at the project root does not exist. Please create a "templates" directory at the root of your project with appropriate read permissions. This is a mandatory step for using the Dynamic Template Manager (DTM). Current path attempted for create the templates folder: "${dir_html_path}"') } else { - dtm.template_folder = dir_html_path + dtmref.template_folder = dir_html_path } } else { - return error('${vweb.message_signature_error} The cache storage directory at the project root does not exist. Please create a "vcache" directory at the root of your project with appropriate read/write permissions. This is a mandatory step for using the Dynamic Template Manager (DTM). Current path attempted for create the cache folder: "${dir_path}"') + return error('${dtm.message_signature_error} The cache storage directory at the project root does not exist. Please create a "vcache" directory at the root of your project with appropriate read/write permissions. This is a mandatory step for using the Dynamic Template Manager (DTM). Current path attempted for create the cache folder: "${dir_path}"') } // Validates the 'max_size_data_in_mem' setting in 'dtm_init_params'. If it's within the valid range, it's applied; otherwise, default value is used. - if dtm_init_params.max_size_data_in_mem <= vweb.max_size_data_in_memory + if dtm_init_params.max_size_data_in_mem <= dtm.max_size_data_in_memory && dtm_init_params.max_size_data_in_mem >= 0 { - dtm.max_size_data_in_memory = dtm_init_params.max_size_data_in_mem + dtmref.max_size_data_in_memory = dtm_init_params.max_size_data_in_mem } else { mut type_error := 'exceeds' if dtm_init_params.max_size_data_in_mem < 0 { type_error = 'is invalid for define' } - eprintln('${vweb.message_signature_info} The value "${dtm_init_params.max_size_data_in_mem}KB" ${type_error} the memory storage limit. It will not be considered, and the limit will be set to ${vweb.max_size_data_in_memory}KB.') + eprintln('${dtm.message_signature_info} The value "${dtm_init_params.max_size_data_in_mem}KB" ${type_error} the memory storage limit. It will not be considered, and the limit will be set to ${dtm.max_size_data_in_memory}KB.') } // Disable light HTML compression if user doesn't required. ( By default is ON ) if !dtm_init_params.compress_html { - dtm.compress_html = false + dtmref.compress_html = false } // Disable cache handler if user doesn't required. Else, new thread is used to start the cache system. ( By default is ON ) if !dtm_init_params.active_cache_server { - dtm.active_cache_server = false + dtmref.active_cache_server = false } else { - spawn dtm.cache_handler() - } - // Include a persistent reference of DTM in the Vweb global Context - unsafe { - ctx.dtm = &dtm + spawn dtmref.cache_handler() } - dtm.dtm_init_is_ok = true - println('${vweb.message_signature} Dynamic Template Manager mode activated') + dtmref.dtm_init_is_ok = true + println('${dtm.message_signature} Dynamic Template Manager mode activated') } /* @@ -231,7 +230,7 @@ fn init_cache_block_middleware(cache_dir string, mut dtm &DynamicTemplateManager } */ -// pub fn (mut Context) serve_dynamic_template(string, TemplateCacheParams) return vweb.Result +// pub fn (mut tm DynamicTemplateManager) serve_dynamic_template(string, TemplateCacheParams) return string // // Serves dynamic template based on its full path and parameters. Manages the cache and returns generated HTML. // It the unique public function of DTM ( with initialization ), but requires an initialization via 'initialize_dtm' to running. @@ -239,13 +238,13 @@ fn init_cache_block_middleware(cache_dir string, mut dtm &DynamicTemplateManager // However, it allows the use of subfolder paths within the 'templates' directory, // enabling users to structure their templates in a way that best suits their project's organization. // -pub fn (mut ctx Context) serve_dynamic_template(tmpl_path string, tmpl_var TemplateCacheParams) Result { - if ctx.dtm.dtm_init_is_ok { - file_path, tmpl_name := ctx.dtm.check_html_and_placeholders_size(tmpl_path, tmpl_var.placeholders) or { - return ctx.html(err.msg()) +pub fn (mut tm DynamicTemplateManager) serve_dynamic_template(tmpl_path string, tmpl_var TemplateCacheParams) string { + if tm.dtm_init_is_ok { + file_path, tmpl_name := tm.check_html_and_placeholders_size(tmpl_path, tmpl_var.placeholders) or { + return err.msg() } // If cache exist, return necessary fields else, 'is_cache_exist' return false. - is_cache_exist, id, path, mut last_template_mod, gen_at, cache_del_exp, c_time, content_checksum := ctx.dtm.return_cache_info_isexistent(file_path) + is_cache_exist, id, path, mut last_template_mod, gen_at, cache_del_exp, c_time, content_checksum := tm.return_cache_info_isexistent(file_path) mut html := '' // Definition of several variables used to assess the need for cache updates.sss // This determination is based on modifications within the HTML template itself. @@ -286,28 +285,28 @@ pub fn (mut ctx Context) serve_dynamic_template(tmpl_path string, tmpl_var Templ match cash_req { .new { // Create a new cache - html = ctx.dtm.create_template_cache_and_display_html(cash_req, last_template_mod, + html = tm.create_template_cache_and_display_html(cash_req, last_template_mod, c_time, file_path, tmpl_name, tmpl_var.cache_delay_expiration, tmpl_var.placeholders) // println('create cache : ${cash_req}') } .update, .exp_update { // Update an existing cache - ctx.dtm.id_to_handlered = id - html = ctx.dtm.create_template_cache_and_display_html(cash_req, test_current_template_mod, + tm.id_to_handlered = id + html = tm.create_template_cache_and_display_html(cash_req, test_current_template_mod, c_time, file_path, tmpl_name, tmpl_var.cache_delay_expiration, tmpl_var.placeholders) // println('update cache : ${cash_req}') } else { // Use the provided cache of html template. - html = ctx.dtm.get_cache(tmpl_name, path, tmpl_var.placeholders) + html = tm.get_cache(tmpl_name, path, tmpl_var.placeholders) // println('get cache : ${cash_req}') } } - return ctx.html(html) + return html } else { - ctx.dtm.stop_cache_handler() - eprintln('${vweb.message_signature_error} The initialization phase of DTM has failed. Therefore, you cannot use it. Please address the errors and then restart the Vweb server.') - return ctx.html(http_500.body) + tm.stop_cache_handler() + eprintln('${dtm.message_signature_error} The initialization phase of DTM has failed. Therefore, you cannot use it. Please address the errors and then restart the dtm server.') + return dtm.internat_server_error } } @@ -325,25 +324,25 @@ pub fn (mut ctx Context) serve_dynamic_template(tmpl_path string, tmpl_var Templ // directory used for the cache does not contain any important files. // fn (tm DynamicTemplateManager) test_and_clear_cache_files() ! { - // println('${vweb.message_signature} WARNING! DTM needs to perform some file tests in the 'vcache' directory in your project. This operation will erase all "*.cache" or "*.tmp" files content in the folder : "${tm.template_cache_folder}"') + // println('${message_signature} WARNING! DTM needs to perform some file tests in the 'vcache' directory in your project. This operation will erase all "*.cache" or "*.tmp" files content in the folder : "${tm.template_cache_folder}"') // println('Do you want to continue the operation? (yes/no)') // mut user_response := os.input('>').to_lower() // if user_response != 'yes' && user_response != 'y' { - // return error('${vweb.message_signature_error} Operation cancelled by the user. DTM initialization failed.') + // return error('${message_signature_error} Operation cancelled by the user. DTM initialization failed.') // } else { file_p := os.join_path(tm.template_cache_folder, 'test.tmp') // Create a text file for test permission access mut f := os.create(file_p) or { - return error('${vweb.message_signature_error} Files are not writable. Test fail, DTM initialization failed : ${err.msg()}') + return error('${dtm.message_signature_error} Files are not writable. Test fail, DTM initialization failed : ${err.msg()}') } f.close() // Read the previous text file for test permission access os.read_file(file_p) or { - return error('${vweb.message_signature_error} Files are not readable. Test fail, DTM initialization failed : ${err.msg()}') + return error('${dtm.message_signature_error} Files are not readable. Test fail, DTM initialization failed : ${err.msg()}') } // List all files in the cache folder files_list := os.ls(tm.template_cache_folder) or { - return error('${vweb.message_signature_error} While listing the cache directorie files, DTM initialization failed : ${err.msg()}') + return error('${dtm.message_signature_error} While listing the cache directorie files, DTM initialization failed : ${err.msg()}') } // Delete one by one "*.cache" or "*.tmp" files in the previous file list for file in files_list { @@ -351,7 +350,7 @@ fn (tm DynamicTemplateManager) test_and_clear_cache_files() ! { file_extension := os.file_ext(file_path).to_lower() if file_extension in ['.tmp', '.cache'] { os.rm(file_path) or { - eprintln('${vweb.message_signature_error} While deleting the cache file: ${file_path}. DTM initialization failed : ${err.msg()}') + eprintln('${dtm.message_signature_error} While deleting the cache file: ${file_path}. DTM initialization failed : ${err.msg()}') return } } @@ -380,27 +379,26 @@ fn (tm DynamicTemplateManager) check_html_and_placeholders_size(f_path string, t file_name := file_name_with_ext.all_before_last('.') // Performs a basic check of the file extension. ext := os.file_ext(html_file) - content_type := mime_types[ext] - if content_type != 'text/html' { - eprintln('${vweb.message_signature_error} ${html_file}, is not a HTML file') - return error(http_500.body) + if ext != '.html' { + eprintln('${dtm.message_signature_error} ${html_file}, is not a HTML file') + return error(dtm.internat_server_error) } // Control placeholder key and value sizes for key, value in tmpl_var { - if key.str().len > vweb.max_placeholders_key_size { - eprintln('${vweb.message_signature_error} Length of placeholder key "${key}" exceeds the maximum allowed size for HTML content in file: ${html_file}. Max allowed size: ${vweb.max_placeholders_key_size} characters.') - return error(http_500.body) + if key.str().len > dtm.max_placeholders_key_size { + eprintln('${dtm.message_signature_error} Length of placeholder key "${key}" exceeds the maximum allowed size for HTML content in file: ${html_file}. Max allowed size: ${dtm.max_placeholders_key_size} characters.') + return error(dtm.internat_server_error) } - if value.str().len > vweb.max_placeholders_value_size { - eprintln('${vweb.message_signature_error} Length of placeholder value for key "${key}" exceeds the maximum allowed size for HTML content in file: ${html_file}. Max allowed size: ${vweb.max_placeholders_value_size} characters.') - return error(http_500.body) + if value.str().len > dtm.max_placeholders_value_size { + eprintln('${dtm.message_signature_error} Length of placeholder value for key "${key}" exceeds the maximum allowed size for HTML content in file: ${html_file}. Max allowed size: ${dtm.max_placeholders_value_size} characters.') + return error(dtm.internat_server_error) } } // If all is ok, return full path of HTML template file and HTML filename without extension return html_file, file_name } else { - eprintln("${vweb.message_signature_error} Template : '${html_file}' not found. Ensure all HTML templates are located in the 'templates' directory at the project's root.") - return error(http_500.body) + eprintln("${dtm.message_signature_error} Template : '${html_file}' not found. Ensure all HTML templates are located in the 'templates' directory at the project's root.") + return error(dtm.internat_server_error) } } @@ -418,16 +416,16 @@ fn (tm DynamicTemplateManager) check_html_and_placeholders_size(f_path string, t // fn (mut tm DynamicTemplateManager) create_template_cache_and_display_html(tcs CacheRequest, last_template_mod i64, c_time i64, file_path string, tmpl_name string, cache_delay_expiration i64, placeholders &map[string]DtmMultiTypeMap) string { // Control if cache delay expiration is correctly setted. See the function itself for more details. - test_if_cache_delay_iscorrect(cache_delay_expiration, tmpl_name) or { + check_if_cache_delay_iscorrect(cache_delay_expiration, tmpl_name) or { eprintln(err) - return http_500.body + return dtm.internat_server_error } // Parses the HTML and stores the rendered output in the variable. See the function itself for more details. mut html, content_checksum := tm.parse_html_file(file_path, tmpl_name, placeholders, tm.compress_html) // If caching is enabled and the HTML content is valid, this section creates a temporary cache file, which is then used by the cache manager. // If successfully temporary is created, a cache creation/update notification is sent through its dedicated channel to the cache manager - if cache_delay_expiration != -1 && html != http_500.body && tm.active_cache_server { + if cache_delay_expiration != -1 && html != dtm.internat_server_error && tm.active_cache_server { op_success, tmp_name := tm.create_temp_cache(html, file_path, c_time) if op_success { tm.ch_cache_handler <- TemplateCache{ @@ -482,11 +480,11 @@ fn (tm DynamicTemplateManager) create_temp_cache(html &string, f_path string, ts // Converts the HTML content into a byte array html_bytes := html.bytes() mut f := os.create(cache_path) or { - eprintln('${vweb.message_signature_error} Cannot create tempory cache file : ${err.msg()}') + eprintln('${dtm.message_signature_error} Cannot create tempory cache file : ${err.msg()}') return false, '' } f.write(html_bytes) or { - eprintln('${vweb.message_signature_error} Cannot write in temporary cache file : ${err.msg()}') + eprintln('${dtm.message_signature_error} Cannot write in temporary cache file : ${err.msg()}') f.close() return false, '' } @@ -514,8 +512,8 @@ fn (mut tm DynamicTemplateManager) get_cache(name string, path string, placehold // Retrieve the HTML render from the file cache in disk and convert it to a string. file_name := os.join_path(tm.template_cache_folder, '${value.name}_${value.checksum}.cache') r_b_html := os.read_bytes(file_name) or { - eprintln('${vweb.message_signature_error} Get_cache() cannot read template cache file ${value.name} : ${err.msg()} ') - return http_500.body + eprintln('${dtm.message_signature_error} Get_cache() cannot read template cache file ${value.name} : ${err.msg()} ') + return dtm.internat_server_error } html = r_b_html.bytestr() } @@ -641,7 +639,7 @@ fn (mut tm DynamicTemplateManager) cache_handler() { mut tc := <-tm.ch_cache_handler { // Close handler if asked. if tm.close_cache_handler { - eprintln('${vweb.message_signature_info} Cache manager has been successfully stopped. Please consider restarting the application if needed.') + eprintln('${dtm.message_signature_info} Cache manager has been successfully stopped. Please consider restarting the application if needed.') break } f_path_tmp := os.join_path(tm.template_cache_folder, tc.tmp_name_file) @@ -661,7 +659,7 @@ fn (mut tm DynamicTemplateManager) cache_handler() { tc.cache_storage_mode = .disk } file_data := os.read_bytes(f_path_tmp) or { - eprintln('${vweb.message_signature_error} Cache Handler : Failed to read tmp file, cache server will be stopped, you need to fix and restart application: ${err.msg()}') + eprintln('${dtm.message_signature_error} Cache Handler : Failed to read tmp file, cache server will be stopped, you need to fix and restart application: ${err.msg()}') break } @@ -673,7 +671,7 @@ fn (mut tm DynamicTemplateManager) cache_handler() { // If the cache is stored in memory, the temporary file is destroyed. tc.html_data = file_data os.rm(f_path_tmp) or { - eprintln('${vweb.message_signature_error} Cache Handler : While deleting the tmp cache file: "${f_path_tmp}", cache server will be stopped, you need to fix and restart application: ${err.msg()}') + eprintln('${dtm.message_signature_error} Cache Handler : While deleting the tmp cache file: "${f_path_tmp}", cache server will be stopped, you need to fix and restart application: ${err.msg()}') break } } @@ -682,7 +680,7 @@ fn (mut tm DynamicTemplateManager) cache_handler() { new_cache_file_name := os.join_path(tm.template_cache_folder, '${tc.name}_${tc.checksum}.cache') os.mv(f_path_tmp, new_cache_file_name) or { - eprintln('${vweb.message_signature_error} Cache Handler : Failed to rename tmp file, cache server will be stopped, you need to fix and restart application: ${err.msg()}') + eprintln('${dtm.message_signature_error} Cache Handler : Failed to rename tmp file, cache server will be stopped, you need to fix and restart application: ${err.msg()}') break } } @@ -720,7 +718,7 @@ fn (mut tm DynamicTemplateManager) cache_handler() { } } else if tc.cache_request != .delete { os.rm(f_path_tmp) or { - eprintln('${vweb.message_signature_error} Cache Handler : While deleting the tmp cache file: "${f_path_tmp}", cache server will be stopped, you need to fix and restart application: ${err.msg()}') + eprintln('${dtm.message_signature_error} Cache Handler : While deleting the tmp cache file: "${f_path_tmp}", cache server will be stopped, you need to fix and restart application: ${err.msg()}') break } } @@ -794,7 +792,7 @@ fn (mut tm DynamicTemplateManager) chandler_clear_specific_cache(id int) (int, b .disk { file_path := os.join_path(tm.template_cache_folder, '${value.name}_${value.checksum}.cache') os.rm(file_path) or { - eprintln('${vweb.message_signature_error} While deleting the specific cache file: ${file_path}, cache server will be stopped, you need to fix and restart application: : ${err.msg()}') + eprintln('${dtm.message_signature_error} While deleting the specific cache file: ${file_path}, cache server will be stopped, you need to fix and restart application: : ${err.msg()}') break } } @@ -888,7 +886,7 @@ fn (mut tm DynamicTemplateManager) stop_cache_handler() { // Addressing this by adding a control mechanism is recommended for enhanced stability. // For now, it is the user's responsibility to provide the correct HTML file(s) and HTML file(s)-content format. // -// TODO - Note that the function 'vlib/vweb/vweb.v : filter()' is currently used here. +// TODO - Note that the function 'vlib/dtm/dtm.v : filter()' is currently used here. // However, it is marked for relocation to the template render in the future. // If this change is implemented, corresponding adjustments will also be needed in this function. // @@ -908,8 +906,8 @@ fn (mut tm DynamicTemplateManager) parse_html_file(file_path string, tmpl_name s // To prevent runtime crashes related to template include directives error, // this code snippet ensures that the paths in include directives '@include' are correct. html_content := os.read_file(file_path) or { - eprintln("${vweb.message_signature_error} Unable to read the file: '${file_path}' with HTML parser function.") - return http_500.body, '' + eprintln("${dtm.message_signature_error} Unable to read the file: '${file_path}' with HTML parser function.") + return dtm.internat_server_error, '' } // TODO - The regex module in V does not support the use of escaped single quotes (') or double quotes (") in regex patterns, which can result in syntax errors. // This limitation can cause runtime errors if double quotes are used in HTML templates with '@include' directives. @@ -947,8 +945,8 @@ fn (mut tm DynamicTemplateManager) parse_html_file(file_path string, tmpl_name s } if directive_inclusion_error { - eprintln("${vweb.message_signature_error} In the HTML template: '${file_path}', an error occurred in one of the '@include' directives. This could be due to the use of an invalid path: ${full_path}") - return http_500.body, '' + eprintln("${dtm.message_signature_error} In the HTML template: '${file_path}', an error occurred in one of the '@include' directives. This could be due to the use of an invalid path: ${full_path}") + return dtm.internat_server_error, '' } } mut p := parser.Parser{} @@ -958,7 +956,7 @@ fn (mut tm DynamicTemplateManager) parse_html_file(file_path string, tmpl_name s placeholders) // This section completes the processing by replacing any placeholders that were not handled by the compiler template parser. // If there are placeholders present, it iterates through them, applying necessary filters and substituting their values into the HTML content. - // vweb.filter function used here. 'vlib/vweb.vweb.v line 1159.' + // dtm.filter function used here. 'vlib/dtm.dtm.v line 1159.' mut combined_str := '' mut current_content_checksum := '' // Checks if there are any placeholders to process @@ -971,25 +969,25 @@ fn (mut tm DynamicTemplateManager) parse_html_file(file_path string, tmpl_name s // Converts value to string temp_val := value.str() // Filters the string value for safe HTML insertion - val = filter(temp_val) + val = templating.filter(temp_val) // Appends the original string value to the combined string for the content checksum combined_str += temp_val } string { // Checks if the placeholder allows HTML inclusion - if key.ends_with(vweb.include_html_key_tag) { + if key.ends_with(dtm.include_html_key_tag) { // Iterates over allowed HTML tags for inclusion - for tag in vweb.allowed_tags { + for tag in dtm.allowed_tags { // Escapes the HTML tag - escaped_tag := filter(tag) + escaped_tag := templating.filter(tag) // Replaces the escaped tags with actual HTML tags in the value val = value.replace(escaped_tag, tag) } // Adjusts the placeholder key by removing the HTML inclusion tag - key_m = key.all_before_last(vweb.include_html_key_tag) + key_m = key.all_before_last(dtm.include_html_key_tag) } else { // Filters the string value for safe HTML insertion - val = filter(value) + val = templating.filter(value) } // Appends the string value to the combined string for the content checksum combined_str += value @@ -1035,7 +1033,7 @@ fn (mut tm DynamicTemplateManager) parse_html_file(file_path string, tmpl_name s // TODO - This function does not currently handle the cleanup of all template directives typically managed by the Vlang compiler, such as conditional statements or loops.... // Implementation of these features will be necessary. // -// TODO - Note that the function 'vlib/vweb/vweb.v : filter()' is currently used here. +// TODO - Note that the function 'vlib/dtm/dtm.v : filter()' is currently used here. // However, it is marked for relocation to the template render in the future. // If this change is implemented, corresponding adjustments will also be needed in this function. // @@ -1046,15 +1044,15 @@ fn (mut tm DynamicTemplateManager) clean_parsed_html(tmpl string, tmpl_name stri end_marker := "')\n\n\t_tmpl_res_${tmpl_name} := sb_${tmpl_name}.str()" // Searches for the start marker in the processed HTML content. Triggers an error if the start marker is not found. start := tmpl.index(start_marker) or { - eprintln("${vweb.message_signature_error} Start marker not found for '${tmpl_name}': ${err.msg()}") - // vweb.filter function used here. 'vlib/vweb.vweb.v line 1159.' - return filter(tmpl) + eprintln("${dtm.message_signature_error} Start marker not found for '${tmpl_name}': ${err.msg()}") + // dtm.filter function used here. 'vlib/dtm.dtm.v line 1159.' + return templating.filter(tmpl) } // Identifies the last occurrence of the end marker. Signals an error if it is missing. end := tmpl.index_last(end_marker) or { - eprintln("${vweb.message_signature_error} End marker not found for '${tmpl_name}': ${err.msg()}") - // vweb.filter function used here. 'vlib/vweb.vweb.v line 1159.' - return filter(tmpl) + eprintln("${dtm.message_signature_error} End marker not found for '${tmpl_name}': ${err.msg()}") + // dtm.filter function used here. 'vlib/dtm.dtm.v line 1159.' + return templating.filter(tmpl) } // Extracts the portion of HTML content between the start and end markers. mut html := tmpl[start + start_marker.len..end] @@ -1078,9 +1076,9 @@ fn (mut tm DynamicTemplateManager) clean_parsed_html(tmpl string, tmpl_name stri placeholder_name := placeholder[1..] // Checks if the placeholder or its variant with '_#includehtml' is not in the provided placeholders map. if !(placeholder_name in provided_placeholders - || (placeholder_name + vweb.include_html_key_tag) in provided_placeholders) { + || (placeholder_name + dtm.include_html_key_tag) in provided_placeholders) { // If so, escapes the unresolved placeholder and replaces the original placeholder with the escaped version - escaped_placeholder := filter(placeholder) + escaped_placeholder := templating.filter(placeholder) html = html.replace(placeholder, escaped_placeholder) } } @@ -1090,7 +1088,7 @@ fn (mut tm DynamicTemplateManager) clean_parsed_html(tmpl string, tmpl_name stri return html } -// fn test_if_cache_delay_iscorrect(i64, string) return ! +// fn check_if_cache_delay_iscorrect(i64, string) return ! // // Validates the user-specified cache expiration delay for HTML templates. // It enforces three permissible delay settings: @@ -1098,10 +1096,10 @@ fn (mut tm DynamicTemplateManager) clean_parsed_html(tmpl string, tmpl_name stri // - A parameter of 0 for an infinite cache expiration delay // - A parameter of -1 for no caching, meaning the HTML template is processed every time without being stored in the cache." // -fn test_if_cache_delay_iscorrect(cde i64, tmpl_name string) ! { - if (cde != 0 && cde != -1 && cde < vweb.cache_delay_expiration_at_min) - || (cde != 0 && cde != -1 && cde > vweb.cache_delay_expiration_at_max) { - return error("${vweb.message_signature_error} The cache timeout for template '${tmpl_name}.html' cannot be set to a value less than '${vweb.cache_delay_expiration_at_min}' seconds and more than '${vweb.cache_delay_expiration_at_max}' seconds. Exception for the value '0' which means no cache expiration, and the value '-1' which means html generation without caching.") +fn check_if_cache_delay_iscorrect(cde i64, tmpl_name string) ! { + if (cde != 0 && cde != -1 && cde < dtm.cache_delay_expiration_at_min) + || (cde != 0 && cde != -1 && cde > dtm.cache_delay_expiration_at_max) { + return error("${dtm.message_signature_error} The cache timeout for template '${tmpl_name}.html' cannot be set to a value less than '${dtm.cache_delay_expiration_at_min}' seconds and more than '${dtm.cache_delay_expiration_at_max}' seconds. Exception for the value '0' which means no cache expiration, and the value '-1' which means html generation without caching.") } } diff --git a/vlib/x/templating/dtm/dynamic_template_manager_test.v b/vlib/x/templating/dtm/dynamic_template_manager_test.v new file mode 100644 index 00000000000000..0661ec301735b8 --- /dev/null +++ b/vlib/x/templating/dtm/dynamic_template_manager_test.v @@ -0,0 +1,402 @@ +module dtm + +import os +import time + +const temp_dtm_dir = 'dynamic_template_manager_test' +const temp_cache_dir = 'vcache' +const temp_templates_dir = 'templates' +const temp_html_fp = 'temp.html' +const temp_html_n = 'temp' +const vtmp_dir = os.vtmp_dir() + +fn testsuite_begin() { + temp_folder := os.join_path(dtm.vtmp_dir, dtm.temp_dtm_dir) + os.mkdir_all(temp_folder) or { panic(err) } + + vcache_path := os.join_path(temp_folder, dtm.temp_cache_dir) + templates_path := os.join_path(temp_folder, dtm.temp_templates_dir) + + os.mkdir_all(vcache_path) or { panic(err) } + os.mkdir_all(templates_path) or { panic(err) } + + temp_html_file := os.join_path(templates_path, dtm.temp_html_fp) + + html_content := ' + + + + TEST + + +
+

TEST

+
+ + ' + + os.write_file(temp_html_file, html_content) or { panic(err) } +} + +fn test_initialize_dtm() { + dtmi := init_dtm(false, 0) + assert dtmi.dtm_init_is_ok == true +} + +fn test_test_and_clear_cache_files() { + dtmi := init_dtm(false, 0) + dtmi.test_and_clear_cache_files() or { panic(err) } + + count_cache_files := os.ls(dtmi.template_cache_folder) or { panic(err) } + assert count_cache_files.len == 0 +} + +fn test_create_template_cache_and_display_html() { + mut dtmi := init_dtm(true, max_size_data_in_memory) + defer { + dtmi.stop_cache_handler() + } + html := dtmi.create_cache() + assert html.len > 10 +} + +fn test_get_cache() { + mut dtmi := init_dtm(true, max_size_data_in_memory) + dtmi.create_cache() + defer { + dtmi.stop_cache_handler() + } + dtm_placeholers := map[string]DtmMultiTypeMap{} + temp_html_file := os.join_path(dtmi.template_folder, dtm.temp_html_fp) + html_mem := dtmi.get_cache(dtm.temp_html_n, temp_html_file, &dtm_placeholers) + assert html_mem.len > 10 +} + +fn test_return_cache_info_isexistent() { + mut dtmi := init_dtm(false, 0) + path_template := os.join_path(dtmi.template_folder, dtm.temp_html_fp) + lock dtmi.template_caches { + dtmi.template_caches << TemplateCache{ + id: 1 + path: path_template + } + } + lock dtmi.nbr_of_remaining_template_request { + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 1 + } + } + cache_exists, _, _, _, _, _, _, _ := dtmi.return_cache_info_isexistent(path_template) + assert cache_exists == true + lock dtmi.template_caches { + dtmi.template_caches[0].id_redirection = 2 + dtmi.template_caches << TemplateCache{ + id: 2 + path: path_template + id_redirection: 3 + } + dtmi.template_caches << TemplateCache{ + id: 3 + path: path_template + id_redirection: 4 + } + dtmi.template_caches << TemplateCache{ + id: 4 + path: path_template + id_redirection: 5 + } + dtmi.template_caches << TemplateCache{ + id: 5 + path: path_template + } + } + lock dtmi.nbr_of_remaining_template_request { + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 2 + } + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 3 + } + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 4 + } + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 5 + } + } + _, id, _, _, _, _, _, _ := dtmi.return_cache_info_isexistent(path_template) + assert id == 5 +} + +fn test_remaining_template_request() { + mut dtmi := init_dtm(false, 0) + + lock dtmi.nbr_of_remaining_template_request { + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 1 + } + + dtmi.remaining_template_request(true, 1) + assert dtmi.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 1 + dtmi.remaining_template_request(true, 1) + assert dtmi.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 2 + dtmi.remaining_template_request(false, 1) + assert dtmi.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 1 + dtmi.remaining_template_request(false, 1) + assert dtmi.nbr_of_remaining_template_request[0].nbr_of_remaining_request == 0 + } +} + +fn test_check_html_and_placeholders_size() { + dtmi := init_dtm(false, 0) + temp_html_file := os.join_path(dtmi.template_folder, dtm.temp_html_fp) + placeholders := map[string]DtmMultiTypeMap{} + + path, filename := dtmi.check_html_and_placeholders_size(temp_html_file, &placeholders) or { + panic(err) + } + + assert path.len > 10 + assert filename.len > 3 +} + +fn test_chandler_prevent_cache_duplicate_request() { + dtmi := init_dtm(false, 0) + temp_html_file := os.join_path(dtmi.template_folder, dtm.temp_html_fp) + + lock dtmi.template_caches { + dtmi.template_caches << TemplateCache{ + id: 1 + path: temp_html_file + cache_request: .new + } + dtmi.template_caches << TemplateCache{ + id: 2 + path: temp_html_file + cache_request: .update + last_template_mod: i64(1) + } + dtmi.template_caches << TemplateCache{ + id: 3 + path: temp_html_file + cache_request: .exp_update + last_template_mod: i64(1) + generate_at: i64(100) + } + dtmi.template_caches << TemplateCache{ + id: 4 + cache_request: .delete + } + } + new_cache := TemplateCache{ + id: 5 + path: temp_html_file + cache_request: .new + } + update_cache := TemplateCache{ + id: 6 + path: temp_html_file + cache_request: .update + last_template_mod: i64(1) + } + exp_update_cache := TemplateCache{ + id: 7 + path: temp_html_file + cache_request: .exp_update + last_template_mod: i64(1) + generate_at: i64(10) + cache_delay_expiration: i64(10) + } + delete_cache := TemplateCache{ + id: 4 + cache_request: .delete + } + mut is_duplicate := dtmi.chandler_prevent_cache_duplicate_request(&new_cache) + assert is_duplicate == true + is_duplicate = dtmi.chandler_prevent_cache_duplicate_request(&update_cache) + assert is_duplicate == true + is_duplicate = dtmi.chandler_prevent_cache_duplicate_request(&exp_update_cache) + assert is_duplicate == true + is_duplicate = dtmi.chandler_prevent_cache_duplicate_request(&delete_cache) + assert is_duplicate == false + + lock dtmi.template_caches { + dtmi.template_caches.delete(3) + } + + is_duplicate = dtmi.chandler_prevent_cache_duplicate_request(&delete_cache) + assert is_duplicate == true +} + +fn test_chandler_clear_specific_cache() { + mut dtmi := init_dtm(true, 0) + defer { + dtmi.stop_cache_handler() + } + dtmi.create_cache() + lock dtmi.template_caches { + cache_file := os.join_path(dtmi.template_cache_folder, '${dtmi.template_caches[0].name}_${dtmi.template_caches[0].checksum}.cache') + index, is_success := dtmi.chandler_clear_specific_cache(dtmi.template_caches[0].id) + assert is_success == true + assert index == 0 + cache_exist := os.exists(cache_file) + assert cache_exist == false + } +} + +fn test_chandler_remaining_cache_template_used() { + mut dtmi := init_dtm(false, 0) + lock dtmi.nbr_of_remaining_template_request { + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 1 + nbr_of_remaining_request: 0 + } + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 2 + nbr_of_remaining_request: 1 + need_to_delete: true + } + dtmi.nbr_of_remaining_template_request << RemainingTemplateRequest{ + id: 3 + nbr_of_remaining_request: 0 + need_to_delete: true + } + } + mut can_delete := dtmi.chandler_remaining_cache_template_used(CacheRequest.update, + 3, 3) + assert can_delete == true + can_delete = dtmi.chandler_remaining_cache_template_used(CacheRequest.update, 2, 2) + assert can_delete == false + can_delete = dtmi.chandler_remaining_cache_template_used(CacheRequest.delete, 1, 0) + assert can_delete == true + can_delete = dtmi.chandler_remaining_cache_template_used(CacheRequest.new, 4, 0) + assert can_delete == true +} + +fn test_parse_html_file() { + mut dtmi := init_dtm(false, 0) + temp_folder := os.join_path(dtm.vtmp_dir, dtm.temp_dtm_dir) + templates_path := os.join_path(temp_folder, dtm.temp_templates_dir) + temp_html_file := os.join_path(templates_path, dtm.temp_html_fp) + + mut placeholders := map[string]DtmMultiTypeMap{} + + is_compressed := true + html, content_checksum := dtmi.parse_html_file(temp_html_file, dtm.temp_html_n, &placeholders, + is_compressed) + + assert html.len > 0 + if placeholders.len > 0 { + assert content_checksum.len > 0 + } else { + assert content_checksum.len == 0 + } +} + +fn test_check_if_cache_delay_iscorrect() { + check_if_cache_delay_iscorrect(i64(300), dtm.temp_html_n) or { assert false } + + check_if_cache_delay_iscorrect(i64(-100), dtm.temp_html_n) or { assert true } +} + +fn test_cache_request_route() { + mut is_cache_exist := true + mut cache_delay_expiration := i64(400) + mut last_template_mod := get_current_unix_timestamp() + mut test_current_template_mod := last_template_mod + mut cache_del_exp := 300 + mut gen_at := last_template_mod + mut content_checksum := 'checksumtest1' + mut current_content_checksum := 'checksumtest2' + + mut request_type := cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, + test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), + content_checksum, current_content_checksum) + + assert request_type == CacheRequest.update + + current_content_checksum = 'checksumtest1' + + request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, + test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), + content_checksum, current_content_checksum) + + assert request_type == CacheRequest.cached + + gen_at = (last_template_mod - 500) + + request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, + test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), + content_checksum, current_content_checksum) + + assert request_type == CacheRequest.exp_update + + is_cache_exist = false + + request_type = cache_request_route(is_cache_exist, cache_delay_expiration, last_template_mod, + test_current_template_mod, cache_del_exp, gen_at, get_current_unix_timestamp(), + content_checksum, current_content_checksum) + + assert request_type == CacheRequest.new +} + +fn test_cache_handler() { + mut dtmi := init_dtm(true, max_size_data_in_memory) + defer { + dtmi.stop_cache_handler() + } + dtmi.create_cache() + path_f := os.join_path(dtmi.template_folder, dtm.temp_html_fp) + lock dtmi.template_caches { + assert dtmi.template_caches[0].id == 1 + assert dtmi.template_caches[0].name == dtm.temp_html_n + assert dtmi.template_caches[0].path == path_f + } + dtmi.id_to_handlered = 1 + dtmi.ch_cache_handler <- TemplateCache{ + id: 1 + cache_request: .delete + } + time.sleep(1 * time.millisecond) + lock dtmi.template_caches { + assert dtmi.template_caches.len == 0 + } +} + +fn testsuite_end() { + temp_folder := os.join_path(dtm.vtmp_dir, dtm.temp_dtm_dir) + os.rmdir_all(temp_folder) or {} +} + +// Utilities function : + +fn init_dtm(b bool, m int) &DynamicTemplateManager { + temp_folder := os.join_path(dtm.vtmp_dir, dtm.temp_dtm_dir) + vcache_path := os.join_path(temp_folder, dtm.temp_cache_dir) + templates_path := os.join_path(temp_folder, dtm.temp_templates_dir) + + mut dtm := create_dtm() + + init_params := DynamicTemplateManagerInitialisationParams{ + active_cache_server: b + max_size_data_in_mem: m + test_cache_dir: vcache_path + test_template_dir: templates_path + } + + initialize_dtm(mut dtm, init_params) or { panic(err) } + + return dtm +} + +fn (mut tm DynamicTemplateManager) create_cache() string { + temp_html_file := os.join_path(tm.template_folder, dtm.temp_html_fp) + html_last_mod := os.file_last_mod_unix(temp_html_file) + c_time := get_current_unix_timestamp() + cache_delay_exp := i64(500) + placeholder := map[string]DtmMultiTypeMap{} + html := tm.create_template_cache_and_display_html(.new, html_last_mod, c_time, temp_html_file, + dtm.temp_html_n, cache_delay_exp, &placeholder) + time.sleep(1 * time.millisecond) + return html +} diff --git a/vlib/x/templating/escape_html_strings_in_templates.v b/vlib/x/templating/escape_html_strings_in_templates.v new file mode 100644 index 00000000000000..186e09ee456719 --- /dev/null +++ b/vlib/x/templating/escape_html_strings_in_templates.v @@ -0,0 +1,11 @@ +module templating + +import encoding.html + +// Do not delete. +// Calls to this function are generated by `fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) {` in vlib/v/gen/c/str_intp.v, +// for string interpolation inside vweb templates. +// TODO: move it to template render +pub fn filter(s string) string { + return html.escape(s) +}