+ Hello
+ >
+ return(0);
+}
+
+RENDER()
+{
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ String view_name = safe_name(first(context->get["view"], "default")) + ".uce";
+ if(file_exists(view_name))
+ render_file(view_name);
+ else
+ print("view not found");
+ ?>
+
+
+
+ >
+}
diff --git a/examples/blog/robots.txt b/examples/blog/robots.txt
new file mode 100644
index 0000000..d0e5f1b
--- /dev/null
+++ b/examples/blog/robots.txt
@@ -0,0 +1,5 @@
+# www.robotstxt.org/
+
+# Allow crawling of all content
+User-agent: *
+Disallow:
diff --git a/examples/blog/site.webmanifest b/examples/blog/site.webmanifest
new file mode 100644
index 0000000..222ae16
--- /dev/null
+++ b/examples/blog/site.webmanifest
@@ -0,0 +1,12 @@
+{
+ "short_name": "",
+ "name": "",
+ "icons": [{
+ "src": "icon.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ }],
+ "start_url": "/?utm_source=homescreen",
+ "background_color": "#fafafa",
+ "theme_color": "#fafafa"
+}
diff --git a/examples/blog/tile-wide.png b/examples/blog/tile-wide.png
new file mode 100644
index 0000000..ccd739c
Binary files /dev/null and b/examples/blog/tile-wide.png differ
diff --git a/examples/blog/tile.png b/examples/blog/tile.png
new file mode 100644
index 0000000..f820f61
Binary files /dev/null and b/examples/blog/tile.png differ
diff --git a/scripts/compile b/scripts/compile
index 64f194d..0fba5f6 100755
--- a/scripts/compile
+++ b/scripts/compile
@@ -9,6 +9,8 @@ SRC_FN="$3"
PP_FN="$4"
SO_FN="$5"
+LINK_OBJECTS="$6"
+
#echo "Source Dir: $SRC_DIR"
#echo "Dest Dir: $DEST_DIR"
#echo "Source File: $SRC_FN"
@@ -32,6 +34,10 @@ SRCFLAGS="-D PLATFORM_NAME=\"linux\""
# echo "Compliling executable..."
$COMPILER "$DEST_DIR/$PP_FN" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$SO_FN"
+# separate .o file
+#$COMPILER -c "$DEST_DIR/$PP_FN" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$PP_FN.o"
+#$COMPILER "$DEST_DIR/$PP_FN.o" "$LINK_OBJECTS" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$SO_FN"
+
if [ $? -eq 0 ]
then
# ls -lh "$DEST_DIR"
diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp
index 1360ee3..4be7395 100644
--- a/src/lib/compiler.cpp
+++ b/src/lib/compiler.cpp
@@ -159,13 +159,14 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
pc.append("#include \"" + sub_su->bin_path + "/" + sub_su->pre_file_name + "\"\n");
}
}
- else if(current_line.length() == 4 && current_line.substr(0, 4) == "API ")
+ else if(false && current_line.substr(0, 6) == "EXPORT" && isspace(current_line[6]))
{
auto end_declaration_pos = content.find("{", i);
if(end_declaration_pos != std::string::npos)
{
// remove string "API " from output
- pc.resize(pc.length() - 4);
+ //pc.resize(pc.length() - 7);
+ pc.append(1, '\n');
String declaration = trim(content.substr(i, end_declaration_pos - i));
String return_type_and_name = nibble(declaration, "(");
StringList rtn_list = split_space(return_type_and_name);
@@ -208,7 +209,7 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
su->pre_file_name = su->src_file_name + ".cpp";
su->so_name = su->bin_path + "/" + su->bin_file_name;
- su->api_file_name = su->bin_path + "/" + su->src_file_name + ".api.txt";
+ su->api_file_name = su->bin_path + "/" + su->src_file_name + ".exports.txt";
su->setup_file_name = su->bin_path + "/" + su->src_file_name + ".setup.h";
}
@@ -224,7 +225,7 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
{
if(su->opt_so_optional)
return;
- printf("(i) unit file not found: %s\n", su->so_name.c_str());
+ //printf("(i) unit file not found: %s\n", su->so_name.c_str());
su->compiler_messages = "unit file not found";
return;
}
@@ -235,11 +236,11 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
su->last_compiled = file_mtime(su->so_name);
char *error;
su->on_setup = (request_handler)dlsym(su->so_handle, "set_current_request");
- su->on_render = (call_handler)dlsym(su->so_handle, "render");
if ((error = dlerror()) != NULL)
printf("Error - %s in %s\n", error, su->file_name.c_str());
- else
- printf("(i) loaded unit %s\n", su->file_name.c_str());
+ su->on_render = (call_handler)dlsym(su->so_handle, "render");
+ //else
+ // printf("(i) loaded unit %s\n", su->file_name.c_str());
}
else
{
@@ -253,7 +254,7 @@ String compile_setup_file(Request* context, SharedUnit* su)
String("#ifndef UCE_LIB_INCLUDED\n") +
"#define UCE_LIB_INCLUDED\n" +
("#include \"")+context->server->config.COMPILER_SYS_PATH +"/src/lib/uce_lib.h\" \n"+
- file_get_contents(context->server->config.SETUP_TEMPLATE) +
+ file_get_contents(context->server->config.COMPILER_SYS_PATH + "/" + context->server->config.SETUP_TEMPLATE) +
"#endif \n";
StringList declarations;
StringList load_units;
@@ -296,7 +297,7 @@ void compile_shared_unit(Request* context, SharedUnit* su, String file_name)
else
{
load_shared_unit(context, su, file_name);
- printf("(i) compiled unit %s\n", file_name.c_str());
+ //printf("(i) compiled unit %s\n", file_name.c_str());
}
}
@@ -356,52 +357,18 @@ SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_opti
return(su);
}
-void compiler_invoke(Request* context, String file_name, DTree& call_param)
-{
-
- if(file_name[0] != '/')
- {
- file_name = expand_path(file_name);
- }
- //printf("(i) invoke %s\n", file_name.c_str());
-
- //printf("(i) invoke(%s)\n", file_name.c_str());
- switch_to_system_alloc();
- auto su = get_shared_unit(context, file_name);
- switch_to_arena(context->mem);
- if(!su)
- {
- printf("Error loading unit %s\n", file_name.c_str());
- print("Error loading unit: "+file_name);
- }
- else if(su->compiler_messages.length() > 0)
- {
- context->header["Content-Type"] = "text/plain";
- print(su->compiler_messages);
- }
- else if(!su->on_render)
- {
- context->header["Content-Type"] = "text/plain";
- print("no RENDER() entry point");
- }
- else
- {
- String prev_wd = get_cwd();
- set_cwd(su->src_path);
- su->on_setup(context);
- su->on_render(call_param);
- set_cwd(prev_wd);
- }
-}
-
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional)
{
+ context->stats.invoke_count++;
+
if(file_name[0] != '/')
{
file_name = expand_path(file_name, current_path);
}
+ //printf("(i) load '%s'\n", file_name.c_str());
+
switch_to_system_alloc();
auto su = get_shared_unit(context, file_name, opt_so_optional);
switch_to_arena(context->mem);
@@ -413,7 +380,8 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
}
else if(su->compiler_messages.length() > 0)
{
- context->header["Content-Type"] = "text/plain";
+ if(context->stats.invoke_count == 1)
+ context->header["Content-Type"] = "text/plain";
print(su->compiler_messages);
return(0);
}
@@ -424,3 +392,77 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
}
+void compiler_invoke(Request* context, String file_name, DTree& call_param)
+{
+ auto su = compiler_load_shared_unit(context, file_name, "", false);
+ if(su)
+ {
+ if(!su->on_setup)
+ {
+ if(context->stats.invoke_count == 1)
+ context->header["Content-Type"] = "text/plain";
+ print("internal error: set_current_request() not defined in", file_name, "\n");
+ }
+ else if(!su->on_render)
+ {
+ if(context->stats.invoke_count == 1)
+ context->header["Content-Type"] = "text/plain";
+ print("no RENDER() entry point");
+ }
+ else
+ {
+ String prev_wd = get_cwd();
+ set_cwd(su->src_path);
+ su->on_setup(context);
+ su->on_render(call_param);
+ set_cwd(prev_wd);
+ }
+ }
+}
+
+void render_file(String file_name)
+{
+ //printf("(i) render_file(%s)\n", file_name.c_str());
+ DTree call_param;
+ compiler_invoke(context, file_name, call_param);
+}
+
+void render_file(String file_name, DTree& call_param)
+{
+ compiler_invoke(context, file_name, call_param);
+}
+
+DTree* call_file_function(String file_name, String function_name, DTree* call_param)
+{
+ DTree* result;
+ auto su = compiler_load_shared_unit(context, file_name, "", false);
+ if(su && su->so_handle)
+ {
+ if(!su->on_setup)
+ {
+ print("internal error: set_current_request() not defined in", file_name, "\n");
+ }
+ else
+ {
+ auto f = (dtree_call_handler)dlsym(su->so_handle, function_name.c_str());
+ if(!f)
+ {
+ print("Error: call_file_function() function '", function_name, "' not found");
+ }
+ else
+ {
+ String prev_wd = get_cwd();
+ set_cwd(su->src_path);
+ su->on_setup(context);
+ result = f(call_param);
+ set_cwd(prev_wd);
+ }
+ }
+ }
+ else
+ {
+ print("Error: call_file_function() could not load unit file '", file_name, "'");
+ }
+ return(result);
+}
+
diff --git a/src/lib/compiler.h b/src/lib/compiler.h
index 4263e6c..b43d6ba 100644
--- a/src/lib/compiler.h
+++ b/src/lib/compiler.h
@@ -1,4 +1,5 @@
#define RENDER() extern "C" void render(DTree& call)
+#define EXPORT extern "C"
String process_html_literal(Request* context, SharedUnit* su, String content);
String preprocess_shared_unit(Request* context, SharedUnit* su);
@@ -8,3 +9,9 @@ void compile_shared_unit(Request* context, SharedUnit* su, String file_name);
SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_optional = false);
void compiler_invoke(Request* context, String file_name, DTree& call_param);
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional = false);
+
+void render_file(String file_name);
+void render_file(String file_name, DTree& call_param);
+DTree* call_file_function(String file_name, String function_name, DTree* call_param = 0);
+
+StringList precompile_jobs;
diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp
index e986b36..fb2d63b 100644
--- a/src/lib/functionlib.cpp
+++ b/src/lib/functionlib.cpp
@@ -533,3 +533,13 @@ String ob_get_close()
return(result);
}
+String safe_name(String raw)
+{
+ String result = "";
+ for(auto c : raw)
+ {
+ if(isalnum(c) || c == '_')
+ result.append(1, c);
+ }
+ return(result);
+}
diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h
index edd0de8..857d9c4 100644
--- a/src/lib/functionlib.h
+++ b/src/lib/functionlib.h
@@ -60,5 +60,6 @@ void ob_start();
void ob_clear();
String ob_get_clear();
String ob_get();
+String safe_name(String raw);
#define is_bit_set(var,pos) ((var) & (1<<(pos)))
diff --git a/src/lib/sys.cpp b/src/lib/sys.cpp
index 2317fa0..050e095 100644
--- a/src/lib/sys.cpp
+++ b/src/lib/sys.cpp
@@ -12,7 +12,7 @@
String shell_exec(String cmd)
{
- printf("(i) shell_exec(%s)\n", cmd.c_str());
+ //printf("(i) shell_exec(%s)\n", cmd.c_str());
String data;
FILE * stream;
const int max_buffer = 256;
diff --git a/src/lib/types.cpp b/src/lib/types.cpp
index b255529..855c8e4 100644
--- a/src/lib/types.cpp
+++ b/src/lib/types.cpp
@@ -39,6 +39,7 @@ String nibble(String div, String& haystack)
}
}
+/*
void Request::invoke(String file_name)
{
DTree call_param;
@@ -50,6 +51,8 @@ void Request::invoke(String file_name, DTree& call_param)
compiler_invoke(this, file_name, call_param);
}
+*/
+
void Request::ob_start()
{
ob_stack.push_back(new std::ostringstream());
@@ -61,3 +64,4 @@ Request::~Request()
for(auto& sockfd : resources.sockets)
close(sockfd);
}
+
diff --git a/src/lib/types.h b/src/lib/types.h
index 272fa9e..732a6ba 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -141,6 +141,7 @@ struct Request;
struct DTree;
typedef void (*call_handler)(DTree& call_param);
+typedef DTree* (*dtree_call_handler)(DTree* call_param);
typedef void (*request_handler)(Request* request);
String to_string(s64 v) { return(std::to_string(v)); }
@@ -156,6 +157,8 @@ struct ServerSettings {
String TMP_UPLOAD_PATH = "/tmp/uce/uploads";
String SESSION_PATH = "/tmp/uce/sessions";
String COMPILER_SYS_PATH = ".";
+ String PRECOMPILE_FILES_IN = ".";
+
u32 LISTEN_PORT = 9993;
u64 SESSION_TIME = 60*60*24*30;
u32 WORKER_COUNT = 4;
@@ -260,6 +263,7 @@ struct Request {
f64 time_init;
f64 time_start;
f64 time_end;
+ u32 invoke_count = 0;
} stats;
struct Resources {
@@ -268,8 +272,8 @@ struct Request {
u64 fcgi_socket = 0;
} resources;
- void invoke(String file_name);
- void invoke(String file_name, DTree& call_param);
+ //void invoke(String file_name);
+ //void invoke(String file_name, DTree& call_param);
void ob_start();
diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp
index 0f02cd0..d16d7a3 100644
--- a/src/linux_fastcgi.cpp
+++ b/src/linux_fastcgi.cpp
@@ -70,7 +70,7 @@ int handle_complete(FastCGIRequest& request) {
}
// printf("(i) request ready\n");
- request.invoke(request.params["SCRIPT_FILENAME"]);
+ render_file(request.params["SCRIPT_FILENAME"]);
for( auto &f : request.uploaded_files)
{
@@ -87,6 +87,17 @@ int handle_complete(FastCGIRequest& request) {
void listen_for_connections()
{
+ if(precompile_jobs.size() > 0)
+ {
+ context = new Request();
+ context->server = &server_state;
+ for(auto s : precompile_jobs)
+ {
+ printf("- worker [%i] precompile %s\n", getpid(), s.c_str());
+ get_shared_unit(context, s, false);
+ }
+ }
+
signal(SIGSEGV, on_segfault);
server.on_request = &handle_request;
server.on_data = &handle_data;
@@ -106,6 +117,9 @@ void listen_for_connections()
int main(int argc, char** argv)
{
+ StringList precompile_jobs_pending;
+ u32 precompile_jobs_per_worker = 1;
+
printf("(P) Starting parent server PID:%i\n", getpid());
signal(SIGCHLD, on_child_exit);
@@ -143,11 +157,41 @@ int main(int argc, char** argv)
{
std::cout << e.what();
}*/
+ if(server_state.config.PRECOMPILE_FILES_IN != "" && server_state.config.WORKER_COUNT >= 2)
+ {
+ if(server_state.config.PRECOMPILE_FILES_IN != "/")
+ server_state.config.PRECOMPILE_FILES_IN = expand_path(server_state.config.PRECOMPILE_FILES_IN);
+ precompile_jobs_pending = split(trim(shell_exec(
+ "find " +
+ shell_escape(server_state.config.PRECOMPILE_FILES_IN) +
+ " -iname '*.uce' ")), "\n");
+ precompile_jobs_per_worker = 1 + (precompile_jobs_pending.size() / (server_state.config.WORKER_COUNT -1));
+ /*
+ */
+ }
+
+ s32 worker_spawn_count = 0;
for(;;)
{
while(workers.size() < server_state.config.WORKER_COUNT)
{
+ worker_spawn_count++;
+ precompile_jobs.clear();
+ // spawn workers with precompile jobs if necessary but
+ // leave the first worker alone so it can start responding
+ // to requests right away
+ if(precompile_jobs_pending.size() > 0 && worker_spawn_count > 1)
+ {
+ for(u32 i = 0; i < precompile_jobs_per_worker; i++)
+ {
+ if(precompile_jobs_pending.size() > 0)
+ {
+ precompile_jobs.push_back(precompile_jobs_pending.back());
+ precompile_jobs_pending.pop_back();
+ }
+ }
+ }
spawn_subprocess(listen_for_connections);
}
sleep(1);
diff --git a/test/random.uce b/test/random.uce
index ea92559..f922630 100644
--- a/test/random.uce
+++ b/test/random.uce
@@ -20,8 +20,8 @@ RENDER()
for(auto i = 0; i < 100; i++)
{
- print(i, ": ", (float)noise32(i)/(float)max_32, " / ", (float)noise64(i)/(float)max_64, " / ", noise01(i), " / ",
- generate_int(0, 4, i), " / ", generate_float(0.0, 4.0, i), "\n");
+ print(i, ": ", (float)gen_noise32(i)/(float)max_32, " / ", (float)gen_noise64(i)/(float)max_64, " / ", gen_noise01(i), " / ",
+ gen_int(0, 4, i), " / ", gen_float(0.0, 4.0, i), "\n");
}
?>
@@ -39,7 +39,7 @@ RENDER()
?>
- Sha1 of '1234': = sha1("1234") ?>
+ Sha1 of '1234': = gen_sha1("1234") ?>
Params
diff --git a/test/working-dir.uce b/test/working-dir.uce
index 6322d3d..f4fd296 100644
--- a/test/working-dir.uce
+++ b/test/working-dir.uce
@@ -11,7 +11,7 @@ RENDER()
print("Base WD: " + get_cwd() + "\n");
- context->invoke("test2/working-dir-test.uce");
+ render_file("test2/working-dir-test.uce");
?>
= var_dump(context->params) ?>
>